/
LocalConnectionChecker.java
105 lines (101 loc) · 4.69 KB
/
LocalConnectionChecker.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/*
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.cloud.spanner.connection;
import com.google.api.gax.core.NoCredentialsProvider;
import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
import com.google.api.gax.rpc.UnavailableException;
import com.google.api.gax.rpc.UnimplementedException;
import com.google.cloud.spanner.ErrorCode;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.admin.instance.v1.stub.GrpcInstanceAdminStub;
import com.google.cloud.spanner.admin.instance.v1.stub.InstanceAdminStubSettings;
import com.google.spanner.admin.instance.v1.ListInstanceConfigsRequest;
import java.io.IOException;
import org.threeten.bp.Duration;
/**
* Util class for quickly checking whether a local emulator or test server can be found. A common
* configuration error is to add 'localhost' to the connection string or to forget to unset the
* SPANNER_EMULATOR_HOST environment variable. This can cause cryptic error messages. This util
* checks for common configurations and errors and returns a more understandable error message for
* known misconfigurations.
*/
class LocalConnectionChecker {
/**
* Executes a quick check to see if this connection can actually connect to a local emulator host
* or other (mock) test server, if the options point to localhost instead of Cloud Spanner.
*/
void checkLocalConnection(ConnectionOptions options) {
final String emulatorHost = System.getenv("SPANNER_EMULATOR_HOST");
String host = options.getHost() == null ? emulatorHost : options.getHost();
if (host.startsWith("https://")) {
host = host.substring(8);
}
if (host.startsWith("http://")) {
host = host.substring(7);
}
// Only do the check if the host has been set to localhost.
if (host != null && host.startsWith("localhost") && options.isUsePlainText()) {
// Do a quick check to see if anything is actually running on the host.
try {
InstanceAdminStubSettings.Builder testEmulatorSettings =
InstanceAdminStubSettings.newBuilder()
.setCredentialsProvider(NoCredentialsProvider.create())
.setTransportChannelProvider(
InstantiatingGrpcChannelProvider.newBuilder()
.setEndpoint(host)
.setChannelConfigurator(
input -> {
input.usePlaintext();
return input;
})
.build());
testEmulatorSettings
.listInstanceConfigsSettings()
.setSimpleTimeoutNoRetries(Duration.ofSeconds(10L));
try (GrpcInstanceAdminStub stub =
GrpcInstanceAdminStub.create(testEmulatorSettings.build())) {
stub.listInstanceConfigsCallable()
.call(
ListInstanceConfigsRequest.newBuilder()
.setParent(String.format("projects/%s", options.getProjectId()))
.build());
}
} catch (UnavailableException e) {
String msg;
if (options.getHost() != null) {
msg =
String.format(
"The connection string '%s' contains host '%s', but no running"
+ " emulator or other server could be found at that address.\n"
+ "Please check the connection string and/or that the emulator is running.",
options.getUri(), host);
} else {
msg =
String.format(
"The environment variable SPANNER_EMULATOR_HOST has been set to '%s', but no running"
+ " emulator or other server could be found at that address.\n"
+ "Please check the environment variable and/or that the emulator is running.",
emulatorHost);
}
throw SpannerExceptionFactory.newSpannerException(ErrorCode.UNAVAILABLE, msg);
} catch (UnimplementedException e) {
// Ignore, this is probably a local mock server.
} catch (IOException e) {
// Ignore, this method is not checking whether valid credentials have been set.
}
}
}
}