Skip to content

Commit

Permalink
pkg/srv: package for SRV utilities
Browse files Browse the repository at this point in the history
Trying to decouple the v2 client from SRV code. Can't move
into discovery/ since that creates a circular dependency. So,
give up and move all the SRV code into a new package.
  • Loading branch information
Anthony Romano committed May 5, 2017
1 parent db6f45e commit 07ad181
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 198 deletions.
19 changes: 19 additions & 0 deletions client/discover.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,27 @@

package client

import (
"github.com/coreos/etcd/pkg/srv"
)

// Discoverer is an interface that wraps the Discover method.
type Discoverer interface {
// Discover looks up the etcd servers for the domain.
Discover(domain string) ([]string, error)
}

type srvDiscover struct{}

// NewSRVDiscover constructs a new Discoverer that uses the stdlib to lookup SRV records.
func NewSRVDiscover() Discoverer {
return &srvDiscover{}
}

func (d *srvDiscover) Discover(domain string) ([]string, error) {
srvs, err := srv.GetClient("etcd-client", domain)
if err != nil {
return nil, err
}
return srvs.Endpoints, nil
}
65 changes: 0 additions & 65 deletions client/srv.go

This file was deleted.

102 changes: 0 additions & 102 deletions client/srv_test.go

This file was deleted.

14 changes: 9 additions & 5 deletions embed/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ import (
"net/url"
"strings"

"github.com/coreos/etcd/discovery"
"github.com/coreos/etcd/etcdserver"
"github.com/coreos/etcd/pkg/cors"
"github.com/coreos/etcd/pkg/netutil"
"github.com/coreos/etcd/pkg/srv"
"github.com/coreos/etcd/pkg/transport"
"github.com/coreos/etcd/pkg/types"

Expand Down Expand Up @@ -321,11 +321,15 @@ func (cfg *Config) PeerURLsMapAndToken(which string) (urlsmap types.URLsMap, tok
urlsmap[cfg.Name] = cfg.APUrls
token = cfg.Durl
case cfg.DNSCluster != "":
var clusterStr string
clusterStr, err = discovery.SRVGetCluster(cfg.Name, cfg.DNSCluster, cfg.APUrls)
if err != nil {
return nil, "", err
clusterStrs, cerr := srv.GetCluster("etcd-server", cfg.Name, cfg.DNSCluster, cfg.APUrls)
if cerr != nil {
plog.Errorf("couldn't resolve during SRV discovery (%v)", cerr)
return nil, "", cerr
}
for _, s := range clusterStrs {
plog.Noticef("got bootstrap from DNS for etcd-server at %s", s)
}
clusterStr := strings.Join(clusterStrs, ",")
if strings.Contains(clusterStr, "https://") && cfg.PeerTLSInfo.CAFile == "" {
cfg.PeerTLSInfo.ServerName = cfg.DNSCluster
}
Expand Down
5 changes: 3 additions & 2 deletions etcdmain/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,20 @@ import (
"fmt"
"os"

"github.com/coreos/etcd/client"
"github.com/coreos/etcd/pkg/srv"
"github.com/coreos/etcd/pkg/transport"
)

func discoverEndpoints(dns string, ca string, insecure bool) (endpoints []string) {
if dns == "" {
return nil
}
endpoints, err := client.NewSRVDiscover().Discover(dns)
srvs, err := srv.GetClient("etcd-client", dns)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
endpoints = srvs.Endpoints
plog.Infof("discovered the cluster %s from %s", endpoints, dns)
if insecure {
return endpoints
Expand Down
78 changes: 57 additions & 21 deletions discovery/srv.go → pkg/srv/srv.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package discovery
package srv

import (
"fmt"
Expand All @@ -25,23 +25,21 @@ import (

var (
// indirection for testing
lookupSRV = net.LookupSRV
lookupSRV = net.LookupSRV // net.DefaultResolver.LookupSRV when ctxs don't conflict
resolveTCPAddr = net.ResolveTCPAddr
)

// SRVGetCluster gets the cluster information via DNS discovery.
// TODO(barakmich): Currently ignores priority and weight (as they don't make as much sense for a bootstrap)
// GetCluster gets the cluster information via DNS discovery.
// Also sees each entry as a separate instance.
func SRVGetCluster(name, dns string, apurls types.URLs) (string, error) {
func GetCluster(service, name, dns string, apurls types.URLs) ([]string, error) {
tempName := int(0)
tcp2ap := make(map[string]url.URL)

// First, resolve the apurls
for _, url := range apurls {
tcpAddr, err := resolveTCPAddr("tcp", url.Host)
if err != nil {
plog.Errorf("couldn't resolve host %s during SRV discovery", url.Host)
return "", err
return nil, err
}
tcp2ap[tcpAddr.String()] = url
}
Expand All @@ -55,9 +53,9 @@ func SRVGetCluster(name, dns string, apurls types.URLs) (string, error) {
for _, srv := range addrs {
port := fmt.Sprintf("%d", srv.Port)
host := net.JoinHostPort(srv.Target, port)
tcpAddr, err := resolveTCPAddr("tcp", host)
if err != nil {
plog.Warningf("couldn't resolve host %s during SRV discovery", host)
tcpAddr, terr := resolveTCPAddr("tcp", host)
if terr != nil {
terr = err
continue
}
n := ""
Expand All @@ -73,31 +71,69 @@ func SRVGetCluster(name, dns string, apurls types.URLs) (string, error) {
shortHost := strings.TrimSuffix(srv.Target, ".")
urlHost := net.JoinHostPort(shortHost, port)
stringParts = append(stringParts, fmt.Sprintf("%s=%s://%s", n, scheme, urlHost))
plog.Noticef("got bootstrap from DNS for %s at %s://%s", service, scheme, urlHost)
if ok && url.Scheme != scheme {
plog.Errorf("bootstrap at %s from DNS for %s has scheme mismatch with expected peer %s", scheme+"://"+urlHost, service, url.String())
err = fmt.Errorf("bootstrap at %s from DNS for %s has scheme mismatch with expected peer %s", scheme+"://"+urlHost, service, url.String())
}
}
if len(stringParts) == 0 {
return err
}
return nil
}

failCount := 0
err := updateNodeMap("etcd-server-ssl", "https")
err := updateNodeMap(service+"-ssl", "https")
srvErr := make([]string, 2)
if err != nil {
srvErr[0] = fmt.Sprintf("error querying DNS SRV records for _etcd-server-ssl %s", err)
srvErr[0] = fmt.Sprintf("error querying DNS SRV records for _%s-ssl %s", service, err)
failCount++
}
err = updateNodeMap("etcd-server", "http")
err = updateNodeMap(service, "http")
if err != nil {
srvErr[1] = fmt.Sprintf("error querying DNS SRV records for _etcd-server %s", err)
srvErr[1] = fmt.Sprintf("error querying DNS SRV records for _%s %s", service, err)
failCount++
}
if failCount == 2 {
plog.Warningf(srvErr[0])
plog.Warningf(srvErr[1])
plog.Errorf("SRV discovery failed: too many errors querying DNS SRV records")
return "", err
return nil, fmt.Errorf("srv: too many errors querying DNS SRV records (%q, %q)", srvErr[0], srvErr[1])
}
return stringParts, nil
}

type SRVClients struct {
Endpoints []string
SRVs []*net.SRV
}

// GetClient looks up the client endpoints for a service and domain.
func GetClient(service, domain string) (*SRVClients, error) {
var urls []*url.URL
var srvs []*net.SRV

updateURLs := func(service, scheme string) error {
_, addrs, err := lookupSRV(service, "tcp", domain)
if err != nil {
return err
}
for _, srv := range addrs {
urls = append(urls, &url.URL{
Scheme: scheme,
Host: net.JoinHostPort(srv.Target, fmt.Sprintf("%d", srv.Port)),
})
}
srvs = append(srvs, addrs...)
return nil
}

errHTTPS := updateURLs(service+"-ssl", "https")
errHTTP := updateURLs(service, "http")

if errHTTPS != nil && errHTTP != nil {
return nil, fmt.Errorf("dns lookup errors: %s and %s", errHTTPS, errHTTP)
}

endpoints := make([]string, len(urls))
for i := range urls {
endpoints[i] = urls[i].String()
}
return strings.Join(stringParts, ","), nil
return &SRVClients{Endpoints: endpoints, SRVs: srvs}, nil
}
Loading

0 comments on commit 07ad181

Please sign in to comment.