mirror of https://github.com/grpc/grpc-java.git
xds: support multiple xDS servers in bootstrap file (#6493)
Support bootstrap file containing multiple xDS servers, with each has its own server URI and channel credential options. Multiple xDS servers are provided in case of one not reachable. For now, we would only use the first one. This change also formats JSON strings in bootstrap related tests and add several tests for parsing bootstrap JSON as completeness. Implementation of XdsClient is changed to take in a list of xDS servers. But still, we only use the first one.
This commit is contained in:
parent
29638780ae
commit
d168632f82
|
|
@ -73,29 +73,34 @@ public abstract class Bootstrapper {
|
|||
@SuppressWarnings("unchecked")
|
||||
Map<String, ?> rawBootstrap = (Map<String, ?>) JsonParser.parse(rawData);
|
||||
|
||||
Map<String, ?> rawServerConfig = JsonUtil.getObject(rawBootstrap, "xds_server");
|
||||
if (rawServerConfig == null) {
|
||||
throw new IOException("Invalid bootstrap: 'xds_server' does not exist.");
|
||||
List<ServerInfo> servers = new ArrayList<>();
|
||||
List<?> rawServerConfigs = JsonUtil.getList(rawBootstrap, "xds_servers");
|
||||
if (rawServerConfigs == null) {
|
||||
throw new IOException("Invalid bootstrap: 'xds_servers' does not exist.");
|
||||
}
|
||||
// Field "server_uri" is required.
|
||||
String serverUri = JsonUtil.getString(rawServerConfig, "server_uri");
|
||||
List<Map<String, ?>> serverConfigList = JsonUtil.checkObjectList(rawServerConfigs);
|
||||
for (Map<String, ?> serverConfig : serverConfigList) {
|
||||
String serverUri = JsonUtil.getString(serverConfig, "server_uri");
|
||||
if (serverUri == null) {
|
||||
throw new IOException("Invalid bootstrap: 'xds_server : server_uri' does not exist.");
|
||||
throw new IOException("Invalid bootstrap: 'xds_servers' contains unknown server.");
|
||||
}
|
||||
List<ChannelCreds> channelCredsOptions = new ArrayList<>();
|
||||
List<?> rawChannelCredsList = JsonUtil.getList(rawServerConfig, "channel_creds");
|
||||
List<?> rawChannelCredsList = JsonUtil.getList(serverConfig, "channel_creds");
|
||||
// List of channel creds is optional.
|
||||
if (rawChannelCredsList != null) {
|
||||
List<Map<String, ?>> channelCredsList = JsonUtil.checkObjectList(rawChannelCredsList);
|
||||
for (Map<String, ?> channelCreds : channelCredsList) {
|
||||
String type = JsonUtil.getString(channelCreds, "type");
|
||||
if (type == null) {
|
||||
throw new IOException("Invalid bootstrap: 'channel_creds' contains unknown type.");
|
||||
throw new IOException("Invalid bootstrap: 'xds_servers' contains server with "
|
||||
+ "unknown type 'channel_creds'.");
|
||||
}
|
||||
ChannelCreds creds = new ChannelCreds(type, JsonUtil.getObject(channelCreds, "config"));
|
||||
channelCredsOptions.add(creds);
|
||||
}
|
||||
}
|
||||
servers.add(new ServerInfo(serverUri, channelCredsOptions));
|
||||
}
|
||||
|
||||
Node.Builder nodeBuilder = Node.newBuilder();
|
||||
Map<String, ?> rawNode = JsonUtil.getObject(rawBootstrap, "node");
|
||||
|
|
@ -133,7 +138,7 @@ public abstract class Bootstrapper {
|
|||
}
|
||||
nodeBuilder.setBuildVersion(GrpcUtil.getGrpcBuildVersion());
|
||||
|
||||
return new BootstrapInfo(serverUri, channelCredsOptions, nodeBuilder.build());
|
||||
return new BootstrapInfo(servers, nodeBuilder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -202,27 +207,49 @@ public abstract class Bootstrapper {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data class containing xDS server information, such as server URI and channel credential
|
||||
* options to be used for communication.
|
||||
*/
|
||||
@Immutable
|
||||
static class ServerInfo {
|
||||
private final String serverUri;
|
||||
private final List<ChannelCreds> channelCredsList;
|
||||
|
||||
@VisibleForTesting
|
||||
ServerInfo(String serverUri, List<ChannelCreds> channelCredsList) {
|
||||
this.serverUri = serverUri;
|
||||
this.channelCredsList = channelCredsList;
|
||||
}
|
||||
|
||||
String getServerUri() {
|
||||
return serverUri;
|
||||
}
|
||||
|
||||
List<ChannelCreds> getChannelCredentials() {
|
||||
return Collections.unmodifiableList(channelCredsList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data class containing the results of reading bootstrap.
|
||||
*/
|
||||
@Immutable
|
||||
public static class BootstrapInfo {
|
||||
private final String serverUri;
|
||||
private final List<ChannelCreds> channelCredsList;
|
||||
private List<ServerInfo> servers;
|
||||
private final Node node;
|
||||
|
||||
@VisibleForTesting
|
||||
BootstrapInfo(String serverUri, List<ChannelCreds> channelCredsList, Node node) {
|
||||
this.serverUri = serverUri;
|
||||
this.channelCredsList = channelCredsList;
|
||||
BootstrapInfo(List<ServerInfo> servers, Node node) {
|
||||
this.servers = servers;
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URI the traffic director to be connected to.
|
||||
* Returns the list of xDS servers to be connected to.
|
||||
*/
|
||||
String getServerUri() {
|
||||
return serverUri;
|
||||
List<ServerInfo> getServers() {
|
||||
return Collections.unmodifiableList(servers);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -232,11 +259,5 @@ public abstract class Bootstrapper {
|
|||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the credentials to use when communicating with the xDS server.
|
||||
*/
|
||||
List<ChannelCreds> getChannelCredentials() {
|
||||
return Collections.unmodifiableList(channelCredsList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import io.grpc.internal.ObjectPool;
|
|||
import io.grpc.util.GracefulSwitchLoadBalancer;
|
||||
import io.grpc.xds.Bootstrapper.BootstrapInfo;
|
||||
import io.grpc.xds.Bootstrapper.ChannelCreds;
|
||||
import io.grpc.xds.Bootstrapper.ServerInfo;
|
||||
import io.grpc.xds.EnvoyProtoData.DropOverload;
|
||||
import io.grpc.xds.EnvoyProtoData.Locality;
|
||||
import io.grpc.xds.EnvoyProtoData.LocalityLbEndpoints;
|
||||
|
|
@ -204,9 +205,21 @@ final class LookasideLb extends LoadBalancer {
|
|||
new ErrorPicker(Status.UNAVAILABLE.withCause(e)));
|
||||
return;
|
||||
}
|
||||
|
||||
List<ServerInfo> serverList = bootstrapInfo.getServers();
|
||||
if (serverList.isEmpty()) {
|
||||
lookasideLbHelper.updateBalancingState(
|
||||
TRANSIENT_FAILURE,
|
||||
new ErrorPicker(
|
||||
Status.UNAVAILABLE
|
||||
.withDescription("No traffic director provided by bootstrap")));
|
||||
return;
|
||||
}
|
||||
// Currently we only support using the first server from bootstrap.
|
||||
ServerInfo serverInfo = serverList.get(0);
|
||||
channel = initLbChannel(
|
||||
lookasideLbHelper, bootstrapInfo.getServerUri(),
|
||||
bootstrapInfo.getChannelCredentials());
|
||||
lookasideLbHelper, serverInfo.getServerUri(),
|
||||
serverInfo.getChannelCredentials());
|
||||
xdsClientRef = new RefCountedXdsClientObjectPool(new XdsClientFactory() {
|
||||
@Override
|
||||
XdsClient createXdsClient() {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ import io.grpc.alts.GoogleDefaultChannelBuilder;
|
|||
import io.grpc.internal.BackoffPolicy;
|
||||
import io.grpc.stub.StreamObserver;
|
||||
import io.grpc.xds.Bootstrapper.ChannelCreds;
|
||||
import io.grpc.xds.Bootstrapper.ServerInfo;
|
||||
import io.grpc.xds.EnvoyProtoData.DropOverload;
|
||||
import io.grpc.xds.EnvoyProtoData.Locality;
|
||||
import io.grpc.xds.EnvoyProtoData.LocalityLbEndpoints;
|
||||
|
|
@ -135,19 +136,14 @@ final class XdsClientImpl extends XdsClient {
|
|||
private String ldsResourceName;
|
||||
|
||||
XdsClientImpl(
|
||||
// URI of the management server to be connected to.
|
||||
String serverUri,
|
||||
List<ServerInfo> servers, // list of management servers
|
||||
Node node,
|
||||
// List of channel credential configurations for the channel to management server.
|
||||
// Should pick the first supported one.
|
||||
List<ChannelCreds> channelCredsList,
|
||||
SynchronizationContext syncContext,
|
||||
ScheduledExecutorService timeService,
|
||||
BackoffPolicy.Provider backoffPolicyProvider,
|
||||
Stopwatch stopwatch) {
|
||||
this(
|
||||
buildChannel(checkNotNull(serverUri, "serverUri"),
|
||||
checkNotNull(channelCredsList, "channelCredsList")),
|
||||
buildChannel(checkNotNull(servers, "servers")),
|
||||
node,
|
||||
syncContext,
|
||||
timeService,
|
||||
|
|
@ -319,9 +315,15 @@ final class XdsClientImpl extends XdsClient {
|
|||
}
|
||||
|
||||
/**
|
||||
* Builds a channel to the given server URI with the first supported channel creds config.
|
||||
* Builds a channel to one of the provided management servers.
|
||||
*
|
||||
* <p>Note: currently we only support using the first server.
|
||||
*/
|
||||
private static ManagedChannel buildChannel(String serverUri,List<ChannelCreds> channelCredsList) {
|
||||
private static ManagedChannel buildChannel(List<ServerInfo> servers) {
|
||||
checkArgument(!servers.isEmpty(), "No management server provided.");
|
||||
ServerInfo serverInfo = servers.get(0);
|
||||
String serverUri = serverInfo.getServerUri();
|
||||
List<ChannelCreds> channelCredsList = serverInfo.getChannelCredentials();
|
||||
ManagedChannel ch = null;
|
||||
// Use the first supported channel credentials configuration.
|
||||
// Currently, only "google_default" is supported.
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import io.grpc.internal.GrpcAttributes;
|
|||
import io.grpc.internal.JsonParser;
|
||||
import io.grpc.xds.Bootstrapper.BootstrapInfo;
|
||||
import io.grpc.xds.Bootstrapper.ChannelCreds;
|
||||
import io.grpc.xds.Bootstrapper.ServerInfo;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
|
|
@ -89,13 +90,26 @@ final class XdsNameResolver extends NameResolver {
|
|||
return;
|
||||
}
|
||||
|
||||
String serviceConfig = "{"
|
||||
+ "\"loadBalancingConfig\": ["
|
||||
+ "{\"xds_experimental\" : {"
|
||||
+ "\"balancerName\" : \"" + bootstrapInfo.getServerUri() + "\","
|
||||
+ "\"childPolicy\" : [{\"round_robin\" : {}}]"
|
||||
+ "}}"
|
||||
+ "]}";
|
||||
List<ServerInfo> serverList = bootstrapInfo.getServers();
|
||||
if (serverList.isEmpty()) {
|
||||
listener.onError(
|
||||
Status.UNAVAILABLE.withDescription("No traffic director provided by bootstrap"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Currently we only support using the first server from bootstrap.
|
||||
ServerInfo serverInfo = serverList.get(0);
|
||||
|
||||
String serviceConfig = "{\n"
|
||||
+ " \"loadBalancingConfig\": [\n"
|
||||
+ " {\n"
|
||||
+ " \"xds_experimental\": {\n"
|
||||
+ " \"balancerName\": \"" + serverInfo.getServerUri() + "\",\n"
|
||||
+ " \"childPolicy\": [ {\"round_robin\": {} } ]\n"
|
||||
+ " }\n"
|
||||
+ " }"
|
||||
+ " ]\n"
|
||||
+ "}";
|
||||
Map<String, ?> config;
|
||||
try {
|
||||
config = (Map<String, ?>) JsonParser.parse(serviceConfig);
|
||||
|
|
@ -108,7 +122,7 @@ final class XdsNameResolver extends NameResolver {
|
|||
Attributes.newBuilder()
|
||||
.set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, config)
|
||||
.set(XDS_NODE, bootstrapInfo.getNode())
|
||||
.set(XDS_CHANNEL_CREDS_LIST, bootstrapInfo.getChannelCredentials())
|
||||
.set(XDS_CHANNEL_CREDS_LIST, serverInfo.getChannelCredentials())
|
||||
.build();
|
||||
ResolutionResult result =
|
||||
ResolutionResult.newBuilder()
|
||||
|
|
|
|||
|
|
@ -18,13 +18,16 @@ package io.grpc.xds;
|
|||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.protobuf.Struct;
|
||||
import com.google.protobuf.Value;
|
||||
import io.envoyproxy.envoy.api.v2.core.Locality;
|
||||
import io.envoyproxy.envoy.api.v2.core.Node;
|
||||
import io.grpc.internal.GrpcUtil;
|
||||
import io.grpc.xds.Bootstrapper.BootstrapInfo;
|
||||
import io.grpc.xds.Bootstrapper.ServerInfo;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
|
@ -38,35 +41,163 @@ public class BootstrapperTest {
|
|||
@Rule public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void parseBootstrap_validData() throws IOException {
|
||||
String rawData = "{"
|
||||
+ "\"node\": {"
|
||||
+ "\"id\": \"ENVOY_NODE_ID\","
|
||||
+ "\"cluster\": \"ENVOY_CLUSTER\","
|
||||
+ "\"locality\": {"
|
||||
+ "\"region\": \"ENVOY_REGION\", \"zone\": \"ENVOY_ZONE\", \"sub_zone\": \"ENVOY_SUBZONE\""
|
||||
+ "},"
|
||||
+ "\"metadata\": {"
|
||||
+ "\"TRAFFICDIRECTOR_INTERCEPTION_PORT\": \"ENVOY_PORT\", "
|
||||
+ "\"TRAFFICDIRECTOR_NETWORK_NAME\": \"VPC_NETWORK_NAME\""
|
||||
+ "}"
|
||||
+ "},"
|
||||
+ "\"xds_server\": {"
|
||||
+ "\"server_uri\": \"trafficdirector.googleapis.com:443\","
|
||||
+ "\"channel_creds\": "
|
||||
+ "[ {\"type\": \"tls\"}, {\"type\": \"loas\"}, {\"type\": \"google_default\"} ]"
|
||||
+ "} "
|
||||
public void parseBootstrap_validData_singleXdsServer() throws IOException {
|
||||
String rawData = "{\n"
|
||||
+ " \"node\": {\n"
|
||||
+ " \"id\": \"ENVOY_NODE_ID\",\n"
|
||||
+ " \"cluster\": \"ENVOY_CLUSTER\",\n"
|
||||
+ " \"locality\": {\n"
|
||||
+ " \"region\": \"ENVOY_REGION\",\n"
|
||||
+ " \"zone\": \"ENVOY_ZONE\",\n"
|
||||
+ " \"sub_zone\": \"ENVOY_SUBZONE\"\n"
|
||||
+ " },\n"
|
||||
+ " \"metadata\": {\n"
|
||||
+ " \"TRAFFICDIRECTOR_INTERCEPTION_PORT\": \"ENVOY_PORT\",\n"
|
||||
+ " \"TRAFFICDIRECTOR_NETWORK_NAME\": \"VPC_NETWORK_NAME\"\n"
|
||||
+ " }\n"
|
||||
+ " },\n"
|
||||
+ " \"xds_servers\": [\n"
|
||||
+ " {\n"
|
||||
+ " \"server_uri\": \"trafficdirector.googleapis.com:443\",\n"
|
||||
+ " \"channel_creds\": [\n"
|
||||
+ " {\"type\": \"tls\"}, {\"type\": \"loas\"}, {\"type\": \"google_default\"}\n"
|
||||
+ " ]\n"
|
||||
+ " }\n"
|
||||
+ " ]\n"
|
||||
+ "}";
|
||||
|
||||
BootstrapInfo info = Bootstrapper.parseConfig(rawData);
|
||||
assertThat(info.getServerUri()).isEqualTo("trafficdirector.googleapis.com:443");
|
||||
assertThat(info.getChannelCredentials()).hasSize(3);
|
||||
assertThat(info.getChannelCredentials().get(0).getType()).isEqualTo("tls");
|
||||
assertThat(info.getChannelCredentials().get(0).getConfig()).isNull();
|
||||
assertThat(info.getChannelCredentials().get(1).getType()).isEqualTo("loas");
|
||||
assertThat(info.getChannelCredentials().get(1).getConfig()).isNull();
|
||||
assertThat(info.getChannelCredentials().get(2).getType()).isEqualTo("google_default");
|
||||
assertThat(info.getChannelCredentials().get(2).getConfig()).isNull();
|
||||
assertThat(info.getServers()).hasSize(1);
|
||||
ServerInfo serverInfo = Iterables.getOnlyElement(info.getServers());
|
||||
assertThat(serverInfo.getServerUri()).isEqualTo("trafficdirector.googleapis.com:443");
|
||||
assertThat(serverInfo.getChannelCredentials()).hasSize(3);
|
||||
assertThat(serverInfo.getChannelCredentials().get(0).getType()).isEqualTo("tls");
|
||||
assertThat(serverInfo.getChannelCredentials().get(0).getConfig()).isNull();
|
||||
assertThat(serverInfo.getChannelCredentials().get(1).getType()).isEqualTo("loas");
|
||||
assertThat(serverInfo.getChannelCredentials().get(1).getConfig()).isNull();
|
||||
assertThat(serverInfo.getChannelCredentials().get(2).getType()).isEqualTo("google_default");
|
||||
assertThat(serverInfo.getChannelCredentials().get(2).getConfig()).isNull();
|
||||
assertThat(info.getNode()).isEqualTo(
|
||||
Node.newBuilder()
|
||||
.setId("ENVOY_NODE_ID")
|
||||
.setCluster("ENVOY_CLUSTER")
|
||||
.setLocality(
|
||||
Locality.newBuilder()
|
||||
.setRegion("ENVOY_REGION").setZone("ENVOY_ZONE").setSubZone("ENVOY_SUBZONE"))
|
||||
.setMetadata(
|
||||
Struct.newBuilder()
|
||||
.putFields("TRAFFICDIRECTOR_INTERCEPTION_PORT",
|
||||
Value.newBuilder().setStringValue("ENVOY_PORT").build())
|
||||
.putFields("TRAFFICDIRECTOR_NETWORK_NAME",
|
||||
Value.newBuilder().setStringValue("VPC_NETWORK_NAME").build())
|
||||
.build())
|
||||
.setBuildVersion(GrpcUtil.getGrpcBuildVersion())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseBootstrap_validData_multipleXdsServers() throws IOException {
|
||||
String rawData = "{\n"
|
||||
+ " \"node\": {\n"
|
||||
+ " \"id\": \"ENVOY_NODE_ID\",\n"
|
||||
+ " \"cluster\": \"ENVOY_CLUSTER\",\n"
|
||||
+ " \"locality\": {\n"
|
||||
+ " \"region\": \"ENVOY_REGION\",\n"
|
||||
+ " \"zone\": \"ENVOY_ZONE\",\n"
|
||||
+ " \"sub_zone\": \"ENVOY_SUBZONE\"\n"
|
||||
+ " },\n"
|
||||
+ " \"metadata\": {\n"
|
||||
+ " \"TRAFFICDIRECTOR_INTERCEPTION_PORT\": \"ENVOY_PORT\",\n"
|
||||
+ " \"TRAFFICDIRECTOR_NETWORK_NAME\": \"VPC_NETWORK_NAME\"\n"
|
||||
+ " }\n"
|
||||
+ " },\n"
|
||||
+ " \"xds_servers\": [\n"
|
||||
+ " {\n"
|
||||
+ " \"server_uri\": \"trafficdirector-foo.googleapis.com:443\",\n"
|
||||
+ " \"channel_creds\": [\n"
|
||||
+ " {\"type\": \"tls\"}, {\"type\": \"loas\"}, {\"type\": \"google_default\"}\n"
|
||||
+ " ]\n"
|
||||
+ " },\n"
|
||||
+ " {\n"
|
||||
+ " \"server_uri\": \"trafficdirector-bar.googleapis.com:443\",\n"
|
||||
+ " \"channel_creds\": []\n"
|
||||
+ " }\n"
|
||||
+ " ]\n"
|
||||
+ "}";
|
||||
|
||||
BootstrapInfo info = Bootstrapper.parseConfig(rawData);
|
||||
assertThat(info.getServers()).hasSize(2);
|
||||
List<ServerInfo> serverInfoList = info.getServers();
|
||||
assertThat(serverInfoList.get(0).getServerUri())
|
||||
.isEqualTo("trafficdirector-foo.googleapis.com:443");
|
||||
assertThat(serverInfoList.get(0).getChannelCredentials()).hasSize(3);
|
||||
assertThat(serverInfoList.get(0).getChannelCredentials().get(0).getType()).isEqualTo("tls");
|
||||
assertThat(serverInfoList.get(0).getChannelCredentials().get(0).getConfig()).isNull();
|
||||
assertThat(serverInfoList.get(0).getChannelCredentials().get(1).getType()).isEqualTo("loas");
|
||||
assertThat(serverInfoList.get(0).getChannelCredentials().get(1).getConfig()).isNull();
|
||||
assertThat(serverInfoList.get(0).getChannelCredentials().get(2).getType())
|
||||
.isEqualTo("google_default");
|
||||
assertThat(serverInfoList.get(0).getChannelCredentials().get(2).getConfig()).isNull();
|
||||
assertThat(serverInfoList.get(1).getServerUri())
|
||||
.isEqualTo("trafficdirector-bar.googleapis.com:443");
|
||||
assertThat(serverInfoList.get(1).getChannelCredentials()).isEmpty();
|
||||
assertThat(info.getNode()).isEqualTo(
|
||||
Node.newBuilder()
|
||||
.setId("ENVOY_NODE_ID")
|
||||
.setCluster("ENVOY_CLUSTER")
|
||||
.setLocality(
|
||||
Locality.newBuilder()
|
||||
.setRegion("ENVOY_REGION").setZone("ENVOY_ZONE").setSubZone("ENVOY_SUBZONE"))
|
||||
.setMetadata(
|
||||
Struct.newBuilder()
|
||||
.putFields("TRAFFICDIRECTOR_INTERCEPTION_PORT",
|
||||
Value.newBuilder().setStringValue("ENVOY_PORT").build())
|
||||
.putFields("TRAFFICDIRECTOR_NETWORK_NAME",
|
||||
Value.newBuilder().setStringValue("VPC_NETWORK_NAME").build())
|
||||
.build())
|
||||
.setBuildVersion(GrpcUtil.getGrpcBuildVersion())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseBootstrap_IgnoreIrrelevantFields() throws IOException {
|
||||
String rawData = "{\n"
|
||||
+ " \"node\": {\n"
|
||||
+ " \"id\": \"ENVOY_NODE_ID\",\n"
|
||||
+ " \"cluster\": \"ENVOY_CLUSTER\",\n"
|
||||
+ " \"locality\": {\n"
|
||||
+ " \"region\": \"ENVOY_REGION\",\n"
|
||||
+ " \"zone\": \"ENVOY_ZONE\",\n"
|
||||
+ " \"sub_zone\": \"ENVOY_SUBZONE\"\n"
|
||||
+ " },\n"
|
||||
+ " \"metadata\": {\n"
|
||||
+ " \"TRAFFICDIRECTOR_INTERCEPTION_PORT\": \"ENVOY_PORT\",\n"
|
||||
+ " \"TRAFFICDIRECTOR_NETWORK_NAME\": \"VPC_NETWORK_NAME\"\n"
|
||||
+ " }\n"
|
||||
+ " },\n"
|
||||
+ " \"xds_servers\": [\n"
|
||||
+ " {\n"
|
||||
+ " \"server_uri\": \"trafficdirector.googleapis.com:443\",\n"
|
||||
+ " \"ignore\": \"something irrelevant\","
|
||||
+ " \"channel_creds\": [\n"
|
||||
+ " {\"type\": \"tls\"}, {\"type\": \"loas\"}, {\"type\": \"google_default\"}\n"
|
||||
+ " ]\n"
|
||||
+ " }\n"
|
||||
+ " ],\n"
|
||||
+ " \"ignore\": \"something irrelevant\"\n"
|
||||
+ "}";
|
||||
|
||||
BootstrapInfo info = Bootstrapper.parseConfig(rawData);
|
||||
assertThat(info.getServers()).hasSize(1);
|
||||
ServerInfo serverInfo = Iterables.getOnlyElement(info.getServers());
|
||||
assertThat(serverInfo.getServerUri()).isEqualTo("trafficdirector.googleapis.com:443");
|
||||
assertThat(serverInfo.getChannelCredentials()).hasSize(3);
|
||||
assertThat(serverInfo.getChannelCredentials().get(0).getType()).isEqualTo("tls");
|
||||
assertThat(serverInfo.getChannelCredentials().get(0).getConfig()).isNull();
|
||||
assertThat(serverInfo.getChannelCredentials().get(1).getType()).isEqualTo("loas");
|
||||
assertThat(serverInfo.getChannelCredentials().get(1).getConfig()).isNull();
|
||||
assertThat(serverInfo.getChannelCredentials().get(2).getType()).isEqualTo("google_default");
|
||||
assertThat(serverInfo.getChannelCredentials().get(2).getConfig()).isNull();
|
||||
assertThat(info.getNode()).isEqualTo(
|
||||
Node.newBuilder()
|
||||
.setId("ENVOY_NODE_ID")
|
||||
|
|
@ -95,14 +226,12 @@ public class BootstrapperTest {
|
|||
|
||||
@Test
|
||||
public void parseBootstrap_minimumRequiredFields() throws IOException {
|
||||
String rawData = "{"
|
||||
+ "\"xds_server\": {"
|
||||
+ "\"server_uri\": \"trafficdirector.googleapis.com:443\""
|
||||
+ "}"
|
||||
String rawData = "{\n"
|
||||
+ " \"xds_servers\": []\n"
|
||||
+ "}";
|
||||
|
||||
BootstrapInfo info = Bootstrapper.parseConfig(rawData);
|
||||
assertThat(info.getServerUri()).isEqualTo("trafficdirector.googleapis.com:443");
|
||||
assertThat(info.getServers()).isEmpty();
|
||||
assertThat(info.getNode())
|
||||
.isEqualTo(
|
||||
Node.newBuilder()
|
||||
|
|
@ -112,48 +241,78 @@ public class BootstrapperTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void parseBootstrap_noXdsServer() throws IOException {
|
||||
String rawData = "{"
|
||||
+ "\"node\": {"
|
||||
+ "\"id\": \"ENVOY_NODE_ID\","
|
||||
+ "\"cluster\": \"ENVOY_CLUSTER\","
|
||||
+ "\"locality\": {"
|
||||
+ "\"region\": \"ENVOY_REGION\", \"zone\": \"ENVOY_ZONE\", \"sub_zone\": \"ENVOY_SUBZONE\""
|
||||
+ "},"
|
||||
+ "\"metadata\": {"
|
||||
+ "\"TRAFFICDIRECTOR_INTERCEPTION_PORT\": \"ENVOY_PORT\", "
|
||||
+ "\"TRAFFICDIRECTOR_NETWORK_NAME\": \"VPC_NETWORK_NAME\""
|
||||
+ "}"
|
||||
+ "}"
|
||||
public void parseBootstrap_minimalUsableData() throws IOException {
|
||||
String rawData = "{\n"
|
||||
+ " \"xds_servers\": [\n"
|
||||
+ " {\n"
|
||||
+ " \"server_uri\": \"trafficdirector.googleapis.com:443\"\n"
|
||||
+ " }\n"
|
||||
+ " ]\n"
|
||||
+ "}";
|
||||
|
||||
BootstrapInfo info = Bootstrapper.parseConfig(rawData);
|
||||
assertThat(info.getServers()).hasSize(1);
|
||||
ServerInfo serverInfo = Iterables.getOnlyElement(info.getServers());
|
||||
assertThat(serverInfo.getServerUri()).isEqualTo("trafficdirector.googleapis.com:443");
|
||||
assertThat(serverInfo.getChannelCredentials()).isEmpty();
|
||||
assertThat(info.getNode())
|
||||
.isEqualTo(
|
||||
Node.newBuilder()
|
||||
.setBuildVersion(
|
||||
GrpcUtil.getGrpcBuildVersion())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseBootstrap_noXdsServers() throws IOException {
|
||||
String rawData = "{\n"
|
||||
+ " \"node\": {\n"
|
||||
+ " \"id\": \"ENVOY_NODE_ID\",\n"
|
||||
+ " \"cluster\": \"ENVOY_CLUSTER\",\n"
|
||||
+ " \"locality\": {\n"
|
||||
+ " \"region\": \"ENVOY_REGION\",\n"
|
||||
+ " \"zone\": \"ENVOY_ZONE\",\n"
|
||||
+ " \"sub_zone\": \"ENVOY_SUBZONE\"\n"
|
||||
+ " },\n"
|
||||
+ " \"metadata\": {\n"
|
||||
+ " \"TRAFFICDIRECTOR_INTERCEPTION_PORT\": \"ENVOY_PORT\",\n"
|
||||
+ " \"TRAFFICDIRECTOR_NETWORK_NAME\": \"VPC_NETWORK_NAME\"\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
+ "}";
|
||||
|
||||
thrown.expect(IOException.class);
|
||||
thrown.expectMessage("Invalid bootstrap: 'xds_server' does not exist.");
|
||||
thrown.expectMessage("Invalid bootstrap: 'xds_servers' does not exist.");
|
||||
Bootstrapper.parseConfig(rawData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseBootstrap_noServerUri() throws IOException {
|
||||
public void parseBootstrap_serverWithoutServerUri() throws IOException {
|
||||
String rawData = "{"
|
||||
+ "\"node\": {"
|
||||
+ "\"id\": \"ENVOY_NODE_ID\","
|
||||
+ "\"cluster\": \"ENVOY_CLUSTER\","
|
||||
+ "\"locality\": {"
|
||||
+ "\"region\": \"ENVOY_REGION\", \"zone\": \"ENVOY_ZONE\", \"sub_zone\": \"ENVOY_SUBZONE\""
|
||||
+ "},"
|
||||
+ "\"metadata\": {"
|
||||
+ "\"TRAFFICDIRECTOR_INTERCEPTION_PORT\": \"ENVOY_PORT\", "
|
||||
+ "\"TRAFFICDIRECTOR_NETWORK_NAME\": \"VPC_NETWORK_NAME\""
|
||||
+ "}"
|
||||
+ "},"
|
||||
+ "\"xds_server\": {"
|
||||
+ "\"channel_creds\": "
|
||||
+ "[ {\"type\": \"tls\"}, {\"type\": \"loas\"} ]"
|
||||
+ "} "
|
||||
+ " \"node\": {\n"
|
||||
+ " \"id\": \"ENVOY_NODE_ID\",\n"
|
||||
+ " \"cluster\": \"ENVOY_CLUSTER\",\n"
|
||||
+ " \"locality\": {\n"
|
||||
+ " \"region\": \"ENVOY_REGION\",\n"
|
||||
+ " \"zone\": \"ENVOY_ZONE\",\n"
|
||||
+ " \"sub_zone\": \"ENVOY_SUBZONE\"\n"
|
||||
+ " },\n"
|
||||
+ " \"metadata\": {\n"
|
||||
+ " \"TRAFFICDIRECTOR_INTERCEPTION_PORT\": \"ENVOY_PORT\",\n"
|
||||
+ " \"TRAFFICDIRECTOR_NETWORK_NAME\": \"VPC_NETWORK_NAME\"\n"
|
||||
+ " }\n"
|
||||
+ " },\n"
|
||||
+ " \"xds_servers\": [\n"
|
||||
+ " {\n"
|
||||
+ " \"channel_creds\": [\n"
|
||||
+ " {\"type\": \"tls\"}, {\"type\": \"loas\"}\n"
|
||||
+ " ]\n"
|
||||
+ " }\n"
|
||||
+ " ]\n "
|
||||
+ "}";
|
||||
|
||||
thrown.expect(IOException.class);
|
||||
thrown.expectMessage("Invalid bootstrap: 'xds_server : server_uri' does not exist.");
|
||||
thrown.expectMessage("Invalid bootstrap: 'xds_servers' contains unknown server.");
|
||||
Bootstrapper.parseConfig(rawData);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ import io.grpc.stub.StreamObserver;
|
|||
import io.grpc.testing.GrpcCleanupRule;
|
||||
import io.grpc.xds.Bootstrapper.BootstrapInfo;
|
||||
import io.grpc.xds.Bootstrapper.ChannelCreds;
|
||||
import io.grpc.xds.Bootstrapper.ServerInfo;
|
||||
import io.grpc.xds.EnvoyProtoData.DropOverload;
|
||||
import io.grpc.xds.EnvoyProtoData.Locality;
|
||||
import io.grpc.xds.EnvoyProtoData.LocalityLbEndpoints;
|
||||
|
|
@ -489,9 +490,10 @@ public class LookasideLbTest {
|
|||
|
||||
@Test
|
||||
public void handleResolvedAddress_withBootstrap() throws Exception {
|
||||
BootstrapInfo bootstrapInfo = new BootstrapInfo(
|
||||
"trafficdirector.googleapis.com", ImmutableList.<ChannelCreds>of(),
|
||||
Node.getDefaultInstance());
|
||||
List<ServerInfo> serverList =
|
||||
ImmutableList.of(
|
||||
new ServerInfo("trafficdirector.googleapis.com", ImmutableList.<ChannelCreds>of()));
|
||||
BootstrapInfo bootstrapInfo = new BootstrapInfo(serverList, Node.getDefaultInstance());
|
||||
doReturn(bootstrapInfo).when(bootstrapper).readBootstrap();
|
||||
|
||||
String lbConfigRaw =
|
||||
|
|
|
|||
|
|
@ -111,8 +111,11 @@ public class XdsNameResolverTest {
|
|||
Bootstrapper bootstrapper = new Bootstrapper() {
|
||||
@Override
|
||||
public BootstrapInfo readBootstrap() {
|
||||
return new BootstrapInfo("trafficdirector.googleapis.com",
|
||||
ImmutableList.of(loasCreds, googleDefaultCreds), FAKE_BOOTSTRAP_NODE);
|
||||
List<ServerInfo> serverList =
|
||||
ImmutableList.of(
|
||||
new ServerInfo("trafficdirector.googleapis.com",
|
||||
ImmutableList.of(loasCreds, googleDefaultCreds)));
|
||||
return new BootstrapInfo(serverList, FAKE_BOOTSTRAP_NODE);
|
||||
}
|
||||
};
|
||||
XdsNameResolver resolver = new XdsNameResolver("foo.googleapis.com", bootstrapper);
|
||||
|
|
@ -143,6 +146,24 @@ public class XdsNameResolverTest {
|
|||
.containsExactly(loasCreds, googleDefaultCreds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolve_bootstrapProvidesNoTrafficDirectorInfo() {
|
||||
Bootstrapper bootstrapper = new Bootstrapper() {
|
||||
@Override
|
||||
public BootstrapInfo readBootstrap() {
|
||||
return new BootstrapInfo(ImmutableList.<ServerInfo>of(), FAKE_BOOTSTRAP_NODE);
|
||||
}
|
||||
};
|
||||
|
||||
XdsNameResolver resolver = new XdsNameResolver("foo.googleapis.com", bootstrapper);
|
||||
resolver.start(mockListener);
|
||||
ArgumentCaptor<Status> statusCaptor = ArgumentCaptor.forClass(null);
|
||||
verify(mockListener).onError(statusCaptor.capture());
|
||||
assertThat(statusCaptor.getValue().getCode()).isEqualTo(Code.UNAVAILABLE);
|
||||
assertThat(statusCaptor.getValue().getDescription())
|
||||
.isEqualTo("No traffic director provided by bootstrap");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolve_failToBootstrap() {
|
||||
Bootstrapper bootstrapper = new Bootstrapper() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue