1/*
2 *
3 * Copyright 2021 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19package clusterresolver
20
21import (
22	"fmt"
23
24	"google.golang.org/grpc/resolver"
25	"google.golang.org/grpc/serviceconfig"
26)
27
28var (
29	newDNS = func(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {
30		// The dns resolver is registered by the grpc package. So, this call to
31		// resolver.Get() is never expected to return nil.
32		return resolver.Get("dns").Build(target, cc, opts)
33	}
34)
35
36// dnsDiscoveryMechanism watches updates for the given DNS hostname.
37//
38// It implements resolver.ClientConn interface to work with the DNS resolver.
39type dnsDiscoveryMechanism struct {
40	target           string
41	topLevelResolver *resourceResolver
42	r                resolver.Resolver
43
44	addrs          []string
45	updateReceived bool
46}
47
48func newDNSResolver(target string, topLevelResolver *resourceResolver) *dnsDiscoveryMechanism {
49	ret := &dnsDiscoveryMechanism{
50		target:           target,
51		topLevelResolver: topLevelResolver,
52	}
53	r, err := newDNS(resolver.Target{Scheme: "dns", Endpoint: target}, ret, resolver.BuildOptions{})
54	if err != nil {
55		select {
56		case <-topLevelResolver.updateChannel:
57		default:
58		}
59		topLevelResolver.updateChannel <- &resourceUpdate{err: err}
60	}
61	ret.r = r
62	return ret
63}
64
65func (dr *dnsDiscoveryMechanism) lastUpdate() (interface{}, bool) {
66	if !dr.updateReceived {
67		return nil, false
68	}
69	return dr.addrs, true
70}
71
72func (dr *dnsDiscoveryMechanism) resolveNow() {
73	dr.r.ResolveNow(resolver.ResolveNowOptions{})
74}
75
76func (dr *dnsDiscoveryMechanism) stop() {
77	dr.r.Close()
78}
79
80// dnsDiscoveryMechanism needs to implement resolver.ClientConn interface to receive
81// updates from the real DNS resolver.
82
83func (dr *dnsDiscoveryMechanism) UpdateState(state resolver.State) error {
84	dr.topLevelResolver.mu.Lock()
85	defer dr.topLevelResolver.mu.Unlock()
86	addrs := make([]string, len(state.Addresses))
87	for i, a := range state.Addresses {
88		addrs[i] = a.Addr
89	}
90	dr.addrs = addrs
91	dr.updateReceived = true
92	dr.topLevelResolver.generate()
93	return nil
94}
95
96func (dr *dnsDiscoveryMechanism) ReportError(err error) {
97	select {
98	case <-dr.topLevelResolver.updateChannel:
99	default:
100	}
101	dr.topLevelResolver.updateChannel <- &resourceUpdate{err: err}
102}
103
104func (dr *dnsDiscoveryMechanism) NewAddress(addresses []resolver.Address) {
105	dr.UpdateState(resolver.State{Addresses: addresses})
106}
107
108func (dr *dnsDiscoveryMechanism) NewServiceConfig(string) {
109	// This method is deprecated, and service config isn't supported.
110}
111
112func (dr *dnsDiscoveryMechanism) ParseServiceConfig(string) *serviceconfig.ParseResult {
113	return &serviceconfig.ParseResult{Err: fmt.Errorf("service config not supported")}
114}
115