Skip to content

Commit ad0971e

Browse files
authored
xds: fix parsing RouteLookupClusterSpecifier mistake (#8641)
- Partially revert the change of RlsProtoData.java in #8612 by removing `public` accessor - Have grpc-xds no longer strongly depend on grpc-rls. The application will need grpc-rls as runtime dependencies if they need route lookup feature in xds. - Parse RouteLookupServiceClusterSpecifierPlugin config to the Json/Map representation of `io.grpc.lookup.v1.RouteLookupClusterSpecifier` instead of `io.grpc.rls.RlsProtoData.RouteLookupConfig`
1 parent b3579db commit ad0971e

File tree

5 files changed

+109
-147
lines changed

5 files changed

+109
-147
lines changed

rls/src/main/java/io/grpc/rls/RlsProtoData.java

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import com.google.common.base.Objects;
2626
import com.google.common.collect.ImmutableList;
2727
import com.google.common.collect.ImmutableMap;
28-
import io.grpc.Internal;
2928
import io.grpc.rls.RlsProtoData.GrpcKeyBuilder.Name;
3029
import java.util.HashSet;
3130
import java.util.List;
@@ -36,8 +35,7 @@
3635
import javax.annotation.concurrent.Immutable;
3736

3837
/** RlsProtoData is a collection of internal representation of RouteLookupService proto messages. */
39-
@Internal
40-
public final class RlsProtoData {
38+
final class RlsProtoData {
4139

4240
private RlsProtoData() {}
4341

@@ -142,7 +140,7 @@ public String toString() {
142140

143141
/** A config object for gRPC RouteLookupService. */
144142
@Immutable
145-
public static final class RouteLookupConfig {
143+
static final class RouteLookupConfig {
146144

147145
private static final long MAX_AGE_MILLIS = TimeUnit.MINUTES.toMillis(5);
148146
private static final long MAX_CACHE_SIZE = 5 * 1024 * 1024;
@@ -164,8 +162,7 @@ public static final class RouteLookupConfig {
164162
@Nullable
165163
private final String defaultTarget;
166164

167-
/** Constructor. */
168-
public RouteLookupConfig(
165+
RouteLookupConfig(
169166
List<GrpcKeyBuilder> grpcKeyBuilders,
170167
String lookupService,
171168
long lookupServiceTimeoutInMillis,
@@ -336,16 +333,15 @@ private static void checkUniqueName(List<GrpcKeyBuilder> grpcKeyBuilders) {
336333
* is true, one of the specified names must be present for the keybuilder to match.
337334
*/
338335
@Immutable
339-
public static final class NameMatcher {
336+
static final class NameMatcher {
340337

341338
private final String key;
342339

343340
private final ImmutableList<String> names;
344341

345342
private final boolean optional;
346343

347-
/** Constructor. */
348-
public NameMatcher(String key, List<String> names, @Nullable Boolean optional) {
344+
NameMatcher(String key, List<String> names, @Nullable Boolean optional) {
349345
this.key = checkNotNull(key, "key");
350346
this.names = ImmutableList.copyOf(checkNotNull(names, "names"));
351347
this.optional = optional != null ? optional : true;
@@ -398,7 +394,7 @@ public String toString() {
398394
}
399395

400396
/** GrpcKeyBuilder is a configuration to construct headers consumed by route lookup service. */
401-
public static final class GrpcKeyBuilder {
397+
static final class GrpcKeyBuilder {
402398

403399
private final ImmutableList<Name> names;
404400

@@ -407,7 +403,7 @@ public static final class GrpcKeyBuilder {
407403
private final ImmutableMap<String, String> constantKeys;
408404

409405
/** Constructor. All args should be nonnull. Headers should head unique keys. */
410-
public GrpcKeyBuilder(
406+
GrpcKeyBuilder(
411407
List<Name> names, List<NameMatcher> headers, ExtraKeys extraKeys,
412408
Map<String, String> constantKeys) {
413409
checkState(names != null && !names.isEmpty(), "names cannot be empty");
@@ -486,7 +482,7 @@ public String toString() {
486482
* required and includes the proto package name. The method name may be omitted, in which case
487483
* any method on the given service is matched.
488484
*/
489-
public static final class Name {
485+
static final class Name {
490486

491487
private final String service;
492488

@@ -497,7 +493,7 @@ public Name(String service) {
497493
}
498494

499495
/** The primary constructor. */
500-
public Name(String service, String method) {
496+
Name(String service, String method) {
501497
checkState(
502498
!checkNotNull(service, "service").isEmpty(),
503499
"service must not be empty or null");
@@ -542,7 +538,7 @@ public String toString() {
542538
}
543539

544540
@AutoValue
545-
public abstract static class ExtraKeys {
541+
abstract static class ExtraKeys {
546542
static final ExtraKeys DEFAULT = create(null, null, null);
547543

548544
@Nullable abstract String host();
@@ -551,7 +547,7 @@ public abstract static class ExtraKeys {
551547

552548
@Nullable abstract String method();
553549

554-
public static ExtraKeys create(
550+
static ExtraKeys create(
555551
@Nullable String host, @Nullable String service, @Nullable String method) {
556552
return new AutoValue_RlsProtoData_ExtraKeys(host, service, method);
557553
}

xds/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ dependencies {
3939
libraries.autovalue_annotation,
4040
libraries.opencensus_proto,
4141
libraries.protobuf_util
42-
implementation project(path: ':grpc-rls')
4342
def nettyDependency = implementation project(':grpc-netty')
4443

44+
testImplementation project(':grpc-rls')
4545
testImplementation project(':grpc-core').sourceSets.test.output
4646

4747
annotationProcessor libraries.autovalue

xds/src/main/java/io/grpc/xds/MessagePrinter.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616

1717
package io.grpc.xds;
1818

19+
import com.google.protobuf.Descriptors.Descriptor;
1920
import com.google.protobuf.InvalidProtocolBufferException;
21+
import com.google.protobuf.Message;
2022
import com.google.protobuf.MessageOrBuilder;
2123
import com.google.protobuf.TypeRegistry;
2224
import com.google.protobuf.util.JsonFormat;
@@ -46,7 +48,7 @@ private static class LazyHolder {
4648
static final JsonFormat.Printer printer = newPrinter();
4749

4850
private static JsonFormat.Printer newPrinter() {
49-
TypeRegistry registry =
51+
TypeRegistry.Builder registry =
5052
TypeRegistry.newBuilder()
5153
.add(Listener.getDescriptor())
5254
.add(io.envoyproxy.envoy.api.v2.Listener.getDescriptor())
@@ -71,9 +73,20 @@ private static JsonFormat.Printer newPrinter() {
7173
.add(io.envoyproxy.envoy.config.cluster.aggregate.v2alpha.ClusterConfig
7274
.getDescriptor())
7375
.add(ClusterLoadAssignment.getDescriptor())
74-
.add(io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.getDescriptor())
75-
.build();
76-
return JsonFormat.printer().usingTypeRegistry(registry);
76+
.add(io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.getDescriptor());
77+
try {
78+
@SuppressWarnings("unchecked")
79+
Class<? extends Message> routeLookupClusterSpecifierClass =
80+
(Class<? extends Message>)
81+
Class.forName("io.grpc.lookup.v1.RouteLookupClusterSpecifier");
82+
Descriptor descriptor =
83+
(Descriptor)
84+
routeLookupClusterSpecifierClass.getDeclaredMethod("getDescriptor").invoke(null);
85+
registry.add(descriptor);
86+
} catch (Exception e) {
87+
// Ignore. In most cases RouteLookup is not required.
88+
}
89+
return JsonFormat.printer().usingTypeRegistry(registry.build());
7790
}
7891
}
7992

xds/src/main/java/io/grpc/xds/RouteLookupServiceClusterSpecifierPlugin.java

Lines changed: 34 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,14 @@
1717
package io.grpc.xds;
1818

1919
import com.google.auto.value.AutoValue;
20+
import com.google.common.collect.ImmutableMap;
2021
import com.google.protobuf.Any;
2122
import com.google.protobuf.InvalidProtocolBufferException;
2223
import com.google.protobuf.Message;
23-
import com.google.protobuf.util.Durations;
24-
import io.grpc.lookup.v1.GrpcKeyBuilder;
25-
import io.grpc.lookup.v1.GrpcKeyBuilder.ExtraKeys;
26-
import io.grpc.lookup.v1.GrpcKeyBuilder.Name;
27-
import io.grpc.lookup.v1.NameMatcher;
28-
import io.grpc.lookup.v1.RouteLookupConfig;
29-
import io.grpc.rls.RlsProtoData;
30-
import java.util.ArrayList;
31-
import java.util.List;
24+
import io.grpc.internal.JsonParser;
25+
import io.grpc.internal.JsonUtil;
26+
import java.io.IOException;
27+
import java.util.Map;
3228

3329
/** The ClusterSpecifierPlugin for RouteLookup policy. */
3430
final class RouteLookupServiceClusterSpecifierPlugin implements ClusterSpecifierPlugin {
@@ -49,84 +45,49 @@ public String[] typeUrls() {
4945
}
5046

5147
@Override
48+
@SuppressWarnings("unchecked")
5249
public ConfigOrError<RlsPluginConfig> parsePlugin(Message rawProtoMessage) {
5350
if (!(rawProtoMessage instanceof Any)) {
5451
return ConfigOrError.fromError("Invalid config type: " + rawProtoMessage.getClass());
5552
}
56-
57-
Any anyMessage = (Any) rawProtoMessage;
58-
RouteLookupConfig configProto;
59-
try {
60-
configProto = anyMessage.unpack(RouteLookupConfig.class);
61-
} catch (InvalidProtocolBufferException e) {
62-
return ConfigOrError.fromError("Invalid proto: " + e);
63-
}
6453
try {
65-
List<GrpcKeyBuilder> keyBuildersProto = configProto.getGrpcKeybuildersList();
66-
List<RlsProtoData.GrpcKeyBuilder> keyBuilders =
67-
new ArrayList<>(keyBuildersProto.size());
68-
for (GrpcKeyBuilder keyBuilderProto : keyBuildersProto) {
69-
List<Name> namesProto = keyBuilderProto.getNamesList();
70-
List<RlsProtoData.GrpcKeyBuilder.Name> names = new ArrayList<>(namesProto.size());
71-
for (Name nameProto : namesProto) {
72-
if (nameProto.getMethod().isEmpty()) {
73-
names.add(new RlsProtoData.GrpcKeyBuilder.Name(nameProto.getService()));
74-
} else {
75-
names.add(
76-
new RlsProtoData.GrpcKeyBuilder.Name(
77-
nameProto.getService(), nameProto.getMethod()));
78-
}
79-
}
80-
81-
List<NameMatcher> headersProto = keyBuilderProto.getHeadersList();
82-
List<RlsProtoData.NameMatcher> headers = new ArrayList<>(headersProto.size());
83-
for (NameMatcher headerProto : headersProto) {
84-
headers.add(
85-
new RlsProtoData.NameMatcher(
86-
headerProto.getKey(), headerProto.getNamesList(),
87-
headerProto.getRequiredMatch()));
88-
}
89-
90-
String host = null;
91-
String service = null;
92-
String method = null;
93-
if (keyBuilderProto.hasExtraKeys()) {
94-
ExtraKeys extraKeysProto = keyBuilderProto.getExtraKeys();
95-
host = extraKeysProto.getHost();
96-
service = extraKeysProto.getService();
97-
method = extraKeysProto.getMethod();
98-
}
99-
RlsProtoData.ExtraKeys extraKeys =
100-
RlsProtoData.ExtraKeys.create(host, service, method);
101-
102-
RlsProtoData.GrpcKeyBuilder keyBuilder =
103-
new RlsProtoData.GrpcKeyBuilder(
104-
names, headers, extraKeys, keyBuilderProto.getConstantKeysMap());
105-
keyBuilders.add(keyBuilder);
54+
Any anyMessage = (Any) rawProtoMessage;
55+
Class<? extends Message> protoClass;
56+
try {
57+
protoClass =
58+
(Class<? extends Message>)
59+
Class.forName("io.grpc.lookup.v1.RouteLookupClusterSpecifier");
60+
} catch (ClassNotFoundException e) {
61+
return ConfigOrError.fromError("Dependency for 'io.grpc:grpc-rls' is missing: " + e);
62+
}
63+
Message configProto;
64+
try {
65+
configProto = anyMessage.unpack(protoClass);
66+
} catch (InvalidProtocolBufferException e) {
67+
return ConfigOrError.fromError("Invalid proto: " + e);
68+
}
69+
String jsonString = MessagePrinter.print(configProto);
70+
try {
71+
Map<String, ?> jsonMap = (Map<String, ?>) JsonParser.parse(jsonString);
72+
Map<String, ?> config = JsonUtil.getObject(jsonMap, "routeLookupConfig");
73+
return ConfigOrError.fromConfig(RlsPluginConfig.create(config));
74+
} catch (IOException e) {
75+
return ConfigOrError.fromError(
76+
"Unable to parse RouteLookupClusterSpecifier: " + jsonString);
10677
}
107-
RlsProtoData.RouteLookupConfig config = new RlsProtoData.RouteLookupConfig(
108-
keyBuilders,
109-
configProto.getLookupService(),
110-
Durations.toMillis(configProto.getLookupServiceTimeout()),
111-
configProto.hasMaxAge() ? Durations.toMillis(configProto.getMaxAge()) : null,
112-
configProto.hasStaleAge() ? Durations.toMillis(configProto.getStaleAge()) : null,
113-
configProto.getCacheSizeBytes(),
114-
configProto.getValidTargetsList(),
115-
configProto.getDefaultTarget());
116-
return ConfigOrError.fromConfig(RlsPluginConfig.create(config));
11778
} catch (RuntimeException e) {
118-
return ConfigOrError.fromError(
119-
"Error parsing RouteLookupConfig: \n" + configProto + "\n reason: " + e);
79+
return ConfigOrError.fromError("Error parsing RouteLookupConfig: " + e);
12080
}
12181
}
12282

12383
@AutoValue
12484
abstract static class RlsPluginConfig implements PluginConfig {
12585

126-
abstract RlsProtoData.RouteLookupConfig config();
86+
abstract ImmutableMap<String, ?> config();
12787

128-
static RlsPluginConfig create(RlsProtoData.RouteLookupConfig config) {
129-
return new AutoValue_RouteLookupServiceClusterSpecifierPlugin_RlsPluginConfig(config);
88+
static RlsPluginConfig create(Map<String, ?> config) {
89+
return new AutoValue_RouteLookupServiceClusterSpecifierPlugin_RlsPluginConfig(
90+
ImmutableMap.copyOf(config));
13091
}
13192

13293
@Override

0 commit comments

Comments
 (0)