Add NS records and A records for each server. Constructs ns host names using the advertise address of the server.
This commit is contained in:
parent
710c4b0d41
commit
c38906daad
|
@ -65,6 +65,7 @@ type delegate interface {
|
|||
JoinLAN(addrs []string) (n int, err error)
|
||||
RemoveFailedNode(node string) error
|
||||
RPC(method string, args interface{}, reply interface{}) error
|
||||
ServerAddrs() []string
|
||||
SnapshotRPC(args *structs.SnapshotRequest, in io.Reader, out io.Writer, replyFn structs.SnapshotReplyFn) error
|
||||
Shutdown() error
|
||||
Stats() map[string]map[string]string
|
||||
|
|
|
@ -411,6 +411,10 @@ func (c *Client) Stats() map[string]map[string]string {
|
|||
return stats
|
||||
}
|
||||
|
||||
func (c *Client) ServerAddrs() []string {
|
||||
return c.servers.GetServerAddrs()
|
||||
}
|
||||
|
||||
// GetLANCoordinate returns the network coordinate of the current node, as
|
||||
// maintained by Serf.
|
||||
func (c *Client) GetLANCoordinate() (*coordinate.Coordinate, error) {
|
||||
|
|
|
@ -1047,6 +1047,15 @@ func (s *Server) GetWANCoordinate() (*coordinate.Coordinate, error) {
|
|||
return s.serfWAN.GetCoordinate()
|
||||
}
|
||||
|
||||
func (s *Server) ServerAddrs() []string {
|
||||
ret, err := s.router.FindServerAddrs(s.config.Datacenter)
|
||||
if err != nil {
|
||||
s.logger.Printf("[WARN] Unexpected state, no server addresses for datacenter %v, got error: %v", s.config.Datacenter, err)
|
||||
return nil
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Atomically sets a readiness state flag when leadership is obtained, to indicate that server is past its barrier write
|
||||
func (s *Server) setConsistentReadReady() {
|
||||
atomic.StoreInt32(&s.readyForConsistentReads, 1)
|
||||
|
|
|
@ -223,6 +223,15 @@ func (m *Manager) getServerList() serverList {
|
|||
return m.listValue.Load().(serverList)
|
||||
}
|
||||
|
||||
// GetServerAddrs returns a slice with all server addresses
|
||||
func (m *Manager) GetServerAddrs() []string {
|
||||
var ret []string
|
||||
for _, server := range m.getServerList().servers {
|
||||
ret = append(ret, server.Addr.String())
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// saveServerList is a convenience method which hides the locking semantics
|
||||
// of atomic.Value from the caller.
|
||||
func (m *Manager) saveServerList(l serverList) {
|
||||
|
|
|
@ -489,3 +489,25 @@ func (r *Router) GetDatacenterMaps() ([]structs.DatacenterMap, error) {
|
|||
}
|
||||
return maps, nil
|
||||
}
|
||||
|
||||
func (r *Router) FindServerAddrs(datacenter string) ([]string, error) {
|
||||
r.RLock()
|
||||
defer r.RUnlock()
|
||||
|
||||
// Get the list of managers for this datacenter. This will usually just
|
||||
// have one entry, but it's possible to have a user-defined area + WAN.
|
||||
managers, ok := r.managers[datacenter]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("datacenter %v not found", datacenter)
|
||||
}
|
||||
|
||||
var ret []string
|
||||
// Try each manager until we get a server.
|
||||
for _, manager := range managers {
|
||||
if manager.IsOffline() {
|
||||
continue
|
||||
}
|
||||
ret = append(ret, manager.GetServerAddrs()...)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
|
46
agent/dns.go
46
agent/dns.go
|
@ -372,6 +372,7 @@ PARSE:
|
|||
INVALID:
|
||||
d.logger.Printf("[WARN] dns: QName invalid: %s", qName)
|
||||
d.addSOA(d.domain, resp)
|
||||
d.addNSAndARecordsForDomain(resp)
|
||||
resp.SetRcode(req, dns.RcodeNameError)
|
||||
}
|
||||
|
||||
|
@ -414,6 +415,7 @@ RPC:
|
|||
// If we have no address, return not found!
|
||||
if out.NodeServices == nil {
|
||||
d.addSOA(d.domain, resp)
|
||||
d.addNSAndARecordsForDomain(resp)
|
||||
resp.SetRcode(req, dns.RcodeNameError)
|
||||
return
|
||||
}
|
||||
|
@ -427,6 +429,9 @@ RPC:
|
|||
if records != nil {
|
||||
resp.Answer = append(resp.Answer, records...)
|
||||
}
|
||||
|
||||
// Add NS record and A record
|
||||
d.addNSAndARecordsForDomain(resp)
|
||||
}
|
||||
|
||||
// formatNodeRecord takes a Node and returns an A, AAAA, or CNAME record
|
||||
|
@ -641,6 +646,7 @@ RPC:
|
|||
// If we have no nodes, return not found!
|
||||
if len(out.Nodes) == 0 {
|
||||
d.addSOA(d.domain, resp)
|
||||
d.addNSAndARecordsForDomain(resp)
|
||||
resp.SetRcode(req, dns.RcodeNameError)
|
||||
return
|
||||
}
|
||||
|
@ -656,6 +662,9 @@ RPC:
|
|||
d.serviceNodeRecords(datacenter, out.Nodes, req, resp, ttl)
|
||||
}
|
||||
|
||||
// Add NS and A records
|
||||
d.addNSAndARecordsForDomain(resp)
|
||||
|
||||
// If the network is not TCP, restrict the number of responses
|
||||
if network != "tcp" {
|
||||
wasTrimmed := trimUDPResponse(d.config, req, resp)
|
||||
|
@ -673,6 +682,40 @@ RPC:
|
|||
}
|
||||
}
|
||||
|
||||
// addNSAndARecordsForDomain uses the agent's advertise address to
|
||||
func (d *DNSServer) addNSAndARecordsForDomain(msg *dns.Msg) {
|
||||
serverAddrs := d.agent.delegate.ServerAddrs()
|
||||
for _, addr := range serverAddrs {
|
||||
ipAddrStr := strings.Split(addr, ":")[0]
|
||||
nsName := "ns." + ipAddrStr + "." + d.domain
|
||||
ip := net.ParseIP(ipAddrStr)
|
||||
if ip != nil {
|
||||
ns := &dns.NS{
|
||||
Hdr: dns.RR_Header{
|
||||
Name: d.domain,
|
||||
Rrtype: dns.TypeNS,
|
||||
Class: dns.ClassINET,
|
||||
Ttl: 0,
|
||||
},
|
||||
Ns: nsName,
|
||||
}
|
||||
msg.Ns = append(msg.Ns, ns)
|
||||
|
||||
//add an A record for the NS record
|
||||
a := &dns.A{
|
||||
Hdr: dns.RR_Header{
|
||||
Name: nsName,
|
||||
Rrtype: dns.TypeA,
|
||||
Class: dns.ClassINET,
|
||||
Ttl: uint32(d.config.NodeTTL / time.Second),
|
||||
},
|
||||
A: ip,
|
||||
}
|
||||
msg.Extra = append(msg.Extra, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// preparedQueryLookup is used to handle a prepared query.
|
||||
func (d *DNSServer) preparedQueryLookup(network, datacenter, query string, req, resp *dns.Msg) {
|
||||
// Execute the prepared query.
|
||||
|
@ -710,6 +753,7 @@ RPC:
|
|||
// here since the RPC layer loses the type information.
|
||||
if err.Error() == consul.ErrQueryNotFound.Error() {
|
||||
d.addSOA(d.domain, resp)
|
||||
d.addNSAndARecordsForDomain(resp)
|
||||
resp.SetRcode(req, dns.RcodeNameError)
|
||||
return
|
||||
}
|
||||
|
@ -752,6 +796,7 @@ RPC:
|
|||
// If we have no nodes, return not found!
|
||||
if len(out.Nodes) == 0 {
|
||||
d.addSOA(d.domain, resp)
|
||||
d.addNSAndARecordsForDomain(resp)
|
||||
resp.SetRcode(req, dns.RcodeNameError)
|
||||
return
|
||||
}
|
||||
|
@ -776,6 +821,7 @@ RPC:
|
|||
|
||||
// If the answer is empty and the response isn't truncated, return not found
|
||||
if len(resp.Answer) == 0 && !resp.Truncated {
|
||||
d.addNSAndARecordsForDomain(resp)
|
||||
d.addSOA(d.domain, resp)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -168,7 +168,7 @@ func TestDNS_NodeLookup(t *testing.T) {
|
|||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
if len(in.Ns) != 1 {
|
||||
if len(in.Ns) != 2 {
|
||||
t.Fatalf("Bad: %#v %#v", in, len(in.Answer))
|
||||
}
|
||||
|
||||
|
@ -179,6 +179,14 @@ func TestDNS_NodeLookup(t *testing.T) {
|
|||
if soaRec.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Ns[0])
|
||||
}
|
||||
|
||||
nsRec, ok := in.Ns[1].(*dns.NS)
|
||||
if !ok {
|
||||
t.Fatalf("Bad: %#v", in.Ns[1])
|
||||
}
|
||||
if nsRec.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Ns[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestDNS_CaseInsensitiveNodeLookup(t *testing.T) {
|
||||
|
@ -619,7 +627,7 @@ func TestDNS_ServiceLookup(t *testing.T) {
|
|||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
if len(in.Ns) != 1 {
|
||||
if len(in.Ns) != 2 {
|
||||
t.Fatalf("Bad: %#v", in)
|
||||
}
|
||||
|
||||
|
@ -630,6 +638,14 @@ func TestDNS_ServiceLookup(t *testing.T) {
|
|||
if soaRec.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Ns[0])
|
||||
}
|
||||
|
||||
nsRec, ok := in.Ns[1].(*dns.NS)
|
||||
if !ok {
|
||||
t.Fatalf("Bad: %#v", in.Ns[1])
|
||||
}
|
||||
if nsRec.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Ns[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -679,7 +695,6 @@ func TestDNS_ServiceLookupWithInternalServiceAddress(t *testing.T) {
|
|||
},
|
||||
}
|
||||
verify.Values(t, "answer", in.Answer, wantAnswer)
|
||||
|
||||
wantExtra := []dns.RR{
|
||||
&dns.CNAME{
|
||||
Hdr: dns.RR_Header{Name: "foo.node.dc1.consul.", Rrtype: 0x5, Class: 0x1, Rdlength: 0x2},
|
||||
|
@ -689,6 +704,10 @@ func TestDNS_ServiceLookupWithInternalServiceAddress(t *testing.T) {
|
|||
Hdr: dns.RR_Header{Name: "db.service.consul.", Rrtype: 0x1, Class: 0x1, Rdlength: 0x4},
|
||||
A: []byte{0x7f, 0x0, 0x0, 0x1}, // 127.0.0.1
|
||||
},
|
||||
&dns.A{
|
||||
Hdr: dns.RR_Header{Name: "ns.127.0.0.1.consul.", Rrtype: 0x1, Class: 0x1, Rdlength: 0x4},
|
||||
A: []byte{0x7f, 0x0, 0x0, 0x1}, // 127.0.0.1
|
||||
},
|
||||
}
|
||||
verify.Values(t, "extra", in.Extra, wantExtra)
|
||||
}
|
||||
|
@ -842,7 +861,7 @@ func TestDNS_ExternalServiceToConsulCNAMELookup(t *testing.T) {
|
|||
t.Fatalf("Bad: %#v", in.Answer[0])
|
||||
}
|
||||
|
||||
if len(in.Extra) != 2 {
|
||||
if len(in.Extra) != 3 {
|
||||
t.Fatalf("Bad: %#v", in)
|
||||
}
|
||||
|
||||
|
@ -873,6 +892,20 @@ func TestDNS_ExternalServiceToConsulCNAMELookup(t *testing.T) {
|
|||
if aRec.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Extra[1])
|
||||
}
|
||||
|
||||
aRec2, ok := in.Extra[2].(*dns.A)
|
||||
if !ok {
|
||||
t.Fatalf("Bad: %#v", in.Extra[2])
|
||||
}
|
||||
if aRec2.Hdr.Name != "ns.127.0.0.1.consul." {
|
||||
t.Fatalf("Bad: %#v", in.Extra[2])
|
||||
}
|
||||
if aRec2.A.String() != "127.0.0.1" {
|
||||
t.Fatalf("Bad: %#v", in.Extra[2])
|
||||
}
|
||||
if aRec2.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Extra[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -968,7 +1001,7 @@ func TestDNS_ExternalServiceToConsulCNAMENestedLookup(t *testing.T) {
|
|||
t.Fatalf("Bad: %#v", in.Answer[0])
|
||||
}
|
||||
|
||||
if len(in.Extra) != 3 {
|
||||
if len(in.Extra) != 4 {
|
||||
t.Fatalf("Bad: %#v", in)
|
||||
}
|
||||
|
||||
|
@ -1013,6 +1046,20 @@ func TestDNS_ExternalServiceToConsulCNAMENestedLookup(t *testing.T) {
|
|||
if aRec.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Extra[2])
|
||||
}
|
||||
|
||||
aRec2, ok := in.Extra[3].(*dns.A)
|
||||
if !ok {
|
||||
t.Fatalf("Bad: %#v", in.Extra[3])
|
||||
}
|
||||
if aRec2.Hdr.Name != "ns.127.0.0.1.consul." {
|
||||
t.Fatalf("Bad: %#v", in.Extra[3])
|
||||
}
|
||||
if aRec2.A.String() != "127.0.0.1" {
|
||||
t.Fatalf("Bad: %#v", in.Extra[3])
|
||||
}
|
||||
if aRec2.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Extra[3])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3758,7 +3805,7 @@ func TestDNS_NonExistingLookup(t *testing.T) {
|
|||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
if len(in.Ns) != 1 {
|
||||
if len(in.Ns) != 2 {
|
||||
t.Fatalf("Bad: %#v %#v", in, len(in.Answer))
|
||||
}
|
||||
|
||||
|
@ -3769,6 +3816,14 @@ func TestDNS_NonExistingLookup(t *testing.T) {
|
|||
if soaRec.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Ns[0])
|
||||
}
|
||||
|
||||
nsRec, ok := in.Ns[1].(*dns.NS)
|
||||
if !ok {
|
||||
t.Fatalf("Bad: %#v", in.Ns[1])
|
||||
}
|
||||
if nsRec.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Ns[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestDNS_NonExistingLookupEmptyAorAAAA(t *testing.T) {
|
||||
|
@ -3859,21 +3914,28 @@ func TestDNS_NonExistingLookupEmptyAorAAAA(t *testing.T) {
|
|||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
if len(in.Ns) != 1 {
|
||||
if len(in.Ns) != 2 {
|
||||
t.Fatalf("Bad: %#v", in)
|
||||
}
|
||||
|
||||
soaRec, ok := in.Ns[0].(*dns.SOA)
|
||||
soaRec, ok := in.Ns[1].(*dns.SOA)
|
||||
if !ok {
|
||||
t.Fatalf("Bad: %#v", in.Ns[0])
|
||||
t.Fatalf("Bad: %#v", in.Ns[1])
|
||||
}
|
||||
if soaRec.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Ns[0])
|
||||
t.Fatalf("Bad: %#v", in.Ns[1])
|
||||
}
|
||||
|
||||
if in.Rcode != dns.RcodeSuccess {
|
||||
t.Fatalf("Bad: %#v", in)
|
||||
}
|
||||
|
||||
nsRec, ok := in.Ns[0].(*dns.NS)
|
||||
if !ok {
|
||||
t.Fatalf("Bad: %#v", in.Ns[0])
|
||||
}
|
||||
if nsRec.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Ns[0])
|
||||
}
|
||||
}
|
||||
|
||||
// Check for ipv4 records on ipv6-only service directly and via the
|
||||
|
@ -3893,18 +3955,26 @@ func TestDNS_NonExistingLookupEmptyAorAAAA(t *testing.T) {
|
|||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
if len(in.Ns) != 1 {
|
||||
if len(in.Ns) != 2 {
|
||||
t.Fatalf("Bad: %#v", in)
|
||||
}
|
||||
|
||||
soaRec, ok := in.Ns[0].(*dns.SOA)
|
||||
nsRec, ok := in.Ns[0].(*dns.NS)
|
||||
if !ok {
|
||||
t.Fatalf("Bad: %#v", in.Ns[0])
|
||||
}
|
||||
if soaRec.Hdr.Ttl != 0 {
|
||||
if nsRec.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Ns[0])
|
||||
}
|
||||
|
||||
soaRec, ok := in.Ns[1].(*dns.SOA)
|
||||
if !ok {
|
||||
t.Fatalf("Bad: %#v", in.Ns[1])
|
||||
}
|
||||
if soaRec.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Ns[1])
|
||||
}
|
||||
|
||||
if in.Rcode != dns.RcodeSuccess {
|
||||
t.Fatalf("Bad: %#v", in)
|
||||
}
|
||||
|
@ -3944,7 +4014,7 @@ func TestDNS_PreparedQuery_AllowStale(t *testing.T) {
|
|||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
if len(in.Ns) != 1 {
|
||||
if len(in.Ns) != 2 {
|
||||
t.Fatalf("Bad: %#v", in)
|
||||
}
|
||||
|
||||
|
@ -3955,6 +4025,15 @@ func TestDNS_PreparedQuery_AllowStale(t *testing.T) {
|
|||
if soaRec.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Ns[0])
|
||||
}
|
||||
|
||||
nsRec, ok := in.Ns[1].(*dns.NS)
|
||||
if !ok {
|
||||
t.Fatalf("Bad: %#v", in.Ns[1])
|
||||
}
|
||||
if nsRec.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Ns[1])
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3982,7 +4061,7 @@ func TestDNS_InvalidQueries(t *testing.T) {
|
|||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
if len(in.Ns) != 1 {
|
||||
if len(in.Ns) != 2 {
|
||||
t.Fatalf("Bad: %#v", in)
|
||||
}
|
||||
|
||||
|
@ -3993,6 +4072,14 @@ func TestDNS_InvalidQueries(t *testing.T) {
|
|||
if soaRec.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Ns[0])
|
||||
}
|
||||
|
||||
nsRec, ok := in.Ns[1].(*dns.NS)
|
||||
if !ok {
|
||||
t.Fatalf("Bad: %#v", in.Ns[1])
|
||||
}
|
||||
if nsRec.Hdr.Ttl != 0 {
|
||||
t.Fatalf("Bad: %#v", in.Ns[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue