etcd/discovery/srv.go

105 lines
3.2 KiB
Go
Raw Normal View History

2016-05-13 06:51:48 +03:00
// Copyright 2015 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2014-12-25 08:35:11 +03:00
package discovery
import (
"fmt"
"net"
2016-11-18 23:47:21 +03:00
"net/url"
2014-12-25 08:35:11 +03:00
"strings"
"github.com/coreos/etcd/pkg/types"
)
var (
// indirection for testing
lookupSRV = net.LookupSRV
resolveTCPAddr = net.ResolveTCPAddr
2014-12-25 08:35:11 +03:00
)
2016-02-21 16:05:03 +03:00
// SRVGetCluster gets the cluster information via DNS discovery.
2014-12-25 08:35:11 +03:00
// TODO(barakmich): Currently ignores priority and weight (as they don't make as much sense for a bootstrap)
// Also doesn't do any lookups for the token (though it could)
// Also sees each entry as a separate instance.
func SRVGetCluster(name, dns string, defaultToken string, apurls types.URLs) (string, string, error) {
tempName := int(0)
2016-11-18 23:47:21 +03:00
tcp2ap := make(map[string]url.URL)
2014-12-25 08:35:11 +03:00
// First, resolve the apurls
for _, url := range apurls {
tcpAddr, err := resolveTCPAddr("tcp", url.Host)
2014-12-25 08:35:11 +03:00
if err != nil {
2015-06-11 19:48:10 +03:00
plog.Errorf("couldn't resolve host %s during SRV discovery", url.Host)
2014-12-25 08:35:11 +03:00
return "", "", err
}
2016-11-18 23:47:21 +03:00
tcp2ap[tcpAddr.String()] = url
2014-12-25 08:35:11 +03:00
}
2016-11-18 23:47:21 +03:00
stringParts := []string{}
updateNodeMap := func(service, scheme string) error {
2014-12-25 08:35:11 +03:00
_, addrs, err := lookupSRV(service, "tcp", dns)
if err != nil {
return err
}
for _, srv := range addrs {
port := fmt.Sprintf("%d", srv.Port)
host := net.JoinHostPort(srv.Target, port)
tcpAddr, err := resolveTCPAddr("tcp", host)
2014-12-25 08:35:11 +03:00
if err != nil {
2015-06-11 19:48:10 +03:00
plog.Warningf("couldn't resolve host %s during SRV discovery", host)
2014-12-25 08:35:11 +03:00
continue
}
n := ""
2016-11-18 23:47:21 +03:00
url, ok := tcp2ap[tcpAddr.String()]
if ok {
n = name
2014-12-25 08:35:11 +03:00
}
if n == "" {
n = fmt.Sprintf("%d", tempName)
2016-06-30 17:00:01 +03:00
tempName++
2014-12-25 08:35:11 +03:00
}
// SRV records have a trailing dot but URL shouldn't.
shortHost := strings.TrimSuffix(srv.Target, ".")
urlHost := net.JoinHostPort(shortHost, port)
2016-11-18 23:47:21 +03:00
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)
2016-11-18 23:47:21 +03:00
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())
}
2014-12-25 08:35:11 +03:00
}
return nil
}
failCount := 0
2016-11-18 23:47:21 +03:00
err := updateNodeMap("etcd-server-ssl", "https")
srvErr := make([]string, 2)
2014-12-25 08:35:11 +03:00
if err != nil {
srvErr[0] = fmt.Sprintf("error querying DNS SRV records for _etcd-server-ssl %s", err)
2016-06-30 17:00:01 +03:00
failCount++
2014-12-25 08:35:11 +03:00
}
2016-11-18 23:47:21 +03:00
err = updateNodeMap("etcd-server", "http")
2014-12-25 08:35:11 +03:00
if err != nil {
srvErr[1] = fmt.Sprintf("error querying DNS SRV records for _etcd-server %s", err)
2016-06-30 17:00:01 +03:00
failCount++
2014-12-25 08:35:11 +03:00
}
if failCount == 2 {
plog.Warningf(srvErr[0])
plog.Warningf(srvErr[1])
2015-06-11 19:48:10 +03:00
plog.Errorf("SRV discovery failed: too many errors querying DNS SRV records")
2014-12-25 08:35:11 +03:00
return "", "", err
}
return strings.Join(stringParts, ","), defaultToken, nil
}