• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #20192

12 Mar 2026 12:40PM UTC coverage: 88.694% (+0.02%) from 88.675%
#20192

push

github

ejona86
Remove InternalResolutionResult from DnsNameResolver

The internal result was needed before 90d0fabb1 allowed addresses to
fail yet still provide attributes and service config. Now the code can
just use the regular API.

This does cause a behavior change where TXT records are looked up even
if address lookup failed, however that's actually what we wanted to
allow in 90d0fabb1 by adding the new API. Also, the TXT code was added
in 2017 and it's now 2026 yet it is still disabled, so it's unlikely to
matter soon.

35460 of 39980 relevant lines covered (88.69%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.47
/../grpclb/src/main/java/io/grpc/grpclb/GrpclbNameResolver.java
1
/*
2
 * Copyright 2020 The gRPC Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package io.grpc.grpclb;
18

19
import com.google.common.annotations.VisibleForTesting;
20
import com.google.common.base.Stopwatch;
21
import io.grpc.Attributes;
22
import io.grpc.EquivalentAddressGroup;
23
import io.grpc.NameResolver;
24
import io.grpc.StatusOr;
25
import io.grpc.internal.DnsNameResolver;
26
import io.grpc.internal.SharedResourceHolder.Resource;
27
import java.net.InetAddress;
28
import java.net.InetSocketAddress;
29
import java.net.SocketAddress;
30
import java.util.ArrayList;
31
import java.util.Collections;
32
import java.util.List;
33
import java.util.concurrent.Executor;
34
import java.util.logging.Level;
35
import java.util.logging.Logger;
36
import javax.annotation.Nullable;
37

38
/**
39
 * A DNS-based {@link NameResolver} with gRPC LB specific add-ons for resolving balancer
40
 * addresses via service records.
41
 *
42
 * @see SecretGrpclbNameResolverProvider
43
 */
44
final class GrpclbNameResolver extends DnsNameResolver {
45

46
  private static final Logger logger = Logger.getLogger(GrpclbNameResolver.class.getName());
1✔
47

48
  // From https://github.com/grpc/proposal/blob/master/A5-grpclb-in-dns.md
49
  private static final String GRPCLB_NAME_PREFIX = "_grpclb._tcp.";
50

51
  GrpclbNameResolver(
52
      @Nullable String nsAuthority,
53
      String name,
54
      Args args,
55
      Resource<Executor> executorResource,
56
      Stopwatch stopwatch,
57
      boolean isAndroid) {
58
    super(nsAuthority, name, args, executorResource, stopwatch, isAndroid);
1✔
59
  }
1✔
60

61
  @Override
62
  protected ResolutionResult doResolve() {
63
    ResolutionResult result = super.doResolve();
1✔
64
    List<EquivalentAddressGroup> balancerAddrs = resolveBalancerAddresses();
1✔
65
    if (!balancerAddrs.isEmpty()) {
1✔
66
      ResolutionResult.Builder resultBuilder = result.toBuilder()
1✔
67
          .setAttributes(result.getAttributes().toBuilder()
1✔
68
              .set(GrpclbConstants.ATTR_LB_ADDRS, balancerAddrs)
1✔
69
              .build());
1✔
70
      if (!result.getAddressesOrError().hasValue()) {
1✔
71
        // While ResolutionResult is powerful enough to communicate attributes simultaneously with
72
        // an address resolution failure, LoadBalancer.ResolvedAddresses isn't yet and so the
73
        // attributes are lost if addresses fail. GrpclbLB will be able to handle the lack of
74
        // addresses since there are LB addresses, so discard the failure for now.
75
        resultBuilder.setAddressesOrError(StatusOr.fromValue(Collections.emptyList()));
1✔
76
      }
77
      result = resultBuilder.build();
1✔
78
    }
79
    return result;
1✔
80
  }
81

82
  private List<EquivalentAddressGroup> resolveBalancerAddresses() {
83
    List<SrvRecord> srvRecords = Collections.emptyList();
1✔
84
    Exception srvRecordsException = null;
1✔
85
    ResourceResolver resourceResolver = getResourceResolver();
1✔
86
    if (resourceResolver != null) {
1✔
87
      try {
88
        // This host behaves "unconventionally" with SRV records - we exclude it here.
89
        if (!getHost().equals("metadata.google.internal.")) {
1✔
90
          srvRecords = resourceResolver.resolveSrv(GRPCLB_NAME_PREFIX + getHost());
1✔
91
        }
92
      } catch (Exception e) {
1✔
93
        srvRecordsException = e;
1✔
94
      }
1✔
95
    }
96
    List<EquivalentAddressGroup> balancerAddresses = new ArrayList<>(srvRecords.size());
1✔
97
    Exception balancerAddressesException = null;
1✔
98
    Level level = Level.WARNING;
1✔
99
    for (SrvRecord record : srvRecords) {
1✔
100
      try {
101
        // Strip trailing dot for appearance's sake. It _should_ be fine either way, but most
102
        // people expect to see it without the dot.
103
        String authority = record.host.substring(0, record.host.length() - 1);
1✔
104
        // But we want to use the trailing dot for the IP lookup. The dot makes the name absolute
105
        // instead of relative and so will avoid the search list like that in resolv.conf.
106
        List<? extends InetAddress> addrs = addressResolver.resolveAddress(record.host);
1✔
107
        List<SocketAddress> sockAddrs = new ArrayList<>(addrs.size());
1✔
108
        for (InetAddress addr : addrs) {
1✔
109
          sockAddrs.add(new InetSocketAddress(addr, record.port));
1✔
110
        }
1✔
111
        Attributes attrs =
112
            Attributes.newBuilder()
1✔
113
                .set(GrpclbConstants.ATTR_LB_ADDR_AUTHORITY, authority)
1✔
114
                .build();
1✔
115
        balancerAddresses.add(
1✔
116
            new EquivalentAddressGroup(Collections.unmodifiableList(sockAddrs), attrs));
1✔
117
      } catch (Exception e) {
×
118
        logger.log(level, "Can't find address for SRV record " + record, e);
×
119
        if (balancerAddressesException == null) {
×
120
          balancerAddressesException = e;
×
121
          level = Level.FINE;
×
122
        }
123
      }
1✔
124
    }
1✔
125
    if (srvRecordsException != null) {
1✔
126
      logger.log(Level.FINE, "SRV lookup failure", srvRecordsException);
1✔
127
    } else if (balancerAddressesException != null && balancerAddresses.isEmpty()) {
1✔
128
      logger.log(Level.FINE, "SRV-provided hostname lookup failure", balancerAddressesException);
×
129
    }
130
    return Collections.unmodifiableList(balancerAddresses);
1✔
131
  }
132

133
  @VisibleForTesting
134
  @Override
135
  protected void setAddressResolver(AddressResolver addressResolver) {
136
    super.setAddressResolver(addressResolver);
1✔
137
  }
1✔
138

139
  @VisibleForTesting
140
  @Override
141
  protected void setResourceResolver(ResourceResolver resourceResolver) {
142
    super.setResourceResolver(resourceResolver);
1✔
143
  }
1✔
144

145
  @VisibleForTesting
146
  @Override
147
  protected String getHost() {
148
    return super.getHost();
1✔
149
  }
150

151
  @VisibleForTesting
152
  static void setEnableTxt(boolean enableTxt) {
153
    DnsNameResolver.enableTxt = enableTxt;
1✔
154
  }
1✔
155
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc