Remove BPA from Makefile
[icn.git] / cmd / bpa-operator / vendor / google.golang.org / grpc / naming / dns_resolver.go
1 /*
2  *
3  * Copyright 2017 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
19 package naming
20
21 import (
22         "context"
23         "errors"
24         "fmt"
25         "net"
26         "strconv"
27         "time"
28
29         "google.golang.org/grpc/grpclog"
30 )
31
32 const (
33         defaultPort = "443"
34         defaultFreq = time.Minute * 30
35 )
36
37 var (
38         errMissingAddr  = errors.New("missing address")
39         errWatcherClose = errors.New("watcher has been closed")
40
41         lookupHost = net.DefaultResolver.LookupHost
42         lookupSRV  = net.DefaultResolver.LookupSRV
43 )
44
45 // NewDNSResolverWithFreq creates a DNS Resolver that can resolve DNS names, and
46 // create watchers that poll the DNS server using the frequency set by freq.
47 func NewDNSResolverWithFreq(freq time.Duration) (Resolver, error) {
48         return &dnsResolver{freq: freq}, nil
49 }
50
51 // NewDNSResolver creates a DNS Resolver that can resolve DNS names, and create
52 // watchers that poll the DNS server using the default frequency defined by defaultFreq.
53 func NewDNSResolver() (Resolver, error) {
54         return NewDNSResolverWithFreq(defaultFreq)
55 }
56
57 // dnsResolver handles name resolution for names following the DNS scheme
58 type dnsResolver struct {
59         // frequency of polling the DNS server that the watchers created by this resolver will use.
60         freq time.Duration
61 }
62
63 // formatIP returns ok = false if addr is not a valid textual representation of an IP address.
64 // If addr is an IPv4 address, return the addr and ok = true.
65 // If addr is an IPv6 address, return the addr enclosed in square brackets and ok = true.
66 func formatIP(addr string) (addrIP string, ok bool) {
67         ip := net.ParseIP(addr)
68         if ip == nil {
69                 return "", false
70         }
71         if ip.To4() != nil {
72                 return addr, true
73         }
74         return "[" + addr + "]", true
75 }
76
77 // parseTarget takes the user input target string, returns formatted host and port info.
78 // If target doesn't specify a port, set the port to be the defaultPort.
79 // If target is in IPv6 format and host-name is enclosed in square brackets, brackets
80 // are stripped when setting the host.
81 // examples:
82 // target: "www.google.com" returns host: "www.google.com", port: "443"
83 // target: "ipv4-host:80" returns host: "ipv4-host", port: "80"
84 // target: "[ipv6-host]" returns host: "ipv6-host", port: "443"
85 // target: ":80" returns host: "localhost", port: "80"
86 // target: ":" returns host: "localhost", port: "443"
87 func parseTarget(target string) (host, port string, err error) {
88         if target == "" {
89                 return "", "", errMissingAddr
90         }
91
92         if ip := net.ParseIP(target); ip != nil {
93                 // target is an IPv4 or IPv6(without brackets) address
94                 return target, defaultPort, nil
95         }
96         if host, port, err := net.SplitHostPort(target); err == nil {
97                 // target has port, i.e ipv4-host:port, [ipv6-host]:port, host-name:port
98                 if host == "" {
99                         // Keep consistent with net.Dial(): If the host is empty, as in ":80", the local system is assumed.
100                         host = "localhost"
101                 }
102                 if port == "" {
103                         // If the port field is empty(target ends with colon), e.g. "[::1]:", defaultPort is used.
104                         port = defaultPort
105                 }
106                 return host, port, nil
107         }
108         if host, port, err := net.SplitHostPort(target + ":" + defaultPort); err == nil {
109                 // target doesn't have port
110                 return host, port, nil
111         }
112         return "", "", fmt.Errorf("invalid target address %v", target)
113 }
114
115 // Resolve creates a watcher that watches the name resolution of the target.
116 func (r *dnsResolver) Resolve(target string) (Watcher, error) {
117         host, port, err := parseTarget(target)
118         if err != nil {
119                 return nil, err
120         }
121
122         if net.ParseIP(host) != nil {
123                 ipWatcher := &ipWatcher{
124                         updateChan: make(chan *Update, 1),
125                 }
126                 host, _ = formatIP(host)
127                 ipWatcher.updateChan <- &Update{Op: Add, Addr: host + ":" + port}
128                 return ipWatcher, nil
129         }
130
131         ctx, cancel := context.WithCancel(context.Background())
132         return &dnsWatcher{
133                 r:      r,
134                 host:   host,
135                 port:   port,
136                 ctx:    ctx,
137                 cancel: cancel,
138                 t:      time.NewTimer(0),
139         }, nil
140 }
141
142 // dnsWatcher watches for the name resolution update for a specific target
143 type dnsWatcher struct {
144         r    *dnsResolver
145         host string
146         port string
147         // The latest resolved address set
148         curAddrs map[string]*Update
149         ctx      context.Context
150         cancel   context.CancelFunc
151         t        *time.Timer
152 }
153
154 // ipWatcher watches for the name resolution update for an IP address.
155 type ipWatcher struct {
156         updateChan chan *Update
157 }
158
159 // Next returns the address resolution Update for the target. For IP address,
160 // the resolution is itself, thus polling name server is unnecessary. Therefore,
161 // Next() will return an Update the first time it is called, and will be blocked
162 // for all following calls as no Update exists until watcher is closed.
163 func (i *ipWatcher) Next() ([]*Update, error) {
164         u, ok := <-i.updateChan
165         if !ok {
166                 return nil, errWatcherClose
167         }
168         return []*Update{u}, nil
169 }
170
171 // Close closes the ipWatcher.
172 func (i *ipWatcher) Close() {
173         close(i.updateChan)
174 }
175
176 // AddressType indicates the address type returned by name resolution.
177 type AddressType uint8
178
179 const (
180         // Backend indicates the server is a backend server.
181         Backend AddressType = iota
182         // GRPCLB indicates the server is a grpclb load balancer.
183         GRPCLB
184 )
185
186 // AddrMetadataGRPCLB contains the information the name resolver for grpclb should provide. The
187 // name resolver used by the grpclb balancer is required to provide this type of metadata in
188 // its address updates.
189 type AddrMetadataGRPCLB struct {
190         // AddrType is the type of server (grpc load balancer or backend).
191         AddrType AddressType
192         // ServerName is the name of the grpc load balancer. Used for authentication.
193         ServerName string
194 }
195
196 // compileUpdate compares the old resolved addresses and newly resolved addresses,
197 // and generates an update list
198 func (w *dnsWatcher) compileUpdate(newAddrs map[string]*Update) []*Update {
199         var res []*Update
200         for a, u := range w.curAddrs {
201                 if _, ok := newAddrs[a]; !ok {
202                         u.Op = Delete
203                         res = append(res, u)
204                 }
205         }
206         for a, u := range newAddrs {
207                 if _, ok := w.curAddrs[a]; !ok {
208                         res = append(res, u)
209                 }
210         }
211         return res
212 }
213
214 func (w *dnsWatcher) lookupSRV() map[string]*Update {
215         newAddrs := make(map[string]*Update)
216         _, srvs, err := lookupSRV(w.ctx, "grpclb", "tcp", w.host)
217         if err != nil {
218                 grpclog.Infof("grpc: failed dns SRV record lookup due to %v.\n", err)
219                 return nil
220         }
221         for _, s := range srvs {
222                 lbAddrs, err := lookupHost(w.ctx, s.Target)
223                 if err != nil {
224                         grpclog.Warningf("grpc: failed load balancer address dns lookup due to %v.\n", err)
225                         continue
226                 }
227                 for _, a := range lbAddrs {
228                         a, ok := formatIP(a)
229                         if !ok {
230                                 grpclog.Errorf("grpc: failed IP parsing due to %v.\n", err)
231                                 continue
232                         }
233                         addr := a + ":" + strconv.Itoa(int(s.Port))
234                         newAddrs[addr] = &Update{Addr: addr,
235                                 Metadata: AddrMetadataGRPCLB{AddrType: GRPCLB, ServerName: s.Target}}
236                 }
237         }
238         return newAddrs
239 }
240
241 func (w *dnsWatcher) lookupHost() map[string]*Update {
242         newAddrs := make(map[string]*Update)
243         addrs, err := lookupHost(w.ctx, w.host)
244         if err != nil {
245                 grpclog.Warningf("grpc: failed dns A record lookup due to %v.\n", err)
246                 return nil
247         }
248         for _, a := range addrs {
249                 a, ok := formatIP(a)
250                 if !ok {
251                         grpclog.Errorf("grpc: failed IP parsing due to %v.\n", err)
252                         continue
253                 }
254                 addr := a + ":" + w.port
255                 newAddrs[addr] = &Update{Addr: addr}
256         }
257         return newAddrs
258 }
259
260 func (w *dnsWatcher) lookup() []*Update {
261         newAddrs := w.lookupSRV()
262         if newAddrs == nil {
263                 // If failed to get any balancer address (either no corresponding SRV for the
264                 // target, or caused by failure during resolution/parsing of the balancer target),
265                 // return any A record info available.
266                 newAddrs = w.lookupHost()
267         }
268         result := w.compileUpdate(newAddrs)
269         w.curAddrs = newAddrs
270         return result
271 }
272
273 // Next returns the resolved address update(delta) for the target. If there's no
274 // change, it will sleep for 30 mins and try to resolve again after that.
275 func (w *dnsWatcher) Next() ([]*Update, error) {
276         for {
277                 select {
278                 case <-w.ctx.Done():
279                         return nil, errWatcherClose
280                 case <-w.t.C:
281                 }
282                 result := w.lookup()
283                 // Next lookup should happen after an interval defined by w.r.freq.
284                 w.t.Reset(w.r.freq)
285                 if len(result) > 0 {
286                         return result, nil
287                 }
288         }
289 }
290
291 func (w *dnsWatcher) Close() {
292         w.cancel()
293 }