1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package srv
17
18 import (
19 "fmt"
20 "net"
21 "net/url"
22 "strings"
23
24 "go.etcd.io/etcd/client/pkg/v3/types"
25 )
26
27 var (
28
29 lookupSRV = net.LookupSRV
30 resolveTCPAddr = net.ResolveTCPAddr
31 )
32
33
34
35 func GetCluster(serviceScheme, service, name, dns string, apurls types.URLs) ([]string, error) {
36 tempName := int(0)
37 tcp2ap := make(map[string]url.URL)
38
39
40 for _, url := range apurls {
41 tcpAddr, err := resolveTCPAddr("tcp", url.Host)
42 if err != nil {
43 return nil, err
44 }
45 tcp2ap[tcpAddr.String()] = url
46 }
47
48 stringParts := []string{}
49 updateNodeMap := func(service, scheme string) error {
50 _, addrs, err := lookupSRV(service, "tcp", dns)
51 if err != nil {
52 return err
53 }
54 for _, srv := range addrs {
55 port := fmt.Sprintf("%d", srv.Port)
56 host := net.JoinHostPort(srv.Target, port)
57 tcpAddr, terr := resolveTCPAddr("tcp", host)
58 if terr != nil {
59 err = terr
60 continue
61 }
62 n := ""
63 url, ok := tcp2ap[tcpAddr.String()]
64 if ok {
65 n = name
66 }
67 if n == "" {
68 n = fmt.Sprintf("%d", tempName)
69 tempName++
70 }
71
72 shortHost := strings.TrimSuffix(srv.Target, ".")
73 urlHost := net.JoinHostPort(shortHost, port)
74 if ok && url.Scheme != scheme {
75 err = fmt.Errorf("bootstrap at %s from DNS for %s has scheme mismatch with expected peer %s", scheme+"://"+urlHost, service, url.String())
76 } else {
77 stringParts = append(stringParts, fmt.Sprintf("%s=%s://%s", n, scheme, urlHost))
78 }
79 }
80 if len(stringParts) == 0 {
81 return err
82 }
83 return nil
84 }
85
86 err := updateNodeMap(service, serviceScheme)
87 if err != nil {
88 return nil, fmt.Errorf("error querying DNS SRV records for _%s %s", service, err)
89 }
90 return stringParts, nil
91 }
92
93 type SRVClients struct {
94 Endpoints []string
95 SRVs []*net.SRV
96 }
97
98
99 func GetClient(service, domain string, serviceName string) (*SRVClients, error) {
100 var urls []*url.URL
101 var srvs []*net.SRV
102
103 updateURLs := func(service, scheme string) error {
104 _, addrs, err := lookupSRV(service, "tcp", domain)
105 if err != nil {
106 return err
107 }
108 for _, srv := range addrs {
109 urls = append(urls, &url.URL{
110 Scheme: scheme,
111 Host: net.JoinHostPort(srv.Target, fmt.Sprintf("%d", srv.Port)),
112 })
113 }
114 srvs = append(srvs, addrs...)
115 return nil
116 }
117
118 errHTTPS := updateURLs(GetSRVService(service, serviceName, "https"), "https")
119 errHTTP := updateURLs(GetSRVService(service, serviceName, "http"), "http")
120
121 if errHTTPS != nil && errHTTP != nil {
122 return nil, fmt.Errorf("dns lookup errors: %s and %s", errHTTPS, errHTTP)
123 }
124
125 endpoints := make([]string, len(urls))
126 for i := range urls {
127 endpoints[i] = urls[i].String()
128 }
129 return &SRVClients{Endpoints: endpoints, SRVs: srvs}, nil
130 }
131
132
133 func GetSRVService(service, serviceName string, scheme string) (SRVService string) {
134 if scheme == "https" {
135 service = fmt.Sprintf("%s-ssl", service)
136 }
137
138 if serviceName != "" {
139 return fmt.Sprintf("%s-%s", service, serviceName)
140 }
141 return service
142 }
143
View as plain text