mirror of https://github.com/status-im/consul.git
Merge pull request #8218 from yurkeen/fix-dns-rcode
This commit is contained in:
commit
e0f9e4a2d9
|
@ -1,7 +1,6 @@
|
||||||
package consul
|
package consul
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -16,11 +15,6 @@ import (
|
||||||
"github.com/hashicorp/go-uuid"
|
"github.com/hashicorp/go-uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrQueryNotFound is returned if the query lookup failed.
|
|
||||||
ErrQueryNotFound = errors.New("Query not found")
|
|
||||||
)
|
|
||||||
|
|
||||||
// PreparedQuery manages the prepared query endpoint.
|
// PreparedQuery manages the prepared query endpoint.
|
||||||
type PreparedQuery struct {
|
type PreparedQuery struct {
|
||||||
srv *Server
|
srv *Server
|
||||||
|
@ -228,7 +222,7 @@ func (p *PreparedQuery) Get(args *structs.PreparedQuerySpecificRequest,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if query == nil {
|
if query == nil {
|
||||||
return ErrQueryNotFound
|
return structs.ErrQueryNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no prefix ACL applies to this query, then they are
|
// If no prefix ACL applies to this query, then they are
|
||||||
|
@ -303,7 +297,7 @@ func (p *PreparedQuery) Explain(args *structs.PreparedQueryExecuteRequest,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if query == nil {
|
if query == nil {
|
||||||
return ErrQueryNotFound
|
return structs.ErrQueryNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// Place the query into a list so we can run the standard ACL filter on
|
// Place the query into a list so we can run the standard ACL filter on
|
||||||
|
@ -350,7 +344,7 @@ func (p *PreparedQuery) Execute(args *structs.PreparedQueryExecuteRequest,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if query == nil {
|
if query == nil {
|
||||||
return ErrQueryNotFound
|
return structs.ErrQueryNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the query for the local DC.
|
// Execute the query for the local DC.
|
||||||
|
|
|
@ -175,7 +175,7 @@ func TestPreparedQuery_Apply(t *testing.T) {
|
||||||
}
|
}
|
||||||
var resp structs.IndexedPreparedQueries
|
var resp structs.IndexedPreparedQueries
|
||||||
if err = msgpackrpc.CallWithCodec(codec, "PreparedQuery.Get", req, &resp); err != nil {
|
if err = msgpackrpc.CallWithCodec(codec, "PreparedQuery.Get", req, &resp); err != nil {
|
||||||
if err.Error() != ErrQueryNotFound.Error() {
|
if !structs.IsErrQueryNotFound(err) {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,7 +317,7 @@ func TestPreparedQuery_Apply_ACLDeny(t *testing.T) {
|
||||||
}
|
}
|
||||||
var resp structs.IndexedPreparedQueries
|
var resp structs.IndexedPreparedQueries
|
||||||
if err = msgpackrpc.CallWithCodec(codec, "PreparedQuery.Get", req, &resp); err != nil {
|
if err = msgpackrpc.CallWithCodec(codec, "PreparedQuery.Get", req, &resp); err != nil {
|
||||||
if err.Error() != ErrQueryNotFound.Error() {
|
if !structs.IsErrQueryNotFound(err) {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -412,7 +412,7 @@ func TestPreparedQuery_Apply_ACLDeny(t *testing.T) {
|
||||||
}
|
}
|
||||||
var resp structs.IndexedPreparedQueries
|
var resp structs.IndexedPreparedQueries
|
||||||
if err = msgpackrpc.CallWithCodec(codec, "PreparedQuery.Get", req, &resp); err != nil {
|
if err = msgpackrpc.CallWithCodec(codec, "PreparedQuery.Get", req, &resp); err != nil {
|
||||||
if err.Error() != ErrQueryNotFound.Error() {
|
if !structs.IsErrQueryNotFound(err) {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1082,7 +1082,7 @@ func TestPreparedQuery_Get(t *testing.T) {
|
||||||
}
|
}
|
||||||
var resp structs.IndexedPreparedQueries
|
var resp structs.IndexedPreparedQueries
|
||||||
if err := msgpackrpc.CallWithCodec(codec, "PreparedQuery.Get", req, &resp); err != nil {
|
if err := msgpackrpc.CallWithCodec(codec, "PreparedQuery.Get", req, &resp); err != nil {
|
||||||
if err.Error() != ErrQueryNotFound.Error() {
|
if !structs.IsErrQueryNotFound(err) {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1429,7 +1429,7 @@ func TestPreparedQuery_Explain(t *testing.T) {
|
||||||
}
|
}
|
||||||
var resp structs.IndexedPreparedQueries
|
var resp structs.IndexedPreparedQueries
|
||||||
if err := msgpackrpc.CallWithCodec(codec, "PreparedQuery.Explain", req, &resp); err != nil {
|
if err := msgpackrpc.CallWithCodec(codec, "PreparedQuery.Explain", req, &resp); err != nil {
|
||||||
if err.Error() != ErrQueryNotFound.Error() {
|
if !structs.IsErrQueryNotFound(err) {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1617,7 +1617,7 @@ func TestPreparedQuery_Execute(t *testing.T) {
|
||||||
|
|
||||||
var reply structs.PreparedQueryExecuteResponse
|
var reply structs.PreparedQueryExecuteResponse
|
||||||
err := msgpackrpc.CallWithCodec(codec1, "PreparedQuery.Execute", &req, &reply)
|
err := msgpackrpc.CallWithCodec(codec1, "PreparedQuery.Execute", &req, &reply)
|
||||||
assert.EqualError(t, err, ErrQueryNotFound.Error())
|
assert.EqualError(t, err, structs.ErrQueryNotFound.Error())
|
||||||
assert.Len(t, reply.Nodes, 0)
|
assert.Len(t, reply.Nodes, 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ import (
|
||||||
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||||
cachetype "github.com/hashicorp/consul/agent/cache-types"
|
cachetype "github.com/hashicorp/consul/agent/cache-types"
|
||||||
"github.com/hashicorp/consul/agent/config"
|
"github.com/hashicorp/consul/agent/config"
|
||||||
"github.com/hashicorp/consul/agent/consul"
|
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
"github.com/hashicorp/consul/ipaddr"
|
"github.com/hashicorp/consul/ipaddr"
|
||||||
|
@ -828,8 +827,7 @@ func (d *DNSServer) computeRCode(err error) int {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return dns.RcodeSuccess
|
return dns.RcodeSuccess
|
||||||
}
|
}
|
||||||
dErr := err.Error()
|
if structs.IsErrNoDCPath(err) || structs.IsErrQueryNotFound(err) {
|
||||||
if dErr == structs.ErrNoDCPath.Error() || dErr == consul.ErrQueryNotFound.Error() {
|
|
||||||
return dns.RcodeNameError
|
return dns.RcodeNameError
|
||||||
}
|
}
|
||||||
return dns.RcodeServerFailure
|
return dns.RcodeServerFailure
|
||||||
|
|
|
@ -5790,15 +5790,17 @@ func TestDNS_AddressLookupIPV6(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDNS_NonExistingDC(t *testing.T) {
|
// TestDNS_NonExistentDC_Server verifies NXDOMAIN is returned when
|
||||||
|
// Consul server agent is queried for a service in a non-existent
|
||||||
|
// domain.
|
||||||
|
func TestDNS_NonExistentDC_Server(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
a := NewTestAgent(t, "")
|
a := NewTestAgent(t, "")
|
||||||
defer a.Shutdown()
|
defer a.Shutdown()
|
||||||
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
||||||
|
|
||||||
// lookup a non-existing node, we should receive a SOA
|
|
||||||
m := new(dns.Msg)
|
m := new(dns.Msg)
|
||||||
m.SetQuestion("consul.dc2.consul.", dns.TypeANY)
|
m.SetQuestion("consul.service.dc2.consul.", dns.TypeANY)
|
||||||
|
|
||||||
c := new(dns.Client)
|
c := new(dns.Client)
|
||||||
in, _, err := c.Exchange(m, a.DNSAddr())
|
in, _, err := c.Exchange(m, a.DNSAddr())
|
||||||
|
@ -5811,6 +5813,47 @@ func TestDNS_NonExistingDC(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestDNS_NonExistentDC_RPC verifies NXDOMAIN is returned when
|
||||||
|
// Consul server agent is queried over RPC by a non-server agent
|
||||||
|
// for a service in a non-existent domain
|
||||||
|
func TestDNS_NonExistentDC_RPC(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
s := NewTestAgent(t, `
|
||||||
|
node_name = "test-server"
|
||||||
|
`)
|
||||||
|
|
||||||
|
defer s.Shutdown()
|
||||||
|
c := NewTestAgent(t, `
|
||||||
|
node_name = "test-client"
|
||||||
|
bootstrap = false
|
||||||
|
server = false
|
||||||
|
`)
|
||||||
|
defer c.Shutdown()
|
||||||
|
testrpc.WaitForLeader(t, s.RPC, "dc1")
|
||||||
|
|
||||||
|
// Join LAN cluster
|
||||||
|
addr := fmt.Sprintf("127.0.0.1:%d", s.Config.SerfPortLAN)
|
||||||
|
_, err := c.JoinLAN([]string{addr})
|
||||||
|
require.NoError(t, err)
|
||||||
|
retry.Run(t, func(r *retry.R) {
|
||||||
|
require.Len(r, s.LANMembers(), 2)
|
||||||
|
require.Len(r, c.LANMembers(), 2)
|
||||||
|
})
|
||||||
|
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetQuestion("consul.service.dc2.consul.", dns.TypeANY)
|
||||||
|
|
||||||
|
d := new(dns.Client)
|
||||||
|
in, _, err := d.Exchange(m, c.DNSAddr())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if in.Rcode != dns.RcodeNameError {
|
||||||
|
t.Fatalf("Expected RCode: %#v, had: %#v", dns.RcodeNameError, in.Rcode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDNS_NonExistingLookup(t *testing.T) {
|
func TestDNS_NonExistingLookup(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
a := NewTestAgent(t, "")
|
a := NewTestAgent(t, "")
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
cachetype "github.com/hashicorp/consul/agent/cache-types"
|
cachetype "github.com/hashicorp/consul/agent/cache-types"
|
||||||
"github.com/hashicorp/consul/agent/consul"
|
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -144,7 +143,7 @@ func (s *HTTPServer) preparedQueryExecute(id string, resp http.ResponseWriter, r
|
||||||
if err := s.agent.RPC("PreparedQuery.Execute", &args, &reply); err != nil {
|
if err := s.agent.RPC("PreparedQuery.Execute", &args, &reply); err != nil {
|
||||||
// We have to check the string since the RPC sheds
|
// We have to check the string since the RPC sheds
|
||||||
// the specific error type.
|
// the specific error type.
|
||||||
if err.Error() == consul.ErrQueryNotFound.Error() {
|
if structs.IsErrQueryNotFound(err) {
|
||||||
resp.WriteHeader(http.StatusNotFound)
|
resp.WriteHeader(http.StatusNotFound)
|
||||||
fmt.Fprint(resp, err.Error())
|
fmt.Fprint(resp, err.Error())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -198,7 +197,7 @@ RETRY_ONCE:
|
||||||
if err := s.agent.RPC("PreparedQuery.Explain", &args, &reply); err != nil {
|
if err := s.agent.RPC("PreparedQuery.Explain", &args, &reply); err != nil {
|
||||||
// We have to check the string since the RPC sheds
|
// We have to check the string since the RPC sheds
|
||||||
// the specific error type.
|
// the specific error type.
|
||||||
if err.Error() == consul.ErrQueryNotFound.Error() {
|
if structs.IsErrQueryNotFound(err) {
|
||||||
resp.WriteHeader(http.StatusNotFound)
|
resp.WriteHeader(http.StatusNotFound)
|
||||||
fmt.Fprint(resp, err.Error())
|
fmt.Fprint(resp, err.Error())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -229,7 +228,7 @@ RETRY_ONCE:
|
||||||
if err := s.agent.RPC("PreparedQuery.Get", &args, &reply); err != nil {
|
if err := s.agent.RPC("PreparedQuery.Get", &args, &reply); err != nil {
|
||||||
// We have to check the string since the RPC sheds
|
// We have to check the string since the RPC sheds
|
||||||
// the specific error type.
|
// the specific error type.
|
||||||
if err.Error() == consul.ErrQueryNotFound.Error() {
|
if structs.IsErrQueryNotFound(err) {
|
||||||
resp.WriteHeader(http.StatusNotFound)
|
resp.WriteHeader(http.StatusNotFound)
|
||||||
fmt.Fprint(resp, err.Error())
|
fmt.Fprint(resp, err.Error())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
|
@ -14,6 +14,7 @@ const (
|
||||||
errSegmentsNotSupported = "Network segments are not supported in this version of Consul"
|
errSegmentsNotSupported = "Network segments are not supported in this version of Consul"
|
||||||
errRPCRateExceeded = "RPC rate limit exceeded"
|
errRPCRateExceeded = "RPC rate limit exceeded"
|
||||||
errServiceNotFound = "Service not found: "
|
errServiceNotFound = "Service not found: "
|
||||||
|
errQueryNotFound = "Query not found"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -24,8 +25,17 @@ var (
|
||||||
ErrSegmentsNotSupported = errors.New(errSegmentsNotSupported)
|
ErrSegmentsNotSupported = errors.New(errSegmentsNotSupported)
|
||||||
ErrRPCRateExceeded = errors.New(errRPCRateExceeded)
|
ErrRPCRateExceeded = errors.New(errRPCRateExceeded)
|
||||||
ErrDCNotAvailable = errors.New(errDCNotAvailable)
|
ErrDCNotAvailable = errors.New(errDCNotAvailable)
|
||||||
|
ErrQueryNotFound = errors.New(errQueryNotFound)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func IsErrNoDCPath(err error) bool {
|
||||||
|
return err != nil && strings.Contains(err.Error(), errNoDCPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsErrQueryNotFound(err error) bool {
|
||||||
|
return err != nil && strings.Contains(err.Error(), errQueryNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
func IsErrNoLeader(err error) bool {
|
func IsErrNoLeader(err error) bool {
|
||||||
return err != nil && strings.Contains(err.Error(), errNoLeader)
|
return err != nil && strings.Contains(err.Error(), errNoLeader)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue