mirror of
https://github.com/status-im/consul.git
synced 2025-01-10 05:45:46 +00:00
8837907de4
Blocking queries issues will still be uncancellable (that cannot be helped until we get rid of net/rpc). However this makes it so that if calling getWithIndex (like during a cache Notify go routine) we can cancell the outer routine. Previously it would keep issuing more blocking queries until the result state actually changed.
130 lines
4.0 KiB
Go
130 lines
4.0 KiB
Go
package agent
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
cachetype "github.com/hashicorp/consul/agent/cache-types"
|
|
"github.com/hashicorp/consul/agent/structs"
|
|
"github.com/hashicorp/consul/lib/decode"
|
|
"github.com/mitchellh/mapstructure"
|
|
)
|
|
|
|
func (s *HTTPServer) DiscoveryChainRead(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
|
var args structs.DiscoveryChainRequest
|
|
if done := s.parse(resp, req, &args.Datacenter, &args.QueryOptions); done {
|
|
return nil, nil
|
|
}
|
|
|
|
args.Name = strings.TrimPrefix(req.URL.Path, "/v1/discovery-chain/")
|
|
if args.Name == "" {
|
|
return nil, BadRequestError{Reason: "Missing chain name"}
|
|
}
|
|
|
|
args.EvaluateInDatacenter = req.URL.Query().Get("compile-dc")
|
|
var entMeta structs.EnterpriseMeta
|
|
if err := s.parseEntMetaNoWildcard(req, &entMeta); err != nil {
|
|
return nil, err
|
|
}
|
|
args.WithEnterpriseMeta(&entMeta)
|
|
|
|
if req.Method == "POST" {
|
|
var raw map[string]interface{}
|
|
if err := decodeBody(req.Body, &raw); err != nil {
|
|
return nil, BadRequestError{Reason: fmt.Sprintf("Request decoding failed: %v", err)}
|
|
}
|
|
|
|
apiReq, err := decodeDiscoveryChainReadRequest(raw)
|
|
if err != nil {
|
|
return nil, BadRequestError{Reason: fmt.Sprintf("Request decoding failed: %v", err)}
|
|
}
|
|
|
|
args.OverrideProtocol = apiReq.OverrideProtocol
|
|
args.OverrideConnectTimeout = apiReq.OverrideConnectTimeout
|
|
|
|
if apiReq.OverrideMeshGateway.Mode != "" {
|
|
_, err := structs.ValidateMeshGatewayMode(string(apiReq.OverrideMeshGateway.Mode))
|
|
if err != nil {
|
|
resp.WriteHeader(http.StatusBadRequest)
|
|
fmt.Fprint(resp, "Invalid OverrideMeshGateway.Mode parameter")
|
|
return nil, nil
|
|
}
|
|
args.OverrideMeshGateway = apiReq.OverrideMeshGateway
|
|
}
|
|
}
|
|
|
|
// Make the RPC request
|
|
var out structs.DiscoveryChainResponse
|
|
defer setMeta(resp, &out.QueryMeta)
|
|
|
|
if s.agent.config.HTTPUseCache && args.QueryOptions.UseCache {
|
|
raw, m, err := s.agent.cache.Get(req.Context(), cachetype.CompiledDiscoveryChainName, &args)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer setCacheMeta(resp, &m)
|
|
|
|
reply, ok := raw.(*structs.DiscoveryChainResponse)
|
|
if !ok {
|
|
// This should never happen, but we want to protect against panics
|
|
return nil, fmt.Errorf("internal error: response type not correct")
|
|
}
|
|
out = *reply
|
|
} else {
|
|
RETRY_ONCE:
|
|
if err := s.agent.RPC("DiscoveryChain.Get", &args, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
if args.QueryOptions.AllowStale && args.MaxStaleDuration > 0 && args.MaxStaleDuration < out.LastContact {
|
|
args.AllowStale = false
|
|
args.MaxStaleDuration = 0
|
|
goto RETRY_ONCE
|
|
}
|
|
}
|
|
out.ConsistencyLevel = args.QueryOptions.ConsistencyLevel()
|
|
|
|
return discoveryChainReadResponse{Chain: out.Chain}, nil
|
|
}
|
|
|
|
// discoveryChainReadRequest is the API variation of structs.DiscoveryChainRequest
|
|
type discoveryChainReadRequest struct {
|
|
OverrideMeshGateway structs.MeshGatewayConfig `alias:"override_mesh_gateway"`
|
|
OverrideProtocol string `alias:"override_protocol"`
|
|
OverrideConnectTimeout time.Duration `alias:"override_connect_timeout"`
|
|
}
|
|
|
|
// discoveryChainReadResponse is the API variation of structs.DiscoveryChainResponse
|
|
type discoveryChainReadResponse struct {
|
|
Chain *structs.CompiledDiscoveryChain
|
|
}
|
|
|
|
func decodeDiscoveryChainReadRequest(raw map[string]interface{}) (*discoveryChainReadRequest, error) {
|
|
var apiReq discoveryChainReadRequest
|
|
// TODO(dnephin): at this time only JSON payloads are read, so it is unlikely
|
|
// that HookWeakDecodeFromSlice is necessary. It was added while porting
|
|
// from lib.PatchSliceOfMaps to decode.HookWeakDecodeFromSlice. It may be
|
|
// safe to remove in the future.
|
|
decodeConf := &mapstructure.DecoderConfig{
|
|
DecodeHook: mapstructure.ComposeDecodeHookFunc(
|
|
decode.HookWeakDecodeFromSlice,
|
|
decode.HookTranslateKeys,
|
|
mapstructure.StringToTimeDurationHookFunc(),
|
|
),
|
|
Result: &apiReq,
|
|
WeaklyTypedInput: true,
|
|
}
|
|
|
|
decoder, err := mapstructure.NewDecoder(decodeConf)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := decoder.Decode(raw); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &apiReq, nil
|
|
}
|