GH-3798: Add near=_ip support for prepared queries
This commit is contained in:
parent
d5b8b75614
commit
89cd24aeca
|
@ -393,6 +393,23 @@ func (p *PreparedQuery) Execute(args *structs.PreparedQueryExecuteRequest,
|
||||||
// Respect the magic "_agent" flag.
|
// Respect the magic "_agent" flag.
|
||||||
if qs.Node == "_agent" {
|
if qs.Node == "_agent" {
|
||||||
qs.Node = args.Agent.Node
|
qs.Node = args.Agent.Node
|
||||||
|
} else if qs.Node == "_ip" {
|
||||||
|
if args.Source.Ip != "" {
|
||||||
|
_, nodes, err := state.Nodes(nil)
|
||||||
|
if err == nil {
|
||||||
|
for _, node := range nodes {
|
||||||
|
if args.Source.Ip == node.Address {
|
||||||
|
qs.Node = node.Node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Either a source IP was given but we couldnt find the associated node
|
||||||
|
// or no source ip was given. In both cases we should wipe the Node value
|
||||||
|
if qs.Node == "_ip" {
|
||||||
|
qs.Node = ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the distance sort
|
// Perform the distance sort
|
||||||
|
|
23
agent/dns.go
23
agent/dns.go
|
@ -917,6 +917,23 @@ func (d *DNSServer) serviceLookup(network, datacenter, service, tag string, req,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ednsSubnetForRequest(req *dns.Msg) (*dns.EDNS0_SUBNET) {
|
||||||
|
// Its probably not obvious but IsEdns0 returns the EDNS RR if present or nil otherwise
|
||||||
|
edns := req.IsEdns0()
|
||||||
|
|
||||||
|
if edns == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, o := range edns.Option {
|
||||||
|
if subnet, ok := o.(*dns.EDNS0_SUBNET); ok {
|
||||||
|
return subnet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
// preparedQueryLookup is used to handle a prepared query.
|
// preparedQueryLookup is used to handle a prepared query.
|
||||||
func (d *DNSServer) preparedQueryLookup(network, datacenter, query string, req, resp *dns.Msg) {
|
func (d *DNSServer) preparedQueryLookup(network, datacenter, query string, req, resp *dns.Msg) {
|
||||||
// Execute the prepared query.
|
// Execute the prepared query.
|
||||||
|
@ -939,6 +956,12 @@ func (d *DNSServer) preparedQueryLookup(network, datacenter, query string, req,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subnet := ednsSubnetForRequest(req)
|
||||||
|
|
||||||
|
if subnet != nil {
|
||||||
|
args.Source.Ip = subnet.Address.String()
|
||||||
|
}
|
||||||
|
|
||||||
// TODO (slackpad) - What's a safe limit we can set here? It seems like
|
// TODO (slackpad) - What's a safe limit we can set here? It seems like
|
||||||
// with dup filtering done at this level we need to get everything to
|
// with dup filtering done at this level we need to get everything to
|
||||||
// match the previous behavior. We can optimize by pushing more filtering
|
// match the previous behavior. We can optimize by pushing more filtering
|
||||||
|
|
|
@ -498,11 +498,33 @@ func (s *HTTPServer) parseToken(req *http.Request, token *string) {
|
||||||
*token = s.agent.tokens.UserToken()
|
*token = s.agent.tokens.UserToken()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sourceAddrFromRequest(req *http.Request) (string, error) {
|
||||||
|
host, _, err := net.SplitHostPort(req.RemoteAddr)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
ip := net.ParseIP(host)
|
||||||
|
if ip == nil {
|
||||||
|
return "", fmt.Errorf("Could not get IP from request")
|
||||||
|
}
|
||||||
|
|
||||||
|
forwardHost := req.Header.Get("X-Forwarded-For")
|
||||||
|
forwardIp := net.ParseIP(forwardHost)
|
||||||
|
if forwardIp != nil {
|
||||||
|
return forwardIp.String(), nil
|
||||||
|
} else {
|
||||||
|
return ip.String(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// parseSource is used to parse the ?near=<node> query parameter, used for
|
// parseSource is used to parse the ?near=<node> query parameter, used for
|
||||||
// sorting by RTT based on a source node. We set the source's DC to the target
|
// sorting by RTT based on a source node. We set the source's DC to the target
|
||||||
// DC in the request, if given, or else the agent's DC.
|
// DC in the request, if given, or else the agent's DC.
|
||||||
func (s *HTTPServer) parseSource(req *http.Request, source *structs.QuerySource) {
|
func (s *HTTPServer) parseSource(req *http.Request, source *structs.QuerySource) {
|
||||||
s.parseDC(req, &source.Datacenter)
|
s.parseDC(req, &source.Datacenter)
|
||||||
|
source.Ip, _ = sourceAddrFromRequest(req)
|
||||||
if node := req.URL.Query().Get("near"); node != "" {
|
if node := req.URL.Query().Get("near"); node != "" {
|
||||||
if node == "_agent" {
|
if node == "_agent" {
|
||||||
source.Node = s.agent.config.NodeName
|
source.Node = s.agent.config.NodeName
|
||||||
|
|
|
@ -258,6 +258,7 @@ type QuerySource struct {
|
||||||
Datacenter string
|
Datacenter string
|
||||||
Segment string
|
Segment string
|
||||||
Node string
|
Node string
|
||||||
|
Ip string
|
||||||
}
|
}
|
||||||
|
|
||||||
// DCSpecificRequest is used to query about a specific DC
|
// DCSpecificRequest is used to query about a specific DC
|
||||||
|
|
Loading…
Reference in New Issue