io.grpc.xds.client.BootstrapperImpl Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2021 The gRPC Authors
*
* 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 io.grpc.xds.client;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import io.grpc.Internal;
import io.grpc.InternalLogId;
import io.grpc.internal.GrpcUtil;
import io.grpc.internal.GrpcUtil.GrpcBuildVersion;
import io.grpc.internal.JsonParser;
import io.grpc.internal.JsonUtil;
import io.grpc.xds.client.EnvoyProtoData.Node;
import io.grpc.xds.client.XdsLogger.XdsLogLevel;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* A {@link Bootstrapper} implementation that reads xDS configurations from local file system.
*/
@Internal
public abstract class BootstrapperImpl extends Bootstrapper {
// Client features.
@VisibleForTesting
public static final String CLIENT_FEATURE_DISABLE_OVERPROVISIONING =
"envoy.lb.does_not_support_overprovisioning";
@VisibleForTesting
public static final String CLIENT_FEATURE_RESOURCE_IN_SOTW = "xds.config.resource-in-sotw";
// Server features.
private static final String SERVER_FEATURE_IGNORE_RESOURCE_DELETION = "ignore_resource_deletion";
private static final String SERVER_FEATURE_TRUSTED_XDS_SERVER = "trusted_xds_server";
protected final XdsLogger logger;
protected FileReader reader = LocalFileReader.INSTANCE;
protected BootstrapperImpl() {
logger = XdsLogger.withLogId(InternalLogId.allocate("bootstrapper", null));
}
protected abstract String getJsonContent() throws IOException, XdsInitializationException;
protected abstract Object getImplSpecificConfig(Map serverConfig, String serverUri)
throws XdsInitializationException;
/**
* Reads and parses bootstrap config. The config is expected to be in JSON format.
*/
@SuppressWarnings("unchecked")
@Override
public BootstrapInfo bootstrap() throws XdsInitializationException {
String jsonContent;
try {
jsonContent = getJsonContent();
} catch (IOException e) {
throw new XdsInitializationException("Fail to read bootstrap file", e);
}
Map rawBootstrap;
try {
rawBootstrap = (Map) JsonParser.parse(jsonContent);
} catch (IOException e) {
throw new XdsInitializationException("Failed to parse JSON", e);
}
logger.log(XdsLogLevel.DEBUG, "Bootstrap configuration:\n{0}", rawBootstrap);
return bootstrap(rawBootstrap);
}
@Override
public BootstrapInfo bootstrap(Map rawData) throws XdsInitializationException {
return bootstrapBuilder(rawData).build();
}
protected BootstrapInfo.Builder bootstrapBuilder(Map rawData)
throws XdsInitializationException {
BootstrapInfo.Builder builder = BootstrapInfo.builder();
List> rawServerConfigs = JsonUtil.getList(rawData, "xds_servers");
if (rawServerConfigs == null) {
throw new XdsInitializationException("Invalid bootstrap: 'xds_servers' does not exist.");
}
List servers = parseServerInfos(rawServerConfigs, logger);
builder.servers(servers);
Node.Builder nodeBuilder = Node.newBuilder();
Map rawNode = JsonUtil.getObject(rawData, "node");
if (rawNode != null) {
String id = JsonUtil.getString(rawNode, "id");
if (id != null) {
logger.log(XdsLogLevel.INFO, "Node id: {0}", id);
nodeBuilder.setId(id);
}
String cluster = JsonUtil.getString(rawNode, "cluster");
if (cluster != null) {
logger.log(XdsLogLevel.INFO, "Node cluster: {0}", cluster);
nodeBuilder.setCluster(cluster);
}
Map metadata = JsonUtil.getObject(rawNode, "metadata");
if (metadata != null) {
nodeBuilder.setMetadata(metadata);
}
Map rawLocality = JsonUtil.getObject(rawNode, "locality");
if (rawLocality != null) {
String region = "";
String zone = "";
String subZone = "";
if (rawLocality.containsKey("region")) {
region = JsonUtil.getString(rawLocality, "region");
}
if (rawLocality.containsKey("zone")) {
zone = JsonUtil.getString(rawLocality, "zone");
}
if (rawLocality.containsKey("sub_zone")) {
subZone = JsonUtil.getString(rawLocality, "sub_zone");
}
logger.log(XdsLogLevel.INFO, "Locality region: {0}, zone: {1}, subZone: {2}",
region, zone, subZone);
Locality locality = Locality.create(region, zone, subZone);
nodeBuilder.setLocality(locality);
}
}
GrpcBuildVersion buildVersion = GrpcUtil.getGrpcBuildVersion();
logger.log(XdsLogLevel.INFO, "Build version: {0}", buildVersion);
nodeBuilder.setBuildVersion(buildVersion.toString());
nodeBuilder.setUserAgentName(buildVersion.getUserAgent());
nodeBuilder.setUserAgentVersion(buildVersion.getImplementationVersion());
nodeBuilder.addClientFeatures(CLIENT_FEATURE_DISABLE_OVERPROVISIONING);
nodeBuilder.addClientFeatures(CLIENT_FEATURE_RESOURCE_IN_SOTW);
builder.node(nodeBuilder.build());
Map certProvidersBlob = JsonUtil.getObject(rawData, "certificate_providers");
if (certProvidersBlob != null) {
logger.log(XdsLogLevel.INFO, "Configured with {0} cert providers", certProvidersBlob.size());
Map certProviders = new HashMap<>(certProvidersBlob.size());
for (String name : certProvidersBlob.keySet()) {
Map valueMap = JsonUtil.getObject(certProvidersBlob, name);
String pluginName =
checkForNull(JsonUtil.getString(valueMap, "plugin_name"), "plugin_name");
logger.log(XdsLogLevel.INFO, "cert provider: {0}, plugin name: {1}", name, pluginName);
Map config = checkForNull(JsonUtil.getObject(valueMap, "config"), "config");
CertificateProviderInfo certificateProviderInfo =
CertificateProviderInfo.create(pluginName, config);
certProviders.put(name, certificateProviderInfo);
}
builder.certProviders(certProviders);
}
String serverResourceId =
JsonUtil.getString(rawData, "server_listener_resource_name_template");
logger.log(
XdsLogLevel.INFO, "server_listener_resource_name_template: {0}", serverResourceId);
builder.serverListenerResourceNameTemplate(serverResourceId);
String clientDefaultListener =
JsonUtil.getString(rawData, "client_default_listener_resource_name_template");
logger.log(
XdsLogLevel.INFO, "client_default_listener_resource_name_template: {0}",
clientDefaultListener);
if (clientDefaultListener != null) {
builder.clientDefaultListenerResourceNameTemplate(clientDefaultListener);
}
Map rawAuthoritiesMap =
JsonUtil.getObject(rawData, "authorities");
ImmutableMap.Builder authorityInfoMapBuilder = ImmutableMap.builder();
if (rawAuthoritiesMap != null) {
logger.log(
XdsLogLevel.INFO, "Configured with {0} xDS server authorities", rawAuthoritiesMap.size());
for (String authorityName : rawAuthoritiesMap.keySet()) {
logger.log(XdsLogLevel.INFO, "xDS server authority: {0}", authorityName);
Map rawAuthority = JsonUtil.getObject(rawAuthoritiesMap, authorityName);
String clientListnerTemplate =
JsonUtil.getString(rawAuthority, "client_listener_resource_name_template");
logger.log(
XdsLogLevel.INFO, "client_listener_resource_name_template: {0}", clientListnerTemplate);
String prefix = XDSTP_SCHEME + "//" + authorityName + "/";
if (clientListnerTemplate == null) {
clientListnerTemplate = prefix + "envoy.config.listener.v3.Listener/%s";
} else if (!clientListnerTemplate.startsWith(prefix)) {
throw new XdsInitializationException(
"client_listener_resource_name_template: '" + clientListnerTemplate
+ "' does not start with " + prefix);
}
List> rawAuthorityServers = JsonUtil.getList(rawAuthority, "xds_servers");
List authorityServers;
if (rawAuthorityServers == null || rawAuthorityServers.isEmpty()) {
authorityServers = servers;
} else {
authorityServers = parseServerInfos(rawAuthorityServers, logger);
}
authorityInfoMapBuilder.put(
authorityName, AuthorityInfo.create(clientListnerTemplate, authorityServers));
}
builder.authorities(authorityInfoMapBuilder.buildOrThrow());
}
return builder;
}
private List parseServerInfos(List> rawServerConfigs, XdsLogger logger)
throws XdsInitializationException {
logger.log(XdsLogLevel.INFO, "Configured with {0} xDS servers", rawServerConfigs.size());
ImmutableList.Builder servers = ImmutableList.builder();
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy