Skip to content

Commit

Permalink
proxy: Added a connectivity test on startup that will test if the ins…
Browse files Browse the repository at this point in the history
…tances are reachable
  • Loading branch information
hilts-vaughan committed Apr 15, 2020
1 parent 0eb0bd1 commit ca0e769
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 2 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ cloud_sql_proxy takes a few arguments to configure what instances to connect to
down the proxy. Defaults to 0.
* `-skip_failed_instance_config`: Setting this flag will allow you to prevent the proxy from terminating when
some instance configurations could not be parsed and/or are unavailable.
* `-perform_connectivity_tests`: Performs connectivity tests on startup to the
databases and exits the proxy if one of them fails.

Note: `-instances` and `-instances_metadata` may be used at the same time but
are not compatible with the `-fuse` flag.
Expand Down
45 changes: 43 additions & 2 deletions cmd/cloud_sql_proxy/cloud_sql_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ to use the instance metadata value named 'cloud-sql-instances' you would
provide 'instance/attributes/cloud-sql-instances'. Not compatible with -fuse`)
useFuse = flag.Bool("fuse", false, `Mount a directory at 'dir' using FUSE for accessing instances. Note that the
directory at 'dir' must be empty before this program is started.`)
fuseTmp = flag.String("fuse_tmp", defaultTmp, `Used as a temporary directory if -fuse is set. Note that files in this directory
performConnectivityTestsOnStartup = flag.Bool("perform_connectivity_tests", false, `Performs connectivity tests on startup to the databases and exits the proxy if one of them fails.`)
fuseTmp = flag.String("fuse_tmp", defaultTmp, `Used as a temporary directory if -fuse is set. Note that files in this directory
can be removed automatically by this program.`)

// Settings for limits
Expand Down Expand Up @@ -324,6 +325,27 @@ func stringList(s string) []string {
return spl
}

func checkInstanceConnectivity(instanceName string, public bool, client *proxy.Client) error {
// The connectivity test right now is just a basic dial to make sure it is reachable
// and nothing more. This will help rule out basic network connectivity problems, though
// such as firewalls and the like.
conn, err := client.Dial(instanceName)

if conn != nil {
conn.Close()
}

if err != nil {
if public {
return fmt.Errorf("Performed connectivity test to public instance %v and got an error: %v. Do you have a route to it?", instanceName, err)
} else {
return fmt.Errorf("Performed connectivity test to private instance %v and got an error: %v. Do you have a route to it?", instanceName, err)
}
}

return nil
}

func listInstances(ctx context.Context, cl *http.Client, projects []string) ([]string, error) {
if len(projects) == 0 {
// No projects requested.
Expand Down Expand Up @@ -524,7 +546,6 @@ func main() {
if refreshCfgThrottle < minimumRefreshCfgThrottle {
refreshCfgThrottle = minimumRefreshCfgThrottle
}
logging.Infof("Ready for new connections")

proxyClient := &proxy.Client{
Port: port,
Expand All @@ -539,6 +560,26 @@ func main() {
RefreshCfgThrottle: refreshCfgThrottle,
}

if *performConnectivityTestsOnStartup {
wg := &sync.WaitGroup{}
wg.Add(len(cfgs))

for index, instanceConfig := range cfgs {
logging.Infof("Checking connection to instance %s...", instanceConfig.Instance)
go func(index int, instance string, isPublic bool, client *proxy.Client) {
defer wg.Done()
err := checkInstanceConnectivity(instance, isPublic, client)

if err != nil {
log.Fatalf("%v", instance, err)
}
}(index, instanceConfig.Instance, instanceConfig.IsPublic, proxyClient)
}
wg.Wait()
}

logging.Infof("Ready for new connections")

signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT)

Expand Down
10 changes: 10 additions & 0 deletions cmd/cloud_sql_proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ func listenInstance(dst chan<- proxy.Conn, cfg instanceConfig) (net.Listener, er
type instanceConfig struct {
Instance string
Network, Address string
IsPublic bool
}

// loopbackForNet maps a network (e.g. tcp6) to the loopback address for that
Expand Down Expand Up @@ -273,6 +274,15 @@ func parseInstanceConfig(dir, instance string, cl *http.Client) (instanceConfig,
if err != nil {
return instanceConfig{}, err
}

// Check to see if one of the addresses is public or not
// and mark that on the config
for _, mapping := range inst.IpAddresses {
if mapping.Type == "PRIMARY" {
ret.IsPublic = true
}
}

if inst.BackendType == "FIRST_GEN" {
logging.Errorf("WARNING: proxy client does not support first generation Cloud SQL instances.")
return instanceConfig{}, fmt.Errorf("%q is a first generation instance", instance)
Expand Down

0 comments on commit ca0e769

Please sign in to comment.