Skip to content

Commit 39c05c5

Browse files
mandyh2018hfwang
authored andcommitted
Add flag to specify IP types to use when connecting (GoogleCloudPlatform#174)
* Add user input flag ip_address_type to choose IP address for a given instance * Add PUBLIC as an alias for PRIMARY, change the IP address type to be uppercase and fix some grammar issues * Allow users to input multiple IP address types, and add the field IPAddrTypes in RemoteCertSource struct * Add user input flag ip_address_type to choose IP address for a given instance * remove additional ipAddressType in const due to the previous wrong Git operations * Revert "remove additional ipAddressType in const due to the previous wrong Git operations" This reverts commit b0c37b5. * Remove ip_address_type from const part * Add the default value PRIMARY to IPAddrTypeOpts field in struct RemoteOpts * Extract clientFromCredentials method from common.go to common_open_source.go * removed clientFromCredentials from common.go * Add findIpAddr helper function and improve the code based on comments * Change findIpAddr() to be part of struct RemoteCertSource and fix some format naming issues
1 parent 679c7d5 commit 39c05c5

File tree

2 files changed

+59
-6
lines changed

2 files changed

+59
-6
lines changed

cmd/cloud_sql_proxy/cloud_sql_proxy.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ can be removed automatically by this program.`)
8383
token = flag.String("token", "", "When set, the proxy uses this Bearer token for authorization.")
8484
tokenFile = flag.String("credential_file", "", `If provided, this json file will be used to retrieve Service Account credentials.
8585
You may set the GOOGLE_APPLICATION_CREDENTIALS environment variable for the same effect.`)
86+
ipAddressTypes = flag.String("ip_address_types", "PRIMARY", "Default to be 'PRIMARY'. Options: a list of strings separated by ',', e.g. 'PRIMARY, PRIVATE' ")
8687

8788
// Set to non-default value when gcloud execution failed.
8889
gcloudStatus gcloudStatusCode
@@ -102,7 +103,7 @@ const (
102103

103104
const (
104105
minimumRefreshCfgThrottle = time.Second
105-
106+
106107
port = 3307
107108
)
108109

@@ -183,7 +184,6 @@ Connection:
183184
When using Unix sockets (the default for systems which support them), the
184185
Proxy places the sockets in the directory specified by the -dir parameter.
185186
186-
187187
Automatic instance discovery:
188188
If the Google Cloud SQL is installed on the local machine and no instance
189189
connection flags are specified, the proxy connects to all instances in the
@@ -412,6 +412,9 @@ func main() {
412412
log.SetOutput(ioutil.Discard)
413413
}
414414

415+
// Split the input ipAddressTypes to the slice of string
416+
ipAddrTypeOptsInput := strings.Split(*ipAddressTypes, ",")
417+
415418
if *fdRlimit != 0 {
416419
if err := limits.SetupFDLimits(*fdRlimit); err != nil {
417420
logging.Infof("failed to setup file descriptor limits: %v", err)
@@ -447,7 +450,6 @@ func main() {
447450
log.Fatal(err)
448451
}
449452
instList = append(instList, ins...)
450-
451453
cfgs, err := CreateInstanceConfigs(*dir, *useFuse, instList, *instanceSrc, client)
452454
if err != nil {
453455
log.Fatal(err)
@@ -506,6 +508,7 @@ func main() {
506508
APIBasePath: *host,
507509
IgnoreRegion: !*checkRegion,
508510
UserAgent: userAgentFromVersionString(),
511+
IPAddrTypeOpts: ipAddrTypeOptsInput,
509512
}),
510513
Conns: connset,
511514
RefreshCfgThrottle: refreshCfgThrottle,

proxy/certs/certs.go

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"math"
2727
mrand "math/rand"
2828
"net/http"
29+
"strings"
2930
"time"
3031

3132
"github.com/GoogleCloudPlatform/cloudsql-proxy/logging"
@@ -64,6 +65,9 @@ type RemoteOpts struct {
6465
// A string for the RemoteCertSource to identify itself when contacting the
6566
// sqladmin API.
6667
UserAgent string
68+
69+
// IP address type options
70+
IPAddrTypeOpts []string
6771
}
6872

6973
// NewCertSourceOpts returns a CertSource configured with the provided Opts.
@@ -88,7 +92,20 @@ func NewCertSourceOpts(c *http.Client, opts RemoteOpts) *RemoteCertSource {
8892
ua = defaultUserAgent
8993
}
9094
serv.UserAgent = ua
91-
return &RemoteCertSource{pkey, serv, !opts.IgnoreRegion}
95+
96+
// Set default value to be PRIMARY if input opts.IPAddrTypeOpts is empty
97+
if len(opts.IPAddrTypeOpts) < 1 {
98+
opts.IPAddrTypeOpts = append(opts.IPAddrTypeOpts, "PRIMARY")
99+
} else {
100+
// Add "PUBLIC" as an alias for "PRIMARY"
101+
for index, ipAddressType := range opts.IPAddrTypeOpts {
102+
if strings.ToUpper(ipAddressType) == "PUBLIC" {
103+
opts.IPAddrTypeOpts[index] = "PRIMARY"
104+
}
105+
}
106+
}
107+
108+
return &RemoteCertSource{pkey, serv, !opts.IgnoreRegion, opts.IPAddrTypeOpts}
92109
}
93110

94111
// RemoteCertSource implements a CertSource, using Cloud SQL APIs to
@@ -104,6 +121,8 @@ type RemoteCertSource struct {
104121
// treated as an error. This is to provide the same functionality that will
105122
// occur when API calls require the region.
106123
checkRegion bool
124+
// a list of ip address types that users select
125+
IPAddrTypes []string
107126
}
108127

109128
// Constants for backoffAPIRetry. These cause the retry logic to scale the
@@ -185,6 +204,27 @@ func parseCert(pemCert string) (*x509.Certificate, error) {
185204
return x509.ParseCertificate(bl.Bytes)
186205
}
187206

207+
// Find the first matching IP address by user input IP address types
208+
func (s *RemoteCertSource) findIPAddr(data *sqladmin.DatabaseInstance, instance string) (ipAddrInUse string, err error) {
209+
for _, eachIPAddrTypeByUser := range s.IPAddrTypes {
210+
for _, eachIPAddrTypeOfInstance := range data.IpAddresses {
211+
if strings.ToUpper(eachIPAddrTypeOfInstance.Type) == strings.ToUpper(eachIPAddrTypeByUser) {
212+
ipAddrInUse = eachIPAddrTypeOfInstance.IpAddress
213+
return ipAddrInUse, nil
214+
}
215+
}
216+
}
217+
218+
ipAddrTypesOfInstance := ""
219+
for _, eachIPAddrTypeOfInstance := range data.IpAddresses {
220+
ipAddrTypesOfInstance += fmt.Sprintf("(TYPE=%v, IP_ADDR=%v)", eachIPAddrTypeOfInstance.Type, eachIPAddrTypeOfInstance.IpAddress)
221+
}
222+
223+
ipAddrTypeOfUser := fmt.Sprintf("%v", s.IPAddrTypes)
224+
225+
return "", fmt.Errorf("User input IP address type %v does not match the instance %v, the instance's IP addresses are %v ", ipAddrTypeOfUser, instance, ipAddrTypesOfInstance)
226+
}
227+
188228
// Remote returns the specified instance's CA certificate, address, and name.
189229
func (s *RemoteCertSource) Remote(instance string) (cert *x509.Certificate, addr, name string, err error) {
190230
p, region, n := util.SplitName(instance)
@@ -215,9 +255,19 @@ func (s *RemoteCertSource) Remote(instance string) (cert *x509.Certificate, addr
215255
logging.Errorf("%v", err)
216256
logging.Errorf("WARNING: specifying the correct region in an instance string will become required in a future version!")
217257
}
218-
if len(data.IpAddresses) == 0 || data.IpAddresses[0].IpAddress == "" {
258+
259+
if len(data.IpAddresses) == 0 {
219260
return nil, "", "", fmt.Errorf("no IP address found for %v", instance)
220261
}
262+
263+
// Find the first matching IP address by user input IP address types
264+
ipAddrInUse := ""
265+
ipAddrInUse, err = s.findIPAddr(data, instance)
266+
if err != nil {
267+
return nil, "", "", err
268+
}
269+
221270
c, err := parseCert(data.ServerCaCert.Cert)
222-
return c, data.IpAddresses[0].IpAddress, p + ":" + n, err
271+
272+
return c, ipAddrInUse, p + ":" + n, err
223273
}

0 commit comments

Comments
 (0)