Consul
Discovery Chain HTTP Endpoint
1.6.0+: The discovery chain API is available in Consul versions 1.6.0 and newer.
This is a low-level API primarily targeted at developers building external Connect proxy integrations. Future high-level proxy integration APIs may obviate the need for this API over time.
The /discovery-chain
endpoint returns the compiled discovery
chain for a service.
This will fetch all related configuration entries and render them into a form suitable for use by a connect proxy implementation. This is a key component of L7 Traffic Management.
Read Compiled Discovery Chain
If overrides are needed they are passed as the JSON-encoded request body and
the POST
method must be used, otherwise GET
is sufficient.
Method | Path | Produces |
---|---|---|
GET | /discovery-chain/:service | application/json |
POST 1 | /discovery-chain/:service | application/json |
1 Both GET and POST are for read operations. GET requests do not permit request bodies so a POST is required if override parameters are needed.
The table below shows this endpoint's support for blocking queries, consistency modes, agent caching, and required ACLs.
Blocking Queries | Consistency Modes | Agent Caching | ACL Required |
---|---|---|---|
YES | all | background refresh | service:read |
URL Parameters
service
(string: <required>)
- Specifies the service to query when compiling the discovery chain. This is provided as part of the URL.compile-dc
(string: "")
- Specifies the datacenter to use as the basis of compilation. This will default to the datacenter of the agent being queried. This is specified as part of the URL as a query parameter.This value comes from an upstream configuration
datacenter
parameter.ns
(string: "")
Enterprise - Specifies the source namespace to use as the basis of compilation. This value can be specified as thens
URL query parameter or theX-Consul-Namespace
header. If not provided by either, the namespace will be inherited from the request's ACL token or will default to thedefault
namespace. Added in Consul 1.7.0.
POST Body Parameters
OverrideConnectTimeout
(duration: 0s)
- Overrides the final connect timeout for any service resolved in the compiled chain.This value comes from the
connect_timeout_ms
key in an upstream configuration opaqueconfig
parameter.OverrideProtocol
(string: "")
- Overrides the final protocol used in the compiled discovery chain.If the chain ordinarily would be TCP and an L7 protocol is passed here the chain will still not include Routers or Splitters. If the chain ordinarily would be L7 and TCP is passed here the chain will not include Routers or Splitters.
This value comes from the
protocol
key in an upstream configuration opaqueconfig
parameter.OverrideMeshGateway
(MeshGatewayConfig: <optional>)
- Overrides the final mesh gateway configuration for this any service resolved in the compiled chain.This value comes from either the proxy configuration
mesh_gateway
parameter or an upstream configurationmesh_gateway
parameter. If both are present the value defined on the upstream is used.Mode
(string: "")
- One ofnone
,local
, orremote
.
Sample Compilations
Full documentation for the output fields is found on the discovery chain internals page.
Multi-Datacenter Failover
Config entries defined:
kind = "service-resolver"
name = "web"
connect_timeout = "15s"
failover = {
"*" = {
datacenters = ["dc3", "dc4"]
}
}
Request:
$ curl http://127.0.0.1:8500/v1/discovery-chain/web
Response:
{
"Chain": {
"ServiceName": "web",
"Namespace": "default",
"Datacenter": "dc1",
"Protocol": "tcp",
"StartNode": "resolver:web.default.dc1",
"Nodes": {
"resolver:web.default.dc1": {
"Type": "resolver",
"Name": "web.default.dc1",
"Resolver": {
"ConnectTimeout": "15s",
"Target": "web.default.dc1",
"Failover": {
"Targets": ["web.default.dc3", "web.default.dc4"]
}
}
}
},
"Targets": {
"web.default.dc1": {
"ID": "web.default.dc1",
"Service": "web",
"Namespace": "default",
"Datacenter": "dc1",
"MeshGateway": {},
"Subset": {},
"SNI": "web.default.dc1.internal.47e25151-6212-ba25-8b7e-81adbbbab461.consul",
"Name": "web.default.dc1.internal.47e25151-6212-ba25-8b7e-81adbbbab461.consul"
},
"web.default.dc3": {
"ID": "web.default.dc3",
"Service": "web",
"Namespace": "default",
"Datacenter": "dc3",
"MeshGateway": {},
"Subset": {},
"SNI": "web.default.dc3.internal.47e25151-6212-ba25-8b7e-81adbbbab461.consul",
"Name": "web.default.dc3.internal.47e25151-6212-ba25-8b7e-81adbbbab461.consul"
},
"web.default.dc4": {
"ID": "web.default.dc4",
"Service": "web",
"Namespace": "default",
"Datacenter": "dc4",
"MeshGateway": {},
"Subset": {},
"SNI": "web.default.dc4.internal.47e25151-6212-ba25-8b7e-81adbbbab461.consul",
"Name": "web.default.dc4.internal.47e25151-6212-ba25-8b7e-81adbbbab461.consul"
}
}
}
}
Datacenter Redirect with Overrides
Config entries defined:
kind = "service-resolver"
name = "web"
redirect {
datacenter = "dc2"
}
Request:
$ curl --request POST \
--data '
{
"OverrideConnectTimeout": "7s",
"OverrideProtocol": "grpc",
"OverrideMeshGateway": {
"Mode": "remote"
}
}
' http://127.0.0.1:8500/v1/discovery-chain/web
Response:
{
"Chain": {
"ServiceName": "web",
"Namespace": "default",
"Datacenter": "dc1",
"CustomizationHash": "b94f529a",
"Protocol": "grpc",
"StartNode": "resolver:web.default.dc2",
"Nodes": {
"resolver:web.default.dc2": {
"Type": "resolver",
"Name": "web.default.dc2",
"Resolver": {
"ConnectTimeout": "7s",
"Target": "web.default.dc2"
}
}
},
"Targets": {
"web.default.dc2": {
"ID": "web.default.dc2",
"Service": "web",
"Namespace": "default",
"Datacenter": "dc2",
"MeshGateway": {
"Mode": "remote"
},
"Subset": {},
"SNI": "web.default.dc2.internal.59c17fd4-8dfa-f54a-ae71-855b26faf637.consul",
"Name": "web.default.dc2.internal.59c17fd4-8dfa-f54a-ae71-855b26faf637.consul"
}
}
}
}
Version Split For Alternate Datacenter
Config entries defined:
kind = "service-resolver"
name = "web"
default_subset = "v1"
subsets = {
"v1" = {
filter = "Service.Meta.version == v1"
}
"v2" = {
filter = "Service.Meta.version == v2"
}
}
# ---------------------------
kind = "service-defaults"
name = "web"
protocol = "http"
# ---------------------------
kind = "service-splitter"
name = "web"
splits = [
{
weight = 90
service_subset = "v1"
},
{
weight = 10
service_subset = "v2"
},
]
Request:
$ curl http://127.0.0.1:8500/v1/discovery-chain/web?compile-dc=dc2
Response:
{
"Chain": {
"ServiceName": "web",
"Namespace": "default",
"Datacenter": "dc2",
"Protocol": "http",
"StartNode": "splitter:web",
"Nodes": {
"resolver:v1.web.default.dc2": {
"Type": "resolver",
"Name": "v1.web.default.dc2",
"Resolver": {
"ConnectTimeout": "5s",
"Target": "v1.web.default.dc2"
}
},
"resolver:v2.web.default.dc2": {
"Type": "resolver",
"Name": "v2.web.default.dc2",
"Resolver": {
"ConnectTimeout": "5s",
"Target": "v2.web.default.dc2"
}
},
"splitter:web": {
"Type": "splitter",
"Name": "web",
"Splits": [
{
"Weight": 90,
"NextNode": "resolver:v1.web.default.dc2"
},
{
"Weight": 10,
"NextNode": "resolver:v2.web.default.dc2"
}
]
}
},
"Targets": {
"v1.web.default.dc2": {
"ID": "v1.web.default.dc2",
"Service": "web",
"ServiceSubset": "v1",
"Namespace": "default",
"Datacenter": "dc2",
"MeshGateway": {},
"Subset": {
"Filter": "Service.Meta.version == v1"
},
"SNI": "v1.web.default.dc2.internal.6c9594ec-d798-28b9-d084-aa03e81cf078.consul",
"Name": "v1.web.default.dc2.internal.6c9594ec-d798-28b9-d084-aa03e81cf078.consul"
},
"v2.web.default.dc2": {
"ID": "v2.web.default.dc2",
"Service": "web",
"ServiceSubset": "v2",
"Namespace": "default",
"Datacenter": "dc2",
"MeshGateway": {},
"Subset": {
"Filter": "Service.Meta.version == v2"
},
"SNI": "v2.web.default.dc2.internal.6c9594ec-d798-28b9-d084-aa03e81cf078.consul",
"Name": "v2.web.default.dc2.internal.6c9594ec-d798-28b9-d084-aa03e81cf078.consul"
}
}
}
}
HTTP Path Routing
Config entries defined:
kind = "service-resolver"
name = "web"
subsets = {
"canary" = {
filter = "Service.Meta.flavor == canary"
}
}
# ---------------------------
kind = "proxy-defaults"
name = "web"
config {
protocol = "http"
}
# ---------------------------
kind = "service-router"
name = "web"
routes = [
{
match {
http {
path_prefix = "/admin"
}
}
destination {
service = "admin"
prefix_rewrite = "/"
request_timeout = "15s"
}
},
{
match {
http {
header = [
{
name = "x-debug"
exact = "1"
},
]
}
}
destination {
service = "web"
service_subset = "canary"
num_retries = 5
retry_on_connect_failure = true
retry_on_status_codes = [401, 409]
}
},
]
Request:
$ curl http://127.0.0.1:8500/v1/discovery-chain/web
Response:
{
"Chain": {
"ServiceName": "web",
"Namespace": "default",
"Datacenter": "dc1",
"Protocol": "http",
"StartNode": "router:web",
"Nodes": {
"resolver:admin.default.dc1": {
"Type": "resolver",
"Name": "admin.default.dc1",
"Resolver": {
"ConnectTimeout": "5s",
"Default": true,
"Target": "admin.default.dc1"
}
},
"resolver:canary.web.default.dc1": {
"Type": "resolver",
"Name": "canary.web.default.dc1",
"Resolver": {
"ConnectTimeout": "5s",
"Target": "canary.web.default.dc1"
}
},
"resolver:web.default.dc1": {
"Type": "resolver",
"Name": "web.default.dc1",
"Resolver": {
"ConnectTimeout": "5s",
"Target": "web.default.dc1"
}
},
"router:web": {
"Type": "router",
"Name": "web",
"Routes": [
{
"Definition": {
"Match": {
"HTTP": {
"PathPrefix": "/admin"
}
},
"Destination": {
"RequestTimeout": "15s",
"Service": "admin",
"PrefixRewrite": "/"
}
},
"NextNode": "resolver:admin.default.dc1"
},
{
"Definition": {
"Match": {
"HTTP": {
"Header": [
{
"Name": "x-debug",
"Exact": "1"
}
]
}
},
"Destination": {
"Service": "web",
"ServiceSubset": "canary",
"NumRetries": 5,
"RetryOnConnectFailure": true,
"RetryOnStatusCodes": [401, 409]
}
},
"NextNode": "resolver:canary.web.default.dc1"
},
{
"Definition": {
"Match": {
"HTTP": {
"PathPrefix": "/"
}
},
"Destination": {
"Service": "web"
}
},
"NextNode": "resolver:web.default.dc1"
}
]
}
},
"Targets": {
"admin.default.dc1": {
"ID": "admin.default.dc1",
"Service": "admin",
"Namespace": "default",
"Datacenter": "dc1",
"MeshGateway": {},
"Subset": {},
"SNI": "admin.default.dc1.internal.fce8a058-0981-2c04-d23c-b7375af64ce8.consul",
"Name": "admin.default.dc1.internal.fce8a058-0981-2c04-d23c-b7375af64ce8.consul"
},
"canary.web.default.dc1": {
"ID": "canary.web.default.dc1",
"Service": "web",
"ServiceSubset": "canary",
"Namespace": "default",
"Datacenter": "dc1",
"MeshGateway": {},
"Subset": {
"Filter": "Service.Meta.flavor == canary"
},
"SNI": "canary.web.default.dc1.internal.fce8a058-0981-2c04-d23c-b7375af64ce8.consul",
"Name": "canary.web.default.dc1.internal.fce8a058-0981-2c04-d23c-b7375af64ce8.consul"
},
"web.default.dc1": {
"ID": "web.default.dc1",
"Service": "web",
"Namespace": "default",
"Datacenter": "dc1",
"MeshGateway": {},
"Subset": {},
"SNI": "web.default.dc1.internal.fce8a058-0981-2c04-d23c-b7375af64ce8.consul",
"Name": "web.default.dc1.internal.fce8a058-0981-2c04-d23c-b7375af64ce8.consul"
}
}
}
}