Adds an `X-Consul-Translate-Addresses` to signal translation is enabled.

pull/2280/head
James Phillips 2016-08-16 11:31:41 -07:00
parent fbdd021ab9
commit 9f7a973ace
No known key found for this signature in database
GPG Key ID: 77183E682AC5FC11
6 changed files with 88 additions and 3 deletions

View File

@ -80,6 +80,9 @@ type QueryMeta struct {
// How long did the request take // How long did the request take
RequestTime time.Duration RequestTime time.Duration
// Is address translation enabled for HTTP responses on this agent
AddressTranslationEnabled bool
} }
// WriteMeta is used to return meta data about a write // WriteMeta is used to return meta data about a write
@ -542,6 +545,15 @@ func parseQueryMeta(resp *http.Response, q *QueryMeta) error {
default: default:
q.KnownLeader = false q.KnownLeader = false
} }
// Parse X-Consul-Translate-Addresses
switch header.Get("X-Consul-Translate-Addresses") {
case "true":
q.AddressTranslationEnabled = true
default:
q.AddressTranslationEnabled = false
}
return nil return nil
} }

View File

@ -306,6 +306,7 @@ func TestParseQueryMeta(t *testing.T) {
resp.Header.Set("X-Consul-Index", "12345") resp.Header.Set("X-Consul-Index", "12345")
resp.Header.Set("X-Consul-LastContact", "80") resp.Header.Set("X-Consul-LastContact", "80")
resp.Header.Set("X-Consul-KnownLeader", "true") resp.Header.Set("X-Consul-KnownLeader", "true")
resp.Header.Set("X-Consul-Translate-Addresses", "true")
qm := &QueryMeta{} qm := &QueryMeta{}
if err := parseQueryMeta(resp, qm); err != nil { if err := parseQueryMeta(resp, qm); err != nil {
@ -321,6 +322,9 @@ func TestParseQueryMeta(t *testing.T) {
if !qm.KnownLeader { if !qm.KnownLeader {
t.Fatalf("Bad: %v", qm) t.Fatalf("Bad: %v", qm)
} }
if !qm.AddressTranslationEnabled {
t.Fatalf("Bad: %v", qm)
}
} }
func TestAPI_UnixSocket(t *testing.T) { func TestAPI_UnixSocket(t *testing.T) {

View File

@ -329,6 +329,7 @@ func (s *HTTPServer) registerHandlers(enableDebug bool) {
func (s *HTTPServer) wrap(handler func(resp http.ResponseWriter, req *http.Request) (interface{}, error)) func(resp http.ResponseWriter, req *http.Request) { func (s *HTTPServer) wrap(handler func(resp http.ResponseWriter, req *http.Request) (interface{}, error)) func(resp http.ResponseWriter, req *http.Request) {
f := func(resp http.ResponseWriter, req *http.Request) { f := func(resp http.ResponseWriter, req *http.Request) {
setHeaders(resp, s.agent.config.HTTPAPIResponseHeaders) setHeaders(resp, s.agent.config.HTTPAPIResponseHeaders)
setTranslateAddr(resp, s.agent.config.TranslateWanAddrs)
// Obfuscate any tokens from appearing in the logs // Obfuscate any tokens from appearing in the logs
formVals, err := url.ParseQuery(req.URL.RawQuery) formVals, err := url.ParseQuery(req.URL.RawQuery)
@ -373,6 +374,7 @@ func (s *HTTPServer) wrap(handler func(resp http.ResponseWriter, req *http.Reque
if strings.Contains(errMsg, "Permission denied") || strings.Contains(errMsg, "ACL not found") { if strings.Contains(errMsg, "Permission denied") || strings.Contains(errMsg, "ACL not found") {
code = http.StatusForbidden // 403 code = http.StatusForbidden // 403
} }
resp.WriteHeader(code) resp.WriteHeader(code)
resp.Write([]byte(err.Error())) resp.Write([]byte(err.Error()))
return return
@ -452,6 +454,14 @@ func decodeBody(req *http.Request, out interface{}, cb func(interface{}) error)
return mapstructure.Decode(raw, out) return mapstructure.Decode(raw, out)
} }
// setTranslateAddr is used to set the address translation header. This is only
// present if the feature is active.
func setTranslateAddr(resp http.ResponseWriter, active bool) {
if active {
resp.Header().Set("X-Consul-Translate-Addresses", "true")
}
}
// setIndex is used to set the index response header // setIndex is used to set the index response header
func setIndex(resp http.ResponseWriter, index uint64) { func setIndex(resp http.ResponseWriter, index uint64) {
resp.Header().Set("X-Consul-Index", strconv.FormatUint(index, 10)) resp.Header().Set("X-Consul-Index", strconv.FormatUint(index, 10))

View File

@ -223,6 +223,51 @@ func TestSetMeta(t *testing.T) {
} }
} }
func TestHTTPAPI_TranslateAddrHeader(t *testing.T) {
// Header should not be present if address translation is off.
{
dir, srv := makeHTTPServer(t)
defer os.RemoveAll(dir)
defer srv.Shutdown()
defer srv.agent.Shutdown()
resp := httptest.NewRecorder()
handler := func(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
return nil, nil
}
req, _ := http.NewRequest("GET", "/v1/agent/self", nil)
srv.wrap(handler)(resp, req)
translate := resp.Header().Get("X-Consul-Translate-Addresses")
if translate != "" {
t.Fatalf("bad: expected %q, got %q", "", translate)
}
}
// Header should be set to true if it's turned on.
{
dir, srv := makeHTTPServer(t)
srv.agent.config.TranslateWanAddrs = true
defer os.RemoveAll(dir)
defer srv.Shutdown()
defer srv.agent.Shutdown()
resp := httptest.NewRecorder()
handler := func(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
return nil, nil
}
req, _ := http.NewRequest("GET", "/v1/agent/self", nil)
srv.wrap(handler)(resp, req)
translate := resp.Header().Get("X-Consul-Translate-Addresses")
if translate != "true" {
t.Fatalf("bad: expected %q, got %q", "true", translate)
}
}
}
func TestHTTPAPIResponseHeaders(t *testing.T) { func TestHTTPAPIResponseHeaders(t *testing.T) {
dir, srv := makeHTTPServer(t) dir, srv := makeHTTPServer(t)
srv.agent.config.HTTPAPIResponseHeaders = map[string]string{ srv.agent.config.HTTPAPIResponseHeaders = map[string]string{

View File

@ -96,3 +96,12 @@ configuration option. However, the token can also be specified per-request
by using the `X-Consul-Token` request header or the `token` querystring by using the `X-Consul-Token` request header or the `token` querystring
parameter. The request header takes precedence over the default token, and parameter. The request header takes precedence over the default token, and
the querystring parameter takes precedence over everything. the querystring parameter takes precedence over everything.
## <a id="translate_header"></a>Translated Addresses
Consul 0.7 added the ability to translate addresses in HTTP response based on the configuration
setting for [`translate_wan_addrs`](/docs/agent/options.html#translate_wan_addrs). In order to
allow clients to know if address translation is in effect, the `X-Consul-Translate-Addresses`
header will be added if translation is enabled, and will have a value of `true`. If translation
is not enabled then this header will not be present.

View File

@ -756,9 +756,14 @@ Consul will not enable TLS for the HTTP API unless the `https` port has been ass
default. default.
<br> <br>
<br> <br>
Starting in Consul 0.7 and later, node addresses in responses to the following HTTP endpoints will Starting in Consul 0.7 and later, node addresses in responses to HTTP requests will also prefer a
prefer a node's configured <a href="#_advertise-wan">WAN address</a> when querying for a node in a node's configured <a href="#_advertise-wan">WAN address</a> when querying for a node in a remote
remote datacenter: datacenter. An [`X-Consul-Translate-Addresses`](/docs/agent/http.html#translate_header) header
will be present on all responses when translation is enabled to help clients know that the addresses
may be translated. The `TaggedAddresses` field in responses also have a `lan` address for clients that
need knowledge of that address, regardless of translation.
<br>
<br>The following endpoints translate addresses:
<br> <br>
* [`/v1/catalog/nodes`](/docs/agent/http/catalog.html#catalog_nodes) * [`/v1/catalog/nodes`](/docs/agent/http/catalog.html#catalog_nodes)
* [`/v1/catalog/node/<node>`](/docs/agent/http/catalog.html#catalog_node) * [`/v1/catalog/node/<node>`](/docs/agent/http/catalog.html#catalog_node)