diff --git a/.changelog/13782.txt b/.changelog/13782.txt new file mode 100644 index 000000000000..1c426e29fc46 --- /dev/null +++ b/.changelog/13782.txt @@ -0,0 +1,3 @@ +```release-note:feature +deps: update to latest go-discover to provide ECS auto-discover capabilities. +``` \ No newline at end of file diff --git a/.changelog/14340.txt b/.changelog/14340.txt new file mode 100644 index 000000000000..f871e5542871 --- /dev/null +++ b/.changelog/14340.txt @@ -0,0 +1,4 @@ +```release-note:feature +connect: Add local_idle_timeout_ms to allow configuring the Envoy route idle timeout on local_app +connect: Add IdleTimeout to service-router to allow configuring the Envoy route idle timeout +``` diff --git a/.changelog/14679.txt b/.changelog/14679.txt index 601fd6c76055..0c3197ca57c8 100644 --- a/.changelog/14679.txt +++ b/.changelog/14679.txt @@ -1,3 +1,3 @@ -```release-note:improvement -dns: **(Enterprise Only)** All enterprise locality labels are now optional in DNS lookups. For example, service lookups support the following format: .].service[..ns][..ap][..dc]`. -``` +```release-note:improvement +dns: **(Enterprise Only)** All enterprise locality labels are now optional in DNS lookups. For example, service lookups support the following format: `[.].service[..ns][..ap][..dc]`. +``` diff --git a/.changelog/14930.txt b/.changelog/14930.txt deleted file mode 100644 index c8a82cc1861d..000000000000 --- a/.changelog/14930.txt +++ /dev/null @@ -1 +0,0 @@ -peering: remove ServerExternalAddresses parameter from token generation endpoint. \ No newline at end of file diff --git a/.changelog/15050.txt b/.changelog/15050.txt new file mode 100644 index 000000000000..2738b7dc03d1 --- /dev/null +++ b/.changelog/15050.txt @@ -0,0 +1,6 @@ +```release-note:feature +cli: Add `-consul-dns-port` flag to the `consul connect redirect-traffic` command to allow forwarding DNS traffic to a specific Consul DNS port. +``` +```release-note:feature +sdk: Configure `iptables` to forward DNS traffic to a specific DNS port. +``` diff --git a/.changelog/15083.txt b/.changelog/15083.txt new file mode 100644 index 000000000000..301f0f43b288 --- /dev/null +++ b/.changelog/15083.txt @@ -0,0 +1,3 @@ +```release-note:bug +connect: fixed bug where endpoint updates for new xDS clusters could block for 15s before being sent to Envoy. +``` diff --git a/.changelog/15090.txt b/.changelog/15090.txt new file mode 100644 index 000000000000..4be43a0e17b0 --- /dev/null +++ b/.changelog/15090.txt @@ -0,0 +1,3 @@ +```release-note:note +deps: Upgrade to use Go 1.19.2 +``` \ No newline at end of file diff --git a/.changelog/15093.txt b/.changelog/15093.txt new file mode 100644 index 000000000000..1387a7b82960 --- /dev/null +++ b/.changelog/15093.txt @@ -0,0 +1,6 @@ +```release-note: improvement +connect: Add Envoy 1.24.0 to support matrix +``` +```release-note: breaking-change +connect: Removes support for Envoy 1.20 +``` diff --git a/.changelog/15108.txt b/.changelog/15108.txt new file mode 100644 index 000000000000..10055f0cd9e8 --- /dev/null +++ b/.changelog/15108.txt @@ -0,0 +1,3 @@ +```release-note:bug +peering: when wan address is set, peering stream should use the wan address. +``` \ No newline at end of file diff --git a/.changelog/15155.txt b/.changelog/15155.txt new file mode 100644 index 000000000000..1b51c2b96c77 --- /dev/null +++ b/.changelog/15155.txt @@ -0,0 +1,3 @@ +```release-note:bug +debug: fixed bug that caused consul debug CLI to error on ACL-disabled clusters +``` \ No newline at end of file diff --git a/.changelog/15160.txt b/.changelog/15160.txt new file mode 100644 index 000000000000..8cfda548f51e --- /dev/null +++ b/.changelog/15160.txt @@ -0,0 +1,3 @@ +```release-note:bug +peering: fix nil pointer in calling handleUpdateService +``` \ No newline at end of file diff --git a/.changelog/15178.txt b/.changelog/15178.txt new file mode 100644 index 000000000000..fadea091332c --- /dev/null +++ b/.changelog/15178.txt @@ -0,0 +1,3 @@ +```release-note:bug +peering: Fix a bug that resulted in /v1/agent/metrics returning an error. +``` diff --git a/.changelog/15186.txt b/.changelog/15186.txt new file mode 100644 index 000000000000..d8b1c65b60b1 --- /dev/null +++ b/.changelog/15186.txt @@ -0,0 +1,3 @@ +```release-note:bug +connect: Fix issue where mesh-gateway settings were not properly inherited from configuration entries. +``` \ No newline at end of file diff --git a/.changelog/15233.txt b/.changelog/15233.txt new file mode 100644 index 000000000000..7c121db06799 --- /dev/null +++ b/.changelog/15233.txt @@ -0,0 +1,3 @@ +```release-note: improvement +integ test: fix flakiness due to test condition from retry app endoint +``` diff --git a/.changelog/15253.txt b/.changelog/15253.txt new file mode 100644 index 000000000000..b0063ffb4799 --- /dev/null +++ b/.changelog/15253.txt @@ -0,0 +1,3 @@ +```release-note:bug +connect: Fixed issue where using Vault 1.11+ as CA provider would eventually break Intermediate CAs [[GH-15217](https://github.com/hashicorp/consul/issues/15217)] +``` \ No newline at end of file diff --git a/.changelog/15272.txt b/.changelog/15272.txt new file mode 100644 index 000000000000..0dffd91cb2bc --- /dev/null +++ b/.changelog/15272.txt @@ -0,0 +1,3 @@ +```release-note:bug +proxycfg(mesh-gateway): Fix issue where deregistered services are not removed from mesh-gateway clusters. +``` diff --git a/.changelog/15302.txt b/.changelog/15302.txt new file mode 100644 index 000000000000..fad082601f84 --- /dev/null +++ b/.changelog/15302.txt @@ -0,0 +1,7 @@ +```release-note:breaking-change +config: update 1.14 config defaults: Enable `peering` and `connect` by default. +``` + +```release-note:breaking-change +config: update 1.14 config defaults: Set gRPC TLS port default value to 8503 +``` \ No newline at end of file diff --git a/.changelog/15317.txt b/.changelog/15317.txt new file mode 100644 index 000000000000..8425dda8b24f --- /dev/null +++ b/.changelog/15317.txt @@ -0,0 +1,3 @@ +```release-note:improvements +acl: Allow reading imported services and nodes from cluster peers with read all permissions +``` \ No newline at end of file diff --git a/.changelog/15320.txt b/.changelog/15320.txt new file mode 100644 index 000000000000..b38b554d2516 --- /dev/null +++ b/.changelog/15320.txt @@ -0,0 +1,3 @@ +```release-note:bug +connect: strip port from DNS SANs for ingress gateway leaf certificate to avoid an invalid hostname error when using the Vault provider. +``` diff --git a/.changelog/14294.txt b/.changelog/15339.txt similarity index 64% rename from .changelog/14294.txt rename to .changelog/15339.txt index 7fcb497b1ec3..e5392e818ab9 100644 --- a/.changelog/14294.txt +++ b/.changelog/15339.txt @@ -2,5 +2,5 @@ config: Add new `ports.grpc_tls` configuration option. Introduce a new port to better separate TLS config from the existing `ports.grpc` config. The new `ports.grpc_tls` only supports TLS encrypted communication. -The existing `ports.grpc` currently supports both plain-text and tls communication, but tls support will be removed in a future release. +The existing `ports.grpc` now only supports plain-text communication. ``` diff --git a/.changelog/15346.txt b/.changelog/15346.txt new file mode 100644 index 000000000000..fe0e833c2b0d --- /dev/null +++ b/.changelog/15346.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +acl: relax permissions on the `WatchServers`, `WatchRoots` and `GetSupportedDataplaneFeatures` gRPC endpoints to accept *any* valid ACL token +``` diff --git a/.changelog/15356.txt b/.changelog/15356.txt new file mode 100644 index 000000000000..3fd854e0bde8 --- /dev/null +++ b/.changelog/15356.txt @@ -0,0 +1,3 @@ +```release-note:security +Ensure that data imported from peers is filtered by ACLs at the UI Nodes/Services endpoints [CVE-2022-3920](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-3920) +``` \ No newline at end of file diff --git a/.changelog/15370.txt b/.changelog/15370.txt new file mode 100644 index 000000000000..dca44b37ccd5 --- /dev/null +++ b/.changelog/15370.txt @@ -0,0 +1,3 @@ +```release-note:improvement +auto-config: Relax the validation on auto-config JWT authorization to allow non-whitespace, non-quote characters in node names. +``` diff --git a/.changelog/15423.txt b/.changelog/15423.txt new file mode 100644 index 000000000000..3721d5c8ceba --- /dev/null +++ b/.changelog/15423.txt @@ -0,0 +1,3 @@ +```release-note:bug +sdk: Fix SDK testutil backwards compatibility by only configuring grpc_tls port for new Consul versions. +``` diff --git a/.changelog/15466.txt b/.changelog/15466.txt new file mode 100644 index 000000000000..9ab3e48e1a8e --- /dev/null +++ b/.changelog/15466.txt @@ -0,0 +1,3 @@ +```release-note:bug +cli: Fix issue where `consul connect envoy` incorrectly uses the HTTPS API configuration for xDS connections. +``` diff --git a/.changelog/15503.txt b/.changelog/15503.txt new file mode 100644 index 000000000000..05997fad5979 --- /dev/null +++ b/.changelog/15503.txt @@ -0,0 +1,3 @@ +```release-note:bug +peering: fix the limit of replication gRPC message; set to 8MB +``` diff --git a/.changelog/15525.txt b/.changelog/15525.txt new file mode 100644 index 000000000000..d920109e6493 --- /dev/null +++ b/.changelog/15525.txt @@ -0,0 +1,3 @@ +```release-note:bug +ca: Fixed issue where using Vault as Connect CA with Vault-managed policies would error on start-up if the intermediate PKI mount existed but was empty +``` \ No newline at end of file diff --git a/.changelog/15541.txt b/.changelog/15541.txt new file mode 100644 index 000000000000..1ec33896e4bf --- /dev/null +++ b/.changelog/15541.txt @@ -0,0 +1,3 @@ +```release-note:bug +agent: Fixed issue where blocking queries with short waits could timeout on the client +``` diff --git a/.changelog/15555.txt b/.changelog/15555.txt new file mode 100644 index 000000000000..c6bec62883d0 --- /dev/null +++ b/.changelog/15555.txt @@ -0,0 +1,3 @@ +```release-note:feature +ui: Add field for fallback server addresses to peer token generation form +``` diff --git a/.changelog/15596.txt b/.changelog/15596.txt new file mode 100644 index 000000000000..cab67c613296 --- /dev/null +++ b/.changelog/15596.txt @@ -0,0 +1,3 @@ +```release-note:improvement +dns: Add support for cluster peering `.service` and `.node` DNS queries. +``` diff --git a/.changelog/15610.txt b/.changelog/15610.txt new file mode 100644 index 000000000000..6e8cfad169bc --- /dev/null +++ b/.changelog/15610.txt @@ -0,0 +1,3 @@ +```release-note:bug +acl: avoid debug log spam in secondary datacenter servers due to management token not being initialized. +``` \ No newline at end of file diff --git a/.changelog/15615.txt b/.changelog/15615.txt new file mode 100644 index 000000000000..e8b0cd30b273 --- /dev/null +++ b/.changelog/15615.txt @@ -0,0 +1,3 @@ +```release-note:bug +peering: better represent non-passing states during peer check flattening +``` diff --git a/.changelog/15659.txt b/.changelog/15659.txt new file mode 100644 index 000000000000..05559f3b1e40 --- /dev/null +++ b/.changelog/15659.txt @@ -0,0 +1,3 @@ +```release-note:improvement +connect: Add support for ConsulResolver to specifies a filter expression +``` diff --git a/.changelog/15661.txt b/.changelog/15661.txt new file mode 100644 index 000000000000..54915746ada4 --- /dev/null +++ b/.changelog/15661.txt @@ -0,0 +1,3 @@ +```release-note:bug +connect: Fixed issue where using Vault 1.11+ as CA provider in a secondary datacenter would eventually break Intermediate CAs +``` diff --git a/.changelog/15669.txt b/.changelog/15669.txt new file mode 100644 index 000000000000..2f83aebcab1a --- /dev/null +++ b/.changelog/15669.txt @@ -0,0 +1,3 @@ +```release-note:improvement +connect: ensure all vault connect CA tests use limited privilege tokens +``` diff --git a/.changelog/15690.txt b/.changelog/15690.txt new file mode 100644 index 000000000000..75e08b2293bf --- /dev/null +++ b/.changelog/15690.txt @@ -0,0 +1,3 @@ +```release-note:bug +connect: Fix peering failovers ignoring local mesh gateway configuration. +``` diff --git a/.changelog/15697.txt b/.changelog/15697.txt new file mode 100644 index 000000000000..bf2bfed84037 --- /dev/null +++ b/.changelog/15697.txt @@ -0,0 +1,3 @@ +```release-note:breaking-change +peering: Newly created peering connections must use only lowercase characters in the `name` field. Existing peerings with uppercase characters will not be modified, but they may encounter issues in various circumstances. To maintain forward compatibility and avoid issues, it is recommended to destroy and re-create any invalid peering connections so that they do not have a name containing uppercase characters. +``` diff --git a/.changelog/15701.txt b/.changelog/15701.txt new file mode 100644 index 000000000000..8caab9cac57a --- /dev/null +++ b/.changelog/15701.txt @@ -0,0 +1,3 @@ +```release-note:improvement +grpc: Use new balancer implementation to reduce periodic WARN logs when shuffling servers. +``` diff --git a/.changelog/15705.txt b/.changelog/15705.txt new file mode 100644 index 000000000000..5fafb83677cf --- /dev/null +++ b/.changelog/15705.txt @@ -0,0 +1,3 @@ +```release-note:security +Upgrade to use Go 1.19.4. This resolves a vulnerability where restricted files can be read on Windows. [CVE-2022-41720](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-41720) +``` diff --git a/.changelog/15737.txt b/.changelog/15737.txt new file mode 100644 index 000000000000..b07fb1a803f8 --- /dev/null +++ b/.changelog/15737.txt @@ -0,0 +1,4 @@ +```release-note:security +Upgrades `golang.org/x/net` to prevent a denial of service by excessive memory usage caused by HTTP2 requests. [CVE-2022-41717](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-41717) +``` + diff --git a/.changelog/15760.txt b/.changelog/15760.txt new file mode 100644 index 000000000000..83816802b07c --- /dev/null +++ b/.changelog/15760.txt @@ -0,0 +1,3 @@ +```release-note:bug +connect: Fix issue where DialedDirectly configuration was not used by Consul Dataplane. +``` diff --git a/.changelog/15769.txt b/.changelog/15769.txt new file mode 100644 index 000000000000..f8fc27a28f65 --- /dev/null +++ b/.changelog/15769.txt @@ -0,0 +1,3 @@ +```release-note:bug +agent: Fix assignment of error when auto-reloading cert and key file changes. +``` diff --git a/.changelog/15789.txt b/.changelog/15789.txt new file mode 100644 index 000000000000..682b4bd1e2e8 --- /dev/null +++ b/.changelog/15789.txt @@ -0,0 +1,3 @@ +```release-note:bug +xds: fix bug where sessions for locally-managed services could fail with "this server has too many xDS streams open" +``` diff --git a/.changelog/15833.txt b/.changelog/15833.txt new file mode 100644 index 000000000000..df91a7708ab5 --- /dev/null +++ b/.changelog/15833.txt @@ -0,0 +1,3 @@ +```release-note:bug +connect: Fix issue where service-resolver protocol checks incorrectly errored for failover peer targets. +``` diff --git a/.changelog/15865.txt b/.changelog/15865.txt new file mode 100644 index 000000000000..6e34813a8144 --- /dev/null +++ b/.changelog/15865.txt @@ -0,0 +1,3 @@ +```release-note:bug +connect: Fix issue where watches on upstream failover peer targets did not always query the correct data. +``` diff --git a/.changelog/15866.txt b/.changelog/15866.txt new file mode 100644 index 000000000000..09fc7da70861 --- /dev/null +++ b/.changelog/15866.txt @@ -0,0 +1,3 @@ +```release-note:bug +agent: Fix issue where the agent cache would incorrectly mark protobuf objects as updated. +``` diff --git a/.changelog/15913.txt b/.changelog/15913.txt new file mode 100644 index 000000000000..1d54f64a7ae6 --- /dev/null +++ b/.changelog/15913.txt @@ -0,0 +1,3 @@ +```release-note:bug +cli: Fix issue where `consul connect envoy` was unable to configure TLS over unix-sockets to gRPC. +``` diff --git a/.changelog/15979.txt b/.changelog/15979.txt new file mode 100644 index 000000000000..d06c39be24f5 --- /dev/null +++ b/.changelog/15979.txt @@ -0,0 +1,3 @@ +```release-note:improvement +envoy: add `MaxEjectionPercent` and `BaseEjectionTime` to passive health check configs. +``` \ No newline at end of file diff --git a/.changelog/15988.txt b/.changelog/15988.txt new file mode 100644 index 000000000000..a5df03ad687e --- /dev/null +++ b/.changelog/15988.txt @@ -0,0 +1,3 @@ +```release-note:improvements +cli: Added a flag, `-enable-config-gen-logging`, to the `connect envoy` command to display log messages when generating the bootstrap config. +``` diff --git a/.changelog/16000.txt b/.changelog/16000.txt new file mode 100644 index 000000000000..aeea16f5e7f0 --- /dev/null +++ b/.changelog/16000.txt @@ -0,0 +1,3 @@ +```release-note:breaking-change +connect: Fix configuration merging for transparent proxy upstreams. Proxy-defaults and service-defaults config entries were not correctly merged for implicit upstreams in transparent proxy mode and would result in some configuration not being applied. To avoid issues when upgrading, ensure that any proxy-defaults or service-defaults have correct configuration for upstreams, since all fields will now be properly used to configure proxies. +``` diff --git a/.changelog/16015.txt b/.changelog/16015.txt new file mode 100644 index 000000000000..6d9e05294bb6 --- /dev/null +++ b/.changelog/16015.txt @@ -0,0 +1,3 @@ +```release-note:feature +connect: add flags `envoy-ready-bind-port` and `envoy-ready-bind-address` to the `consul connect envoy` command that allows configuration of readiness probe on proxy for any service kind. +``` \ No newline at end of file diff --git a/.changelog/16024.txt b/.changelog/16024.txt new file mode 100644 index 000000000000..d3d4575ba375 --- /dev/null +++ b/.changelog/16024.txt @@ -0,0 +1,4 @@ +```release-note:improvement +partitiion: **(Consul Enterprise only)** when loading service from on-disk config file or sending API request to agent endpoint, +if the partition is unspecified, consul will default the partition in the request to agent's partition +``` diff --git a/.changelog/16230.txt b/.changelog/16230.txt new file mode 100644 index 000000000000..81e574798a09 --- /dev/null +++ b/.changelog/16230.txt @@ -0,0 +1,3 @@ +```release-note:bug +peering: Fix issue where secondary wan-federated datacenters could not be used as peering acceptors. +``` diff --git a/.changelog/16257.txt b/.changelog/16257.txt new file mode 100644 index 000000000000..8e98530c421a --- /dev/null +++ b/.changelog/16257.txt @@ -0,0 +1,3 @@ +```release-note:bug +peering: Fix issue where mesh gateways would use the wrong address when contacting a remote peer with the same datacenter name. +``` diff --git a/.changelog/16263.txt b/.changelog/16263.txt new file mode 100644 index 000000000000..a8cd3f9043af --- /dev/null +++ b/.changelog/16263.txt @@ -0,0 +1,4 @@ +```release-note:security +Upgrade to use Go 1.20.1. +This resolves vulnerabilities [CVE-2022-41724](https://go.dev/issue/58001) in `crypto/tls` and [CVE-2022-41723](https://go.dev/issue/57855) in `net/http`. +``` diff --git a/.changelog/16339.txt b/.changelog/16339.txt new file mode 100644 index 000000000000..cf44f010aff5 --- /dev/null +++ b/.changelog/16339.txt @@ -0,0 +1,3 @@ +```release-note:bug +peering: Fix bug where services were incorrectly imported as connect-enabled. +``` diff --git a/.changelog/16358.txt b/.changelog/16358.txt new file mode 100644 index 000000000000..91fcfe4505c4 --- /dev/null +++ b/.changelog/16358.txt @@ -0,0 +1,3 @@ +```release-note:improvement +container: Upgrade container image to use to Alpine 3.17. +``` diff --git a/.changelog/16495.txt b/.changelog/16495.txt new file mode 100644 index 000000000000..4b8ee933ed0e --- /dev/null +++ b/.changelog/16495.txt @@ -0,0 +1,3 @@ +```release-note:improvement +mesh: Add ServiceResolver RequestTimeout for route timeouts to make request timeouts configurable +``` diff --git a/.changelog/16497.txt b/.changelog/16497.txt new file mode 100644 index 000000000000..3aa3633ac3a6 --- /dev/null +++ b/.changelog/16497.txt @@ -0,0 +1,3 @@ +```release-note:bug +proxycfg: ensure that an irrecoverable error in proxycfg closes the xds session and triggers a replacement proxycfg watcher +``` diff --git a/.changelog/16498.txt b/.changelog/16498.txt new file mode 100644 index 000000000000..cdb045d67c9a --- /dev/null +++ b/.changelog/16498.txt @@ -0,0 +1,3 @@ +```release-note:bug +proxycfg: fix a bug where terminating gateways were not cleaning up deleted service resolvers for their referenced services +``` diff --git a/.changelog/16499.txt b/.changelog/16499.txt new file mode 100644 index 000000000000..4bd50db47e8a --- /dev/null +++ b/.changelog/16499.txt @@ -0,0 +1,3 @@ +```release-note:bug +mesh: Fix resolution of service resolvers with subsets for external upstreams +``` diff --git a/.changelog/16552.txt b/.changelog/16552.txt new file mode 100644 index 000000000000..40633be17307 --- /dev/null +++ b/.changelog/16552.txt @@ -0,0 +1,3 @@ +```release-note:improvement +raft: Remove expensive reflection from raft/mesh hot path +``` diff --git a/.changelog/16570.txt b/.changelog/16570.txt new file mode 100644 index 000000000000..ad07cda81c06 --- /dev/null +++ b/.changelog/16570.txt @@ -0,0 +1,3 @@ +```release-note:bug +peering: Fixes a bug that can lead to peering service deletes impacting the state of local services +``` diff --git a/.changelog/16592.txt b/.changelog/16592.txt new file mode 100644 index 000000000000..ba37d69015ff --- /dev/null +++ b/.changelog/16592.txt @@ -0,0 +1,3 @@ +```release-note:bug +ca: Fixes a bug where updating Vault CA Provider config would cause TLS issues in the service mesh +``` diff --git a/.changelog/16660.txt b/.changelog/16660.txt new file mode 100644 index 000000000000..f8971862165c --- /dev/null +++ b/.changelog/16660.txt @@ -0,0 +1,3 @@ +```release-note:bug +ui: fix PUT token request with adding missed AccessorID property to requestBody +``` \ No newline at end of file diff --git a/.changelog/16693.txt b/.changelog/16693.txt new file mode 100644 index 000000000000..8a9b4bb475b1 --- /dev/null +++ b/.changelog/16693.txt @@ -0,0 +1,3 @@ +```release-note:bug +peering: Fixes a bug where the importing partition was not added to peered failover targets, which causes issues when the importing partition is a non-default partition. +``` \ No newline at end of file diff --git a/.changelog/16700.txt b/.changelog/16700.txt new file mode 100644 index 000000000000..82da5936ddb5 --- /dev/null +++ b/.changelog/16700.txt @@ -0,0 +1,3 @@ +```release-note:bug +audit-logging: (Enterprise only) Fix a bug where `/agent/monitor` and `/agent/metrics` endpoints return a `Streaming not supported` error when audit logs are enabled. This also fixes the delay receiving logs when running `consul monitor` against an agent with audit logs enabled. +``` diff --git a/.changelog/16729.txt b/.changelog/16729.txt new file mode 100644 index 000000000000..36c6e1aeabb2 --- /dev/null +++ b/.changelog/16729.txt @@ -0,0 +1,3 @@ +```release-note:bug +peering: Fix issue resulting in prepared query failover to cluster peers never un-failing over. +``` diff --git a/.changelog/16776.txt b/.changelog/16776.txt new file mode 100644 index 000000000000..0159aee85897 --- /dev/null +++ b/.changelog/16776.txt @@ -0,0 +1,3 @@ +```release-note:improvement +peering: allow re-establishing terminated peering from new token without deleting existing peering first. +``` \ No newline at end of file diff --git a/.changelog/16845.txt b/.changelog/16845.txt new file mode 100644 index 000000000000..7181e319e3ae --- /dev/null +++ b/.changelog/16845.txt @@ -0,0 +1,3 @@ +```release-note:improvement +systemd: set service type to notify. +``` diff --git a/.changelog/16888.txt b/.changelog/16888.txt new file mode 100644 index 000000000000..4cea20517ae0 --- /dev/null +++ b/.changelog/16888.txt @@ -0,0 +1,3 @@ +```release-note:improvement +connect: update supported envoy versions to 1.21.6, 1.22.11, 1.23.8, 1.24.6 +``` diff --git a/.changelog/16916.txt b/.changelog/16916.txt new file mode 100644 index 000000000000..a911e14d7e0a --- /dev/null +++ b/.changelog/16916.txt @@ -0,0 +1,3 @@ +```release-note:improvement +hcp: Add support for linking existing Consul clusters to HCP management plane. +``` \ No newline at end of file diff --git a/.changelog/17048.txt b/.changelog/17048.txt new file mode 100644 index 000000000000..74f31c7ce275 --- /dev/null +++ b/.changelog/17048.txt @@ -0,0 +1,3 @@ +```release-note:bug +Fix an bug where decoding some Config structs with unset pointer fields could fail with `reflect: call of reflect.Value.Type on zero Value`. +``` diff --git a/.changelog/17160.txt b/.changelog/17160.txt new file mode 100644 index 000000000000..666a6e8f252c --- /dev/null +++ b/.changelog/17160.txt @@ -0,0 +1,3 @@ +```release-note:bug +Fix a bug that wrongly trims domains when there is an overlap with DC name. +``` diff --git a/.changelog/17185.txt b/.changelog/17185.txt new file mode 100644 index 000000000000..cde123e2deb4 --- /dev/null +++ b/.changelog/17185.txt @@ -0,0 +1,3 @@ +```release-note:bug +xds: Fix possible panic that can when generating clusters before the root certificates have been fetched. +``` diff --git a/.changelog/17235.txt b/.changelog/17235.txt new file mode 100644 index 000000000000..3356b715ef31 --- /dev/null +++ b/.changelog/17235.txt @@ -0,0 +1,3 @@ +```release-note:bug +peering: Fix issue where peer streams could incorrectly deregister services in various scenarios. +``` diff --git a/.changelog/17236.txt b/.changelog/17236.txt new file mode 100644 index 000000000000..c824bb7ed782 --- /dev/null +++ b/.changelog/17236.txt @@ -0,0 +1,3 @@ +```release-note:improvement +logging: change snapshot log header from `agent.server.snapshot` to `agent.server.raft.snapshot` +``` diff --git a/.changelog/17240.txt b/.changelog/17240.txt new file mode 100644 index 000000000000..59d120f747ba --- /dev/null +++ b/.changelog/17240.txt @@ -0,0 +1,12 @@ +```release-note:security +Upgrade to use Go 1.20.4. +This resolves vulnerabilities [CVE-2023-24537](https://github.com/advisories/GHSA-9f7g-gqwh-jpf5)(`go/scanner`), +[CVE-2023-24538](https://github.com/advisories/GHSA-v4m2-x4rp-hv22)(`html/template`), +[CVE-2023-24534](https://github.com/advisories/GHSA-8v5j-pwr7-w5f8)(`net/textproto`) and +[CVE-2023-24536](https://github.com/advisories/GHSA-9f7g-gqwh-jpf5)(`mime/multipart`). +Also, `golang.org/x/net` has been updated to v0.7.0 to resolve CVEs [CVE-2022-41721 +](https://github.com/advisories/GHSA-fxg5-wq6x-vr4w +), [CVE-2022-27664](https://github.com/advisories/GHSA-69cg-p879-7622) and [CVE-2022-41723 +](https://github.com/advisories/GHSA-vvpx-j8f3-3w6h +.) +``` diff --git a/.changelog/17241.txt b/.changelog/17241.txt new file mode 100644 index 000000000000..0369710928ed --- /dev/null +++ b/.changelog/17241.txt @@ -0,0 +1,3 @@ +```release-note:bug +connect: Fix multiple inefficient behaviors when querying service health. +``` diff --git a/.changelog/17270.txt b/.changelog/17270.txt new file mode 100644 index 000000000000..b9bd52888e4c --- /dev/null +++ b/.changelog/17270.txt @@ -0,0 +1,3 @@ +```release-note:bug +grpc: ensure grpc resolver correctly uses lan/wan addresses on servers +``` diff --git a/.changelog/17317.txt b/.changelog/17317.txt new file mode 100644 index 000000000000..76c86a0a28eb --- /dev/null +++ b/.changelog/17317.txt @@ -0,0 +1,3 @@ +```release-note:bug +connect: fix a bug with Envoy potentially starting with incomplete configuration by not waiting enough for initial xDS configuration. +``` diff --git a/.changelog/17426.txt b/.changelog/17426.txt new file mode 100644 index 000000000000..d8fbd2ae2c4d --- /dev/null +++ b/.changelog/17426.txt @@ -0,0 +1,5 @@ +```release-note:improvement + peering: gRPC queries for TrustBundleList, TrustBundleRead, PeeringList, and PeeringRead now support blocking semantics, + reducing network and CPU demand. + The HTTP APIs for Peering List and Read have been updated to support blocking. + ``` \ No newline at end of file diff --git a/.changelog/17456.txt b/.changelog/17456.txt new file mode 100644 index 000000000000..7b81d53543ca --- /dev/null +++ b/.changelog/17456.txt @@ -0,0 +1,3 @@ +```release-note:bug +peering: Fix issue where modifying the list of exported services did not correctly replicate changes for services that exist in a non-default namespace. +``` diff --git a/.changelog/17483.txt b/.changelog/17483.txt new file mode 100644 index 000000000000..26c81dbe4cdf --- /dev/null +++ b/.changelog/17483.txt @@ -0,0 +1,3 @@ +```release-note:bug +peering: Fix a bug that caused server agents to continue cleaning up peering resources even after loss of leadership. +``` diff --git a/.changelog/17513.txt b/.changelog/17513.txt new file mode 100644 index 000000000000..a87557d08cab --- /dev/null +++ b/.changelog/17513.txt @@ -0,0 +1,3 @@ +```release-note:security +Update to UBI base image to 9.2. +``` diff --git a/.changelog/17541.txt b/.changelog/17541.txt new file mode 100644 index 000000000000..6dc29121dff9 --- /dev/null +++ b/.changelog/17541.txt @@ -0,0 +1,3 @@ +```release-note:bug +connect: reverts #17317 fix that caused a downstream error for Ingress/Mesh/Terminating GWs when their respective config entry does not already exist. +``` diff --git a/.changelog/17547.txt b/.changelog/17547.txt new file mode 100644 index 000000000000..7311d9173e0c --- /dev/null +++ b/.changelog/17547.txt @@ -0,0 +1,3 @@ +```release-note:improvement +connect: update supported envoy versions to 1.21.6, 1.22.11, 1.23.9, 1.24.7 +``` diff --git a/.changelog/17565.txt b/.changelog/17565.txt new file mode 100644 index 000000000000..f7cf46c38954 --- /dev/null +++ b/.changelog/17565.txt @@ -0,0 +1,3 @@ +```release-note:feature +reloadable config: Made enable_debug config reloadable and enable pprof command to work when config toggles to true +``` \ No newline at end of file diff --git a/.changelog/17577.txt b/.changelog/17577.txt new file mode 100644 index 000000000000..3699d5261122 --- /dev/null +++ b/.changelog/17577.txt @@ -0,0 +1,3 @@ +```release-note:improvement +fix metric names in /docs/agent/telemetry +``` \ No newline at end of file diff --git a/.changelog/17582.txt b/.changelog/17582.txt new file mode 100644 index 000000000000..122b9df98116 --- /dev/null +++ b/.changelog/17582.txt @@ -0,0 +1,3 @@ +```release-note:feature +cli: `consul operator raft list-peers` command shows the number of commits each follower is trailing the leader by to aid in troubleshooting. +``` diff --git a/.changelog/17596.txt b/.changelog/17596.txt new file mode 100644 index 000000000000..1058df1ea3ab --- /dev/null +++ b/.changelog/17596.txt @@ -0,0 +1,3 @@ +```release-note:improvement + debug: change default setting of consul debug command. now default duration is 5ms and default log level is 'TRACE' + ``` \ No newline at end of file diff --git a/.changelog/17636.txt b/.changelog/17636.txt new file mode 100644 index 000000000000..aa06f9191b96 --- /dev/null +++ b/.changelog/17636.txt @@ -0,0 +1,3 @@ +```release-note:bug +cache: fix a few minor goroutine leaks in leaf certs and the agent cache +``` diff --git a/.changelog/17780.txt b/.changelog/17780.txt new file mode 100644 index 000000000000..b90925a8b9fd --- /dev/null +++ b/.changelog/17780.txt @@ -0,0 +1,3 @@ +```release-note:feature +cli: `consul watch` command uses `-filter` expression to filter response from checks, services, nodes, and service. +``` diff --git a/.changelog/17846.txt b/.changelog/17846.txt new file mode 100644 index 000000000000..bd5a052f851f --- /dev/null +++ b/.changelog/17846.txt @@ -0,0 +1,3 @@ +```release-note:bug +connect/ca: Fixes a bug preventing CA configuration updates in secondary datacenters +``` diff --git a/.changelog/17894.txt b/.changelog/17894.txt new file mode 100644 index 000000000000..5749f995f71a --- /dev/null +++ b/.changelog/17894.txt @@ -0,0 +1,3 @@ +```release-note:bug +connect: Fix incorrect protocol config merging for transparent proxy implicit upstreams. +``` diff --git a/.changelog/18024.txt b/.changelog/18024.txt new file mode 100644 index 000000000000..a661e7304c62 --- /dev/null +++ b/.changelog/18024.txt @@ -0,0 +1,3 @@ +```release-note:bug +connect: fix a bug with Envoy potentially starting with incomplete configuration by not waiting enough for initial xDS configuration. +``` \ No newline at end of file diff --git a/.changelog/18080.txt b/.changelog/18080.txt new file mode 100644 index 000000000000..9826b249eb31 --- /dev/null +++ b/.changelog/18080.txt @@ -0,0 +1,3 @@ +```release-note:improvement +Fix some typos in metrics docs +``` \ No newline at end of file diff --git a/.changelog/18140.txt b/.changelog/18140.txt new file mode 100644 index 000000000000..fabd9fc2916b --- /dev/null +++ b/.changelog/18140.txt @@ -0,0 +1,3 @@ +```release-note:improvement +hcp: Removes requirement for HCP to provide a management token +``` diff --git a/.changelog/18150.txt b/.changelog/18150.txt new file mode 100644 index 000000000000..492e7ad1b9ff --- /dev/null +++ b/.changelog/18150.txt @@ -0,0 +1,3 @@ +```release-note:improvement +xds: Explicitly enable WebSocket connection upgrades in HTTP connection manager +``` diff --git a/.changelog/18186.txt b/.changelog/18186.txt new file mode 100644 index 000000000000..dcc75b57653b --- /dev/null +++ b/.changelog/18186.txt @@ -0,0 +1,3 @@ +```release-note:security +Upgrade golang.org/x/net to address [CVE-2023-29406](https://nvd.nist.gov/vuln/detail/CVE-2023-29406) +``` diff --git a/.changelog/18190.txt b/.changelog/18190.txt new file mode 100644 index 000000000000..3468442e2161 --- /dev/null +++ b/.changelog/18190.txt @@ -0,0 +1,5 @@ +```release-note:security +Upgrade to use Go 1.20.6. +This resolves [CVE-2023-29406](https://github.com/advisories/GHSA-f8f7-69v5-w4vx)(`net/http`) for uses of the standard library. +A separate change updates dependencies on `golang.org/x/net` to use `0.12.0`. +``` diff --git a/.changelog/18223.txt b/.changelog/18223.txt new file mode 100644 index 000000000000..067ca64f48e8 --- /dev/null +++ b/.changelog/18223.txt @@ -0,0 +1,3 @@ +```release-note:feature +cli: `consul members` command uses `-filter` expression to filter members based on bexpr. +``` diff --git a/.changelog/18302.txt b/.changelog/18302.txt new file mode 100644 index 000000000000..c77e7106be91 --- /dev/null +++ b/.changelog/18302.txt @@ -0,0 +1,4 @@ +```release-note:bug +snapshot: fix access denied and handle is invalid when we call snapshot save on windows - skip sync() for folders in windows in +https://github.com/rboyer/safeio/pull/3 +``` diff --git a/.changelog/18305.txt b/.changelog/18305.txt new file mode 100644 index 000000000000..3cb293dc8a4c --- /dev/null +++ b/.changelog/18305.txt @@ -0,0 +1,3 @@ +```release-note:improvement +connect: update supported envoy versions to 1.21.6, 1.22.11, 1.23.12, 1.24.10 +``` diff --git a/.changelog/18319.txt b/.changelog/18319.txt new file mode 100644 index 000000000000..bb9c8cdf2c72 --- /dev/null +++ b/.changelog/18319.txt @@ -0,0 +1,6 @@ +```release-note:improvement +acl: added builtin ACL policy that provides global read-only access (builtin/global-read-only) +``` +```release-note:improvement +acl: allow for a single slash character in policy names +``` diff --git a/.changelog/18358.txt b/.changelog/18358.txt new file mode 100644 index 000000000000..e29d258c6c92 --- /dev/null +++ b/.changelog/18358.txt @@ -0,0 +1,7 @@ +```release-note:security +Upgrade to use Go 1.20.7. +This resolves vulnerability [CVE-2023-29409](https://nvd.nist.gov/vuln/detail/CVE-2023-29409)(`crypto/tls`). +``` +```release-note:security +Update `golang.org/x/net` to v0.13.0 to address [CVE-2023-3978](https://nvd.nist.gov/vuln/detail/CVE-2023-3978). +``` diff --git a/.changelog/18617.txt b/.changelog/18617.txt new file mode 100644 index 000000000000..1f840d836dee --- /dev/null +++ b/.changelog/18617.txt @@ -0,0 +1,4 @@ +```release-note:improvement +log: Currently consul logs files like this consul-{timestamp}.log. This change makes sure that there is always +consul.log file with the latest logs in it. +``` \ No newline at end of file diff --git a/.changelog/18625.txt b/.changelog/18625.txt new file mode 100644 index 000000000000..8474cac8dc1d --- /dev/null +++ b/.changelog/18625.txt @@ -0,0 +1,5 @@ +```release-note:improvement +Adds flag -append-filename (which works on values version, dc, node and status) to consul snapshot save command. +Adding the flag -append-filename version,dc,node,status will add consul version, consul datacenter, node name and leader/follower +(status) in the file name given in the snapshot save command before the file extension. +``` diff --git a/.changelog/18667.txt b/.changelog/18667.txt new file mode 100644 index 000000000000..c9ef7b455121 --- /dev/null +++ b/.changelog/18667.txt @@ -0,0 +1,3 @@ +```release-note:improvement +api: Add support for listing ACL tokens by service name. +``` diff --git a/.changelog/18681.txt b/.changelog/18681.txt new file mode 100644 index 000000000000..971e9ef81637 --- /dev/null +++ b/.changelog/18681.txt @@ -0,0 +1,3 @@ +```release-note:bug +api: Fix `/v1/agent/self` not returning latest configuration +``` diff --git a/.changelog/18724.txt b/.changelog/18724.txt new file mode 100644 index 000000000000..7fa289eba19f --- /dev/null +++ b/.changelog/18724.txt @@ -0,0 +1,3 @@ +```release-note:bug +telemetry: emit consul version metric on a regular interval. +``` diff --git a/.changelog/18742.txt b/.changelog/18742.txt new file mode 100644 index 000000000000..2d31e5266758 --- /dev/null +++ b/.changelog/18742.txt @@ -0,0 +1,8 @@ +```release-note:security +Upgrade to use Go 1.20.8. This resolves CVEs +[CVE-2023-39320](https://github.com/advisories/GHSA-rxv8-v965-v333) (`cmd/go`), +[CVE-2023-39318](https://github.com/advisories/GHSA-vq7j-gx56-rxjh) (`html/template`), +[CVE-2023-39319](https://github.com/advisories/GHSA-vv9m-32rr-3g55) (`html/template`), +[CVE-2023-39321](https://github.com/advisories/GHSA-9v7r-x7cv-v437) (`crypto/tls`), and +[CVE-2023-39322](https://github.com/advisories/GHSA-892h-r6cr-53g4) (`crypto/tls`) +``` \ No newline at end of file diff --git a/.changelog/18773.txt b/.changelog/18773.txt new file mode 100644 index 000000000000..80c1ac4d5c7c --- /dev/null +++ b/.changelog/18773.txt @@ -0,0 +1,3 @@ +```release-note:bug +ca: Vault provider now cleans up the previous Vault issuer when generating a new leaf signing certificate +``` diff --git a/.changelog/5102.txt b/.changelog/5102.txt new file mode 100644 index 000000000000..97d8c7bf8bf1 --- /dev/null +++ b/.changelog/5102.txt @@ -0,0 +1,3 @@ +```release-note:feature +server: **(Enterprise Only)** allow automatic license utilization reporting. +``` \ No newline at end of file diff --git a/.changelog/_3550.txt b/.changelog/_3550.txt new file mode 100644 index 000000000000..2029e57d335a --- /dev/null +++ b/.changelog/_3550.txt @@ -0,0 +1,3 @@ +```release-note:bug +namespace: **(Enterprise Only)** Fixed a bug where a client may incorrectly log that namespaces were not enabled in the local datacenter +``` \ No newline at end of file diff --git a/.changelog/_3556.txt b/.changelog/_3556.txt new file mode 100644 index 000000000000..520c7b8cd298 --- /dev/null +++ b/.changelog/_3556.txt @@ -0,0 +1,3 @@ +```release-note:feature +snapshot: **(Enterprise Only)** Add support for the snapshot agent to use an IAM role for authentication/authorization when managing snapshots in S3. +``` \ No newline at end of file diff --git a/.changelog/_3557.txt b/.changelog/_3557.txt new file mode 100644 index 000000000000..4ffab7042843 --- /dev/null +++ b/.changelog/_3557.txt @@ -0,0 +1,3 @@ +```release-note:improvement +dns/peering: **(Enterprise Only)** Support addresses in the formats `.virtual..ns..ap..peer.consul` and `.virtual..ap..peer.consul`. This longer form address that allows specifying `.peer` would need to be used for tproxy DNS requests made within non-default partitions for imported services. +``` diff --git a/.changelog/_3729.txt b/.changelog/_3729.txt new file mode 100644 index 000000000000..6032c69ed594 --- /dev/null +++ b/.changelog/_3729.txt @@ -0,0 +1,3 @@ +```release-note:bug +namespace: **(Enterprise Only)** Fix a bug that caused blocking queries during namespace replication to timeout +``` \ No newline at end of file diff --git a/.changelog/_3783.txt b/.changelog/_3783.txt new file mode 100644 index 000000000000..2835ab816320 --- /dev/null +++ b/.changelog/_3783.txt @@ -0,0 +1,3 @@ +```release-note:bug +cli: **(Enterprise Only)** Fix issue where `consul partition update` subcommand was not registered and therefore not available through the cli. +``` \ No newline at end of file diff --git a/.changelog/_3846.txt b/.changelog/_3846.txt new file mode 100644 index 000000000000..ac59261688ff --- /dev/null +++ b/.changelog/_3846.txt @@ -0,0 +1,3 @@ +```release-note:bug +agent: **(Enterprise Only)** Ensure configIntentionsConvertToList does not compare empty strings with populated strings when filtering intentions created prior to AdminPartitions. +``` diff --git a/.changelog/_4696.txt b/.changelog/_4696.txt new file mode 100644 index 000000000000..951896fd66f3 --- /dev/null +++ b/.changelog/_4696.txt @@ -0,0 +1,3 @@ +```release-note:bug +peering: **(Consul Enterprise only)** Fix issue where connect-enabled services with peer upstreams incorrectly required `service:write` access in the `default` namespace to query data, which was too restrictive. Now having `service:write` to any namespace is sufficient to query the peering data. +``` diff --git a/.changelog/_4832.txt b/.changelog/_4832.txt new file mode 100644 index 000000000000..b45768715540 --- /dev/null +++ b/.changelog/_4832.txt @@ -0,0 +1,3 @@ +```release-note:bug +peering: **(Consul Enterprise only)** Fix issue where resolvers, routers, and splitters referencing peer targets may not work correctly for non-default partitions and namespaces. Enterprise customers leveraging peering are encouraged to upgrade both servers and agents to avoid this problem. +``` diff --git a/.changelog/_5517.txt b/.changelog/_5517.txt new file mode 100644 index 000000000000..5152a6ff78f7 --- /dev/null +++ b/.changelog/_5517.txt @@ -0,0 +1,3 @@ +```release-note:bug +namespaces: **(Enterprise only)** fixes a bug where agent health checks stop syncing for all services on a node if the namespace of any service has been removed from the server. +``` diff --git a/.changelog/_5614.txt b/.changelog/_5614.txt new file mode 100644 index 000000000000..9951b9111875 --- /dev/null +++ b/.changelog/_5614.txt @@ -0,0 +1,4 @@ +```release-note:bug +namespaces: **(Enterprise only)** fixes a bug where namespaces are stuck in a deferred deletion state indefinitely under some conditions. +Also fixes the Consul query metadata present in the HTTP headers of the namespace read and list endpoints. +``` diff --git a/.circleci/bash_env.sh b/.circleci/bash_env.sh deleted file mode 100644 index 69004e7c8d00..000000000000 --- a/.circleci/bash_env.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -export GIT_COMMIT=$(git rev-parse --short HEAD) -export GIT_COMMIT_YEAR=$(git show -s --format=%cd --date=format:%Y HEAD) -export GIT_DIRTY=$(test -n "`git status --porcelain`" && echo "+CHANGES" || true) -export GIT_IMPORT=github.com/hashicorp/consul/version -# we're using this for build date because it's stable across platform builds -# the env -i and -noprofile are used to ensure we don't try to recursively call this profile when starting bash -export GIT_DATE=$(env -i /bin/bash --noprofile -norc ${CIRCLE_WORKING_DIRECTORY}/build-support/scripts/build-date.sh) -export GOLDFLAGS="-X ${GIT_IMPORT}.GitCommit=${GIT_COMMIT}${GIT_DIRTY} -X ${GIT_IMPORT}.BuildDate=${GIT_DATE}" diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 1413810f1dfe..000000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,1207 +0,0 @@ ---- -version: 2.1 - -parameters: - commit: - type: string - default: "" - description: "Commit to run load tests against" - trigger-load-test: - type: boolean - default: false - description: "Boolean whether to run the load test workflow" - -references: - paths: - test-results: &TEST_RESULTS_DIR /tmp/test-results - environment: &ENVIRONMENT - TEST_RESULTS_DIR: *TEST_RESULTS_DIR - EMAIL: noreply@hashicorp.com - GIT_AUTHOR_NAME: circleci-consul - GIT_COMMITTER_NAME: circleci-consul - S3_ARTIFACT_BUCKET: consul-dev-artifacts-v2 - BASH_ENV: .circleci/bash_env.sh - VAULT_BINARY_VERSION: 1.9.4 - GO_VERSION: 1.18.1 - envoy-versions: &supported_envoy_versions - - &default_envoy_version "1.20.7" - - "1.21.5" - - "1.22.5" - - "1.23.1" - nomad-versions: &supported_nomad_versions - - &default_nomad_version "1.3.3" - - "1.2.10" - - "1.1.16" - images: - # When updating the Go version, remember to also update the versions in the - # workflows section for go-test-lib jobs. - go: &GOLANG_IMAGE docker.mirror.hashicorp.services/cimg/go:1.18.1 - ember: &EMBER_IMAGE docker.mirror.hashicorp.services/circleci/node:14-browsers - ubuntu: &UBUNTU_CI_IMAGE ubuntu-2004:202201-02 - cache: - yarn: &YARN_CACHE_KEY consul-ui-v9-{{ checksum "ui/yarn.lock" }} - -steps: - install-gotestsum: &install-gotestsum - name: install gotestsum - environment: - GOTESTSUM_RELEASE: 1.6.4 - command: | - ARCH=`uname -m` - if [[ "$ARCH" == "aarch64" ]]; then - ARCH="arm64" - else - ARCH="amd64" - fi - url=https://github.com/gotestyourself/gotestsum/releases/download - curl -sSL "${url}/v${GOTESTSUM_RELEASE}/gotestsum_${GOTESTSUM_RELEASE}_linux_${ARCH}.tar.gz" | \ - sudo tar -xz --overwrite -C /usr/local/bin gotestsum - - get-aws-cli: &get-aws-cli - run: - name: download and install AWS CLI - command: | - curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" - echo -e "${AWS_CLI_GPG_KEY}" | gpg --import - curl -o awscliv2.sig https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip.sig - gpg --verify awscliv2.sig awscliv2.zip - unzip awscliv2.zip - sudo ./aws/install - - # This step MUST be at the end of any set of steps due to the 'when' condition - notify-slack-failure: ¬ify-slack-failure - name: notify-slack-failure - when: on_fail - command: | - if [[ $CIRCLE_BRANCH == "main" ]]; then - CIRCLE_ENDPOINT="https://app.circleci.com/pipelines/github/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}?branch=${CIRCLE_BRANCH}" - GITHUB_ENDPOINT="https://github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/commit/${CIRCLE_SHA1}" - COMMIT_MESSAGE=$(git log -1 --pretty=%B | head -n1) - SHORT_REF=$(git rev-parse --short "${CIRCLE_SHA1}") - curl -X POST -H 'Content-type: application/json' \ - --data \ - "{ \ - \"attachments\": [ \ - { \ - \"fallback\": \"CircleCI job failed!\", \ - \"text\": \"❌ Failed: \`${CIRCLE_USERNAME}\`'s <${CIRCLE_BUILD_URL}|${CIRCLE_STAGE}> job failed for commit <${GITHUB_ENDPOINT}|${SHORT_REF}> on \`${CIRCLE_BRANCH}\`!\n\n- <${COMMIT_MESSAGE}\", \ - \"footer\": \"${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}\", \ - \"ts\": \"$(date +%s)\", \ - \"color\": \"danger\" \ - } \ - ] \ - }" "${FEED_CONSUL_GH_URL}" - else - echo "Not posting slack failure notifications for non-main branch" - fi - -commands: - assume-role: - description: "Assume role to an ARN" - parameters: - access-key: - type: env_var_name - default: AWS_ACCESS_KEY_ID - secret-key: - type: env_var_name - default: AWS_SECRET_ACCESS_KEY - role-arn: - type: env_var_name - default: ROLE_ARN - steps: - # Only run the assume-role command for the main repo. The AWS credentials aren't available for forks. - - run: | - if [[ "${CIRCLE_BRANCH%%/*}/" != "pull/" ]]; then - export AWS_ACCESS_KEY_ID="${<< parameters.access-key >>}" - export AWS_SECRET_ACCESS_KEY="${<< parameters.secret-key >>}" - export ROLE_ARN="${<< parameters.role-arn >>}" - # assume role has duration of 15 min (the minimum allowed) - CREDENTIALS="$(aws sts assume-role --duration-seconds 900 --role-arn ${ROLE_ARN} --role-session-name build-${CIRCLE_SHA1} | jq '.Credentials')" - echo "export AWS_ACCESS_KEY_ID=$(echo $CREDENTIALS | jq -r '.AccessKeyId')" >> $BASH_ENV - echo "export AWS_SECRET_ACCESS_KEY=$(echo $CREDENTIALS | jq -r '.SecretAccessKey')" >> $BASH_ENV - echo "export AWS_SESSION_TOKEN=$(echo $CREDENTIALS | jq -r '.SessionToken')" >> $BASH_ENV - fi - - run-go-test-full: - parameters: - go_test_flags: - type: string - default: "" - steps: - - attach_workspace: - at: /home/circleci/go/bin - - run: sudo apt-get update --allow-releaseinfo-change-suite --allow-releaseinfo-change-version && sudo apt-get install -y rsyslog - - run: sudo service rsyslog start - - run: go mod download - - run: - name: go test - command: | - mkdir -p $TEST_RESULTS_DIR /tmp/jsonfile - PACKAGE_NAMES=$(go list -tags "$GOTAGS" ./... | circleci tests split --split-by=timings --timings-type=classname) - echo "Running $(echo $PACKAGE_NAMES | wc -w) packages" - echo $PACKAGE_NAMES - # some tests expect this umask, and arm images have a different default - umask 0022 - - << parameters.go_test_flags >> - - gotestsum \ - --format=short-verbose \ - --jsonfile /tmp/jsonfile/go-test-${CIRCLE_NODE_INDEX}.log \ - --debug \ - --rerun-fails=3 \ - --rerun-fails-max-failures=40 \ - --rerun-fails-report=/tmp/gotestsum-rerun-fails \ - --packages="$PACKAGE_NAMES" \ - --junitfile $TEST_RESULTS_DIR/gotestsum-report.xml -- \ - -tags="$GOTAGS" -p 2 \ - ${GO_TEST_FLAGS-} \ - -cover -coverprofile=coverage.txt - - - store_test_results: - path: *TEST_RESULTS_DIR - - store_artifacts: - path: *TEST_RESULTS_DIR - - store_artifacts: - path: /tmp/jsonfile - - run: &rerun-fails-report - name: "Re-run fails report" - command: | - .circleci/scripts/rerun-fails-report.sh /tmp/gotestsum-rerun-fails - - run: *notify-slack-failure - -jobs: - # lint consul tests - lint-consul-retry: - docker: - - image: *GOLANG_IMAGE - steps: - - checkout - - run: go install github.com/hashicorp/lint-consul-retry@master && lint-consul-retry - - run: *notify-slack-failure - - lint-enums: - docker: - - image: *GOLANG_IMAGE - steps: - - checkout - - run: go install github.com/reillywatson/enumcover/cmd/enumcover@master && enumcover ./... - - run: *notify-slack-failure - - lint: - description: "Run golangci-lint" - parameters: - go-arch: - type: string - default: "" - docker: - - image: *GOLANG_IMAGE - resource_class: xlarge - environment: - GOTAGS: "" # No tags for OSS but there are for enterprise - GOARCH: "<>" - steps: - - checkout - - run: go env - - run: - name: Install golangci-lint - command: make lint-tools - - run: go mod download - - run: - name: lint - command: &lintcmd | - golangci-lint run --build-tags="$GOTAGS" -v - - run: - name: lint api - working_directory: api - command: *lintcmd - - run: - name: lint sdk - working_directory: sdk - command: *lintcmd - - run: *notify-slack-failure - - check-go-mod: - docker: - - image: *GOLANG_IMAGE - environment: - <<: *ENVIRONMENT - steps: - - checkout - - run: go mod tidy - - run: | - if [[ -n $(git status -s) ]]; then - echo "Git directory has changes" - git status -s - exit 1 - fi - - run: *notify-slack-failure - - check-generated-protobuf: - docker: - - image: *GOLANG_IMAGE - environment: - <<: *ENVIRONMENT - # tput complains if this isn't set to something. - TERM: ansi - steps: - - checkout - - run: - name: Install protobuf - command: make proto-tools - - run: - name: "Protobuf Format" - command: make proto-format - - run: - command: make --always-make proto - - run: | - if ! git diff --exit-code; then - echo "Generated code was not updated correctly" - exit 1 - fi - - run: - name: "Protobuf Lint" - command: make proto-lint - - check-generated-deep-copy: - docker: - - image: *GOLANG_IMAGE - environment: - <<: *ENVIRONMENT - # tput complains if this isn't set to something. - TERM: ansi - steps: - - checkout - - run: - name: Install deep-copy - command: make codegen-tools - - run: - command: make --always-make deep-copy - - run: | - if ! git diff --exit-code; then - echo "Generated code was not updated correctly" - exit 1 - fi - - go-test-arm64: - machine: - image: *UBUNTU_CI_IMAGE - resource_class: arm.large - parallelism: 4 - environment: - <<: *ENVIRONMENT - GOTAGS: "" # No tags for OSS but there are for enterprise - # GOMAXPROCS defaults to number of cores on underlying hardware, set - # explicitly to avoid OOM issues https://support.circleci.com/hc/en-us/articles/360034684273-common-GoLang-memory-issues - GOMAXPROCS: 4 - steps: - - checkout - - run: - command: | - sudo rm -rf /usr/local/go - wget https://dl.google.com/go/go${GO_VERSION}.linux-arm64.tar.gz - sudo tar -C /usr/local -xzvf go${GO_VERSION}.linux-arm64.tar.gz - - run: *install-gotestsum - - run: go mod download - - run: - name: make dev - command: | - if [[ "$CIRCLE_BRANCH" =~ ^main$|^release/ ]]; then - make dev - mkdir -p /home/circleci/bin - cp ./bin/consul /home/circleci/bin/consul - fi - - run-go-test-full: - go_test_flags: 'if ! [[ "$CIRCLE_BRANCH" =~ ^main$|^release/ ]]; then export GO_TEST_FLAGS="-short"; fi' - - go-test: - docker: - - image: *GOLANG_IMAGE - resource_class: large - parallelism: 4 - environment: - <<: *ENVIRONMENT - GOTAGS: "" # No tags for OSS but there are for enterprise - # GOMAXPROCS defaults to number of cores on underlying hardware, set - # explicitly to avoid OOM issues https://support.circleci.com/hc/en-us/articles/360034684273-common-GoLang-memory-issues - GOMAXPROCS: 4 - steps: - - checkout - - run-go-test-full - - go-test-race: - docker: - - image: *GOLANG_IMAGE - environment: - <<: *ENVIRONMENT - GOTAGS: "" # No tags for OSS but there are for enterprise - # GOMAXPROCS defaults to number of cores on underlying hardware, set - # explicitly to avoid OOM issues https://support.circleci.com/hc/en-us/articles/360034684273-common-GoLang-memory-issues - GOMAXPROCS: 4 - # The medium resource class (default) boxes are 2 vCPUs, 4GB RAM - # https://circleci.com/docs/2.0/configuration-reference/#docker-executor - # but we can run a little over that limit. - steps: - - checkout - - run: go mod download - - run: - name: go test -race - command: | - mkdir -p $TEST_RESULTS_DIR /tmp/jsonfile - pkgs="$(go list ./... | \ - grep -E -v '^github.com/hashicorp/consul/agent(/consul|/local|/routine-leak-checker)?$' | \ - grep -E -v '^github.com/hashicorp/consul/command/')" - gotestsum \ - --jsonfile /tmp/jsonfile/go-test-race.log \ - --junitfile $TEST_RESULTS_DIR/gotestsum-report.xml -- \ - -tags="$GOTAGS" -p 2 \ - -race -gcflags=all=-d=checkptr=0 \ - $pkgs - - - store_test_results: - path: *TEST_RESULTS_DIR - - store_artifacts: - path: *TEST_RESULTS_DIR - - store_artifacts: - path: /tmp/jsonfile - - run: *notify-slack-failure - - # go-test-32bit is to catch problems where 64-bit ints must be 64-bit aligned - # to use them with sync/atomic. See https://golang.org/pkg/sync/atomic/#pkg-note-BUG. - # Running tests with GOARCH=386 seems to be the best way to detect this - # problem. Only runs tests that are -short to limit the time we spend checking - # for these bugs. - go-test-32bit: - docker: - - image: *GOLANG_IMAGE - resource_class: large - environment: - <<: *ENVIRONMENT - GOTAGS: "" # No tags for OSS but there are for enterprise - steps: - - checkout - - run: go mod download - - run: - name: go test 32-bit - environment: - GOARCH: 386 - command: | - mkdir -p $TEST_RESULTS_DIR /tmp/jsonfile - go env - PACKAGE_NAMES=$(go list -tags "$GOTAGS" ./...) - gotestsum \ - --jsonfile /tmp/jsonfile/go-test-32bit.log \ - --rerun-fails=3 \ - --rerun-fails-max-failures=40 \ - --rerun-fails-report=/tmp/gotestsum-rerun-fails \ - --packages="$PACKAGE_NAMES" \ - --junitfile $TEST_RESULTS_DIR/gotestsum-report.xml -- \ - -tags="$GOTAGS" -p 2 \ - -short - - - store_test_results: - path: *TEST_RESULTS_DIR - - store_artifacts: - path: *TEST_RESULTS_DIR - - run: *notify-slack-failure - - go-test-lib: - description: "test a library against a specific Go version" - parameters: - go-version: - type: string - path: - type: string - docker: - - image: "docker.mirror.hashicorp.services/cimg/go:<>" - environment: - <<: *ENVIRONMENT - GOTAGS: "" # No tags for OSS but there are for enterprise - steps: - - checkout - - attach_workspace: - at: /home/circleci/go/bin - - run: - working_directory: <> - command: go mod download - - run: - working_directory: <> - name: go test - command: | - mkdir -p $TEST_RESULTS_DIR /tmp/jsonfile - gotestsum \ - --format=short-verbose \ - --jsonfile /tmp/jsonfile/go-test-<>.log \ - --junitfile $TEST_RESULTS_DIR/gotestsum-report.xml -- \ - -tags="$GOTAGS" -cover -coverprofile=coverage.txt \ - ./... - - - store_test_results: - path: *TEST_RESULTS_DIR - - store_artifacts: - path: *TEST_RESULTS_DIR - - store_artifacts: - path: /tmp/jsonfile - - run: *notify-slack-failure - - # build is a templated job for build-x - build-distros: &build-distros - docker: - - image: *GOLANG_IMAGE - resource_class: large - environment: &build-env - <<: *ENVIRONMENT - steps: - - checkout - - run: - name: Build - command: | - for os in $XC_OS; do - target="./pkg/bin/${GOOS}_${GOARCH}/" - GOOS="$os" CGO_ENABLED=0 go build -o "${target}" -ldflags "${GOLDFLAGS}" -tags "${GOTAGS}" - done - - # save dev build to CircleCI - - store_artifacts: - path: ./pkg/bin - - run: *notify-slack-failure - - # build all 386 architecture supported OS binaries - build-386: - <<: *build-distros - environment: - <<: *build-env - XC_OS: "freebsd linux windows" - GOARCH: "386" - - # build all amd64 architecture supported OS binaries - build-amd64: - <<: *build-distros - environment: - <<: *build-env - XC_OS: "darwin freebsd linux solaris windows" - GOARCH: "amd64" - - # build all arm/arm64 architecture supported OS binaries - build-arm: - docker: - - image: *GOLANG_IMAGE - resource_class: large - environment: - <<: *ENVIRONMENT - CGO_ENABLED: 1 - GOOS: linux - steps: - - checkout - - run: sudo apt-get update --allow-releaseinfo-change-suite --allow-releaseinfo-change-version && sudo apt-get install -y gcc-arm-linux-gnueabi gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu - - run: - environment: - GOARM: 5 - CC: arm-linux-gnueabi-gcc - GOARCH: arm - command: go build -o ./pkg/bin/linux_armel/consul -ldflags="-linkmode=external ${GOLDFLAGS}" - - run: - environment: - GOARM: 6 - CC: arm-linux-gnueabihf-gcc - GOARCH: arm - command: go build -o ./pkg/bin/linux_armhf/consul -ldflags="-linkmode=external ${GOLDFLAGS}" - - run: - environment: - CC: aarch64-linux-gnu-gcc - GOARCH: arm64 - command: go build -o ./pkg/bin/linux_aarch64/consul -ldflags="-linkmode=external ${GOLDFLAGS}" - - store_artifacts: - path: ./pkg/bin - - run: *notify-slack-failure - - # create a development build - dev-build: - docker: - - image: *GOLANG_IMAGE - resource_class: large - environment: - <<: *ENVIRONMENT - steps: - - checkout - - attach_workspace: # this normally runs as the first job and has nothing to attach; only used in main branch after rebuilding UI - at: . - - run: - name: Build - command: | - make dev - mkdir -p /home/circleci/go/bin - cp ./bin/consul /home/circleci/go/bin/consul - - # save dev build to pass to downstream jobs - - persist_to_workspace: - root: /home/circleci/go/bin - paths: - - consul - - run: *notify-slack-failure - - # upload development build to s3 - dev-upload-s3: - docker: - - image: *GOLANG_IMAGE - environment: - <<: *ENVIRONMENT - steps: - - checkout - - *get-aws-cli - - assume-role: - access-key: AWS_ACCESS_KEY_ID_S3_UPLOAD - secret-key: AWS_SECRET_ACCESS_KEY_S3_UPLOAD - role-arn: ROLE_ARN_S3_UPLOAD - # get consul binary - - attach_workspace: - at: bin/ - - run: - name: package binary - command: zip -j consul.zip bin/consul - - run: - name: Upload to s3 - command: | - if [ -n "${S3_ARTIFACT_PATH}" ]; then - aws s3 cp \ - --metadata "CIRCLECI=${CIRCLECI},CIRCLE_BUILD_URL=${CIRCLE_BUILD_URL},CIRCLE_BRANCH=${CIRCLE_BRANCH}" \ - "consul.zip" "s3://${S3_ARTIFACT_BUCKET}/${S3_ARTIFACT_PATH}/${CIRCLE_SHA1}.zip" --acl public-read - else - echo "CircleCI - S3_ARTIFACT_PATH was not set" - exit 1 - fi - - run: *notify-slack-failure - - # upload dev docker image - dev-upload-docker: - docker: - - image: *GOLANG_IMAGE # use a circleci image so the attach_workspace step works (has ca-certs installed) - environment: - <<: *ENVIRONMENT - steps: - - checkout - # get consul binary - - attach_workspace: - at: bin/ - - setup_remote_docker - - run: make ci.dev-docker - - run: *notify-slack-failure - - nomad-integration-test: &NOMAD_TESTS - docker: - - image: docker.mirror.hashicorp.services/cimg/go:1.19 - parameters: - nomad-version: - type: enum - enum: *supported_nomad_versions - default: *default_nomad_version - environment: - <<: *ENVIRONMENT - NOMAD_WORKING_DIR: &NOMAD_WORKING_DIR /home/circleci/go/src/github.com/hashicorp/nomad - NOMAD_VERSION: << parameters.nomad-version >> - steps: &NOMAD_INTEGRATION_TEST_STEPS - - run: git clone https://github.com/hashicorp/nomad.git --branch v${NOMAD_VERSION} ${NOMAD_WORKING_DIR} - - # get consul binary - - attach_workspace: - at: /home/circleci/go/bin - - # make dev build of nomad - - run: - command: make pkg/linux_amd64/nomad - working_directory: *NOMAD_WORKING_DIR - - - run: *install-gotestsum - - # run integration tests - - run: - name: go test - command: | - mkdir -p $TEST_RESULTS_DIR - gotestsum \ - --format=short-verbose \ - --junitfile $TEST_RESULTS_DIR/results.xml -- \ - ./command/agent/consul -run TestConsul - working_directory: *NOMAD_WORKING_DIR - - # store test results for CircleCI - - store_test_results: - path: *TEST_RESULTS_DIR - - store_artifacts: - path: *TEST_RESULTS_DIR - - run: *notify-slack-failure - - # build frontend yarn cache - frontend-cache: - docker: - - image: *EMBER_IMAGE - steps: - - checkout - - # cache yarn deps - - restore_cache: - key: *YARN_CACHE_KEY - - - run: - name: install yarn packages - command: cd ui && make deps - - - save_cache: - key: *YARN_CACHE_KEY - paths: - - ui/node_modules - - ui/packages/consul-ui/node_modules - - run: *notify-slack-failure - - # build ember so frontend tests run faster - ember-build-oss: &ember-build-oss - docker: - - image: *EMBER_IMAGE - environment: - JOBS: 2 # limit parallelism for broccoli-babel-transpiler - CONSUL_NSPACES_ENABLED: 0 - steps: - - checkout - - restore_cache: - key: *YARN_CACHE_KEY - - run: cd ui/packages/consul-ui && make build-ci - - # saves the build to a workspace to be passed to a downstream job - - persist_to_workspace: - root: ui - paths: - - packages/consul-ui/dist - - run: *notify-slack-failure - - # build ember so frontend tests run faster - ember-build-ent: - <<: *ember-build-oss - environment: - JOBS: 2 # limit parallelism for broccoli-babel-transpiler - CONSUL_NSPACES_ENABLED: 1 - - # rebuild UI for packaging - ember-build-prod: - docker: - - image: *EMBER_IMAGE - environment: - JOBS: 2 # limit parallelism for broccoli-babel-transpiler - steps: - - checkout - - restore_cache: - key: *YARN_CACHE_KEY - - run: cd ui && make - - # saves the build to a workspace to be passed to a downstream job - - persist_to_workspace: - root: ui - paths: - - packages/consul-ui/dist - - run: *notify-slack-failure - - # commits static assets to git - publish-static-assets: - docker: - - image: *GOLANG_IMAGE - steps: - - checkout - - add_ssh_keys: # needs a key to push updated static asset commit back to github - fingerprints: - - "fc:55:84:15:0a:1d:c8:e9:06:d0:e8:9c:7b:a9:b7:31" - - attach_workspace: - at: . - - run: - name: move compiled ui files to agent/uiserver - command: | - rm -rf agent/uiserver/dist - mv packages/consul-ui/dist agent/uiserver - - run: - name: commit agent/uiserver/dist/ if there are UI changes - command: | - # check if there are any changes in ui/ - # if there are, we commit the ui static asset file - # HEAD^! is shorthand for HEAD^..HEAD (parent of HEAD and HEAD) - if ! git diff --quiet --exit-code HEAD^! ui/; then - git config --local user.email "github-team-consul-core@hashicorp.com" - git config --local user.name "hc-github-team-consul-core" - - # -B resets the CI branch to main which may diverge history - # but we will force push anyways. - git checkout -B ci/main-assetfs-build main - - short_sha=$(git rev-parse --short HEAD) - git add agent/uiserver/dist/ - git commit -m "auto-updated agent/uiserver/dist/ from commit ${short_sha}" - git push --force origin ci/main-assetfs-build - else - echo "no UI changes so no static assets to publish" - fi - - run: *notify-slack-failure - - # run node tests - node-tests: - docker: - - image: *EMBER_IMAGE - steps: - - checkout - - restore_cache: - key: *YARN_CACHE_KEY - - attach_workspace: - at: ui - - run: - working_directory: ui/packages/consul-ui - command: make test-node - - run: *notify-slack-failure - # run yarn workspace wide checks/tests - workspace-tests: - docker: - - image: *EMBER_IMAGE - steps: - - checkout - - restore_cache: - key: *YARN_CACHE_KEY - - attach_workspace: - at: ui - - run: - working_directory: ui - command: make test-workspace - - run: *notify-slack-failure - - # run ember frontend tests - ember-test-oss: - docker: - - image: *EMBER_IMAGE - environment: - EMBER_TEST_REPORT: test-results/report-oss.xml #outputs test report for CircleCI test summary - EMBER_TEST_PARALLEL: true #enables test parallelization with ember-exam - CONSUL_NSPACES_ENABLED: 0 - parallelism: 4 - steps: - - checkout - - restore_cache: - key: *YARN_CACHE_KEY - - attach_workspace: - at: ui - - run: - working_directory: ui/packages/consul-ui - command: node_modules/.bin/ember exam --split=$CIRCLE_NODE_TOTAL --partition=`expr $CIRCLE_NODE_INDEX + 1` --path dist --silent -r xunit - - store_test_results: - path: ui/packages/consul-ui/test-results - - run: *notify-slack-failure - - # run ember frontend tests - ember-test-ent: - docker: - - image: *EMBER_IMAGE - environment: - EMBER_TEST_REPORT: test-results/report-ent.xml #outputs test report for CircleCI test summary - EMBER_TEST_PARALLEL: true #enables test parallelization with ember-exam - CONSUL_NSPACES_ENABLED: 1 - parallelism: 4 - steps: - - checkout - - restore_cache: - key: *YARN_CACHE_KEY - - attach_workspace: - at: ui - - run: - working_directory: ui/packages/consul-ui - command: node_modules/.bin/ember exam --split=$CIRCLE_NODE_TOTAL --partition=`expr $CIRCLE_NODE_INDEX + 1` --path dist --silent -r xunit - - store_test_results: - path: ui/packages/consul-ui/test-results - - run: *notify-slack-failure - - # run ember frontend unit tests to produce coverage report - ember-coverage: - docker: - - image: *EMBER_IMAGE - steps: - - checkout - - restore_cache: - key: *YARN_CACHE_KEY - - attach_workspace: - at: ui - - run: - working_directory: ui/packages/consul-ui - command: make test-coverage-ci - - run: *notify-slack-failure - - compatibility-integration-test: - machine: - image: *UBUNTU_CI_IMAGE - docker_layer_caching: true - parallelism: 1 - steps: - - checkout - # Get go binary from workspace - - attach_workspace: - at: . - # Build the consul:local image from the already built binary - - run: - command: | - sudo rm -rf /usr/local/go - wget https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz - sudo tar -C /usr/local -xzvf go${GO_VERSION}.linux-amd64.tar.gz - environment: - <<: *ENVIRONMENT - - run: *install-gotestsum - - run: docker build -t consul:local -f ./build-support/docker/Consul-Dev.dockerfile . - - run: - name: Compatibility Integration Tests - command: | - mkdir -p /tmp/test-results/ - cd ./test/integration/consul-container - docker run --rm consul:local consul version - gotestsum \ - --format=short-verbose \ - --debug \ - --rerun-fails=3 \ - --packages="./..." \ - -- \ - -timeout=30m \ - ./... \ - --target-version local \ - --latest-version latest - ls -lrt - environment: - # this is needed because of incompatibility between RYUK container and circleci - GOTESTSUM_JUNITFILE: /tmp/test-results/results.xml - GOTESTSUM_FORMAT: standard-verbose - COMPOSE_INTERACTIVE_NO_CLI: 1 - # tput complains if this isn't set to something. - TERM: ansi - - store_artifacts: - path: ./test/integration/consul-container/upgrade/workdir/logs - destination: container-logs - - store_test_results: - path: *TEST_RESULTS_DIR - - store_artifacts: - path: *TEST_RESULTS_DIR - - run: *notify-slack-failure - - envoy-integration-test: &ENVOY_TESTS - machine: - image: *UBUNTU_CI_IMAGE - parallelism: 4 - resource_class: medium - parameters: - envoy-version: - type: enum - enum: *supported_envoy_versions - default: *default_envoy_version - xds-target: - type: enum - enum: ["server", "client"] - default: "server" - environment: - ENVOY_VERSION: << parameters.envoy-version >> - XDS_TARGET: << parameters.xds-target >> - AWS_LAMBDA_REGION: us-west-2 - steps: &ENVOY_INTEGRATION_TEST_STEPS - - checkout - - assume-role: - access-key: AWS_ACCESS_KEY_ID_LAMBDA - secret-key: AWS_SECRET_ACCESS_KEY_LAMBDA - role-arn: ROLE_ARN_LAMBDA - # Get go binary from workspace - - attach_workspace: - at: . - - run: *install-gotestsum - # Build the consul:local image from the already built binary - - run: docker build -t consul:local -f ./build-support/docker/Consul-Dev.dockerfile . - - run: - name: Envoy Integration Tests - command: | - subtests=$(ls -d test/integration/connect/envoy/*/ | xargs -n 1 basename | circleci tests split) - echo "Running $(echo $subtests | wc -w) subtests" - echo "$subtests" - subtests_pipe_sepr=$(echo "$subtests" | xargs | sed 's/ /|/g') - mkdir -p /tmp/test-results/ - gotestsum -- -timeout=30m -tags integration ./test/integration/connect/envoy -run="TestEnvoy/($subtests_pipe_sepr)" - environment: - GOTESTSUM_JUNITFILE: /tmp/test-results/results.xml - GOTESTSUM_FORMAT: standard-verbose - COMPOSE_INTERACTIVE_NO_CLI: 1 - LAMBDA_TESTS_ENABLED: "true" - # tput complains if this isn't set to something. - TERM: ansi - - store_artifacts: - path: ./test/integration/connect/envoy/workdir/logs - destination: container-logs - - store_test_results: - path: *TEST_RESULTS_DIR - - store_artifacts: - path: *TEST_RESULTS_DIR - - run: *notify-slack-failure - - # run integration tests for the connect ca providers - test-connect-ca-providers: - docker: - - image: *GOLANG_IMAGE - environment: - <<: *ENVIRONMENT - steps: - - run: - name: Install vault - command: | - wget -q -O /tmp/vault.zip https://releases.hashicorp.com/vault/${VAULT_BINARY_VERSION}/vault_${VAULT_BINARY_VERSION}_linux_amd64.zip - sudo unzip -d /usr/local/bin /tmp/vault.zip - rm -rf /tmp/vault* - - checkout - - run: go mod download - - run: - name: go test - command: | - mkdir -p $TEST_RESULTS_DIR - make test-connect-ca-providers - - store_test_results: - path: *TEST_RESULTS_DIR - - run: *notify-slack-failure - - # Run load tests against a commit - load-test: - docker: - - image: hashicorp/terraform:latest - environment: - AWS_DEFAULT_REGION: us-east-2 - BUCKET: consul-ci-load-tests - BASH_ENV: /etc/profile - shell: /bin/sh -leo pipefail - steps: - - checkout - - run: apk add jq curl bash - - run: - name: export load-test credentials - command: | - echo "export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID_LOAD_TEST" >> $BASH_ENV - echo "export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY_LOAD_TEST" >> $BASH_ENV - - run: - name: export role arn - command: | - echo "export TF_VAR_role_arn=$ROLE_ARN_LOAD_TEST" >> $BASH_ENV - - run: - name: setup TF_VARs - command: | - # if pipeline.parameters.commit="" it was not triggered/set through the API - # so we use the latest commit from _this_ branch. This is the case for nightly tests. - if [ "<< pipeline.parameters.commit >>" = "" ]; then - LOCAL_COMMIT_SHA=$(git rev-parse HEAD) - else - LOCAL_COMMIT_SHA="<< pipeline.parameters.commit >>" - fi - echo "export LOCAL_COMMIT_SHA=${LOCAL_COMMIT_SHA}" >> $BASH_ENV - git checkout ${LOCAL_COMMIT_SHA} - - short_ref=$(git rev-parse --short ${LOCAL_COMMIT_SHA}) - echo "export TF_VAR_ami_owners=$LOAD_TEST_AMI_OWNERS" >> $BASH_ENV - echo "export TF_VAR_vpc_name=$short_ref" >> $BASH_ENV - echo "export TF_VAR_cluster_name=$short_ref" >> $BASH_ENV - echo "export TF_VAR_consul_download_url=https://${S3_ARTIFACT_BUCKET}.s3.${AWS_DEFAULT_REGION}.amazonaws.com/${S3_ARTIFACT_PATH}/${LOCAL_COMMIT_SHA}.zip" >> $BASH_ENV - - run: - name: wait for dev build from test-integrations workflow - command: | - echo "curl-ing https://${S3_ARTIFACT_BUCKET}.s3.${AWS_DEFAULT_REGION}.amazonaws.com/${S3_ARTIFACT_PATH}/${LOCAL_COMMIT_SHA}.zip" - until [ $SECONDS -ge 300 ] && exit 1; do - curl -o /dev/null --fail --silent "https://${S3_ARTIFACT_BUCKET}.s3.${AWS_DEFAULT_REGION}.amazonaws.com/${S3_ARTIFACT_PATH}/${LOCAL_COMMIT_SHA}.zip" && exit - echo -n "." - sleep 2 - done - - run: - working_directory: .circleci/terraform/load-test - name: terraform init - command: | - short_ref=$(git rev-parse --short HEAD) - echo "Testing commit id: $short_ref" - terraform init \ - -backend-config="bucket=${BUCKET}" \ - -backend-config="key=${LOCAL_COMMIT_SHA}" \ - -backend-config="region=${AWS_DEFAULT_REGION}" \ - -backend-config="role_arn=${ROLE_ARN_LOAD_TEST}" - - run: - working_directory: .circleci/terraform/load-test - name: run terraform apply - command: | - terraform apply -auto-approve - - run: - working_directory: .circleci/terraform/load-test - when: always - name: terraform destroy - command: | - for i in $(seq 1 5); do terraform destroy -auto-approve && s=0 && break || s=$? && sleep 20; done; (exit $s) - - run: *notify-slack-failure - - # The noop job is a used as a very fast job in the verify-ci workflow because every workflow - # requires at least one job. It does nothing. - noop: - docker: - - image: docker.mirror.hashicorp.services/alpine:latest - steps: - - run: "echo ok" - -workflows: - version: 2 - # verify-ci is a no-op workflow that must run on every PR. It is used in a - # branch protection rule to detect when CI workflows are not running. - verify-ci: - jobs: [noop] - - go-tests: - unless: << pipeline.parameters.trigger-load-test >> - jobs: - - check-go-mod: &filter-ignore-non-go-branches - filters: - branches: - ignore: - - stable-website - - /^docs\/.*/ - - /^ui\/.*/ - - check-generated-protobuf: *filter-ignore-non-go-branches - - check-generated-deep-copy: *filter-ignore-non-go-branches - - lint-enums: *filter-ignore-non-go-branches - - lint-consul-retry: *filter-ignore-non-go-branches - - lint: *filter-ignore-non-go-branches - - lint: - name: "lint-32bit" - go-arch: "386" - <<: *filter-ignore-non-go-branches - - test-connect-ca-providers: *filter-ignore-non-go-branches - - go-test-arm64: *filter-ignore-non-go-branches - - dev-build: *filter-ignore-non-go-branches - - go-test: - requires: [dev-build] - - go-test-lib: - name: "go-test-api go1.17" - path: api - go-version: "1.17" - requires: [dev-build] - - go-test-lib: - name: "go-test-api go1.18" - path: api - go-version: "1.18" - requires: [dev-build] - - go-test-lib: - name: "go-test-sdk go1.17" - path: sdk - go-version: "1.17" - <<: *filter-ignore-non-go-branches - - go-test-lib: - name: "go-test-sdk go1.18" - path: sdk - go-version: "1.18" - <<: *filter-ignore-non-go-branches - - go-test-race: *filter-ignore-non-go-branches - - go-test-32bit: *filter-ignore-non-go-branches - - noop - build-distros: - unless: << pipeline.parameters.trigger-load-test >> - jobs: - - check-go-mod: *filter-ignore-non-go-branches - - build-386: &require-check-go-mod - requires: - - check-go-mod - - build-amd64: *require-check-go-mod - - build-arm: *require-check-go-mod - # every commit on main will have a rebuilt UI - - frontend-cache: - filters: - branches: - only: - - main - - ember-build-prod: - requires: - - frontend-cache - - publish-static-assets: - requires: - - ember-build-prod - - dev-build: - requires: - - ember-build-prod - - dev-upload-s3: - requires: - - dev-build - - dev-upload-docker: - requires: - - dev-build - context: consul-ci - - noop - test-integrations: - unless: << pipeline.parameters.trigger-load-test >> - jobs: - - dev-build: *filter-ignore-non-go-branches - - dev-upload-s3: &dev-upload - requires: - - dev-build - filters: - branches: - ignore: - - /^pull\/.*$/ # only push dev builds from non forks - - main # all main dev uploads will include a UI rebuild in build-distros - - dev-upload-docker: - <<: *dev-upload - context: consul-ci - - nomad-integration-test: - requires: - - dev-build - matrix: - parameters: - nomad-version: *supported_nomad_versions - - envoy-integration-test: - requires: - - dev-build - matrix: - parameters: - envoy-version: *supported_envoy_versions - xds-target: ["server", "client"] - - compatibility-integration-test: - requires: - - dev-build - - noop - frontend: - unless: << pipeline.parameters.trigger-load-test >> - jobs: - - frontend-cache: - filters: - branches: - only: - - main - - /^ui\/.*/ - - workspace-tests: - requires: - - frontend-cache - - node-tests: - requires: - - frontend-cache - - ember-build-oss: - requires: - - frontend-cache - - ember-build-ent: - requires: - - frontend-cache - - ember-test-oss: - requires: - - ember-build-oss - - ember-test-ent: - requires: - - ember-build-ent - # ember-coverage in CI uses the dist/ folder to run tests so it requires - # either/or ent/oss to be built first - - ember-coverage: - requires: - - ember-build-ent - - noop - - load-test: - when: << pipeline.parameters.trigger-load-test >> - jobs: - - load-test - - nightly-jobs: - triggers: - - schedule: - cron: "0 4 * * *" # 4AM UTC <> 12AM EST <> 9PM PST should have no impact - filters: - branches: - only: - - main - jobs: - - load-test diff --git a/.circleci/terraform/load-test/.terraform.lock.hcl b/.circleci/terraform/load-test/.terraform.lock.hcl deleted file mode 100755 index 9f4d960dcd42..000000000000 --- a/.circleci/terraform/load-test/.terraform.lock.hcl +++ /dev/null @@ -1,110 +0,0 @@ -# This file is maintained automatically by "terraform init". -# Manual edits may be lost in future updates. - -provider "registry.terraform.io/hashicorp/aws" { - version = "3.41.0" - constraints = "~> 3.0, >= 3.27.0" - hashes = [ - "h1:YLbsjPt/oZdEhV+KJzMVBwGDViw14Ih5bYr+EOudIVw=", - "zh:01449ed390710428c92dcd3c6b8ba7e06cc1581b927e96eabe9ebc2653d1e3e0", - "zh:259c1267ab5798e90c8edb4b9c3b17c1dd98e5265c121eaf025a5836e88f4d1d", - "zh:2671ec766eb63d642b8b3d847d67db83d578a44d4945bc45ddd7fbb6d09298ca", - "zh:36082943070c8f4f9a1e557a6b18d279db079b19210cd5249ba03c87de44e5d4", - "zh:49a52c679a14c7755db34e0b98ef062f5e42b7beec1decec2511ecef16690b3f", - "zh:82cf0db34865d8844139a6db35436a6b4664995972dc53e298c93a7133101b0f", - "zh:9082239ae74e4f8b9763087bf454dcfb1019e1a65c4d9ab8057f8425b9da550b", - "zh:a9b51d299b3ffe07684e86d8ea11513411f53375439be5aa87fdfef59cbe5dfa", - "zh:b33fb3990c9bb2a1337725651a98d9563a3b91b50ddeb7c7b655c463faa81dda", - "zh:bd759da1e0c18a2c17bfe607660d52d8981aa51460d70d2e338ddbcef1b50183", - "zh:eebb98f9ba764dd09b059c5865ce7e8bace49fe470980f813a767cbe833a933e", - ] -} - -provider "registry.terraform.io/hashicorp/local" { - version = "2.1.0" - hashes = [ - "h1:KfieWtVyGWwplSoLIB5usKAUnrIkDQBkWaR5TI+4WYg=", - "zh:0f1ec65101fa35050978d483d6e8916664b7556800348456ff3d09454ac1eae2", - "zh:36e42ac19f5d68467aacf07e6adcf83c7486f2e5b5f4339e9671f68525fc87ab", - "zh:6db9db2a1819e77b1642ec3b5e95042b202aee8151a0256d289f2e141bf3ceb3", - "zh:719dfd97bb9ddce99f7d741260b8ece2682b363735c764cac83303f02386075a", - "zh:7598bb86e0378fd97eaa04638c1a4c75f960f62f69d3662e6d80ffa5a89847fe", - "zh:ad0a188b52517fec9eca393f1e2c9daea362b33ae2eb38a857b6b09949a727c1", - "zh:c46846c8df66a13fee6eff7dc5d528a7f868ae0dcf92d79deaac73cc297ed20c", - "zh:dc1a20a2eec12095d04bf6da5321f535351a594a636912361db20eb2a707ccc4", - "zh:e57ab4771a9d999401f6badd8b018558357d3cbdf3d33cc0c4f83e818ca8e94b", - "zh:ebdcde208072b4b0f8d305ebf2bfdc62c926e0717599dcf8ec2fd8c5845031c3", - "zh:ef34c52b68933bedd0868a13ccfd59ff1c820f299760b3c02e008dc95e2ece91", - ] -} - -provider "registry.terraform.io/hashicorp/null" { - version = "3.1.0" - hashes = [ - "h1:xhbHC6in3nQryvTQBWKxebi3inG5OCgHgc4fRxL0ymc=", - "zh:02a1675fd8de126a00460942aaae242e65ca3380b5bb192e8773ef3da9073fd2", - "zh:53e30545ff8926a8e30ad30648991ca8b93b6fa496272cd23b26763c8ee84515", - "zh:5f9200bf708913621d0f6514179d89700e9aa3097c77dac730e8ba6e5901d521", - "zh:9ebf4d9704faba06b3ec7242c773c0fbfe12d62db7d00356d4f55385fc69bfb2", - "zh:a6576c81adc70326e4e1c999c04ad9ca37113a6e925aefab4765e5a5198efa7e", - "zh:a8a42d13346347aff6c63a37cda9b2c6aa5cc384a55b2fe6d6adfa390e609c53", - "zh:c797744d08a5307d50210e0454f91ca4d1c7621c68740441cf4579390452321d", - "zh:cecb6a304046df34c11229f20a80b24b1603960b794d68361a67c5efe58e62b8", - "zh:e1371aa1e502000d9974cfaff5be4cfa02f47b17400005a16f14d2ef30dc2a70", - "zh:fc39cc1fe71234a0b0369d5c5c7f876c71b956d23d7d6f518289737a001ba69b", - "zh:fea4227271ebf7d9e2b61b89ce2328c7262acd9fd190e1fd6d15a591abfa848e", - ] -} - -provider "registry.terraform.io/hashicorp/random" { - version = "3.1.0" - hashes = [ - "h1:rKYu5ZUbXwrLG1w81k7H3nce/Ys6yAxXhWcbtk36HjY=", - "zh:2bbb3339f0643b5daa07480ef4397bd23a79963cc364cdfbb4e86354cb7725bc", - "zh:3cd456047805bf639fbf2c761b1848880ea703a054f76db51852008b11008626", - "zh:4f251b0eda5bb5e3dc26ea4400dba200018213654b69b4a5f96abee815b4f5ff", - "zh:7011332745ea061e517fe1319bd6c75054a314155cb2c1199a5b01fe1889a7e2", - "zh:738ed82858317ccc246691c8b85995bc125ac3b4143043219bd0437adc56c992", - "zh:7dbe52fac7bb21227acd7529b487511c91f4107db9cc4414f50d04ffc3cab427", - "zh:a3a9251fb15f93e4cfc1789800fc2d7414bbc18944ad4c5c98f466e6477c42bc", - "zh:a543ec1a3a8c20635cf374110bd2f87c07374cf2c50617eee2c669b3ceeeaa9f", - "zh:d9ab41d556a48bd7059f0810cf020500635bfc696c9fc3adab5ea8915c1d886b", - "zh:d9e13427a7d011dbd654e591b0337e6074eef8c3b9bb11b2e39eaaf257044fd7", - "zh:f7605bd1437752114baf601bdf6931debe6dc6bfe3006eb7e9bb9080931dca8a", - ] -} - -provider "registry.terraform.io/hashicorp/template" { - version = "2.2.0" - hashes = [ - "h1:0wlehNaxBX7GJQnPfQwTNvvAf38Jm0Nv7ssKGMaG6Og=", - "zh:01702196f0a0492ec07917db7aaa595843d8f171dc195f4c988d2ffca2a06386", - "zh:09aae3da826ba3d7df69efeb25d146a1de0d03e951d35019a0f80e4f58c89b53", - "zh:09ba83c0625b6fe0a954da6fbd0c355ac0b7f07f86c91a2a97849140fea49603", - "zh:0e3a6c8e16f17f19010accd0844187d524580d9fdb0731f675ffcf4afba03d16", - "zh:45f2c594b6f2f34ea663704cc72048b212fe7d16fb4cfd959365fa997228a776", - "zh:77ea3e5a0446784d77114b5e851c970a3dde1e08fa6de38210b8385d7605d451", - "zh:8a154388f3708e3df5a69122a23bdfaf760a523788a5081976b3d5616f7d30ae", - "zh:992843002f2db5a11e626b3fc23dc0c87ad3729b3b3cff08e32ffb3df97edbde", - "zh:ad906f4cebd3ec5e43d5cd6dc8f4c5c9cc3b33d2243c89c5fc18f97f7277b51d", - "zh:c979425ddb256511137ecd093e23283234da0154b7fa8b21c2687182d9aea8b2", - ] -} - -provider "registry.terraform.io/hashicorp/tls" { - version = "3.1.0" - hashes = [ - "h1:XTU9f6sGMZHOT8r/+LWCz2BZOPH127FBTPjMMEAAu1U=", - "zh:3d46616b41fea215566f4a957b6d3a1aa43f1f75c26776d72a98bdba79439db6", - "zh:623a203817a6dafa86f1b4141b645159e07ec418c82fe40acd4d2a27543cbaa2", - "zh:668217e78b210a6572e7b0ecb4134a6781cc4d738f4f5d09eb756085b082592e", - "zh:95354df03710691773c8f50a32e31fca25f124b7f3d6078265fdf3c4e1384dca", - "zh:9f97ab190380430d57392303e3f36f4f7835c74ea83276baa98d6b9a997c3698", - "zh:a16f0bab665f8d933e95ca055b9c8d5707f1a0dd8c8ecca6c13091f40dc1e99d", - "zh:be274d5008c24dc0d6540c19e22dbb31ee6bfdd0b2cddd4d97f3cd8a8d657841", - "zh:d5faa9dce0a5fc9d26b2463cea5be35f8586ab75030e7fa4d4920cd73ee26989", - "zh:e9b672210b7fb410780e7b429975adcc76dd557738ecc7c890ea18942eb321a5", - "zh:eb1f8368573d2370605d6dbf60f9aaa5b64e55741d96b5fb026dbfe91de67c0d", - "zh:fc1e12b713837b85daf6c3bb703d7795eaf1c5177aebae1afcf811dd7009f4b0", - ] -} diff --git a/.circleci/terraform/load-test/main.tf b/.circleci/terraform/load-test/main.tf deleted file mode 100644 index 1a8865c065d9..000000000000 --- a/.circleci/terraform/load-test/main.tf +++ /dev/null @@ -1,26 +0,0 @@ -terraform { - backend "s3" { - } -} - -provider "aws" { - assume_role { - role_arn = var.role_arn - } -} - -module "load-test" { - source = "../../../test/load/terraform" - - vpc_az = ["us-east-2a", "us-east-2b"] - vpc_name = var.vpc_name - vpc_cidr = "10.0.0.0/16" - vpc_allwed_ssh_cidr = "0.0.0.0/0" - public_subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24"] - private_subnet_cidrs = ["10.0.3.0/24"] - test_public_ip = true - ami_owners = var.ami_owners - consul_download_url = var.consul_download_url - cluster_name = var.cluster_name - cluster_tag_key = var.cluster_tag_key -} diff --git a/.circleci/terraform/load-test/variables.tf b/.circleci/terraform/load-test/variables.tf deleted file mode 100644 index 414cfa84e7fe..000000000000 --- a/.circleci/terraform/load-test/variables.tf +++ /dev/null @@ -1,30 +0,0 @@ -variable "vpc_name" { - description = "Name of the VPC" -} - -variable "ami_owners" { - type = list(string) - description = "The account owner number which the desired AMI is in" -} - -variable "role_arn" { - type = string - description = "Role ARN for assume role" -} - -variable "consul_download_url" { - type = string - description = "URL to download the Consul binary from" - default = "" -} -variable "cluster_name" { - description = "What to name the Consul cluster and all of its associated resources" - type = string - default = "consul-example" -} - -variable "cluster_tag_key" { - description = "The tag the EC2 Instances will look for to automatically discover each other and form a cluster." - type = string - default = "consul-ci-load-test" -} diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 31495d06491b..d9af3f042a7e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,3 +8,34 @@ # release configuration /.release/ @hashicorp/release-engineering @hashicorp/github-consul-core /.github/workflows/build.yml @hashicorp/release-engineering @hashicorp/github-consul-core + + +# Staff Engineer Review (protocol buffer definitions) +/proto-public/ @hashicorp/consul-core-staff +/proto/ @hashicorp/consul-core-staff + +# Staff Engineer Review (v1 architecture shared components) +/agent/cache/ @hashicorp/consul-core-staff +/agent/consul/fsm/ @hashicorp/consul-core-staff +/agent/consul/leader*.go @hashicorp/consul-core-staff +/agent/consul/server*.go @hashicorp/consul-core-staff +/agent/consul/state/ @hashicorp/consul-core-staff +/agent/consul/stream/ @hashicorp/consul-core-staff +/agent/submatview/ @hashicorp/consul-core-staff +/agent/blockingquery/ @hashicorp/consul-core-staff + +# Staff Engineer Review (raft/autopilot) +/agent/consul/autopilotevents/ @hashicorp/consul-core-staff +/agent/consul/autopilot*.go @hashicorp/consul-core-staff + +# Staff Engineer Review (v2 architecture shared components) +/internal/controller/ @hashicorp/consul-core-staff +/internal/resource/ @hashicorp/consul-core-staff +/internal/storage/ @hashicorp/consul-core-staff +/agent/consul/controller/ @hashicorp/consul-core-staff +/agent/grpc-external/services/resource/ @hashicorp/consul-core-staff + +# Staff Engineer Review (v1 security) +/acl/ @hashicorp/consul-core-staff +/agent/xds/rbac*.go @hashicorp/consul-core-staff +/agent/xds/jwt*.go @hashicorp/consul-core-staff diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 131d9057d2cc..c1b965235c9f 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -67,8 +67,7 @@ issue. Stale issues will be closed. ### Prerequisites If you wish to work on Consul itself, you'll first need to: -- install [Go](https://golang.org) (the version should match that of our - [CI config's](https://github.com/hashicorp/consul/blob/main/.circleci/config.yml) Go image). +- install [Go](https://golang.org) - [fork the Consul repo](../docs/contributing/fork-the-project.md) ### Building Consul diff --git a/.github/go_test_coverage.txt b/.github/go_test_coverage.txt new file mode 100644 index 000000000000..20e8b9e572cd --- /dev/null +++ b/.github/go_test_coverage.txt @@ -0,0 +1,12474 @@ +mode: set +github.com/hashicorp/consul/agent/intentions_endpoint.go:15.108,16.20 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:17.13,18.36 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:20.14,21.38 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:23.10,24.73 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:29.104,33.76 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:37.2,37.66 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:41.2,43.69 3 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:47.2,47.30 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:33.76,35.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:37.66,39.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:43.69,45.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:52.106,56.64 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:60.2,60.64 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:64.2,69.62 4 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:73.2,73.99 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:76.2,76.89 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:80.2,82.70 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:86.2,87.70 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:91.2,91.44 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:56.64,58.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:60.64,62.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:69.62,71.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:73.99,75.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:76.89,78.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:82.70,84.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:87.70,89.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:94.82,95.103 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:98.2,98.113 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:101.2,101.95 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:104.2,104.105 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:108.2,108.12 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:95.103,97.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:98.113,100.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:101.95,103.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:104.105,106.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:112.105,115.76 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:119.2,120.64 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:124.2,127.44 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:139.2,140.28 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:146.2,147.26 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:161.2,164.63 3 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:188.2,191.36 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:196.2,197.35 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:201.2,201.22 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:115.76,117.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:120.64,122.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:127.44,129.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:129.8,130.52 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:131.72,132.23 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:133.11,134.85 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:140.28,142.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:147.26,149.17 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:153.3,157.4 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:149.17,151.4 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:164.63,166.17 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:169.3,172.10 3 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:176.3,176.15 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:166.17,168.4 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:172.10,175.4 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:177.8,178.2 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:179.3,179.68 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:182.3,182.107 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:179.68,181.4 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:182.107,185.19 3 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:191.36,193.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:197.35,199.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:205.105,208.76 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:212.2,213.64 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:217.2,221.67 3 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:226.2,227.29 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:230.2,231.34 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:236.2,237.60 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:248.2,249.16 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:252.2,257.69 5 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:261.2,261.20 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:208.76,210.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:213.64,215.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:221.67,223.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:227.29,229.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:231.34,233.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:237.60,239.17 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:242.3,244.38 3 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:239.17,241.4 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:249.16,251.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:257.69,259.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:265.105,266.20 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:267.13,268.40 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:269.13,270.40 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:271.16,272.43 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:273.10,274.82 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:279.108,281.64 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:285.2,288.76 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:292.2,296.29 3 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:299.2,300.34 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:326.2,327.68 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:346.2,346.32 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:351.2,351.33 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:281.64,283.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:288.76,290.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:296.29,298.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:300.34,302.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:304.2,306.17 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:310.3,313.38 4 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:306.17,308.4 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:316.2,318.17 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:321.3,323.43 3 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:318.17,320.4 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:327.68,329.73 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:337.3,337.44 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:341.3,341.18 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:329.73,331.4 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:337.44,339.4 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:346.32,349.3 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:355.108,357.64 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:361.2,362.16 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:366.2,371.62 4 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:376.2,389.72 10 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:393.2,393.18 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:357.64,359.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:362.16,364.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:371.62,373.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:389.72,391.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:397.111,399.64 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:403.2,404.16 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:408.2,424.72 5 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:428.2,428.18 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:399.64,401.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:404.16,406.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:424.72,426.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:434.117,439.48 3 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:442.2,443.58 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:447.2,448.2 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:468.2,468.20 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:439.48,441.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:443.58,445.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:448.2,450.17 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:453.3,455.33 3 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:450.17,452.4 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:458.2,460.17 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:463.3,465.38 3 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:460.17,462.4 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:475.133,476.60 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:480.2,481.17 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:476.60,478.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:482.9,484.40 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:488.3,490.65 3 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:491.9,492.40 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:499.3,500.68 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:501.9,502.40 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:508.10,509.62 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:484.40,486.4 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:492.40,497.4 3 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:502.40,505.4 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:505.9,507.4 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:515.108,518.20 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:519.13,520.47 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:522.13,523.50 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:525.16,526.50 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:528.10,529.82 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:534.122,540.76 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:544.2,545.68 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:564.2,564.32 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:569.2,569.33 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:540.76,542.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:545.68,547.57 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:555.3,555.44 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:559.3,559.18 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:547.57,549.4 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:555.44,557.4 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:564.32,567.3 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:573.125,577.64 2 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:581.2,581.64 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:585.2,590.62 4 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:594.2,594.99 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:597.2,597.89 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:601.2,607.70 4 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:612.2,612.44 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:577.64,579.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:581.64,583.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:590.62,592.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:594.99,596.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:597.89,599.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:607.70,609.3 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:616.125,627.70 5 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:631.2,631.18 1 0 +github.com/hashicorp/consul/agent/intentions_endpoint.go:627.70,629.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:15.102,18.76 2 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:23.2,28.33 4 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:33.2,33.20 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:18.76,20.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:28.33,30.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:34.13,35.14 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:38.3,38.36 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:39.13,40.36 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:41.16,42.39 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:43.10,44.82 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:35.14,37.4 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:49.123,53.36 3 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:60.2,60.25 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:71.2,72.56 2 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:75.2,78.27 2 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:91.2,91.55 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:101.2,101.25 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:53.36,55.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:55.8,55.27 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:55.27,57.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:60.25,61.77 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:61.77,63.4 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:64.8,65.67 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:65.67,67.4 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:72.56,74.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:78.27,81.3 2 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:91.55,99.3 7 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:105.127,106.66 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:112.2,114.38 3 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:117.2,117.38 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:122.2,132.69 3 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:135.2,139.49 2 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:145.2,145.21 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:148.2,148.22 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:106.66,108.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:114.38,116.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:117.38,119.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:132.69,134.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:139.49,142.3 2 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:145.21,147.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:152.123,153.76 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:156.2,156.20 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:159.2,159.62 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:162.2,176.34 4 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:185.2,185.32 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:195.2,195.36 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:201.2,201.36 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:207.2,207.62 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:216.2,217.50 2 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:220.2,224.66 3 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:229.2,229.30 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:232.2,232.17 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:153.76,155.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:156.20,158.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:159.62,161.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:176.34,178.17 2 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:181.3,181.34 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:178.17,180.4 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:185.32,187.17 2 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:190.3,191.26 2 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:187.17,189.4 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:195.36,198.3 2 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:201.36,204.3 2 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:207.62,213.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:217.50,219.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:224.66,226.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:229.30,231.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:236.126,237.76 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:240.2,240.51 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:243.2,255.36 4 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:262.2,262.32 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:272.2,273.66 2 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:278.2,278.36 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:281.2,281.18 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:237.76,239.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:240.51,242.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:255.36,257.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:257.8,257.27 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:257.27,259.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:262.32,264.17 2 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:267.3,268.32 2 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:264.17,266.4 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:273.66,275.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:278.36,280.3 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:285.90,289.33 3 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:300.2,300.14 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:289.33,290.36 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:290.36,291.13 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:296.4,296.16 1 0 +github.com/hashicorp/consul/agent/kvs_endpoint.go:291.13,295.5 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:23.48,24.32 1 1 +github.com/hashicorp/consul/agent/acl_endpoint.go:27.2,27.13 1 1 +github.com/hashicorp/consul/agent/acl_endpoint.go:24.32,26.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:32.103,33.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:37.2,42.16 4 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:49.2,49.68 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:33.26,35.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:42.16,43.79 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:43.79,45.4 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:45.9,47.4 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:52.111,53.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:59.2,61.76 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:66.2,67.74 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:70.2,70.17 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:53.26,55.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:61.76,63.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:67.74,69.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:73.104,74.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:78.2,79.76 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:82.2,82.66 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:86.2,86.27 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:90.2,92.67 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:97.2,97.25 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:101.2,101.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:74.26,76.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:79.76,81.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:82.66,84.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:86.27,88.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:92.67,94.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:97.25,99.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:104.104,105.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:109.2,111.20 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:125.2,126.43 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:130.2,130.32 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:105.26,107.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:112.13,113.27 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:115.13,116.24 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:118.16,119.25 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:121.10,122.82 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:126.43,128.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:133.133,139.76 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:143.2,143.66 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:147.2,147.27 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:151.2,153.67 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:157.2,157.23 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:162.2,162.24 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:139.76,141.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:143.66,145.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:147.27,149.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:153.67,155.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:157.23,160.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:165.110,166.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:170.2,171.22 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:175.2,175.51 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:166.26,168.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:171.22,173.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:178.125,180.2 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:182.106,183.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:187.2,187.54 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:183.26,185.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:190.122,192.2 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:194.144,199.73 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:203.2,203.100 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:207.2,209.12 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:221.2,222.65 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:226.2,226.18 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:199.73,201.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:203.100,205.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:209.12,210.27 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:210.27,212.4 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:213.8,214.57 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:214.57,216.4 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:216.9,216.34 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:216.34,218.4 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:222.65,224.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:229.123,235.66 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:239.2,240.72 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:244.2,244.18 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:235.66,237.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:240.72,242.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:247.103,248.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:252.2,256.76 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:260.2,260.66 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:264.2,264.27 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:268.2,271.97 4 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:275.2,277.66 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:281.2,281.24 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:248.26,250.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:256.76,258.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:260.66,262.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:264.27,266.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:271.97,273.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:277.66,279.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:284.103,285.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:289.2,291.20 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:305.2,306.65 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:310.2,310.42 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:314.2,314.31 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:285.26,287.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:292.13,293.21 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:295.13,296.21 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:298.16,299.24 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:301.10,302.82 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:306.65,309.3 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:310.42,312.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:317.103,318.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:322.2,326.76 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:331.2,333.27 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:337.2,339.66 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:343.2,343.22 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:347.2,347.23 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:318.26,320.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:326.76,328.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:333.27,335.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:339.66,341.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:343.22,345.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:350.105,351.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:355.2,355.45 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:351.26,353.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:358.118,365.76 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:369.2,369.66 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:372.2,372.46 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:376.2,376.27 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:380.2,382.66 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:386.2,386.22 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:390.2,390.19 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:398.2,398.23 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:365.76,367.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:369.66,371.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:372.46,374.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:376.27,378.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:382.66,384.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:386.22,388.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:390.19,396.3 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:401.115,403.2 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:405.113,411.75 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:415.2,415.102 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:419.2,419.13 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:427.2,428.64 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:432.2,432.18 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:411.75,413.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:415.102,417.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:419.13,420.76 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:420.76,422.4 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:422.9,422.44 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:422.44,424.4 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:428.64,430.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:435.121,441.66 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:445.2,446.71 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:449.2,449.18 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:441.66,443.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:446.71,448.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:452.120,453.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:457.2,462.75 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:465.2,465.102 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:468.2,474.66 4 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:478.2,478.18 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:453.26,455.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:462.75,464.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:465.102,467.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:474.66,476.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:481.102,482.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:486.2,487.76 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:490.2,490.66 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:494.2,494.27 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:498.2,502.65 4 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:507.2,507.22 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:511.2,511.23 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:482.26,484.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:487.76,489.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:490.66,492.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:494.27,496.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:502.65,504.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:507.22,509.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:514.102,515.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:519.2,521.20 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:535.2,536.41 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:540.2,540.30 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:515.26,517.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:522.13,523.25 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:525.13,526.22 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:528.16,529.23 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:531.10,532.82 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:536.41,538.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:543.108,544.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:548.2,549.20 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:553.2,553.47 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:544.26,546.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:549.20,551.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:556.121,558.2 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:560.127,566.76 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:569.2,569.66 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:573.2,573.27 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:577.2,579.65 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:583.2,583.21 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:588.2,588.22 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:566.76,568.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:569.66,571.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:573.27,575.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:579.65,581.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:583.21,586.3 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:591.104,592.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:596.2,596.38 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:592.26,594.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:599.118,604.71 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:608.2,608.98 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:612.2,612.50 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:618.2,619.63 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:623.2,623.18 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:604.71,606.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:608.98,610.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:612.50,614.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:614.8,614.31 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:614.31,616.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:619.63,621.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:626.119,632.66 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:636.2,637.70 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:641.2,641.18 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:632.66,634.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:637.70,639.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:644.109,645.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:649.2,650.76 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:654.2,654.66 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:658.2,658.27 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:662.2,666.72 4 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:671.2,671.29 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:675.2,675.30 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:645.26,647.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:650.76,652.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:654.66,656.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:658.27,660.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:666.72,668.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:671.29,673.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:678.109,679.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:683.2,685.20 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:699.2,700.48 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:704.2,704.37 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:679.26,681.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:686.13,687.28 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:689.13,690.29 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:692.16,693.30 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:695.10,696.82 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:700.48,702.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:707.131,712.76 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:716.2,716.66 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:720.2,720.27 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:724.2,726.72 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:730.2,730.28 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:735.2,735.29 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:712.76,714.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:716.66,718.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:720.27,722.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:726.72,728.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:730.28,733.3 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:738.111,739.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:743.2,743.45 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:739.26,741.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:746.132,750.78 4 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:754.2,754.105 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:758.2,758.71 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:764.2,765.70 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:769.2,769.18 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:750.78,752.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:754.105,756.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:758.71,760.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:760.8,760.38 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:760.38,762.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:765.70,767.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:772.133,778.66 4 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:782.2,783.77 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:787.2,787.18 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:778.66,780.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:783.77,785.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:790.108,791.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:795.2,796.76 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:799.2,799.66 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:803.2,803.27 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:807.2,809.71 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:814.2,814.28 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:818.2,818.29 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:791.26,793.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:796.76,798.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:799.66,801.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:803.27,805.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:809.71,811.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:814.28,816.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:821.108,822.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:826.2,828.20 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:842.2,843.45 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:847.2,847.34 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:822.26,824.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:829.13,830.27 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:832.13,833.28 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:835.16,836.29 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:838.10,839.82 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:843.45,845.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:850.127,855.76 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:858.2,858.66 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:862.2,862.27 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:866.2,868.71 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:872.2,872.27 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:877.2,878.28 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:855.76,857.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:858.66,860.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:862.27,864.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:868.71,870.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:872.27,875.3 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:881.110,882.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:886.2,886.44 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:882.26,884.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:889.128,893.77 4 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:897.2,897.104 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:901.2,901.22 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:909.2,910.69 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:914.2,915.18 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:893.77,895.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:897.104,899.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:901.22,902.71 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:902.71,904.4 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:904.9,904.40 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:904.40,906.4 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:910.69,912.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:918.129,924.66 4 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:928.2,929.76 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:933.2,933.18 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:924.66,926.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:929.76,931.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:936.99,937.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:941.2,946.71 3 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:950.2,950.98 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:954.2,955.61 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:959.2,959.18 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:937.26,939.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:946.71,948.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:950.98,952.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:955.61,957.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:962.100,963.26 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:967.2,973.22 4 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:977.2,978.67 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:982.2,982.18 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:963.26,965.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:973.22,975.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:978.67,980.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:989.59,990.34 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:990.34,991.33 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:991.33,994.4 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:998.103,1023.26 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:1027.2,1039.64 5 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:1043.2,1043.41 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:1047.2,1047.32 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:1051.2,1051.81 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:1069.2,1069.22 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:1073.2,1073.23 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:1023.26,1025.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:1039.64,1041.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:1043.41,1045.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:1047.32,1049.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:1051.81,1054.76 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:1054.76,1056.4 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:1057.8,1059.17 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:1063.3,1064.17 2 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:1059.17,1061.4 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:1064.17,1066.4 1 0 +github.com/hashicorp/consul/agent/acl_endpoint.go:1069.22,1071.3 1 0 +github.com/hashicorp/consul/agent/acl_endpoint_legacy.go:8.100,13.2 4 0 +github.com/hashicorp/consul/agent/dns.go:145.49,158.16 5 1 +github.com/hashicorp/consul/agent/dns.go:161.2,171.26 4 1 +github.com/hashicorp/consul/agent/dns.go:174.2,176.17 2 1 +github.com/hashicorp/consul/agent/dns.go:158.16,160.3 1 0 +github.com/hashicorp/consul/agent/dns.go:171.26,173.3 1 0 +github.com/hashicorp/consul/agent/dns.go:180.67,206.31 2 1 +github.com/hashicorp/consul/agent/dns.go:220.2,220.38 1 1 +github.com/hashicorp/consul/agent/dns.go:228.2,228.17 1 1 +github.com/hashicorp/consul/agent/dns.go:206.31,210.44 3 1 +github.com/hashicorp/consul/agent/dns.go:210.44,213.35 1 0 +github.com/hashicorp/consul/agent/dns.go:213.35,215.5 1 0 +github.com/hashicorp/consul/agent/dns.go:215.10,217.5 1 0 +github.com/hashicorp/consul/agent/dns.go:220.38,222.17 2 0 +github.com/hashicorp/consul/agent/dns.go:225.3,225.44 1 0 +github.com/hashicorp/consul/agent/dns.go:222.17,224.4 1 0 +github.com/hashicorp/consul/agent/dns.go:233.78,234.26 1 0 +github.com/hashicorp/consul/agent/dns.go:240.2,240.25 1 0 +github.com/hashicorp/consul/agent/dns.go:246.2,246.17 1 0 +github.com/hashicorp/consul/agent/dns.go:234.26,236.9 2 0 +github.com/hashicorp/consul/agent/dns.go:236.9,238.4 1 0 +github.com/hashicorp/consul/agent/dns.go:240.25,242.9 2 0 +github.com/hashicorp/consul/agent/dns.go:242.9,244.4 1 0 +github.com/hashicorp/consul/agent/dns.go:249.78,256.22 2 1 +github.com/hashicorp/consul/agent/dns.go:259.2,259.34 1 1 +github.com/hashicorp/consul/agent/dns.go:256.22,258.3 1 1 +github.com/hashicorp/consul/agent/dns.go:263.69,266.75 2 1 +github.com/hashicorp/consul/agent/dns.go:272.2,272.76 1 1 +github.com/hashicorp/consul/agent/dns.go:266.75,270.3 3 0 +github.com/hashicorp/consul/agent/dns.go:272.76,276.3 3 0 +github.com/hashicorp/consul/agent/dns.go:280.70,282.16 2 0 +github.com/hashicorp/consul/agent/dns.go:285.2,287.12 3 0 +github.com/hashicorp/consul/agent/dns.go:282.16,284.3 1 0 +github.com/hashicorp/consul/agent/dns.go:293.67,295.17 2 0 +github.com/hashicorp/consul/agent/dns.go:301.2,307.60 5 0 +github.com/hashicorp/consul/agent/dns.go:323.2,323.51 1 0 +github.com/hashicorp/consul/agent/dns.go:295.17,297.3 1 0 +github.com/hashicorp/consul/agent/dns.go:307.60,313.152 6 0 +github.com/hashicorp/consul/agent/dns.go:320.3,320.51 1 0 +github.com/hashicorp/consul/agent/dns.go:313.152,316.4 1 0 +github.com/hashicorp/consul/agent/dns.go:316.9,319.4 1 0 +github.com/hashicorp/consul/agent/dns.go:327.52,329.1 1 0 +github.com/hashicorp/consul/agent/dns.go:330.2,331.40 2 0 +github.com/hashicorp/consul/agent/dns.go:342.2,342.16 1 0 +github.com/hashicorp/consul/agent/dns.go:347.2,348.16 2 0 +github.com/hashicorp/consul/agent/dns.go:353.2,353.27 1 0 +github.com/hashicorp/consul/agent/dns.go:331.40,332.42 1 0 +github.com/hashicorp/consul/agent/dns.go:332.42,334.14 2 0 +github.com/hashicorp/consul/agent/dns.go:335.9,335.52 1 0 +github.com/hashicorp/consul/agent/dns.go:335.52,336.65 1 0 +github.com/hashicorp/consul/agent/dns.go:336.65,338.15 2 0 +github.com/hashicorp/consul/agent/dns.go:342.16,344.3 1 0 +github.com/hashicorp/consul/agent/dns.go:348.16,350.3 1 0 +github.com/hashicorp/consul/agent/dns.go:356.81,358.2 1 0 +github.com/hashicorp/consul/agent/dns.go:360.100,362.2 1 0 +github.com/hashicorp/consul/agent/dns.go:366.67,369.40 3 0 +github.com/hashicorp/consul/agent/dns.go:375.2,375.15 1 0 +github.com/hashicorp/consul/agent/dns.go:369.40,371.98 2 0 +github.com/hashicorp/consul/agent/dns.go:371.98,373.4 1 0 +github.com/hashicorp/consul/agent/dns.go:379.70,381.26 2 0 +github.com/hashicorp/consul/agent/dns.go:392.2,402.42 7 0 +github.com/hashicorp/consul/agent/dns.go:406.2,422.70 5 0 +github.com/hashicorp/consul/agent/dns.go:437.2,437.24 1 0 +github.com/hashicorp/consul/agent/dns.go:466.2,466.24 1 0 +github.com/hashicorp/consul/agent/dns.go:472.2,475.41 2 0 +github.com/hashicorp/consul/agent/dns.go:381.26,390.3 2 0 +github.com/hashicorp/consul/agent/dns.go:402.42,404.3 1 0 +github.com/hashicorp/consul/agent/dns.go:422.70,423.31 1 0 +github.com/hashicorp/consul/agent/dns.go:423.31,425.21 2 0 +github.com/hashicorp/consul/agent/dns.go:425.21,431.10 3 0 +github.com/hashicorp/consul/agent/dns.go:437.24,451.76 4 0 +github.com/hashicorp/consul/agent/dns.go:451.76,452.40 1 0 +github.com/hashicorp/consul/agent/dns.go:452.40,453.43 1 0 +github.com/hashicorp/consul/agent/dns.go:453.43,459.11 3 0 +github.com/hashicorp/consul/agent/dns.go:466.24,469.3 2 0 +github.com/hashicorp/consul/agent/dns.go:475.41,477.3 1 0 +github.com/hashicorp/consul/agent/dns.go:481.72,483.26 2 0 +github.com/hashicorp/consul/agent/dns.go:497.2,498.51 2 0 +github.com/hashicorp/consul/agent/dns.go:502.2,513.31 8 0 +github.com/hashicorp/consul/agent/dns.go:539.2,543.41 3 0 +github.com/hashicorp/consul/agent/dns.go:483.26,494.3 2 0 +github.com/hashicorp/consul/agent/dns.go:498.51,500.3 1 0 +github.com/hashicorp/consul/agent/dns.go:514.19,519.36 5 0 +github.com/hashicorp/consul/agent/dns.go:521.18,525.36 4 0 +github.com/hashicorp/consul/agent/dns.go:527.20,528.43 1 0 +github.com/hashicorp/consul/agent/dns.go:530.10,533.63 3 0 +github.com/hashicorp/consul/agent/dns.go:536.3,536.25 1 0 +github.com/hashicorp/consul/agent/dns.go:533.63,535.4 1 0 +github.com/hashicorp/consul/agent/dns.go:543.41,545.3 1 0 +github.com/hashicorp/consul/agent/dns.go:548.71,550.75 2 0 +github.com/hashicorp/consul/agent/dns.go:554.2,569.3 1 0 +github.com/hashicorp/consul/agent/dns.go:550.75,552.3 1 0 +github.com/hashicorp/consul/agent/dns.go:573.79,575.2 1 0 +github.com/hashicorp/consul/agent/dns.go:580.123,588.16 2 0 +github.com/hashicorp/consul/agent/dns.go:593.2,593.25 1 0 +github.com/hashicorp/consul/agent/dns.go:599.2,601.30 2 0 +github.com/hashicorp/consul/agent/dns.go:632.2,632.8 1 0 +github.com/hashicorp/consul/agent/dns.go:588.16,591.3 2 0 +github.com/hashicorp/consul/agent/dns.go:593.25,596.3 2 0 +github.com/hashicorp/consul/agent/dns.go:601.30,604.47 2 0 +github.com/hashicorp/consul/agent/dns.go:608.3,627.19 7 0 +github.com/hashicorp/consul/agent/dns.go:604.47,606.12 2 0 +github.com/hashicorp/consul/agent/dns.go:627.19,629.4 1 0 +github.com/hashicorp/consul/agent/dns.go:635.84,639.2 3 0 +github.com/hashicorp/consul/agent/dns.go:641.79,642.21 1 0 +github.com/hashicorp/consul/agent/dns.go:643.9,645.14 2 0 +github.com/hashicorp/consul/agent/dns.go:646.9,647.14 1 0 +github.com/hashicorp/consul/agent/dns.go:648.10,649.15 1 0 +github.com/hashicorp/consul/agent/dns.go:668.43,669.20 1 0 +github.com/hashicorp/consul/agent/dns.go:672.2,672.24 1 0 +github.com/hashicorp/consul/agent/dns.go:669.20,671.3 1 0 +github.com/hashicorp/consul/agent/dns.go:675.49,677.2 1 0 +github.com/hashicorp/consul/agent/dns.go:679.43,681.2 1 0 +github.com/hashicorp/consul/agent/dns.go:695.69,697.24 1 0 +github.com/hashicorp/consul/agent/dns.go:701.2,701.30 1 0 +github.com/hashicorp/consul/agent/dns.go:705.2,705.18 1 0 +github.com/hashicorp/consul/agent/dns.go:697.24,699.3 1 0 +github.com/hashicorp/consul/agent/dns.go:701.30,703.3 1 0 +github.com/hashicorp/consul/agent/dns.go:710.100,728.49 10 0 +github.com/hashicorp/consul/agent/dns.go:747.2,747.26 1 0 +github.com/hashicorp/consul/agent/dns.go:752.2,752.19 1 0 +github.com/hashicorp/consul/agent/dns.go:728.49,729.20 1 0 +github.com/hashicorp/consul/agent/dns.go:730.76,734.15 4 0 +github.com/hashicorp/consul/agent/dns.go:735.11,738.81 1 0 +github.com/hashicorp/consul/agent/dns.go:738.81,743.5 4 0 +github.com/hashicorp/consul/agent/dns.go:747.26,750.3 2 0 +github.com/hashicorp/consul/agent/dns.go:753.17,755.12 2 0 +github.com/hashicorp/consul/agent/dns.go:759.3,760.10 2 0 +github.com/hashicorp/consul/agent/dns.go:764.3,772.95 2 0 +github.com/hashicorp/consul/agent/dns.go:790.3,791.13 2 0 +github.com/hashicorp/consul/agent/dns.go:795.3,799.49 3 0 +github.com/hashicorp/consul/agent/dns.go:801.17,802.26 1 0 +github.com/hashicorp/consul/agent/dns.go:806.3,807.10 2 0 +github.com/hashicorp/consul/agent/dns.go:811.3,820.49 2 0 +github.com/hashicorp/consul/agent/dns.go:822.17,823.26 1 0 +github.com/hashicorp/consul/agent/dns.go:827.3,828.10 2 0 +github.com/hashicorp/consul/agent/dns.go:832.3,844.81 3 0 +github.com/hashicorp/consul/agent/dns.go:847.3,847.16 1 0 +github.com/hashicorp/consul/agent/dns.go:859.3,859.13 1 0 +github.com/hashicorp/consul/agent/dns.go:861.17,862.26 1 0 +github.com/hashicorp/consul/agent/dns.go:866.3,867.10 2 0 +github.com/hashicorp/consul/agent/dns.go:871.3,880.49 2 0 +github.com/hashicorp/consul/agent/dns.go:882.14,883.26 1 0 +github.com/hashicorp/consul/agent/dns.go:887.3,888.10 2 0 +github.com/hashicorp/consul/agent/dns.go:894.3,894.37 1 0 +github.com/hashicorp/consul/agent/dns.go:899.3,908.46 3 0 +github.com/hashicorp/consul/agent/dns.go:910.15,914.26 2 0 +github.com/hashicorp/consul/agent/dns.go:918.3,918.53 1 0 +github.com/hashicorp/consul/agent/dns.go:923.3,925.39 3 0 +github.com/hashicorp/consul/agent/dns.go:927.14,930.27 1 0 +github.com/hashicorp/consul/agent/dns.go:934.3,934.33 1 0 +github.com/hashicorp/consul/agent/dns.go:978.3,978.13 1 0 +github.com/hashicorp/consul/agent/dns.go:979.10,980.19 1 0 +github.com/hashicorp/consul/agent/dns.go:755.12,757.4 1 0 +github.com/hashicorp/consul/agent/dns.go:760.10,762.4 1 0 +github.com/hashicorp/consul/agent/dns.go:772.95,778.20 2 0 +github.com/hashicorp/consul/agent/dns.go:782.4,785.50 3 0 +github.com/hashicorp/consul/agent/dns.go:778.20,780.5 1 0 +github.com/hashicorp/consul/agent/dns.go:791.13,793.4 1 0 +github.com/hashicorp/consul/agent/dns.go:802.26,804.4 1 0 +github.com/hashicorp/consul/agent/dns.go:807.10,809.4 1 0 +github.com/hashicorp/consul/agent/dns.go:823.26,825.4 1 0 +github.com/hashicorp/consul/agent/dns.go:828.10,830.4 1 0 +github.com/hashicorp/consul/agent/dns.go:844.81,846.4 1 0 +github.com/hashicorp/consul/agent/dns.go:847.16,857.4 1 0 +github.com/hashicorp/consul/agent/dns.go:862.26,864.4 1 0 +github.com/hashicorp/consul/agent/dns.go:867.10,869.4 1 0 +github.com/hashicorp/consul/agent/dns.go:883.26,885.4 1 0 +github.com/hashicorp/consul/agent/dns.go:888.10,890.4 1 0 +github.com/hashicorp/consul/agent/dns.go:894.37,896.4 1 0 +github.com/hashicorp/consul/agent/dns.go:914.26,916.4 1 0 +github.com/hashicorp/consul/agent/dns.go:918.53,920.4 1 0 +github.com/hashicorp/consul/agent/dns.go:930.27,932.4 1 0 +github.com/hashicorp/consul/agent/dns.go:936.10,938.18 2 0 +github.com/hashicorp/consul/agent/dns.go:942.4,951.82 2 0 +github.com/hashicorp/consul/agent/dns.go:957.11,959.18 2 0 +github.com/hashicorp/consul/agent/dns.go:963.4,972.85 2 0 +github.com/hashicorp/consul/agent/dns.go:938.18,940.5 1 0 +github.com/hashicorp/consul/agent/dns.go:951.82,953.5 1 0 +github.com/hashicorp/consul/agent/dns.go:953.10,955.5 1 0 +github.com/hashicorp/consul/agent/dns.go:959.18,961.5 1 0 +github.com/hashicorp/consul/agent/dns.go:972.85,974.5 1 0 +github.com/hashicorp/consul/agent/dns.go:974.10,976.5 1 0 +github.com/hashicorp/consul/agent/dns.go:984.53,988.32 3 0 +github.com/hashicorp/consul/agent/dns.go:992.2,992.38 1 0 +github.com/hashicorp/consul/agent/dns.go:995.2,995.43 1 0 +github.com/hashicorp/consul/agent/dns.go:988.32,990.3 1 0 +github.com/hashicorp/consul/agent/dns.go:992.38,994.3 1 0 +github.com/hashicorp/consul/agent/dns.go:999.36,1000.9 1 0 +github.com/hashicorp/consul/agent/dns.go:1001.18,1002.26 1 0 +github.com/hashicorp/consul/agent/dns.go:1003.33,1004.26 1 0 +github.com/hashicorp/consul/agent/dns.go:1005.39,1006.44 1 0 +github.com/hashicorp/consul/agent/dns.go:1007.39,1008.28 1 0 +github.com/hashicorp/consul/agent/dns.go:1009.69,1010.28 1 0 +github.com/hashicorp/consul/agent/dns.go:1011.10,1012.32 1 0 +github.com/hashicorp/consul/agent/dns.go:1017.93,1020.97 2 0 +github.com/hashicorp/consul/agent/dns.go:1025.2,1035.16 3 0 +github.com/hashicorp/consul/agent/dns.go:1040.2,1040.29 1 0 +github.com/hashicorp/consul/agent/dns.go:1045.2,1048.50 3 0 +github.com/hashicorp/consul/agent/dns.go:1052.2,1054.26 2 0 +github.com/hashicorp/consul/agent/dns.go:1059.2,1059.69 1 0 +github.com/hashicorp/consul/agent/dns.go:1063.2,1063.12 1 0 +github.com/hashicorp/consul/agent/dns.go:1020.97,1022.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1035.16,1037.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1040.29,1042.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1048.50,1050.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1054.26,1057.3 2 0 +github.com/hashicorp/consul/agent/dns.go:1059.69,1062.3 2 0 +github.com/hashicorp/consul/agent/dns.go:1066.121,1070.1 3 0 +github.com/hashicorp/consul/agent/dns.go:1071.2,1071.14 1 0 +github.com/hashicorp/consul/agent/dns.go:1089.2,1089.21 1 0 +github.com/hashicorp/consul/agent/dns.go:1100.2,1100.18 1 0 +github.com/hashicorp/consul/agent/dns.go:1071.14,1073.17 2 0 +github.com/hashicorp/consul/agent/dns.go:1076.3,1077.10 2 0 +github.com/hashicorp/consul/agent/dns.go:1081.3,1081.15 1 0 +github.com/hashicorp/consul/agent/dns.go:1073.17,1075.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1077.10,1080.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1082.8,1083.74 1 0 +github.com/hashicorp/consul/agent/dns.go:1083.74,1085.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1089.21,1090.37 1 0 +github.com/hashicorp/consul/agent/dns.go:1090.37,1094.12 4 0 +github.com/hashicorp/consul/agent/dns.go:1095.9,1095.53 1 0 +github.com/hashicorp/consul/agent/dns.go:1095.53,1097.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1104.56,1122.2 10 0 +github.com/hashicorp/consul/agent/dns.go:1127.54,1128.25 1 0 +github.com/hashicorp/consul/agent/dns.go:1128.25,1130.32 2 0 +github.com/hashicorp/consul/agent/dns.go:1130.32,1132.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1141.56,1144.36 3 0 +github.com/hashicorp/consul/agent/dns.go:1170.2,1170.20 1 0 +github.com/hashicorp/consul/agent/dns.go:1144.36,1146.10 2 0 +github.com/hashicorp/consul/agent/dns.go:1153.3,1155.2 2 0 +github.com/hashicorp/consul/agent/dns.go:1156.3,1156.36 1 0 +github.com/hashicorp/consul/agent/dns.go:1159.3,1162.9 3 0 +github.com/hashicorp/consul/agent/dns.go:1146.10,1147.12 1 0 +github.com/hashicorp/consul/agent/dns.go:1156.36,1157.12 1 0 +github.com/hashicorp/consul/agent/dns.go:1162.9,1164.45 2 0 +github.com/hashicorp/consul/agent/dns.go:1164.45,1166.17 2 0 +github.com/hashicorp/consul/agent/dns.go:1175.96,1179.30 4 0 +github.com/hashicorp/consul/agent/dns.go:1197.2,1197.19 1 0 +github.com/hashicorp/consul/agent/dns.go:1179.30,1183.15 3 0 +github.com/hashicorp/consul/agent/dns.go:1186.3,1187.22 2 0 +github.com/hashicorp/consul/agent/dns.go:1183.15,1185.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1187.22,1188.25 1 0 +github.com/hashicorp/consul/agent/dns.go:1192.4,1192.23 1 0 +github.com/hashicorp/consul/agent/dns.go:1188.25,1191.5 1 0 +github.com/hashicorp/consul/agent/dns.go:1193.9,1195.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1202.57,1215.42 5 0 +github.com/hashicorp/consul/agent/dns.go:1219.2,1219.35 1 0 +github.com/hashicorp/consul/agent/dns.go:1222.2,1222.14 1 0 +github.com/hashicorp/consul/agent/dns.go:1226.2,1229.51 2 0 +github.com/hashicorp/consul/agent/dns.go:1247.2,1247.18 1 0 +github.com/hashicorp/consul/agent/dns.go:1215.42,1218.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1219.35,1221.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1222.14,1225.3 2 0 +github.com/hashicorp/consul/agent/dns.go:1229.51,1232.24 2 0 +github.com/hashicorp/consul/agent/dns.go:1236.3,1236.31 1 0 +github.com/hashicorp/consul/agent/dns.go:1242.3,1242.15 1 0 +github.com/hashicorp/consul/agent/dns.go:1232.24,1234.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1236.31,1239.4 2 0 +github.com/hashicorp/consul/agent/dns.go:1239.9,1241.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1242.15,1244.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1254.77,1260.40 4 0 +github.com/hashicorp/consul/agent/dns.go:1267.2,1267.34 1 0 +github.com/hashicorp/consul/agent/dns.go:1273.2,1274.14 2 0 +github.com/hashicorp/consul/agent/dns.go:1280.2,1282.61 3 0 +github.com/hashicorp/consul/agent/dns.go:1300.2,1300.53 1 0 +github.com/hashicorp/consul/agent/dns.go:1318.2,1319.38 2 0 +github.com/hashicorp/consul/agent/dns.go:1260.40,1261.53 1 0 +github.com/hashicorp/consul/agent/dns.go:1261.53,1263.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1267.34,1269.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1274.14,1277.3 2 0 +github.com/hashicorp/consul/agent/dns.go:1282.61,1286.15 3 0 +github.com/hashicorp/consul/agent/dns.go:1286.15,1288.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1300.53,1302.24 1 0 +github.com/hashicorp/consul/agent/dns.go:1306.3,1306.31 1 0 +github.com/hashicorp/consul/agent/dns.go:1312.3,1312.15 1 0 +github.com/hashicorp/consul/agent/dns.go:1302.24,1304.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1306.31,1309.4 2 0 +github.com/hashicorp/consul/agent/dns.go:1309.9,1311.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1312.15,1314.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1323.89,1327.22 4 0 +github.com/hashicorp/consul/agent/dns.go:1333.2,1333.13 1 0 +github.com/hashicorp/consul/agent/dns.go:1327.22,1329.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1329.8,1331.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1333.13,1334.25 1 0 +github.com/hashicorp/consul/agent/dns.go:1337.3,1342.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1334.25,1336.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1347.120,1349.22 2 0 +github.com/hashicorp/consul/agent/dns.go:1352.2,1370.16 3 0 +github.com/hashicorp/consul/agent/dns.go:1376.2,1379.17 4 0 +github.com/hashicorp/consul/agent/dns.go:1349.22,1351.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1370.16,1372.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1383.99,1385.16 2 0 +github.com/hashicorp/consul/agent/dns.go:1390.2,1390.25 1 0 +github.com/hashicorp/consul/agent/dns.go:1395.2,1402.26 4 0 +github.com/hashicorp/consul/agent/dns.go:1408.2,1408.27 1 0 +github.com/hashicorp/consul/agent/dns.go:1411.2,1411.12 1 0 +github.com/hashicorp/consul/agent/dns.go:1385.16,1387.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1390.25,1392.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1402.26,1404.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1404.8,1406.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1408.27,1410.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1414.59,1418.17 2 0 +github.com/hashicorp/consul/agent/dns.go:1422.2,1422.32 1 0 +github.com/hashicorp/consul/agent/dns.go:1428.2,1428.12 1 0 +github.com/hashicorp/consul/agent/dns.go:1418.17,1420.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1422.32,1423.46 1 0 +github.com/hashicorp/consul/agent/dns.go:1423.46,1425.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1432.153,1457.19 3 0 +github.com/hashicorp/consul/agent/dns.go:1470.2,1471.16 2 0 +github.com/hashicorp/consul/agent/dns.go:1487.2,1488.23 2 0 +github.com/hashicorp/consul/agent/dns.go:1502.2,1502.25 1 0 +github.com/hashicorp/consul/agent/dns.go:1507.2,1508.26 2 0 +github.com/hashicorp/consul/agent/dns.go:1514.2,1514.27 1 0 +github.com/hashicorp/consul/agent/dns.go:1517.2,1517.12 1 0 +github.com/hashicorp/consul/agent/dns.go:1457.19,1459.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1459.8,1460.33 1 0 +github.com/hashicorp/consul/agent/dns.go:1461.21,1462.34 1 0 +github.com/hashicorp/consul/agent/dns.go:1463.21,1464.34 1 0 +github.com/hashicorp/consul/agent/dns.go:1465.20,1466.34 1 0 +github.com/hashicorp/consul/agent/dns.go:1471.16,1473.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1488.23,1491.17 3 0 +github.com/hashicorp/consul/agent/dns.go:1491.17,1496.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1497.8,1499.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1502.25,1504.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1508.26,1510.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1510.8,1512.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1514.27,1516.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1520.146,1523.1 2 0 +github.com/hashicorp/consul/agent/dns.go:1524.2,1524.18 1 0 +github.com/hashicorp/consul/agent/dns.go:1548.2,1548.21 1 0 +github.com/hashicorp/consul/agent/dns.go:1558.2,1558.18 1 0 +github.com/hashicorp/consul/agent/dns.go:1524.18,1526.17 2 0 +github.com/hashicorp/consul/agent/dns.go:1529.3,1530.10 2 0 +github.com/hashicorp/consul/agent/dns.go:1535.3,1540.15 2 0 +github.com/hashicorp/consul/agent/dns.go:1526.17,1528.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1530.10,1533.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1541.8,1542.75 1 0 +github.com/hashicorp/consul/agent/dns.go:1542.75,1544.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1548.21,1549.37 1 0 +github.com/hashicorp/consul/agent/dns.go:1549.37,1552.12 3 0 +github.com/hashicorp/consul/agent/dns.go:1553.9,1553.53 1 0 +github.com/hashicorp/consul/agent/dns.go:1553.53,1555.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1562.162,1567.29 4 0 +github.com/hashicorp/consul/agent/dns.go:1603.2,1603.51 1 0 +github.com/hashicorp/consul/agent/dns.go:1567.29,1571.24 3 0 +github.com/hashicorp/consul/agent/dns.go:1577.3,1577.48 1 0 +github.com/hashicorp/consul/agent/dns.go:1580.3,1582.28 2 0 +github.com/hashicorp/consul/agent/dns.go:1594.3,1594.17 1 0 +github.com/hashicorp/consul/agent/dns.go:1571.24,1572.12 1 0 +github.com/hashicorp/consul/agent/dns.go:1577.48,1578.12 1 0 +github.com/hashicorp/consul/agent/dns.go:1583.19,1586.29 1 0 +github.com/hashicorp/consul/agent/dns.go:1589.11,1591.21 2 0 +github.com/hashicorp/consul/agent/dns.go:1586.29,1588.5 1 0 +github.com/hashicorp/consul/agent/dns.go:1594.17,1596.33 2 0 +github.com/hashicorp/consul/agent/dns.go:1596.33,1599.5 1 0 +github.com/hashicorp/consul/agent/dns.go:1603.51,1605.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1608.52,1614.33 3 0 +github.com/hashicorp/consul/agent/dns.go:1618.2,1619.32 2 0 +github.com/hashicorp/consul/agent/dns.go:1635.2,1636.16 2 0 +github.com/hashicorp/consul/agent/dns.go:1614.33,1617.3 2 0 +github.com/hashicorp/consul/agent/dns.go:1619.32,1620.67 1 0 +github.com/hashicorp/consul/agent/dns.go:1620.67,1633.4 2 0 +github.com/hashicorp/consul/agent/dns.go:1637.25,1638.23 1 0 +github.com/hashicorp/consul/agent/dns.go:1639.25,1640.23 1 0 +github.com/hashicorp/consul/agent/dns.go:1641.23,1643.11 1 0 +github.com/hashicorp/consul/agent/dns.go:1644.26,1646.11 1 0 +github.com/hashicorp/consul/agent/dns.go:1647.10,1649.11 1 0 +github.com/hashicorp/consul/agent/dns.go:1653.86,1656.17 3 0 +github.com/hashicorp/consul/agent/dns.go:1656.17,1659.3 2 0 +github.com/hashicorp/consul/agent/dns.go:1659.8,1661.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1664.69,1668.17 3 0 +github.com/hashicorp/consul/agent/dns.go:1689.2,1689.17 1 0 +github.com/hashicorp/consul/agent/dns.go:1668.17,1669.120 1 0 +github.com/hashicorp/consul/agent/dns.go:1669.120,1678.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1679.8,1679.129 1 0 +github.com/hashicorp/consul/agent/dns.go:1679.129,1688.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1695.139,1697.24 2 0 +github.com/hashicorp/consul/agent/dns.go:1705.2,1710.15 4 0 +github.com/hashicorp/consul/agent/dns.go:1728.2,1729.21 2 0 +github.com/hashicorp/consul/agent/dns.go:1733.2,1734.27 2 0 +github.com/hashicorp/consul/agent/dns.go:1697.24,1699.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1699.8,1699.34 1 0 +github.com/hashicorp/consul/agent/dns.go:1699.34,1701.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1701.8,1703.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1710.15,1726.3 3 0 +github.com/hashicorp/consul/agent/dns.go:1729.21,1731.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1740.163,1745.21 4 0 +github.com/hashicorp/consul/agent/dns.go:1748.2,1748.28 1 0 +github.com/hashicorp/consul/agent/dns.go:1769.2,1770.32 2 0 +github.com/hashicorp/consul/agent/dns.go:1745.21,1747.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1748.28,1767.3 4 0 +github.com/hashicorp/consul/agent/dns.go:1776.154,1779.21 3 0 +github.com/hashicorp/consul/agent/dns.go:1783.2,1783.28 1 0 +github.com/hashicorp/consul/agent/dns.go:1804.2,1805.32 2 0 +github.com/hashicorp/consul/agent/dns.go:1779.21,1781.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1783.28,1802.3 4 0 +github.com/hashicorp/consul/agent/dns.go:1811.195,1819.26 6 0 +github.com/hashicorp/consul/agent/dns.go:1833.2,1833.28 1 0 +github.com/hashicorp/consul/agent/dns.go:1851.2,1863.21 3 0 +github.com/hashicorp/consul/agent/dns.go:1819.26,1820.29 1 0 +github.com/hashicorp/consul/agent/dns.go:1821.47,1827.43 4 0 +github.com/hashicorp/consul/agent/dns.go:1827.43,1828.19 1 0 +github.com/hashicorp/consul/agent/dns.go:1833.28,1849.3 2 0 +github.com/hashicorp/consul/agent/dns.go:1866.175,1868.40 2 0 +github.com/hashicorp/consul/agent/dns.go:1876.2,1878.41 3 0 +github.com/hashicorp/consul/agent/dns.go:1882.2,1886.44 3 0 +github.com/hashicorp/consul/agent/dns.go:1896.2,1896.23 1 0 +github.com/hashicorp/consul/agent/dns.go:1901.2,1901.26 1 0 +github.com/hashicorp/consul/agent/dns.go:1907.2,1907.72 1 0 +github.com/hashicorp/consul/agent/dns.go:1912.2,1912.86 1 0 +github.com/hashicorp/consul/agent/dns.go:1868.40,1870.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1870.8,1870.50 1 0 +github.com/hashicorp/consul/agent/dns.go:1870.50,1872.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1872.8,1874.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1878.41,1880.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1886.44,1887.36 1 0 +github.com/hashicorp/consul/agent/dns.go:1892.3,1892.69 1 0 +github.com/hashicorp/consul/agent/dns.go:1887.36,1890.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1896.23,1898.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1901.26,1903.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1907.72,1909.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1915.96,1917.36 2 0 +github.com/hashicorp/consul/agent/dns.go:1933.2,1933.14 1 0 +github.com/hashicorp/consul/agent/dns.go:1917.36,1919.59 2 0 +github.com/hashicorp/consul/agent/dns.go:1923.3,1931.5 1 0 +github.com/hashicorp/consul/agent/dns.go:1919.59,1921.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1937.161,1940.29 2 0 +github.com/hashicorp/consul/agent/dns.go:1940.29,1946.34 4 0 +github.com/hashicorp/consul/agent/dns.go:1949.3,1957.22 6 0 +github.com/hashicorp/consul/agent/dns.go:1946.34,1947.12 1 0 +github.com/hashicorp/consul/agent/dns.go:1957.22,1959.4 1 0 +github.com/hashicorp/consul/agent/dns.go:1964.74,1969.26 4 0 +github.com/hashicorp/consul/agent/dns.go:1980.2,1980.51 1 0 +github.com/hashicorp/consul/agent/dns.go:1985.2,1989.71 5 0 +github.com/hashicorp/consul/agent/dns.go:2024.2,2034.40 7 0 +github.com/hashicorp/consul/agent/dns.go:2037.2,2037.18 1 0 +github.com/hashicorp/consul/agent/dns.go:1969.26,1977.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1980.51,1982.3 1 0 +github.com/hashicorp/consul/agent/dns.go:1989.71,1993.81 3 0 +github.com/hashicorp/consul/agent/dns.go:2020.3,2020.49 1 0 +github.com/hashicorp/consul/agent/dns.go:1993.81,2002.12 2 0 +github.com/hashicorp/consul/agent/dns.go:2003.9,2003.53 1 0 +github.com/hashicorp/consul/agent/dns.go:2003.53,2015.43 3 0 +github.com/hashicorp/consul/agent/dns.go:2018.4,2018.10 1 0 +github.com/hashicorp/consul/agent/dns.go:2015.43,2017.5 1 0 +github.com/hashicorp/consul/agent/dns.go:2034.40,2036.3 1 0 +github.com/hashicorp/consul/agent/dns.go:2041.95,2046.112 1 0 +github.com/hashicorp/consul/agent/dns.go:2062.2,2062.29 1 0 +github.com/hashicorp/consul/agent/dns.go:2067.2,2075.71 7 0 +github.com/hashicorp/consul/agent/dns.go:2090.2,2091.12 2 0 +github.com/hashicorp/consul/agent/dns.go:2046.112,2047.28 1 0 +github.com/hashicorp/consul/agent/dns.go:2051.3,2058.21 5 0 +github.com/hashicorp/consul/agent/dns.go:2047.28,2050.4 2 0 +github.com/hashicorp/consul/agent/dns.go:2062.29,2064.3 1 0 +github.com/hashicorp/consul/agent/dns.go:2075.71,2078.17 3 0 +github.com/hashicorp/consul/agent/dns.go:2085.3,2088.4 1 0 +github.com/hashicorp/consul/agent/dns.go:2078.17,2084.4 2 0 +github.com/hashicorp/consul/agent/setup_oss.go:14.84,16.2 1 1 +github.com/hashicorp/consul/agent/setup_oss.go:19.107,21.2 1 1 +github.com/hashicorp/consul/agent/sidecar_service.go:15.54,17.2 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:20.54,22.2 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:41.135,42.38 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:47.2,58.25 4 0 +github.com/hashicorp/consul/agent/sidecar_service.go:67.2,67.48 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:77.2,77.48 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:84.2,87.43 2 0 +github.com/hashicorp/consul/agent/sidecar_service.go:92.2,92.24 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:95.2,95.27 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:98.2,98.27 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:103.2,103.48 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:106.2,106.46 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:112.2,112.131 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:126.2,127.16 2 0 +github.com/hashicorp/consul/agent/sidecar_service.go:131.2,131.36 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:42.38,44.3 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:58.25,61.92 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:61.92,63.4 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:67.48,68.26 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:71.3,71.29 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:68.26,70.4 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:71.29,73.4 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:77.48,79.3 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:87.43,89.3 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:92.24,94.3 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:95.27,97.3 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:98.27,101.3 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:103.48,105.3 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:106.46,108.3 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:112.131,113.26 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:113.26,115.4 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:115.9,116.47 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:119.4,119.42 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:116.47,118.5 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:119.42,121.5 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:127.16,129.3 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:136.105,141.75 3 0 +github.com/hashicorp/consul/agent/sidecar_service.go:184.2,184.21 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:198.2,198.25 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:141.75,151.49 2 0 +github.com/hashicorp/consul/agent/sidecar_service.go:172.3,172.22 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:151.49,154.52 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:154.52,155.64 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:162.5,162.41 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:155.64,160.11 2 0 +github.com/hashicorp/consul/agent/sidecar_service.go:172.22,174.86 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:174.86,176.14 2 0 +github.com/hashicorp/consul/agent/sidecar_service.go:176.14,178.11 2 0 +github.com/hashicorp/consul/agent/sidecar_service.go:184.21,189.79 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:193.3,195.35 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:189.79,192.4 1 0 +github.com/hashicorp/consul/agent/sidecar_service.go:201.127,210.24 2 0 +github.com/hashicorp/consul/agent/sidecar_service.go:213.2,224.3 2 0 +github.com/hashicorp/consul/agent/sidecar_service.go:210.24,212.3 1 0 +github.com/hashicorp/consul/agent/user_event.go:51.55,53.23 1 0 +github.com/hashicorp/consul/agent/user_event.go:56.2,56.58 1 0 +github.com/hashicorp/consul/agent/user_event.go:59.2,59.29 1 0 +github.com/hashicorp/consul/agent/user_event.go:64.2,64.32 1 0 +github.com/hashicorp/consul/agent/user_event.go:69.2,69.28 1 0 +github.com/hashicorp/consul/agent/user_event.go:74.2,74.12 1 0 +github.com/hashicorp/consul/agent/user_event.go:53.23,55.3 1 0 +github.com/hashicorp/consul/agent/user_event.go:56.58,58.3 1 0 +github.com/hashicorp/consul/agent/user_event.go:59.29,60.62 1 0 +github.com/hashicorp/consul/agent/user_event.go:60.62,62.4 1 0 +github.com/hashicorp/consul/agent/user_event.go:64.32,65.65 1 0 +github.com/hashicorp/consul/agent/user_event.go:65.65,67.4 1 0 +github.com/hashicorp/consul/agent/user_event.go:69.28,70.61 1 0 +github.com/hashicorp/consul/agent/user_event.go:70.61,72.4 1 0 +github.com/hashicorp/consul/agent/user_event.go:78.70,80.56 1 0 +github.com/hashicorp/consul/agent/user_event.go:85.2,86.54 2 0 +github.com/hashicorp/consul/agent/user_event.go:89.2,91.16 3 0 +github.com/hashicorp/consul/agent/user_event.go:97.2,108.49 4 0 +github.com/hashicorp/consul/agent/user_event.go:80.56,82.3 1 0 +github.com/hashicorp/consul/agent/user_event.go:86.54,88.3 1 0 +github.com/hashicorp/consul/agent/user_event.go:91.16,93.3 1 0 +github.com/hashicorp/consul/agent/user_event.go:112.32,113.6 1 1 +github.com/hashicorp/consul/agent/user_event.go:113.6,114.10 1 1 +github.com/hashicorp/consul/agent/user_event.go:115.25,118.65 2 0 +github.com/hashicorp/consul/agent/user_event.go:122.4,125.38 2 0 +github.com/hashicorp/consul/agent/user_event.go:130.4,130.26 1 0 +github.com/hashicorp/consul/agent/user_event.go:132.23,133.10 1 1 +github.com/hashicorp/consul/agent/user_event.go:118.65,120.13 2 0 +github.com/hashicorp/consul/agent/user_event.go:125.38,126.13 1 0 +github.com/hashicorp/consul/agent/user_event.go:139.61,141.39 1 0 +github.com/hashicorp/consul/agent/user_event.go:149.2,149.26 1 0 +github.com/hashicorp/consul/agent/user_event.go:164.2,164.29 1 0 +github.com/hashicorp/consul/agent/user_event.go:219.2,219.13 1 0 +github.com/hashicorp/consul/agent/user_event.go:141.39,146.3 1 0 +github.com/hashicorp/consul/agent/user_event.go:149.26,151.17 2 0 +github.com/hashicorp/consul/agent/user_event.go:159.3,159.41 1 0 +github.com/hashicorp/consul/agent/user_event.go:151.17,158.4 2 0 +github.com/hashicorp/consul/agent/user_event.go:159.41,161.4 1 0 +github.com/hashicorp/consul/agent/user_event.go:164.29,166.17 2 0 +github.com/hashicorp/consul/agent/user_event.go:175.3,176.26 2 0 +github.com/hashicorp/consul/agent/user_event.go:191.3,194.36 3 0 +github.com/hashicorp/consul/agent/user_event.go:215.3,215.13 1 0 +github.com/hashicorp/consul/agent/user_event.go:166.17,173.4 2 0 +github.com/hashicorp/consul/agent/user_event.go:176.26,178.18 2 0 +github.com/hashicorp/consul/agent/user_event.go:186.4,186.14 1 0 +github.com/hashicorp/consul/agent/user_event.go:178.18,185.5 2 0 +github.com/hashicorp/consul/agent/user_event.go:194.36,196.38 1 0 +github.com/hashicorp/consul/agent/user_event.go:199.4,199.20 1 0 +github.com/hashicorp/consul/agent/user_event.go:205.4,205.34 1 0 +github.com/hashicorp/consul/agent/user_event.go:196.38,197.13 1 0 +github.com/hashicorp/consul/agent/user_event.go:199.20,201.10 2 0 +github.com/hashicorp/consul/agent/user_event.go:205.34,206.32 1 0 +github.com/hashicorp/consul/agent/user_event.go:209.5,210.16 2 0 +github.com/hashicorp/consul/agent/user_event.go:206.32,207.14 1 0 +github.com/hashicorp/consul/agent/user_event.go:215.13,217.4 1 0 +github.com/hashicorp/consul/agent/user_event.go:223.49,225.18 1 0 +github.com/hashicorp/consul/agent/user_event.go:243.2,244.15 2 0 +github.com/hashicorp/consul/agent/user_event.go:249.2,251.44 3 0 +github.com/hashicorp/consul/agent/user_event.go:226.22,227.33 1 0 +github.com/hashicorp/consul/agent/user_event.go:235.3,235.9 1 0 +github.com/hashicorp/consul/agent/user_event.go:236.10,240.4 1 0 +github.com/hashicorp/consul/agent/user_event.go:227.33,232.4 1 0 +github.com/hashicorp/consul/agent/user_event.go:232.9,234.4 1 0 +github.com/hashicorp/consul/agent/user_event.go:244.15,247.3 2 0 +github.com/hashicorp/consul/agent/user_event.go:256.43,263.37 5 0 +github.com/hashicorp/consul/agent/user_event.go:275.2,275.12 1 0 +github.com/hashicorp/consul/agent/user_event.go:263.37,264.24 1 0 +github.com/hashicorp/consul/agent/user_event.go:264.24,266.4 1 0 +github.com/hashicorp/consul/agent/user_event.go:266.9,269.4 2 0 +github.com/hashicorp/consul/agent/user_event.go:270.8,274.3 2 0 +github.com/hashicorp/consul/agent/user_event.go:280.44,286.2 5 0 +github.com/hashicorp/consul/agent/user_event.go:296.64,298.2 1 0 +github.com/hashicorp/consul/agent/user_event.go:301.62,305.2 3 0 +github.com/hashicorp/consul/agent/apiserver.go:45.53,52.2 2 1 +github.com/hashicorp/consul/agent/apiserver.go:54.43,58.2 3 1 +github.com/hashicorp/consul/agent/apiserver.go:60.59,65.2 1 1 +github.com/hashicorp/consul/agent/apiserver.go:69.52,72.27 2 1 +github.com/hashicorp/consul/agent/apiserver.go:88.2,89.22 2 1 +github.com/hashicorp/consul/agent/apiserver.go:72.27,76.13 3 1 +github.com/hashicorp/consul/agent/apiserver.go:76.13,83.47 6 1 +github.com/hashicorp/consul/agent/apiserver.go:83.47,85.5 1 0 +github.com/hashicorp/consul/agent/apiserver.go:94.46,96.2 1 1 +github.com/hashicorp/consul/agent/apiserver.go:98.88,103.21 1 1 +github.com/hashicorp/consul/agent/apiserver.go:103.21,105.49 2 1 +github.com/hashicorp/consul/agent/apiserver.go:108.4,108.70 1 0 +github.com/hashicorp/consul/agent/apiserver.go:105.49,107.5 1 1 +github.com/hashicorp/consul/agent/event_endpoint.go:16.100,24.22 5 0 +github.com/hashicorp/consul/agent/event_endpoint.go:29.2,33.53 3 0 +github.com/hashicorp/consul/agent/event_endpoint.go:36.2,36.56 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:39.2,39.52 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:44.2,44.27 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:53.2,53.60 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:62.2,62.19 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:24.22,26.3 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:33.53,35.3 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:36.56,38.3 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:39.52,41.3 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:44.27,46.52 2 0 +github.com/hashicorp/consul/agent/event_endpoint.go:49.3,49.30 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:46.52,48.4 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:53.60,54.37 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:57.3,58.18 2 0 +github.com/hashicorp/consul/agent/event_endpoint.go:54.37,56.4 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:66.100,69.30 2 0 +github.com/hashicorp/consul/agent/event_endpoint.go:74.2,77.16 4 0 +github.com/hashicorp/consul/agent/event_endpoint.go:82.2,83.53 2 0 +github.com/hashicorp/consul/agent/event_endpoint.go:90.2,94.26 3 0 +github.com/hashicorp/consul/agent/event_endpoint.go:99.2,99.35 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:104.2,104.48 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:109.2,109.24 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:115.2,115.25 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:123.2,126.22 2 0 +github.com/hashicorp/consul/agent/event_endpoint.go:141.2,142.35 2 0 +github.com/hashicorp/consul/agent/event_endpoint.go:161.2,161.17 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:166.2,167.22 2 0 +github.com/hashicorp/consul/agent/event_endpoint.go:176.2,181.43 2 0 +github.com/hashicorp/consul/agent/event_endpoint.go:188.2,188.20 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:69.30,71.3 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:77.16,79.3 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:83.53,85.3 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:94.26,95.17 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:99.35,101.3 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:104.48,106.3 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:109.24,111.3 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:115.25,119.3 3 0 +github.com/hashicorp/consul/agent/event_endpoint.go:126.22,127.36 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:127.36,128.36 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:128.36,131.5 2 0 +github.com/hashicorp/consul/agent/event_endpoint.go:142.35,144.46 2 0 +github.com/hashicorp/consul/agent/event_endpoint.go:147.3,150.6 4 0 +github.com/hashicorp/consul/agent/event_endpoint.go:144.46,145.12 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:161.17,163.3 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:167.22,172.3 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:172.8,175.3 2 0 +github.com/hashicorp/consul/agent/event_endpoint.go:181.43,182.10 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:183.19,184.21 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:185.18,185.18 0 0 +github.com/hashicorp/consul/agent/event_endpoint.go:196.39,200.16 4 0 +github.com/hashicorp/consul/agent/event_endpoint.go:203.2,204.16 2 0 +github.com/hashicorp/consul/agent/event_endpoint.go:207.2,207.25 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:200.16,201.38 1 0 +github.com/hashicorp/consul/agent/event_endpoint.go:204.16,205.38 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:11.109,13.26 2 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:17.2,20.82 2 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:24.2,26.72 3 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:30.2,30.22 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:35.2,35.17 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:13.26,15.3 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:20.82,22.3 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:26.72,28.3 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:30.22,33.3 2 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:39.110,41.76 2 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:45.2,45.27 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:49.2,51.73 3 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:56.2,56.23 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:60.2,60.24 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:41.76,43.3 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:45.27,47.3 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:51.73,53.3 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:56.23,58.3 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:64.122,66.76 2 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:70.2,70.27 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:74.2,76.85 3 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:81.2,81.32 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:84.2,84.45 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:90.2,90.33 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:66.76,68.3 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:70.27,72.3 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:76.85,78.3 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:81.32,83.3 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:84.45,85.19 1 0 +github.com/hashicorp/consul/agent/federation_state_endpoint.go:85.19,87.4 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:17.106,19.16 2 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:24.2,24.20 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:19.16,21.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:25.13,26.40 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:27.16,28.42 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:29.10,30.75 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:36.115,38.63 2 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:41.2,50.16 6 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:54.2,55.16 2 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:58.2,58.27 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:62.2,62.36 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:38.63,40.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:50.16,52.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:55.16,57.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:58.27,60.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:66.102,68.63 2 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:71.2,79.16 6 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:83.2,84.16 2 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:88.2,88.28 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:68.63,70.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:79.16,81.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:84.16,86.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:93.111,94.21 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:98.2,99.62 2 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:103.2,104.25 2 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:108.2,109.63 2 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:112.2,112.26 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:116.2,120.16 5 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:124.2,125.16 2 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:129.2,129.25 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:94.21,96.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:99.62,101.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:104.25,106.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:109.63,111.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:112.26,114.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:120.16,122.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:125.16,127.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:134.107,135.21 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:139.2,140.62 2 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:144.2,145.25 2 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:148.2,148.29 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:152.2,153.63 2 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:156.2,156.26 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:160.2,164.16 5 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:168.2,169.16 2 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:173.2,173.25 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:135.21,137.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:140.62,142.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:145.25,147.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:148.29,150.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:153.63,155.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:156.26,158.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:164.16,166.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:169.16,171.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:178.117,180.63 2 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:183.2,192.16 6 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:196.2,197.16 2 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:201.2,201.17 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:180.63,182.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:192.16,194.3 1 0 +github.com/hashicorp/consul/agent/peering_endpoint.go:197.16,199.3 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:23.114,24.63 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:29.2,29.13 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:24.63,25.88 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:25.88,27.4 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:35.154,41.18 5 0 +github.com/hashicorp/consul/agent/translate_addr.go:53.2,53.52 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:41.18,42.61 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:45.3,45.65 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:48.3,48.65 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:42.61,44.4 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:45.65,47.4 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:48.65,50.4 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:59.131,65.18 5 0 +github.com/hashicorp/consul/agent/translate_addr.go:77.2,77.52 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:65.18,66.61 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:69.3,69.65 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:72.3,72.65 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:66.61,68.4 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:69.65,71.4 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:72.65,74.4 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:80.87,81.9 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:100.2,100.11 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:82.57,83.12 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:84.57,85.12 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:86.57,87.13 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:88.10,90.10 2 0 +github.com/hashicorp/consul/agent/translate_addr.go:91.84,92.14 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:93.84,94.14 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:95.64,96.14 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:106.96,118.64 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:125.2,125.26 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:118.64,120.3 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:126.33,127.27 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:132.21,133.75 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:134.21,135.26 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:138.28,139.27 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:144.29,145.20 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:148.3,148.36 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:152.32,153.20 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:156.3,156.36 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:160.10,161.78 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:127.27,131.4 3 0 +github.com/hashicorp/consul/agent/translate_addr.go:135.26,137.4 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:139.27,143.4 3 0 +github.com/hashicorp/consul/agent/translate_addr.go:145.20,147.4 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:148.36,151.4 2 0 +github.com/hashicorp/consul/agent/translate_addr.go:153.20,155.4 1 0 +github.com/hashicorp/consul/agent/translate_addr.go:156.36,159.4 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:45.63,46.54 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:49.2,49.28 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:46.54,48.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:84.98,87.76 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:91.2,91.66 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:95.2,100.1 4 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:101.2,101.70 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:111.2,111.32 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:119.2,119.21 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:124.2,124.40 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:133.2,133.51 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:87.76,89.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:91.66,93.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:101.70,103.85 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:107.3,107.18 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:103.85,105.12 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:111.32,112.27 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:115.3,115.25 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:112.27,114.4 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:115.25,117.4 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:119.21,121.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:124.40,125.27 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:128.3,128.25 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:125.27,127.4 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:128.25,130.4 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:138.101,141.76 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:145.2,145.66 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:150.2,151.21 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:155.2,155.53 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:160.2,162.1 3 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:163.2,163.70 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:173.2,173.23 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:184.2,185.17 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:141.76,143.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:145.66,147.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:151.21,153.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:155.53,157.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:163.70,165.85 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:169.3,169.18 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:165.85,167.12 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:173.23,175.27 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:178.3,178.25 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:181.3,181.19 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:175.27,177.4 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:178.25,180.4 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:190.108,193.76 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:198.2,199.77 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:203.2,203.17 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:193.76,195.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:199.77,201.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:208.101,211.76 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:214.2,214.53 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:217.2,217.66 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:221.2,226.1 4 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:227.2,227.73 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:237.2,241.34 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:248.2,253.29 4 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:272.2,272.20 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:211.76,213.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:214.53,216.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:217.66,219.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:227.73,229.85 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:233.3,233.18 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:229.85,231.12 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:241.34,246.3 4 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:253.29,258.20 4 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:263.3,263.43 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:268.3,270.32 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:258.20,260.4 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:263.43,264.61 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:264.61,266.5 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:276.113,279.76 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:282.2,282.76 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:287.2,288.28 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:293.2,295.1 3 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:296.2,296.80 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:305.2,308.20 3 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:311.2,311.21 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:279.76,281.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:282.76,284.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:288.28,290.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:296.80,298.85 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:302.3,302.18 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:298.85,300.12 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:308.20,310.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:317.108,320.76 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:323.2,323.66 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:327.2,328.28 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:332.2,333.9 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:336.2,338.26 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:346.2,348.1 3 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:349.2,349.77 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:358.2,368.38 5 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:377.2,377.56 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:393.2,394.40 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:404.2,411.18 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:320.76,322.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:323.66,325.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:328.28,330.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:333.9,335.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:339.69,339.69 0 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:341.10,342.129 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:349.77,351.85 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:355.3,355.18 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:351.85,353.12 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:368.38,376.3 3 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:377.56,378.47 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:378.47,390.4 3 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:394.40,402.3 3 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:414.172,420.68 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:436.2,436.27 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:533.2,533.26 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:420.68,422.10 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:433.3,433.14 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:422.10,432.4 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:436.27,439.22 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:446.3,446.46 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:455.3,455.25 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:459.3,469.50 10 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:495.3,495.32 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:512.3,512.70 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:523.3,523.36 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:439.22,442.4 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:442.9,444.4 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:446.46,452.4 4 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:455.25,456.12 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:469.50,475.37 5 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:487.4,487.90 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:490.4,490.54 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:493.4,493.42 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:475.37,478.34 3 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:481.5,481.36 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:478.34,480.6 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:487.90,489.5 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:490.54,492.5 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:495.32,497.38 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:503.4,503.14 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:497.38,498.24 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:498.24,500.11 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:503.14,505.5 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:512.70,514.36 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:517.4,517.51 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:514.36,516.5 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:517.51,520.5 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:523.36,526.25 3 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:529.4,529.27 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:526.25,528.5 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:536.121,542.32 3 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:561.2,561.39 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:564.2,564.13 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:542.32,546.34 3 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:556.3,556.113 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:559.3,559.27 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:546.34,547.22 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:548.27,549.24 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:550.27,551.24 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:552.28,553.25 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:556.113,557.12 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:561.39,563.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:572.3,574.67 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:588.2,588.53 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:574.67,577.19 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:580.3,585.5 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:577.19,578.12 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:588.53,591.57 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:591.57,592.45 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:595.4,598.5 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:592.45,594.5 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:604.110,606.76 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:610.2,611.64 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:616.2,617.16 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:620.2,634.80 4 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:638.2,638.30 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:606.76,608.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:611.64,613.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:617.16,619.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:634.80,636.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:644.105,647.22 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:652.2,653.30 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:660.2,667.63 5 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:670.2,671.16 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:680.2,684.84 4 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:687.2,687.87 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:691.2,705.16 5 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:712.2,714.32 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:738.2,750.49 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:760.2,760.35 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:768.2,771.35 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:780.2,781.17 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:647.22,649.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:653.30,656.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:667.63,669.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:671.16,673.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:684.84,686.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:687.87,689.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:705.16,708.3 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:714.32,719.49 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:725.3,725.13 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:719.49,720.29 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:720.29,722.10 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:725.13,734.4 3 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:750.49,757.3 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:760.35,761.40 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:761.40,763.4 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:763.9,765.4 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:771.35,773.4 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:787.109,790.76 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:793.2,793.53 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:796.2,796.66 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:801.2,803.1 3 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:804.2,804.85 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:813.2,814.35 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:827.2,827.20 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:790.76,792.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:793.53,795.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:796.66,798.3 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:804.85,806.85 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:810.3,810.18 1 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:806.85,808.12 2 0 +github.com/hashicorp/consul/agent/ui_endpoint.go:814.35,826.3 2 0 +github.com/hashicorp/consul/agent/denylist.go:14.47,16.34 2 1 +github.com/hashicorp/consul/agent/denylist.go:19.2,19.24 1 1 +github.com/hashicorp/consul/agent/denylist.go:16.34,18.3 1 0 +github.com/hashicorp/consul/agent/denylist.go:24.44,27.2 2 0 +github.com/hashicorp/consul/agent/keyring.go:25.102,27.68 1 1 +github.com/hashicorp/consul/agent/keyring.go:33.2,34.23 2 1 +github.com/hashicorp/consul/agent/keyring.go:41.2,42.42 2 0 +github.com/hashicorp/consul/agent/keyring.go:49.2,49.12 1 0 +github.com/hashicorp/consul/agent/keyring.go:27.68,29.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:34.23,36.3 1 1 +github.com/hashicorp/consul/agent/keyring.go:42.42,44.17 2 0 +github.com/hashicorp/consul/agent/keyring.go:47.3,47.56 1 0 +github.com/hashicorp/consul/agent/keyring.go:44.17,46.4 1 0 +github.com/hashicorp/consul/agent/keyring.go:53.106,57.33 2 1 +github.com/hashicorp/consul/agent/keyring.go:75.2,79.31 4 1 +github.com/hashicorp/consul/agent/keyring.go:82.2,82.44 1 0 +github.com/hashicorp/consul/agent/keyring.go:89.2,89.46 1 0 +github.com/hashicorp/consul/agent/keyring.go:100.2,100.44 1 1 +github.com/hashicorp/consul/agent/keyring.go:103.2,103.62 1 1 +github.com/hashicorp/consul/agent/keyring.go:106.2,106.46 1 1 +github.com/hashicorp/consul/agent/keyring.go:117.2,117.31 1 1 +github.com/hashicorp/consul/agent/keyring.go:135.2,135.12 1 1 +github.com/hashicorp/consul/agent/keyring.go:57.33,58.32 1 0 +github.com/hashicorp/consul/agent/keyring.go:62.3,63.65 2 0 +github.com/hashicorp/consul/agent/keyring.go:66.3,66.47 1 0 +github.com/hashicorp/consul/agent/keyring.go:71.3,71.13 1 0 +github.com/hashicorp/consul/agent/keyring.go:58.32,60.4 1 0 +github.com/hashicorp/consul/agent/keyring.go:63.65,65.4 1 0 +github.com/hashicorp/consul/agent/keyring.go:66.47,67.66 1 0 +github.com/hashicorp/consul/agent/keyring.go:67.66,69.5 1 0 +github.com/hashicorp/consul/agent/keyring.go:79.31,80.12 1 1 +github.com/hashicorp/consul/agent/keyring.go:82.44,83.67 1 0 +github.com/hashicorp/consul/agent/keyring.go:83.67,85.4 1 0 +github.com/hashicorp/consul/agent/keyring.go:86.8,88.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:89.46,90.45 1 0 +github.com/hashicorp/consul/agent/keyring.go:90.45,91.68 1 0 +github.com/hashicorp/consul/agent/keyring.go:91.68,93.5 1 0 +github.com/hashicorp/consul/agent/keyring.go:94.9,96.4 1 0 +github.com/hashicorp/consul/agent/keyring.go:100.44,102.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:103.62,105.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:106.46,107.45 1 1 +github.com/hashicorp/consul/agent/keyring.go:110.3,110.63 1 1 +github.com/hashicorp/consul/agent/keyring.go:107.45,109.4 1 0 +github.com/hashicorp/consul/agent/keyring.go:110.63,112.4 1 0 +github.com/hashicorp/consul/agent/keyring.go:117.31,123.6 2 0 +github.com/hashicorp/consul/agent/keyring.go:126.3,130.6 1 0 +github.com/hashicorp/consul/agent/keyring.go:123.6,125.4 1 0 +github.com/hashicorp/consul/agent/keyring.go:130.6,132.4 1 0 +github.com/hashicorp/consul/agent/keyring.go:139.42,142.55 2 0 +github.com/hashicorp/consul/agent/keyring.go:149.2,149.41 1 0 +github.com/hashicorp/consul/agent/keyring.go:153.2,155.16 3 0 +github.com/hashicorp/consul/agent/keyring.go:159.2,159.62 1 0 +github.com/hashicorp/consul/agent/keyring.go:163.2,164.16 2 0 +github.com/hashicorp/consul/agent/keyring.go:167.2,169.50 2 0 +github.com/hashicorp/consul/agent/keyring.go:174.2,174.12 1 0 +github.com/hashicorp/consul/agent/keyring.go:142.55,144.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:144.8,144.64 1 0 +github.com/hashicorp/consul/agent/keyring.go:144.64,146.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:149.41,151.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:155.16,157.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:159.62,161.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:164.16,166.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:169.50,172.3 2 0 +github.com/hashicorp/consul/agent/keyring.go:179.44,180.25 1 1 +github.com/hashicorp/consul/agent/keyring.go:184.2,184.50 1 0 +github.com/hashicorp/consul/agent/keyring.go:188.2,189.16 2 0 +github.com/hashicorp/consul/agent/keyring.go:193.2,194.59 2 0 +github.com/hashicorp/consul/agent/keyring.go:198.2,198.29 1 0 +github.com/hashicorp/consul/agent/keyring.go:180.25,182.3 1 1 +github.com/hashicorp/consul/agent/keyring.go:184.50,186.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:189.16,191.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:194.59,196.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:203.55,205.27 2 0 +github.com/hashicorp/consul/agent/keyring.go:213.2,213.27 1 0 +github.com/hashicorp/consul/agent/keyring.go:217.2,218.16 2 0 +github.com/hashicorp/consul/agent/keyring.go:222.2,223.12 2 0 +github.com/hashicorp/consul/agent/keyring.go:205.27,207.17 2 0 +github.com/hashicorp/consul/agent/keyring.go:210.3,210.28 1 0 +github.com/hashicorp/consul/agent/keyring.go:207.17,209.4 1 0 +github.com/hashicorp/consul/agent/keyring.go:213.27,215.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:218.16,220.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:226.50,228.2 1 0 +github.com/hashicorp/consul/agent/keyring.go:232.97,235.73 2 0 +github.com/hashicorp/consul/agent/keyring.go:239.2,239.20 1 0 +github.com/hashicorp/consul/agent/keyring.go:235.73,237.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:243.45,244.20 1 0 +github.com/hashicorp/consul/agent/keyring.go:247.2,247.22 1 0 +github.com/hashicorp/consul/agent/keyring.go:244.20,246.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:252.53,253.20 1 0 +github.com/hashicorp/consul/agent/keyring.go:256.2,256.12 1 0 +github.com/hashicorp/consul/agent/keyring.go:253.20,255.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:261.110,265.2 3 0 +github.com/hashicorp/consul/agent/keyring.go:268.101,272.2 3 0 +github.com/hashicorp/consul/agent/keyring.go:275.97,279.2 3 0 +github.com/hashicorp/consul/agent/keyring.go:282.100,286.2 3 0 +github.com/hashicorp/consul/agent/keyring.go:288.88,291.2 2 0 +github.com/hashicorp/consul/agent/keyring.go:295.72,297.16 2 0 +github.com/hashicorp/consul/agent/keyring.go:300.2,300.39 1 0 +github.com/hashicorp/consul/agent/keyring.go:305.2,305.13 1 0 +github.com/hashicorp/consul/agent/keyring.go:297.16,299.3 1 0 +github.com/hashicorp/consul/agent/keyring.go:300.39,301.26 1 0 +github.com/hashicorp/consul/agent/keyring.go:301.26,303.4 1 0 +github.com/hashicorp/consul/agent/service_manager.go:38.54,46.2 2 1 +github.com/hashicorp/consul/agent/service_manager.go:51.33,54.2 2 1 +github.com/hashicorp/consul/agent/service_manager.go:78.72,86.14 5 0 +github.com/hashicorp/consul/agent/service_manager.go:93.2,94.46 2 0 +github.com/hashicorp/consul/agent/service_manager.go:97.2,97.55 1 0 +github.com/hashicorp/consul/agent/service_manager.go:101.2,103.14 2 0 +github.com/hashicorp/consul/agent/service_manager.go:109.2,109.12 1 0 +github.com/hashicorp/consul/agent/service_manager.go:86.14,89.3 2 0 +github.com/hashicorp/consul/agent/service_manager.go:94.46,96.3 1 0 +github.com/hashicorp/consul/agent/service_manager.go:97.55,99.3 1 0 +github.com/hashicorp/consul/agent/service_manager.go:103.14,105.3 1 0 +github.com/hashicorp/consul/agent/service_manager.go:105.8,107.3 1 0 +github.com/hashicorp/consul/agent/service_manager.go:113.69,117.55 3 0 +github.com/hashicorp/consul/agent/service_manager.go:117.55,120.3 2 0 +github.com/hashicorp/consul/agent/service_manager.go:139.66,141.16 2 0 +github.com/hashicorp/consul/agent/service_manager.go:148.2,149.16 2 0 +github.com/hashicorp/consul/agent/service_manager.go:154.2,162.16 4 0 +github.com/hashicorp/consul/agent/service_manager.go:165.2,165.12 1 0 +github.com/hashicorp/consul/agent/service_manager.go:141.16,144.3 1 0 +github.com/hashicorp/consul/agent/service_manager.go:149.16,151.3 1 0 +github.com/hashicorp/consul/agent/service_manager.go:162.16,164.3 1 0 +github.com/hashicorp/consul/agent/service_manager.go:168.128,169.73 1 0 +github.com/hashicorp/consul/agent/service_manager.go:169.73,171.3 1 0 +github.com/hashicorp/consul/agent/service_manager.go:174.129,176.75 1 0 +github.com/hashicorp/consul/agent/service_manager.go:176.75,180.17 3 0 +github.com/hashicorp/consul/agent/service_manager.go:184.3,185.10 2 0 +github.com/hashicorp/consul/agent/service_manager.go:189.3,189.28 1 0 +github.com/hashicorp/consul/agent/service_manager.go:180.17,182.4 1 0 +github.com/hashicorp/consul/agent/service_manager.go:185.10,188.4 1 0 +github.com/hashicorp/consul/agent/service_manager.go:198.83,215.16 6 0 +github.com/hashicorp/consul/agent/service_manager.go:220.2,224.12 4 0 +github.com/hashicorp/consul/agent/service_manager.go:215.16,218.3 2 0 +github.com/hashicorp/consul/agent/service_manager.go:227.37,230.2 2 0 +github.com/hashicorp/consul/agent/service_manager.go:236.113,240.6 3 0 +github.com/hashicorp/consul/agent/service_manager.go:240.6,241.10 1 0 +github.com/hashicorp/consul/agent/service_manager.go:242.21,243.10 1 0 +github.com/hashicorp/consul/agent/service_manager.go:244.28,245.53 1 0 +github.com/hashicorp/consul/agent/service_manager.go:245.53,247.5 1 0 +github.com/hashicorp/consul/agent/service_manager.go:256.95,259.22 1 0 +github.com/hashicorp/consul/agent/service_manager.go:263.2,264.9 2 0 +github.com/hashicorp/consul/agent/service_manager.go:270.2,270.39 1 0 +github.com/hashicorp/consul/agent/service_manager.go:278.2,279.16 2 0 +github.com/hashicorp/consul/agent/service_manager.go:284.2,294.55 5 0 +github.com/hashicorp/consul/agent/service_manager.go:297.2,300.34 2 0 +github.com/hashicorp/consul/agent/service_manager.go:304.2,304.57 1 0 +github.com/hashicorp/consul/agent/service_manager.go:307.2,307.12 1 0 +github.com/hashicorp/consul/agent/service_manager.go:259.22,261.3 1 0 +github.com/hashicorp/consul/agent/service_manager.go:264.9,266.3 1 0 +github.com/hashicorp/consul/agent/service_manager.go:270.39,274.3 1 0 +github.com/hashicorp/consul/agent/service_manager.go:279.16,281.3 1 0 +github.com/hashicorp/consul/agent/service_manager.go:294.55,296.3 1 0 +github.com/hashicorp/consul/agent/service_manager.go:300.34,302.3 1 0 +github.com/hashicorp/consul/agent/service_manager.go:304.57,306.3 1 0 +github.com/hashicorp/consul/agent/service_manager.go:310.93,320.25 3 0 +github.com/hashicorp/consul/agent/service_manager.go:336.2,345.34 2 0 +github.com/hashicorp/consul/agent/service_manager.go:348.2,348.12 1 0 +github.com/hashicorp/consul/agent/service_manager.go:320.25,327.41 2 0 +github.com/hashicorp/consul/agent/service_manager.go:327.41,328.89 1 0 +github.com/hashicorp/consul/agent/service_manager.go:328.89,332.5 3 0 +github.com/hashicorp/consul/agent/service_manager.go:345.34,347.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:20.104,37.84 4 0 +github.com/hashicorp/consul/agent/session_endpoint.go:42.2,42.27 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:48.2,52.66 3 0 +github.com/hashicorp/consul/agent/session_endpoint.go:57.2,57.40 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:37.84,39.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:42.27,43.102 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:43.102,45.4 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:52.66,54.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:61.105,68.84 4 0 +github.com/hashicorp/consul/agent/session_endpoint.go:73.2,74.27 2 0 +github.com/hashicorp/consul/agent/session_endpoint.go:78.2,79.66 2 0 +github.com/hashicorp/consul/agent/session_endpoint.go:82.2,82.18 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:68.84,70.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:74.27,76.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:79.66,81.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:86.103,88.76 2 0 +github.com/hashicorp/consul/agent/session_endpoint.go:91.2,91.76 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:96.2,98.26 3 0 +github.com/hashicorp/consul/agent/session_endpoint.go:102.2,103.66 2 0 +github.com/hashicorp/consul/agent/session_endpoint.go:109.2,109.26 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:88.76,90.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:91.76,93.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:98.26,100.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:103.66,105.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:105.8,105.32 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:105.32,107.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:113.101,115.76 2 0 +github.com/hashicorp/consul/agent/session_endpoint.go:118.2,118.76 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:123.2,125.26 3 0 +github.com/hashicorp/consul/agent/session_endpoint.go:129.2,131.64 3 0 +github.com/hashicorp/consul/agent/session_endpoint.go:136.2,136.25 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:139.2,139.26 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:115.76,117.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:118.76,120.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:125.26,127.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:131.64,133.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:136.25,138.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:143.102,145.76 2 0 +github.com/hashicorp/consul/agent/session_endpoint.go:148.2,148.66 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:152.2,154.65 3 0 +github.com/hashicorp/consul/agent/session_endpoint.go:159.2,159.25 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:162.2,162.26 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:145.76,147.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:148.66,150.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:154.65,156.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:159.25,161.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:166.106,168.76 2 0 +github.com/hashicorp/consul/agent/session_endpoint.go:171.2,171.66 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:176.2,177.21 2 0 +github.com/hashicorp/consul/agent/session_endpoint.go:181.2,183.73 3 0 +github.com/hashicorp/consul/agent/session_endpoint.go:188.2,188.25 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:191.2,191.26 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:168.76,170.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:171.66,173.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:177.21,179.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:183.73,185.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:188.25,190.3 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:196.56,198.30 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:204.2,204.74 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:210.2,210.34 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:214.2,214.8 1 0 +github.com/hashicorp/consul/agent/session_endpoint.go:198.30,201.3 2 0 +github.com/hashicorp/consul/agent/session_endpoint.go:204.74,207.3 2 0 +github.com/hashicorp/consul/agent/session_endpoint.go:210.34,213.3 2 0 +github.com/hashicorp/consul/agent/config_endpoint.go:16.97,17.20 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:18.13,19.32 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:21.16,22.35 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:24.10,25.75 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:31.100,33.76 2 0 +github.com/hashicorp/consul/agent/config_endpoint.go:36.2,39.23 3 0 +github.com/hashicorp/consul/agent/config_endpoint.go:33.76,35.3 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:40.9,45.96 3 0 +github.com/hashicorp/consul/agent/config_endpoint.go:49.3,50.71 2 0 +github.com/hashicorp/consul/agent/config_endpoint.go:53.3,55.25 2 0 +github.com/hashicorp/consul/agent/config_endpoint.go:59.3,59.26 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:60.9,61.67 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:65.3,68.72 3 0 +github.com/hashicorp/consul/agent/config_endpoint.go:71.3,73.28 2 0 +github.com/hashicorp/consul/agent/config_endpoint.go:74.10,75.117 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:45.96,47.4 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:50.71,52.4 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:55.25,57.4 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:61.67,63.4 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:68.72,70.4 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:80.103,87.24 6 0 +github.com/hashicorp/consul/agent/config_endpoint.go:91.2,92.16 2 0 +github.com/hashicorp/consul/agent/config_endpoint.go:95.2,99.85 3 0 +github.com/hashicorp/consul/agent/config_endpoint.go:104.2,104.56 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:113.2,114.73 2 0 +github.com/hashicorp/consul/agent/config_endpoint.go:120.2,120.45 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:123.2,123.24 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:87.24,89.3 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:92.16,94.3 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:99.85,101.3 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:104.56,106.17 2 0 +github.com/hashicorp/consul/agent/config_endpoint.go:109.3,110.49 2 0 +github.com/hashicorp/consul/agent/config_endpoint.go:106.17,108.4 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:114.73,116.3 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:120.45,122.3 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:127.102,135.61 5 0 +github.com/hashicorp/consul/agent/config_endpoint.go:139.2,139.62 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:146.2,147.91 2 0 +github.com/hashicorp/consul/agent/config_endpoint.go:150.2,153.56 2 0 +github.com/hashicorp/consul/agent/config_endpoint.go:162.2,163.72 2 0 +github.com/hashicorp/consul/agent/config_endpoint.go:167.2,167.19 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:135.61,137.3 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:139.62,141.3 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:141.8,143.3 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:147.91,149.3 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:153.56,155.17 2 0 +github.com/hashicorp/consul/agent/config_endpoint.go:158.3,159.49 2 0 +github.com/hashicorp/consul/agent/config_endpoint.go:155.17,157.4 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:163.72,165.3 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:170.122,171.39 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:174.2,174.47 1 0 +github.com/hashicorp/consul/agent/config_endpoint.go:171.39,173.3 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:17.109,19.76 2 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:23.2,24.21 2 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:28.2,30.64 3 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:33.2,35.26 2 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:59.2,62.32 3 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:86.2,88.58 2 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:19.76,21.3 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:24.21,26.3 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:30.64,32.3 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:35.26,37.52 2 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:41.3,42.17 2 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:46.3,49.44 3 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:37.52,39.4 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:42.17,44.4 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:49.44,51.18 2 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:54.4,54.57 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:51.18,53.5 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:62.32,64.17 2 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:67.3,70.10 3 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:74.3,74.15 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:64.17,66.4 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:70.10,73.4 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:75.8,76.2 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:77.3,77.72 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:80.3,80.107 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:77.72,79.4 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:80.107,83.19 3 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:103.102,120.16 4 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:124.2,124.44 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:128.2,128.21 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:120.16,122.3 1 0 +github.com/hashicorp/consul/agent/discovery_chain_endpoint.go:124.44,126.3 1 0 +github.com/hashicorp/consul/agent/dns_oss.go:15.77,17.2 1 1 +github.com/hashicorp/consul/agent/dns_oss.go:22.90,23.21 1 0 +github.com/hashicorp/consul/agent/dns_oss.go:31.2,31.31 1 0 +github.com/hashicorp/consul/agent/dns_oss.go:24.9,25.58 1 0 +github.com/hashicorp/consul/agent/dns_oss.go:27.9,28.31 1 0 +github.com/hashicorp/consul/agent/dns_oss.go:34.99,36.2 1 0 +github.com/hashicorp/consul/agent/operator_endpoint_oss.go:11.88,13.2 0 0 +github.com/hashicorp/consul/agent/operator_endpoint_oss.go:15.90,19.2 1 0 +github.com/hashicorp/consul/agent/util.go:17.40,19.2 1 0 +github.com/hashicorp/consul/agent/util.go:22.48,24.2 1 0 +github.com/hashicorp/consul/agent/util.go:32.70,36.16 3 0 +github.com/hashicorp/consul/agent/util.go:50.2,50.17 1 0 +github.com/hashicorp/consul/agent/util.go:55.2,55.49 1 0 +github.com/hashicorp/consul/agent/util.go:60.2,60.16 1 0 +github.com/hashicorp/consul/agent/util.go:71.2,71.12 1 0 +github.com/hashicorp/consul/agent/util.go:36.16,37.48 1 0 +github.com/hashicorp/consul/agent/util.go:42.3,43.17 2 0 +github.com/hashicorp/consul/agent/util.go:46.3,46.31 1 0 +github.com/hashicorp/consul/agent/util.go:37.48,38.14 1 0 +github.com/hashicorp/consul/agent/util.go:43.17,45.4 1 0 +github.com/hashicorp/consul/agent/util.go:50.17,51.49 1 0 +github.com/hashicorp/consul/agent/util.go:51.49,53.4 1 0 +github.com/hashicorp/consul/agent/util.go:55.49,58.3 1 0 +github.com/hashicorp/consul/agent/util.go:60.16,62.17 2 0 +github.com/hashicorp/consul/agent/util.go:65.3,65.59 1 0 +github.com/hashicorp/consul/agent/util.go:62.17,64.4 1 0 +github.com/hashicorp/consul/agent/util.go:65.59,68.4 1 0 +github.com/hashicorp/consul/agent/util.go:76.83,77.12 1 0 +github.com/hashicorp/consul/agent/util.go:77.12,82.7 4 0 +github.com/hashicorp/consul/agent/util.go:82.7,83.11 1 0 +github.com/hashicorp/consul/agent/util.go:84.27,85.51 1 0 +github.com/hashicorp/consul/agent/util.go:89.22,90.11 1 0 +github.com/hashicorp/consul/agent/util.go:85.51,87.6 1 0 +github.com/hashicorp/consul/agent/util.go:98.55,100.31 2 0 +github.com/hashicorp/consul/agent/util.go:103.2,103.10 1 0 +github.com/hashicorp/consul/agent/util.go:100.31,102.3 1 0 +github.com/hashicorp/consul/agent/util.go:107.62,109.9 2 0 +github.com/hashicorp/consul/agent/util.go:112.2,112.31 1 0 +github.com/hashicorp/consul/agent/util.go:146.2,146.12 1 0 +github.com/hashicorp/consul/agent/util.go:109.9,111.3 1 0 +github.com/hashicorp/consul/agent/util.go:112.31,113.21 1 0 +github.com/hashicorp/consul/agent/util.go:114.31,115.48 1 0 +github.com/hashicorp/consul/agent/util.go:119.22,120.42 1 0 +github.com/hashicorp/consul/agent/util.go:126.33,127.53 1 0 +github.com/hashicorp/consul/agent/util.go:133.11,134.31 1 0 +github.com/hashicorp/consul/agent/util.go:115.48,117.5 1 0 +github.com/hashicorp/consul/agent/util.go:120.42,121.47 1 0 +github.com/hashicorp/consul/agent/util.go:121.47,123.6 1 0 +github.com/hashicorp/consul/agent/util.go:127.53,128.47 1 0 +github.com/hashicorp/consul/agent/util.go:128.47,130.6 1 0 +github.com/hashicorp/consul/agent/util.go:134.31,136.37 1 0 +github.com/hashicorp/consul/agent/util.go:136.37,138.20 2 0 +github.com/hashicorp/consul/agent/util.go:141.6,141.23 1 0 +github.com/hashicorp/consul/agent/util.go:138.20,140.7 1 0 +github.com/hashicorp/consul/agent/testagent.go:35.13,37.2 1 1 +github.com/hashicorp/consul/agent/testagent.go:98.56,100.19 2 0 +github.com/hashicorp/consul/agent/testagent.go:101.2,101.10 1 0 +github.com/hashicorp/consul/agent/testagent.go:100.19,100.35 1 0 +github.com/hashicorp/consul/agent/testagent.go:108.92,110.19 2 0 +github.com/hashicorp/consul/agent/testagent.go:111.2,111.10 1 0 +github.com/hashicorp/consul/agent/testagent.go:110.19,110.35 1 0 +github.com/hashicorp/consul/agent/testagent.go:119.59,121.56 2 1 +github.com/hashicorp/consul/agent/testagent.go:128.2,128.11 1 1 +github.com/hashicorp/consul/agent/testagent.go:121.56,123.36 2 1 +github.com/hashicorp/consul/agent/testagent.go:123.36,125.4 1 0 +github.com/hashicorp/consul/agent/testagent.go:131.42,153.2 1 1 +github.com/hashicorp/consul/agent/testagent.go:157.47,159.20 2 1 +github.com/hashicorp/consul/agent/testagent.go:163.2,164.16 2 1 +github.com/hashicorp/consul/agent/testagent.go:168.2,168.21 1 1 +github.com/hashicorp/consul/agent/testagent.go:174.2,178.22 4 1 +github.com/hashicorp/consul/agent/testagent.go:182.2,182.21 1 1 +github.com/hashicorp/consul/agent/testagent.go:186.2,197.66 4 1 +github.com/hashicorp/consul/agent/testagent.go:225.2,226.16 2 1 +github.com/hashicorp/consul/agent/testagent.go:230.2,232.40 2 1 +github.com/hashicorp/consul/agent/testagent.go:238.2,238.79 1 1 +github.com/hashicorp/consul/agent/testagent.go:241.2,243.27 2 1 +github.com/hashicorp/consul/agent/testagent.go:247.2,248.16 2 1 +github.com/hashicorp/consul/agent/testagent.go:252.2,253.58 2 1 +github.com/hashicorp/consul/agent/testagent.go:260.2,267.38 4 1 +github.com/hashicorp/consul/agent/testagent.go:273.2,274.12 2 1 +github.com/hashicorp/consul/agent/testagent.go:159.20,161.3 1 0 +github.com/hashicorp/consul/agent/testagent.go:164.16,166.3 1 1 +github.com/hashicorp/consul/agent/testagent.go:168.21,171.3 2 1 +github.com/hashicorp/consul/agent/testagent.go:178.22,180.3 1 1 +github.com/hashicorp/consul/agent/testagent.go:182.21,184.3 1 1 +github.com/hashicorp/consul/agent/testagent.go:197.66,212.34 3 1 +github.com/hashicorp/consul/agent/testagent.go:223.3,223.21 1 1 +github.com/hashicorp/consul/agent/testagent.go:212.34,214.68 1 1 +github.com/hashicorp/consul/agent/testagent.go:221.4,221.68 1 1 +github.com/hashicorp/consul/agent/testagent.go:214.68,216.5 1 1 +github.com/hashicorp/consul/agent/testagent.go:216.10,218.5 1 0 +github.com/hashicorp/consul/agent/testagent.go:226.16,228.3 1 0 +github.com/hashicorp/consul/agent/testagent.go:232.40,236.3 1 0 +github.com/hashicorp/consul/agent/testagent.go:238.79,240.3 1 0 +github.com/hashicorp/consul/agent/testagent.go:243.27,245.3 1 0 +github.com/hashicorp/consul/agent/testagent.go:248.16,250.3 1 0 +github.com/hashicorp/consul/agent/testagent.go:253.58,258.3 3 0 +github.com/hashicorp/consul/agent/testagent.go:267.38,271.3 3 0 +github.com/hashicorp/consul/agent/testagent.go:279.39,285.60 5 1 +github.com/hashicorp/consul/agent/testagent.go:328.2,328.58 1 0 +github.com/hashicorp/consul/agent/testagent.go:285.60,286.37 1 1 +github.com/hashicorp/consul/agent/testagent.go:290.3,290.48 1 1 +github.com/hashicorp/consul/agent/testagent.go:286.37,288.12 2 0 +github.com/hashicorp/consul/agent/testagent.go:290.48,299.65 2 1 +github.com/hashicorp/consul/agent/testagent.go:303.4,303.34 1 1 +github.com/hashicorp/consul/agent/testagent.go:307.4,307.22 1 1 +github.com/hashicorp/consul/agent/testagent.go:311.4,311.14 1 1 +github.com/hashicorp/consul/agent/testagent.go:299.65,301.13 2 0 +github.com/hashicorp/consul/agent/testagent.go:303.34,305.13 2 0 +github.com/hashicorp/consul/agent/testagent.go:307.22,309.13 2 0 +github.com/hashicorp/consul/agent/testagent.go:312.9,316.58 4 0 +github.com/hashicorp/consul/agent/testagent.go:324.4,324.14 1 0 +github.com/hashicorp/consul/agent/testagent.go:316.59,320.5 0 0 +github.com/hashicorp/consul/agent/testagent.go:320.10,320.45 1 0 +github.com/hashicorp/consul/agent/testagent.go:320.45,322.13 2 0 +github.com/hashicorp/consul/agent/testagent.go:333.38,334.20 1 1 +github.com/hashicorp/consul/agent/testagent.go:339.2,340.48 2 1 +github.com/hashicorp/consul/agent/testagent.go:343.2,344.12 2 1 +github.com/hashicorp/consul/agent/testagent.go:334.20,336.3 1 0 +github.com/hashicorp/consul/agent/testagent.go:340.48,342.3 1 0 +github.com/hashicorp/consul/agent/testagent.go:347.38,348.18 1 0 +github.com/hashicorp/consul/agent/testagent.go:351.2,351.19 1 0 +github.com/hashicorp/consul/agent/testagent.go:348.18,350.3 1 0 +github.com/hashicorp/consul/agent/testagent.go:354.39,356.16 2 0 +github.com/hashicorp/consul/agent/testagent.go:360.2,360.22 1 0 +github.com/hashicorp/consul/agent/testagent.go:356.16,358.37 1 0 +github.com/hashicorp/consul/agent/testagent.go:365.66,366.32 1 0 +github.com/hashicorp/consul/agent/testagent.go:371.2,371.75 1 0 +github.com/hashicorp/consul/agent/testagent.go:366.32,367.31 1 0 +github.com/hashicorp/consul/agent/testagent.go:367.31,369.4 1 0 +github.com/hashicorp/consul/agent/testagent.go:374.53,375.57 1 0 +github.com/hashicorp/consul/agent/testagent.go:378.2,378.11 1 0 +github.com/hashicorp/consul/agent/testagent.go:375.57,377.3 1 0 +github.com/hashicorp/consul/agent/testagent.go:381.42,385.16 4 0 +github.com/hashicorp/consul/agent/testagent.go:388.2,388.10 1 0 +github.com/hashicorp/consul/agent/testagent.go:385.16,386.66 1 0 +github.com/hashicorp/consul/agent/testagent.go:392.51,393.35 1 0 +github.com/hashicorp/consul/agent/testagent.go:393.35,396.3 2 0 +github.com/hashicorp/consul/agent/testagent.go:402.51,404.16 2 0 +github.com/hashicorp/consul/agent/testagent.go:407.2,407.10 1 0 +github.com/hashicorp/consul/agent/testagent.go:404.16,405.13 1 0 +github.com/hashicorp/consul/agent/testagent.go:418.60,422.14 3 1 +github.com/hashicorp/consul/agent/testagent.go:430.2,441.3 1 1 +github.com/hashicorp/consul/agent/testagent.go:422.14,425.3 2 0 +github.com/hashicorp/consul/agent/testagent.go:425.8,428.3 2 1 +github.com/hashicorp/consul/agent/testagent.go:444.22,446.16 2 1 +github.com/hashicorp/consul/agent/testagent.go:449.2,449.11 1 1 +github.com/hashicorp/consul/agent/testagent.go:446.16,447.13 1 0 +github.com/hashicorp/consul/agent/testagent.go:453.86,483.16 5 0 +github.com/hashicorp/consul/agent/testagent.go:486.2,486.31 1 0 +github.com/hashicorp/consul/agent/testagent.go:490.2,499.12 4 0 +github.com/hashicorp/consul/agent/testagent.go:483.16,484.46 1 0 +github.com/hashicorp/consul/agent/testagent.go:486.31,488.3 1 0 +github.com/hashicorp/consul/agent/testagent.go:504.29,519.2 1 0 +github.com/hashicorp/consul/agent/testagent.go:537.56,545.2 1 0 +github.com/hashicorp/consul/agent/testagent.go:547.58,553.2 1 0 +github.com/hashicorp/consul/agent/testagent.go:555.32,563.2 1 0 +github.com/hashicorp/consul/agent/testagent.go:597.66,601.19 3 0 +github.com/hashicorp/consul/agent/testagent.go:605.2,606.16 2 0 +github.com/hashicorp/consul/agent/testagent.go:610.2,610.21 1 0 +github.com/hashicorp/consul/agent/testagent.go:601.19,603.3 1 0 +github.com/hashicorp/consul/agent/testagent.go:606.16,607.68 1 0 +github.com/hashicorp/consul/agent/testagent.go:615.97,617.16 2 0 +github.com/hashicorp/consul/agent/testagent.go:621.2,622.16 2 0 +github.com/hashicorp/consul/agent/testagent.go:626.2,634.16 2 0 +github.com/hashicorp/consul/agent/testagent.go:638.2,638.34 1 0 +github.com/hashicorp/consul/agent/testagent.go:617.16,619.3 1 0 +github.com/hashicorp/consul/agent/testagent.go:622.16,624.3 1 0 +github.com/hashicorp/consul/agent/testagent.go:634.16,636.3 1 0 +github.com/hashicorp/consul/agent/http.go:52.47,54.2 1 0 +github.com/hashicorp/consul/agent/http.go:64.46,66.2 1 0 +github.com/hashicorp/consul/agent/http.go:75.35,77.2 1 0 +github.com/hashicorp/consul/agent/http.go:109.77,110.22 1 1 +github.com/hashicorp/consul/agent/http.go:113.2,113.65 1 1 +github.com/hashicorp/consul/agent/http.go:117.2,118.35 2 1 +github.com/hashicorp/consul/agent/http.go:110.22,112.3 1 1 +github.com/hashicorp/consul/agent/http.go:113.65,114.65 1 0 +github.com/hashicorp/consul/agent/http.go:128.77,130.2 1 0 +github.com/hashicorp/consul/agent/http.go:134.73,135.38 1 0 +github.com/hashicorp/consul/agent/http.go:140.2,140.12 1 0 +github.com/hashicorp/consul/agent/http.go:135.38,136.35 1 0 +github.com/hashicorp/consul/agent/http.go:136.35,138.4 1 0 +github.com/hashicorp/consul/agent/http.go:165.63,167.16 1 1 +github.com/hashicorp/consul/agent/http.go:171.2,175.70 2 1 +github.com/hashicorp/consul/agent/http.go:207.2,207.64 1 1 +github.com/hashicorp/consul/agent/http.go:233.2,234.37 2 1 +github.com/hashicorp/consul/agent/http.go:244.2,244.42 1 1 +github.com/hashicorp/consul/agent/http.go:252.2,252.21 1 1 +github.com/hashicorp/consul/agent/http.go:278.2,279.86 2 1 +github.com/hashicorp/consul/agent/http.go:287.2,288.53 2 1 +github.com/hashicorp/consul/agent/http.go:291.2,296.12 3 1 +github.com/hashicorp/consul/agent/http.go:167.16,169.3 1 0 +github.com/hashicorp/consul/agent/http.go:175.70,183.64 2 1 +github.com/hashicorp/consul/agent/http.go:191.3,193.78 3 1 +github.com/hashicorp/consul/agent/http.go:196.3,197.17 2 1 +github.com/hashicorp/consul/agent/http.go:202.3,202.35 1 1 +github.com/hashicorp/consul/agent/http.go:183.64,189.4 4 0 +github.com/hashicorp/consul/agent/http.go:193.78,195.4 1 1 +github.com/hashicorp/consul/agent/http.go:197.17,199.4 1 1 +github.com/hashicorp/consul/agent/http.go:199.9,201.4 1 0 +github.com/hashicorp/consul/agent/http.go:207.64,208.64 1 0 +github.com/hashicorp/consul/agent/http.go:231.3,231.56 1 0 +github.com/hashicorp/consul/agent/http.go:208.64,213.18 4 0 +github.com/hashicorp/consul/agent/http.go:222.4,222.44 1 0 +github.com/hashicorp/consul/agent/http.go:228.4,228.22 1 0 +github.com/hashicorp/consul/agent/http.go:213.18,216.5 2 0 +github.com/hashicorp/consul/agent/http.go:222.44,225.5 2 0 +github.com/hashicorp/consul/agent/http.go:234.37,237.83 3 1 +github.com/hashicorp/consul/agent/http.go:240.3,240.53 1 1 +github.com/hashicorp/consul/agent/http.go:237.83,239.4 1 0 +github.com/hashicorp/consul/agent/http.go:244.42,250.3 5 0 +github.com/hashicorp/consul/agent/http.go:252.21,276.3 5 0 +github.com/hashicorp/consul/agent/http.go:279.86,282.3 2 0 +github.com/hashicorp/consul/agent/http.go:288.53,290.3 1 0 +github.com/hashicorp/consul/agent/http.go:300.42,302.2 1 0 +github.com/hashicorp/consul/agent/http.go:328.82,330.59 2 1 +github.com/hashicorp/consul/agent/http.go:330.59,337.17 5 0 +github.com/hashicorp/consul/agent/http.go:345.3,346.42 2 0 +github.com/hashicorp/consul/agent/http.go:355.3,357.37 2 0 +github.com/hashicorp/consul/agent/http.go:370.3,370.39 1 0 +github.com/hashicorp/consul/agent/http.go:380.3,380.46 1 0 +github.com/hashicorp/consul/agent/http.go:385.3,385.45 1 0 +github.com/hashicorp/consul/agent/http.go:390.3,390.44 1 0 +github.com/hashicorp/consul/agent/http.go:394.3,394.39 1 0 +github.com/hashicorp/consul/agent/http.go:399.3,399.32 1 0 +github.com/hashicorp/consul/agent/http.go:449.3,450.16 2 0 +github.com/hashicorp/consul/agent/http.go:459.3,462.50 2 0 +github.com/hashicorp/consul/agent/http.go:468.3,469.34 2 0 +github.com/hashicorp/consul/agent/http.go:476.3,476.19 1 0 +github.com/hashicorp/consul/agent/http.go:497.3,499.17 3 0 +github.com/hashicorp/consul/agent/http.go:513.3,513.17 1 0 +github.com/hashicorp/consul/agent/http.go:516.3,517.40 2 0 +github.com/hashicorp/consul/agent/http.go:530.3,532.18 3 0 +github.com/hashicorp/consul/agent/http.go:337.17,344.4 3 0 +github.com/hashicorp/consul/agent/http.go:346.42,347.33 1 0 +github.com/hashicorp/consul/agent/http.go:347.33,348.20 1 0 +github.com/hashicorp/consul/agent/http.go:352.5,352.60 1 0 +github.com/hashicorp/consul/agent/http.go:348.20,350.14 2 0 +github.com/hashicorp/consul/agent/http.go:357.37,368.4 5 0 +github.com/hashicorp/consul/agent/http.go:370.39,371.64 1 0 +github.com/hashicorp/consul/agent/http.go:374.4,374.80 1 0 +github.com/hashicorp/consul/agent/http.go:377.4,377.16 1 0 +github.com/hashicorp/consul/agent/http.go:371.64,373.5 1 0 +github.com/hashicorp/consul/agent/http.go:374.80,376.5 1 0 +github.com/hashicorp/consul/agent/http.go:380.46,383.4 2 0 +github.com/hashicorp/consul/agent/http.go:385.45,388.4 1 0 +github.com/hashicorp/consul/agent/http.go:390.44,392.4 1 0 +github.com/hashicorp/consul/agent/http.go:394.39,397.4 2 0 +github.com/hashicorp/consul/agent/http.go:399.32,400.34 1 0 +github.com/hashicorp/consul/agent/http.go:414.4,414.11 1 0 +github.com/hashicorp/consul/agent/http.go:400.34,406.5 1 0 +github.com/hashicorp/consul/agent/http.go:406.10,412.5 1 0 +github.com/hashicorp/consul/agent/http.go:415.26,417.34 2 0 +github.com/hashicorp/consul/agent/http.go:418.43,419.49 1 0 +github.com/hashicorp/consul/agent/http.go:420.33,427.34 3 0 +github.com/hashicorp/consul/agent/http.go:428.26,431.28 3 0 +github.com/hashicorp/consul/agent/http.go:434.5,435.26 2 0 +github.com/hashicorp/consul/agent/http.go:438.5,439.29 2 0 +github.com/hashicorp/consul/agent/http.go:440.32,442.34 2 0 +github.com/hashicorp/consul/agent/http.go:443.12,445.34 2 0 +github.com/hashicorp/consul/agent/http.go:431.28,433.6 1 0 +github.com/hashicorp/consul/agent/http.go:435.26,437.6 1 0 +github.com/hashicorp/consul/agent/http.go:450.16,457.4 1 0 +github.com/hashicorp/consul/agent/http.go:462.50,465.4 2 0 +github.com/hashicorp/consul/agent/http.go:469.34,470.28 1 0 +github.com/hashicorp/consul/agent/http.go:470.28,472.10 2 0 +github.com/hashicorp/consul/agent/http.go:476.19,478.4 1 0 +github.com/hashicorp/consul/agent/http.go:478.9,483.36 2 0 +github.com/hashicorp/consul/agent/http.go:492.4,492.18 1 0 +github.com/hashicorp/consul/agent/http.go:483.36,484.30 1 0 +github.com/hashicorp/consul/agent/http.go:484.30,489.6 1 0 +github.com/hashicorp/consul/agent/http.go:492.18,495.5 1 0 +github.com/hashicorp/consul/agent/http.go:499.17,500.56 1 0 +github.com/hashicorp/consul/agent/http.go:500.56,502.37 2 0 +github.com/hashicorp/consul/agent/http.go:505.5,505.32 1 0 +github.com/hashicorp/consul/agent/http.go:502.37,504.6 1 0 +github.com/hashicorp/consul/agent/http.go:505.32,507.6 1 0 +github.com/hashicorp/consul/agent/http.go:508.10,511.5 2 0 +github.com/hashicorp/consul/agent/http.go:513.17,515.4 1 0 +github.com/hashicorp/consul/agent/http.go:517.40,519.18 2 0 +github.com/hashicorp/consul/agent/http.go:519.18,522.5 2 0 +github.com/hashicorp/consul/agent/http.go:523.9,524.47 1 0 +github.com/hashicorp/consul/agent/http.go:524.47,525.36 1 0 +github.com/hashicorp/consul/agent/http.go:525.36,527.6 1 0 +github.com/hashicorp/consul/agent/http.go:538.88,539.70 1 0 +github.com/hashicorp/consul/agent/http.go:548.2,549.16 2 0 +github.com/hashicorp/consul/agent/http.go:552.2,552.17 1 0 +github.com/hashicorp/consul/agent/http.go:539.70,541.17 2 0 +github.com/hashicorp/consul/agent/http.go:544.3,545.18 2 0 +github.com/hashicorp/consul/agent/http.go:541.17,543.4 1 0 +github.com/hashicorp/consul/agent/http.go:549.16,551.3 1 0 +github.com/hashicorp/consul/agent/http.go:556.43,560.2 1 1 +github.com/hashicorp/consul/agent/http.go:563.75,569.25 2 0 +github.com/hashicorp/consul/agent/http.go:582.2,582.22 1 0 +github.com/hashicorp/consul/agent/http.go:588.2,593.3 1 0 +github.com/hashicorp/consul/agent/http.go:569.25,572.45 2 0 +github.com/hashicorp/consul/agent/http.go:577.3,577.9 1 0 +github.com/hashicorp/consul/agent/http.go:572.45,574.4 1 0 +github.com/hashicorp/consul/agent/http.go:574.9,576.4 1 0 +github.com/hashicorp/consul/agent/http.go:582.22,585.3 2 0 +github.com/hashicorp/consul/agent/http.go:596.56,598.2 1 0 +github.com/hashicorp/consul/agent/http.go:602.97,606.21 1 0 +github.com/hashicorp/consul/agent/http.go:610.2,612.41 3 0 +github.com/hashicorp/consul/agent/http.go:617.2,617.15 1 0 +github.com/hashicorp/consul/agent/http.go:623.2,633.16 3 0 +github.com/hashicorp/consul/agent/http.go:637.2,637.28 1 0 +github.com/hashicorp/consul/agent/http.go:606.21,608.3 1 0 +github.com/hashicorp/consul/agent/http.go:612.41,614.3 1 0 +github.com/hashicorp/consul/agent/http.go:617.15,618.33 1 0 +github.com/hashicorp/consul/agent/http.go:618.33,620.4 1 0 +github.com/hashicorp/consul/agent/http.go:633.16,635.3 1 0 +github.com/hashicorp/consul/agent/http.go:642.65,646.42 1 0 +github.com/hashicorp/consul/agent/http.go:646.42,648.29 2 0 +github.com/hashicorp/consul/agent/http.go:652.3,652.10 1 0 +github.com/hashicorp/consul/agent/http.go:648.29,650.4 1 0 +github.com/hashicorp/consul/agent/http.go:653.35,654.65 1 0 +github.com/hashicorp/consul/agent/http.go:659.4,659.17 1 0 +github.com/hashicorp/consul/agent/http.go:660.11,661.20 1 0 +github.com/hashicorp/consul/agent/http.go:654.65,656.5 1 0 +github.com/hashicorp/consul/agent/http.go:656.10,658.5 1 0 +github.com/hashicorp/consul/agent/http.go:668.62,669.12 1 0 +github.com/hashicorp/consul/agent/http.go:669.12,671.3 1 0 +github.com/hashicorp/consul/agent/http.go:675.55,681.16 1 0 +github.com/hashicorp/consul/agent/http.go:684.2,684.68 1 0 +github.com/hashicorp/consul/agent/http.go:681.16,683.3 1 0 +github.com/hashicorp/consul/agent/http.go:688.59,690.12 2 0 +github.com/hashicorp/consul/agent/http.go:693.2,693.46 1 0 +github.com/hashicorp/consul/agent/http.go:690.12,692.3 1 0 +github.com/hashicorp/consul/agent/http.go:696.67,697.23 1 0 +github.com/hashicorp/consul/agent/http.go:697.23,699.3 1 0 +github.com/hashicorp/consul/agent/http.go:702.77,703.28 1 0 +github.com/hashicorp/consul/agent/http.go:703.28,705.3 1 0 +github.com/hashicorp/consul/agent/http.go:709.67,710.14 1 0 +github.com/hashicorp/consul/agent/http.go:713.2,714.77 2 0 +github.com/hashicorp/consul/agent/http.go:710.14,712.3 1 0 +github.com/hashicorp/consul/agent/http.go:718.68,720.16 2 0 +github.com/hashicorp/consul/agent/http.go:723.2,729.12 7 0 +github.com/hashicorp/consul/agent/http.go:720.16,722.3 1 0 +github.com/hashicorp/consul/agent/http.go:732.78,733.36 1 0 +github.com/hashicorp/consul/agent/http.go:733.36,735.3 1 0 +github.com/hashicorp/consul/agent/http.go:739.66,740.14 1 0 +github.com/hashicorp/consul/agent/http.go:743.2,744.11 2 0 +github.com/hashicorp/consul/agent/http.go:747.2,748.11 2 0 +github.com/hashicorp/consul/agent/http.go:740.14,742.3 1 0 +github.com/hashicorp/consul/agent/http.go:744.11,746.3 1 0 +github.com/hashicorp/consul/agent/http.go:748.11,750.3 1 0 +github.com/hashicorp/consul/agent/http.go:757.72,758.14 1 0 +github.com/hashicorp/consul/agent/http.go:758.14,760.3 1 0 +github.com/hashicorp/consul/agent/http.go:764.70,765.36 1 0 +github.com/hashicorp/consul/agent/http.go:765.36,767.3 1 0 +github.com/hashicorp/consul/agent/http.go:771.90,772.59 1 0 +github.com/hashicorp/consul/agent/http.go:772.59,775.3 2 0 +github.com/hashicorp/consul/agent/http.go:780.88,782.43 2 0 +github.com/hashicorp/consul/agent/http.go:791.2,791.42 1 0 +github.com/hashicorp/consul/agent/http.go:800.2,800.14 1 0 +github.com/hashicorp/consul/agent/http.go:782.43,784.17 2 0 +github.com/hashicorp/consul/agent/http.go:789.3,789.25 1 0 +github.com/hashicorp/consul/agent/http.go:784.17,788.4 3 0 +github.com/hashicorp/consul/agent/http.go:791.42,793.17 2 0 +github.com/hashicorp/consul/agent/http.go:798.3,798.28 1 0 +github.com/hashicorp/consul/agent/http.go:793.17,797.4 3 0 +github.com/hashicorp/consul/agent/http.go:805.96,808.15 2 0 +github.com/hashicorp/consul/agent/http.go:817.2,819.64 2 0 +github.com/hashicorp/consul/agent/http.go:829.2,829.31 1 0 +github.com/hashicorp/consul/agent/http.go:858.2,858.14 1 0 +github.com/hashicorp/consul/agent/http.go:808.15,810.3 1 0 +github.com/hashicorp/consul/agent/http.go:819.64,821.17 2 0 +github.com/hashicorp/consul/agent/http.go:826.3,826.47 1 0 +github.com/hashicorp/consul/agent/http.go:821.17,825.4 3 0 +github.com/hashicorp/consul/agent/http.go:829.31,832.29 2 0 +github.com/hashicorp/consul/agent/http.go:836.3,836.39 1 0 +github.com/hashicorp/consul/agent/http.go:849.3,849.46 1 0 +github.com/hashicorp/consul/agent/http.go:832.29,834.4 1 0 +github.com/hashicorp/consul/agent/http.go:836.39,838.14 2 0 +github.com/hashicorp/consul/agent/http.go:841.4,842.14 2 0 +github.com/hashicorp/consul/agent/http.go:838.14,840.5 1 0 +github.com/hashicorp/consul/agent/http.go:842.14,847.5 1 0 +github.com/hashicorp/consul/agent/http.go:849.46,851.14 2 0 +github.com/hashicorp/consul/agent/http.go:854.4,854.24 1 0 +github.com/hashicorp/consul/agent/http.go:851.14,853.5 1 0 +github.com/hashicorp/consul/agent/http.go:863.113,866.33 3 0 +github.com/hashicorp/consul/agent/http.go:870.2,870.38 1 0 +github.com/hashicorp/consul/agent/http.go:874.2,874.34 1 0 +github.com/hashicorp/consul/agent/http.go:880.2,880.65 1 0 +github.com/hashicorp/consul/agent/http.go:884.2,884.56 1 0 +github.com/hashicorp/consul/agent/http.go:898.2,898.14 1 0 +github.com/hashicorp/consul/agent/http.go:907.2,907.51 1 0 +github.com/hashicorp/consul/agent/http.go:912.2,912.49 1 0 +github.com/hashicorp/consul/agent/http.go:917.2,917.14 1 0 +github.com/hashicorp/consul/agent/http.go:866.33,869.3 2 0 +github.com/hashicorp/consul/agent/http.go:870.38,873.3 2 0 +github.com/hashicorp/consul/agent/http.go:874.34,879.3 1 0 +github.com/hashicorp/consul/agent/http.go:880.65,883.3 2 0 +github.com/hashicorp/consul/agent/http.go:884.56,886.17 2 0 +github.com/hashicorp/consul/agent/http.go:891.3,892.28 2 0 +github.com/hashicorp/consul/agent/http.go:886.17,890.4 3 0 +github.com/hashicorp/consul/agent/http.go:892.28,895.4 2 0 +github.com/hashicorp/consul/agent/http.go:898.14,900.86 2 0 +github.com/hashicorp/consul/agent/http.go:900.86,901.58 1 0 +github.com/hashicorp/consul/agent/http.go:901.58,904.5 2 0 +github.com/hashicorp/consul/agent/http.go:907.51,911.3 3 0 +github.com/hashicorp/consul/agent/http.go:912.49,916.3 3 0 +github.com/hashicorp/consul/agent/http.go:921.104,923.38 2 0 +github.com/hashicorp/consul/agent/http.go:923.38,925.3 1 0 +github.com/hashicorp/consul/agent/http.go:929.63,930.53 1 0 +github.com/hashicorp/consul/agent/http.go:930.53,932.3 1 0 +github.com/hashicorp/consul/agent/http.go:932.8,932.22 1 0 +github.com/hashicorp/consul/agent/http.go:932.22,934.3 1 0 +github.com/hashicorp/consul/agent/http.go:939.77,940.56 1 1 +github.com/hashicorp/consul/agent/http.go:945.2,945.51 1 1 +github.com/hashicorp/consul/agent/http.go:949.2,950.8 2 1 +github.com/hashicorp/consul/agent/http.go:940.56,943.3 2 0 +github.com/hashicorp/consul/agent/http.go:945.51,947.3 1 0 +github.com/hashicorp/consul/agent/http.go:953.85,954.60 1 1 +github.com/hashicorp/consul/agent/http.go:959.2,959.59 1 1 +github.com/hashicorp/consul/agent/http.go:981.2,981.14 1 1 +github.com/hashicorp/consul/agent/http.go:954.60,957.3 2 0 +github.com/hashicorp/consul/agent/http.go:959.59,966.21 2 0 +github.com/hashicorp/consul/agent/http.go:966.21,972.43 3 0 +github.com/hashicorp/consul/agent/http.go:972.43,977.5 2 0 +github.com/hashicorp/consul/agent/http.go:984.65,987.2 2 0 +github.com/hashicorp/consul/agent/http.go:992.80,994.34 2 1 +github.com/hashicorp/consul/agent/http.go:998.2,998.8 1 0 +github.com/hashicorp/consul/agent/http.go:994.34,997.3 2 1 +github.com/hashicorp/consul/agent/http.go:1003.69,1005.2 1 1 +github.com/hashicorp/consul/agent/http.go:1007.54,1010.27 3 0 +github.com/hashicorp/consul/agent/http.go:1017.2,1018.16 2 0 +github.com/hashicorp/consul/agent/http.go:1022.2,1023.15 2 0 +github.com/hashicorp/consul/agent/http.go:1010.27,1012.23 2 0 +github.com/hashicorp/consul/agent/http.go:1012.23,1014.4 1 0 +github.com/hashicorp/consul/agent/http.go:1018.16,1020.3 1 0 +github.com/hashicorp/consul/agent/http.go:1023.15,1025.3 1 0 +github.com/hashicorp/consul/agent/http.go:1025.8,1027.3 1 0 +github.com/hashicorp/consul/agent/http.go:1033.84,1036.53 3 0 +github.com/hashicorp/consul/agent/http.go:1036.53,1037.23 1 0 +github.com/hashicorp/consul/agent/http.go:1042.3,1042.59 1 0 +github.com/hashicorp/consul/agent/http.go:1037.23,1039.4 1 0 +github.com/hashicorp/consul/agent/http.go:1039.9,1041.4 1 0 +github.com/hashicorp/consul/agent/http.go:1046.95,1047.53 1 0 +github.com/hashicorp/consul/agent/http.go:1047.53,1049.3 1 0 +github.com/hashicorp/consul/agent/http.go:1054.77,1055.56 1 0 +github.com/hashicorp/consul/agent/http.go:1063.2,1063.12 1 0 +github.com/hashicorp/consul/agent/http.go:1055.56,1057.37 2 0 +github.com/hashicorp/consul/agent/http.go:1061.3,1061.17 1 0 +github.com/hashicorp/consul/agent/http.go:1057.37,1060.4 2 0 +github.com/hashicorp/consul/agent/http.go:1066.49,1068.20 2 0 +github.com/hashicorp/consul/agent/http.go:1071.2,1071.20 1 0 +github.com/hashicorp/consul/agent/http.go:1068.20,1070.3 1 0 +github.com/hashicorp/consul/agent/http.go:1076.114,1084.38 8 0 +github.com/hashicorp/consul/agent/http.go:1087.2,1087.37 1 0 +github.com/hashicorp/consul/agent/http.go:1090.2,1090.32 1 0 +github.com/hashicorp/consul/agent/http.go:1084.38,1086.3 1 0 +github.com/hashicorp/consul/agent/http.go:1087.37,1089.3 1 0 +github.com/hashicorp/consul/agent/http.go:1093.66,1094.103 1 0 +github.com/hashicorp/consul/agent/http.go:1098.2,1099.23 2 0 +github.com/hashicorp/consul/agent/http.go:1103.2,1104.16 2 0 +github.com/hashicorp/consul/agent/http.go:1108.2,1110.28 2 0 +github.com/hashicorp/consul/agent/http.go:1116.2,1116.84 1 0 +github.com/hashicorp/consul/agent/http.go:1094.103,1096.3 1 0 +github.com/hashicorp/consul/agent/http.go:1099.23,1101.3 1 0 +github.com/hashicorp/consul/agent/http.go:1104.16,1106.3 1 0 +github.com/hashicorp/consul/agent/http.go:1110.28,1111.21 1 0 +github.com/hashicorp/consul/agent/http.go:1111.21,1113.4 1 0 +github.com/hashicorp/consul/agent/http.go:1119.71,1120.57 1 0 +github.com/hashicorp/consul/agent/http.go:1120.57,1122.3 1 0 +github.com/hashicorp/consul/agent/http.go:1125.79,1129.2 3 0 +github.com/hashicorp/consul/agent/setup.go:56.119,59.16 3 1 +github.com/hashicorp/consul/agent/setup.go:62.2,67.27 5 1 +github.com/hashicorp/consul/agent/setup.go:76.2,76.28 1 1 +github.com/hashicorp/consul/agent/setup.go:80.2,80.36 1 1 +github.com/hashicorp/consul/agent/setup.go:84.2,85.16 2 1 +github.com/hashicorp/consul/agent/setup.go:89.2,96.16 7 1 +github.com/hashicorp/consul/agent/setup.go:100.2,101.16 2 1 +github.com/hashicorp/consul/agent/setup.go:105.2,137.16 13 1 +github.com/hashicorp/consul/agent/setup.go:141.2,153.16 3 1 +github.com/hashicorp/consul/agent/setup.go:157.2,163.26 5 1 +github.com/hashicorp/consul/agent/setup.go:170.2,170.15 1 1 +github.com/hashicorp/consul/agent/setup.go:59.16,61.3 1 0 +github.com/hashicorp/consul/agent/setup.go:67.27,69.3 1 1 +github.com/hashicorp/consul/agent/setup.go:69.8,71.17 2 0 +github.com/hashicorp/consul/agent/setup.go:71.17,73.4 1 0 +github.com/hashicorp/consul/agent/setup.go:76.28,78.3 1 1 +github.com/hashicorp/consul/agent/setup.go:80.36,82.3 1 1 +github.com/hashicorp/consul/agent/setup.go:85.16,87.3 1 0 +github.com/hashicorp/consul/agent/setup.go:96.16,98.3 1 0 +github.com/hashicorp/consul/agent/setup.go:101.16,103.3 1 0 +github.com/hashicorp/consul/agent/setup.go:137.16,139.3 1 0 +github.com/hashicorp/consul/agent/setup.go:153.16,155.3 1 0 +github.com/hashicorp/consul/agent/setup.go:163.26,165.17 2 0 +github.com/hashicorp/consul/agent/setup.go:165.17,167.4 1 0 +github.com/hashicorp/consul/agent/setup.go:177.111,179.39 2 1 +github.com/hashicorp/consul/agent/setup.go:183.2,193.23 3 1 +github.com/hashicorp/consul/agent/setup.go:206.2,206.13 1 1 +github.com/hashicorp/consul/agent/setup.go:179.39,181.3 1 1 +github.com/hashicorp/consul/agent/setup.go:193.23,196.3 2 1 +github.com/hashicorp/consul/agent/setup.go:196.8,205.3 2 0 +github.com/hashicorp/consul/agent/setup.go:211.159,248.14 4 1 +github.com/hashicorp/consul/agent/setup.go:259.2,260.27 2 1 +github.com/hashicorp/consul/agent/setup.go:271.2,303.29 4 1 +github.com/hashicorp/consul/agent/setup.go:313.2,357.30 4 1 +github.com/hashicorp/consul/agent/setup.go:367.2,367.44 1 1 +github.com/hashicorp/consul/agent/setup.go:248.14,255.3 1 1 +github.com/hashicorp/consul/agent/setup.go:260.27,264.27 2 1 +github.com/hashicorp/consul/agent/setup.go:268.3,268.48 1 1 +github.com/hashicorp/consul/agent/setup.go:264.27,267.4 2 1 +github.com/hashicorp/consul/agent/setup.go:303.29,306.29 2 1 +github.com/hashicorp/consul/agent/setup.go:310.3,310.52 1 1 +github.com/hashicorp/consul/agent/setup.go:306.29,309.4 2 1 +github.com/hashicorp/consul/agent/setup.go:357.30,360.29 2 1 +github.com/hashicorp/consul/agent/setup.go:364.3,364.52 1 1 +github.com/hashicorp/consul/agent/setup.go:360.29,363.4 2 1 +github.com/hashicorp/consul/agent/health_endpoint.go:19.110,22.66 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:25.2,27.76 3 0 +github.com/hashicorp/consul/agent/health_endpoint.go:32.2,33.22 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:38.2,40.1 3 0 +github.com/hashicorp/consul/agent/health_endpoint.go:41.2,41.73 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:44.2,44.106 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:49.2,52.29 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:55.2,55.37 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:62.2,62.30 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:22.66,24.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:27.76,29.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:33.22,35.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:41.73,43.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:44.106,47.18 3 0 +github.com/hashicorp/consul/agent/health_endpoint.go:52.29,54.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:55.37,56.27 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:56.27,60.4 3 0 +github.com/hashicorp/consul/agent/health_endpoint.go:65.107,68.66 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:71.2,71.76 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:76.2,77.21 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:82.2,84.1 3 0 +github.com/hashicorp/consul/agent/health_endpoint.go:85.2,85.70 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:88.2,88.106 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:93.2,96.29 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:99.2,99.37 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:106.2,106.30 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:68.66,70.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:71.76,73.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:77.21,79.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:85.70,87.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:88.106,91.18 3 0 +github.com/hashicorp/consul/agent/health_endpoint.go:96.29,98.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:99.37,100.27 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:100.27,104.4 3 0 +github.com/hashicorp/consul/agent/health_endpoint.go:109.110,112.76 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:115.2,117.76 3 0 +github.com/hashicorp/consul/agent/health_endpoint.go:122.2,123.28 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:128.2,130.1 3 0 +github.com/hashicorp/consul/agent/health_endpoint.go:131.2,131.73 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:134.2,134.106 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:139.2,142.29 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:145.2,145.37 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:152.2,152.30 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:112.76,114.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:117.76,119.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:123.28,125.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:131.73,133.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:134.106,137.18 3 0 +github.com/hashicorp/consul/agent/health_endpoint.go:142.29,144.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:145.37,146.27 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:146.27,150.4 3 0 +github.com/hashicorp/consul/agent/health_endpoint.go:157.116,159.2 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:164.116,166.2 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:170.109,172.2 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:174.128,177.76 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:180.2,182.76 3 0 +github.com/hashicorp/consul/agent/health_endpoint.go:186.2,190.32 3 0 +github.com/hashicorp/consul/agent/health_endpoint.go:195.2,195.49 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:200.2,201.20 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:214.2,215.28 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:219.2,220.16 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:224.2,224.32 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:227.2,233.16 4 0 +github.com/hashicorp/consul/agent/health_endpoint.go:238.2,238.12 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:243.2,246.22 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:249.2,249.27 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:266.2,266.23 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:177.76,179.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:182.76,184.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:190.32,193.3 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:195.49,197.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:202.21,204.22 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:205.21,207.22 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:208.10,210.33 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:215.28,217.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:220.16,222.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:224.32,226.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:233.16,235.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:238.12,240.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:246.22,248.3 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:249.27,250.33 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:253.3,253.41 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:260.3,260.70 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:250.33,252.4 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:253.41,254.28 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:254.28,258.5 3 0 +github.com/hashicorp/consul/agent/health_endpoint.go:260.70,264.4 3 0 +github.com/hashicorp/consul/agent/health_endpoint.go:269.69,271.30 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:287.2,287.19 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:271.30,277.16 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:277.16,279.4 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:279.9,282.18 3 0 +github.com/hashicorp/consul/agent/health_endpoint.go:282.18,284.5 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:291.82,298.25 3 0 +github.com/hashicorp/consul/agent/health_endpoint.go:309.2,309.16 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:298.25,300.37 2 0 +github.com/hashicorp/consul/agent/health_endpoint.go:300.37,301.41 1 0 +github.com/hashicorp/consul/agent/health_endpoint.go:301.41,305.19 4 0 +github.com/hashicorp/consul/agent/acl.go:18.55,20.28 2 0 +github.com/hashicorp/consul/agent/acl.go:23.2,23.16 1 0 +github.com/hashicorp/consul/agent/acl.go:27.2,27.27 1 0 +github.com/hashicorp/consul/agent/acl.go:20.28,22.3 1 0 +github.com/hashicorp/consul/agent/acl.go:23.16,26.3 2 0 +github.com/hashicorp/consul/agent/acl.go:32.86,35.16 2 0 +github.com/hashicorp/consul/agent/acl.go:39.2,39.59 1 0 +github.com/hashicorp/consul/agent/acl.go:35.16,37.3 1 0 +github.com/hashicorp/consul/agent/acl.go:42.108,47.102 3 0 +github.com/hashicorp/consul/agent/acl.go:52.2,52.79 1 0 +github.com/hashicorp/consul/agent/acl.go:61.2,61.53 1 0 +github.com/hashicorp/consul/agent/acl.go:68.2,68.12 1 0 +github.com/hashicorp/consul/agent/acl.go:47.102,49.3 1 0 +github.com/hashicorp/consul/agent/acl.go:52.79,54.104 2 0 +github.com/hashicorp/consul/agent/acl.go:54.104,56.4 1 0 +github.com/hashicorp/consul/agent/acl.go:61.53,63.124 2 0 +github.com/hashicorp/consul/agent/acl.go:63.124,65.4 1 0 +github.com/hashicorp/consul/agent/acl.go:71.105,75.61 2 0 +github.com/hashicorp/consul/agent/acl.go:92.2,92.12 1 0 +github.com/hashicorp/consul/agent/acl.go:75.61,77.104 2 0 +github.com/hashicorp/consul/agent/acl.go:77.104,80.4 1 0 +github.com/hashicorp/consul/agent/acl.go:81.8,90.3 1 0 +github.com/hashicorp/consul/agent/acl.go:95.104,100.32 3 0 +github.com/hashicorp/consul/agent/acl.go:112.2,112.73 1 0 +github.com/hashicorp/consul/agent/acl.go:126.2,126.12 1 0 +github.com/hashicorp/consul/agent/acl.go:100.32,101.105 1 0 +github.com/hashicorp/consul/agent/acl.go:101.105,103.4 1 0 +github.com/hashicorp/consul/agent/acl.go:104.8,106.102 1 0 +github.com/hashicorp/consul/agent/acl.go:106.102,108.4 1 0 +github.com/hashicorp/consul/agent/acl.go:112.73,113.36 1 0 +github.com/hashicorp/consul/agent/acl.go:113.36,115.109 1 0 +github.com/hashicorp/consul/agent/acl.go:115.109,117.5 1 0 +github.com/hashicorp/consul/agent/acl.go:118.9,120.103 1 0 +github.com/hashicorp/consul/agent/acl.go:120.103,122.5 1 0 +github.com/hashicorp/consul/agent/acl.go:129.99,134.57 3 0 +github.com/hashicorp/consul/agent/acl.go:151.2,151.12 1 0 +github.com/hashicorp/consul/agent/acl.go:134.57,135.36 1 0 +github.com/hashicorp/consul/agent/acl.go:135.36,136.109 1 0 +github.com/hashicorp/consul/agent/acl.go:136.109,138.5 1 0 +github.com/hashicorp/consul/agent/acl.go:139.9,140.103 1 0 +github.com/hashicorp/consul/agent/acl.go:140.103,142.5 1 0 +github.com/hashicorp/consul/agent/acl.go:144.8,149.3 1 0 +github.com/hashicorp/consul/agent/acl.go:155.75,158.16 2 0 +github.com/hashicorp/consul/agent/acl.go:162.2,165.30 3 0 +github.com/hashicorp/consul/agent/acl.go:176.2,177.12 2 0 +github.com/hashicorp/consul/agent/acl.go:158.16,160.3 1 0 +github.com/hashicorp/consul/agent/acl.go:165.30,168.55 3 0 +github.com/hashicorp/consul/agent/acl.go:171.3,174.6 4 0 +github.com/hashicorp/consul/agent/acl.go:168.55,169.12 1 0 +github.com/hashicorp/consul/agent/acl.go:180.113,183.36 2 0 +github.com/hashicorp/consul/agent/acl.go:191.2,191.12 1 0 +github.com/hashicorp/consul/agent/acl.go:183.36,185.69 2 0 +github.com/hashicorp/consul/agent/acl.go:188.3,189.23 2 0 +github.com/hashicorp/consul/agent/acl.go:185.69,186.12 1 0 +github.com/hashicorp/consul/agent/acl.go:194.119,197.32 2 0 +github.com/hashicorp/consul/agent/acl.go:211.2,211.12 1 0 +github.com/hashicorp/consul/agent/acl.go:197.32,199.33 2 0 +github.com/hashicorp/consul/agent/acl.go:208.3,209.21 2 0 +github.com/hashicorp/consul/agent/acl.go:199.33,200.72 1 0 +github.com/hashicorp/consul/agent/acl.go:200.72,201.13 1 0 +github.com/hashicorp/consul/agent/acl.go:203.9,204.69 1 0 +github.com/hashicorp/consul/agent/acl.go:204.69,205.13 1 0 +github.com/hashicorp/consul/agent/http_register.go:3.13,135.2 127 1 +github.com/hashicorp/consul/agent/connect_auth.go:32.102,36.72 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:40.2,40.16 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:45.2,45.22 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:50.2,51.16 2 0 +github.com/hashicorp/consul/agent/connect_auth.go:55.2,56.9 2 0 +github.com/hashicorp/consul/agent/connect_auth.go:63.2,65.16 3 0 +github.com/hashicorp/consul/agent/connect_auth.go:69.2,69.97 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:73.2,73.57 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:86.2,102.16 3 0 +github.com/hashicorp/consul/agent/connect_auth.go:106.2,107.9 2 0 +github.com/hashicorp/consul/agent/connect_auth.go:110.2,110.29 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:115.2,116.39 2 0 +github.com/hashicorp/consul/agent/connect_auth.go:125.2,125.21 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:138.2,139.74 2 0 +github.com/hashicorp/consul/agent/connect_auth.go:36.72,38.3 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:40.16,42.3 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:45.22,47.3 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:51.16,53.3 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:56.9,58.3 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:65.16,67.3 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:69.97,71.3 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:73.57,78.3 2 0 +github.com/hashicorp/consul/agent/connect_auth.go:102.16,104.3 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:107.9,109.3 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:110.29,112.3 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:116.39,119.107 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:119.107,121.9 2 0 +github.com/hashicorp/consul/agent/connect_auth.go:125.21,126.37 1 0 +github.com/hashicorp/consul/agent/connect_auth.go:134.3,135.35 2 0 +github.com/hashicorp/consul/agent/connect_auth.go:126.37,131.4 3 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:13.105,15.76 2 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:19.2,20.60 2 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:28.2,30.70 3 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:34.2,34.18 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:39.2,41.35 2 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:51.2,51.17 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:15.76,17.3 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:20.60,22.17 2 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:25.3,25.20 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:22.17,24.4 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:30.70,32.3 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:34.18,36.3 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:41.35,42.62 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:45.3,45.55 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:42.62,44.4 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:45.55,46.62 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:46.62,48.5 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:55.113,56.20 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:57.13,58.48 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:60.13,61.42 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:63.10,64.73 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:69.116,72.76 2 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:76.2,78.16 3 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:82.2,82.19 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:72.76,74.3 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:78.16,80.3 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:86.90,92.59 4 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:96.2,98.66 3 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:105.2,105.17 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:92.59,94.3 1 0 +github.com/hashicorp/consul/agent/connect_ca_endpoint.go:98.66,104.3 1 0 +github.com/hashicorp/consul/agent/notify.go:18.32,21.27 3 0 +github.com/hashicorp/consul/agent/notify.go:27.2,27.16 1 0 +github.com/hashicorp/consul/agent/notify.go:21.27,22.10 1 0 +github.com/hashicorp/consul/agent/notify.go:23.25,23.25 0 0 +github.com/hashicorp/consul/agent/notify.go:24.11,24.11 0 0 +github.com/hashicorp/consul/agent/notify.go:31.46,34.21 3 0 +github.com/hashicorp/consul/agent/notify.go:37.2,37.27 1 0 +github.com/hashicorp/consul/agent/notify.go:34.21,36.3 1 0 +github.com/hashicorp/consul/agent/notify.go:41.47,44.21 3 0 +github.com/hashicorp/consul/agent/notify.go:47.2,47.22 1 0 +github.com/hashicorp/consul/agent/notify.go:44.21,46.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:20.116,22.76 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:26.2,27.84 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:31.2,31.19 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:22.76,24.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:27.84,29.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:36.107,43.11 6 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:46.2,47.16 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:51.2,51.27 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:57.2,57.25 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:61.2,63.16 3 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:66.2,66.59 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:70.2,70.17 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:43.11,45.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:47.16,49.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:51.27,56.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:57.25,59.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:63.16,65.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:66.59,68.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:81.114,83.75 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:88.2,91.75 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:104.2,104.69 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:118.2,118.20 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:83.75,84.53 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:84.53,86.4 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:91.75,93.17 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:97.3,98.17 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:93.17,95.4 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:98.17,100.4 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:104.69,107.17 3 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:111.3,112.17 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:107.17,109.4 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:112.17,114.4 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:119.13,120.41 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:121.14,122.44 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:123.13,124.40 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:125.16,126.43 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:127.10,128.90 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:133.124,135.16 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:139.2,139.53 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:135.16,137.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:143.121,145.16 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:149.2,149.69 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:145.16,147.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:153.123,155.16 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:159.2,159.53 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:155.16,157.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:163.120,165.16 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:169.2,169.53 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:165.16,167.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:172.69,174.37 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:191.2,191.13 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:174.37,175.27 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:175.27,177.20 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:180.4,180.30 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:185.4,186.48 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:177.20,179.5 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:180.30,182.5 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:182.10,182.58 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:182.58,184.5 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:186.48,188.5 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:196.121,198.20 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:199.13,201.77 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:205.3,206.90 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:210.3,223.18 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:225.13,231.53 5 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:235.3,248.33 3 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:257.3,258.90 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:263.3,263.16 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:266.3,266.20 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:268.10,269.72 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:201.77,203.4 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:206.90,208.4 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:231.53,233.4 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:248.33,250.18 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:253.4,254.19 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:250.18,252.5 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:258.90,260.4 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:263.16,265.4 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:274.111,276.76 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:280.2,281.76 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:286.2,286.20 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:290.2,294.39 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:311.2,311.17 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:276.76,278.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:281.76,283.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:286.20,288.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:294.39,309.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:314.113,316.76 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:320.2,321.78 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:325.2,326.17 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:316.76,318.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:321.78,323.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:329.46,331.25 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:334.2,334.12 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:331.25,333.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:337.70,346.37 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:350.2,352.12 2 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:346.37,348.3 1 0 +github.com/hashicorp/consul/agent/operator_endpoint.go:355.75,375.2 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:63.100,68.16 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:73.2,75.107 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:79.2,80.40 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:87.2,88.30 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:106.2,137.8 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:68.16,70.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:75.107,77.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:80.40,82.55 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:82.55,84.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:88.30,101.38 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:101.38,103.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:141.59,143.30 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:155.2,155.14 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:143.30,145.24 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:145.24,147.49 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:150.4,150.107 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:147.49,149.5 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:150.107,152.5 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:159.53,160.69 1 1 +github.com/hashicorp/consul/agent/agent_endpoint.go:163.2,163.61 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:160.69,162.3 1 1 +github.com/hashicorp/consul/agent/agent_endpoint.go:166.103,171.16 4 1 +github.com/hashicorp/consul/agent/agent_endpoint.go:176.2,178.107 3 1 +github.com/hashicorp/consul/agent/agent_endpoint.go:181.2,181.33 1 1 +github.com/hashicorp/consul/agent/agent_endpoint.go:200.2,200.73 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:171.16,173.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:178.107,180.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:181.33,182.61 1 1 +github.com/hashicorp/consul/agent/agent_endpoint.go:189.3,198.18 4 1 +github.com/hashicorp/consul/agent/agent_endpoint.go:182.61,188.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:203.109,208.16 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:213.2,215.107 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:219.2,220.9 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:224.2,238.17 7 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:208.16,210.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:215.107,217.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:220.9,222.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:247.59,248.50 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:252.2,253.12 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:248.50,251.3 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:256.102,261.16 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:266.2,268.108 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:272.2,272.36 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:261.16,263.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:268.108,270.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:275.76,277.22 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:284.2,285.32 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:292.2,309.20 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:312.2,312.20 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:316.2,316.64 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:321.2,321.22 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:327.2,328.11 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:277.22,278.28 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:281.3,281.38 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:278.28,280.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:285.32,287.39 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:287.39,289.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:309.20,311.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:312.20,314.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:316.64,318.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:321.22,325.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:331.104,337.64 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:341.2,345.16 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:349.2,349.49 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:355.2,363.32 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:368.2,369.16 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:373.2,374.16 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:377.2,384.79 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:396.2,396.17 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:400.2,400.23 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:337.64,339.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:345.16,347.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:349.49,351.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:363.32,366.3 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:369.16,371.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:374.16,376.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:384.79,386.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:396.17,398.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:407.103,413.38 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:419.2,423.64 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:428.2,429.16 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:435.2,439.49 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:443.2,446.56 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:485.2,485.22 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:488.2,488.21 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:413.38,416.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:423.64,425.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:429.16,431.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:439.49,441.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:446.56,449.23 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:453.4,460.18 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:463.4,465.99 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:470.4,475.18 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:480.4,482.40 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:449.23,451.5 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:460.18,462.5 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:465.99,467.5 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:475.18,477.5 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:485.22,487.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:491.102,497.64 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:501.2,502.16 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:506.2,506.49 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:510.2,513.16 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:518.2,521.28 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:531.2,532.16 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:535.2,542.79 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:554.2,554.17 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:558.2,558.25 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:497.64,499.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:502.16,504.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:506.49,508.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:513.16,515.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:521.28,522.27 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:522.27,526.4 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:526.9,528.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:532.16,534.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:542.79,544.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:554.17,556.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:561.103,568.54 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:572.2,573.9 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:585.2,586.62 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:590.2,591.9 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:614.2,615.63 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:627.2,627.17 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:631.2,631.21 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:568.54,570.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:573.9,574.18 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:575.28,575.28 0 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:579.11,580.110 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:586.62,588.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:591.9,593.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:593.8,597.33 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:607.3,609.17 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:597.33,601.48 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:601.48,603.5 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:604.9,606.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:609.17,611.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:615.63,617.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:627.17,629.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:634.100,639.16 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:644.2,647.108 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:652.2,653.62 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:658.2,659.54 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:664.2,666.9 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:674.2,674.17 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:639.16,641.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:647.108,649.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:653.62,655.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:659.54,661.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:666.9,667.60 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:670.3,670.43 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:667.60,669.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:671.8,673.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:677.101,682.16 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:687.2,689.108 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:693.2,693.40 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:696.2,696.37 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:682.16,684.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:689.108,691.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:693.40,695.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:699.106,704.16 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:708.2,708.76 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:713.2,714.62 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:719.2,725.9 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:704.16,706.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:708.76,710.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:714.62,716.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:725.9,727.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:727.8,729.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:735.38,736.52 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:736.52,738.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:741.109,746.76 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:750.2,750.52 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:755.2,755.21 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:759.2,759.60 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:763.2,764.16 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:768.2,768.61 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:773.2,778.16 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:783.2,785.28 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:797.2,797.78 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:802.2,802.91 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:805.2,806.17 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:746.76,748.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:750.52,752.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:755.21,757.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:759.60,761.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:764.16,766.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:768.61,770.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:778.16,780.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:785.28,789.21 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:789.21,791.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:791.9,793.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:797.78,799.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:802.91,804.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:809.111,817.79 5 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:821.2,822.16 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:826.2,828.64 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:832.2,832.77 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:836.2,836.59 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:839.2,840.17 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:817.79,819.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:822.16,824.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:828.64,830.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:832.77,834.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:836.59,838.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:843.105,848.2 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:850.105,857.2 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:859.105,865.2 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:882.107,884.54 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:888.2,888.23 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:896.2,899.77 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:884.54,886.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:889.25,889.25 0 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:890.25,890.25 0 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:891.26,891.26 0 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:892.10,893.125 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:902.160,909.75 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:913.2,914.16 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:918.2,920.73 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:924.2,924.60 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:928.2,928.68 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:931.2,932.17 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:909.75,911.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:914.16,916.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:920.73,922.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:924.60,926.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:928.68,930.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:936.103,939.27 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:955.2,956.16 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:939.27,954.3 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:957.25,958.59 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:959.25,960.46 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:961.10,962.62 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:966.46,967.91 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:970.2,970.59 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:973.2,973.14 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:967.91,969.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:970.59,972.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:977.113,980.21 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:984.2,985.64 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:989.2,995.16 5 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:999.2,999.49 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1003.2,1007.59 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1023.2,1024.26 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1027.2,1031.115 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:980.21,982.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:985.64,987.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:995.16,997.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:999.49,1001.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1007.59,1008.102 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1011.3,1012.27 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1015.3,1021.105 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1008.102,1010.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1012.27,1014.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1024.26,1026.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1035.115,1038.23 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1042.2,1043.64 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1047.2,1053.16 5 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1057.2,1057.97 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1061.2,1061.49 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1065.2,1072.35 6 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1095.2,1095.26 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1098.2,1098.104 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1038.23,1040.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1043.64,1045.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1053.16,1055.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1057.97,1059.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1061.49,1063.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1072.35,1084.34 6 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1090.3,1090.19 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1084.34,1087.4 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1090.19,1093.4 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1095.26,1097.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1101.111,1105.76 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1109.2,1109.52 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1114.2,1114.21 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1120.2,1120.32 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1124.2,1128.16 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1132.2,1132.61 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1137.2,1138.23 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1143.2,1143.81 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1149.2,1149.38 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1154.2,1155.16 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1158.2,1158.33 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1165.2,1165.63 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1178.2,1178.76 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1183.2,1184.16 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1187.2,1187.20 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1205.2,1208.145 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1212.2,1220.51 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1224.2,1224.20 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1237.2,1238.17 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1105.76,1107.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1109.52,1111.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1114.21,1116.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1120.32,1122.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1128.16,1130.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1132.61,1134.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1138.23,1139.61 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1139.61,1141.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1143.81,1145.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1149.38,1151.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1155.16,1157.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1158.33,1159.63 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1159.63,1161.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1165.63,1167.17 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1170.3,1170.34 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1167.17,1169.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1170.34,1171.64 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1171.64,1173.5 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1178.76,1180.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1184.16,1186.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1187.20,1188.52 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1194.3,1194.75 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1201.3,1201.34 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1188.52,1190.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1194.75,1196.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1208.145,1210.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1220.51,1222.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1224.20,1233.52 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1233.52,1235.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1241.113,1249.75 5 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1253.2,1254.16 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1258.2,1260.60 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1264.2,1264.75 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1268.2,1268.51 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1272.2,1273.17 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1249.75,1251.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1254.16,1256.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1260.60,1262.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1264.75,1266.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1268.51,1270.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1276.114,1281.18 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1286.2,1287.36 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1291.2,1293.16 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1298.2,1301.75 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1305.2,1306.16 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1310.2,1312.60 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1316.2,1316.75 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1320.2,1320.12 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1330.2,1331.17 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1281.18,1283.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1287.36,1289.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1293.16,1295.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1301.75,1303.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1306.16,1308.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1312.60,1314.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1316.75,1318.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1320.12,1322.77 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1322.77,1324.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1325.8,1326.63 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1326.63,1328.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1334.111,1337.36 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1341.2,1343.16 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1348.2,1352.16 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1356.2,1358.107 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1362.2,1362.12 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1367.2,1368.17 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1337.36,1339.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1343.16,1345.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1352.16,1354.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1358.107,1360.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1362.12,1364.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1364.8,1366.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1371.103,1376.16 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1381.2,1383.107 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1388.2,1389.20 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1393.2,1394.45 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1398.2,1398.41 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1402.2,1403.9 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1407.2,1429.6 9 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1376.16,1378.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1383.107,1385.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1389.20,1391.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1394.45,1396.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1398.41,1400.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1403.9,1405.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1429.6,1430.10 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1431.31,1433.24 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1436.4,1437.19 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1439.24,1440.33 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1442.24,1443.19 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1433.24,1435.5 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1448.101,1449.26 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1454.2,1457.16 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1462.2,1464.108 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1470.2,1471.52 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1476.2,1478.56 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1509.2,1509.16 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1513.2,1514.17 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1449.26,1451.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1457.16,1459.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1464.108,1466.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1471.52,1473.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1478.56,1480.17 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1504.3,1504.29 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1507.3,1507.13 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1481.31,1483.15 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1487.35,1489.15 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1493.67,1494.83 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1496.47,1497.81 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1499.11,1500.105 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1483.15,1485.5 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1489.15,1491.5 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1504.29,1506.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1509.16,1511.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1518.110,1520.76 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1524.2,1525.16 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1528.2,1533.9 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1537.2,1539.20 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1520.76,1522.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1525.16,1527.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1533.9,1536.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1546.113,1558.76 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1563.2,1563.64 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1566.2,1574.29 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1578.2,1578.61 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1582.2,1583.16 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1586.2,1589.9 3 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1593.2,1595.19 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1558.76,1560.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1563.64,1565.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1574.29,1576.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1578.61,1580.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1583.16,1585.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1589.9,1592.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1606.112,1613.79 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1617.2,1617.55 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1621.2,1621.64 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1625.2,1626.16 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1629.2,1634.8 2 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1613.79,1615.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1617.55,1619.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1621.64,1623.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1626.16,1628.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1651.100,1656.16 4 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1661.2,1661.75 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1665.2,1665.37 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1656.16,1658.3 1 0 +github.com/hashicorp/consul/agent/agent_endpoint.go:1661.75,1663.3 1 0 +github.com/hashicorp/consul/agent/agent_oss.go:21.82,21.83 0 0 +github.com/hashicorp/consul/agent/agent_oss.go:24.80,24.81 0 0 +github.com/hashicorp/consul/agent/agent_oss.go:27.64,29.2 1 1 +github.com/hashicorp/consul/agent/agent_oss.go:32.68,34.2 1 0 +github.com/hashicorp/consul/agent/agent_oss.go:37.73,38.2 0 1 +github.com/hashicorp/consul/agent/agent_oss.go:41.68,42.2 0 0 +github.com/hashicorp/consul/agent/agent_oss.go:45.62,47.2 1 1 +github.com/hashicorp/consul/agent/agent_oss.go:50.39,50.40 0 1 +github.com/hashicorp/consul/agent/agent_oss.go:53.64,55.2 1 0 +github.com/hashicorp/consul/agent/agent_oss.go:57.59,59.2 1 1 +github.com/hashicorp/consul/agent/agent_oss.go:61.37,61.38 0 1 +github.com/hashicorp/consul/agent/agent_oss.go:63.70,63.71 0 1 +github.com/hashicorp/consul/agent/catalog_endpoint.go:130.106,135.76 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:139.2,139.89 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:144.2,144.27 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:147.2,151.69 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:156.2,158.18 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:135.76,137.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:139.89,141.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:144.27,146.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:151.69,155.3 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:161.108,166.76 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:169.2,169.89 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:174.2,174.27 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:177.2,181.71 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:186.2,188.18 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:166.76,168.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:169.89,171.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:174.27,176.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:181.71,185.3 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:191.109,200.32 6 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:222.2,224.17 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:200.32,202.17 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:207.3,208.10 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:212.3,213.15 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:202.17,206.4 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:208.10,211.4 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:214.8,215.77 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:215.77,219.4 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:227.103,234.75 4 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:237.2,238.76 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:244.2,246.1 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:247.2,247.70 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:250.2,250.106 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:255.2,260.22 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:263.2,265.23 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:234.75,236.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:238.76,242.3 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:247.70,249.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:250.106,253.18 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:260.22,262.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:268.106,273.76 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:277.2,278.76 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:281.2,284.32 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:312.2,315.25 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:318.2,320.26 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:273.76,275.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:278.76,280.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:284.32,286.17 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:291.3,292.10 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:296.3,297.15 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:286.17,290.4 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:292.10,295.4 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:298.8,299.2 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:300.3,300.74 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:305.3,305.107 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:300.74,304.4 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:305.107,308.19 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:315.25,317.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:323.117,325.2 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:327.110,329.2 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:331.124,334.13 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:339.2,343.76 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:347.2,349.76 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:354.2,355.32 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:360.2,360.49 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:365.2,366.28 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:371.2,374.32 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:402.2,406.29 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:409.2,409.37 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:416.2,418.30 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:334.13,337.3 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:343.76,345.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:349.76,351.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:355.32,358.3 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:360.49,362.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:366.28,368.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:374.32,376.17 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:381.3,383.10 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:387.3,387.15 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:376.17,380.4 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:383.10,386.4 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:388.8,389.2 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:390.3,390.74 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:395.3,395.107 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:390.74,394.4 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:395.107,398.19 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:406.29,408.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:409.37,410.27 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:410.27,414.4 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:421.110,427.76 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:431.2,431.76 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:436.2,437.21 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:442.2,444.1 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:445.2,445.73 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:450.2,450.106 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:455.2,456.29 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:470.2,470.29 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:477.2,479.30 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:427.76,429.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:431.76,433.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:437.21,439.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:445.73,449.3 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:450.106,453.18 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:456.29,458.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:470.29,471.47 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:471.47,472.21 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:472.21,474.5 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:482.113,488.66 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:492.2,492.76 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:497.2,498.21 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:502.2,502.58 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:507.2,509.1 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:510.2,510.76 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:515.2,515.106 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:520.2,524.46 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:529.2,531.31 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:488.66,490.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:492.76,494.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:498.21,500.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:502.58,504.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:510.76,514.3 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:515.106,518.18 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:524.46,525.20 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:525.20,527.4 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:534.113,540.76 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:543.2,543.76 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:548.2,549.28 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:554.2,556.1 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:557.2,557.76 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:562.2,562.106 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:567.2,571.26 3 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:540.76,542.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:543.76,545.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:549.28,551.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:557.76,561.3 2 0 +github.com/hashicorp/consul/agent/catalog_endpoint.go:562.106,565.18 3 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:19.110,25.58 4 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:29.2,30.74 2 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:33.2,33.48 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:25.58,27.3 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:30.74,32.3 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:37.108,39.76 2 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:43.2,45.1 3 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:46.2,46.73 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:49.2,49.108 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:54.2,57.26 2 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:60.2,60.27 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:39.76,41.3 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:46.73,48.3 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:49.108,52.18 3 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:57.26,59.3 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:64.111,65.20 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:66.14,67.42 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:69.13,70.40 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:72.10,73.73 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:78.54,80.52 2 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:87.2,87.12 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:80.52,82.17 2 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:85.3,85.13 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:82.17,84.4 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:91.122,102.76 3 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:105.2,105.53 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:109.2,110.45 2 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:119.2,122.32 3 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:156.2,165.24 3 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:168.2,168.19 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:102.76,104.3 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:105.53,107.3 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:110.45,112.17 2 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:116.3,116.21 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:112.17,114.4 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:122.32,124.17 2 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:133.3,135.10 3 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:139.3,139.13 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:124.17,127.69 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:127.70,129.5 0 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:129.10,131.5 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:135.10,138.4 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:140.8,141.2 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:142.3,142.77 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:150.3,150.109 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:142.77,145.39 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:148.4,148.19 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:145.39,147.5 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:150.109,153.19 3 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:165.24,167.3 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:174.122,185.76 3 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:188.2,188.53 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:192.2,194.1 3 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:195.2,195.76 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:203.2,203.108 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:208.2,209.19 2 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:185.76,187.3 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:188.53,190.3 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:195.76,198.38 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:201.3,201.18 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:198.38,200.4 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:203.108,206.18 3 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:213.118,217.76 2 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:221.2,223.1 3 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:224.2,224.72 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:232.2,232.108 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:237.2,238.27 2 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:217.76,219.3 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:224.72,227.38 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:230.3,230.18 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:227.38,229.4 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:232.108,235.18 3 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:242.121,248.27 4 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:254.2,254.23 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:259.2,262.74 3 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:265.2,265.17 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:248.27,249.59 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:249.59,251.4 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:254.23,256.3 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:262.74,264.3 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:269.121,280.74 5 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:283.2,283.17 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:280.74,282.3 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:287.110,289.9 2 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:290.43,292.14 2 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:294.43,296.14 2 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:298.10,300.14 2 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:306.112,307.29 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:311.2,314.9 3 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:307.29,309.3 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:315.43,316.26 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:319.3,320.47 2 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:322.43,323.26 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:326.3,327.47 2 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:329.10,330.21 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:316.26,318.4 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:323.26,325.4 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:331.14,332.44 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:334.14,335.47 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:337.17,338.47 1 0 +github.com/hashicorp/consul/agent/prepared_query_endpoint.go:340.11,341.83 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:24.43,26.9 2 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:29.2,29.27 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:51.2,51.12 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:26.9,28.3 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:29.27,30.29 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:31.16,34.16 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:39.4,40.11 2 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:43.4,44.18 2 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:47.4,48.14 2 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:34.16,36.5 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:40.11,42.5 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:44.18,46.5 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:55.32,56.12 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:60.2,60.14 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:57.103,58.14 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:67.109,85.32 3 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:90.2,90.35 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:98.2,100.51 3 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:119.2,119.40 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:129.2,131.25 3 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:334.2,334.28 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:85.32,87.3 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:90.35,96.3 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:100.51,101.52 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:101.52,109.4 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:109.9,114.4 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:119.40,124.3 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:131.25,132.10 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:133.21,135.36 2 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:142.4,143.21 2 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:147.4,165.32 2 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:167.23,168.35 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:173.4,173.37 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:177.4,196.32 3 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:198.26,199.41 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:203.4,232.24 3 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:264.4,264.32 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:266.24,267.37 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:271.4,278.65 3 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:281.4,282.64 2 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:285.4,286.87 2 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:290.4,330.32 2 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:135.36,140.5 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:143.21,145.5 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:168.35,170.5 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:173.37,175.5 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:199.41,201.5 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:232.24,235.47 3 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:238.5,238.45 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:241.5,241.44 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:244.5,244.40 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:247.5,247.47 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:250.5,250.41 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:254.5,254.42 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:235.47,237.6 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:238.45,240.6 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:241.44,243.6 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:244.40,246.6 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:247.47,249.6 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:250.41,252.6 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:254.42,255.51 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:259.6,259.62 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:255.51,257.7 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:259.62,261.7 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:267.37,269.5 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:278.65,280.5 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:282.64,284.5 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:286.87,288.5 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:341.94,344.16 2 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:350.2,352.17 3 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:383.2,383.14 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:398.2,398.17 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:344.16,346.3 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:352.17,354.77 2 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:358.3,359.64 2 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:365.3,368.47 3 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:354.77,356.4 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:359.64,361.4 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:369.8,375.65 5 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:378.3,378.47 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:375.65,377.4 1 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:383.14,387.17 4 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:391.3,394.18 4 0 +github.com/hashicorp/consul/agent/txn_endpoint.go:387.17,389.4 1 0 +github.com/hashicorp/consul/agent/agent_endpoint_oss.go:12.100,14.2 1 0 +github.com/hashicorp/consul/agent/http_oss.go:15.91,16.70 1 0 +github.com/hashicorp/consul/agent/http_oss.go:22.2,22.57 1 0 +github.com/hashicorp/consul/agent/http_oss.go:29.2,29.46 1 0 +github.com/hashicorp/consul/agent/http_oss.go:16.70,21.3 1 0 +github.com/hashicorp/consul/agent/http_oss.go:22.57,27.3 1 0 +github.com/hashicorp/consul/agent/http_oss.go:32.94,33.21 1 0 +github.com/hashicorp/consul/agent/http_oss.go:41.2,44.3 1 0 +github.com/hashicorp/consul/agent/http_oss.go:33.21,35.3 1 0 +github.com/hashicorp/consul/agent/http_oss.go:35.8,35.52 1 0 +github.com/hashicorp/consul/agent/http_oss.go:35.52,37.3 1 0 +github.com/hashicorp/consul/agent/http_oss.go:47.95,48.14 1 0 +github.com/hashicorp/consul/agent/http_oss.go:56.2,59.3 1 0 +github.com/hashicorp/consul/agent/http_oss.go:48.14,50.3 1 0 +github.com/hashicorp/consul/agent/http_oss.go:50.8,50.69 1 0 +github.com/hashicorp/consul/agent/http_oss.go:50.69,52.3 1 0 +github.com/hashicorp/consul/agent/http_oss.go:62.95,64.2 1 0 +github.com/hashicorp/consul/agent/http_oss.go:66.75,67.16 1 0 +github.com/hashicorp/consul/agent/http_oss.go:71.2,73.51 2 0 +github.com/hashicorp/consul/agent/http_oss.go:82.2,82.12 1 0 +github.com/hashicorp/consul/agent/http_oss.go:67.16,69.3 1 0 +github.com/hashicorp/consul/agent/http_oss.go:73.51,76.22 2 0 +github.com/hashicorp/consul/agent/http_oss.go:77.22,78.77 1 0 +github.com/hashicorp/consul/agent/http_oss.go:85.104,86.70 1 0 +github.com/hashicorp/consul/agent/http_oss.go:93.2,93.12 1 0 +github.com/hashicorp/consul/agent/http_oss.go:86.70,91.3 1 0 +github.com/hashicorp/consul/agent/http_oss.go:97.74,99.2 1 1 +github.com/hashicorp/consul/agent/http_oss.go:103.83,105.2 1 0 +github.com/hashicorp/consul/agent/http_oss.go:107.97,108.70 1 0 +github.com/hashicorp/consul/agent/http_oss.go:114.2,114.64 1 0 +github.com/hashicorp/consul/agent/http_oss.go:121.2,121.12 1 0 +github.com/hashicorp/consul/agent/http_oss.go:108.70,113.3 1 0 +github.com/hashicorp/consul/agent/http_oss.go:114.64,119.3 1 0 +github.com/hashicorp/consul/agent/retry_join.go:16.32,23.43 1 1 +github.com/hashicorp/consul/agent/retry_join.go:30.2,30.38 1 1 +github.com/hashicorp/consul/agent/retry_join.go:23.43,27.4 1 0 +github.com/hashicorp/consul/agent/retry_join.go:30.38,32.3 1 0 +github.com/hashicorp/consul/agent/retry_join.go:35.32,36.26 1 1 +github.com/hashicorp/consul/agent/retry_join.go:41.2,44.53 3 1 +github.com/hashicorp/consul/agent/retry_join.go:77.2,86.38 2 1 +github.com/hashicorp/consul/agent/retry_join.go:36.26,39.3 2 0 +github.com/hashicorp/consul/agent/retry_join.go:44.53,54.16 1 0 +github.com/hashicorp/consul/agent/retry_join.go:62.3,72.4 3 0 +github.com/hashicorp/consul/agent/retry_join.go:54.16,59.4 1 0 +github.com/hashicorp/consul/agent/retry_join.go:73.8,75.3 1 1 +github.com/hashicorp/consul/agent/retry_join.go:86.38,88.3 1 0 +github.com/hashicorp/consul/agent/retry_join.go:91.58,98.43 1 0 +github.com/hashicorp/consul/agent/retry_join.go:107.2,107.38 1 0 +github.com/hashicorp/consul/agent/retry_join.go:98.43,99.74 1 0 +github.com/hashicorp/consul/agent/retry_join.go:102.4,102.26 1 0 +github.com/hashicorp/consul/agent/retry_join.go:99.74,101.5 1 0 +github.com/hashicorp/consul/agent/retry_join.go:107.38,109.3 1 0 +github.com/hashicorp/consul/agent/retry_join.go:112.48,114.39 2 0 +github.com/hashicorp/consul/agent/retry_join.go:117.2,123.3 3 0 +github.com/hashicorp/consul/agent/retry_join.go:114.39,116.3 1 0 +github.com/hashicorp/consul/agent/retry_join.go:126.122,128.18 2 0 +github.com/hashicorp/consul/agent/retry_join.go:131.2,131.33 1 0 +github.com/hashicorp/consul/agent/retry_join.go:166.2,166.14 1 0 +github.com/hashicorp/consul/agent/retry_join.go:128.18,130.3 1 0 +github.com/hashicorp/consul/agent/retry_join.go:131.33,132.10 1 0 +github.com/hashicorp/consul/agent/retry_join.go:133.44,137.18 2 0 +github.com/hashicorp/consul/agent/retry_join.go:161.11,162.31 1 0 +github.com/hashicorp/consul/agent/retry_join.go:137.18,138.22 1 0 +github.com/hashicorp/consul/agent/retry_join.go:138.22,143.6 1 0 +github.com/hashicorp/consul/agent/retry_join.go:144.10,146.22 2 0 +github.com/hashicorp/consul/agent/retry_join.go:146.22,147.48 1 0 +github.com/hashicorp/consul/agent/retry_join.go:147.48,152.7 1 0 +github.com/hashicorp/consul/agent/retry_join.go:152.12,157.7 1 0 +github.com/hashicorp/consul/agent/retry_join.go:205.41,206.23 1 1 +github.com/hashicorp/consul/agent/retry_join.go:210.2,211.16 2 0 +github.com/hashicorp/consul/agent/retry_join.go:215.2,215.46 1 0 +github.com/hashicorp/consul/agent/retry_join.go:227.2,228.6 2 0 +github.com/hashicorp/consul/agent/retry_join.go:206.23,208.3 1 1 +github.com/hashicorp/consul/agent/retry_join.go:211.16,213.3 1 0 +github.com/hashicorp/consul/agent/retry_join.go:215.46,220.3 2 0 +github.com/hashicorp/consul/agent/retry_join.go:220.8,225.3 2 0 +github.com/hashicorp/consul/agent/retry_join.go:228.6,230.21 2 0 +github.com/hashicorp/consul/agent/retry_join.go:249.3,250.51 2 0 +github.com/hashicorp/consul/agent/retry_join.go:258.3,258.47 1 0 +github.com/hashicorp/consul/agent/retry_join.go:270.3,270.10 1 0 +github.com/hashicorp/consul/agent/retry_join.go:230.21,233.18 3 0 +github.com/hashicorp/consul/agent/retry_join.go:233.18,234.49 1 0 +github.com/hashicorp/consul/agent/retry_join.go:239.5,239.15 1 0 +github.com/hashicorp/consul/agent/retry_join.go:234.49,236.6 1 0 +github.com/hashicorp/consul/agent/retry_join.go:236.11,238.6 1 0 +github.com/hashicorp/consul/agent/retry_join.go:241.9,241.29 1 0 +github.com/hashicorp/consul/agent/retry_join.go:241.29,242.48 1 0 +github.com/hashicorp/consul/agent/retry_join.go:242.48,244.5 1 0 +github.com/hashicorp/consul/agent/retry_join.go:244.10,246.5 1 0 +github.com/hashicorp/consul/agent/retry_join.go:250.51,251.48 1 0 +github.com/hashicorp/consul/agent/retry_join.go:251.48,253.5 1 0 +github.com/hashicorp/consul/agent/retry_join.go:253.10,255.5 1 0 +github.com/hashicorp/consul/agent/retry_join.go:258.47,263.4 1 0 +github.com/hashicorp/consul/agent/retry_join.go:263.9,268.4 1 0 +github.com/hashicorp/consul/agent/retry_join.go:271.33,271.33 0 0 +github.com/hashicorp/consul/agent/retry_join.go:272.19,273.14 1 0 +github.com/hashicorp/consul/agent/snapshot_endpoint.go:13.99,17.43 4 0 +github.com/hashicorp/consul/agent/snapshot_endpoint.go:21.2,21.20 1 0 +github.com/hashicorp/consul/agent/snapshot_endpoint.go:17.43,19.3 1 0 +github.com/hashicorp/consul/agent/snapshot_endpoint.go:22.13,26.58 2 0 +github.com/hashicorp/consul/agent/snapshot_endpoint.go:33.3,34.83 2 0 +github.com/hashicorp/consul/agent/snapshot_endpoint.go:37.3,37.18 1 0 +github.com/hashicorp/consul/agent/snapshot_endpoint.go:39.13,41.82 2 0 +github.com/hashicorp/consul/agent/snapshot_endpoint.go:44.3,44.18 1 0 +github.com/hashicorp/consul/agent/snapshot_endpoint.go:46.10,47.72 1 0 +github.com/hashicorp/consul/agent/snapshot_endpoint.go:26.58,29.4 2 0 +github.com/hashicorp/consul/agent/snapshot_endpoint.go:34.83,36.4 1 0 +github.com/hashicorp/consul/agent/snapshot_endpoint.go:41.82,43.4 1 0 +github.com/hashicorp/consul/agent/acl_oss.go:13.78,15.2 0 0 +github.com/hashicorp/consul/agent/acl_oss.go:17.85,19.2 0 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:14.56,15.40 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:18.2,18.94 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:15.40,17.3 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:28.28,30.2 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:33.33,35.2 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:38.38,40.2 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:44.112,45.52 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:49.2,50.84 2 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:60.2,60.21 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:65.2,65.16 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:68.2,68.17 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:45.52,47.3 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:50.84,51.22 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:54.3,54.18 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:51.22,53.4 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:60.21,61.32 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:61.32,63.4 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:65.16,67.3 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:73.106,74.52 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:78.2,79.76 2 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:82.2,82.75 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:86.2,88.73 3 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:93.2,93.53 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:74.52,76.3 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:79.76,81.3 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:82.75,84.3 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:88.73,91.3 2 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:98.105,99.52 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:103.2,105.76 3 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:108.2,108.75 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:112.2,114.68 3 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:118.2,119.22 2 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:124.2,124.20 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:99.52,101.3 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:105.76,107.3 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:108.75,110.3 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:114.68,116.3 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:119.22,122.3 2 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:127.87,130.15 2 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:134.2,136.35 3 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:140.2,140.23 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:146.2,146.12 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:130.15,132.3 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:136.35,138.3 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:140.23,141.46 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:144.3,144.23 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:141.46,142.12 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:150.107,151.52 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:155.2,156.52 2 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:159.2,162.76 3 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:166.2,167.72 2 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:171.2,171.17 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:151.52,153.3 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:156.52,158.3 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:162.76,164.3 1 0 +github.com/hashicorp/consul/agent/coordinate_endpoint.go:167.72,169.3 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:30.83,35.29 3 0 +github.com/hashicorp/consul/agent/watch_handler.go:44.2,44.43 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:101.2,101.11 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:36.14,37.13 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:38.16,39.11 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:40.10,41.56 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:44.43,49.20 3 0 +github.com/hashicorp/consul/agent/watch_handler.go:54.3,54.17 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:59.3,71.42 7 0 +github.com/hashicorp/consul/agent/watch_handler.go:78.3,81.35 2 0 +github.com/hashicorp/consul/agent/watch_handler.go:89.3,90.44 2 0 +github.com/hashicorp/consul/agent/watch_handler.go:96.3,99.4 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:49.20,51.4 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:51.9,53.4 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:54.17,57.4 2 0 +github.com/hashicorp/consul/agent/watch_handler.go:71.42,77.4 2 0 +github.com/hashicorp/consul/agent/watch_handler.go:81.35,86.4 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:90.44,93.4 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:104.99,105.43 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:185.2,185.11 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:105.43,109.35 2 0 +github.com/hashicorp/consul/agent/watch_handler.go:117.3,129.42 7 0 +github.com/hashicorp/consul/agent/watch_handler.go:137.3,138.17 2 0 +github.com/hashicorp/consul/agent/watch_handler.go:142.3,145.42 4 0 +github.com/hashicorp/consul/agent/watch_handler.go:150.3,151.17 2 0 +github.com/hashicorp/consul/agent/watch_handler.go:158.3,166.44 5 0 +github.com/hashicorp/consul/agent/watch_handler.go:171.3,171.55 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:109.35,113.4 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:113.9,115.4 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:129.42,135.4 2 0 +github.com/hashicorp/consul/agent/watch_handler.go:138.17,141.4 2 0 +github.com/hashicorp/consul/agent/watch_handler.go:145.42,146.31 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:146.31,148.5 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:151.17,157.4 2 0 +github.com/hashicorp/consul/agent/watch_handler.go:166.44,169.4 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:171.55,177.4 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:177.9,183.4 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:190.93,192.16 2 0 +github.com/hashicorp/consul/agent/watch_handler.go:196.2,197.16 2 0 +github.com/hashicorp/consul/agent/watch_handler.go:201.2,201.50 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:205.2,206.13 2 0 +github.com/hashicorp/consul/agent/watch_handler.go:213.2,213.108 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:216.2,216.57 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:219.2,219.16 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:192.16,194.3 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:197.16,200.3 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:201.50,203.3 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:206.13,208.17 2 0 +github.com/hashicorp/consul/agent/watch_handler.go:208.17,210.4 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:213.108,215.3 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:216.57,218.3 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:222.57,223.29 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:224.14,225.29 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:226.16,227.19 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:228.21,230.28 2 0 +github.com/hashicorp/consul/agent/watch_handler.go:238.3,238.21 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:239.10,240.65 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:230.28,232.11 2 0 +github.com/hashicorp/consul/agent/watch_handler.go:236.4,236.30 1 0 +github.com/hashicorp/consul/agent/watch_handler.go:232.11,234.5 1 0 +github.com/hashicorp/consul/agent/nodeid.go:20.99,21.25 1 1 +github.com/hashicorp/consul/agent/nodeid.go:30.2,30.26 1 0 +github.com/hashicorp/consul/agent/nodeid.go:36.2,37.45 2 0 +github.com/hashicorp/consul/agent/nodeid.go:51.2,52.16 2 0 +github.com/hashicorp/consul/agent/nodeid.go:55.2,55.56 1 0 +github.com/hashicorp/consul/agent/nodeid.go:58.2,58.65 1 0 +github.com/hashicorp/consul/agent/nodeid.go:61.2,61.30 1 0 +github.com/hashicorp/consul/agent/nodeid.go:21.25,23.51 2 1 +github.com/hashicorp/consul/agent/nodeid.go:26.3,26.35 1 1 +github.com/hashicorp/consul/agent/nodeid.go:23.51,25.4 1 0 +github.com/hashicorp/consul/agent/nodeid.go:30.26,33.3 2 0 +github.com/hashicorp/consul/agent/nodeid.go:37.45,39.17 2 0 +github.com/hashicorp/consul/agent/nodeid.go:43.3,45.50 3 0 +github.com/hashicorp/consul/agent/nodeid.go:48.3,48.35 1 0 +github.com/hashicorp/consul/agent/nodeid.go:39.17,41.4 1 0 +github.com/hashicorp/consul/agent/nodeid.go:45.50,47.4 1 0 +github.com/hashicorp/consul/agent/nodeid.go:52.16,54.3 1 0 +github.com/hashicorp/consul/agent/nodeid.go:55.56,57.3 1 0 +github.com/hashicorp/consul/agent/nodeid.go:58.65,60.3 1 0 +github.com/hashicorp/consul/agent/nodeid.go:69.78,70.23 1 0 +github.com/hashicorp/consul/agent/nodeid.go:75.2,76.16 2 0 +github.com/hashicorp/consul/agent/nodeid.go:84.2,93.16 4 0 +github.com/hashicorp/consul/agent/nodeid.go:70.23,72.3 1 0 +github.com/hashicorp/consul/agent/nodeid.go:76.16,79.3 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:69.52,72.20 3 0 +github.com/hashicorp/consul/agent/remote_exec.go:76.2,77.18 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:82.2,83.21 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:96.2,97.20 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:72.20,75.3 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:77.18,79.3 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:83.21,86.3 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:86.8,93.12 7 0 +github.com/hashicorp/consul/agent/remote_exec.go:100.31,103.20 3 0 +github.com/hashicorp/consul/agent/remote_exec.go:107.2,107.19 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:110.2,110.9 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:103.20,106.3 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:107.19,109.3 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:111.35,113.15 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:114.20,115.15 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:120.50,124.60 3 0 +github.com/hashicorp/consul/agent/remote_exec.go:130.2,131.41 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:136.2,136.35 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:141.2,146.27 4 0 +github.com/hashicorp/consul/agent/remote_exec.go:163.2,166.24 4 0 +github.com/hashicorp/consul/agent/remote_exec.go:171.2,171.16 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:178.2,188.36 4 0 +github.com/hashicorp/consul/agent/remote_exec.go:195.2,196.12 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:216.1,217.24 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:239.2,239.21 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:124.60,127.3 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:131.41,133.3 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:136.35,138.3 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:146.27,148.17 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:153.3,157.26 5 0 +github.com/hashicorp/consul/agent/remote_exec.go:148.17,152.4 3 0 +github.com/hashicorp/consul/agent/remote_exec.go:158.8,160.3 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:166.24,168.3 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:168.8,170.3 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:171.16,175.3 3 0 +github.com/hashicorp/consul/agent/remote_exec.go:188.36,192.3 3 0 +github.com/hashicorp/consul/agent/remote_exec.go:196.12,200.17 4 0 +github.com/hashicorp/consul/agent/remote_exec.go:206.3,206.49 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:212.3,212.14 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:200.17,203.4 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:206.49,207.60 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:207.60,210.5 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:217.24,218.10 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:219.30,220.18 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:223.4,223.50 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:228.32,230.50 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:220.18,221.15 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:223.50,227.5 3 0 +github.com/hashicorp/consul/agent/remote_exec.go:230.50,234.5 3 0 +github.com/hashicorp/consul/agent/remote_exec.go:244.86,254.1 4 0 +github.com/hashicorp/consul/agent/remote_exec.go:255.2,255.53 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:259.2,259.27 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:270.2,270.68 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:274.2,274.13 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:255.53,258.3 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:259.27,261.34 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:261.34,264.14 3 0 +github.com/hashicorp/consul/agent/remote_exec.go:265.9,268.4 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:270.68,273.3 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:279.65,280.78 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:284.2,284.13 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:280.78,283.3 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:288.92,290.68 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:294.2,294.13 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:290.68,293.3 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:298.85,300.79 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:304.2,304.13 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:300.79,303.3 2 0 +github.com/hashicorp/consul/agent/remote_exec.go:308.93,321.61 5 0 +github.com/hashicorp/consul/agent/remote_exec.go:324.2,324.14 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:327.2,327.12 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:321.61,323.3 1 0 +github.com/hashicorp/consul/agent/remote_exec.go:324.14,326.3 1 0 +github.com/hashicorp/consul/agent/status_endpoint.go:9.103,11.76 2 0 +github.com/hashicorp/consul/agent/status_endpoint.go:15.2,16.66 2 0 +github.com/hashicorp/consul/agent/status_endpoint.go:19.2,19.17 1 0 +github.com/hashicorp/consul/agent/status_endpoint.go:11.76,13.3 1 0 +github.com/hashicorp/consul/agent/status_endpoint.go:16.66,18.3 1 0 +github.com/hashicorp/consul/agent/status_endpoint.go:22.102,24.76 2 0 +github.com/hashicorp/consul/agent/status_endpoint.go:28.2,29.65 2 0 +github.com/hashicorp/consul/agent/status_endpoint.go:32.2,32.17 1 0 +github.com/hashicorp/consul/agent/status_endpoint.go:24.76,26.3 1 0 +github.com/hashicorp/consul/agent/status_endpoint.go:29.65,31.3 1 0 +github.com/hashicorp/consul/agent/agent.go:127.39,129.2 1 0 +github.com/hashicorp/consul/agent/agent.go:132.61,135.2 2 0 +github.com/hashicorp/consul/agent/agent.go:419.39,452.16 3 1 +github.com/hashicorp/consul/agent/agent.go:456.2,491.4 7 1 +github.com/hashicorp/consul/agent/agent.go:499.2,499.83 1 1 +github.com/hashicorp/consul/agent/agent.go:507.2,507.16 1 1 +github.com/hashicorp/consul/agent/agent.go:452.16,454.3 1 0 +github.com/hashicorp/consul/agent/agent.go:491.4,492.26 1 1 +github.com/hashicorp/consul/agent/agent.go:495.3,495.27 1 1 +github.com/hashicorp/consul/agent/agent.go:492.26,494.4 1 0 +github.com/hashicorp/consul/agent/agent.go:495.27,497.4 1 0 +github.com/hashicorp/consul/agent/agent.go:499.83,501.17 2 0 +github.com/hashicorp/consul/agent/agent.go:504.3,504.26 1 0 +github.com/hashicorp/consul/agent/agent.go:501.17,503.4 1 0 +github.com/hashicorp/consul/agent/agent.go:514.51,518.2 3 0 +github.com/hashicorp/consul/agent/agent.go:521.58,532.40 2 1 +github.com/hashicorp/consul/agent/agent.go:535.2,535.11 1 1 +github.com/hashicorp/consul/agent/agent.go:532.40,534.3 1 1 +github.com/hashicorp/consul/agent/agent.go:539.50,546.16 4 1 +github.com/hashicorp/consul/agent/agent.go:554.2,557.63 3 1 +github.com/hashicorp/consul/agent/agent.go:563.2,569.51 2 1 +github.com/hashicorp/consul/agent/agent.go:574.2,582.16 4 1 +github.com/hashicorp/consul/agent/agent.go:587.2,587.54 1 1 +github.com/hashicorp/consul/agent/agent.go:597.2,600.16 3 1 +github.com/hashicorp/consul/agent/agent.go:605.2,605.18 1 1 +github.com/hashicorp/consul/agent/agent.go:641.2,641.34 1 1 +github.com/hashicorp/consul/agent/agent.go:647.2,650.99 3 1 +github.com/hashicorp/consul/agent/agent.go:655.2,656.62 2 1 +github.com/hashicorp/consul/agent/agent.go:659.2,659.45 1 1 +github.com/hashicorp/consul/agent/agent.go:662.2,662.42 1 1 +github.com/hashicorp/consul/agent/agent.go:666.2,667.55 2 1 +github.com/hashicorp/consul/agent/agent.go:676.2,696.16 3 1 +github.com/hashicorp/consul/agent/agent.go:700.2,719.27 4 1 +github.com/hashicorp/consul/agent/agent.go:724.2,724.37 1 1 +github.com/hashicorp/consul/agent/agent.go:729.2,729.46 1 1 +github.com/hashicorp/consul/agent/agent.go:734.2,741.16 3 1 +github.com/hashicorp/consul/agent/agent.go:746.2,746.30 1 1 +github.com/hashicorp/consul/agent/agent.go:751.2,751.47 1 1 +github.com/hashicorp/consul/agent/agent.go:756.2,759.50 2 1 +github.com/hashicorp/consul/agent/agent.go:764.2,765.25 2 1 +github.com/hashicorp/consul/agent/agent.go:769.2,769.37 1 1 +github.com/hashicorp/consul/agent/agent.go:775.2,781.32 2 1 +github.com/hashicorp/consul/agent/agent.go:795.2,795.28 1 1 +github.com/hashicorp/consul/agent/agent.go:806.2,806.12 1 1 +github.com/hashicorp/consul/agent/agent.go:546.16,548.3 1 0 +github.com/hashicorp/consul/agent/agent.go:557.63,559.3 1 0 +github.com/hashicorp/consul/agent/agent.go:569.51,571.3 1 0 +github.com/hashicorp/consul/agent/agent.go:582.16,584.3 1 0 +github.com/hashicorp/consul/agent/agent.go:587.54,588.10 1 0 +github.com/hashicorp/consul/agent/agent.go:589.23,589.23 0 0 +github.com/hashicorp/consul/agent/agent.go:590.23,590.23 0 0 +github.com/hashicorp/consul/agent/agent.go:600.16,602.3 1 0 +github.com/hashicorp/consul/agent/agent.go:605.18,607.17 2 1 +github.com/hashicorp/consul/agent/agent.go:610.3,612.57 2 1 +github.com/hashicorp/consul/agent/agent.go:607.17,609.4 1 0 +github.com/hashicorp/consul/agent/agent.go:612.57,620.46 1 1 +github.com/hashicorp/consul/agent/agent.go:623.4,624.93 2 1 +github.com/hashicorp/consul/agent/agent.go:620.46,620.77 1 0 +github.com/hashicorp/consul/agent/agent.go:624.93,626.5 1 0 +github.com/hashicorp/consul/agent/agent.go:629.8,631.17 2 0 +github.com/hashicorp/consul/agent/agent.go:634.3,634.22 1 0 +github.com/hashicorp/consul/agent/agent.go:631.17,633.4 1 0 +github.com/hashicorp/consul/agent/agent.go:641.34,641.89 1 1 +github.com/hashicorp/consul/agent/agent.go:650.99,652.3 1 0 +github.com/hashicorp/consul/agent/agent.go:656.62,658.3 1 0 +github.com/hashicorp/consul/agent/agent.go:659.45,661.3 1 0 +github.com/hashicorp/consul/agent/agent.go:662.42,664.3 1 0 +github.com/hashicorp/consul/agent/agent.go:668.15,669.31 1 1 +github.com/hashicorp/consul/agent/agent.go:670.14,671.32 1 0 +github.com/hashicorp/consul/agent/agent.go:672.10,673.112 1 0 +github.com/hashicorp/consul/agent/agent.go:696.16,698.3 1 0 +github.com/hashicorp/consul/agent/agent.go:719.27,721.3 1 1 +github.com/hashicorp/consul/agent/agent.go:724.37,726.3 1 0 +github.com/hashicorp/consul/agent/agent.go:729.46,731.3 1 0 +github.com/hashicorp/consul/agent/agent.go:741.16,743.3 1 0 +github.com/hashicorp/consul/agent/agent.go:746.30,748.3 1 1 +github.com/hashicorp/consul/agent/agent.go:751.47,753.3 1 0 +github.com/hashicorp/consul/agent/agent.go:759.50,761.3 1 0 +github.com/hashicorp/consul/agent/agent.go:765.25,767.3 1 1 +github.com/hashicorp/consul/agent/agent.go:769.37,772.3 2 0 +github.com/hashicorp/consul/agent/agent.go:781.32,784.13 3 0 +github.com/hashicorp/consul/agent/agent.go:784.13,785.54 1 0 +github.com/hashicorp/consul/agent/agent.go:785.54,788.19 3 0 +github.com/hashicorp/consul/agent/agent.go:788.19,790.6 1 0 +github.com/hashicorp/consul/agent/agent.go:795.28,800.48 2 0 +github.com/hashicorp/consul/agent/agent.go:800.48,803.4 1 0 +github.com/hashicorp/consul/agent/agent.go:818.42,820.2 1 0 +github.com/hashicorp/consul/agent/agent.go:822.44,823.67 1 1 +github.com/hashicorp/consul/agent/agent.go:828.2,829.51 2 1 +github.com/hashicorp/consul/agent/agent.go:844.2,849.43 1 1 +github.com/hashicorp/consul/agent/agent.go:855.2,859.88 3 1 +github.com/hashicorp/consul/agent/agent.go:891.2,891.27 1 1 +github.com/hashicorp/consul/agent/agent.go:904.2,904.30 1 1 +github.com/hashicorp/consul/agent/agent.go:910.2,910.12 1 1 +github.com/hashicorp/consul/agent/agent.go:823.67,825.3 1 0 +github.com/hashicorp/consul/agent/agent.go:829.51,835.52 1 1 +github.com/hashicorp/consul/agent/agent.go:838.3,838.13 1 1 +github.com/hashicorp/consul/agent/agent.go:842.3,842.19 1 1 +github.com/hashicorp/consul/agent/agent.go:835.52,835.83 1 0 +github.com/hashicorp/consul/agent/agent.go:838.13,841.4 2 1 +github.com/hashicorp/consul/agent/agent.go:849.43,851.4 1 0 +github.com/hashicorp/consul/agent/agent.go:859.88,860.21 1 1 +github.com/hashicorp/consul/agent/agent.go:864.3,865.17 2 1 +github.com/hashicorp/consul/agent/agent.go:868.3,868.21 1 1 +github.com/hashicorp/consul/agent/agent.go:873.3,873.24 1 1 +github.com/hashicorp/consul/agent/agent.go:886.3,886.13 1 1 +github.com/hashicorp/consul/agent/agent.go:860.21,862.4 1 0 +github.com/hashicorp/consul/agent/agent.go:865.17,867.4 1 0 +github.com/hashicorp/consul/agent/agent.go:868.21,871.4 2 1 +github.com/hashicorp/consul/agent/agent.go:873.24,874.33 1 1 +github.com/hashicorp/consul/agent/agent.go:874.33,881.19 3 1 +github.com/hashicorp/consul/agent/agent.go:881.19,883.6 1 0 +github.com/hashicorp/consul/agent/agent.go:891.27,894.72 2 1 +github.com/hashicorp/consul/agent/agent.go:898.3,898.69 1 1 +github.com/hashicorp/consul/agent/agent.go:894.72,897.4 2 0 +github.com/hashicorp/consul/agent/agent.go:898.69,901.4 2 0 +github.com/hashicorp/consul/agent/agent.go:904.30,905.90 1 1 +github.com/hashicorp/consul/agent/agent.go:905.90,908.4 2 0 +github.com/hashicorp/consul/agent/agent.go:913.43,916.41 3 1 +github.com/hashicorp/consul/agent/agent.go:934.2,947.30 6 1 +github.com/hashicorp/consul/agent/agent.go:962.2,962.26 1 1 +github.com/hashicorp/consul/agent/agent.go:916.41,919.17 2 1 +github.com/hashicorp/consul/agent/agent.go:922.3,926.26 3 1 +github.com/hashicorp/consul/agent/agent.go:919.17,921.4 1 0 +github.com/hashicorp/consul/agent/agent.go:926.26,928.66 2 1 +github.com/hashicorp/consul/agent/agent.go:929.4,929.62 1 1 +github.com/hashicorp/consul/agent/agent.go:928.66,928.83 1 1 +github.com/hashicorp/consul/agent/agent.go:929.62,931.5 1 0 +github.com/hashicorp/consul/agent/agent.go:947.30,948.10 1 1 +github.com/hashicorp/consul/agent/agent.go:949.24,953.5 1 1 +github.com/hashicorp/consul/agent/agent.go:955.23,956.39 1 0 +github.com/hashicorp/consul/agent/agent.go:957.18,959.28 2 0 +github.com/hashicorp/consul/agent/agent.go:968.74,971.21 2 1 +github.com/hashicorp/consul/agent/agent.go:977.2,977.29 1 1 +github.com/hashicorp/consul/agent/agent.go:1009.2,1009.17 1 1 +github.com/hashicorp/consul/agent/agent.go:971.21,972.25 1 0 +github.com/hashicorp/consul/agent/agent.go:972.25,974.4 1 0 +github.com/hashicorp/consul/agent/agent.go:977.29,981.27 3 1 +github.com/hashicorp/consul/agent/agent.go:1007.3,1007.23 1 1 +github.com/hashicorp/consul/agent/agent.go:982.22,984.18 2 0 +github.com/hashicorp/consul/agent/agent.go:989.21,991.18 2 1 +github.com/hashicorp/consul/agent/agent.go:995.4,995.51 1 1 +github.com/hashicorp/consul/agent/agent.go:997.25,999.18 2 0 +github.com/hashicorp/consul/agent/agent.go:1003.11,1005.63 2 0 +github.com/hashicorp/consul/agent/agent.go:984.18,987.5 2 0 +github.com/hashicorp/consul/agent/agent.go:991.18,994.5 2 0 +github.com/hashicorp/consul/agent/agent.go:999.18,1001.5 1 0 +github.com/hashicorp/consul/agent/agent.go:1027.51,1031.54 3 1 +github.com/hashicorp/consul/agent/agent.go:1081.2,1082.31 2 1 +github.com/hashicorp/consul/agent/agent.go:1086.2,1086.49 1 1 +github.com/hashicorp/consul/agent/agent.go:1090.2,1090.60 1 1 +github.com/hashicorp/consul/agent/agent.go:1094.2,1094.21 1 1 +github.com/hashicorp/consul/agent/agent.go:1031.54,1033.17 2 1 +github.com/hashicorp/consul/agent/agent.go:1036.3,1038.31 2 1 +github.com/hashicorp/consul/agent/agent.go:1078.3,1078.13 1 1 +github.com/hashicorp/consul/agent/agent.go:1033.17,1035.4 1 0 +github.com/hashicorp/consul/agent/agent.go:1038.31,1041.33 3 1 +github.com/hashicorp/consul/agent/agent.go:1046.4,1060.39 5 1 +github.com/hashicorp/consul/agent/agent.go:1066.4,1068.24 2 1 +github.com/hashicorp/consul/agent/agent.go:1076.4,1076.69 1 1 +github.com/hashicorp/consul/agent/agent.go:1041.33,1044.5 2 0 +github.com/hashicorp/consul/agent/agent.go:1060.39,1063.5 1 0 +github.com/hashicorp/consul/agent/agent.go:1068.24,1069.95 1 0 +github.com/hashicorp/consul/agent/agent.go:1069.95,1071.6 1 0 +github.com/hashicorp/consul/agent/agent.go:1072.10,1074.5 1 1 +github.com/hashicorp/consul/agent/agent.go:1082.31,1084.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1086.49,1089.3 2 0 +github.com/hashicorp/consul/agent/agent.go:1090.60,1093.3 2 0 +github.com/hashicorp/consul/agent/agent.go:1097.41,1098.24 1 0 +github.com/hashicorp/consul/agent/agent.go:1098.24,1100.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1105.109,1107.63 1 0 +github.com/hashicorp/consul/agent/agent.go:1127.2,1127.43 1 0 +github.com/hashicorp/consul/agent/agent.go:1107.63,1108.16 1 0 +github.com/hashicorp/consul/agent/agent.go:1122.3,1122.25 1 0 +github.com/hashicorp/consul/agent/agent.go:1109.22,1112.49 1 0 +github.com/hashicorp/consul/agent/agent.go:1113.25,1118.37 1 0 +github.com/hashicorp/consul/agent/agent.go:1136.65,1138.16 2 1 +github.com/hashicorp/consul/agent/agent.go:1141.2,1143.16 3 0 +github.com/hashicorp/consul/agent/agent.go:1138.16,1140.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1146.65,1147.50 1 0 +github.com/hashicorp/consul/agent/agent.go:1150.2,1150.63 1 0 +github.com/hashicorp/consul/agent/agent.go:1153.2,1154.16 2 0 +github.com/hashicorp/consul/agent/agent.go:1157.2,1158.68 2 0 +github.com/hashicorp/consul/agent/agent.go:1161.2,1161.15 1 0 +github.com/hashicorp/consul/agent/agent.go:1147.50,1149.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1150.63,1152.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1154.16,1156.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1158.68,1160.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1165.34,1166.34 1 1 +github.com/hashicorp/consul/agent/agent.go:1166.34,1168.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1173.64,1179.27 3 1 +github.com/hashicorp/consul/agent/agent.go:1184.2,1184.57 1 0 +github.com/hashicorp/consul/agent/agent.go:1189.2,1190.37 2 0 +github.com/hashicorp/consul/agent/agent.go:1215.2,1215.32 1 0 +github.com/hashicorp/consul/agent/agent.go:1244.2,1244.12 1 0 +github.com/hashicorp/consul/agent/agent.go:1179.27,1181.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1184.57,1186.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1190.37,1191.53 1 0 +github.com/hashicorp/consul/agent/agent.go:1201.3,1201.45 1 0 +github.com/hashicorp/consul/agent/agent.go:1207.3,1208.17 2 0 +github.com/hashicorp/consul/agent/agent.go:1211.3,1211.38 1 0 +github.com/hashicorp/consul/agent/agent.go:1191.53,1193.4 1 0 +github.com/hashicorp/consul/agent/agent.go:1193.9,1193.62 1 0 +github.com/hashicorp/consul/agent/agent.go:1193.62,1195.4 1 0 +github.com/hashicorp/consul/agent/agent.go:1201.45,1202.42 1 0 +github.com/hashicorp/consul/agent/agent.go:1202.42,1204.5 1 0 +github.com/hashicorp/consul/agent/agent.go:1208.17,1210.4 1 0 +github.com/hashicorp/consul/agent/agent.go:1215.32,1217.17 2 0 +github.com/hashicorp/consul/agent/agent.go:1222.3,1223.27 2 0 +github.com/hashicorp/consul/agent/agent.go:1217.17,1219.12 2 0 +github.com/hashicorp/consul/agent/agent.go:1223.27,1224.41 1 0 +github.com/hashicorp/consul/agent/agent.go:1232.4,1235.32 3 0 +github.com/hashicorp/consul/agent/agent.go:1239.4,1239.57 1 0 +github.com/hashicorp/consul/agent/agent.go:1224.41,1226.5 1 0 +github.com/hashicorp/consul/agent/agent.go:1226.10,1226.45 1 0 +github.com/hashicorp/consul/agent/agent.go:1226.45,1228.5 1 0 +github.com/hashicorp/consul/agent/agent.go:1228.10,1231.5 2 0 +github.com/hashicorp/consul/agent/agent.go:1235.32,1237.5 1 0 +github.com/hashicorp/consul/agent/agent.go:1239.57,1241.5 1 0 +github.com/hashicorp/consul/agent/agent.go:1249.101,1290.41 30 1 +github.com/hashicorp/consul/agent/agent.go:1294.2,1294.39 1 1 +github.com/hashicorp/consul/agent/agent.go:1315.2,1324.34 7 1 +github.com/hashicorp/consul/agent/agent.go:1331.2,1331.26 1 1 +github.com/hashicorp/consul/agent/agent.go:1334.2,1334.39 1 1 +github.com/hashicorp/consul/agent/agent.go:1337.2,1337.33 1 1 +github.com/hashicorp/consul/agent/agent.go:1340.2,1340.37 1 1 +github.com/hashicorp/consul/agent/agent.go:1343.2,1343.32 1 1 +github.com/hashicorp/consul/agent/agent.go:1346.2,1346.34 1 1 +github.com/hashicorp/consul/agent/agent.go:1349.2,1349.43 1 1 +github.com/hashicorp/consul/agent/agent.go:1352.2,1352.42 1 1 +github.com/hashicorp/consul/agent/agent.go:1355.2,1355.38 1 1 +github.com/hashicorp/consul/agent/agent.go:1358.2,1358.48 1 1 +github.com/hashicorp/consul/agent/agent.go:1361.2,1363.39 3 1 +github.com/hashicorp/consul/agent/agent.go:1366.2,1366.35 1 1 +github.com/hashicorp/consul/agent/agent.go:1369.2,1369.28 1 1 +github.com/hashicorp/consul/agent/agent.go:1375.2,1385.29 9 1 +github.com/hashicorp/consul/agent/agent.go:1390.2,1390.33 1 1 +github.com/hashicorp/consul/agent/agent.go:1393.2,1393.32 1 1 +github.com/hashicorp/consul/agent/agent.go:1398.2,1398.40 1 1 +github.com/hashicorp/consul/agent/agent.go:1401.2,1401.41 1 1 +github.com/hashicorp/consul/agent/agent.go:1407.2,1412.35 4 1 +github.com/hashicorp/consul/agent/agent.go:1418.2,1418.35 1 1 +github.com/hashicorp/consul/agent/agent.go:1423.2,1424.23 2 1 +github.com/hashicorp/consul/agent/agent.go:1427.2,1437.31 6 1 +github.com/hashicorp/consul/agent/agent.go:1450.2,1464.63 11 1 +github.com/hashicorp/consul/agent/agent.go:1468.2,1479.17 7 1 +github.com/hashicorp/consul/agent/agent.go:1290.41,1292.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1294.39,1307.42 13 1 +github.com/hashicorp/consul/agent/agent.go:1307.42,1309.4 1 0 +github.com/hashicorp/consul/agent/agent.go:1310.8,1313.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1324.34,1326.17 2 0 +github.com/hashicorp/consul/agent/agent.go:1329.3,1329.26 1 0 +github.com/hashicorp/consul/agent/agent.go:1326.17,1328.4 1 0 +github.com/hashicorp/consul/agent/agent.go:1331.26,1333.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1334.39,1336.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1337.33,1339.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1340.37,1342.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1343.32,1345.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1346.34,1348.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1349.43,1351.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1352.42,1354.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1355.38,1357.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1358.48,1360.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1363.39,1365.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1366.35,1368.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1369.28,1371.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1385.29,1387.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1390.33,1392.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1393.32,1395.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1398.40,1400.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1401.41,1403.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1412.35,1414.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1418.35,1420.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1424.23,1426.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1437.31,1442.17 4 1 +github.com/hashicorp/consul/agent/agent.go:1446.3,1446.20 1 1 +github.com/hashicorp/consul/agent/agent.go:1442.17,1444.4 1 0 +github.com/hashicorp/consul/agent/agent.go:1464.63,1466.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1483.83,1486.36 2 0 +github.com/hashicorp/consul/agent/agent.go:1524.2,1524.22 1 0 +github.com/hashicorp/consul/agent/agent.go:1486.36,1496.38 7 0 +github.com/hashicorp/consul/agent/agent.go:1499.3,1499.55 1 0 +github.com/hashicorp/consul/agent/agent.go:1502.3,1502.55 1 0 +github.com/hashicorp/consul/agent/agent.go:1506.3,1507.20 2 0 +github.com/hashicorp/consul/agent/agent.go:1514.3,1521.5 1 0 +github.com/hashicorp/consul/agent/agent.go:1496.38,1498.4 1 0 +github.com/hashicorp/consul/agent/agent.go:1499.55,1501.4 1 0 +github.com/hashicorp/consul/agent/agent.go:1502.55,1504.4 1 0 +github.com/hashicorp/consul/agent/agent.go:1507.20,1512.4 1 0 +github.com/hashicorp/consul/agent/agent.go:1531.74,1533.9 2 0 +github.com/hashicorp/consul/agent/agent.go:1536.2,1540.48 5 0 +github.com/hashicorp/consul/agent/agent.go:1533.9,1534.34 1 0 +github.com/hashicorp/consul/agent/agent.go:1545.79,1548.26 2 1 +github.com/hashicorp/consul/agent/agent.go:1554.2,1555.44 2 1 +github.com/hashicorp/consul/agent/agent.go:1548.26,1550.38 2 0 +github.com/hashicorp/consul/agent/agent.go:1550.38,1552.4 1 0 +github.com/hashicorp/consul/agent/agent.go:1559.31,1561.2 1 0 +github.com/hashicorp/consul/agent/agent.go:1566.39,1570.16 3 1 +github.com/hashicorp/consul/agent/agent.go:1573.2,1578.32 3 1 +github.com/hashicorp/consul/agent/agent.go:1582.2,1592.29 6 1 +github.com/hashicorp/consul/agent/agent.go:1597.2,1597.38 1 1 +github.com/hashicorp/consul/agent/agent.go:1600.2,1600.34 1 1 +github.com/hashicorp/consul/agent/agent.go:1603.2,1603.35 1 1 +github.com/hashicorp/consul/agent/agent.go:1606.2,1606.34 1 1 +github.com/hashicorp/consul/agent/agent.go:1609.2,1609.34 1 1 +github.com/hashicorp/consul/agent/agent.go:1612.2,1612.35 1 1 +github.com/hashicorp/consul/agent/agent.go:1615.2,1615.37 1 1 +github.com/hashicorp/consul/agent/agent.go:1618.2,1618.37 1 1 +github.com/hashicorp/consul/agent/agent.go:1621.2,1621.37 1 1 +github.com/hashicorp/consul/agent/agent.go:1626.2,1626.33 1 1 +github.com/hashicorp/consul/agent/agent.go:1631.2,1631.26 1 1 +github.com/hashicorp/consul/agent/agent.go:1636.2,1636.20 1 1 +github.com/hashicorp/consul/agent/agent.go:1640.2,1643.28 2 1 +github.com/hashicorp/consul/agent/agent.go:1647.2,1648.23 2 1 +github.com/hashicorp/consul/agent/agent.go:1657.2,1658.19 2 1 +github.com/hashicorp/consul/agent/agent.go:1662.2,1665.12 4 1 +github.com/hashicorp/consul/agent/agent.go:1570.16,1572.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1578.32,1580.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1592.29,1594.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1597.38,1599.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1600.34,1602.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1603.35,1605.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1606.34,1608.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1609.34,1611.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1612.35,1614.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1615.37,1617.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1618.37,1620.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1621.37,1623.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1626.33,1628.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1631.26,1633.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1636.20,1638.3 1 1 +github.com/hashicorp/consul/agent/agent.go:1643.28,1645.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1648.23,1650.47 2 1 +github.com/hashicorp/consul/agent/agent.go:1650.47,1652.4 1 1 +github.com/hashicorp/consul/agent/agent.go:1652.9,1654.4 1 0 +github.com/hashicorp/consul/agent/agent.go:1658.19,1660.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1671.37,1677.35 4 1 +github.com/hashicorp/consul/agent/agent.go:1687.2,1691.55 4 1 +github.com/hashicorp/consul/agent/agent.go:1694.2,1694.33 1 1 +github.com/hashicorp/consul/agent/agent.go:1677.35,1678.24 1 1 +github.com/hashicorp/consul/agent/agent.go:1678.24,1685.4 2 1 +github.com/hashicorp/consul/agent/agent.go:1691.55,1693.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1699.44,1701.2 1 0 +github.com/hashicorp/consul/agent/agent.go:1705.46,1707.2 1 1 +github.com/hashicorp/consul/agent/agent.go:1710.89,1713.16 3 0 +github.com/hashicorp/consul/agent/agent.go:1726.2,1726.8 1 0 +github.com/hashicorp/consul/agent/agent.go:1713.16,1715.31 2 0 +github.com/hashicorp/consul/agent/agent.go:1715.31,1716.76 1 0 +github.com/hashicorp/consul/agent/agent.go:1716.76,1718.5 1 0 +github.com/hashicorp/consul/agent/agent.go:1720.8,1725.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1730.60,1732.48 2 0 +github.com/hashicorp/consul/agent/agent.go:1737.2,1737.16 1 0 +github.com/hashicorp/consul/agent/agent.go:1745.2,1745.8 1 0 +github.com/hashicorp/consul/agent/agent.go:1732.48,1734.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1734.8,1736.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1737.16,1739.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1739.8,1744.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1751.70,1752.48 1 0 +github.com/hashicorp/consul/agent/agent.go:1755.2,1755.12 1 0 +github.com/hashicorp/consul/agent/agent.go:1752.48,1754.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1759.75,1760.48 1 0 +github.com/hashicorp/consul/agent/agent.go:1763.2,1763.11 1 0 +github.com/hashicorp/consul/agent/agent.go:1760.48,1762.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1768.78,1769.48 1 0 +github.com/hashicorp/consul/agent/agent.go:1773.2,1773.88 1 0 +github.com/hashicorp/consul/agent/agent.go:1769.48,1772.3 2 0 +github.com/hashicorp/consul/agent/agent.go:1777.88,1781.16 3 0 +github.com/hashicorp/consul/agent/agent.go:1787.2,1787.12 1 0 +github.com/hashicorp/consul/agent/agent.go:1781.16,1786.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1791.91,1795.9 3 0 +github.com/hashicorp/consul/agent/agent.go:1799.2,1800.16 2 0 +github.com/hashicorp/consul/agent/agent.go:1806.2,1806.12 1 0 +github.com/hashicorp/consul/agent/agent.go:1795.9,1797.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1800.16,1805.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1810.48,1812.2 1 0 +github.com/hashicorp/consul/agent/agent.go:1816.60,1818.2 1 1 +github.com/hashicorp/consul/agent/agent.go:1827.77,1829.2 1 0 +github.com/hashicorp/consul/agent/agent.go:1832.44,1833.48 1 0 +github.com/hashicorp/consul/agent/agent.go:1836.2,1836.12 1 0 +github.com/hashicorp/consul/agent/agent.go:1833.48,1835.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1841.29,1844.2 2 1 +github.com/hashicorp/consul/agent/agent.go:1849.29,1856.21 4 0 +github.com/hashicorp/consul/agent/agent.go:1856.21,1858.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1862.30,1871.14 2 0 +github.com/hashicorp/consul/agent/agent.go:1878.2,1881.21 3 0 +github.com/hashicorp/consul/agent/agent.go:1871.14,1875.3 1 0 +github.com/hashicorp/consul/agent/agent.go:1881.21,1884.3 2 0 +github.com/hashicorp/consul/agent/agent.go:1889.48,1893.2 3 0 +github.com/hashicorp/consul/agent/agent.go:1897.63,1899.2 1 0 +github.com/hashicorp/consul/agent/agent.go:1903.34,1905.6 1 1 +github.com/hashicorp/consul/agent/agent.go:1905.6,1911.10 5 1 +github.com/hashicorp/consul/agent/agent.go:1912.27,1915.18 3 0 +github.com/hashicorp/consul/agent/agent.go:1919.4,1919.13 1 0 +github.com/hashicorp/consul/agent/agent.go:1924.4,1925.18 2 0 +github.com/hashicorp/consul/agent/agent.go:1930.4,1930.35 1 0 +github.com/hashicorp/consul/agent/agent.go:1953.23,1954.10 1 1 +github.com/hashicorp/consul/agent/agent.go:1915.18,1917.13 2 0 +github.com/hashicorp/consul/agent/agent.go:1919.13,1921.13 2 0 +github.com/hashicorp/consul/agent/agent.go:1925.18,1927.13 2 0 +github.com/hashicorp/consul/agent/agent.go:1930.35,1943.68 4 0 +github.com/hashicorp/consul/agent/agent.go:1943.68,1944.40 1 0 +github.com/hashicorp/consul/agent/agent.go:1950.6,1950.20 1 0 +github.com/hashicorp/consul/agent/agent.go:1944.40,1947.7 2 0 +github.com/hashicorp/consul/agent/agent.go:1947.12,1949.7 1 0 +github.com/hashicorp/consul/agent/agent.go:1960.40,1962.60 2 0 +github.com/hashicorp/consul/agent/agent.go:1962.60,1966.25 2 0 +github.com/hashicorp/consul/agent/agent.go:1972.3,1972.24 1 0 +github.com/hashicorp/consul/agent/agent.go:1978.3,1984.48 4 0 +github.com/hashicorp/consul/agent/agent.go:1966.25,1967.12 1 0 +github.com/hashicorp/consul/agent/agent.go:1972.24,1973.12 1 0 +github.com/hashicorp/consul/agent/agent.go:1984.48,1986.53 2 0 +github.com/hashicorp/consul/agent/agent.go:1986.53,1993.5 1 0 +github.com/hashicorp/consul/agent/agent.go:1993.10,1999.5 1 0 +github.com/hashicorp/consul/agent/agent.go:2006.32,2007.6 1 1 +github.com/hashicorp/consul/agent/agent.go:2007.6,2008.10 1 1 +github.com/hashicorp/consul/agent/agent.go:2009.49,2010.28 1 0 +github.com/hashicorp/consul/agent/agent.go:2012.23,2013.10 1 1 +github.com/hashicorp/consul/agent/agent.go:2032.69,2034.2 1 0 +github.com/hashicorp/consul/agent/agent.go:2037.89,2048.16 5 0 +github.com/hashicorp/consul/agent/agent.go:2052.2,2052.43 1 0 +github.com/hashicorp/consul/agent/agent.go:2048.16,2050.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2056.65,2058.44 2 0 +github.com/hashicorp/consul/agent/agent.go:2061.2,2061.12 1 0 +github.com/hashicorp/consul/agent/agent.go:2058.44,2060.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2065.113,2078.16 5 0 +github.com/hashicorp/consul/agent/agent.go:2082.2,2082.45 1 0 +github.com/hashicorp/consul/agent/agent.go:2078.16,2080.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2086.59,2088.46 2 0 +github.com/hashicorp/consul/agent/agent.go:2091.2,2091.12 1 0 +github.com/hashicorp/consul/agent/agent.go:2088.46,2090.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2103.79,2105.2 1 0 +github.com/hashicorp/consul/agent/agent.go:2107.114,2116.16 3 0 +github.com/hashicorp/consul/agent/agent.go:2120.2,2124.47 3 0 +github.com/hashicorp/consul/agent/agent.go:2128.2,2128.46 1 0 +github.com/hashicorp/consul/agent/agent.go:2116.16,2118.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2124.47,2126.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2131.71,2133.47 2 0 +github.com/hashicorp/consul/agent/agent.go:2136.2,2136.12 1 0 +github.com/hashicorp/consul/agent/agent.go:2133.47,2135.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2139.109,2144.16 4 1 +github.com/hashicorp/consul/agent/agent.go:2151.2,2151.27 1 0 +github.com/hashicorp/consul/agent/agent.go:2211.2,2211.17 1 0 +github.com/hashicorp/consul/agent/agent.go:2144.16,2145.25 1 1 +github.com/hashicorp/consul/agent/agent.go:2148.3,2148.86 1 0 +github.com/hashicorp/consul/agent/agent.go:2145.25,2147.4 1 1 +github.com/hashicorp/consul/agent/agent.go:2151.27,2153.17 1 0 +github.com/hashicorp/consul/agent/agent.go:2158.3,2158.42 1 0 +github.com/hashicorp/consul/agent/agent.go:2164.3,2166.17 3 0 +github.com/hashicorp/consul/agent/agent.go:2171.3,2172.49 2 0 +github.com/hashicorp/consul/agent/agent.go:2180.3,2184.22 3 0 +github.com/hashicorp/consul/agent/agent.go:2194.3,2194.97 1 0 +github.com/hashicorp/consul/agent/agent.go:2208.3,2208.30 1 0 +github.com/hashicorp/consul/agent/agent.go:2153.17,2154.12 1 0 +github.com/hashicorp/consul/agent/agent.go:2158.42,2160.12 2 0 +github.com/hashicorp/consul/agent/agent.go:2166.17,2168.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2172.49,2177.12 2 0 +github.com/hashicorp/consul/agent/agent.go:2184.22,2185.51 1 0 +github.com/hashicorp/consul/agent/agent.go:2185.51,2191.5 1 0 +github.com/hashicorp/consul/agent/agent.go:2194.97,2199.42 2 0 +github.com/hashicorp/consul/agent/agent.go:2205.4,2205.12 1 0 +github.com/hashicorp/consul/agent/agent.go:2199.42,2204.5 1 0 +github.com/hashicorp/consul/agent/agent.go:2217.57,2227.2 4 0 +github.com/hashicorp/consul/agent/agent.go:2231.69,2233.44 1 0 +github.com/hashicorp/consul/agent/agent.go:2247.2,2249.69 2 0 +github.com/hashicorp/consul/agent/agent.go:2253.2,2253.102 1 0 +github.com/hashicorp/consul/agent/agent.go:2257.2,2258.86 2 0 +github.com/hashicorp/consul/agent/agent.go:2233.44,2234.27 1 0 +github.com/hashicorp/consul/agent/agent.go:2242.3,2242.28 1 0 +github.com/hashicorp/consul/agent/agent.go:2234.27,2236.18 2 0 +github.com/hashicorp/consul/agent/agent.go:2239.4,2239.27 1 0 +github.com/hashicorp/consul/agent/agent.go:2236.18,2238.5 1 0 +github.com/hashicorp/consul/agent/agent.go:2242.28,2244.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2249.69,2251.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2253.102,2255.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2307.73,2318.36 7 0 +github.com/hashicorp/consul/agent/agent.go:2321.2,2321.94 1 0 +github.com/hashicorp/consul/agent/agent.go:2324.2,2324.94 1 0 +github.com/hashicorp/consul/agent/agent.go:2327.2,2327.94 1 0 +github.com/hashicorp/consul/agent/agent.go:2330.2,2330.94 1 0 +github.com/hashicorp/consul/agent/agent.go:2334.2,2339.85 3 0 +github.com/hashicorp/consul/agent/agent.go:2346.2,2346.35 1 0 +github.com/hashicorp/consul/agent/agent.go:2351.2,2351.39 1 0 +github.com/hashicorp/consul/agent/agent.go:2408.2,2412.41 4 0 +github.com/hashicorp/consul/agent/agent.go:2416.2,2416.31 1 0 +github.com/hashicorp/consul/agent/agent.go:2423.2,2424.16 2 0 +github.com/hashicorp/consul/agent/agent.go:2429.2,2431.24 3 0 +github.com/hashicorp/consul/agent/agent.go:2448.2,2450.33 2 0 +github.com/hashicorp/consul/agent/agent.go:2461.2,2461.56 1 0 +github.com/hashicorp/consul/agent/agent.go:2476.2,2476.39 1 0 +github.com/hashicorp/consul/agent/agent.go:2487.2,2487.31 1 0 +github.com/hashicorp/consul/agent/agent.go:2495.2,2495.12 1 0 +github.com/hashicorp/consul/agent/agent.go:2318.36,2320.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2321.94,2323.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2324.94,2326.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2327.94,2329.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2330.94,2332.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2339.85,2341.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2346.35,2348.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2351.39,2353.20 2 0 +github.com/hashicorp/consul/agent/agent.go:2360.3,2364.17 4 0 +github.com/hashicorp/consul/agent/agent.go:2368.3,2370.28 3 0 +github.com/hashicorp/consul/agent/agent.go:2373.3,2373.27 1 0 +github.com/hashicorp/consul/agent/agent.go:2377.3,2391.27 2 0 +github.com/hashicorp/consul/agent/agent.go:2396.3,2397.9 2 0 +github.com/hashicorp/consul/agent/agent.go:2402.3,2402.33 1 0 +github.com/hashicorp/consul/agent/agent.go:2353.20,2355.29 2 0 +github.com/hashicorp/consul/agent/agent.go:2355.29,2357.5 1 0 +github.com/hashicorp/consul/agent/agent.go:2364.17,2366.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2370.28,2372.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2373.27,2375.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2391.27,2393.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2397.9,2400.4 2 0 +github.com/hashicorp/consul/agent/agent.go:2412.41,2414.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2416.31,2418.40 2 0 +github.com/hashicorp/consul/agent/agent.go:2418.40,2420.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2424.16,2427.3 2 0 +github.com/hashicorp/consul/agent/agent.go:2431.24,2432.92 1 0 +github.com/hashicorp/consul/agent/agent.go:2437.3,2437.40 1 0 +github.com/hashicorp/consul/agent/agent.go:2432.92,2435.4 2 0 +github.com/hashicorp/consul/agent/agent.go:2437.40,2438.77 1 0 +github.com/hashicorp/consul/agent/agent.go:2438.77,2442.5 2 0 +github.com/hashicorp/consul/agent/agent.go:2450.33,2452.17 2 0 +github.com/hashicorp/consul/agent/agent.go:2452.17,2454.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2455.8,2459.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2461.56,2463.40 2 0 +github.com/hashicorp/consul/agent/agent.go:2469.3,2469.17 1 0 +github.com/hashicorp/consul/agent/agent.go:2463.40,2465.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2465.9,2467.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2469.17,2472.4 2 0 +github.com/hashicorp/consul/agent/agent.go:2476.39,2477.32 1 0 +github.com/hashicorp/consul/agent/agent.go:2481.3,2481.70 1 0 +github.com/hashicorp/consul/agent/agent.go:2477.32,2479.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2481.70,2484.4 2 0 +github.com/hashicorp/consul/agent/agent.go:2487.31,2488.45 1 0 +github.com/hashicorp/consul/agent/agent.go:2488.45,2489.13 1 0 +github.com/hashicorp/consul/agent/agent.go:2489.13,2491.5 1 0 +github.com/hashicorp/consul/agent/agent.go:2500.100,2501.27 1 0 +github.com/hashicorp/consul/agent/agent.go:2504.2,2504.47 1 0 +github.com/hashicorp/consul/agent/agent.go:2507.2,2507.33 1 0 +github.com/hashicorp/consul/agent/agent.go:2515.2,2515.28 1 0 +github.com/hashicorp/consul/agent/agent.go:2520.2,2520.52 1 0 +github.com/hashicorp/consul/agent/agent.go:2535.2,2535.35 1 0 +github.com/hashicorp/consul/agent/agent.go:2552.2,2552.36 1 0 +github.com/hashicorp/consul/agent/agent.go:2579.2,2579.12 1 0 +github.com/hashicorp/consul/agent/agent.go:2501.27,2503.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2504.47,2506.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2507.33,2508.42 1 0 +github.com/hashicorp/consul/agent/agent.go:2508.42,2510.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2515.28,2517.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2520.52,2526.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2526.8,2526.54 1 0 +github.com/hashicorp/consul/agent/agent.go:2526.54,2532.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2535.35,2536.41 1 0 +github.com/hashicorp/consul/agent/agent.go:2536.41,2542.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2542.9,2542.43 1 0 +github.com/hashicorp/consul/agent/agent.go:2542.43,2548.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2552.36,2553.74 1 0 +github.com/hashicorp/consul/agent/agent.go:2559.3,2559.74 1 0 +github.com/hashicorp/consul/agent/agent.go:2565.3,2565.74 1 0 +github.com/hashicorp/consul/agent/agent.go:2571.3,2571.74 1 0 +github.com/hashicorp/consul/agent/agent.go:2553.74,2555.36 2 0 +github.com/hashicorp/consul/agent/agent.go:2555.36,2557.5 1 0 +github.com/hashicorp/consul/agent/agent.go:2559.74,2561.36 2 0 +github.com/hashicorp/consul/agent/agent.go:2561.36,2563.5 1 0 +github.com/hashicorp/consul/agent/agent.go:2565.74,2567.36 2 0 +github.com/hashicorp/consul/agent/agent.go:2567.36,2569.5 1 0 +github.com/hashicorp/consul/agent/agent.go:2571.74,2573.36 2 0 +github.com/hashicorp/consul/agent/agent.go:2573.36,2575.5 1 0 +github.com/hashicorp/consul/agent/agent.go:2584.98,2585.31 1 0 +github.com/hashicorp/consul/agent/agent.go:2609.2,2609.30 1 0 +github.com/hashicorp/consul/agent/agent.go:2585.31,2586.50 1 0 +github.com/hashicorp/consul/agent/agent.go:2592.3,2592.43 1 0 +github.com/hashicorp/consul/agent/agent.go:2598.3,2598.49 1 0 +github.com/hashicorp/consul/agent/agent.go:2604.3,2604.58 1 0 +github.com/hashicorp/consul/agent/agent.go:2586.50,2591.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2592.43,2597.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2598.49,2603.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2604.58,2606.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2609.30,2611.48 2 0 +github.com/hashicorp/consul/agent/agent.go:2617.3,2617.41 1 0 +github.com/hashicorp/consul/agent/agent.go:2611.48,2616.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2617.41,2622.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2628.66,2630.2 1 0 +github.com/hashicorp/consul/agent/agent.go:2632.80,2636.2 3 0 +github.com/hashicorp/consul/agent/agent.go:2640.86,2642.24 1 0 +github.com/hashicorp/consul/agent/agent.go:2647.2,2647.41 1 0 +github.com/hashicorp/consul/agent/agent.go:2653.2,2655.16 2 0 +github.com/hashicorp/consul/agent/agent.go:2660.2,2662.25 3 0 +github.com/hashicorp/consul/agent/agent.go:2667.2,2667.77 1 0 +github.com/hashicorp/consul/agent/agent.go:2676.2,2676.13 1 0 +github.com/hashicorp/consul/agent/agent.go:2686.2,2686.30 1 0 +github.com/hashicorp/consul/agent/agent.go:2692.2,2695.52 2 0 +github.com/hashicorp/consul/agent/agent.go:2642.24,2644.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2647.41,2649.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2655.16,2658.3 2 0 +github.com/hashicorp/consul/agent/agent.go:2662.25,2664.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2667.77,2673.3 2 0 +github.com/hashicorp/consul/agent/agent.go:2676.13,2677.51 1 0 +github.com/hashicorp/consul/agent/agent.go:2680.3,2680.57 1 0 +github.com/hashicorp/consul/agent/agent.go:2677.51,2679.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2680.57,2682.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2686.30,2687.63 1 0 +github.com/hashicorp/consul/agent/agent.go:2687.63,2689.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2698.88,2700.60 2 0 +github.com/hashicorp/consul/agent/agent.go:2712.2,2712.12 1 0 +github.com/hashicorp/consul/agent/agent.go:2700.60,2703.41 1 0 +github.com/hashicorp/consul/agent/agent.go:2703.41,2706.18 2 0 +github.com/hashicorp/consul/agent/agent.go:2706.18,2708.5 1 0 +github.com/hashicorp/consul/agent/agent.go:2719.137,2723.2 3 0 +github.com/hashicorp/consul/agent/agent.go:2725.143,2730.27 3 0 +github.com/hashicorp/consul/agent/agent.go:2739.2,2739.41 1 0 +github.com/hashicorp/consul/agent/agent.go:2744.2,2746.15 3 0 +github.com/hashicorp/consul/agent/agent.go:2752.2,2753.16 2 0 +github.com/hashicorp/consul/agent/agent.go:2759.2,2760.16 2 0 +github.com/hashicorp/consul/agent/agent.go:2765.2,2765.39 1 0 +github.com/hashicorp/consul/agent/agent.go:2769.2,2769.12 1 0 +github.com/hashicorp/consul/agent/agent.go:2730.27,2733.21 3 0 +github.com/hashicorp/consul/agent/agent.go:2733.21,2735.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2739.41,2741.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2746.15,2747.22 1 0 +github.com/hashicorp/consul/agent/agent.go:2747.22,2749.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2753.16,2756.3 2 0 +github.com/hashicorp/consul/agent/agent.go:2760.16,2762.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2765.39,2767.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2772.153,2773.25 1 0 +github.com/hashicorp/consul/agent/agent.go:2777.2,2777.20 1 0 +github.com/hashicorp/consul/agent/agent.go:2793.2,2793.27 1 0 +github.com/hashicorp/consul/agent/agent.go:2800.2,2800.20 1 0 +github.com/hashicorp/consul/agent/agent.go:3195.2,3195.12 1 0 +github.com/hashicorp/consul/agent/agent.go:2773.25,2775.3 1 0 +github.com/hashicorp/consul/agent/agent.go:2777.20,2778.44 1 0 +github.com/hashicorp/consul/agent/agent.go:2782.3,2782.25 1 0 +github.com/hashicorp/consul/agent/agent.go:2778.44,2780.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2782.25,2783.72 1 0 +github.com/hashicorp/consul/agent/agent.go:2787.4,2787.74 1 0 +github.com/hashicorp/consul/agent/agent.go:2783.72,2785.5 1 0 +github.com/hashicorp/consul/agent/agent.go:2787.74,2789.5 1 0 +github.com/hashicorp/consul/agent/agent.go:2793.27,2797.3 3 0 +github.com/hashicorp/consul/agent/agent.go:2800.20,2802.25 2 0 +github.com/hashicorp/consul/agent/agent.go:2805.3,2805.73 1 0 +github.com/hashicorp/consul/agent/agent.go:2810.3,2810.41 1 0 +github.com/hashicorp/consul/agent/agent.go:2816.3,2817.21 2 0 +github.com/hashicorp/consul/agent/agent.go:2828.3,2833.10 4 0 +github.com/hashicorp/consul/agent/agent.go:3172.3,3173.29 2 0 +github.com/hashicorp/consul/agent/agent.go:3180.3,3180.49 1 0 +github.com/hashicorp/consul/agent/agent.go:2802.25,2804.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2805.73,2807.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2810.41,2812.4 1 0 +github.com/hashicorp/consul/agent/agent.go:2817.21,2820.66 1 0 +github.com/hashicorp/consul/agent/agent.go:2820.66,2821.53 1 0 +github.com/hashicorp/consul/agent/agent.go:2821.53,2823.11 2 0 +github.com/hashicorp/consul/agent/agent.go:2835.24,2836.44 1 0 +github.com/hashicorp/consul/agent/agent.go:2841.4,2851.50 2 0 +github.com/hashicorp/consul/agent/agent.go:2858.4,2859.26 2 0 +github.com/hashicorp/consul/agent/agent.go:2861.25,2862.45 1 0 +github.com/hashicorp/consul/agent/agent.go:2866.4,2866.45 1 0 +github.com/hashicorp/consul/agent/agent.go:2874.4,2892.49 3 0 +github.com/hashicorp/consul/agent/agent.go:2905.4,2906.28 2 0 +github.com/hashicorp/consul/agent/agent.go:2908.24,2909.44 1 0 +github.com/hashicorp/consul/agent/agent.go:2913.4,2913.45 1 0 +github.com/hashicorp/consul/agent/agent.go:2921.4,2931.26 3 0 +github.com/hashicorp/consul/agent/agent.go:2933.24,2934.44 1 0 +github.com/hashicorp/consul/agent/agent.go:2938.4,2938.45 1 0 +github.com/hashicorp/consul/agent/agent.go:2946.4,2956.26 3 0 +github.com/hashicorp/consul/agent/agent.go:2958.25,2959.45 1 0 +github.com/hashicorp/consul/agent/agent.go:2963.4,2963.45 1 0 +github.com/hashicorp/consul/agent/agent.go:2971.4,2972.26 2 0 +github.com/hashicorp/consul/agent/agent.go:2976.4,2987.49 2 0 +github.com/hashicorp/consul/agent/agent.go:3000.4,3001.28 2 0 +github.com/hashicorp/consul/agent/agent.go:3003.27,3004.47 1 0 +github.com/hashicorp/consul/agent/agent.go:3008.4,3008.45 1 0 +github.com/hashicorp/consul/agent/agent.go:3016.4,3016.29 1 0 +github.com/hashicorp/consul/agent/agent.go:3026.4,3038.37 3 0 +github.com/hashicorp/consul/agent/agent.go:3040.30,3041.50 1 0 +github.com/hashicorp/consul/agent/agent.go:3045.4,3045.45 1 0 +github.com/hashicorp/consul/agent/agent.go:3053.4,3053.32 1 0 +github.com/hashicorp/consul/agent/agent.go:3063.4,3074.43 3 0 +github.com/hashicorp/consul/agent/agent.go:3076.28,3077.48 1 0 +github.com/hashicorp/consul/agent/agent.go:3081.4,3081.45 1 0 +github.com/hashicorp/consul/agent/agent.go:3088.4,3100.34 3 0 +github.com/hashicorp/consul/agent/agent.go:3102.27,3103.47 1 0 +github.com/hashicorp/consul/agent/agent.go:3107.4,3107.45 1 0 +github.com/hashicorp/consul/agent/agent.go:3114.4,3115.28 2 0 +github.com/hashicorp/consul/agent/agent.go:3120.4,3132.32 3 0 +github.com/hashicorp/consul/agent/agent.go:3134.26,3135.47 1 0 +github.com/hashicorp/consul/agent/agent.go:3140.4,3149.19 5 0 +github.com/hashicorp/consul/agent/agent.go:3153.4,3164.33 4 0 +github.com/hashicorp/consul/agent/agent.go:3166.11,3167.48 1 0 +github.com/hashicorp/consul/agent/agent.go:2836.44,2839.5 2 0 +github.com/hashicorp/consul/agent/agent.go:2851.50,2856.5 1 0 +github.com/hashicorp/consul/agent/agent.go:2862.45,2865.5 2 0 +github.com/hashicorp/consul/agent/agent.go:2866.45,2872.5 2 0 +github.com/hashicorp/consul/agent/agent.go:2892.49,2894.19 2 0 +github.com/hashicorp/consul/agent/agent.go:2901.5,2902.29 2 0 +github.com/hashicorp/consul/agent/agent.go:2894.19,2900.6 2 0 +github.com/hashicorp/consul/agent/agent.go:2909.44,2912.5 2 0 +github.com/hashicorp/consul/agent/agent.go:2913.45,2919.5 2 0 +github.com/hashicorp/consul/agent/agent.go:2934.44,2937.5 2 0 +github.com/hashicorp/consul/agent/agent.go:2938.45,2944.5 2 0 +github.com/hashicorp/consul/agent/agent.go:2959.45,2962.5 2 0 +github.com/hashicorp/consul/agent/agent.go:2963.45,2969.5 2 0 +github.com/hashicorp/consul/agent/agent.go:2972.26,2974.5 1 0 +github.com/hashicorp/consul/agent/agent.go:2987.49,2989.19 2 0 +github.com/hashicorp/consul/agent/agent.go:2996.5,2997.29 2 0 +github.com/hashicorp/consul/agent/agent.go:2989.19,2995.6 2 0 +github.com/hashicorp/consul/agent/agent.go:3004.47,3007.5 2 0 +github.com/hashicorp/consul/agent/agent.go:3008.45,3014.5 2 0 +github.com/hashicorp/consul/agent/agent.go:3016.29,3018.19 2 0 +github.com/hashicorp/consul/agent/agent.go:3022.5,3023.24 2 0 +github.com/hashicorp/consul/agent/agent.go:3018.19,3021.6 2 0 +github.com/hashicorp/consul/agent/agent.go:3041.50,3044.5 2 0 +github.com/hashicorp/consul/agent/agent.go:3045.45,3051.5 2 0 +github.com/hashicorp/consul/agent/agent.go:3053.32,3055.19 2 0 +github.com/hashicorp/consul/agent/agent.go:3059.5,3060.29 2 0 +github.com/hashicorp/consul/agent/agent.go:3055.19,3058.6 2 0 +github.com/hashicorp/consul/agent/agent.go:3077.48,3080.5 2 0 +github.com/hashicorp/consul/agent/agent.go:3081.45,3087.5 2 0 +github.com/hashicorp/consul/agent/agent.go:3103.47,3106.5 2 0 +github.com/hashicorp/consul/agent/agent.go:3107.45,3113.5 2 0 +github.com/hashicorp/consul/agent/agent.go:3115.28,3118.5 2 0 +github.com/hashicorp/consul/agent/agent.go:3135.47,3138.5 2 0 +github.com/hashicorp/consul/agent/agent.go:3149.19,3151.5 1 0 +github.com/hashicorp/consul/agent/agent.go:3173.29,3174.11 1 0 +github.com/hashicorp/consul/agent/agent.go:3175.33,3175.33 0 0 +github.com/hashicorp/consul/agent/agent.go:3176.12,3176.12 0 0 +github.com/hashicorp/consul/agent/agent.go:3180.49,3182.53 2 0 +github.com/hashicorp/consul/agent/agent.go:3189.4,3189.35 1 0 +github.com/hashicorp/consul/agent/agent.go:3182.53,3188.5 2 0 +github.com/hashicorp/consul/agent/agent.go:3190.9,3192.4 1 0 +github.com/hashicorp/consul/agent/agent.go:3200.74,3204.2 3 0 +github.com/hashicorp/consul/agent/agent.go:3208.80,3210.22 1 0 +github.com/hashicorp/consul/agent/agent.go:3216.2,3217.43 2 0 +github.com/hashicorp/consul/agent/agent.go:3221.2,3222.28 2 0 +github.com/hashicorp/consul/agent/agent.go:3231.2,3237.13 5 0 +github.com/hashicorp/consul/agent/agent.go:3246.2,3247.12 2 0 +github.com/hashicorp/consul/agent/agent.go:3210.22,3212.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3217.43,3219.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3222.28,3223.10 1 0 +github.com/hashicorp/consul/agent/agent.go:3224.32,3224.32 0 0 +github.com/hashicorp/consul/agent/agent.go:3225.11,3225.11 0 0 +github.com/hashicorp/consul/agent/agent.go:3237.13,3238.47 1 0 +github.com/hashicorp/consul/agent/agent.go:3241.3,3241.52 1 0 +github.com/hashicorp/consul/agent/agent.go:3238.47,3240.4 1 0 +github.com/hashicorp/consul/agent/agent.go:3241.52,3243.4 1 0 +github.com/hashicorp/consul/agent/agent.go:3252.89,3257.33 4 0 +github.com/hashicorp/consul/agent/agent.go:3262.2,3262.33 1 0 +github.com/hashicorp/consul/agent/agent.go:3267.2,3267.17 1 0 +github.com/hashicorp/consul/agent/agent.go:3257.33,3258.31 1 0 +github.com/hashicorp/consul/agent/agent.go:3258.31,3260.4 1 0 +github.com/hashicorp/consul/agent/agent.go:3262.33,3263.31 1 0 +github.com/hashicorp/consul/agent/agent.go:3263.31,3265.4 1 0 +github.com/hashicorp/consul/agent/agent.go:3271.43,3273.2 1 0 +github.com/hashicorp/consul/agent/agent.go:3275.62,3278.47 2 0 +github.com/hashicorp/consul/agent/agent.go:3282.2,3282.44 1 0 +github.com/hashicorp/consul/agent/agent.go:3286.2,3286.43 1 0 +github.com/hashicorp/consul/agent/agent.go:3290.2,3290.43 1 0 +github.com/hashicorp/consul/agent/agent.go:3294.2,3294.44 1 0 +github.com/hashicorp/consul/agent/agent.go:3298.2,3298.43 1 0 +github.com/hashicorp/consul/agent/agent.go:3302.2,3302.46 1 0 +github.com/hashicorp/consul/agent/agent.go:3306.2,3306.46 1 0 +github.com/hashicorp/consul/agent/agent.go:3310.2,3310.46 1 0 +github.com/hashicorp/consul/agent/agent.go:3278.47,3281.3 2 0 +github.com/hashicorp/consul/agent/agent.go:3282.44,3285.3 2 0 +github.com/hashicorp/consul/agent/agent.go:3286.43,3289.3 2 0 +github.com/hashicorp/consul/agent/agent.go:3290.43,3293.3 2 0 +github.com/hashicorp/consul/agent/agent.go:3294.44,3297.3 2 0 +github.com/hashicorp/consul/agent/agent.go:3298.43,3301.3 2 0 +github.com/hashicorp/consul/agent/agent.go:3302.46,3305.3 2 0 +github.com/hashicorp/consul/agent/agent.go:3306.46,3309.3 2 0 +github.com/hashicorp/consul/agent/agent.go:3310.46,3313.3 2 0 +github.com/hashicorp/consul/agent/agent.go:3317.86,3323.9 4 0 +github.com/hashicorp/consul/agent/agent.go:3328.2,3331.28 2 0 +github.com/hashicorp/consul/agent/agent.go:3337.2,3337.76 1 0 +github.com/hashicorp/consul/agent/agent.go:3341.2,3341.12 1 0 +github.com/hashicorp/consul/agent/agent.go:3323.9,3325.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3331.28,3333.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3337.76,3339.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3347.88,3359.16 3 0 +github.com/hashicorp/consul/agent/agent.go:3364.2,3365.47 2 0 +github.com/hashicorp/consul/agent/agent.go:3370.2,3376.58 3 0 +github.com/hashicorp/consul/agent/agent.go:3379.2,3379.50 1 0 +github.com/hashicorp/consul/agent/agent.go:3383.2,3383.12 1 0 +github.com/hashicorp/consul/agent/agent.go:3359.16,3361.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3365.47,3367.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3376.58,3378.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3379.50,3381.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3387.66,3392.16 4 0 +github.com/hashicorp/consul/agent/agent.go:3417.2,3418.48 2 0 +github.com/hashicorp/consul/agent/agent.go:3424.2,3424.36 1 0 +github.com/hashicorp/consul/agent/agent.go:3430.2,3432.12 3 0 +github.com/hashicorp/consul/agent/agent.go:3392.16,3393.25 1 0 +github.com/hashicorp/consul/agent/agent.go:3393.25,3397.18 3 0 +github.com/hashicorp/consul/agent/agent.go:3404.4,3404.51 1 0 +github.com/hashicorp/consul/agent/agent.go:3397.18,3398.27 1 0 +github.com/hashicorp/consul/agent/agent.go:3398.27,3400.6 1 0 +github.com/hashicorp/consul/agent/agent.go:3400.11,3402.6 1 0 +github.com/hashicorp/consul/agent/agent.go:3404.51,3410.5 1 0 +github.com/hashicorp/consul/agent/agent.go:3411.9,3413.4 1 0 +github.com/hashicorp/consul/agent/agent.go:3418.48,3421.3 2 0 +github.com/hashicorp/consul/agent/agent.go:3424.36,3427.3 2 0 +github.com/hashicorp/consul/agent/agent.go:3436.64,3439.24 3 0 +github.com/hashicorp/consul/agent/agent.go:3442.2,3442.12 1 0 +github.com/hashicorp/consul/agent/agent.go:3439.24,3441.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3446.54,3452.36 3 0 +github.com/hashicorp/consul/agent/agent.go:3456.2,3457.23 2 0 +github.com/hashicorp/consul/agent/agent.go:3460.2,3467.56 2 0 +github.com/hashicorp/consul/agent/agent.go:3477.2,3477.14 1 0 +github.com/hashicorp/consul/agent/agent.go:3452.36,3454.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3457.23,3459.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3467.56,3468.35 1 0 +github.com/hashicorp/consul/agent/agent.go:3468.35,3469.49 1 0 +github.com/hashicorp/consul/agent/agent.go:3469.49,3471.5 1 0 +github.com/hashicorp/consul/agent/agent.go:3472.9,3474.4 1 0 +github.com/hashicorp/consul/agent/agent.go:3481.34,3484.19 2 1 +github.com/hashicorp/consul/agent/agent.go:3489.2,3490.16 2 0 +github.com/hashicorp/consul/agent/agent.go:3493.2,3498.16 4 0 +github.com/hashicorp/consul/agent/agent.go:3501.2,3501.12 1 0 +github.com/hashicorp/consul/agent/agent.go:3484.19,3486.3 1 1 +github.com/hashicorp/consul/agent/agent.go:3490.16,3492.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3498.16,3500.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3505.35,3508.19 2 1 +github.com/hashicorp/consul/agent/agent.go:3512.2,3513.16 2 0 +github.com/hashicorp/consul/agent/agent.go:3517.2,3517.18 1 0 +github.com/hashicorp/consul/agent/agent.go:3521.2,3522.16 2 0 +github.com/hashicorp/consul/agent/agent.go:3525.2,3525.12 1 0 +github.com/hashicorp/consul/agent/agent.go:3508.19,3510.3 1 1 +github.com/hashicorp/consul/agent/agent.go:3513.16,3515.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3517.18,3519.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3522.16,3524.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3530.111,3534.16 2 1 +github.com/hashicorp/consul/agent/agent.go:3539.2,3539.40 1 1 +github.com/hashicorp/consul/agent/agent.go:3597.2,3599.16 3 1 +github.com/hashicorp/consul/agent/agent.go:3605.2,3605.27 1 0 +github.com/hashicorp/consul/agent/agent.go:3720.2,3720.49 1 0 +github.com/hashicorp/consul/agent/agent.go:3729.2,3729.12 1 0 +github.com/hashicorp/consul/agent/agent.go:3534.16,3536.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3539.40,3542.17 3 0 +github.com/hashicorp/consul/agent/agent.go:3547.3,3548.17 2 0 +github.com/hashicorp/consul/agent/agent.go:3554.3,3570.17 4 0 +github.com/hashicorp/consul/agent/agent.go:3575.3,3575.21 1 0 +github.com/hashicorp/consul/agent/agent.go:3542.17,3544.4 1 0 +github.com/hashicorp/consul/agent/agent.go:3548.17,3550.4 1 0 +github.com/hashicorp/consul/agent/agent.go:3570.17,3572.4 1 0 +github.com/hashicorp/consul/agent/agent.go:3575.21,3590.18 3 0 +github.com/hashicorp/consul/agent/agent.go:3590.18,3592.5 1 0 +github.com/hashicorp/consul/agent/agent.go:3599.16,3600.25 1 1 +github.com/hashicorp/consul/agent/agent.go:3603.3,3603.71 1 0 +github.com/hashicorp/consul/agent/agent.go:3600.25,3602.4 1 1 +github.com/hashicorp/consul/agent/agent.go:3605.27,3607.17 1 0 +github.com/hashicorp/consul/agent/agent.go:3612.3,3612.42 1 0 +github.com/hashicorp/consul/agent/agent.go:3618.3,3620.17 3 0 +github.com/hashicorp/consul/agent/agent.go:3625.3,3626.49 2 0 +github.com/hashicorp/consul/agent/agent.go:3638.3,3639.22 2 0 +github.com/hashicorp/consul/agent/agent.go:3649.3,3649.105 1 0 +github.com/hashicorp/consul/agent/agent.go:3664.3,3669.10 4 0 +github.com/hashicorp/consul/agent/agent.go:3683.3,3683.40 1 0 +github.com/hashicorp/consul/agent/agent.go:3607.17,3608.12 1 0 +github.com/hashicorp/consul/agent/agent.go:3612.42,3614.12 2 0 +github.com/hashicorp/consul/agent/agent.go:3620.17,3622.4 1 0 +github.com/hashicorp/consul/agent/agent.go:3626.49,3628.58 1 0 +github.com/hashicorp/consul/agent/agent.go:3628.58,3633.13 2 0 +github.com/hashicorp/consul/agent/agent.go:3639.22,3640.51 1 0 +github.com/hashicorp/consul/agent/agent.go:3640.51,3646.5 1 0 +github.com/hashicorp/consul/agent/agent.go:3649.105,3654.42 2 0 +github.com/hashicorp/consul/agent/agent.go:3660.4,3660.12 1 0 +github.com/hashicorp/consul/agent/agent.go:3654.42,3659.5 1 0 +github.com/hashicorp/consul/agent/agent.go:3669.10,3674.52 2 0 +github.com/hashicorp/consul/agent/agent.go:3677.4,3677.58 1 0 +github.com/hashicorp/consul/agent/agent.go:3680.4,3680.12 1 0 +github.com/hashicorp/consul/agent/agent.go:3674.52,3676.5 1 0 +github.com/hashicorp/consul/agent/agent.go:3677.58,3679.5 1 0 +github.com/hashicorp/consul/agent/agent.go:3683.40,3690.52 2 0 +github.com/hashicorp/consul/agent/agent.go:3693.4,3693.58 1 0 +github.com/hashicorp/consul/agent/agent.go:3690.52,3692.5 1 0 +github.com/hashicorp/consul/agent/agent.go:3693.58,3695.5 1 0 +github.com/hashicorp/consul/agent/agent.go:3696.9,3714.18 3 0 +github.com/hashicorp/consul/agent/agent.go:3714.18,3716.5 1 0 +github.com/hashicorp/consul/agent/agent.go:3720.49,3721.40 1 0 +github.com/hashicorp/consul/agent/agent.go:3721.40,3723.58 1 0 +github.com/hashicorp/consul/agent/agent.go:3723.58,3725.5 1 0 +github.com/hashicorp/consul/agent/agent.go:3733.40,3734.40 1 0 +github.com/hashicorp/consul/agent/agent.go:3739.2,3739.12 1 0 +github.com/hashicorp/consul/agent/agent.go:3734.40,3735.58 1 0 +github.com/hashicorp/consul/agent/agent.go:3735.58,3737.4 1 0 +github.com/hashicorp/consul/agent/agent.go:3744.109,3746.36 1 1 +github.com/hashicorp/consul/agent/agent.go:3761.2,3763.16 3 1 +github.com/hashicorp/consul/agent/agent.go:3769.2,3769.27 1 0 +github.com/hashicorp/consul/agent/agent.go:3866.2,3866.12 1 0 +github.com/hashicorp/consul/agent/agent.go:3746.36,3749.53 2 0 +github.com/hashicorp/consul/agent/agent.go:3754.3,3755.98 2 0 +github.com/hashicorp/consul/agent/agent.go:3749.53,3752.4 2 0 +github.com/hashicorp/consul/agent/agent.go:3755.98,3757.4 1 0 +github.com/hashicorp/consul/agent/agent.go:3763.16,3764.25 1 1 +github.com/hashicorp/consul/agent/agent.go:3767.3,3767.71 1 0 +github.com/hashicorp/consul/agent/agent.go:3764.25,3766.4 1 1 +github.com/hashicorp/consul/agent/agent.go:3769.27,3771.17 1 0 +github.com/hashicorp/consul/agent/agent.go:3776.3,3778.17 3 0 +github.com/hashicorp/consul/agent/agent.go:3783.3,3784.49 2 0 +github.com/hashicorp/consul/agent/agent.go:3791.3,3795.22 3 0 +github.com/hashicorp/consul/agent/agent.go:3805.3,3805.103 1 0 +github.com/hashicorp/consul/agent/agent.go:3816.3,3817.10 2 0 +github.com/hashicorp/consul/agent/agent.go:3828.3,3828.36 1 0 +github.com/hashicorp/consul/agent/agent.go:3771.17,3772.12 1 0 +github.com/hashicorp/consul/agent/agent.go:3778.17,3780.4 1 0 +github.com/hashicorp/consul/agent/agent.go:3784.49,3789.12 2 0 +github.com/hashicorp/consul/agent/agent.go:3795.22,3796.51 1 0 +github.com/hashicorp/consul/agent/agent.go:3796.51,3802.5 1 0 +github.com/hashicorp/consul/agent/agent.go:3805.103,3810.42 2 0 +github.com/hashicorp/consul/agent/agent.go:3813.4,3813.12 1 0 +github.com/hashicorp/consul/agent/agent.go:3810.42,3812.5 1 0 +github.com/hashicorp/consul/agent/agent.go:3817.10,3822.48 2 0 +github.com/hashicorp/consul/agent/agent.go:3825.4,3825.12 1 0 +github.com/hashicorp/consul/agent/agent.go:3822.48,3824.5 1 0 +github.com/hashicorp/consul/agent/agent.go:3828.36,3835.48 2 0 +github.com/hashicorp/consul/agent/agent.go:3835.48,3837.5 1 0 +github.com/hashicorp/consul/agent/agent.go:3838.9,3844.55 2 0 +github.com/hashicorp/consul/agent/agent.go:3849.4,3849.87 1 0 +github.com/hashicorp/consul/agent/agent.go:3859.4,3862.5 1 0 +github.com/hashicorp/consul/agent/agent.go:3844.55,3847.5 2 0 +github.com/hashicorp/consul/agent/agent.go:3849.87,3855.49 2 0 +github.com/hashicorp/consul/agent/agent.go:3855.49,3857.6 1 0 +github.com/hashicorp/consul/agent/agent.go:3870.38,3871.38 1 0 +github.com/hashicorp/consul/agent/agent.go:3876.2,3876.12 1 0 +github.com/hashicorp/consul/agent/agent.go:3871.38,3872.56 1 0 +github.com/hashicorp/consul/agent/agent.go:3872.56,3874.4 1 0 +github.com/hashicorp/consul/agent/agent.go:3882.79,3884.2 1 0 +github.com/hashicorp/consul/agent/agent.go:3888.64,3890.34 2 1 +github.com/hashicorp/consul/agent/agent.go:3893.2,3894.35 2 1 +github.com/hashicorp/consul/agent/agent.go:3890.34,3892.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3898.34,3900.2 1 0 +github.com/hashicorp/consul/agent/agent.go:3903.71,3906.2 2 0 +github.com/hashicorp/consul/agent/agent.go:3910.99,3912.20 2 0 +github.com/hashicorp/consul/agent/agent.go:3917.2,3918.35 2 0 +github.com/hashicorp/consul/agent/agent.go:3923.2,3923.18 1 0 +github.com/hashicorp/consul/agent/agent.go:3928.2,3942.12 4 0 +github.com/hashicorp/consul/agent/agent.go:3912.20,3914.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3918.35,3920.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3923.18,3925.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3947.78,3948.39 1 0 +github.com/hashicorp/consul/agent/agent.go:3953.2,3954.35 2 0 +github.com/hashicorp/consul/agent/agent.go:3960.2,3963.12 3 0 +github.com/hashicorp/consul/agent/agent.go:3948.39,3950.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3954.35,3957.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3967.61,3969.52 1 0 +github.com/hashicorp/consul/agent/agent.go:3974.2,3974.18 1 0 +github.com/hashicorp/consul/agent/agent.go:3979.2,3988.48 3 0 +github.com/hashicorp/consul/agent/agent.go:3969.52,3971.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3974.18,3976.3 1 0 +github.com/hashicorp/consul/agent/agent.go:3992.42,3993.52 1 0 +github.com/hashicorp/consul/agent/agent.go:3996.2,3997.45 2 0 +github.com/hashicorp/consul/agent/agent.go:3993.52,3995.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4000.42,4002.2 1 0 +github.com/hashicorp/consul/agent/agent.go:4004.38,4006.2 1 0 +github.com/hashicorp/consul/agent/agent.go:4011.53,4013.16 2 0 +github.com/hashicorp/consul/agent/agent.go:4020.2,4023.16 2 0 +github.com/hashicorp/consul/agent/agent.go:4055.2,4055.39 1 0 +github.com/hashicorp/consul/agent/agent.go:4013.16,4015.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4023.16,4031.5 1 0 +github.com/hashicorp/consul/agent/agent.go:4048.3,4048.83 1 0 +github.com/hashicorp/consul/agent/agent.go:4031.5,4032.44 1 0 +github.com/hashicorp/consul/agent/agent.go:4038.4,4038.46 1 0 +github.com/hashicorp/consul/agent/agent.go:4044.4,4044.46 1 0 +github.com/hashicorp/consul/agent/agent.go:4032.44,4034.19 2 0 +github.com/hashicorp/consul/agent/agent.go:4034.19,4036.6 1 0 +github.com/hashicorp/consul/agent/agent.go:4038.46,4040.19 2 0 +github.com/hashicorp/consul/agent/agent.go:4040.19,4042.6 1 0 +github.com/hashicorp/consul/agent/agent.go:4044.46,4046.5 1 0 +github.com/hashicorp/consul/agent/agent.go:4048.83,4052.4 2 0 +github.com/hashicorp/consul/agent/agent.go:4058.92,4065.43 7 0 +github.com/hashicorp/consul/agent/agent.go:4068.2,4068.14 1 0 +github.com/hashicorp/consul/agent/agent.go:4065.43,4067.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4074.74,4076.55 1 0 +github.com/hashicorp/consul/agent/agent.go:4084.2,4096.43 6 0 +github.com/hashicorp/consul/agent/agent.go:4099.2,4099.41 1 0 +github.com/hashicorp/consul/agent/agent.go:4102.2,4109.61 3 0 +github.com/hashicorp/consul/agent/agent.go:4114.2,4114.53 1 0 +github.com/hashicorp/consul/agent/agent.go:4117.2,4117.51 1 0 +github.com/hashicorp/consul/agent/agent.go:4120.2,4120.47 1 0 +github.com/hashicorp/consul/agent/agent.go:4124.2,4124.48 1 0 +github.com/hashicorp/consul/agent/agent.go:4128.2,4132.33 2 0 +github.com/hashicorp/consul/agent/agent.go:4138.2,4139.16 2 0 +github.com/hashicorp/consul/agent/agent.go:4143.2,4155.52 2 0 +github.com/hashicorp/consul/agent/agent.go:4159.2,4159.41 1 0 +github.com/hashicorp/consul/agent/agent.go:4166.2,4171.38 3 0 +github.com/hashicorp/consul/agent/agent.go:4177.2,4179.12 2 0 +github.com/hashicorp/consul/agent/agent.go:4076.55,4078.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4078.8,4081.3 2 0 +github.com/hashicorp/consul/agent/agent.go:4096.43,4098.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4099.41,4101.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4109.61,4111.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4114.53,4116.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4117.51,4119.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4120.47,4122.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4124.48,4126.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4132.33,4133.48 1 0 +github.com/hashicorp/consul/agent/agent.go:4133.48,4135.4 1 0 +github.com/hashicorp/consul/agent/agent.go:4139.16,4141.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4155.52,4157.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4159.41,4161.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4161.8,4163.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4171.38,4172.35 1 0 +github.com/hashicorp/consul/agent/agent.go:4172.35,4174.4 1 0 +github.com/hashicorp/consul/agent/agent.go:4189.88,4197.31 4 0 +github.com/hashicorp/consul/agent/agent.go:4213.2,4213.6 1 0 +github.com/hashicorp/consul/agent/agent.go:4197.31,4198.16 1 0 +github.com/hashicorp/consul/agent/agent.go:4201.3,4201.28 1 0 +github.com/hashicorp/consul/agent/agent.go:4205.3,4210.21 5 0 +github.com/hashicorp/consul/agent/agent.go:4198.16,4200.4 1 0 +github.com/hashicorp/consul/agent/agent.go:4201.28,4203.4 1 0 +github.com/hashicorp/consul/agent/agent.go:4213.6,4219.17 3 0 +github.com/hashicorp/consul/agent/agent.go:4228.3,4228.65 1 0 +github.com/hashicorp/consul/agent/agent.go:4237.3,4237.58 1 0 +github.com/hashicorp/consul/agent/agent.go:4219.17,4221.4 1 0 +github.com/hashicorp/consul/agent/agent.go:4228.65,4230.4 1 0 +github.com/hashicorp/consul/agent/agent.go:4237.58,4238.11 1 0 +github.com/hashicorp/consul/agent/agent.go:4239.23,4239.23 0 0 +github.com/hashicorp/consul/agent/agent.go:4240.22,4240.22 0 0 +github.com/hashicorp/consul/agent/agent.go:4251.33,4314.2 27 1 +github.com/hashicorp/consul/agent/agent.go:4317.43,4319.2 1 0 +github.com/hashicorp/consul/agent/agent.go:4324.91,4325.35 1 0 +github.com/hashicorp/consul/agent/agent.go:4337.2,4337.35 1 0 +github.com/hashicorp/consul/agent/agent.go:4349.2,4349.12 1 0 +github.com/hashicorp/consul/agent/agent.go:4325.35,4326.31 1 0 +github.com/hashicorp/consul/agent/agent.go:4329.3,4330.17 2 0 +github.com/hashicorp/consul/agent/agent.go:4333.3,4335.24 3 0 +github.com/hashicorp/consul/agent/agent.go:4326.31,4327.12 1 0 +github.com/hashicorp/consul/agent/agent.go:4330.17,4332.4 1 0 +github.com/hashicorp/consul/agent/agent.go:4337.35,4338.31 1 0 +github.com/hashicorp/consul/agent/agent.go:4341.3,4342.17 2 0 +github.com/hashicorp/consul/agent/agent.go:4345.3,4347.24 3 0 +github.com/hashicorp/consul/agent/agent.go:4338.31,4339.12 1 0 +github.com/hashicorp/consul/agent/agent.go:4342.17,4344.4 1 0 +github.com/hashicorp/consul/agent/agent.go:4355.65,4357.35 2 0 +github.com/hashicorp/consul/agent/agent.go:4365.2,4365.35 1 0 +github.com/hashicorp/consul/agent/agent.go:4373.2,4373.30 1 0 +github.com/hashicorp/consul/agent/agent.go:4357.35,4358.31 1 0 +github.com/hashicorp/consul/agent/agent.go:4358.31,4363.4 4 0 +github.com/hashicorp/consul/agent/agent.go:4365.35,4366.31 1 0 +github.com/hashicorp/consul/agent/agent.go:4366.31,4371.4 4 0 +github.com/hashicorp/consul/agent/agent.go:4373.30,4375.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4380.99,4382.27 2 0 +github.com/hashicorp/consul/agent/agent.go:4385.2,4385.38 1 0 +github.com/hashicorp/consul/agent/agent.go:4389.2,4390.35 2 0 +github.com/hashicorp/consul/agent/agent.go:4394.2,4395.69 2 0 +github.com/hashicorp/consul/agent/agent.go:4402.2,4402.15 1 0 +github.com/hashicorp/consul/agent/agent.go:4406.2,4406.18 1 0 +github.com/hashicorp/consul/agent/agent.go:4382.27,4384.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4385.38,4387.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4390.35,4392.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4395.69,4397.23 2 0 +github.com/hashicorp/consul/agent/agent.go:4397.23,4399.9 2 0 +github.com/hashicorp/consul/agent/agent.go:4402.15,4404.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4409.57,4436.51 2 1 +github.com/hashicorp/consul/agent/agent.go:4465.2,4466.16 2 1 +github.com/hashicorp/consul/agent/agent.go:4436.51,4443.46 1 1 +github.com/hashicorp/consul/agent/agent.go:4445.3,4462.69 18 1 +github.com/hashicorp/consul/agent/agent.go:4443.46,4443.77 1 0 +github.com/hashicorp/consul/agent/agent.go:4470.79,4472.2 1 0 +github.com/hashicorp/consul/agent/agent.go:4475.66,4483.2 5 0 +github.com/hashicorp/consul/agent/agent.go:4486.61,4496.2 6 0 +github.com/hashicorp/consul/agent/agent.go:4498.37,4499.37 1 0 +github.com/hashicorp/consul/agent/agent.go:4502.2,4502.38 1 0 +github.com/hashicorp/consul/agent/agent.go:4505.2,4505.38 1 0 +github.com/hashicorp/consul/agent/agent.go:4508.2,4508.16 1 0 +github.com/hashicorp/consul/agent/agent.go:4499.37,4501.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4502.38,4504.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4505.38,4507.3 1 0 +github.com/hashicorp/consul/agent/agent.go:4512.52,4513.15 1 0 +github.com/hashicorp/consul/agent/agent.go:4516.2,4516.19 1 0 +github.com/hashicorp/consul/agent/agent.go:4513.15,4515.3 1 0 +github.com/hashicorp/consul/agent/catalog_endpoint_oss.go:8.60,10.2 1 0 +github.com/hashicorp/consul/agent/metrics.go:26.106,30.40 1 0 +github.com/hashicorp/consul/agent/metrics.go:30.40,32.18 2 0 +github.com/hashicorp/consul/agent/metrics.go:36.4,37.18 2 0 +github.com/hashicorp/consul/agent/metrics.go:40.4,40.41 1 0 +github.com/hashicorp/consul/agent/metrics.go:32.18,34.5 1 0 +github.com/hashicorp/consul/agent/metrics.go:37.18,39.5 1 0 +github.com/hashicorp/consul/agent/consul/config.go:47.13,53.2 1 1 +github.com/hashicorp/consul/agent/consul/config.go:419.47,420.44 1 1 +github.com/hashicorp/consul/agent/consul/config.go:423.2,423.44 1 1 +github.com/hashicorp/consul/agent/consul/config.go:426.2,426.12 1 1 +github.com/hashicorp/consul/agent/consul/config.go:420.44,422.3 1 0 +github.com/hashicorp/consul/agent/consul/config.go:423.44,425.3 1 0 +github.com/hashicorp/consul/agent/consul/config.go:431.35,432.48 1 1 +github.com/hashicorp/consul/agent/consul/config.go:438.2,438.45 1 1 +github.com/hashicorp/consul/agent/consul/config.go:445.2,445.12 1 1 +github.com/hashicorp/consul/agent/consul/config.go:433.15,433.15 0 1 +github.com/hashicorp/consul/agent/consul/config.go:434.14,434.14 0 1 +github.com/hashicorp/consul/agent/consul/config.go:435.10,436.98 1 0 +github.com/hashicorp/consul/agent/consul/config.go:439.15,439.15 0 0 +github.com/hashicorp/consul/agent/consul/config.go:440.14,440.14 0 1 +github.com/hashicorp/consul/agent/consul/config.go:441.37,441.37 0 1 +github.com/hashicorp/consul/agent/consul/config.go:442.10,443.92 1 0 +github.com/hashicorp/consul/agent/consul/config.go:449.30,451.16 2 1 +github.com/hashicorp/consul/agent/consul/config.go:455.2,564.13 13 1 +github.com/hashicorp/consul/agent/consul/config.go:451.16,452.13 1 0 +github.com/hashicorp/consul/agent/consul/config.go:575.57,610.2 25 1 +github.com/hashicorp/consul/agent/consul/enterprise_config_oss.go:8.50,10.2 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:15.123,16.88 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:21.2,22.16 2 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:25.2,25.75 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:31.2,32.39 2 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:37.2,38.50 2 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:49.2,51.56 3 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:69.2,69.12 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:16.88,18.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:22.16,24.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:25.75,27.3 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:32.39,34.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:38.50,40.13 2 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:44.3,45.47 2 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:40.13,41.12 1 0 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:51.56,54.50 3 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:59.3,67.47 2 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:54.50,57.4 2 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:76.105,77.91 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:83.2,84.16 2 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:87.2,87.73 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:90.2,90.76 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:113.2,113.63 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:121.2,122.12 2 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:77.91,79.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:84.16,86.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:87.73,89.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:90.76,92.3 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:97.2,99.40 2 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:102.3,102.52 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:108.3,109.17 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:99.40,101.4 1 0 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:102.52,103.33 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:103.33,105.16 2 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:113.63,119.3 2 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:129.100,130.86 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:136.2,137.16 2 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:140.2,140.73 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:143.2,143.76 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:174.2,174.63 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:182.2,183.12 2 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:130.86,132.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:137.16,139.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:140.73,142.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:143.76,145.3 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:150.2,152.40 2 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:155.3,155.52 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:161.3,162.12 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:152.40,154.4 1 0 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:155.52,156.23 1 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:156.23,158.16 2 1 +github.com/hashicorp/consul/agent/consul/operator_raft_endpoint.go:174.63,180.3 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:52.85,54.16 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:58.2,59.16 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:63.2,63.27 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:54.16,56.3 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:59.16,61.3 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:66.79,67.24 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:70.2,70.26 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:73.2,73.14 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:82.2,85.14 3 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:96.2,107.27 12 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:110.2,110.30 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:113.2,113.24 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:116.2,116.35 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:119.2,119.26 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:125.2,125.96 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:131.2,131.33 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:138.2,144.14 4 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:153.2,167.14 8 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:182.2,182.14 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:213.2,215.65 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:229.2,229.23 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:232.2,232.65 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:236.2,242.45 4 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:246.2,246.18 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:67.24,69.3 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:70.26,72.3 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:73.14,74.25 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:77.3,77.27 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:74.25,76.4 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:77.27,79.4 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:85.14,87.3 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:87.8,89.36 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:89.36,91.27 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:91.27,93.5 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:107.27,109.3 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:110.30,112.3 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:113.24,115.3 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:116.35,118.3 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:119.26,124.3 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:125.96,127.3 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:131.33,133.3 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:133.8,135.3 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:144.14,146.3 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:146.8,148.3 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:167.14,171.3 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:171.8,180.3 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:182.14,189.17 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:193.3,193.54 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:189.17,191.4 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:193.54,200.18 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:204.4,204.50 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:200.18,202.5 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:205.9,207.4 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:215.65,217.77 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:217.77,219.18 2 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:225.4,225.36 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:219.18,221.5 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:229.23,231.3 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:232.65,234.3 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:242.45,244.3 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:250.40,252.2 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:255.36,257.2 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:260.43,262.2 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:265.36,266.6 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:266.6,267.10 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:268.28,269.25 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:288.23,289.10 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:270.30,272.45 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:274.77,276.45 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:278.24,279.37 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:280.32,282.45 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:283.25,283.25 0 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:284.12,285.58 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:296.56,298.19 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:303.2,306.31 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:298.19,300.3 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:306.31,308.13 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:311.3,311.10 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:308.13,310.4 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:312.27,312.27 0 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:313.11,313.11 0 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:319.51,321.47 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:325.2,325.29 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:321.47,323.3 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:326.30,330.31 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:333.25,338.39 3 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:341.10,342.43 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:330.31,332.4 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:338.39,340.4 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:342.43,344.4 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:349.51,350.31 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:350.31,352.38 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:355.3,361.36 3 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:366.3,366.18 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:352.38,353.12 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:361.36,363.4 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:370.53,371.31 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:371.31,373.38 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:376.3,379.39 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:373.38,374.12 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:384.35,389.16 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:393.2,393.16 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:399.2,399.26 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:405.2,408.33 4 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:432.2,432.39 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:437.2,437.33 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:475.2,478.33 3 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:494.2,498.39 3 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:504.2,504.30 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:389.16,392.3 2 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:393.16,397.3 3 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:399.26,402.3 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:408.33,410.13 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:413.3,413.42 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:417.3,417.60 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:421.3,421.18 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:425.3,425.21 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:428.3,428.32 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:410.13,411.12 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:413.42,415.12 2 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:417.60,420.4 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:421.18,424.4 2 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:425.21,427.4 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:432.39,434.3 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:437.33,441.63 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:467.3,467.21 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:441.63,443.102 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:443.102,451.5 3 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:451.10,452.10 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:467.21,471.4 3 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:478.33,484.25 5 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:487.3,492.62 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:484.25,486.4 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:498.39,500.3 1 0 +github.com/hashicorp/consul/agent/consul/server_serf.go:508.53,509.31 1 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:509.31,511.38 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:514.3,517.42 2 1 +github.com/hashicorp/consul/agent/consul/server_serf.go:511.38,512.12 1 1 +github.com/hashicorp/consul/agent/consul/system_metadata.go:7.64,9.16 2 1 +github.com/hashicorp/consul/agent/consul/system_metadata.go:12.2,12.18 1 1 +github.com/hashicorp/consul/agent/consul/system_metadata.go:16.2,16.25 1 1 +github.com/hashicorp/consul/agent/consul/system_metadata.go:9.16,11.3 1 0 +github.com/hashicorp/consul/agent/consul/system_metadata.go:12.18,14.3 1 1 +github.com/hashicorp/consul/agent/consul/system_metadata.go:19.62,29.2 3 1 +github.com/hashicorp/consul/agent/consul/system_metadata.go:31.60,41.2 3 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:47.50,52.16 3 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:55.2,55.35 1 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:60.2,60.12 1 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:52.16,54.3 1 0 +github.com/hashicorp/consul/agent/consul/session_ttl.go:55.35,56.54 1 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:56.54,58.4 1 0 +github.com/hashicorp/consul/agent/consul/session_ttl.go:66.68,68.21 1 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:74.2,75.16 2 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:78.2,78.14 1 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:82.2,83.12 2 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:69.33,70.13 1 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:75.16,77.3 1 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:78.14,80.3 1 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:86.96,94.48 2 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:94.48,94.84 1 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:99.76,113.20 4 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:118.2,118.69 1 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:129.2,129.76 1 0 +github.com/hashicorp/consul/agent/consul/session_ttl.go:113.20,115.3 1 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:118.69,121.17 2 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:126.3,127.51 2 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:121.17,124.4 2 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:135.53,138.2 2 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:142.42,144.2 1 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:148.34,149.6 1 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:149.6,150.10 1 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:151.34,155.81 3 1 +github.com/hashicorp/consul/agent/consul/session_ttl.go:156.23,157.10 1 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:32.97,39.2 1 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:45.93,51.15 3 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:57.2,58.16 2 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:65.2,66.16 2 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:74.2,74.43 1 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:51.15,55.3 3 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:58.16,63.3 2 0 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:66.16,72.3 2 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:78.137,87.33 4 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:103.2,108.32 3 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:132.2,132.16 1 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:87.33,88.41 1 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:88.41,93.4 1 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:93.9,101.4 4 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:108.32,110.10 1 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:117.3,117.10 1 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:111.36,113.12 2 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:114.11,114.11 0 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:118.36,119.39 1 1 +github.com/hashicorp/consul/agent/consul/stats_fetcher.go:121.21,129.27 4 1 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:21.112,23.34 1 1 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:27.2,27.76 1 1 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:30.2,36.16 5 1 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:39.2,39.95 1 1 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:43.2,43.21 1 1 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:47.2,48.18 2 1 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:52.2,59.53 2 1 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:23.34,25.3 1 0 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:27.76,29.3 1 0 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:36.16,38.3 1 0 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:39.95,41.3 1 1 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:43.21,45.3 1 0 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:48.18,50.3 1 1 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:59.53,70.18 3 1 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:77.4,78.18 2 1 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:82.4,82.39 1 1 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:93.4,96.25 3 1 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:100.4,100.14 1 1 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:70.18,72.5 1 0 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:78.18,80.5 1 0 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:82.39,88.5 3 1 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:88.10,91.5 2 1 +github.com/hashicorp/consul/agent/consul/discovery_chain_endpoint.go:96.25,98.5 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:44.64,45.30 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:49.2,55.50 6 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:45.30,47.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:59.38,66.2 6 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:68.62,72.6 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:72.6,73.10 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:74.21,75.14 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:76.19,77.43 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:77.43,79.5 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect.go:85.39,86.30 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:90.2,92.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:96.2,97.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:101.2,102.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:106.2,107.26 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:117.2,117.33 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:122.2,127.12 6 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:86.30,88.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect.go:92.16,94.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect.go:97.16,99.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect.go:102.16,104.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect.go:107.26,108.101 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:112.3,113.40 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:108.101,110.12 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:117.33,119.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:130.70,133.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:136.2,136.10 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:141.2,144.6 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:133.16,135.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:136.10,139.3 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:144.6,145.10 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:146.21,147.14 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:148.19,150.18 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:154.4,154.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:150.18,152.13 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:154.12,156.5 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:161.52,163.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:166.2,167.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:171.2,171.62 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:163.16,165.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:167.16,169.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:174.58,176.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:179.2,179.15 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:183.2,183.94 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:188.2,188.96 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:192.2,192.18 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:176.16,178.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect.go:179.15,181.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:183.94,186.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:188.96,190.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:195.76,197.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:200.2,200.15 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:204.2,204.112 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:209.2,209.107 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:213.2,213.18 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:197.16,199.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect.go:200.15,202.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:204.112,207.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:209.107,211.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:218.84,220.2 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:222.98,224.2 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:226.118,229.6 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:229.6,232.10 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:237.3,237.46 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:240.3,242.34 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:258.3,258.21 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:233.21,234.10 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:235.11,235.11 0 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:237.46,239.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:242.34,246.11 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:247.22,249.11 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:250.19,251.13 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:253.9,253.28 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:253.28,255.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:264.47,265.19 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:268.2,268.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:265.19,267.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect.go:273.60,276.2 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect.go:282.70,285.2 2 1 +github.com/hashicorp/consul/agent/consul/merge.go:31.71,33.28 2 1 +github.com/hashicorp/consul/agent/consul/merge.go:84.2,84.12 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:33.28,34.51 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:66.3,66.37 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:73.3,73.51 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:80.3,80.59 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:34.51,35.35 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:39.4,42.72 2 1 +github.com/hashicorp/consul/agent/consul/merge.go:50.4,50.40 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:59.4,59.49 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:35.35,36.13 1 0 +github.com/hashicorp/consul/agent/consul/merge.go:42.72,45.5 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:50.40,53.5 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:59.49,60.45 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:60.45,62.6 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:66.37,67.19 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:67.19,70.5 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:73.51,74.33 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:74.33,77.5 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:80.59,82.4 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:99.74,106.2 5 1 +github.com/hashicorp/consul/agent/consul/merge.go:108.71,115.28 3 1 +github.com/hashicorp/consul/agent/consul/merge.go:127.2,127.12 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:115.28,117.10 2 1 +github.com/hashicorp/consul/agent/consul/merge.go:121.3,121.28 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:117.10,119.4 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:121.28,122.44 1 1 +github.com/hashicorp/consul/agent/consul/merge.go:122.44,124.5 1 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:43.114,53.2 2 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:57.47,58.9 1 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:59.21,60.13 1 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:61.19,62.45 1 0 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:68.48,69.9 1 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:70.26,71.19 1 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:72.19,73.50 1 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:78.35,82.15 3 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:86.2,86.12 1 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:82.15,85.3 2 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:90.37,92.2 1 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:95.95,98.16 3 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:103.2,103.44 1 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:118.2,119.16 2 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:123.2,123.18 1 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:98.16,100.3 1 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:103.44,105.66 1 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:111.3,112.17 2 1 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:105.66,108.4 2 0 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:112.17,114.4 1 0 +github.com/hashicorp/consul/agent/consul/raft_rpc.go:119.16,122.3 2 0 +github.com/hashicorp/consul/agent/consul/rpc.go:107.43,109.2 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:112.48,113.6 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:113.6,116.17 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:124.3,125.17 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:131.3,134.57 3 1 +github.com/hashicorp/consul/agent/consul/rpc.go:116.17,117.18 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:120.4,121.12 2 0 +github.com/hashicorp/consul/agent/consul/rpc.go:117.18,119.5 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:125.17,128.12 3 1 +github.com/hashicorp/consul/agent/consul/rpc.go:140.36,142.2 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:146.56,151.38 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:155.2,155.52 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:180.2,182.42 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:192.2,196.38 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:201.2,201.105 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:208.2,208.13 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:151.38,153.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:155.52,160.17 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:172.3,172.16 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:176.3,176.20 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:160.17,161.21 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:168.4,169.10 2 0 +github.com/hashicorp/consul/agent/consul/rpc.go:161.21,167.5 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:172.16,175.4 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:182.42,183.20 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:189.3,190.9 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:183.20,188.4 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:196.38,198.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:201.105,205.3 3 1 +github.com/hashicorp/consul/agent/consul/rpc.go:209.22,210.27 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:212.20,213.24 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:215.19,217.12 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:222.3,223.27 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:225.27,226.28 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:228.24,229.29 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:231.27,233.12 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:238.3,239.29 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:241.20,242.29 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:244.10,245.51 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:217.12,221.4 3 1 +github.com/hashicorp/consul/agent/consul/rpc.go:233.12,237.4 3 1 +github.com/hashicorp/consul/agent/consul/rpc.go:245.51,251.4 2 0 +github.com/hashicorp/consul/agent/consul/rpc.go:255.49,265.44 4 1 +github.com/hashicorp/consul/agent/consul/rpc.go:277.2,277.38 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:281.2,296.19 3 1 +github.com/hashicorp/consul/agent/consul/rpc.go:265.44,273.3 3 0 +github.com/hashicorp/consul/agent/consul/rpc.go:277.38,279.3 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:297.27,298.30 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:300.25,301.27 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:303.32,304.31 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:306.29,307.32 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:309.25,310.32 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:312.33,313.86 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:323.33,325.57 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:335.10,336.56 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:313.86,321.4 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:325.57,333.4 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:336.56,344.4 2 0 +github.com/hashicorp/consul/agent/consul/rpc.go:350.51,358.6 6 1 +github.com/hashicorp/consul/agent/consul/rpc.go:358.6,360.17 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:382.3,383.17 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:388.3,389.16 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:360.17,361.21 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:367.4,367.10 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:361.21,366.5 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:383.17,387.4 3 0 +github.com/hashicorp/consul/agent/consul/rpc.go:390.29,393.14 3 0 +github.com/hashicorp/consul/agent/consul/rpc.go:402.11,403.30 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:393.14,394.63 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:394.63,400.6 2 0 +github.com/hashicorp/consul/agent/consul/rpc.go:409.50,412.6 3 1 +github.com/hashicorp/consul/agent/consul/rpc.go:412.6,413.10 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:419.3,419.60 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:429.3,429.53 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:414.23,415.10 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:416.11,416.11 0 1 +github.com/hashicorp/consul/agent/consul/rpc.go:419.60,420.65 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:427.4,427.10 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:420.65,426.5 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:434.52,437.6 3 1 +github.com/hashicorp/consul/agent/consul/rpc.go:437.6,438.10 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:444.3,444.68 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:454.3,454.53 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:439.23,440.10 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:441.11,441.11 0 1 +github.com/hashicorp/consul/agent/consul/rpc.go:444.68,445.65 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:452.4,452.10 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:445.65,451.5 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:460.52,461.12 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:461.12,463.55 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:463.55,468.4 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:472.47,473.41 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:482.2,483.27 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:473.41,475.17 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:475.17,479.4 3 1 +github.com/hashicorp/consul/agent/consul/rpc.go:486.72,490.6 3 1 +github.com/hashicorp/consul/agent/consul/rpc.go:490.6,491.10 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:500.3,501.17 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:507.3,507.49 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:511.3,516.90 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:492.23,493.14 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:494.11,494.11 0 1 +github.com/hashicorp/consul/agent/consul/rpc.go:501.17,503.4 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:507.49,509.4 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:516.90,518.4 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:522.71,525.70 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:529.2,530.64 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:534.2,534.58 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:538.2,538.15 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:525.70,527.3 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:530.64,532.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:534.58,536.3 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:546.57,548.2 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:551.86,552.17 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:563.2,563.62 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:569.2,569.32 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:574.2,574.78 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:580.2,580.58 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:552.17,554.26 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:558.3,558.15 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:554.26,556.4 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:558.15,560.4 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:563.62,566.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:569.32,571.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:574.78,576.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:589.99,590.39 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:593.2,593.57 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:597.2,597.57 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:590.39,592.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:593.57,596.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:606.137,607.39 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:614.2,614.57 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:621.2,621.57 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:607.39,609.17 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:612.3,612.17 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:609.17,611.4 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:614.57,616.17 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:619.3,619.17 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:616.17,618.4 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:641.29,643.97 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:649.2,649.33 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:653.2,653.56 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:643.97,645.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:649.33,651.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:658.133,661.14 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:664.2,664.31 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:693.2,693.19 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:661.14,663.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:664.31,668.47 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:686.3,686.44 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:690.3,690.31 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:668.47,670.12 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:670.12,671.46 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:674.5,674.40 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:671.46,673.6 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:674.40,678.6 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:686.44,688.4 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:698.65,701.2 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:705.142,709.9 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:716.2,719.14 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:724.2,724.19 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:731.2,731.66 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:743.2,743.21 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:710.19,711.35 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:712.10,712.10 0 1 +github.com/hashicorp/consul/agent/consul/rpc.go:719.14,721.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:724.19,726.20 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:726.20,728.4 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:731.66,734.10 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:735.29,736.21 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:737.20,737.20 0 0 +github.com/hashicorp/consul/agent/consul/rpc.go:738.23,738.23 0 1 +github.com/hashicorp/consul/agent/consul/rpc.go:753.62,755.18 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:760.2,761.18 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:766.2,774.19 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:779.2,779.27 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:755.18,757.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:761.18,763.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:774.19,777.3 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:783.90,785.9 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:797.2,799.95 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:810.2,810.12 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:785.9,786.33 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:790.3,794.29 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:786.33,789.4 2 0 +github.com/hashicorp/consul/agent/consul/rpc.go:799.95,808.3 3 1 +github.com/hashicorp/consul/agent/consul/rpc.go:816.112,821.25 3 1 +github.com/hashicorp/consul/agent/consul/rpc.go:832.2,833.32 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:841.2,841.23 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:821.25,822.22 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:822.22,824.61 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:828.4,828.16 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:824.61,827.5 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:833.32,834.10 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:835.25,836.19 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:837.23,838.21 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:848.110,855.2 4 1 +github.com/hashicorp/consul/agent/consul/rpc.go:860.89,862.2 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:866.96,868.2 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:872.97,874.2 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:884.37,885.20 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:888.2,889.16 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:894.2,894.37 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:898.2,900.9 3 1 +github.com/hashicorp/consul/agent/consul/rpc.go:908.2,908.39 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:912.2,914.13 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:928.2,928.33 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:931.2,931.18 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:885.20,887.3 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:889.16,891.3 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:894.37,896.3 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:901.76,902.43 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:903.10,905.79 2 0 +github.com/hashicorp/consul/agent/consul/rpc.go:908.39,910.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:914.13,917.18 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:921.3,922.10 2 0 +github.com/hashicorp/consul/agent/consul/rpc.go:925.3,925.33 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:917.18,919.4 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:922.10,924.4 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:928.33,930.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1012.9,1019.24 4 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1035.2,1036.16 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1039.2,1053.6 8 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1019.24,1020.34 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1026.3,1029.67 4 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1032.3,1032.13 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1020.34,1021.45 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1021.45,1023.5 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1029.67,1031.4 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1036.16,1038.3 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:1053.6,1054.34 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1063.3,1073.10 6 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1088.3,1090.46 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1095.3,1095.42 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1101.3,1101.10 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1054.34,1055.45 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1055.45,1057.5 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:1074.36,1075.16 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1079.4,1079.19 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1080.38,1081.15 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1085.19,1086.14 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1075.16,1078.5 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1081.15,1084.5 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1090.46,1092.4 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1095.42,1098.4 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1102.28,1103.14 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1104.11,1104.11 0 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1117.74,1118.18 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1125.2,1134.22 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1118.18,1121.3 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1121.8,1124.3 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1134.22,1136.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1141.41,1144.39 3 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1148.2,1148.35 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1151.2,1154.34 3 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1169.2,1169.46 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1144.39,1146.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1148.35,1150.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1154.34,1156.10 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1164.3,1164.36 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1157.29,1157.29 0 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1160.23,1161.52 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1164.36,1166.4 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1175.76,1177.42 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1184.2,1185.21 2 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1177.42,1179.3 1 0 +github.com/hashicorp/consul/agent/consul/rpc.go:1179.8,1179.30 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1179.30,1181.3 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1210.78,1211.17 1 1 +github.com/hashicorp/consul/agent/consul/rpc.go:1211.17,1213.3 1 1 +github.com/hashicorp/consul/agent/consul/serf_filter.go:15.43,16.38 1 1 +github.com/hashicorp/consul/agent/consul/serf_filter.go:19.2,19.80 1 1 +github.com/hashicorp/consul/agent/consul/serf_filter.go:22.2,22.12 1 1 +github.com/hashicorp/consul/agent/consul/serf_filter.go:16.38,18.3 1 0 +github.com/hashicorp/consul/agent/consul/serf_filter.go:19.80,21.3 1 0 +github.com/hashicorp/consul/agent/consul/serf_filter.go:25.54,27.2 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:30.58,33.54 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:49.2,49.22 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:61.2,61.58 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:68.2,68.17 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:33.54,35.10 2 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:39.3,40.17 2 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:45.3,45.19 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:35.10,37.4 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:40.17,43.4 2 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:49.22,50.56 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:50.56,51.18 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:54.4,54.99 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:51.18,53.5 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:61.58,63.3 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:63.8,63.78 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:63.78,65.3 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:69.28,70.23 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:78.3,83.19 4 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:85.31,86.22 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:91.3,91.64 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:100.3,101.41 2 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:106.3,109.10 3 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:122.3,122.10 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:140.3,140.56 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:142.10,143.65 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:70.23,71.45 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:71.45,73.5 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:86.22,88.4 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:91.64,93.4 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:101.41,103.4 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:112.36,112.36 0 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:115.20,116.72 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:119.23,119.23 0 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:124.23,125.18 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:131.20,132.76 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:135.23,135.23 0 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:125.18,127.5 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:150.61,153.42 3 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:157.2,159.16 3 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:163.2,163.15 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:170.2,171.43 2 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:174.2,174.17 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:180.2,180.12 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:153.42,155.3 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:159.16,161.15 2 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:163.15,164.38 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:164.38,166.4 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:171.43,173.3 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:174.17,175.48 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:175.48,177.4 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:199.26,203.16 2 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:209.2,210.15 2 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:217.2,218.42 2 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:221.2,221.45 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:229.2,229.15 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:239.2,240.42 2 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:243.2,243.23 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:247.2,248.18 2 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:203.16,205.3 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:210.15,211.12 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:211.12,213.4 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:218.42,220.3 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:221.45,223.3 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:229.15,230.41 1 1 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:230.41,232.4 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:233.8,235.3 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:240.42,242.3 1 0 +github.com/hashicorp/consul/agent/consul/snapshot_endpoint.go:243.23,245.3 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:39.53,43.2 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:47.56,51.2 3 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:56.52,60.2 3 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:64.90,65.21 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:74.2,75.16 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:78.2,78.54 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:82.2,85.32 3 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:89.2,89.32 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:65.21,66.35 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:69.3,69.81 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:66.35,68.4 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:69.81,71.4 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:75.16,77.3 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:78.54,80.3 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:85.32,87.3 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:93.70,97.16 3 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:102.2,102.17 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:105.2,105.31 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:97.16,101.3 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:102.17,104.3 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:111.130,113.16 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:117.2,118.16 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:123.2,123.24 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:140.2,140.34 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:113.16,115.3 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:118.16,122.3 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:123.24,129.30 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:134.3,134.26 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:138.3,138.26 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:129.30,132.4 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:134.26,137.4 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:145.105,147.16 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:150.2,150.25 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:153.2,153.58 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:147.16,149.3 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:150.25,152.3 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:159.92,161.16 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:164.2,164.17 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:171.2,171.17 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:161.16,163.3 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:164.17,166.17 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:169.3,169.40 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:166.17,168.4 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:176.83,178.16 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:181.2,182.28 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:185.2,185.44 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:178.16,180.3 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:182.28,184.3 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:189.66,191.25 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:194.2,195.33 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:199.2,199.18 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:191.25,193.3 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:195.33,198.3 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:202.93,204.16 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:208.2,209.29 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:213.2,213.21 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:216.2,216.19 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:204.16,206.3 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:209.29,212.3 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:213.21,215.3 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:219.54,221.65 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:224.2,224.21 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:221.65,223.3 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:227.60,229.16 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:232.2,233.29 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:250.2,250.21 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:253.2,253.19 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:229.16,231.3 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:233.29,238.63 3 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:243.3,244.63 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:238.63,240.12 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:244.63,246.12 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:250.21,252.3 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:257.81,259.16 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:262.2,262.66 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:259.16,261.3 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:266.84,268.16 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:271.2,272.57 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:275.2,275.18 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:268.16,270.3 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:272.57,274.3 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:278.96,280.2 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:282.48,284.2 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:286.76,288.2 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:290.76,292.2 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:294.42,296.2 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:298.68,300.68 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:306.2,306.18 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:300.68,302.3 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:302.8,302.28 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:302.28,304.3 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend.go:309.81,311.2 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:313.88,316.2 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:318.81,321.2 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:324.97,327.2 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:329.103,332.2 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:334.78,337.2 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:339.82,342.2 2 1 +github.com/hashicorp/consul/agent/consul/peering_backend.go:344.154,346.2 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:21.99,24.29 3 1 +github.com/hashicorp/consul/agent/consul/rtt.go:32.2,32.37 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:24.29,26.17 2 1 +github.com/hashicorp/consul/agent/consul/rtt.go:29.3,30.39 2 1 +github.com/hashicorp/consul/agent/consul/rtt.go:26.17,28.4 1 0 +github.com/hashicorp/consul/agent/consul/rtt.go:36.32,38.2 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:41.37,44.2 2 1 +github.com/hashicorp/consul/agent/consul/rtt.go:47.42,49.2 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:61.113,64.29 3 1 +github.com/hashicorp/consul/agent/consul/rtt.go:72.2,72.44 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:64.29,66.17 2 1 +github.com/hashicorp/consul/agent/consul/rtt.go:69.3,70.39 2 1 +github.com/hashicorp/consul/agent/consul/rtt.go:66.17,68.4 1 0 +github.com/hashicorp/consul/agent/consul/rtt.go:76.39,78.2 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:81.44,84.2 2 1 +github.com/hashicorp/consul/agent/consul/rtt.go:87.49,89.2 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:101.114,104.31 3 1 +github.com/hashicorp/consul/agent/consul/rtt.go:112.2,112.45 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:104.31,106.17 2 1 +github.com/hashicorp/consul/agent/consul/rtt.go:109.3,110.39 2 1 +github.com/hashicorp/consul/agent/consul/rtt.go:106.17,108.4 1 0 +github.com/hashicorp/consul/agent/consul/rtt.go:116.39,118.2 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:121.44,124.2 2 1 +github.com/hashicorp/consul/agent/consul/rtt.go:127.49,129.2 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:141.123,144.29 3 1 +github.com/hashicorp/consul/agent/consul/rtt.go:152.2,152.49 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:144.29,146.17 2 1 +github.com/hashicorp/consul/agent/consul/rtt.go:149.3,150.39 2 1 +github.com/hashicorp/consul/agent/consul/rtt.go:146.17,148.4 1 0 +github.com/hashicorp/consul/agent/consul/rtt.go:156.44,158.2 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:161.49,164.2 2 1 +github.com/hashicorp/consul/agent/consul/rtt.go:167.54,169.2 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:172.106,173.26 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:174.21,175.32 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:176.28,177.39 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:178.28,179.39 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:180.33,181.44 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:182.10,183.83 1 0 +github.com/hashicorp/consul/agent/consul/rtt.go:192.94,194.23 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:199.2,199.46 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:205.2,207.16 3 1 +github.com/hashicorp/consul/agent/consul/rtt.go:210.2,210.18 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:215.2,216.16 2 1 +github.com/hashicorp/consul/agent/consul/rtt.go:219.2,220.12 2 1 +github.com/hashicorp/consul/agent/consul/rtt.go:194.23,196.3 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:199.46,201.3 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:207.16,209.3 1 0 +github.com/hashicorp/consul/agent/consul/rtt.go:210.18,212.3 1 1 +github.com/hashicorp/consul/agent/consul/rtt.go:216.16,218.3 1 0 +github.com/hashicorp/consul/agent/consul/autopilot.go:37.65,39.2 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:41.80,43.2 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:45.153,47.2 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:49.65,51.19 2 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:57.2,60.39 3 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:65.2,65.61 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:51.19,53.3 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:53.8,55.3 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:60.39,61.44 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:61.44,63.4 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:68.71,70.12 2 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:70.12,71.83 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:71.83,73.4 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:77.48,82.49 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:86.2,97.125 2 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:82.49,82.73 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:100.73,102.45 2 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:115.2,115.16 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:102.45,104.17 2 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:112.3,112.24 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:104.17,106.12 2 0 +github.com/hashicorp/consul/agent/consul/autopilot.go:107.9,107.24 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:107.24,109.12 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:118.76,120.9 2 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:124.2,124.43 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:120.9,122.3 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:127.95,137.20 2 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:153.2,154.16 2 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:158.2,158.17 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:162.2,162.20 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:138.23,139.41 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:140.44,143.42 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:144.25,145.43 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:146.10,147.44 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:154.16,156.3 1 0 +github.com/hashicorp/consul/agent/consul/autopilot.go:158.17,160.3 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:165.73,169.16 4 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:174.2,174.19 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:181.2,181.33 1 1 +github.com/hashicorp/consul/agent/consul/autopilot.go:169.16,172.3 2 0 +github.com/hashicorp/consul/agent/consul/autopilot.go:174.19,176.3 1 1 +github.com/hashicorp/consul/agent/consul/flood.go:12.32,16.31 3 1 +github.com/hashicorp/consul/agent/consul/flood.go:16.31,17.10 1 1 +github.com/hashicorp/consul/agent/consul/flood.go:18.25,18.25 0 1 +github.com/hashicorp/consul/agent/consul/flood.go:19.11,19.11 0 1 +github.com/hashicorp/consul/agent/consul/flood.go:27.71,35.15 7 1 +github.com/hashicorp/consul/agent/consul/flood.go:48.2,48.6 1 1 +github.com/hashicorp/consul/agent/consul/flood.go:35.15,39.32 3 1 +github.com/hashicorp/consul/agent/consul/flood.go:45.3,45.38 1 0 +github.com/hashicorp/consul/agent/consul/flood.go:39.32,40.21 1 1 +github.com/hashicorp/consul/agent/consul/flood.go:40.21,43.5 2 1 +github.com/hashicorp/consul/agent/consul/flood.go:48.6,49.10 1 1 +github.com/hashicorp/consul/agent/consul/flood.go:50.33,51.10 1 1 +github.com/hashicorp/consul/agent/consul/flood.go:53.31,54.10 1 0 +github.com/hashicorp/consul/agent/consul/flood.go:56.19,57.80 1 1 +github.com/hashicorp/consul/agent/consul/flood.go:59.18,60.80 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:68.38,77.6 4 1 +github.com/hashicorp/consul/agent/consul/leader.go:77.6,78.10 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:79.56,80.20 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:85.35,86.11 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:113.23,114.10 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:80.20,82.5 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:82.10,84.5 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:87.18,88.29 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:93.5,95.31 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:99.5,99.49 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:101.12,102.29 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:107.5,111.45 5 1 +github.com/hashicorp/consul/agent/consul/leader.go:88.29,90.14 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:95.31,98.6 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:102.29,104.14 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:119.45,121.34 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:138.2,138.79 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:121.34,123.40 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:123.40,129.4 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:129.9,135.4 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:143.51,148.75 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:154.2,157.1 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:159.2,165.40 5 1 +github.com/hashicorp/consul/agent/consul/leader.go:169.2,172.24 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:196.2,196.38 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:203.2,209.9 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:217.2,217.6 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:148.75,150.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:165.40,167.12 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:172.24,173.56 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:191.3,192.29 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:173.56,184.49 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:189.4,189.10 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:184.49,187.14 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:196.38,198.12 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:210.16,211.9 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:212.10,212.10 0 1 +github.com/hashicorp/consul/agent/consul/leader.go:217.6,218.10 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:219.17,220.10 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:221.23,222.10 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:223.19,224.18 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:225.32,226.29 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:227.44,228.30 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:229.38,237.26 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:245.4,252.18 4 1 +github.com/hashicorp/consul/agent/consul/leader.go:237.26,239.13 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:252.18,253.50 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:268.5,268.11 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:253.50,263.15 3 0 +github.com/hashicorp/consul/agent/consul/leader.go:279.65,281.46 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:288.2,301.52 4 1 +github.com/hashicorp/consul/agent/consul/leader.go:305.2,305.61 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:309.2,318.29 6 1 +github.com/hashicorp/consul/agent/consul/leader.go:322.2,324.50 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:331.2,331.80 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:335.2,338.12 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:281.46,283.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:301.52,303.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:305.61,307.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:318.29,320.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:324.50,326.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:331.80,333.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:343.37,372.2 13 1 +github.com/hashicorp/consul/agent/consul/leader.go:376.60,377.27 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:383.2,390.30 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:404.2,404.29 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:551.2,553.12 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:377.27,379.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:390.30,392.33 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:392.33,398.18 3 0 +github.com/hashicorp/consul/agent/consul/leader.go:398.18,400.5 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:404.29,409.17 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:412.3,412.73 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:439.3,439.90 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:505.3,507.17 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:511.3,511.19 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:537.3,538.17 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:541.3,541.99 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:546.3,546.25 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:409.17,411.4 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:412.73,421.21 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:426.4,432.18 4 1 +github.com/hashicorp/consul/agent/consul/leader.go:435.4,435.59 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:421.21,424.5 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:432.18,434.5 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:439.90,441.63 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:445.4,446.18 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:450.4,450.20 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:441.63,443.5 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:446.18,448.5 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:450.20,452.19 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:456.5,473.89 4 1 +github.com/hashicorp/consul/agent/consul/leader.go:489.5,489.14 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:452.19,454.6 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:473.89,478.82 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:478.82,481.7 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:481.12,483.72 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:483.72,485.8 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:489.14,495.81 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:499.6,499.78 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:495.81,497.7 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:507.17,509.4 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:511.19,526.18 5 1 +github.com/hashicorp/consul/agent/consul/leader.go:529.4,529.67 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:526.18,528.5 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:538.17,540.4 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:541.99,543.4 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:547.8,549.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:560.67,570.6 4 1 +github.com/hashicorp/consul/agent/consul/leader.go:570.6,571.43 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:576.3,578.17 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:583.3,583.23 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:589.3,590.32 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:626.3,629.17 3 0 +github.com/hashicorp/consul/agent/consul/leader.go:571.43,573.4 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:578.17,580.4 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:583.23,587.4 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:590.32,592.30 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:596.4,597.40 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:609.4,613.35 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:618.4,623.44 4 0 +github.com/hashicorp/consul/agent/consul/leader.go:592.30,593.13 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:597.40,599.5 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:599.10,601.19 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:605.5,605.35 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:601.19,603.14 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:613.35,615.5 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:629.17,631.4 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:637.55,638.55 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:643.2,643.83 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:638.55,641.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:646.35,648.2 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:650.59,651.29 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:658.2,658.71 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:662.2,666.34 4 1 +github.com/hashicorp/consul/agent/consul/leader.go:651.29,653.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:658.71,660.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:666.34,669.3 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:669.8,671.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:678.68,682.2 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:686.66,690.2 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:694.67,698.2 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:708.9,713.6 4 1 +github.com/hashicorp/consul/agent/consul/leader.go:713.6,714.43 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:718.3,718.40 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:722.3,723.11 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:727.3,727.17 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:714.43,716.4 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:718.40,719.12 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:723.11,725.4 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:727.17,736.61 5 1 +github.com/hashicorp/consul/agent/consul/leader.go:740.4,740.11 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:736.61,738.5 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:741.22,742.15 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:743.59,743.59 0 1 +github.com/hashicorp/consul/agent/consul/leader.go:746.9,759.4 6 1 +github.com/hashicorp/consul/agent/consul/leader.go:763.73,768.2 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:770.39,775.2 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:777.61,778.29 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:781.2,781.37 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:778.29,780.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:784.41,787.2 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:789.62,790.91 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:795.2,795.89 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:790.91,793.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:798.42,801.2 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:803.71,804.91 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:809.2,809.29 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:814.2,814.107 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:804.91,807.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:809.29,812.3 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:817.51,821.29 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:821.29,824.3 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:828.72,832.16 4 1 +github.com/hashicorp/consul/agent/consul/leader.go:836.2,836.19 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:840.2,842.105 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:847.2,847.15 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:832.16,835.3 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:836.19,838.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:842.105,845.3 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:850.78,851.91 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:856.2,856.22 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:861.2,861.102 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:868.2,881.16 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:885.2,885.53 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:900.2,900.32 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:923.2,923.12 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:851.91,854.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:856.22,859.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:861.102,866.3 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:881.16,883.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:885.53,886.33 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:886.33,887.52 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:887.52,888.33 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:892.5,892.28 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:888.33,891.6 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:892.28,895.6 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:900.32,903.17 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:907.3,907.22 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:903.17,905.4 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:907.22,918.18 4 1 +github.com/hashicorp/consul/agent/consul/leader.go:918.18,920.5 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:929.100,930.24 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:934.2,936.16 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:939.2,939.31 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1002.2,1002.12 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:930.24,932.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:936.16,938.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:939.31,941.43 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:946.3,946.54 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:951.3,952.17 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:955.3,960.45 4 1 +github.com/hashicorp/consul/agent/consul/leader.go:980.3,990.21 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:998.3,998.65 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:941.43,942.12 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:946.54,947.12 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:952.17,954.4 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:960.45,961.45 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:961.45,963.19 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:968.5,972.19 5 1 +github.com/hashicorp/consul/agent/consul/leader.go:975.5,975.10 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:963.19,965.21 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:972.19,974.6 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:990.21,995.4 4 1 +github.com/hashicorp/consul/agent/consul/leader.go:998.65,1000.4 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1007.60,1009.35 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1016.2,1021.23 4 1 +github.com/hashicorp/consul/agent/consul/leader.go:1031.2,1031.16 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1044.2,1044.12 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1009.35,1015.3 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:1022.24,1023.49 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1024.25,1025.50 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1026.23,1027.48 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1028.18,1029.48 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1031.16,1039.37 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1039.37,1041.4 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1048.62,1049.75 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1052.2,1054.43 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1057.2,1057.14 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1049.75,1051.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1054.43,1056.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1062.95,1063.24 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1068.2,1069.60 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1105.2,1107.16 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:1110.2,1110.57 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1143.2,1164.17 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:1169.2,1170.12 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1063.24,1065.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1069.60,1091.33 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1094.3,1094.36 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1099.3,1099.59 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1091.33,1093.4 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1094.36,1096.4 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1099.59,1101.4 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1107.16,1109.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1110.57,1112.21 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1132.3,1133.17 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1136.3,1136.32 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1112.21,1115.18 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:1118.4,1118.23 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1126.4,1126.14 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1115.18,1117.5 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1118.23,1119.45 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1119.45,1120.26 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1120.26,1123.7 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1126.14,1127.21 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1133.17,1135.4 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1136.32,1137.81 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1137.81,1139.5 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1164.17,1167.3 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1175.96,1176.24 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1181.2,1183.16 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:1187.2,1187.17 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1195.2,1195.42 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1207.2,1232.12 4 1 +github.com/hashicorp/consul/agent/consul/leader.go:1176.24,1178.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1183.16,1185.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1187.17,1193.3 2 0 +github.com/hashicorp/consul/agent/consul/leader.go:1195.42,1198.17 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1201.3,1201.32 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1198.17,1200.4 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1201.32,1202.82 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1202.82,1204.5 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1237.94,1239.2 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1243.94,1245.2 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1248.115,1249.24 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1258.2,1258.55 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1267.2,1267.56 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1274.2,1276.16 3 1 +github.com/hashicorp/consul/agent/consul/leader.go:1279.2,1279.17 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1284.2,1295.12 4 1 +github.com/hashicorp/consul/agent/consul/leader.go:1249.24,1251.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1258.55,1264.3 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1267.56,1268.54 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1268.54,1270.4 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1276.16,1278.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1279.17,1281.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1299.80,1301.21 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1323.2,1324.16 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1329.2,1329.40 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1301.21,1303.34 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1303.34,1305.53 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1305.53,1311.5 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1324.16,1326.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1333.58,1335.33 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1339.2,1339.44 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1335.33,1337.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1348.47,1356.16 4 1 +github.com/hashicorp/consul/agent/consul/leader.go:1356.16,1361.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1364.58,1366.2 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1368.60,1369.58 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1373.2,1379.55 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1389.2,1391.36 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1396.2,1397.14 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1369.58,1371.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1379.55,1382.39 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1382.39,1385.4 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1391.36,1394.3 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1408.73,1409.71 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1416.2,1418.67 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1423.2,1426.14 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1409.71,1413.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1418.67,1420.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1429.67,1431.2 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1433.69,1434.67 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1438.2,1444.55 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1454.2,1456.36 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1461.2,1462.14 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1434.67,1436.3 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1444.55,1447.39 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1447.39,1450.4 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1456.36,1459.3 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1473.82,1474.71 1 1 +github.com/hashicorp/consul/agent/consul/leader.go:1481.2,1483.67 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1488.2,1491.14 2 1 +github.com/hashicorp/consul/agent/consul/leader.go:1474.71,1478.3 1 0 +github.com/hashicorp/consul/agent/consul/leader.go:1483.67,1485.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:91.52,93.2 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:95.91,97.2 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:99.68,114.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:118.2,119.9 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:122.2,122.20 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:114.16,116.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:119.9,121.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:125.88,131.2 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:133.70,135.19 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:138.2,138.16 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:141.2,141.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:135.19,137.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:138.16,140.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:144.96,147.2 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:149.133,158.2 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:170.85,178.66 4 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:183.2,183.19 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:178.66,180.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:180.8,182.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:190.39,192.2 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:195.79,200.2 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:202.80,208.42 4 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:213.2,213.90 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:208.42,209.58 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:209.58,211.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:219.76,222.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:225.2,225.19 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:248.2,252.59 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:255.2,255.20 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:222.16,224.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:225.19,228.90 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:228.90,230.18 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:233.4,233.25 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:230.18,232.5 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:235.8,235.63 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:235.63,238.32 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:241.3,243.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:238.32,240.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:244.8,246.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:252.59,254.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:259.79,261.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:264.2,265.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:268.2,280.8 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:261.16,263.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:265.16,267.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:285.68,287.6 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:287.6,296.61 5 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:302.3,302.28 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:296.61,299.12 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:308.82,313.2 4 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:315.48,319.39 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:319.39,326.3 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:326.8,330.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:333.28,338.55 4 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:344.2,346.27 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:338.55,339.51 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:339.51,341.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:349.70,351.63 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:355.2,355.98 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:351.63,353.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:358.75,359.68 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:366.2,366.34 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:370.2,373.12 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:359.68,364.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:366.34,368.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:379.49,381.34 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:386.2,388.9 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:395.2,395.15 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:408.2,409.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:412.2,413.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:417.2,419.63 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:422.2,422.46 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:381.34,383.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:389.79,390.13 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:391.18,392.13 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:395.15,400.20 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:400.20,402.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:402.9,404.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:409.16,411.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:413.16,415.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:419.63,421.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:425.100,426.68 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:431.2,435.111 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:438.2,441.71 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:444.2,444.75 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:448.2,449.12 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:426.68,428.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:435.111,437.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:441.71,443.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:444.75,446.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:453.85,455.23 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:456.32,457.55 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:458.31,459.42 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:460.29,461.40 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:462.10,463.28 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:466.3,466.66 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:463.28,465.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:472.98,480.49 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:483.2,484.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:488.2,489.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:494.2,495.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:498.2,499.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:505.2,506.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:509.2,509.44 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:521.2,528.49 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:537.2,537.54 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:547.2,549.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:552.2,552.46 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:567.2,567.74 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:570.2,574.12 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:480.49,482.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:484.16,486.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:489.16,491.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:495.16,497.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:499.16,501.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:506.16,508.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:509.44,516.59 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:516.59,518.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:528.49,533.3 3 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:537.54,540.3 2 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:549.16,551.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:552.46,555.33 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:560.3,564.13 4 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:555.33,557.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:567.74,569.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:583.77,584.39 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:587.2,587.38 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:590.2,590.62 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:584.39,586.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:587.38,589.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:599.116,601.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:605.2,606.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:609.2,610.23 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:614.2,615.30 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:623.2,624.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:630.2,631.60 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:637.2,637.79 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:641.2,641.26 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:652.2,653.47 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:656.2,656.77 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:660.2,661.12 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:601.16,603.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:606.16,608.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:610.23,612.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:615.30,617.17 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:620.3,620.83 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:617.17,619.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:624.16,626.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:631.60,633.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:637.79,639.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:641.26,642.83 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:642.83,644.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:645.8,649.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:653.47,655.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:656.77,658.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:668.137,671.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:676.2,678.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:681.2,681.25 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:685.2,685.73 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:689.2,689.19 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:697.2,698.26 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:709.2,710.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:716.2,717.29 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:728.2,728.26 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:732.2,739.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:742.2,742.46 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:746.2,747.12 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:671.16,673.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:678.16,680.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:681.25,683.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:685.73,687.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:689.19,691.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:691.8,693.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:698.26,700.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:700.8,702.17 2 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:705.3,705.53 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:702.17,704.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:710.16,712.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:717.29,719.45 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:723.3,723.40 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:726.3,726.40 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:719.45,722.4 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:723.40,725.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:728.26,730.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:739.16,741.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:742.46,744.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:750.119,751.26 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:755.2,755.22 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:758.2,758.106 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:751.26,753.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:755.22,757.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:761.81,764.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:767.2,767.15 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:780.2,781.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:786.2,788.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:794.2,795.55 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:800.2,801.101 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:808.2,808.45 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:819.2,820.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:823.2,832.45 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:840.2,840.52 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:844.2,844.31 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:851.2,851.63 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:859.2,859.73 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:863.2,863.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:764.16,766.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:767.15,772.20 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:772.20,774.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:774.9,776.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:781.16,783.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:788.16,790.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:795.55,797.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:801.101,803.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:808.45,813.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:820.16,822.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:832.45,833.63 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:833.63,834.96 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:834.96,836.5 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:840.52,842.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:844.31,845.106 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:845.106,847.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:851.63,852.87 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:856.3,857.13 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:852.87,855.4 2 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:859.73,862.3 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:879.130,881.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:885.2,887.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:892.2,893.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:896.2,903.16 4 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:908.2,908.48 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:923.2,924.24 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:932.2,932.17 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:980.2,981.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:984.2,984.32 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:991.2,992.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:996.2,997.26 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1005.2,1012.16 7 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1015.2,1015.46 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1021.2,1023.105 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1027.2,1029.12 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:881.16,883.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:887.16,889.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:893.16,895.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:903.16,905.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:908.48,911.17 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:916.3,918.13 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:911.17,913.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:924.24,926.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:932.17,941.17 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:951.3,952.17 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:955.3,955.57 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:960.3,960.43 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:966.3,966.56 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:941.17,943.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:952.17,954.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:955.57,959.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:960.43,962.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:966.56,969.18 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:975.4,975.54 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:969.18,971.5 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:981.16,983.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:984.32,985.73 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:985.73,987.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:992.16,994.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:997.26,999.21 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1003.3,1003.40 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:999.21,1002.4 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1012.16,1014.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1015.46,1017.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1023.105,1025.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1035.105,1038.16 2 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1042.2,1042.75 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1046.2,1047.12 2 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1038.16,1040.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1042.75,1044.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1054.111,1056.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1060.2,1061.164 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1067.2,1067.90 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1071.2,1071.75 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1075.2,1076.12 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1056.16,1058.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1061.164,1065.3 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1067.90,1069.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1071.75,1073.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1082.67,1084.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1088.2,1088.58 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1092.2,1094.12 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1084.16,1086.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1088.58,1090.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1099.62,1102.59 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1114.2,1115.12 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1102.59,1104.17 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1109.3,1109.31 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1104.17,1106.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1109.31,1111.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1119.69,1122.6 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1122.6,1123.10 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1124.21,1125.14 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1126.60,1127.53 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1127.53,1129.5 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1129.23,1134.5 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1142.82,1145.70 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1148.2,1151.21 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1156.2,1156.50 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1160.2,1162.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1165.2,1169.53 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1173.2,1174.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1178.2,1178.30 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1182.2,1183.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1187.2,1187.96 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1192.2,1193.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1196.2,1197.12 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1202.2,1202.9 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1211.2,1211.77 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1215.2,1216.12 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1145.70,1147.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1151.21,1154.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1156.50,1158.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1162.16,1164.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1169.53,1171.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1174.16,1176.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1178.30,1180.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1183.16,1185.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1187.96,1189.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1193.16,1195.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1197.12,1199.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1203.20,1204.19 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1205.22,1206.17 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1206.17,1208.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1211.77,1213.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1222.69,1233.37 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1259.2,1259.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1233.37,1235.112 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1240.3,1240.10 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1247.3,1247.55 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1250.3,1251.13 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1235.112,1237.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1241.21,1242.20 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1243.11,1243.11 0 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1247.55,1249.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1252.21,1257.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1264.78,1266.61 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1269.2,1275.21 4 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1282.2,1282.35 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1292.2,1292.68 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1295.2,1295.71 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1298.2,1298.75 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1301.2,1301.12 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1266.61,1268.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1275.21,1278.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1282.35,1283.76 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1286.3,1286.13 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1283.76,1285.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1292.68,1294.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1295.71,1297.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1298.75,1300.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1305.107,1306.29 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1310.2,1312.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1316.2,1323.49 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1326.2,1326.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1306.29,1308.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1312.16,1314.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1323.49,1325.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1332.54,1337.2 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1369.93,1376.40 4 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1381.2,1389.25 4 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1376.40,1378.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1395.130,1398.24 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1401.2,1401.33 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1405.2,1406.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1411.2,1413.30 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1463.2,1463.41 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1398.24,1400.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1401.33,1403.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1406.16,1408.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1414.32,1416.77 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1422.3,1423.25 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1427.30,1429.72 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1432.36,1435.63 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1441.3,1442.25 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1446.31,1448.62 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1454.3,1455.25 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1459.10,1460.103 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1416.77,1418.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1423.25,1426.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1429.72,1431.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1435.63,1437.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1442.25,1445.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1448.62,1450.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1455.25,1458.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1466.122,1468.21 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1475.2,1477.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1481.2,1488.9 7 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1538.2,1539.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1542.2,1542.35 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1560.2,1566.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1570.2,1570.75 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1578.2,1579.30 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1582.2,1582.16 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1587.2,1587.45 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1591.2,1592.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1596.2,1597.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1602.2,1614.9 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1630.2,1630.20 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1468.21,1470.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1470.8,1470.26 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1470.26,1472.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1477.16,1479.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1489.17,1490.35 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1494.3,1494.47 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1496.21,1497.35 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1501.3,1501.43 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1503.16,1504.35 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1508.3,1508.22 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1509.15,1515.34 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1532.3,1532.45 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1534.10,1535.111 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1490.35,1493.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1497.35,1500.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1504.35,1507.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1515.34,1522.33 4 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1530.4,1530.19 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1522.33,1523.45 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1523.45,1525.6 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1525.11,1527.6 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1539.16,1541.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1542.35,1547.27 4 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1547.27,1549.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1550.8,1550.43 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1550.43,1554.76 4 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1557.3,1557.56 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1554.76,1556.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1566.16,1568.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1570.75,1572.47 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1572.47,1574.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1579.30,1581.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1582.16,1584.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1587.45,1589.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1592.16,1594.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1597.16,1599.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1615.17,1617.43 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1618.21,1620.40 2 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1621.15,1623.41 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1624.16,1625.42 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1626.10,1627.41 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1633.52,1635.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1638.2,1638.39 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1641.2,1641.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1635.16,1637.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1638.39,1640.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1644.57,1647.2 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1649.57,1650.63 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1653.2,1654.42 2 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1650.63,1652.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1657.49,1658.18 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1659.16,1660.18 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1661.15,1662.17 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1663.17,1664.19 1 0 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1665.23,1666.25 1 1 +github.com/hashicorp/consul/agent/consul/leader_connect_ca.go:1667.10,1668.18 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:88.94,99.68 3 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:103.2,103.23 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:99.68,101.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:106.94,120.63 4 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:123.2,123.23 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:120.63,122.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:126.101,137.70 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:141.2,141.23 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:137.70,139.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:144.99,158.65 4 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:161.2,161.23 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:158.65,160.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:171.80,179.80 5 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:217.2,217.43 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:226.2,226.46 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:235.2,235.12 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:179.80,183.20 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:188.3,188.21 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:194.3,194.26 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:183.20,186.12 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:188.21,191.12 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:194.26,196.74 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:200.4,201.18 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:196.74,198.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:202.9,202.32 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:202.32,208.4 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:208.9,214.4 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:217.43,219.20 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:219.20,221.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:221.9,223.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:226.46,228.21 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:228.21,230.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:230.9,232.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:238.114,242.58 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:265.2,265.19 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:242.58,245.44 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:251.3,251.55 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:255.3,255.44 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:245.44,247.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:247.9,249.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:251.55,253.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:255.44,256.11 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:257.22,258.21 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:259.20,259.20 0 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:268.115,275.48 4 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:313.2,313.19 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:275.48,279.80 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:290.3,291.17 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:294.3,304.28 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:279.80,280.44 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:287.4,287.56 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:280.44,286.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:291.17,293.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:304.28,305.11 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:306.22,307.21 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:308.20,308.20 0 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:316.97,327.69 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:331.2,331.23 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:327.69,329.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:334.96,350.64 4 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:353.2,353.23 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:350.64,352.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:356.125,359.2 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:361.127,364.2 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:366.124,369.2 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:371.145,373.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:377.2,382.9 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:392.2,395.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:402.2,402.35 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:411.2,418.51 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:434.2,434.31 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:447.2,447.31 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:463.2,463.31 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:477.2,477.32 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:373.16,375.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:383.20,384.22 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:385.10,385.10 0 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:395.16,397.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:402.35,409.3 2 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:418.51,426.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:426.8,432.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:434.31,436.37 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:441.3,444.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:436.37,438.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:438.9,438.24 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:438.24,440.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:447.31,454.11 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:457.3,457.17 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:460.3,460.55 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:454.11,456.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:457.17,459.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:463.31,466.11 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:469.3,469.17 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:472.3,472.53 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:466.11,468.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:469.17,471.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:480.67,486.2 4 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:488.108,493.25 4 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:494.34,495.54 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:496.36,497.49 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:498.33,499.53 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:500.10,501.71 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:505.42,512.2 5 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:514.54,519.2 3 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:521.96,530.50 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:534.2,535.58 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication.go:530.50,532.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:538.90,542.2 3 0 +github.com/hashicorp/consul/agent/consul/acl_replication.go:544.73,548.2 3 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:20.109,22.2 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:24.123,26.2 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:29.74,31.2 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:35.97,40.16 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:47.2,48.28 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:55.2,55.23 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:40.16,41.20 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:44.3,44.116 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:41.20,43.4 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:48.28,49.46 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:49.46,52.4 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:59.98,62.36 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:66.2,69.31 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:79.2,79.29 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:88.2,96.91 3 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:101.2,102.19 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:62.36,64.3 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:69.31,71.17 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:75.3,75.33 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:71.17,73.4 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:79.29,81.17 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:85.3,85.29 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:81.17,83.4 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_backend.go:96.91,98.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:12.104,39.27 3 1 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:77.2,77.41 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:86.2,86.42 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:39.27,41.18 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:44.3,45.18 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:49.3,49.95 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:60.3,60.79 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:41.18,43.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:45.18,47.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:49.95,56.12 4 1 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:60.79,62.42 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:65.4,65.42 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:69.4,73.31 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:62.42,64.5 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:65.42,67.5 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:77.41,81.49 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:81.49,83.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions_oss.go:89.111,91.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_client.go:30.75,32.2 1 0 +github.com/hashicorp/consul/agent/consul/acl_client.go:34.59,38.2 1 0 +github.com/hashicorp/consul/agent/consul/acl_client.go:40.110,43.2 1 0 +github.com/hashicorp/consul/agent/consul/acl_client.go:45.107,48.2 1 0 +github.com/hashicorp/consul/agent/consul/acl_client.go:50.101,53.2 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:122.48,128.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:139.2,140.68 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:146.2,147.17 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:128.16,129.26 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:135.3,135.11 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:129.26,134.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:140.68,143.3 2 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:150.42,151.90 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:151.90,153.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:156.35,157.31 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:160.2,160.12 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:157.31,159.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:165.95,166.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:169.2,169.77 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:173.2,173.52 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:178.2,178.34 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:184.2,186.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:189.2,190.14 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:204.2,207.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:210.2,211.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:215.2,235.16 4 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:239.2,239.128 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:243.2,244.12 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:166.40,168.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:169.77,171.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:173.52,175.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:178.34,180.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:186.16,188.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:190.14,193.26 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:193.26,195.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:195.9,195.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:195.40,197.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:207.16,209.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:211.16,213.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:235.16,237.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:239.128,241.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:247.98,248.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:252.2,252.85 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:258.2,258.33 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:262.2,262.71 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:266.2,268.50 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:281.2,282.53 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:248.40,250.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:252.85,254.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:258.33,260.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:262.71,264.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:268.50,274.113 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:274.113,276.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:276.9,276.88 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:276.88,278.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:282.53,287.52 4 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:302.4,302.51 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:306.4,306.18 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:310.4,312.20 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:316.4,316.21 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:324.4,324.14 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:287.52,289.21 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:289.21,293.51 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:293.51,295.7 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:297.10,300.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:302.51,304.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:306.18,308.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:312.20,314.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:316.21,318.19 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:321.5,321.35 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:318.19,320.6 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:328.138,335.40 5 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:338.2,338.39 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:342.2,342.51 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:346.2,346.48 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:352.2,353.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:356.2,358.32 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:361.2,361.29 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:366.2,366.30 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:391.2,392.28 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:402.2,402.42 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:406.2,411.23 5 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:335.40,337.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:338.39,340.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:342.51,345.3 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:346.48,349.3 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:353.16,355.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:358.32,360.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:361.29,363.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:366.30,368.17 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:371.3,371.18 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:375.3,375.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:379.3,379.51 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:383.3,383.48 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:388.3,388.66 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:368.17,370.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:371.18,372.12 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:375.40,377.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:379.51,382.4 2 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:383.48,386.4 2 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:392.28,394.17 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:397.3,397.20 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:400.3,400.38 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:394.17,396.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:397.20,398.12 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:402.42,404.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:414.91,415.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:419.2,419.93 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:425.2,425.33 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:429.2,429.72 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:433.2,437.16 4 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:443.2,444.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:454.2,454.28 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:458.2,458.23 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:462.2,473.37 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:477.2,478.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:481.2,481.12 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:415.40,417.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:419.93,421.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:425.33,427.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:429.72,431.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:437.16,439.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:439.8,439.88 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:439.88,441.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:444.16,446.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:446.8,446.56 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:446.56,448.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:448.8,448.57 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:448.57,452.3 2 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:454.28,456.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:458.23,460.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:473.37,475.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:478.16,480.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:484.89,485.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:489.2,489.93 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:494.2,494.26 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:500.2,500.70 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:504.2,508.122 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:514.2,519.51 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:525.2,525.16 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:528.2,528.12 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:485.40,487.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:489.93,491.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:494.26,496.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:496.8,496.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:496.40,498.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:500.70,502.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:508.122,510.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:510.8,510.88 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:510.88,512.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:519.51,521.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:521.8,523.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:525.16,527.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:531.85,532.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:536.2,536.84 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:540.2,540.33 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:544.2,544.73 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:548.2,552.113 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:558.2,558.56 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:562.2,562.49 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:567.2,568.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:572.2,572.18 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:593.2,598.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:603.2,605.18 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:609.2,609.12 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:532.40,534.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:536.84,538.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:540.33,542.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:544.73,546.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:552.113,554.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:554.8,554.88 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:554.88,556.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:558.56,560.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:562.49,564.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:568.16,570.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:572.18,573.35 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:580.3,580.51 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:573.35,575.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:580.51,583.4 2 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:584.8,584.41 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:584.41,588.3 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:588.8,591.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:598.16,600.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:605.18,607.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:612.103,613.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:617.2,617.85 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:621.2,621.33 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:630.2,630.71 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:634.2,637.16 4 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:641.2,643.80 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:647.2,648.27 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:657.2,658.53 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:613.40,615.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:617.85,619.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:621.33,622.56 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:627.3,627.51 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:622.56,626.4 3 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:630.71,632.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:637.16,639.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:643.80,645.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:648.27,655.3 3 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:658.53,660.18 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:664.4,667.33 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:675.4,678.14 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:660.18,662.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:667.33,668.29 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:671.5,671.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:668.29,669.14 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:682.113,683.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:687.2,687.33 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:691.2,691.76 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:695.2,696.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:700.2,701.53 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:683.40,685.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:687.33,689.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:691.76,693.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:696.16,698.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:701.53,703.18 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:715.4,716.33 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:729.4,730.14 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:703.18,705.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:716.33,719.21 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:719.21,721.51 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:721.51,723.7 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:724.11,726.6 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:734.101,735.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:739.2,739.85 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:743.2,743.72 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:747.2,748.113 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:754.2,755.53 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:735.40,737.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:739.85,741.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:743.72,745.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:748.113,750.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:750.8,750.87 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:750.87,752.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:755.53,761.27 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:767.4,767.18 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:771.4,772.21 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:775.4,775.14 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:761.27,763.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:763.10,765.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:767.18,769.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:772.21,774.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:779.116,780.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:784.2,784.77 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:788.2,789.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:793.2,794.53 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:780.40,782.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:784.77,786.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:789.16,791.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:794.53,796.18 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:800.4,803.14 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:796.18,798.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:807.92,808.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:812.2,812.91 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:816.2,816.34 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:820.2,820.71 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:824.2,829.120 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:835.2,843.23 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:847.2,847.41 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:851.2,855.21 4 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:865.2,866.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:870.2,870.21 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:905.2,906.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:911.2,911.73 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:916.2,923.16 4 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:928.2,930.127 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:934.2,934.12 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:808.40,810.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:812.91,814.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:816.34,818.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:820.71,822.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:829.120,831.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:831.8,831.88 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:831.88,833.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:843.23,845.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:847.41,849.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:855.21,856.54 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:860.3,861.17 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:856.54,858.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:861.17,863.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:866.16,868.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:870.21,874.17 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:879.3,879.23 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:874.17,876.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:879.23,881.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:882.8,884.21 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:889.3,889.54 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:893.3,893.55 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:884.21,886.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:889.54,891.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:893.55,894.64 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:898.4,898.37 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:894.64,896.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:898.37,900.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:906.16,908.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:911.73,913.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:923.16,925.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:930.127,932.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:937.87,938.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:942.2,942.84 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:946.2,946.34 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:950.2,950.74 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:954.2,959.113 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:965.2,966.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:970.2,970.19 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:974.2,974.54 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:978.2,983.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:987.2,991.12 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:938.40,940.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:942.84,944.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:946.34,948.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:950.74,952.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:959.113,961.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:961.8,961.88 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:961.88,963.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:966.16,968.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:970.19,972.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:974.54,976.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:983.16,985.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:994.106,995.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:999.2,999.85 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1003.2,1003.72 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1007.2,1010.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1016.2,1017.53 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:995.40,997.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:999.85,1001.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1003.72,1005.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1010.16,1012.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1012.8,1012.87 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1012.87,1014.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1017.53,1019.18 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1024.4,1027.36 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1031.4,1032.14 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1019.18,1021.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1027.36,1029.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1038.114,1039.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1043.2,1043.75 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1048.2,1049.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1053.2,1054.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1058.2,1059.48 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1062.2,1062.24 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1068.2,1068.34 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1071.2,1071.37 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1075.2,1075.42 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1088.2,1090.12 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1039.40,1041.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1043.75,1045.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1049.16,1051.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1054.16,1056.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1059.48,1061.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1062.24,1063.52 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1063.52,1065.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1068.34,1070.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1071.37,1073.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1075.42,1076.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1076.40,1078.21 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1078.21,1080.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1081.9,1085.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1095.45,1100.79 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1109.2,1112.12 4 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1100.79,1102.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1115.42,1117.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1119.95,1120.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1124.2,1124.85 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1128.2,1128.70 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1132.2,1134.113 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1140.2,1141.53 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1120.40,1122.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1124.85,1126.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1128.70,1130.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1134.113,1136.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1136.8,1136.87 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1136.87,1138.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1141.53,1147.25 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1153.4,1153.18 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1157.4,1158.19 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1161.4,1161.14 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1147.25,1149.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1149.10,1151.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1153.18,1155.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1158.19,1160.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1165.110,1166.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1170.2,1170.75 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1174.2,1175.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1179.2,1180.53 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1166.40,1168.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1170.75,1172.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1175.16,1177.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1180.53,1182.18 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1186.4,1189.14 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1182.18,1184.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1193.86,1194.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1198.2,1198.89 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1202.2,1202.34 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1206.2,1206.69 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1210.2,1215.118 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1221.2,1229.21 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1233.2,1233.37 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1237.2,1239.19 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1275.2,1275.71 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1279.2,1283.37 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1304.2,1306.47 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1314.2,1316.45 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1327.2,1337.16 5 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1342.2,1344.117 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1348.2,1348.12 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1194.40,1196.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1198.89,1200.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1202.34,1204.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1206.69,1208.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1215.118,1217.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1217.8,1217.88 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1217.88,1219.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1229.21,1231.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1233.37,1235.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1239.19,1242.17 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1247.3,1247.98 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1242.17,1244.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1247.98,1249.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1249.9,1249.29 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1249.29,1251.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1252.8,1253.52 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1258.3,1259.17 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1265.3,1265.33 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1253.52,1255.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1259.17,1261.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1261.9,1261.29 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1261.29,1263.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1265.33,1266.101 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1266.101,1268.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1268.10,1268.31 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1268.31,1270.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1275.71,1277.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1283.37,1284.20 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1296.3,1299.39 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1284.20,1286.18 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1289.4,1289.21 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1292.4,1292.23 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1286.18,1288.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1289.21,1291.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1299.39,1302.4 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1306.47,1307.30 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1310.3,1310.57 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1307.30,1309.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1310.57,1312.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1316.45,1317.28 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1320.3,1320.30 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1323.3,1323.52 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1317.28,1319.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1320.30,1322.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1323.52,1325.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1337.16,1339.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1344.117,1346.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1351.83,1352.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1356.2,1356.84 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1360.2,1360.34 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1364.2,1364.72 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1368.2,1373.113 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1379.2,1380.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1384.2,1384.17 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1388.2,1393.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1397.2,1401.12 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1352.40,1354.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1356.84,1358.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1360.34,1362.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1364.72,1366.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1373.113,1375.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1375.8,1375.88 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1375.88,1377.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1380.16,1382.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1384.17,1386.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1393.16,1395.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1404.100,1405.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1409.2,1409.85 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1413.2,1413.70 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1417.2,1420.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1426.2,1427.53 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1405.40,1407.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1409.85,1411.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1413.70,1415.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1420.16,1422.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1422.8,1422.87 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1422.87,1424.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1427.53,1429.18 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1433.4,1436.14 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1429.18,1431.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1442.108,1443.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1447.2,1447.73 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1452.2,1453.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1457.2,1458.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1462.2,1463.44 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1466.2,1466.24 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1472.2,1472.29 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1475.2,1475.32 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1479.2,1479.38 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1492.2,1494.12 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1443.40,1445.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1447.73,1449.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1453.16,1455.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1458.16,1460.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1463.44,1465.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1466.24,1467.48 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1467.48,1469.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1472.29,1474.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1475.32,1477.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1479.38,1480.36 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1480.36,1482.19 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1482.19,1484.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1485.9,1489.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1499.116,1500.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1504.2,1504.85 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1508.2,1508.33 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1512.2,1512.77 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1516.2,1519.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1525.2,1526.53 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1500.40,1502.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1504.85,1506.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1508.33,1510.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1512.77,1514.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1519.16,1521.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1521.8,1521.87 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1521.87,1523.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1526.53,1528.18 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1532.4,1533.19 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1536.4,1536.14 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1528.18,1530.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1533.19,1535.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1540.107,1541.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1545.2,1545.96 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1549.2,1549.33 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1553.2,1553.76 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1557.2,1562.125 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1568.2,1572.19 4 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1602.2,1602.27 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1607.2,1607.85 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1611.2,1612.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1617.2,1618.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1623.2,1625.25 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1631.2,1631.25 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1635.2,1635.25 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1639.2,1639.23 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1647.2,1647.111 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1653.2,1658.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1662.2,1662.124 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1666.2,1666.12 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1541.40,1543.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1545.96,1547.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1549.33,1551.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1553.76,1555.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1562.125,1564.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1564.8,1564.88 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1564.88,1566.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1572.19,1577.17 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1577.17,1579.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1580.8,1581.52 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1586.3,1589.17 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1595.3,1595.28 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1581.52,1583.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1589.17,1591.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1591.9,1591.29 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1591.29,1593.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1595.28,1597.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1597.9,1597.52 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1597.52,1599.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1602.27,1604.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1607.85,1609.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1612.16,1614.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1614.8,1614.26 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1614.26,1616.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1618.16,1620.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1625.25,1626.103 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1626.103,1628.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1631.25,1633.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1635.25,1637.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1640.42,1640.42 0 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1641.39,1641.39 0 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1642.39,1642.39 0 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1643.10,1644.80 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1647.111,1649.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1649.8,1649.19 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1649.19,1651.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1658.16,1660.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1662.124,1664.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1669.95,1670.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1674.2,1674.84 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1678.2,1678.33 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1682.2,1682.79 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1686.2,1691.113 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1697.2,1698.9 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1705.2,1710.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1714.2,1716.12 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1670.40,1672.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1674.84,1676.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1678.33,1680.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1682.79,1684.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1691.113,1693.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1693.8,1693.88 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1693.88,1695.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1699.18,1700.13 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1701.19,1702.13 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1710.16,1712.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1719.121,1720.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1724.2,1724.85 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1728.2,1728.33 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1732.2,1732.77 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1736.2,1739.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1745.2,1746.53 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1720.40,1722.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1724.85,1726.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1728.33,1730.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1732.77,1734.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1739.16,1741.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1741.8,1741.87 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1741.87,1743.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1746.53,1748.18 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1752.4,1755.14 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1748.18,1750.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1759.113,1760.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1764.2,1764.85 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1768.2,1768.33 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1772.2,1772.76 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1776.2,1778.113 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1784.2,1785.53 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1760.40,1762.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1764.85,1766.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1768.33,1770.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1772.76,1774.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1778.113,1780.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1780.8,1780.87 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1780.87,1782.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1785.53,1787.18 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1791.4,1792.21 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1796.4,1797.14 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1787.18,1789.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1792.21,1794.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1801.104,1802.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1806.2,1806.95 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1810.2,1810.33 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1814.2,1814.75 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1818.2,1823.124 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1829.2,1833.23 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1836.2,1836.45 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1840.2,1840.78 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1845.2,1846.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1850.2,1850.21 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1858.2,1858.47 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1862.2,1862.29 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1872.2,1872.30 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1884.2,1885.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1889.2,1889.74 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1893.2,1893.98 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1897.2,1902.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1906.2,1906.135 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1910.2,1910.12 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1802.40,1804.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1806.95,1808.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1810.33,1812.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1814.75,1816.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1823.124,1825.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1825.8,1825.88 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1825.88,1827.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1833.23,1835.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1836.45,1838.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1840.78,1842.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1846.16,1848.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1850.21,1851.24 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1851.24,1853.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1853.9,1853.42 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1853.42,1855.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1858.47,1860.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1862.29,1863.65 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1863.65,1866.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1866.9,1866.72 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1866.72,1869.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1873.19,1873.19 0 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1874.16,1875.35 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1878.10,1879.95 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1875.35,1877.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1885.16,1887.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1889.74,1891.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1893.98,1895.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1902.16,1904.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1906.135,1908.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1913.93,1914.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1918.2,1918.84 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1922.2,1922.33 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1926.2,1926.78 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1930.2,1935.113 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1941.2,1942.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1946.2,1946.19 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1950.2,1950.78 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1954.2,1960.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1964.2,1966.12 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1914.40,1916.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1918.84,1920.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1922.33,1924.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1926.78,1928.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1935.113,1937.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1937.8,1937.88 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1937.88,1939.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1942.16,1944.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1946.19,1948.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1950.78,1952.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1960.16,1962.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1969.118,1970.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1974.2,1974.85 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1978.2,1978.33 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1982.2,1982.76 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1986.2,1989.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1995.2,1996.53 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1970.40,1972.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1974.85,1976.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1978.33,1980.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1982.76,1984.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1989.16,1991.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1991.8,1991.87 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1991.87,1993.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1996.53,1998.18 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2002.4,2005.35 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2010.4,2011.14 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:1998.18,2000.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2005.35,2008.5 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2015.83,2016.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2020.2,2020.33 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2024.2,2024.22 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2028.2,2028.89 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2032.2,2032.22 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2036.2,2036.67 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2040.2,2043.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2047.2,2048.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2052.2,2053.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2057.2,2058.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2061.2,2061.12 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2016.40,2018.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2020.33,2022.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2024.22,2026.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2028.89,2030.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2032.22,2034.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2036.67,2038.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2043.16,2045.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2048.16,2050.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2053.16,2055.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2058.16,2060.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2064.73,2065.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2069.2,2069.33 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2073.2,2073.22 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2077.2,2077.68 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2081.2,2085.9 3 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2094.2,2095.12 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2065.40,2067.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2069.33,2071.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2073.22,2075.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2077.68,2079.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2086.54,2089.84 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2090.18,2091.13 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2098.119,2099.40 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2103.2,2103.71 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2107.2,2108.16 2 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2112.2,2113.16 2 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2117.2,2118.12 2 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2099.40,2101.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2103.71,2105.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2108.16,2110.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint.go:2113.16,2115.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:13.63,15.6 2 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:15.6,16.43 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:20.3,20.29 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:25.3,25.30 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:16.43,18.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:20.29,21.59 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:21.59,23.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:25.30,26.60 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:26.60,28.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:33.60,40.63 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:44.2,44.84 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:40.63,42.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:47.40,49.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:51.60,53.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:54.59,56.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:57.72,58.27 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:61.2,61.21 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:65.2,68.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:72.2,74.31 2 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:78.2,79.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:83.2,83.22 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:87.2,91.31 2 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:99.2,105.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:110.2,110.37 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:114.2,114.31 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:58.27,60.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:61.21,63.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:68.16,70.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:74.31,76.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:79.16,81.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:83.22,85.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:91.31,92.27 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:95.3,96.48 2 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:92.27,94.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:105.16,107.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:110.37,112.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:117.38,118.11 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:121.2,121.17 1 1 +github.com/hashicorp/consul/agent/consul/acl_token_exp.go:118.11,120.3 1 1 +github.com/hashicorp/consul/agent/consul/client.go:94.60,95.54 1 1 +github.com/hashicorp/consul/agent/consul/client.go:98.2,98.26 1 1 +github.com/hashicorp/consul/agent/consul/client.go:101.2,101.42 1 1 +github.com/hashicorp/consul/agent/consul/client.go:105.2,116.47 3 1 +github.com/hashicorp/consul/agent/consul/client.go:121.2,131.65 3 1 +github.com/hashicorp/consul/agent/consul/client.go:137.2,138.16 2 1 +github.com/hashicorp/consul/agent/consul/client.go:143.2,143.79 1 1 +github.com/hashicorp/consul/agent/consul/client.go:147.2,153.15 3 1 +github.com/hashicorp/consul/agent/consul/client.go:95.54,97.3 1 0 +github.com/hashicorp/consul/agent/consul/client.go:98.26,100.3 1 0 +github.com/hashicorp/consul/agent/consul/client.go:101.42,103.3 1 0 +github.com/hashicorp/consul/agent/consul/client.go:116.47,119.3 2 0 +github.com/hashicorp/consul/agent/consul/client.go:131.65,134.3 2 0 +github.com/hashicorp/consul/agent/consul/client.go:138.16,141.3 2 0 +github.com/hashicorp/consul/agent/consul/client.go:143.79,146.3 2 0 +github.com/hashicorp/consul/agent/consul/client.go:157.35,162.16 4 1 +github.com/hashicorp/consul/agent/consul/client.go:166.2,169.19 3 1 +github.com/hashicorp/consul/agent/consul/client.go:174.2,178.12 3 1 +github.com/hashicorp/consul/agent/consul/client.go:162.16,164.3 1 1 +github.com/hashicorp/consul/agent/consul/client.go:169.19,171.3 1 1 +github.com/hashicorp/consul/agent/consul/client.go:182.32,186.19 2 1 +github.com/hashicorp/consul/agent/consul/client.go:191.2,191.12 1 1 +github.com/hashicorp/consul/agent/consul/client.go:186.19,187.40 1 1 +github.com/hashicorp/consul/agent/consul/client.go:187.40,189.4 1 0 +github.com/hashicorp/consul/agent/consul/client.go:196.84,198.89 1 1 +github.com/hashicorp/consul/agent/consul/client.go:204.2,204.33 1 1 +github.com/hashicorp/consul/agent/consul/client.go:198.89,203.3 1 0 +github.com/hashicorp/consul/agent/consul/client.go:208.49,210.2 1 0 +github.com/hashicorp/consul/agent/consul/client.go:215.61,217.2 1 1 +github.com/hashicorp/consul/agent/consul/client.go:226.76,227.42 1 0 +github.com/hashicorp/consul/agent/consul/client.go:232.2,232.88 1 0 +github.com/hashicorp/consul/agent/consul/client.go:236.2,236.63 1 0 +github.com/hashicorp/consul/agent/consul/client.go:240.2,240.30 1 0 +github.com/hashicorp/consul/agent/consul/client.go:227.42,229.3 1 0 +github.com/hashicorp/consul/agent/consul/client.go:232.88,234.3 1 0 +github.com/hashicorp/consul/agent/consul/client.go:236.63,238.3 1 0 +github.com/hashicorp/consul/agent/consul/client.go:244.95,246.89 1 0 +github.com/hashicorp/consul/agent/consul/client.go:250.2,250.33 1 0 +github.com/hashicorp/consul/agent/consul/client.go:253.2,253.11 1 0 +github.com/hashicorp/consul/agent/consul/client.go:256.2,256.38 1 0 +github.com/hashicorp/consul/agent/consul/client.go:246.89,249.3 1 0 +github.com/hashicorp/consul/agent/consul/client.go:250.33,252.3 1 0 +github.com/hashicorp/consul/agent/consul/client.go:253.11,255.3 1 0 +github.com/hashicorp/consul/agent/consul/client.go:260.51,262.2 1 0 +github.com/hashicorp/consul/agent/consul/client.go:265.80,274.1 2 1 +github.com/hashicorp/consul/agent/consul/client.go:275.2,276.19 2 1 +github.com/hashicorp/consul/agent/consul/client.go:281.2,282.50 2 1 +github.com/hashicorp/consul/agent/consul/client.go:288.2,289.19 2 1 +github.com/hashicorp/consul/agent/consul/client.go:294.2,298.67 3 1 +github.com/hashicorp/consul/agent/consul/client.go:308.2,316.9 3 1 +github.com/hashicorp/consul/agent/consul/client.go:321.2,321.15 1 0 +github.com/hashicorp/consul/agent/consul/client.go:276.19,278.3 1 1 +github.com/hashicorp/consul/agent/consul/client.go:282.50,285.3 2 1 +github.com/hashicorp/consul/agent/consul/client.go:289.19,291.3 1 1 +github.com/hashicorp/consul/agent/consul/client.go:298.67,306.3 3 1 +github.com/hashicorp/consul/agent/consul/client.go:317.28,318.11 1 1 +github.com/hashicorp/consul/agent/consul/client.go:319.22,319.22 0 0 +github.com/hashicorp/consul/agent/consul/client.go:328.41,330.19 2 1 +github.com/hashicorp/consul/agent/consul/client.go:335.2,336.50 2 1 +github.com/hashicorp/consul/agent/consul/client.go:342.2,344.16 3 1 +github.com/hashicorp/consul/agent/consul/client.go:348.2,348.15 1 1 +github.com/hashicorp/consul/agent/consul/client.go:355.2,355.20 1 1 +github.com/hashicorp/consul/agent/consul/client.go:362.2,362.16 1 1 +github.com/hashicorp/consul/agent/consul/client.go:368.2,368.12 1 1 +github.com/hashicorp/consul/agent/consul/client.go:330.19,332.3 1 0 +github.com/hashicorp/consul/agent/consul/client.go:336.50,339.3 2 1 +github.com/hashicorp/consul/agent/consul/client.go:344.16,347.3 2 0 +github.com/hashicorp/consul/agent/consul/client.go:348.15,349.38 1 1 +github.com/hashicorp/consul/agent/consul/client.go:349.38,351.4 1 0 +github.com/hashicorp/consul/agent/consul/client.go:355.20,356.41 1 0 +github.com/hashicorp/consul/agent/consul/client.go:356.41,358.4 1 0 +github.com/hashicorp/consul/agent/consul/client.go:362.16,363.47 1 1 +github.com/hashicorp/consul/agent/consul/client.go:363.47,365.4 1 0 +github.com/hashicorp/consul/agent/consul/client.go:373.55,376.36 2 0 +github.com/hashicorp/consul/agent/consul/client.go:379.2,388.26 2 0 +github.com/hashicorp/consul/agent/consul/client.go:394.2,394.14 1 0 +github.com/hashicorp/consul/agent/consul/client.go:376.36,378.3 1 0 +github.com/hashicorp/consul/agent/consul/client.go:388.26,390.3 1 0 +github.com/hashicorp/consul/agent/consul/client.go:390.8,392.3 1 0 +github.com/hashicorp/consul/agent/consul/client.go:411.64,413.16 2 0 +github.com/hashicorp/consul/agent/consul/client.go:417.2,418.16 2 0 +github.com/hashicorp/consul/agent/consul/client.go:413.16,415.3 1 0 +github.com/hashicorp/consul/agent/consul/client.go:423.62,427.2 3 1 +github.com/hashicorp/consul/agent/consul/client.go:429.60,431.2 1 1 +github.com/hashicorp/consul/agent/consul/client.go:433.44,435.2 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:27.40,28.75 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:32.2,33.16 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:37.2,40.53 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:28.75,30.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:33.16,35.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:40.53,42.18 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:46.4,47.45 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:42.18,44.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:53.40,54.75 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:58.2,59.16 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:63.2,64.16 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:68.2,71.53 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:54.75,56.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:59.16,61.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:64.16,66.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:71.53,73.27 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:78.4,81.18 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:85.4,85.24 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:88.4,92.18 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:96.4,96.24 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:101.4,101.37 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:112.4,115.18 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:118.4,121.18 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:124.4,129.61 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:133.4,133.14 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:73.27,75.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:81.18,83.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:85.24,87.5 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:92.18,94.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:96.24,98.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:101.37,103.19 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:106.5,108.25 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:103.19,105.6 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:108.25,110.6 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:115.18,117.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:121.18,123.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:129.61,131.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:137.113,138.78 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:142.2,143.16 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:147.2,148.16 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:152.2,155.53 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:138.78,140.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:143.16,145.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:148.16,150.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:155.53,160.27 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:238.4,239.18 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:242.4,247.61 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:251.4,251.14 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:160.27,170.19 2 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:174.5,174.25 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:177.5,178.32 2 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:170.19,172.6 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:174.25,176.6 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:180.10,185.19 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:189.5,189.25 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:192.5,196.19 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:200.5,200.25 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:204.5,204.38 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:220.5,221.19 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:224.5,226.23 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:229.5,232.19 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:235.5,235.50 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:185.19,187.6 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:189.25,191.6 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:196.19,198.6 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:200.25,202.6 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:204.38,209.20 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:213.6,213.26 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:216.6,216.73 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:209.20,211.7 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:213.26,215.7 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:221.19,223.6 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:226.23,228.6 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:232.19,234.6 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:239.18,241.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:247.61,249.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:255.106,256.82 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:260.2,261.16 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:265.2,265.42 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:269.2,270.20 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:274.2,274.12 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:256.82,258.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:261.16,263.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:265.42,267.3 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:270.20,272.3 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:277.119,278.82 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:281.2,281.28 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:285.2,287.16 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:290.2,290.85 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:293.2,293.102 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:297.2,300.53 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:278.82,280.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:281.28,283.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:287.16,289.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:290.85,292.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:293.102,295.3 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:300.53,304.18 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:308.4,311.61 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:314.4,314.14 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:304.18,306.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:311.61,313.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:321.118,323.34 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:326.2,326.28 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:329.2,329.85 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:332.2,332.73 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:323.34,325.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:326.28,328.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:329.85,331.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:338.129,340.34 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:343.2,343.28 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:346.2,346.96 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:349.2,349.77 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:340.34,342.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:343.28,345.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:346.96,348.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:352.162,355.16 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:358.2,358.85 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:362.2,369.53 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:355.16,357.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:358.85,360.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:369.53,374.18 4 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:378.4,385.18 4 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:389.4,389.39 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:397.4,397.14 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:374.18,376.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:385.18,387.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:389.39,392.5 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:392.10,395.5 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:402.118,403.85 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:408.2,408.28 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:412.2,414.16 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:418.2,418.85 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:423.2,423.102 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:427.2,430.53 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:476.2,476.12 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:403.85,405.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:408.28,410.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:414.16,416.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:418.85,420.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:423.102,425.3 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:430.53,433.18 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:436.4,436.20 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:441.4,442.39 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:468.4,470.61 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:473.4,473.14 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:433.18,435.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:436.20,438.5 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:442.39,444.19 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:447.5,447.21 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:450.5,450.33 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:461.5,461.28 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:444.19,446.6 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:447.21,449.6 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:450.33,458.6 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:461.28,466.6 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:470.61,472.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:480.121,481.82 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:486.2,486.28 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:490.2,492.16 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:496.2,496.85 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:501.2,501.102 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:505.2,508.53 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:526.2,526.12 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:481.82,483.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:486.28,488.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:492.16,494.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:496.85,498.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:501.102,503.3 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:508.53,511.18 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:514.4,514.20 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:518.4,520.61 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:523.4,523.14 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:511.18,513.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:514.20,516.5 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:520.61,522.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:530.115,532.84 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:536.2,536.33 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:541.2,545.16 4 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:549.2,549.43 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:552.2,552.106 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:557.2,557.112 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:561.2,564.53 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:532.84,534.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:536.33,538.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:545.16,547.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:549.43,551.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:552.106,554.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:557.112,559.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:564.53,567.18 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:570.4,570.20 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:575.4,578.39 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:601.4,602.31 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:606.4,606.61 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:609.4,609.14 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:567.18,569.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:570.20,572.5 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:578.39,585.19 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:588.5,588.21 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:593.5,593.36 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:585.19,587.6 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:588.21,590.6 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:593.36,594.23 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:594.23,597.7 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:602.31,604.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:606.61,608.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:617.125,618.89 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:622.2,624.16 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:627.2,627.85 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:631.2,634.53 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:618.89,620.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:624.16,626.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:627.85,629.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:634.53,636.18 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:640.4,642.14 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:636.18,638.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:647.119,648.90 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:652.2,654.16 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:657.2,657.85 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:660.2,660.25 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:664.2,667.53 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:648.90,650.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:654.16,656.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:657.85,659.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:660.25,662.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:667.53,673.18 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:676.4,676.16 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:681.4,682.18 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:686.4,691.47 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:695.4,695.14 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:673.18,675.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:676.16,680.5 3 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:682.18,684.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:691.47,693.5 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:701.123,703.34 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:706.2,706.82 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:710.2,712.16 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:715.2,715.84 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:719.2,719.85 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:723.2,726.53 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:703.34,705.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:706.82,708.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:712.16,714.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:715.84,717.3 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:719.85,721.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:726.53,728.18 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:732.4,733.29 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:737.4,738.14 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:728.18,730.5 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:733.29,735.5 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:746.42,747.76 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:752.2,753.16 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:757.2,757.84 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:764.2,770.63 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:747.76,749.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:753.16,755.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:757.84,761.3 3 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:776.41,779.61 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:784.2,785.16 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:788.2,788.72 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:791.2,791.24 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:808.2,808.62 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:830.2,830.12 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:779.61,781.3 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:785.16,787.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:788.72,790.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:792.27,793.75 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:796.30,797.14 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:798.26,799.14 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:800.29,801.76 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:804.10,805.37 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:793.75,795.4 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:801.76,803.4 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:808.62,813.3 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:813.8,825.17 6 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:828.3,828.23 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:825.17,827.4 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:833.97,835.82 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:847.2,847.18 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:835.82,839.34 4 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:844.3,845.13 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:839.34,841.4 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:841.9,843.4 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:850.95,856.2 5 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:858.129,866.16 2 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:869.2,869.13 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:866.16,868.3 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:878.30,883.24 4 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:894.2,894.22 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:884.27,885.48 1 1 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:886.30,887.60 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:888.26,889.56 1 0 +github.com/hashicorp/consul/agent/consul/internal_endpoint.go:890.29,891.59 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:13.118,14.93 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:19.2,20.16 2 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:23.2,23.73 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:27.2,27.75 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:31.2,33.16 3 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:36.2,36.19 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:40.2,42.12 2 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:14.93,16.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:20.16,22.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:23.73,25.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:27.75,29.3 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:33.16,35.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:36.19,38.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:46.107,47.93 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:52.2,53.16 2 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:56.2,56.73 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:60.2,60.76 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:65.2,66.16 2 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:71.2,71.37 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:74.2,74.12 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:47.93,49.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:53.16,55.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:56.73,58.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:60.76,62.3 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:66.16,68.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:71.37,73.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:78.110,79.80 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:84.2,85.16 2 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:88.2,88.73 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:92.2,92.75 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:96.2,98.18 2 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:104.2,109.36 2 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:138.2,139.12 2 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:79.80,81.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:85.16,87.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:88.73,90.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:92.75,94.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:98.18,102.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:109.36,124.32 2 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:135.3,135.53 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:125.28,126.43 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:127.27,128.42 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:129.29,130.44 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:131.11,132.42 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:142.99,143.82 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:148.2,149.16 2 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:152.2,152.73 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:156.2,156.75 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:160.2,161.18 2 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:165.2,166.12 2 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:143.82,145.3 1 1 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:149.16,151.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:152.73,154.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:156.75,158.3 1 0 +github.com/hashicorp/consul/agent/consul/operator_autopilot_endpoint.go:161.18,163.3 1 0 +github.com/hashicorp/consul/agent/consul/segment_oss.go:22.53,24.2 1 0 +github.com/hashicorp/consul/agent/consul/segment_oss.go:28.69,29.32 1 1 +github.com/hashicorp/consul/agent/consul/segment_oss.go:33.2,33.17 1 1 +github.com/hashicorp/consul/agent/consul/segment_oss.go:29.32,31.3 1 0 +github.com/hashicorp/consul/agent/consul/segment_oss.go:38.92,39.30 1 1 +github.com/hashicorp/consul/agent/consul/segment_oss.go:43.2,43.12 1 1 +github.com/hashicorp/consul/agent/consul/segment_oss.go:39.30,41.3 1 0 +github.com/hashicorp/consul/agent/consul/segment_oss.go:47.49,48.2 0 1 +github.com/hashicorp/consul/agent/consul/subscribe_backend.go:23.27,25.2 1 1 +github.com/hashicorp/consul/agent/consul/subscribe_backend.go:29.115,31.2 1 1 +github.com/hashicorp/consul/agent/consul/subscribe_backend.go:33.97,35.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_server_oss.go:11.78,13.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_server_oss.go:19.46,21.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_server_oss.go:23.80,25.2 1 1 +github.com/hashicorp/consul/agent/consul/config_oss.go:11.60,13.2 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:20.71,22.45 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:31.2,31.48 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:34.2,38.55 2 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:22.45,24.17 2 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:24.17,26.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:26.9,26.32 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:26.32,28.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:31.48,33.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:38.55,40.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:43.51,44.48 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:47.2,48.55 2 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:44.48,46.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:48.55,50.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:53.76,56.37 2 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:72.2,72.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:56.37,57.46 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:61.3,62.17 2 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:66.3,67.13 2 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:57.46,59.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:62.17,64.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:68.21,70.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:75.114,82.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:87.2,87.9 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:93.2,93.38 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:98.2,98.57 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:102.2,104.17 2 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:82.16,84.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:88.20,89.22 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:90.10,90.10 0 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:93.38,96.3 2 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:98.57,100.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:107.80,108.44 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:112.2,119.55 3 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:135.2,135.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:108.44,110.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:119.55,122.17 2 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:122.17,124.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:125.8,130.107 3 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:130.107,132.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:140.71,148.53 2 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:182.2,182.16 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:186.2,186.57 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:148.53,154.18 2 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:159.4,161.18 3 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:165.4,171.19 2 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:177.4,180.14 3 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:154.18,156.5 1 0 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:161.18,163.5 1 0 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:171.19,173.5 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:173.10,175.5 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:182.16,184.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:189.68,193.6 3 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:193.6,194.10 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:195.21,196.14 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:197.19,198.57 1 0 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:198.57,200.5 1 0 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:205.53,208.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:212.2,212.37 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:233.2,233.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:208.16,210.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:212.37,214.33 2 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:218.3,228.17 4 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:214.33,215.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_federation_state_ae.go:228.17,230.4 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:34.59,36.2 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:46.100,48.2 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:61.97,64.16 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:73.2,73.45 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:76.2,76.49 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:79.2,79.61 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:84.2,90.40 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:112.2,118.19 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:136.2,136.18 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:64.16,67.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:73.45,75.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:76.49,78.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:79.61,81.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:90.40,93.17 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:97.3,98.17 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:102.3,103.17 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:107.3,107.10 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:93.17,95.4 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:98.17,100.4 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:103.17,105.4 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:107.10,109.4 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:118.19,120.17 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:124.3,124.80 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:132.3,133.21 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:120.17,122.4 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:124.80,130.4 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:159.140,160.17 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:164.2,169.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:160.17,162.3 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:176.120,178.31 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:182.2,182.21 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:196.2,197.16 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:202.2,203.16 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:207.2,210.31 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:214.2,214.12 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:178.31,180.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:182.21,184.17 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:189.3,190.17 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:193.3,193.28 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:184.17,186.4 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:190.17,192.4 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:197.16,199.3 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:203.16,205.3 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:210.31,212.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:219.109,231.27 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:253.2,254.12 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:231.27,246.17 3 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:250.3,250.58 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:246.17,248.4 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:259.118,261.16 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:265.2,265.31 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:269.2,270.12 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:261.16,263.3 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:265.31,267.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:274.118,277.63 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:294.2,294.12 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:277.63,278.32 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:281.3,281.43 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:285.3,286.18 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:290.3,291.87 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:278.32,280.4 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:281.43,283.4 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:286.18,288.4 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:299.113,300.31 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:305.2,308.12 3 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:300.31,303.3 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:313.101,314.25 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:318.2,324.12 6 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:314.25,316.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:345.122,348.26 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:353.2,353.44 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:358.2,358.23 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:363.2,363.92 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:368.2,368.26 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:373.2,374.16 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:378.2,381.46 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:387.2,387.12 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:348.26,350.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:353.44,355.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:358.23,360.3 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:363.92,365.3 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:368.26,370.3 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:374.16,376.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:381.46,382.50 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:382.50,384.4 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:390.95,393.16 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:398.2,398.28 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:401.2,401.37 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:406.2,407.16 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:411.2,412.14 2 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:416.2,416.30 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:393.16,395.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:398.28,400.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:401.37,403.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:407.16,409.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:412.14,414.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:419.55,420.39 1 1 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:423.2,423.35 1 0 +github.com/hashicorp/consul/agent/consul/auto_config_endpoint.go:420.39,422.3 1 1 +github.com/hashicorp/consul/agent/consul/autopilot_oss.go:11.57,13.2 1 1 +github.com/hashicorp/consul/agent/consul/autopilot_oss.go:15.69,17.2 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_client_oss.go:12.47,14.2 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_client_oss.go:16.70,18.2 0 1 +github.com/hashicorp/consul/agent/consul/enterprise_client_oss.go:20.42,22.2 1 0 +github.com/hashicorp/consul/agent/consul/enterprise_client_oss.go:24.72,26.2 1 0 +github.com/hashicorp/consul/agent/consul/enterprise_client_oss.go:28.65,30.2 1 0 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:33.59,37.40 1 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:37.40,39.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:43.56,46.9 3 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:53.2,53.39 1 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:47.18,48.62 1 0 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:49.19,50.44 1 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:56.62,60.40 1 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:60.40,61.50 1 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:64.4,64.29 1 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:61.50,63.5 1 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:69.68,72.9 3 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:81.2,81.38 1 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:84.2,85.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:88.2,88.39 1 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:73.18,74.62 1 0 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:75.19,76.44 1 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:81.38,83.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:85.16,87.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:106.67,112.23 4 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:130.2,132.6 2 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:112.23,114.17 2 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:119.3,119.23 1 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:124.3,125.63 2 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:114.17,117.4 2 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:119.23,122.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:132.6,133.10 1 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:134.21,138.14 2 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:139.19,140.16 1 0 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:148.26,149.47 1 1 +github.com/hashicorp/consul/agent/consul/leader_metrics.go:149.47,151.3 1 1 +github.com/hashicorp/consul/agent/consul/server_connect.go:14.101,16.16 2 1 +github.com/hashicorp/consul/agent/consul/server_connect.go:19.2,19.45 1 1 +github.com/hashicorp/consul/agent/consul/server_connect.go:23.2,27.22 3 1 +github.com/hashicorp/consul/agent/consul/server_connect.go:33.2,36.31 3 1 +github.com/hashicorp/consul/agent/consul/server_connect.go:43.2,43.39 1 1 +github.com/hashicorp/consul/agent/consul/server_connect.go:75.2,75.26 1 1 +github.com/hashicorp/consul/agent/consul/server_connect.go:16.16,18.3 1 0 +github.com/hashicorp/consul/agent/consul/server_connect.go:19.45,21.3 1 0 +github.com/hashicorp/consul/agent/consul/server_connect.go:27.22,31.3 1 0 +github.com/hashicorp/consul/agent/consul/server_connect.go:36.31,38.3 1 1 +github.com/hashicorp/consul/agent/consul/server_connect.go:43.39,45.33 2 1 +github.com/hashicorp/consul/agent/consul/server_connect.go:54.3,70.15 2 1 +github.com/hashicorp/consul/agent/consul/server_connect.go:45.33,47.53 2 1 +github.com/hashicorp/consul/agent/consul/server_connect.go:47.53,49.5 1 1 +github.com/hashicorp/consul/agent/consul/server_connect.go:70.15,72.4 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:36.90,40.25 2 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:109.2,109.15 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:40.25,41.10 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:42.21,44.18 2 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:56.23,58.35 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:62.4,63.67 2 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:72.4,72.60 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:78.26,80.41 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:84.4,85.92 2 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:91.24,93.37 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:97.4,100.62 2 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:44.18,49.5 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:49.10,49.18 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:49.18,55.5 2 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:58.35,59.10 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:63.67,68.10 2 0 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:72.60,77.5 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:80.41,81.10 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:85.92,90.5 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:93.37,94.10 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:100.62,105.5 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:113.71,117.96 3 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:120.2,120.12 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:117.96,119.3 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:124.73,128.30 3 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:139.2,139.12 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:128.30,130.98 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:130.98,132.4 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:133.8,135.108 1 0 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:135.108,137.4 1 0 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:143.81,144.67 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:147.2,151.16 3 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:154.2,155.27 2 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:160.2,161.16 2 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:167.2,167.51 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:173.2,173.12 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:144.67,146.3 1 0 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:151.16,153.3 1 0 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:155.27,157.3 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:161.16,163.3 1 0 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:167.51,170.3 2 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:170.8,172.3 1 0 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:180.88,181.66 1 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:184.2,187.28 2 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:194.2,195.16 2 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:206.2,207.27 2 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:212.2,222.12 7 1 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:181.66,183.3 1 0 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:187.28,188.48 1 0 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:188.48,190.4 1 0 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:195.16,197.3 1 0 +github.com/hashicorp/consul/agent/consul/txn_endpoint.go:207.27,209.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:77.40,79.2 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:81.49,83.2 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:85.49,87.2 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:89.47,91.2 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:93.80,95.2 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:97.74,99.2 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:101.59,103.2 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:105.43,107.2 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:109.69,111.2 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:117.40,119.2 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:121.39,124.2 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:126.46,128.2 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:146.48,148.2 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:266.121,268.20 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:271.2,287.16 3 1 +github.com/hashicorp/consul/agent/consul/acl.go:291.2,291.89 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:268.20,270.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:287.16,289.3 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:294.70,295.19 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:298.2,298.27 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:302.2,302.26 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:306.2,307.16 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:311.2,312.37 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:323.2,324.16 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:328.2,338.8 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:295.19,297.3 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:298.27,300.3 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:302.26,304.3 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:307.16,309.3 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:313.15,314.24 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:315.14,316.23 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:317.37,318.60 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:319.10,320.84 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:324.16,326.3 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:341.31,343.2 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:345.133,358.16 4 1 +github.com/hashicorp/consul/agent/consul/acl.go:371.2,371.28 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:379.2,379.108 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:385.2,386.17 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:358.16,359.24 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:359.24,362.4 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:362.9,362.78 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:362.78,365.4 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:365.9,368.4 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:371.28,376.3 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:379.108,383.3 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:392.91,394.76 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:399.2,400.67 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:405.2,408.72 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:413.2,414.20 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:420.2,423.20 3 1 +github.com/hashicorp/consul/agent/consul/acl.go:427.2,427.51 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:430.2,430.26 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:394.76,396.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:400.67,403.3 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:408.72,411.3 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:414.20,417.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:423.20,425.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:427.51,429.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:433.190,445.16 4 1 +github.com/hashicorp/consul/agent/consul/acl.go:461.2,461.91 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:467.2,471.37 4 1 +github.com/hashicorp/consul/agent/consul/acl.go:482.2,482.23 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:485.2,485.17 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:445.16,447.40 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:451.3,451.38 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:458.3,458.18 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:447.40,449.4 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:451.38,452.39 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:452.39,454.5 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:454.10,456.5 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:461.91,463.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:471.37,472.55 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:472.55,474.27 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:474.27,476.5 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:477.9,480.4 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:482.23,484.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:488.181,500.16 4 1 +github.com/hashicorp/consul/agent/consul/acl.go:516.2,516.91 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:522.2,526.33 4 1 +github.com/hashicorp/consul/agent/consul/acl.go:538.2,538.23 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:542.2,542.17 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:500.16,502.35 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:506.3,506.34 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:513.3,513.18 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:502.35,504.4 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:506.34,507.35 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:507.35,509.5 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:509.10,511.5 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:516.91,518.3 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:526.33,527.53 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:527.53,529.25 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:529.25,531.5 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:532.9,535.4 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:538.23,540.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:545.106,546.28 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:557.2,557.36 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:567.2,567.12 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:546.28,555.3 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:557.36,565.3 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:570.95,572.34 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:586.2,586.12 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:572.34,573.35 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:578.3,578.41 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:573.35,575.12 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:578.41,579.33 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:579.33,581.13 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:589.109,597.105 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:603.2,604.16 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:609.2,609.29 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:618.2,629.16 7 1 +github.com/hashicorp/consul/agent/consul/acl.go:633.2,635.22 3 1 +github.com/hashicorp/consul/agent/consul/acl.go:597.105,600.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:604.16,606.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:609.29,610.38 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:613.3,614.70 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:610.38,612.4 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:629.16,631.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:638.161,639.33 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:643.2,644.38 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:648.2,648.26 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:639.33,641.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:644.38,646.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:651.152,652.30 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:656.2,657.35 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:661.2,661.26 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:652.30,654.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:657.35,659.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:664.47,669.2 4 0 +github.com/hashicorp/consul/agent/consul/acl.go:671.46,674.18 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:678.2,681.31 3 1 +github.com/hashicorp/consul/agent/consul/acl.go:689.2,689.17 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:674.18,676.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:681.31,682.21 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:685.3,686.16 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:682.21,683.12 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:692.144,701.21 6 1 +github.com/hashicorp/consul/agent/consul/acl.go:705.2,705.37 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:744.2,744.36 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:748.2,751.33 3 1 +github.com/hashicorp/consul/agent/consul/acl.go:756.2,756.87 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:761.2,762.20 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:768.2,770.20 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:774.2,774.20 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:782.2,782.22 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:701.21,703.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:705.37,706.73 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:724.3,725.19 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:730.3,730.26 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:735.3,735.43 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:706.73,707.45 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:711.4,711.21 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:720.4,720.12 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:707.45,709.5 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:711.21,713.5 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:713.10,718.5 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:725.19,727.12 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:730.26,732.12 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:735.43,738.4 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:738.9,740.4 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:744.36,746.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:751.33,753.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:756.87,759.3 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:762.20,766.3 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:770.20,772.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:774.20,777.40 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:777.40,779.4 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:785.103,787.2 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:789.121,790.23 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:796.2,802.33 5 1 +github.com/hashicorp/consul/agent/consul/acl.go:845.2,845.36 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:849.2,852.31 3 1 +github.com/hashicorp/consul/agent/consul/acl.go:856.2,856.85 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:861.2,862.20 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:868.2,870.20 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:874.2,874.20 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:882.2,882.19 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:790.23,792.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:802.33,803.67 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:825.3,826.19 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:831.3,831.24 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:836.3,836.41 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:803.67,804.45 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:808.4,808.19 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:821.4,821.12 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:804.45,806.5 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:808.19,810.5 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:810.10,812.24 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:815.5,818.6 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:812.24,814.6 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:826.19,828.12 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:831.24,833.12 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:836.41,839.4 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:839.9,841.4 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:845.36,847.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:852.31,854.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:856.85,859.3 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:862.20,866.3 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:870.20,872.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:874.20,877.35 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:877.35,879.4 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:885.121,889.55 3 1 +github.com/hashicorp/consul/agent/consul/acl.go:921.2,921.35 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:889.55,892.17 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:900.3,903.17 3 1 +github.com/hashicorp/consul/agent/consul/acl.go:906.3,908.56 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:892.17,894.4 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:894.9,894.29 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:894.29,896.4 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:896.9,896.44 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:896.44,898.4 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:903.17,905.4 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:908.56,909.74 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:909.74,912.5 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:916.9,918.4 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:924.115,928.53 3 1 +github.com/hashicorp/consul/agent/consul/acl.go:960.2,960.35 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:928.53,931.17 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:939.3,942.17 3 1 +github.com/hashicorp/consul/agent/consul/acl.go:945.3,947.56 2 0 +github.com/hashicorp/consul/agent/consul/acl.go:931.17,933.4 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:933.9,933.29 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:933.29,935.4 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:935.9,935.44 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:935.44,937.4 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:942.17,944.4 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:947.56,948.74 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:948.74,951.5 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:955.9,957.4 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:963.57,964.69 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:968.2,971.25 4 0 +github.com/hashicorp/consul/agent/consul/acl.go:964.69,966.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:974.108,976.21 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:980.2,980.42 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:984.2,984.46 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:988.2,988.54 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:976.21,978.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:980.42,982.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:984.46,986.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:994.75,995.22 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:999.2,999.38 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1004.2,1004.17 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1008.2,1008.65 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1012.2,1015.16 3 1 +github.com/hashicorp/consul/agent/consul/acl.go:1027.2,1029.22 3 1 +github.com/hashicorp/consul/agent/consul/acl.go:1032.2,1035.16 3 1 +github.com/hashicorp/consul/agent/consul/acl.go:1038.2,1041.16 3 1 +github.com/hashicorp/consul/agent/consul/acl.go:1051.2,1052.97 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:995.22,997.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:999.38,1001.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1004.17,1006.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1008.65,1010.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1015.16,1017.28 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:1023.3,1023.32 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1017.28,1021.4 3 1 +github.com/hashicorp/consul/agent/consul/acl.go:1029.22,1031.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1035.16,1037.3 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:1041.16,1042.28 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:1046.3,1046.32 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:1042.28,1045.4 2 0 +github.com/hashicorp/consul/agent/consul/acl.go:1047.8,1047.25 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1047.25,1049.3 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:1055.42,1057.27 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1061.2,1061.28 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1068.2,1068.13 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1057.27,1059.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1061.28,1066.3 3 1 +github.com/hashicorp/consul/agent/consul/acl.go:1076.28,1078.2 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1085.28,1087.16 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:1091.2,1091.20 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1097.2,1097.9 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1114.2,1116.20 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:1087.16,1089.3 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:1091.20,1093.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1098.51,1099.57 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1100.33,1108.4 1 0 +github.com/hashicorp/consul/agent/consul/acl.go:1109.10,1110.67 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1119.96,1121.2 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1126.70,1129.16 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:1132.2,1133.12 2 1 +github.com/hashicorp/consul/agent/consul/acl.go:1129.16,1131.3 1 1 +github.com/hashicorp/consul/agent/consul/acl.go:1138.88,1140.2 1 0 +github.com/hashicorp/consul/agent/consul/acl_oss.go:16.66,18.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_oss.go:20.55,22.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_oss.go:24.68,28.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_oss.go:30.114,32.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_oss.go:35.127,38.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_oss.go:41.133,44.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_oss.go:47.114,49.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_oss.go:51.72,51.73 0 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:34.58,41.76 2 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:47.2,47.74 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:53.2,53.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:41.76,43.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:43.8,43.25 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:43.25,45.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:47.74,49.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:49.8,49.25 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:49.25,51.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:56.59,58.72 2 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:64.2,64.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:58.72,60.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:60.8,60.26 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:60.26,62.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:67.57,69.68 2 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:75.2,75.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:69.68,71.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:71.8,71.24 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:71.24,73.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:78.64,80.75 2 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:86.2,86.40 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:80.75,82.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:82.8,82.24 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:82.24,84.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:89.45,91.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:93.44,95.29 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:99.2,99.72 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:104.2,104.13 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:95.29,97.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:99.72,102.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:112.79,114.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:118.2,118.16 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:122.2,122.69 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:114.16,117.3 2 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:118.16,121.3 2 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:125.59,128.38 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:135.2,135.28 1 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:128.38,130.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:140.92,143.63 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:147.2,148.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:154.2,154.67 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:143.63,145.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:148.16,150.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:150.8,150.63 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:150.63,152.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:157.107,159.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:168.2,168.70 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:159.16,161.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:161.8,161.26 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:161.26,163.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:171.101,173.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:182.2,182.68 1 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:173.16,175.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:175.8,175.24 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:175.24,177.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:185.66,187.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:189.87,191.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:193.41,195.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:197.43,199.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:201.53,213.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:215.135,217.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:223.2,223.74 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:227.2,228.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:231.2,231.31 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:217.16,219.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:219.8,219.26 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:219.26,221.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_server.go:223.74,225.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_server.go:228.16,230.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:52.40,54.34 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:58.2,58.84 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:63.2,64.16 2 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:67.2,67.76 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:71.2,73.16 3 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:76.2,78.12 2 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:54.34,56.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:58.84,60.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:64.16,66.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:67.76,69.3 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:73.16,75.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:84.28,86.34 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:90.2,90.84 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:95.2,96.16 2 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:99.2,99.76 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:103.2,103.50 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:86.34,88.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:90.84,92.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:96.16,98.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:99.76,101.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:109.39,111.73 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:116.2,116.34 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:120.2,122.53 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:111.73,113.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:116.34,118.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:122.53,124.18 2 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:128.4,129.14 2 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:124.18,126.5 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:137.35,139.34 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:143.2,143.72 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:147.2,148.16 2 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:152.2,153.16 2 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:157.2,158.16 2 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:161.2,162.12 2 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:139.34,141.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:143.72,145.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:148.16,150.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:153.16,155.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:158.16,160.3 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:168.23,170.34 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:174.2,174.84 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:179.2,179.63 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:184.2,185.16 2 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:188.2,188.76 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:192.2,193.21 2 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:197.2,198.16 2 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:202.2,203.16 2 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:207.2,209.12 2 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:170.34,172.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:174.84,176.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:179.63,181.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:185.16,187.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:188.76,190.3 1 1 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:193.21,195.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:198.16,200.3 1 0 +github.com/hashicorp/consul/agent/consul/connect_ca_endpoint.go:203.16,205.3 1 0 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:80.98,81.14 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:85.2,89.16 4 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:102.2,103.28 2 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:81.14,83.3 1 0 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:89.16,93.22 4 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:93.22,96.4 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:97.8,101.3 3 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:103.28,105.3 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:108.65,109.14 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:113.2,115.25 3 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:109.14,111.3 1 0 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:118.66,119.41 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:124.2,124.14 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:119.41,123.3 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:124.14,126.3 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:126.8,128.3 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:153.64,154.41 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:157.2,159.43 3 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:154.41,156.3 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:164.64,165.29 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:171.2,171.62 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:175.2,175.48 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:179.2,179.86 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:183.2,183.14 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:165.29,170.3 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:171.62,173.3 1 0 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:175.48,177.3 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:179.86,181.3 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:189.79,191.2 1 0 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:195.56,199.2 3 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:201.59,204.2 2 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:206.62,210.26 3 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:214.2,215.13 2 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:232.2,232.14 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:210.26,212.3 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:215.13,216.42 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:216.42,218.4 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:218.9,218.76 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:218.76,220.4 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:220.9,227.4 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:228.8,230.3 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:237.81,243.72 4 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:243.72,246.3 2 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:251.69,258.2 5 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:260.43,261.20 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:262.9,263.12 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:264.9,265.18 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:266.10,268.20 2 0 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:284.19,296.2 4 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:300.51,302.37 2 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:302.37,304.57 2 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:311.3,313.13 2 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:304.57,307.4 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:307.9,307.24 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:307.24,309.4 1 0 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:314.21,316.3 1 0 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:319.73,320.51 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:328.2,340.53 3 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:355.2,355.16 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:359.2,361.29 2 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:320.51,322.3 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:340.53,346.18 2 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:350.4,353.14 3 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:346.18,348.5 1 0 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:355.16,357.3 1 0 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:366.57,368.41 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:372.2,372.22 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:376.2,376.43 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:368.41,370.3 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:372.22,374.3 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:379.78,380.22 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:384.2,388.33 2 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:399.2,409.57 8 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:414.2,414.53 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:419.2,419.13 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:427.2,427.18 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:380.22,382.3 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:388.33,390.40 2 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:394.3,394.47 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:390.40,392.4 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:394.47,396.4 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:409.57,413.3 3 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:414.53,417.3 2 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:419.13,425.3 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:427.18,428.40 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:428.40,430.4 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:434.79,436.27 2 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:453.2,453.12 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:436.27,437.60 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:442.3,443.34 2 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:449.3,449.9 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:437.60,438.12 1 0 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:443.34,444.40 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:444.40,446.5 1 0 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:449.9,451.4 1 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:456.80,458.31 2 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:463.2,464.12 2 1 +github.com/hashicorp/consul/agent/consul/gateway_locator.go:458.31,462.3 3 1 +github.com/hashicorp/consul/agent/consul/peering_backend_oss.go:11.76,12.64 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend_oss.go:15.2,15.65 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend_oss.go:12.64,14.3 1 1 +github.com/hashicorp/consul/agent/consul/peering_backend_oss.go:18.76,19.64 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend_oss.go:22.2,22.65 1 0 +github.com/hashicorp/consul/agent/consul/peering_backend_oss.go:19.64,21.3 1 0 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:16.69,18.2 1 1 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:21.79,25.76 1 1 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:29.2,30.18 2 1 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:35.2,35.12 1 1 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:25.76,27.3 1 1 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:30.18,32.3 1 1 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:32.8,34.3 1 1 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:39.80,43.76 1 1 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:47.2,48.39 2 1 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:52.2,52.56 1 1 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:55.2,55.12 1 1 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:43.76,45.3 1 1 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:48.39,50.3 1 0 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:52.56,54.3 1 1 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:62.41,64.2 1 1 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:67.83,73.16 5 1 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:76.2,77.16 2 1 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:81.2,81.12 1 1 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:73.16,75.3 1 0 +github.com/hashicorp/consul/agent/consul/status_endpoint.go:77.16,79.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:19.64,19.101 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:20.64,20.82 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:21.64,21.83 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:23.100,27.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:31.2,32.56 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:27.16,29.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:35.75,39.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:46.2,47.29 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:39.16,41.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:50.53,55.2 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:56.89,59.2 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:60.90,63.2 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:65.87,68.22 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:82.2,82.28 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:68.22,70.17 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:79.3,79.28 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:70.17,72.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:72.9,72.29 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:72.29,74.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:85.82,92.2 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:94.54,96.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:98.68,100.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:102.66,104.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:106.103,116.2 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:128.65,128.104 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:129.65,129.84 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:130.65,130.86 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:132.101,136.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:140.2,141.58 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:136.16,138.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:144.76,148.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:152.2,153.29 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:148.16,150.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:156.54,161.2 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:162.90,165.2 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:166.91,169.2 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:171.88,174.22 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:182.2,182.28 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:174.22,176.17 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:179.3,179.32 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:176.17,178.4 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:185.83,192.2 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:194.55,196.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:198.69,200.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:202.67,204.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:206.104,213.2 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:225.63,225.99 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:226.63,226.80 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:227.63,227.81 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:229.99,233.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:237.2,238.55 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:233.16,235.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:241.74,245.16 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:249.2,250.29 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:245.16,247.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:253.52,258.2 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:259.88,262.2 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:263.89,266.2 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:268.86,271.22 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:303.2,303.28 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:271.22,279.30 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:283.3,284.33 2 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:290.3,290.31 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:300.3,300.21 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:279.30,281.4 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:284.33,285.34 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:285.34,287.5 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:290.31,291.32 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:294.4,295.25 2 0 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:298.4,298.102 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:291.32,293.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:295.25,297.5 1 0 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:306.81,313.2 3 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:315.53,317.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:319.67,321.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:323.65,325.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_replication_types.go:327.102,336.2 3 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:16.48,17.48 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:17.48,19.3 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:22.154,32.84 4 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:56.2,56.45 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:60.2,60.48 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:64.2,64.27 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:32.84,33.55 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:33.55,35.70 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:39.4,40.18 2 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:35.70,37.5 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:41.9,41.63 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:41.63,47.4 2 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:47.9,53.4 2 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:56.45,58.3 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:60.48,62.3 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:67.80,68.40 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:71.2,71.40 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:75.2,75.68 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:78.2,78.68 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:82.2,82.43 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:68.40,70.3 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:71.40,73.3 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:75.68,77.3 1 0 +github.com/hashicorp/consul/agent/consul/config_replication.go:78.68,80.3 1 0 +github.com/hashicorp/consul/agent/consul/config_replication.go:85.52,89.2 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:91.131,96.75 4 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:100.2,101.32 2 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:127.2,127.20 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:96.75,98.3 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:101.32,103.50 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:106.3,113.17 3 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:117.3,117.25 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:103.50,104.12 1 0 +github.com/hashicorp/consul/agent/consul/config_replication.go:113.17,115.4 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:117.25,118.11 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:119.22,120.21 1 0 +github.com/hashicorp/consul/agent/consul/config_replication.go:121.20,121.20 0 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:130.107,145.70 4 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:149.2,149.23 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:145.70,147.3 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:152.122,154.16 2 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:158.2,163.9 2 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:173.2,176.16 3 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:193.2,193.46 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:201.2,215.24 5 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:231.2,231.22 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:246.2,246.17 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:252.2,252.43 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:154.16,156.3 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:164.20,165.22 1 0 +github.com/hashicorp/consul/agent/consul/config_replication.go:166.10,166.10 0 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:176.16,178.3 1 0 +github.com/hashicorp/consul/agent/consul/config_replication.go:193.46,199.3 2 0 +github.com/hashicorp/consul/agent/consul/config_replication.go:215.24,221.11 3 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:224.3,224.17 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:221.11,223.4 1 0 +github.com/hashicorp/consul/agent/consul/config_replication.go:224.17,226.4 1 0 +github.com/hashicorp/consul/agent/consul/config_replication.go:226.9,228.4 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:231.22,236.11 3 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:239.3,239.17 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:236.11,238.4 1 0 +github.com/hashicorp/consul/agent/consul/config_replication.go:239.17,241.4 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:241.9,243.4 1 1 +github.com/hashicorp/consul/agent/consul/config_replication.go:246.17,248.3 1 1 +github.com/hashicorp/consul/agent/consul/filter.go:13.34,15.2 1 1 +github.com/hashicorp/consul/agent/consul/filter.go:16.43,21.2 3 1 +github.com/hashicorp/consul/agent/consul/filter.go:22.49,24.2 1 1 +github.com/hashicorp/consul/agent/consul/filter.go:28.89,31.2 2 1 +github.com/hashicorp/consul/agent/consul/filter.go:38.38,40.2 1 1 +github.com/hashicorp/consul/agent/consul/filter.go:42.47,45.9 3 1 +github.com/hashicorp/consul/agent/consul/filter.go:62.2,62.14 1 1 +github.com/hashicorp/consul/agent/consul/filter.go:46.24,48.73 2 1 +github.com/hashicorp/consul/agent/consul/filter.go:49.26,51.77 2 1 +github.com/hashicorp/consul/agent/consul/filter.go:52.29,54.86 2 1 +github.com/hashicorp/consul/agent/consul/filter.go:55.27,57.37 2 1 +github.com/hashicorp/consul/agent/consul/filter.go:60.3,60.78 1 1 +github.com/hashicorp/consul/agent/consul/filter.go:57.37,59.4 1 0 +github.com/hashicorp/consul/agent/consul/filter.go:65.53,67.2 1 1 +github.com/hashicorp/consul/agent/consul/filter.go:71.97,74.2 2 1 +github.com/hashicorp/consul/agent/consul/filter.go:86.34,91.14 4 1 +github.com/hashicorp/consul/agent/consul/filter.go:111.2,111.12 1 1 +github.com/hashicorp/consul/agent/consul/filter.go:91.14,92.32 1 1 +github.com/hashicorp/consul/agent/consul/filter.go:95.3,95.15 1 1 +github.com/hashicorp/consul/agent/consul/filter.go:98.3,99.33 2 1 +github.com/hashicorp/consul/agent/consul/filter.go:102.3,103.15 2 1 +github.com/hashicorp/consul/agent/consul/filter.go:92.32,94.4 1 1 +github.com/hashicorp/consul/agent/consul/filter.go:95.15,96.9 1 1 +github.com/hashicorp/consul/agent/consul/filter.go:99.33,101.4 1 1 +github.com/hashicorp/consul/agent/consul/filter.go:103.15,107.4 3 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:27.44,28.78 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:32.2,33.16 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:37.2,38.16 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:42.2,42.85 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:46.2,49.53 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:28.78,30.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:33.16,35.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:38.16,40.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:42.85,44.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:49.53,53.37 4 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:58.4,58.18 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:61.4,64.18 3 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:67.4,72.61 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:76.4,76.73 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:53.37,55.5 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:55.10,57.5 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:58.18,60.5 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:64.18,66.5 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:72.61,74.5 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:82.44,83.75 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:87.2,88.16 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:92.2,93.16 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:97.2,97.85 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:101.2,104.53 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:83.75,85.3 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:88.16,90.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:93.16,95.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:97.85,99.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:104.53,106.18 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:109.4,112.18 3 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:115.4,120.61 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:124.4,124.14 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:106.18,108.5 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:112.18,114.5 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:120.61,122.5 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:130.44,133.20 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:138.2,138.78 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:142.2,143.16 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:147.2,148.16 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:152.2,152.85 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:156.2,159.53 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:133.20,135.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:138.78,140.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:143.16,145.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:148.16,150.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:152.85,154.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:159.53,163.37 4 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:168.4,168.18 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:171.4,174.18 3 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:177.4,182.61 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:186.4,186.73 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:163.37,165.5 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:165.10,167.5 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:168.18,170.5 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:174.18,176.5 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:182.61,184.5 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:191.116,192.77 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:197.2,197.28 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:202.2,203.9 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:214.2,216.16 3 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:220.2,220.85 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:226.2,226.34 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:234.2,235.16 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:239.2,247.53 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:319.2,319.16 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:353.2,353.12 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:192.77,194.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:197.28,199.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:204.20,205.28 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:206.22,207.30 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:208.20,209.28 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:210.10,211.28 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:216.16,218.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:220.85,222.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:226.34,228.70 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:228.70,231.4 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:235.16,237.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:247.53,251.18 3 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:255.4,256.31 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:291.4,293.37 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:297.4,298.18 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:301.4,306.66 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:310.4,310.86 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:314.4,315.14 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:251.18,253.5 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:256.31,257.40 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:273.5,274.19 2 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:277.5,277.55 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:257.40,259.47 2 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:259.47,261.21 2 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:264.7,264.27 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:267.7,267.32 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:261.21,263.8 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:264.27,266.8 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:274.19,276.6 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:277.55,284.6 3 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:284.11,287.6 2 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:293.37,295.5 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:298.18,300.5 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:306.66,308.5 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:310.86,312.5 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:319.16,322.19 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:325.3,325.19 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:329.3,333.28 2 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:337.3,337.32 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:348.3,348.28 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:322.19,324.4 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:325.19,327.4 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:333.28,336.4 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:337.32,343.41 3 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:346.4,346.83 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:343.41,345.5 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:348.28,351.4 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:359.154,361.2 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:363.154,365.2 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:367.156,372.27 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:375.2,375.108 1 1 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:372.27,374.3 1 0 +github.com/hashicorp/consul/agent/consul/health_endpoint.go:378.154,380.2 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:44.63,46.63 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:52.2,52.18 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:46.63,48.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:48.8,48.23 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:48.23,50.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:62.48,64.16 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:67.2,67.25 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:70.2,70.12 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:64.16,66.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:67.25,69.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:74.80,76.34 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:80.2,80.62 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:86.2,88.73 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:91.2,94.47 3 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:98.2,98.26 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:103.2,103.27 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:108.2,110.16 3 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:114.2,119.17 3 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:145.2,145.16 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:148.2,148.16 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:152.2,152.17 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:159.2,163.12 4 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:76.34,78.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:80.62,82.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:88.73,90.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:94.47,96.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:98.26,100.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:103.27,105.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:110.16,112.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:120.33,122.82 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:123.33,125.82 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:126.33,128.76 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:129.33,130.30 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:137.36,140.64 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:141.10,142.64 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:130.30,133.4 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:133.9,136.4 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:145.16,147.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:148.16,150.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:152.17,154.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:154.8,156.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:171.39,176.37 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:191.2,191.29 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:195.2,197.16 3 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:201.2,205.37 3 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:209.2,209.70 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:214.2,214.50 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:222.2,233.17 5 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:176.37,185.3 4 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:191.29,193.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:197.16,199.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:205.37,207.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:209.70,211.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:214.50,216.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:241.39,245.16 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:248.2,248.16 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:252.2,252.26 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:258.2,262.77 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:267.2,267.37 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:271.2,271.70 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:278.2,278.50 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:282.2,293.17 5 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:245.16,247.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:248.16,250.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:252.26,256.3 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:262.77,264.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:267.37,269.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:271.70,273.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:278.50,280.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:301.39,304.29 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:309.2,311.37 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:322.2,323.16 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:327.2,327.22 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:352.2,356.8 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:304.29,307.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:311.37,320.3 4 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:323.16,325.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:327.22,330.35 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:330.35,332.4 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:333.8,334.35 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:334.35,343.66 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:348.4,348.29 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:343.66,345.5 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:364.39,366.16 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:369.2,369.16 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:373.2,373.26 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:379.2,381.8 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:366.16,368.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:369.16,371.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:373.26,377.3 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:389.39,392.37 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:404.2,406.16 3 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:409.2,409.16 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:413.2,416.8 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:392.37,401.3 4 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:406.16,408.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:409.16,411.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:420.102,422.34 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:427.2,427.71 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:432.2,434.16 3 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:438.2,438.23 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:455.2,458.53 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:422.34,424.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:427.71,429.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:434.16,436.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:438.23,440.32 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:443.3,443.95 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:447.3,447.37 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:450.3,450.100 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:440.32,442.4 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:443.95,445.4 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:447.37,449.4 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:450.100,452.4 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:458.53,464.30 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:470.4,470.18 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:473.4,473.18 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:477.4,484.34 4 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:491.4,491.14 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:464.30,466.5 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:466.10,466.32 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:466.32,468.5 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:470.18,472.5 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:473.18,475.5 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:484.34,489.5 3 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:497.102,499.34 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:504.2,504.72 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:508.2,509.16 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:513.2,514.109 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:518.2,518.85 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:522.2,524.53 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:499.34,501.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:504.72,506.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:509.16,511.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:514.109,516.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:518.85,520.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:524.53,531.19 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:536.4,536.18 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:540.4,541.31 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:545.4,545.18 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:550.4,551.18 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:554.4,559.61 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:563.4,563.14 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:531.19,533.5 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:533.10,535.5 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:536.18,538.5 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:541.31,543.5 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:545.18,547.5 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:547.10,549.5 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:551.18,553.5 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:559.61,561.5 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:569.110,571.34 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:576.2,576.73 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:581.2,583.16 3 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:588.2,588.36 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:606.2,615.43 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:627.2,634.53 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:571.34,573.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:576.73,578.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:583.16,585.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:588.36,589.44 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:592.3,592.107 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:597.3,597.44 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:600.3,600.101 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:589.44,591.4 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:592.107,595.4 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:597.44,599.4 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:600.101,603.4 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:615.43,617.41 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:617.41,618.96 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:618.96,623.5 3 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:634.53,636.18 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:640.4,647.18 4 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:651.4,651.39 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:659.4,660.34 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:667.4,667.16 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:671.4,671.14 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:636.18,638.5 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:647.18,649.5 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:651.39,654.5 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:654.10,657.5 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:660.34,661.23 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:661.23,663.11 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:667.16,669.5 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:684.114,686.34 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:691.2,691.73 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:696.2,697.18 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:702.2,704.16 3 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:709.2,709.26 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:712.2,712.31 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:715.2,715.33 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:718.2,718.38 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:722.2,722.90 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:725.2,725.95 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:729.2,729.55 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:739.2,739.44 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:762.2,772.16 5 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:776.2,786.16 3 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:790.2,792.12 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:686.34,688.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:691.73,693.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:697.18,699.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:704.16,706.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:709.26,711.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:712.31,714.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:715.33,717.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:718.38,720.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:722.90,724.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:725.95,727.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:729.55,731.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:739.44,742.93 3 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:742.93,747.4 3 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:772.16,774.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:786.16,789.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:795.79,796.88 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:799.2,799.87 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:802.2,802.93 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:805.2,805.92 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:808.2,808.12 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:796.88,798.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:799.87,801.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:802.93,804.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:805.92,807.3 1 0 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:811.51,812.22 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:816.2,816.19 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:823.2,823.13 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:812.22,814.3 1 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:816.19,818.23 2 1 +github.com/hashicorp/consul/agent/consul/intention_endpoint.go:818.23,820.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:18.80,19.30 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:25.2,26.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:29.2,29.73 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:35.2,35.55 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:72.2,72.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:19.30,21.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:26.16,28.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:29.73,33.3 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:35.55,40.54 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:62.3,62.95 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:40.54,45.18 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:48.4,48.22 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:45.18,47.5 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:48.22,58.5 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:63.8,70.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:77.70,78.55 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:82.2,87.41 4 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:138.2,138.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:78.55,80.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:87.41,89.55 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:93.3,98.17 3 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:104.3,105.17 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:109.3,110.17 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:116.3,117.17 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:122.3,122.72 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:126.3,128.13 3 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:89.55,91.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:98.17,100.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:105.17,107.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:110.17,112.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:117.17,119.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:122.72,124.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:130.21,136.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:141.101,144.32 3 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:153.2,153.28 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:144.32,145.49 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:148.3,148.48 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:151.3,151.49 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:145.49,147.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:148.48,150.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:159.74,160.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:170.2,174.104 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:179.2,181.12 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:160.12,163.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:174.104,176.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:184.83,185.55 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:189.2,237.41 5 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:343.2,343.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:185.55,187.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:237.41,241.7 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:241.7,244.18 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:247.4,247.75 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:254.4,254.24 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:244.18,246.5 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:247.75,252.5 3 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:255.30,256.56 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:286.29,289.19 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:293.5,294.21 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:302.39,317.62 3 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:323.24,324.74 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:328.5,329.15 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:331.12,332.60 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:256.56,267.6 3 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:267.11,267.42 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:267.42,270.20 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:270.20,272.7 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:272.12,272.32 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:272.32,280.7 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:280.12,283.7 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:289.19,291.6 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:294.21,298.6 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:298.11,300.6 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:317.62,319.6 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:319.11,321.6 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:324.74,326.6 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:335.21,341.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:346.110,357.98 3 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:361.2,361.50 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:357.98,359.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:366.114,377.98 3 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:381.2,381.9 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:387.2,387.67 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:391.2,392.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:399.2,399.28 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:407.2,411.32 3 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:430.2,430.43 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:377.98,379.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:382.20,383.29 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:384.10,384.10 0 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:387.67,389.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:392.16,394.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:399.28,400.31 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:400.31,403.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:411.32,417.17 3 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:421.3,421.52 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:417.17,419.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:421.52,422.31 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:422.31,424.5 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:425.9,427.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:435.96,442.34 5 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:445.2,445.35 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:449.2,449.34 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:455.2,455.35 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:464.2,464.25 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:442.34,444.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:445.35,447.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:449.34,450.44 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:450.44,452.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:455.35,457.10 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:457.10,459.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:459.9,459.62 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:459.62,461.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:471.88,473.33 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:481.2,481.33 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:490.2,491.49 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:505.2,505.19 1 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:473.33,479.3 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:481.33,487.3 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:491.49,495.82 3 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:499.3,502.24 2 1 +github.com/hashicorp/consul/agent/consul/leader_intentions.go:495.82,497.4 1 1 +github.com/hashicorp/consul/agent/consul/util.go:17.87,19.28 2 1 +github.com/hashicorp/consul/agent/consul/util.go:40.2,40.60 1 1 +github.com/hashicorp/consul/agent/consul/util.go:19.28,20.33 1 1 +github.com/hashicorp/consul/agent/consul/util.go:23.3,26.17 3 1 +github.com/hashicorp/consul/agent/consul/util.go:30.3,31.17 2 1 +github.com/hashicorp/consul/agent/consul/util.go:35.3,36.37 2 1 +github.com/hashicorp/consul/agent/consul/util.go:20.33,21.12 1 1 +github.com/hashicorp/consul/agent/consul/util.go:26.17,28.4 1 0 +github.com/hashicorp/consul/agent/consul/util.go:31.17,33.4 1 0 +github.com/hashicorp/consul/agent/consul/util.go:36.37,38.4 1 1 +github.com/hashicorp/consul/agent/consul/util.go:45.49,46.30 1 1 +github.com/hashicorp/consul/agent/consul/util.go:49.2,49.27 1 1 +github.com/hashicorp/consul/agent/consul/util.go:46.30,48.3 1 1 +github.com/hashicorp/consul/agent/consul/util.go:53.39,62.2 1 0 +github.com/hashicorp/consul/agent/consul/util.go:91.74,94.14 2 1 +github.com/hashicorp/consul/agent/consul/util.go:101.2,103.9 2 1 +github.com/hashicorp/consul/agent/consul/util.go:113.2,116.13 2 1 +github.com/hashicorp/consul/agent/consul/util.go:94.14,98.3 1 0 +github.com/hashicorp/consul/agent/consul/util.go:103.9,109.3 2 1 +github.com/hashicorp/consul/agent/consul/util.go:121.145,127.2 3 1 +github.com/hashicorp/consul/agent/consul/util.go:132.137,133.99 1 1 +github.com/hashicorp/consul/agent/consul/util.go:133.99,134.72 1 1 +github.com/hashicorp/consul/agent/consul/util.go:139.3,139.48 1 1 +github.com/hashicorp/consul/agent/consul/util.go:134.72,137.4 1 0 +github.com/hashicorp/consul/agent/consul/util.go:144.82,145.39 1 1 +github.com/hashicorp/consul/agent/consul/util.go:145.39,148.3 1 1 +github.com/hashicorp/consul/agent/consul/util.go:148.8,151.3 1 1 +github.com/hashicorp/consul/agent/consul/util.go:155.82,156.39 1 0 +github.com/hashicorp/consul/agent/consul/util.go:160.2,160.39 1 0 +github.com/hashicorp/consul/agent/consul/util.go:156.39,158.3 1 0 +github.com/hashicorp/consul/agent/consul/util.go:163.55,164.32 1 1 +github.com/hashicorp/consul/agent/consul/util.go:169.2,169.14 1 0 +github.com/hashicorp/consul/agent/consul/util.go:164.32,165.42 1 1 +github.com/hashicorp/consul/agent/consul/util.go:165.42,167.4 1 1 +github.com/hashicorp/consul/agent/consul/auto_encrypt_endpoint.go:21.39,22.34 1 1 +github.com/hashicorp/consul/agent/consul/auto_encrypt_endpoint.go:25.2,25.39 1 1 +github.com/hashicorp/consul/agent/consul/auto_encrypt_endpoint.go:31.2,31.48 1 1 +github.com/hashicorp/consul/agent/consul/auto_encrypt_endpoint.go:35.2,35.74 1 1 +github.com/hashicorp/consul/agent/consul/auto_encrypt_endpoint.go:41.2,46.16 5 1 +github.com/hashicorp/consul/agent/consul/auto_encrypt_endpoint.go:50.2,52.16 3 1 +github.com/hashicorp/consul/agent/consul/auto_encrypt_endpoint.go:56.2,61.12 5 1 +github.com/hashicorp/consul/agent/consul/auto_encrypt_endpoint.go:22.34,24.3 1 0 +github.com/hashicorp/consul/agent/consul/auto_encrypt_endpoint.go:25.39,27.3 1 0 +github.com/hashicorp/consul/agent/consul/auto_encrypt_endpoint.go:31.48,34.3 1 1 +github.com/hashicorp/consul/agent/consul/auto_encrypt_endpoint.go:35.74,37.3 1 0 +github.com/hashicorp/consul/agent/consul/auto_encrypt_endpoint.go:46.16,48.3 1 0 +github.com/hashicorp/consul/agent/consul/auto_encrypt_endpoint.go:52.16,54.3 1 0 +github.com/hashicorp/consul/agent/consul/logging.go:15.53,20.2 1 1 +github.com/hashicorp/consul/agent/consul/logging.go:22.56,26.9 4 1 +github.com/hashicorp/consul/agent/consul/logging.go:30.2,30.10 1 1 +github.com/hashicorp/consul/agent/consul/logging.go:26.9,29.3 2 1 +github.com/hashicorp/consul/agent/consul/merge_oss.go:12.79,13.60 1 1 +github.com/hashicorp/consul/agent/consul/merge_oss.go:17.2,17.49 1 1 +github.com/hashicorp/consul/agent/consul/merge_oss.go:21.2,21.12 1 1 +github.com/hashicorp/consul/agent/consul/merge_oss.go:13.60,16.3 1 1 +github.com/hashicorp/consul/agent/consul/merge_oss.go:17.49,20.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint_legacy.go:11.73,13.2 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint_legacy.go:15.78,17.2 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint_legacy.go:21.55,23.2 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint_legacy.go:25.63,27.2 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint_legacy.go:29.73,31.2 1 0 +github.com/hashicorp/consul/agent/consul/replication.go:108.67,109.19 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:112.2,112.28 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:115.2,115.26 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:119.2,122.18 3 1 +github.com/hashicorp/consul/agent/consul/replication.go:125.2,136.8 2 1 +github.com/hashicorp/consul/agent/consul/replication.go:109.19,111.3 1 0 +github.com/hashicorp/consul/agent/consul/replication.go:112.28,114.3 1 0 +github.com/hashicorp/consul/agent/consul/replication.go:115.26,118.3 2 1 +github.com/hashicorp/consul/agent/consul/replication.go:122.18,124.3 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:139.53,142.6 2 1 +github.com/hashicorp/consul/agent/consul/replication.go:142.6,146.45 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:151.3,152.11 2 1 +github.com/hashicorp/consul/agent/consul/replication.go:155.3,155.17 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:173.3,182.19 5 1 +github.com/hashicorp/consul/agent/consul/replication.go:146.45,148.4 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:152.11,154.4 1 0 +github.com/hashicorp/consul/agent/consul/replication.go:155.17,163.61 3 1 +github.com/hashicorp/consul/agent/consul/replication.go:167.4,167.45 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:170.4,170.12 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:163.61,165.5 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:167.45,169.5 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:186.37,188.2 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:197.50,199.2 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:201.128,203.2 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:242.47,244.2 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:246.120,251.16 4 1 +github.com/hashicorp/consul/agent/consul/replication.go:255.2,260.9 2 1 +github.com/hashicorp/consul/agent/consul/replication.go:270.2,273.16 3 1 +github.com/hashicorp/consul/agent/consul/replication.go:290.2,290.35 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:298.2,306.16 3 1 +github.com/hashicorp/consul/agent/consul/replication.go:310.2,315.27 2 1 +github.com/hashicorp/consul/agent/consul/replication.go:331.2,331.25 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:349.2,349.32 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:251.16,253.3 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:261.20,262.22 1 0 +github.com/hashicorp/consul/agent/consul/replication.go:263.10,263.10 0 1 +github.com/hashicorp/consul/agent/consul/replication.go:273.16,275.3 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:290.35,296.3 2 1 +github.com/hashicorp/consul/agent/consul/replication.go:306.16,308.3 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:315.27,321.11 3 1 +github.com/hashicorp/consul/agent/consul/replication.go:325.3,325.17 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:328.3,328.39 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:321.11,323.4 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:325.17,327.4 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:331.25,337.11 3 1 +github.com/hashicorp/consul/agent/consul/replication.go:341.3,341.17 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:344.3,344.37 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:337.11,339.4 1 1 +github.com/hashicorp/consul/agent/consul/replication.go:341.17,343.4 1 1 +github.com/hashicorp/consul/agent/consul/server_lookup.go:18.38,23.2 1 1 +github.com/hashicorp/consul/agent/consul/server_lookup.go:25.60,30.2 4 1 +github.com/hashicorp/consul/agent/consul/server_lookup.go:32.63,37.2 4 1 +github.com/hashicorp/consul/agent/consul/server_lookup.go:40.82,44.9 4 1 +github.com/hashicorp/consul/agent/consul/server_lookup.go:47.2,47.51 1 1 +github.com/hashicorp/consul/agent/consul/server_lookup.go:44.9,46.3 1 1 +github.com/hashicorp/consul/agent/consul/server_lookup.go:51.74,55.2 3 1 +github.com/hashicorp/consul/agent/consul/server_lookup.go:57.54,61.41 4 1 +github.com/hashicorp/consul/agent/consul/server_lookup.go:64.2,64.12 1 1 +github.com/hashicorp/consul/agent/consul/server_lookup.go:61.41,63.3 1 1 +github.com/hashicorp/consul/agent/consul/server_lookup.go:67.74,71.41 3 1 +github.com/hashicorp/consul/agent/consul/server_lookup.go:71.41,72.15 1 1 +github.com/hashicorp/consul/agent/consul/server_lookup.go:72.15,74.4 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:22.79,22.80 0 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:24.52,26.2 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:30.84,32.2 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:41.9,42.63 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:49.2,53.16 3 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:61.2,61.22 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:69.2,69.17 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:73.2,73.15 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:77.2,77.12 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:42.63,43.29 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:46.3,46.33 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:43.29,45.4 1 0 +github.com/hashicorp/consul/agent/consul/server_oss.go:53.16,54.61 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:54.61,56.4 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:56.9,56.19 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:56.19,58.4 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:61.22,62.64 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:62.64,64.4 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:64.9,64.19 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:64.19,66.4 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:69.17,71.3 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:73.15,75.3 1 0 +github.com/hashicorp/consul/agent/consul/server_oss.go:82.61,84.2 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:93.76,94.42 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:97.2,97.26 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:100.2,100.44 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:94.42,96.3 1 0 +github.com/hashicorp/consul/agent/consul/server_oss.go:97.26,99.3 1 0 +github.com/hashicorp/consul/agent/consul/server_oss.go:103.88,105.2 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:107.74,109.2 1 0 +github.com/hashicorp/consul/agent/consul/server_oss.go:111.85,113.16 2 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:116.2,116.12 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:113.16,115.3 1 0 +github.com/hashicorp/consul/agent/consul/server_oss.go:122.9,123.20 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:126.2,127.16 2 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:130.2,130.12 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:123.20,124.48 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:124.48,124.62 1 0 +github.com/hashicorp/consul/agent/consul/server_oss.go:127.16,129.3 1 0 +github.com/hashicorp/consul/agent/consul/server_oss.go:137.42,142.33 4 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:152.2,152.45 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:142.33,144.51 2 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:147.3,147.40 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:144.51,146.4 1 0 +github.com/hashicorp/consul/agent/consul/server_oss.go:155.74,157.2 0 0 +github.com/hashicorp/consul/agent/consul/server_oss.go:159.74,161.2 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:163.105,169.9 3 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:175.2,175.62 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:169.9,171.3 1 1 +github.com/hashicorp/consul/agent/consul/server_oss.go:171.8,173.3 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:5.13,6.47 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:7.2,7.47 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:8.2,8.47 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:9.2,9.47 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:10.2,10.47 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:11.2,11.47 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:12.2,12.47 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:13.2,13.47 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:14.2,14.47 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:15.2,15.47 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:16.2,16.47 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:17.2,17.47 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:18.2,18.47 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:19.2,19.47 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:20.2,20.47 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:21.2,21.47 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:6.47,6.95 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:7.47,7.103 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:8.47,8.84 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:9.47,9.111 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:10.47,10.118 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:11.47,11.77 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:12.47,12.76 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:13.47,13.101 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:14.47,14.108 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:15.47,15.105 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:16.47,16.94 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:17.47,17.105 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:18.47,18.115 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:19.47,19.103 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:20.47,20.68 1 1 +github.com/hashicorp/consul/agent/consul/server_register.go:21.47,21.103 1 1 +github.com/hashicorp/consul/agent/consul/acl_authmethod.go:24.115,25.92 1 1 +github.com/hashicorp/consul/agent/consul/acl_authmethod.go:29.2,30.16 2 1 +github.com/hashicorp/consul/agent/consul/acl_authmethod.go:34.2,36.15 2 1 +github.com/hashicorp/consul/agent/consul/acl_authmethod.go:25.92,27.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_authmethod.go:30.16,32.3 1 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint_oss.go:15.104,18.2 2 0 +github.com/hashicorp/consul/agent/consul/acl_endpoint_oss.go:20.108,23.2 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint_oss.go:25.100,28.2 2 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint_oss.go:30.106,32.2 1 1 +github.com/hashicorp/consul/agent/consul/acl_endpoint_oss.go:34.128,36.2 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:54.82,55.94 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:59.2,60.16 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:66.2,68.75 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:71.2,75.16 4 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:79.2,79.63 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:84.2,84.47 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:87.2,87.46 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:92.2,92.66 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:99.2,99.51 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:103.2,103.85 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:107.2,107.58 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:114.2,115.16 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:118.2,118.37 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:122.2,122.12 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:55.94,57.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:60.16,62.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:68.75,70.3 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:75.16,77.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:79.63,81.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:84.47,86.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:87.46,89.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:92.66,94.36 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:94.36,96.4 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:99.51,101.3 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:103.85,105.3 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:107.58,109.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:109.8,109.17 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:109.17,112.3 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:115.16,117.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:118.37,120.3 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:131.91,134.16 3 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:138.2,138.17 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:134.16,136.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:139.63,140.63 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:141.63,142.36 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:143.10,144.79 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:148.111,149.25 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:153.2,155.78 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:166.2,178.18 5 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:149.25,151.3 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:155.78,157.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:182.101,183.85 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:187.2,187.73 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:190.2,193.16 3 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:198.2,199.16 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:202.2,204.51 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:208.2,211.53 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:183.85,185.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:187.73,189.3 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:193.16,195.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:199.16,201.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:204.51,206.3 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:211.53,213.18 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:217.4,218.20 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:221.4,221.14 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:213.18,215.5 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:218.20,220.5 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:227.103,228.85 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:232.2,232.74 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:235.2,238.16 3 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:242.2,242.21 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:248.2,255.53 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:228.85,230.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:232.74,234.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:238.16,240.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:242.21,243.67 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:243.67,245.4 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:255.53,257.18 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:262.4,263.34 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:272.4,279.18 5 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:283.4,283.39 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:291.4,291.31 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:295.4,295.14 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:257.18,259.5 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:263.34,264.48 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:269.5,269.53 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:264.48,267.14 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:279.18,281.5 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:283.39,286.5 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:286.10,289.5 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:291.31,293.5 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:310.122,311.85 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:315.2,315.77 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:318.2,321.16 3 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:325.2,325.26 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:329.2,330.34 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:334.2,337.53 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:311.85,313.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:315.77,317.3 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:321.16,323.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:325.26,327.3 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:330.34,332.3 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:337.53,339.18 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:344.4,345.34 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:363.4,365.14 3 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:339.18,341.5 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:345.34,346.48 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:357.5,357.47 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:360.5,360.53 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:346.48,349.14 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:357.47,358.14 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:370.112,371.94 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:377.2,379.76 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:382.2,385.16 3 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:389.2,389.63 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:394.2,394.47 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:398.2,398.51 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:404.2,404.17 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:410.2,410.58 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:417.2,418.16 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:422.2,422.45 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:432.2,432.12 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:371.94,373.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:379.76,381.3 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:385.16,387.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:389.63,391.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:394.47,396.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:398.51,400.3 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:405.63,405.63 0 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:406.10,407.38 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:410.58,412.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:412.8,412.17 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:412.17,415.3 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:418.16,420.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:422.45,427.3 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:427.8,430.3 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:436.124,437.85 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:441.2,441.90 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:444.2,448.16 4 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:451.2,451.95 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:455.2,462.53 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:437.85,439.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:441.90,443.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:448.16,450.3 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:451.95,453.3 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:462.53,469.56 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:484.4,491.18 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:498.4,499.18 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:503.4,503.39 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:514.4,521.18 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:524.4,527.25 3 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:532.4,532.14 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:469.56,473.45 3 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:473.45,480.6 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:491.18,493.5 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:499.18,501.5 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:503.39,509.5 3 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:509.10,512.5 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:521.18,523.5 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:527.25,530.5 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:536.76,540.38 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:543.2,543.19 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:548.2,548.21 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:552.2,552.9 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:560.2,560.12 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:540.38,542.3 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:543.19,546.3 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:548.21,550.3 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:553.46,554.120 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:556.47,557.87 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:566.57,567.14 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:583.2,583.12 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:568.33,570.35 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:574.3,575.17 2 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:578.3,578.26 1 1 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:570.35,572.4 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:575.17,577.4 1 0 +github.com/hashicorp/consul/agent/consul/config_endpoint.go:578.26,580.4 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:45.90,50.79 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:54.2,54.49 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:58.2,62.16 3 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:65.2,65.76 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:69.2,69.54 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:73.2,73.17 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:84.2,85.16 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:88.2,88.37 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:92.2,92.12 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:50.79,52.3 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:54.49,56.3 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:62.16,64.3 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:65.76,67.3 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:69.54,71.3 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:74.37,75.36 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:78.37,78.37 0 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:80.10,81.71 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:75.36,77.4 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:85.16,87.3 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:88.37,90.3 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:95.113,96.77 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:100.2,100.49 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:104.2,108.16 3 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:111.2,111.75 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:115.2,118.53 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:96.77,98.3 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:100.49,102.3 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:108.16,110.3 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:111.75,113.3 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:118.53,120.18 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:124.4,125.23 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:128.4,128.14 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:120.18,122.5 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:125.23,127.5 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:134.111,135.78 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:139.2,139.49 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:143.2,147.16 3 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:150.2,150.75 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:154.2,157.53 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:135.78,137.3 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:139.49,141.3 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:147.16,149.3 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:150.75,152.3 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:157.53,159.18 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:163.4,163.27 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:167.4,170.14 3 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:159.18,161.5 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:163.27,165.5 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:177.134,178.90 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:182.2,182.49 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:186.2,191.53 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:178.90,180.3 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:182.49,184.3 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:191.53,193.18 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:197.4,199.29 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:209.4,210.61 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:214.4,214.14 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:193.18,195.5 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:199.29,202.21 3 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:202.21,206.6 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_endpoint.go:210.61,212.5 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:49.94,50.77 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:53.2,57.44 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:78.2,82.16 3 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:89.2,89.49 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:99.2,99.44 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:118.2,118.17 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:133.2,134.16 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:137.2,137.12 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:50.77,52.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:57.44,58.26 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:64.3,65.7 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:58.26,60.4 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:65.7,66.60 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:69.4,70.18 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:73.4,73.20 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:66.60,68.5 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:70.18,72.5 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:73.20,74.10 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:82.16,84.3 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:89.49,90.90 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:90.90,93.4 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:99.44,102.17 3 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:105.3,105.19 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:109.3,109.45 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:102.17,104.4 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:105.19,107.4 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:109.45,110.91 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:110.91,113.5 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:119.64,120.48 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:124.35,124.35 0 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:128.10,129.69 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:120.48,122.4 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:134.16,136.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:144.53,156.74 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:163.2,163.44 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:168.2,168.53 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:173.2,173.45 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:177.2,177.12 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:156.74,158.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:163.44,165.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:168.53,170.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:173.45,175.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:184.52,186.23 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:190.2,192.27 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:196.2,196.94 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:201.2,201.73 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:211.2,211.12 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:186.23,188.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:192.27,194.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:196.94,198.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:201.73,203.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:216.51,217.19 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:228.2,228.12 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:217.19,219.17 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:223.3,223.14 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:219.17,221.4 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:223.14,225.4 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:233.47,234.75 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:238.2,241.53 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:234.75,236.3 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:241.53,243.18 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:246.4,246.20 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:253.4,255.42 3 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:260.4,260.61 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:267.4,267.31 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:272.4,272.14 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:243.18,245.5 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:246.20,248.5 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:255.42,257.5 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:260.61,262.5 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:267.31,270.5 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:277.108,278.76 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:282.2,285.53 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:278.76,280.3 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:285.53,287.18 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:291.4,292.45 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:287.18,289.5 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:301.53,302.79 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:305.2,309.28 3 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:316.2,318.16 3 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:321.2,321.18 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:327.2,330.61 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:335.2,335.31 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:340.2,341.12 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:302.79,304.3 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:309.28,310.48 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:310.48,312.4 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:318.16,320.3 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:321.18,323.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:330.61,332.3 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:335.31,338.3 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:348.53,349.79 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:352.2,355.28 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:362.2,364.16 3 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:367.2,367.18 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:372.2,372.62 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:378.2,379.23 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:382.2,382.54 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:392.2,401.25 4 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:404.2,404.47 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:409.2,409.25 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:439.2,440.16 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:446.2,446.56 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:462.2,462.53 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:469.2,469.27 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:476.2,476.12 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:349.79,351.3 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:355.28,356.48 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:356.48,358.4 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:364.16,366.3 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:367.18,369.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:372.62,374.3 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:379.23,381.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:382.54,384.3 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:401.25,403.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:404.47,406.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:409.25,411.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:411.8,411.29 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:411.29,412.27 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:433.3,433.23 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:412.27,414.18 2 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:418.4,418.31 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:414.18,416.5 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:418.31,419.39 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:419.39,421.11 2 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:424.9,429.4 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:433.23,435.4 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:440.16,442.3 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:446.56,447.36 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:447.36,448.50 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:455.4,455.14 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:448.50,450.10 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:455.14,456.10 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:462.53,464.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:469.27,471.68 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:471.68,473.4 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:485.53,486.85 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:489.2,492.28 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:499.2,499.68 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:505.2,506.28 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:509.2,509.54 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:514.2,522.53 3 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:526.2,526.12 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:486.85,488.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:492.28,493.48 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:493.48,495.4 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:499.68,501.3 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:506.28,508.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:509.54,511.3 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:522.53,524.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:533.27,539.43 3 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:543.2,544.16 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:549.2,553.37 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:558.2,558.40 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:563.2,563.33 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:568.2,574.52 5 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:581.2,581.12 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:539.43,541.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:544.16,546.3 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:553.37,555.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:558.40,560.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:563.33,565.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:574.52,577.3 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:577.8,579.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:587.90,590.27 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:600.2,601.25 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:635.2,635.18 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:590.27,592.34 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:592.34,595.4 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:595.9,597.4 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:601.25,606.26 3 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:614.3,614.28 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:621.3,621.27 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:628.3,628.11 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:631.3,633.6 3 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:606.26,607.42 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:607.42,610.5 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:614.28,615.32 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:615.32,616.16 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:621.27,622.31 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:622.31,623.16 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:640.107,642.29 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:647.2,647.17 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:642.29,643.60 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:643.60,645.4 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:650.110,652.29 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:657.2,657.17 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:652.29,653.63 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:653.63,655.4 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:675.50,677.2 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:680.144,682.2 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:685.55,687.2 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:691.80,695.16 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:699.2,700.25 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:705.2,705.20 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:695.16,697.3 1 0 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:700.25,701.36 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:701.36,703.4 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:712.53,717.16 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:722.2,723.29 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:729.2,731.41 3 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:743.2,743.60 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:765.2,766.33 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:816.2,818.12 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:717.16,719.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:723.29,725.3 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:731.41,732.30 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:732.30,733.46 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:737.4,738.26 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:733.46,734.10 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:743.60,746.40 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:759.3,759.24 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:746.40,747.31 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:754.4,754.31 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:747.31,749.13 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:754.31,756.5 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:759.24,761.4 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:766.33,782.24 5 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:790.3,798.55 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:809.3,809.27 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:782.24,784.4 1 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:798.55,805.12 2 1 +github.com/hashicorp/consul/agent/consul/prepared_query_endpoint.go:809.27,810.9 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:39.72,40.26 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:40.26,42.3 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:47.76,48.71 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:51.2,54.64 2 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:57.2,57.65 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:63.2,67.16 3 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:71.2,71.92 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:75.2,75.17 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:99.2,99.31 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:110.2,110.28 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:126.2,126.38 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:147.2,148.16 2 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:152.2,152.64 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:162.2,162.41 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:165.2,165.12 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:48.71,50.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:54.64,56.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:57.65,59.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:67.16,69.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:71.92,73.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:76.30,79.17 3 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:82.3,82.22 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:85.3,85.101 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:89.29,90.105 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:94.10,95.61 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:79.17,81.4 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:82.22,84.4 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:85.101,87.4 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:90.105,92.4 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:100.10,102.53 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:103.34,103.34 0 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:104.33,104.33 0 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:105.10,106.76 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:110.28,112.17 2 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:116.3,116.84 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:112.17,114.4 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:116.84,119.4 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:126.38,129.7 2 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:129.7,131.62 2 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:135.4,136.18 2 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:140.4,140.19 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:131.62,134.5 2 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:136.18,139.5 2 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:140.19,141.10 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:148.16,150.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:152.64,155.3 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:155.8,155.46 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:155.46,159.3 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:162.41,164.3 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:170.40,171.69 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:175.2,179.16 4 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:183.2,183.85 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:187.2,190.53 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:171.69,173.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:179.16,181.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:183.85,185.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:190.53,192.18 2 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:196.4,197.22 2 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:203.4,204.14 2 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:192.18,194.5 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:197.22,199.5 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:199.10,202.5 2 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:210.40,211.70 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:215.2,217.16 3 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:221.2,221.85 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:225.2,228.53 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:211.70,213.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:217.16,219.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:221.85,223.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:228.53,230.18 2 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:234.4,236.14 3 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:230.18,232.5 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:242.40,243.78 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:247.2,249.16 3 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:253.2,253.85 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:257.2,260.53 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:243.78,245.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:249.16,251.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:253.85,255.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:260.53,262.18 2 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:266.4,268.14 3 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:262.18,264.5 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:274.40,275.71 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:279.2,286.16 5 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:290.2,290.84 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:295.2,297.16 3 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:301.2,302.20 2 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:306.2,306.99 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:311.2,312.57 2 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:317.2,317.12 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:275.71,277.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:286.16,288.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:290.84,292.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:297.16,299.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:302.20,304.3 1 0 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:306.99,308.3 1 1 +github.com/hashicorp/consul/agent/consul/session_endpoint.go:312.57,315.3 2 0 +github.com/hashicorp/consul/agent/consul/session_timers.go:15.40,17.2 1 1 +github.com/hashicorp/consul/agent/consul/session_timers.go:20.52,24.2 3 1 +github.com/hashicorp/consul/agent/consul/session_timers.go:28.56,31.15 3 1 +github.com/hashicorp/consul/agent/consul/session_timers.go:31.15,33.3 1 1 +github.com/hashicorp/consul/agent/consul/session_timers.go:33.8,35.3 1 1 +github.com/hashicorp/consul/agent/consul/session_timers.go:39.40,41.2 1 1 +github.com/hashicorp/consul/agent/consul/session_timers.go:44.35,48.2 3 1 +github.com/hashicorp/consul/agent/consul/session_timers.go:52.87,56.30 3 1 +github.com/hashicorp/consul/agent/consul/session_timers.go:60.2,60.42 1 1 +github.com/hashicorp/consul/agent/consul/session_timers.go:56.30,59.3 2 1 +github.com/hashicorp/consul/agent/consul/session_timers.go:64.41,67.30 3 1 +github.com/hashicorp/consul/agent/consul/session_timers.go:67.30,70.3 2 1 +github.com/hashicorp/consul/agent/consul/session_timers.go:74.35,77.25 3 1 +github.com/hashicorp/consul/agent/consul/session_timers.go:80.2,80.36 1 1 +github.com/hashicorp/consul/agent/consul/session_timers.go:77.25,79.3 1 1 +github.com/hashicorp/consul/agent/consul/acl_authmethod_oss.go:6.57,8.2 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:78.62,79.16 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:83.2,83.48 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:86.2,86.78 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:89.2,89.74 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:92.2,92.35 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:98.2,98.14 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:79.16,81.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:83.48,85.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:86.78,88.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:89.74,91.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:92.35,93.51 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:93.51,95.4 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:103.82,104.83 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:108.2,108.74 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:111.2,115.16 3 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:119.2,119.88 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:125.2,127.16 3 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:132.2,132.65 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:135.2,135.48 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:140.2,140.25 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:147.2,147.23 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:151.2,151.36 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:166.2,167.16 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:170.2,170.60 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:174.2,175.12 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:104.83,106.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:108.74,110.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:115.16,117.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:119.88,121.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:127.16,129.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:132.65,134.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:135.48,137.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:140.25,141.93 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:141.93,143.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:147.23,150.3 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:151.36,152.23 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:155.3,159.23 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:152.23,154.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:159.23,162.4 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:167.16,169.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:170.60,172.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:179.50,180.20 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:183.2,183.18 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:189.2,189.12 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:180.20,182.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:183.18,184.51 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:184.51,186.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:192.124,196.43 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:201.2,201.47 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:206.2,206.47 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:212.2,212.35 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:216.2,224.50 3 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:231.2,231.53 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:237.2,237.12 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:196.43,198.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:201.47,203.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:206.47,208.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:212.35,214.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:224.50,225.103 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:225.103,227.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:231.53,232.124 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:232.124,234.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:241.48,242.45 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:242.45,244.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:265.9,274.15 4 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:283.2,283.25 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:307.2,307.23 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:313.2,313.36 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:364.2,364.12 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:274.15,275.94 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:275.94,277.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:283.25,284.108 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:288.3,288.16 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:284.108,286.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:288.16,291.10 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:291.10,298.103 3 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:298.103,300.6 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:307.23,309.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:313.36,321.48 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:327.3,327.28 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:338.3,338.64 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:344.3,344.16 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:348.3,349.10 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:356.3,359.101 3 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:321.48,324.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:327.28,328.95 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:331.4,331.12 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:328.95,330.5 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:338.64,339.12 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:344.16,346.4 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:349.10,351.4 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:359.101,361.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:374.86,375.76 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:378.2,381.21 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:386.2,387.16 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:391.2,391.84 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:396.2,399.26 3 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:406.2,407.24 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:414.2,414.66 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:418.2,419.12 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:375.76,377.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:381.21,383.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:387.16,389.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:391.84,393.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:399.26,401.17 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:401.17,403.4 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:407.24,409.17 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:409.17,411.4 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:414.66,416.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:432.9,444.25 4 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:452.2,452.26 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:484.2,484.12 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:444.25,446.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:452.26,453.16 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:457.3,459.98 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:453.16,455.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:459.98,461.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:462.8,462.31 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:462.31,463.16 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:467.3,469.25 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:463.16,465.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:469.25,470.103 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:470.103,472.5 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:473.9,474.95 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:474.95,476.5 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:478.8,482.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:488.92,490.16 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:494.2,494.19 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:498.2,499.12 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:490.16,492.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:494.19,496.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:503.97,504.75 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:508.2,509.16 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:513.2,516.53 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:504.75,506.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:509.16,511.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:516.53,518.37 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:523.4,523.18 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:526.4,526.52 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:532.4,533.18 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:536.4,541.61 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:545.4,545.66 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:518.37,520.5 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:520.10,522.5 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:523.18,525.5 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:526.52,530.5 3 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:533.18,535.5 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:541.61,543.5 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:549.65,551.2 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:555.103,556.78 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:560.2,561.16 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:565.2,565.85 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:569.2,570.16 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:576.2,581.53 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:556.78,558.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:561.16,563.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:565.85,567.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:570.16,572.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:581.53,584.37 3 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:589.4,589.18 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:592.4,592.52 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:598.4,599.18 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:603.4,607.14 3 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:584.37,586.5 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:586.10,588.5 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:589.18,591.5 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:592.52,596.5 3 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:599.18,601.5 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:611.75,613.31 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:625.2,626.36 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:632.2,632.16 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:613.31,615.10 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:619.3,619.39 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:615.10,618.4 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:619.39,621.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:626.36,628.25 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:628.25,630.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:637.105,638.77 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:642.2,643.16 2 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:647.2,647.85 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:651.2,654.53 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:638.77,640.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:643.16,645.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:647.85,649.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:654.53,656.18 2 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:660.4,662.14 3 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:656.18,658.5 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:667.112,668.78 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:673.2,673.57 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:678.2,679.9 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:708.2,710.16 3 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:714.2,714.85 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:720.2,720.18 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:729.2,730.16 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:734.2,742.53 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:820.2,820.16 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:853.2,853.12 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:668.78,670.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:673.57,675.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:680.20,681.85 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:685.10,686.85 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:681.85,683.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:686.85,687.33 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:691.4,691.22 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:704.4,704.84 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:687.33,689.5 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:691.22,697.30 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:701.5,701.94 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:697.30,699.6 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:710.16,712.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:714.85,716.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:720.18,723.70 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:723.70,726.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:730.16,732.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:742.53,744.18 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:748.4,750.31 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:791.4,792.37 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:803.4,804.18 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:807.4,812.61 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:816.4,816.73 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:744.18,746.5 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:750.31,752.33 2 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:767.5,767.36 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:773.5,774.19 2 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:777.5,777.55 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:752.33,755.47 3 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:765.6,765.63 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:755.47,757.21 2 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:760.7,760.27 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:763.7,763.49 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:757.21,759.8 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:760.27,762.8 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:767.36,769.6 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:774.19,776.6 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:777.55,784.6 3 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:784.11,787.6 2 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:792.37,794.44 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:799.5,799.34 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:794.44,795.78 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:795.78,797.7 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:804.18,806.5 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:812.61,814.5 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:820.16,823.19 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:827.3,831.28 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:835.3,835.32 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:847.3,847.35 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:823.19,825.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:831.28,834.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:835.32,842.41 3 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:845.4,845.84 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:842.41,844.5 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:847.35,850.4 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:858.109,859.78 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:864.2,864.21 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:868.2,870.16 3 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:874.2,875.16 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:879.2,879.85 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:883.2,886.53 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:859.78,861.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:864.21,866.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:870.16,872.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:875.16,877.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:879.85,881.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:886.53,888.18 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:891.4,893.33 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:904.4,904.61 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:908.4,908.14 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:888.18,890.5 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:893.33,895.19 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:898.5,898.72 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:895.19,897.6 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:904.61,906.5 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:914.115,915.81 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:920.2,920.21 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:924.2,926.16 3 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:930.2,931.16 2 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:935.2,935.85 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:939.2,947.53 2 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:915.81,917.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:920.21,922.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:926.16,928.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:931.16,933.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:935.85,937.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:947.53,949.18 2 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:953.4,955.50 3 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:994.4,996.29 2 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1009.4,1009.61 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1013.4,1013.14 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:949.18,951.5 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:955.50,957.42 2 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:970.5,970.36 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:976.5,977.19 2 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:980.5,980.55 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:957.42,959.47 2 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:968.6,968.63 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:959.47,961.21 2 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:964.7,964.27 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:961.21,963.8 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:964.27,966.8 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:970.36,972.6 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:977.19,979.6 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:980.55,987.6 3 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:987.11,990.6 2 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:996.29,1000.19 3 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1003.5,1003.63 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1000.19,1002.6 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1009.61,1011.5 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1017.118,1018.81 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1022.2,1024.16 3 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1028.2,1028.85 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1032.2,1032.102 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1036.2,1039.53 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1018.81,1020.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1024.16,1026.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1028.85,1030.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1032.102,1034.3 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1039.53,1045.43 5 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1062.4,1062.14 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1068.4,1069.18 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1072.4,1074.61 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1077.4,1077.14 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1045.43,1048.19 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1051.5,1051.21 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1048.19,1050.6 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1051.21,1053.11 2 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1062.14,1066.5 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1069.18,1071.5 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1074.61,1076.5 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1081.98,1082.85 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1086.2,1088.16 3 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1092.2,1092.85 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1096.2,1096.102 1 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1100.2,1103.12 4 1 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1082.85,1084.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1088.16,1090.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1092.85,1094.3 1 0 +github.com/hashicorp/consul/agent/consul/catalog_endpoint.go:1096.102,1098.3 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:37.66,46.2 3 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:50.36,51.6 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:51.6,52.10 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:53.58,54.48 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:57.27,58.10 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:54.48,56.5 1 0 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:65.48,76.18 7 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:83.2,85.33 3 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:102.2,102.80 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:118.2,118.12 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:76.18,79.3 2 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:85.33,86.18 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:90.3,98.6 3 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:86.18,87.9 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:102.80,104.17 2 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:110.3,114.17 4 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:104.17,106.4 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:114.17,116.4 1 0 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:122.97,123.75 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:130.2,130.27 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:136.2,137.16 2 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:140.2,140.41 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:145.2,147.16 3 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:151.2,151.85 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:155.2,155.93 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:160.2,164.12 5 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:123.75,125.3 1 0 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:130.27,132.3 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:137.16,139.3 1 0 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:140.41,142.3 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:147.16,149.3 1 0 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:151.85,153.3 1 0 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:155.93,157.3 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:171.92,173.16 2 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:177.2,180.29 2 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:194.2,195.12 2 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:173.16,175.3 1 0 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:180.29,181.36 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:185.3,186.36 2 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:191.3,191.27 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:181.36,182.12 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:186.36,189.4 2 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:200.106,201.78 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:205.2,206.16 2 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:210.2,210.85 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:214.2,216.53 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:201.78,203.3 1 0 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:206.16,208.3 1 0 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:210.85,212.3 1 0 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:216.53,218.18 2 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:222.4,223.61 2 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:227.4,227.14 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:218.18,220.5 1 0 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:223.61,225.5 1 0 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:232.103,233.73 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:238.2,240.16 3 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:244.2,244.85 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:248.2,248.92 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:252.2,254.53 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:233.73,235.3 1 0 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:240.16,242.3 1 0 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:244.85,246.3 1 0 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:248.92,250.3 1 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:254.53,256.18 2 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:260.4,261.43 2 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:269.4,271.14 2 1 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:256.18,258.5 1 0 +github.com/hashicorp/consul/agent/consul/coordinate_endpoint.go:261.43,268.5 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:28.47,30.2 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:32.42,34.2 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:36.72,38.2 1 0 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:40.94,42.2 1 0 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:44.86,46.2 1 0 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:48.42,50.2 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:52.73,54.2 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:56.53,58.2 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:60.69,61.2 0 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:63.49,64.2 0 0 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:66.91,68.2 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:70.79,71.21 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:79.2,79.64 1 0 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:71.21,73.3 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:73.8,73.52 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:73.52,75.3 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:82.80,83.14 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:91.2,91.64 1 0 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:83.14,85.3 1 0 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:85.8,85.69 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:85.69,87.3 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:95.53,107.16 3 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:110.2,110.12 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:107.16,109.3 1 0 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:113.36,114.22 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:114.22,116.3 1 1 +github.com/hashicorp/consul/agent/consul/enterprise_server_oss.go:119.73,121.2 0 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:72.62,75.2 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:77.63,84.6 5 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:84.6,85.10 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:86.21,93.14 4 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:94.19,95.69 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:95.69,97.5 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:102.77,104.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:108.2,108.29 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:137.2,137.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:104.16,106.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:108.29,114.17 3 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:118.3,119.12 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:127.3,128.10 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:133.3,134.84 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:114.17,116.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:119.12,124.4 3 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:129.30,129.30 0 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:130.53,131.15 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:140.60,144.37 3 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:154.2,154.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:144.37,145.72 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:148.3,148.13 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:145.72,147.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:150.21,152.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:157.42,161.2 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:165.128,207.16 7 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:213.2,214.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:218.2,227.29 4 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:281.2,284.47 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:299.2,305.26 4 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:207.16,209.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:214.16,216.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:227.29,230.23 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:236.3,238.25 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:245.3,247.17 3 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:250.3,250.51 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:254.3,255.32 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:261.3,263.43 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:270.3,270.81 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:230.23,232.12 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:238.25,240.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:247.17,249.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:250.51,251.12 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:255.32,259.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:263.43,268.4 2 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:270.81,277.12 3 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:284.47,285.34 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:290.3,290.10 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:285.34,287.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:291.17,291.17 0 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:293.11,295.17 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:312.49,315.23 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:319.2,320.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:324.2,324.50 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:328.2,331.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:335.2,344.61 5 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:434.2,434.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:315.23,317.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:320.16,322.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:324.50,326.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:331.16,333.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:344.61,347.17 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:352.3,369.17 4 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:372.3,376.17 4 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:380.3,392.49 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:396.3,405.17 3 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:411.3,411.13 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:347.17,350.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:369.17,371.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:376.17,378.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:392.49,394.4 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:405.17,410.4 4 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:413.21,417.10 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:418.49,420.18 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:422.48,424.18 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:426.85,427.61 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:429.19,430.63 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:446.99,452.33 4 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:466.2,466.41 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:470.2,470.6 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:452.33,457.17 3 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:460.3,462.13 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:457.17,459.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:466.41,468.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:470.6,471.10 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:472.49,473.28 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:475.33,476.18 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:482.4,482.43 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:476.18,479.5 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:482.43,486.5 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:491.68,493.2 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:496.65,502.6 3 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:502.6,503.10 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:509.3,512.17 4 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:517.3,517.25 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:527.3,527.30 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:504.21,505.14 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:506.11,506.11 0 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:512.17,514.12 2 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:517.25,521.43 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:524.4,524.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:521.43,523.5 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:527.30,529.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:534.129,540.75 3 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:544.2,544.86 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:549.2,549.42 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:553.2,553.53 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:560.2,565.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:540.75,543.3 2 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:544.86,547.3 2 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:549.42,551.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:553.53,557.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:565.16,568.3 2 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:572.128,577.16 3 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:580.2,580.21 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:584.2,585.6 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:625.2,625.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:577.16,579.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:580.21,582.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:585.6,587.77 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:607.3,611.23 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:587.77,604.4 4 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:611.23,612.44 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:616.4,617.18 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:612.44,614.5 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:617.18,619.5 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:620.9,621.9 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:629.139,631.16 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:634.2,634.19 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:638.2,638.42 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:642.2,647.12 3 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:631.16,633.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:634.19,636.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:638.42,640.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:661.70,664.6 3 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:664.6,665.33 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:684.3,684.9 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:665.33,668.37 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:672.4,676.11 4 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:682.4,682.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:668.37,670.5 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:677.22,679.11 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:680.19,680.19 0 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:694.76,695.68 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:713.2,713.67 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:718.2,718.52 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:721.2,721.60 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:695.68,697.43 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:705.3,706.31 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:709.3,709.12 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:697.43,699.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:706.31,708.4 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:713.67,715.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:718.52,720.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:725.49,726.16 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:730.2,733.32 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:737.2,738.9 2 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:741.2,741.31 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:726.16,728.3 1 0 +github.com/hashicorp/consul/agent/consul/leader_peering.go:733.32,735.3 1 1 +github.com/hashicorp/consul/agent/consul/leader_peering.go:738.9,740.3 1 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:19.100,31.45 11 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:37.2,61.65 10 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:65.2,73.26 5 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:31.45,33.3 1 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:61.65,63.3 1 0 +github.com/hashicorp/consul/agent/consul/client_serf.go:77.36,79.6 2 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:79.6,81.48 2 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:88.3,88.10 1 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:81.48,86.4 1 0 +github.com/hashicorp/consul/agent/consul/client_serf.go:89.25,90.25 1 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:103.23,104.10 1 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:91.30,92.37 1 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:93.77,94.37 1 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:95.24,96.37 1 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:97.32,98.39 1 0 +github.com/hashicorp/consul/agent/consul/client_serf.go:99.25,99.25 0 0 +github.com/hashicorp/consul/agent/consul/client_serf.go:100.12,101.58 1 0 +github.com/hashicorp/consul/agent/consul/client_serf.go:110.48,111.31 1 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:111.31,113.10 2 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:116.3,116.46 1 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:123.3,127.31 3 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:113.10,114.12 1 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:116.46,121.12 2 0 +github.com/hashicorp/consul/agent/consul/client_serf.go:127.31,129.4 1 0 +github.com/hashicorp/consul/agent/consul/client_serf.go:134.50,135.31 1 0 +github.com/hashicorp/consul/agent/consul/client_serf.go:135.31,137.10 2 0 +github.com/hashicorp/consul/agent/consul/client_serf.go:140.3,140.46 1 0 +github.com/hashicorp/consul/agent/consul/client_serf.go:147.3,148.43 2 0 +github.com/hashicorp/consul/agent/consul/client_serf.go:137.10,138.12 1 0 +github.com/hashicorp/consul/agent/consul/client_serf.go:140.46,145.12 2 0 +github.com/hashicorp/consul/agent/consul/client_serf.go:153.48,154.31 1 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:154.31,156.10 2 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:159.3,160.46 2 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:156.10,157.12 1 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:165.51,167.47 1 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:171.2,171.29 1 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:167.47,169.3 1 0 +github.com/hashicorp/consul/agent/consul/client_serf.go:172.30,176.31 2 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:179.25,184.39 3 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:187.10,188.43 1 0 +github.com/hashicorp/consul/agent/consul/client_serf.go:176.31,178.4 1 0 +github.com/hashicorp/consul/agent/consul/client_serf.go:184.39,186.4 1 1 +github.com/hashicorp/consul/agent/consul/client_serf.go:188.43,190.4 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:15.56,17.2 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:27.59,27.88 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:30.57,30.87 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:33.57,33.86 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:36.107,37.49 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:40.2,41.29 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:44.2,44.44 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:37.49,39.3 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:41.29,43.3 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:47.107,58.75 3 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:62.2,64.68 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:58.75,60.3 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:68.76,70.16 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:74.2,74.31 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:70.16,72.3 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:78.160,80.9 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:83.2,84.9 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:87.2,94.84 7 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:118.2,118.45 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:122.2,122.48 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:126.2,131.8 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:80.9,82.3 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:84.9,86.3 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:94.84,95.65 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:95.65,97.55 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:101.4,102.18 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:97.55,99.5 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:103.9,103.71 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:103.71,109.4 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:109.9,115.4 2 0 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:118.45,120.3 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:122.48,124.3 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:134.61,135.41 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:135.41,137.3 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:141.124,143.9 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:147.2,150.34 3 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:172.2,172.19 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:143.9,145.3 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:150.34,158.17 3 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:162.3,162.27 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:158.17,160.4 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:162.27,163.11 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:164.22,165.21 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:166.20,166.20 0 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:176.120,178.9 2 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:182.2,185.32 3 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:213.2,213.19 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:178.9,180.3 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:185.32,199.17 6 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:203.3,203.25 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:199.17,201.4 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:203.25,204.11 1 1 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:205.22,206.21 1 0 +github.com/hashicorp/consul/agent/consul/federation_state_replication.go:207.20,207.20 0 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:36.128,38.48 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:43.2,43.12 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:81.2,81.22 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:93.2,93.18 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:38.48,40.3 1 0 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:44.24,48.100 3 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:52.50,52.50 0 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:55.44,62.93 3 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:66.10,70.94 3 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:48.100,50.4 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:62.93,64.4 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:70.94,72.4 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:81.22,84.32 3 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:84.32,90.4 2 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:97.66,98.67 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:101.2,105.16 3 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:109.2,109.91 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:113.2,114.16 2 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:117.2,117.9 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:123.2,124.16 2 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:129.2,129.37 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:132.2,132.12 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:98.67,100.3 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:105.16,107.3 1 0 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:109.91,111.3 1 0 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:114.16,116.3 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:117.9,120.3 2 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:124.16,126.3 1 0 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:129.37,131.3 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:136.85,137.65 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:141.2,143.16 3 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:147.2,147.85 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:151.2,154.53 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:137.65,139.3 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:143.16,145.3 1 0 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:147.85,149.3 1 0 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:154.53,156.18 2 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:159.4,159.92 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:163.4,163.18 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:169.4,171.14 3 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:156.18,158.5 1 0 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:159.92,161.5 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:163.18,167.5 3 0 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:176.86,177.66 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:181.2,183.16 3 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:187.2,187.85 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:191.2,191.41 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:197.2,200.53 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:177.66,179.3 1 0 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:183.16,185.3 1 0 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:187.85,189.3 1 0 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:191.41,192.91 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:192.91,194.4 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:200.53,202.18 2 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:206.4,210.21 4 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:223.4,223.14 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:202.18,204.5 1 0 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:210.21,213.19 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:218.5,218.24 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:213.19,215.6 1 0 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:215.11,217.6 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:219.10,222.5 2 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:231.91,232.70 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:236.2,238.16 3 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:242.2,242.85 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:246.2,246.41 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:252.2,255.53 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:232.70,234.3 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:238.16,240.3 1 0 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:242.85,244.3 1 0 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:246.41,247.94 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:247.94,249.4 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:255.53,257.18 2 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:263.4,263.18 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:269.4,280.30 8 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:301.4,302.14 2 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:257.18,259.5 1 0 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:263.18,265.5 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:265.10,267.5 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:280.30,282.20 1 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:289.5,291.20 3 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:282.20,284.14 2 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:291.20,293.30 2 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:293.30,296.7 2 1 +github.com/hashicorp/consul/agent/consul/kvs_endpoint.go:297.11,299.6 1 1 +github.com/hashicorp/consul/agent/consul/server.go:397.93,399.54 2 1 +github.com/hashicorp/consul/agent/consul/server.go:402.2,402.45 1 1 +github.com/hashicorp/consul/agent/consul/server.go:405.2,405.42 1 1 +github.com/hashicorp/consul/agent/consul/server.go:410.2,411.16 2 1 +github.com/hashicorp/consul/agent/consul/server.go:416.2,423.38 4 1 +github.com/hashicorp/consul/agent/consul/server.go:430.2,462.40 4 1 +github.com/hashicorp/consul/agent/consul/server.go:467.2,467.21 1 1 +github.com/hashicorp/consul/agent/consul/server.go:471.2,471.42 1 1 +github.com/hashicorp/consul/agent/consul/server.go:479.2,483.53 3 1 +github.com/hashicorp/consul/agent/consul/server.go:495.2,495.47 1 1 +github.com/hashicorp/consul/agent/consul/server.go:500.2,512.16 5 1 +github.com/hashicorp/consul/agent/consul/server.go:517.2,532.16 3 1 +github.com/hashicorp/consul/agent/consul/server.go:538.2,551.65 5 1 +github.com/hashicorp/consul/agent/consul/server.go:557.2,557.37 1 1 +github.com/hashicorp/consul/agent/consul/server.go:563.2,564.16 2 1 +github.com/hashicorp/consul/agent/consul/server.go:570.2,570.38 1 1 +github.com/hashicorp/consul/agent/consul/server.go:575.2,576.98 2 1 +github.com/hashicorp/consul/agent/consul/server.go:580.2,580.29 1 1 +github.com/hashicorp/consul/agent/consul/server.go:594.2,594.33 1 1 +github.com/hashicorp/consul/agent/consul/server.go:624.2,624.66 1 1 +github.com/hashicorp/consul/agent/consul/server.go:630.2,630.47 1 1 +github.com/hashicorp/consul/agent/consul/server.go:635.2,635.79 1 1 +github.com/hashicorp/consul/agent/consul/server.go:639.2,645.22 3 1 +github.com/hashicorp/consul/agent/consul/server.go:667.2,667.44 1 1 +github.com/hashicorp/consul/agent/consul/server.go:672.2,678.44 1 1 +github.com/hashicorp/consul/agent/consul/server.go:687.2,687.16 1 1 +github.com/hashicorp/consul/agent/consul/server.go:691.2,699.89 4 1 +github.com/hashicorp/consul/agent/consul/server.go:713.2,717.44 2 1 +github.com/hashicorp/consul/agent/consul/server.go:726.2,729.44 2 1 +github.com/hashicorp/consul/agent/consul/server.go:735.2,744.48 3 1 +github.com/hashicorp/consul/agent/consul/server.go:757.2,769.44 5 1 +github.com/hashicorp/consul/agent/consul/server.go:772.2,783.12 4 1 +github.com/hashicorp/consul/agent/consul/server.go:788.2,791.44 2 1 +github.com/hashicorp/consul/agent/consul/server.go:797.2,805.15 4 1 +github.com/hashicorp/consul/agent/consul/server.go:399.54,401.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:402.45,404.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:405.42,407.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:411.16,413.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:423.38,425.4 1 1 +github.com/hashicorp/consul/agent/consul/server.go:462.40,464.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:464.8,466.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:467.21,469.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:471.42,474.3 2 1 +github.com/hashicorp/consul/agent/consul/server.go:474.8,477.3 2 1 +github.com/hashicorp/consul/agent/consul/server.go:483.53,492.3 3 1 +github.com/hashicorp/consul/agent/consul/server.go:495.47,498.3 2 0 +github.com/hashicorp/consul/agent/consul/server.go:512.16,515.3 2 0 +github.com/hashicorp/consul/agent/consul/server.go:532.16,535.3 2 0 +github.com/hashicorp/consul/agent/consul/server.go:551.65,554.3 2 0 +github.com/hashicorp/consul/agent/consul/server.go:557.37,560.3 2 0 +github.com/hashicorp/consul/agent/consul/server.go:564.16,567.3 2 0 +github.com/hashicorp/consul/agent/consul/server.go:570.38,573.3 2 0 +github.com/hashicorp/consul/agent/consul/server.go:576.98,578.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:580.29,582.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:594.33,602.17 2 1 +github.com/hashicorp/consul/agent/consul/server.go:609.3,613.27 3 1 +github.com/hashicorp/consul/agent/consul/server.go:602.17,605.4 2 0 +github.com/hashicorp/consul/agent/consul/server.go:613.27,615.28 2 0 +github.com/hashicorp/consul/agent/consul/server.go:618.4,618.64 1 0 +github.com/hashicorp/consul/agent/consul/server.go:615.28,617.5 1 0 +github.com/hashicorp/consul/agent/consul/server.go:624.66,627.3 2 0 +github.com/hashicorp/consul/agent/consul/server.go:630.47,633.3 2 0 +github.com/hashicorp/consul/agent/consul/server.go:635.79,638.3 2 0 +github.com/hashicorp/consul/agent/consul/server.go:645.22,646.80 1 1 +github.com/hashicorp/consul/agent/consul/server.go:650.3,653.54 2 1 +github.com/hashicorp/consul/agent/consul/server.go:663.3,663.32 1 1 +github.com/hashicorp/consul/agent/consul/server.go:646.80,649.4 2 0 +github.com/hashicorp/consul/agent/consul/server.go:653.54,654.26 1 1 +github.com/hashicorp/consul/agent/consul/server.go:657.4,658.18 2 1 +github.com/hashicorp/consul/agent/consul/server.go:661.4,661.57 1 1 +github.com/hashicorp/consul/agent/consul/server.go:654.26,656.5 1 0 +github.com/hashicorp/consul/agent/consul/server.go:658.18,660.5 1 0 +github.com/hashicorp/consul/agent/consul/server.go:667.44,670.3 2 0 +github.com/hashicorp/consul/agent/consul/server.go:678.44,680.19 2 1 +github.com/hashicorp/consul/agent/consul/server.go:684.5,684.19 1 1 +github.com/hashicorp/consul/agent/consul/server.go:680.19,682.6 1 0 +github.com/hashicorp/consul/agent/consul/server.go:687.16,690.3 2 0 +github.com/hashicorp/consul/agent/consul/server.go:699.89,701.4 1 1 +github.com/hashicorp/consul/agent/consul/server.go:703.123,705.4 1 1 +github.com/hashicorp/consul/agent/consul/server.go:708.51,708.74 1 1 +github.com/hashicorp/consul/agent/consul/server.go:709.57,709.86 1 1 +github.com/hashicorp/consul/agent/consul/server.go:717.44,717.70 1 0 +github.com/hashicorp/consul/agent/consul/server.go:721.89,723.4 1 1 +github.com/hashicorp/consul/agent/consul/server.go:729.44,729.70 1 0 +github.com/hashicorp/consul/agent/consul/server.go:744.48,744.74 1 1 +github.com/hashicorp/consul/agent/consul/server.go:749.89,751.87 1 1 +github.com/hashicorp/consul/agent/consul/server.go:754.4,754.50 1 1 +github.com/hashicorp/consul/agent/consul/server.go:751.87,753.5 1 0 +github.com/hashicorp/consul/agent/consul/server.go:769.44,769.68 1 1 +github.com/hashicorp/consul/agent/consul/server.go:783.12,784.45 1 1 +github.com/hashicorp/consul/agent/consul/server.go:784.45,786.4 1 0 +github.com/hashicorp/consul/agent/consul/server.go:791.44,793.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:808.81,809.29 1 1 +github.com/hashicorp/consul/agent/consul/server.go:813.2,817.89 1 1 +github.com/hashicorp/consul/agent/consul/server.go:828.2,830.37 2 1 +github.com/hashicorp/consul/agent/consul/server.go:846.2,846.73 1 1 +github.com/hashicorp/consul/agent/consul/server.go:809.29,810.58 1 0 +github.com/hashicorp/consul/agent/consul/server.go:817.89,819.87 1 1 +github.com/hashicorp/consul/agent/consul/server.go:822.4,822.50 1 1 +github.com/hashicorp/consul/agent/consul/server.go:819.87,821.5 1 0 +github.com/hashicorp/consul/agent/consul/server.go:830.37,831.39 1 1 +github.com/hashicorp/consul/agent/consul/server.go:836.3,843.42 5 1 +github.com/hashicorp/consul/agent/consul/server.go:831.39,835.4 1 1 +github.com/hashicorp/consul/agent/consul/server.go:849.61,850.6 1 1 +github.com/hashicorp/consul/agent/consul/server.go:850.6,855.17 5 1 +github.com/hashicorp/consul/agent/consul/server.go:859.3,860.26 2 1 +github.com/hashicorp/consul/agent/consul/server.go:863.3,863.67 1 1 +github.com/hashicorp/consul/agent/consul/server.go:867.3,867.55 1 1 +github.com/hashicorp/consul/agent/consul/server.go:855.17,858.4 2 0 +github.com/hashicorp/consul/agent/consul/server.go:860.26,862.4 1 1 +github.com/hashicorp/consul/agent/consul/server.go:863.67,865.4 1 0 +github.com/hashicorp/consul/agent/consul/server.go:867.55,870.4 2 1 +github.com/hashicorp/consul/agent/consul/server.go:875.36,877.15 1 1 +github.com/hashicorp/consul/agent/consul/server.go:885.2,886.46 2 1 +github.com/hashicorp/consul/agent/consul/server.go:891.2,906.46 6 1 +github.com/hashicorp/consul/agent/consul/server.go:912.2,915.22 4 1 +github.com/hashicorp/consul/agent/consul/server.go:1013.2,1013.71 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1035.2,1042.12 6 1 +github.com/hashicorp/consul/agent/consul/server.go:877.15,878.42 1 1 +github.com/hashicorp/consul/agent/consul/server.go:878.42,879.46 1 0 +github.com/hashicorp/consul/agent/consul/server.go:879.46,881.5 1 0 +github.com/hashicorp/consul/agent/consul/server.go:886.46,888.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:906.46,908.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:915.22,921.3 5 1 +github.com/hashicorp/consul/agent/consul/server.go:921.8,924.52 2 1 +github.com/hashicorp/consul/agent/consul/server.go:929.3,935.17 2 1 +github.com/hashicorp/consul/agent/consul/server.go:938.3,946.17 5 1 +github.com/hashicorp/consul/agent/consul/server.go:949.3,953.17 3 1 +github.com/hashicorp/consul/agent/consul/server.go:956.3,967.59 4 1 +github.com/hashicorp/consul/agent/consul/server.go:924.52,926.4 1 0 +github.com/hashicorp/consul/agent/consul/server.go:935.17,937.4 1 0 +github.com/hashicorp/consul/agent/consul/server.go:946.17,948.4 1 0 +github.com/hashicorp/consul/agent/consul/server.go:953.17,955.4 1 0 +github.com/hashicorp/consul/agent/consul/server.go:967.59,968.86 1 1 +github.com/hashicorp/consul/agent/consul/server.go:974.4,974.48 1 1 +github.com/hashicorp/consul/agent/consul/server.go:968.86,970.5 1 0 +github.com/hashicorp/consul/agent/consul/server.go:974.48,975.48 1 0 +github.com/hashicorp/consul/agent/consul/server.go:978.5,978.74 1 0 +github.com/hashicorp/consul/agent/consul/server.go:975.48,977.6 1 0 +github.com/hashicorp/consul/agent/consul/server.go:980.9,980.54 1 1 +github.com/hashicorp/consul/agent/consul/server.go:980.54,984.47 3 0 +github.com/hashicorp/consul/agent/consul/server.go:989.4,989.18 1 0 +github.com/hashicorp/consul/agent/consul/server.go:993.4,995.40 1 0 +github.com/hashicorp/consul/agent/consul/server.go:999.4,1000.58 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1004.4,1004.47 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1007.4,1007.70 1 0 +github.com/hashicorp/consul/agent/consul/server.go:984.47,986.5 1 0 +github.com/hashicorp/consul/agent/consul/server.go:986.10,988.5 1 0 +github.com/hashicorp/consul/agent/consul/server.go:989.18,991.5 1 0 +github.com/hashicorp/consul/agent/consul/server.go:995.40,997.6 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1000.58,1002.5 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1004.47,1006.5 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1013.71,1015.17 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1018.3,1018.16 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1015.17,1017.4 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1018.16,1028.58 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1028.58,1030.5 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1053.35,1055.2 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1058.35,1063.31 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1070.2,1074.37 3 1 +github.com/hashicorp/consul/agent/consul/server.go:1091.2,1094.16 3 1 +github.com/hashicorp/consul/agent/consul/server.go:1097.2,1099.34 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1103.2,1103.34 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1108.2,1108.46 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1117.2,1120.51 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1124.2,1125.12 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1063.31,1065.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1074.37,1077.17 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1081.3,1085.4 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1077.17,1079.4 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1086.8,1089.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1094.16,1096.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1099.34,1101.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1103.34,1105.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1108.46,1111.3 2 0 +github.com/hashicorp/consul/agent/consul/server.go:1120.51,1123.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1129.35,1134.16 4 1 +github.com/hashicorp/consul/agent/consul/server.go:1138.2,1142.35 3 1 +github.com/hashicorp/consul/agent/consul/server.go:1146.2,1148.22 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1154.2,1158.19 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1170.2,1170.23 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1174.2,1174.26 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1181.2,1181.23 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1185.2,1185.26 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1189.2,1189.18 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1193.2,1193.12 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1134.16,1136.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1142.35,1144.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1148.22,1150.60 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1150.60,1152.4 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1158.19,1162.40 4 1 +github.com/hashicorp/consul/agent/consul/server.go:1165.3,1165.25 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1162.40,1164.4 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1165.25,1167.4 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1170.23,1172.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1174.26,1175.50 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1175.50,1177.4 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1181.23,1183.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1185.26,1187.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1189.18,1191.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1196.61,1200.9 3 1 +github.com/hashicorp/consul/agent/consul/server.go:1204.2,1205.39 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1209.2,1209.13 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1200.9,1202.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1205.39,1208.3 2 0 +github.com/hashicorp/consul/agent/consul/server.go:1213.32,1218.16 3 1 +github.com/hashicorp/consul/agent/consul/server.go:1223.2,1230.30 3 1 +github.com/hashicorp/consul/agent/consul/server.go:1242.2,1242.22 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1249.2,1249.22 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1256.2,1269.15 5 1 +github.com/hashicorp/consul/agent/consul/server.go:1313.2,1313.12 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1218.16,1221.3 2 0 +github.com/hashicorp/consul/agent/consul/server.go:1230.30,1231.36 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1231.36,1233.4 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1233.9,1235.41 2 0 +github.com/hashicorp/consul/agent/consul/server.go:1235.41,1237.5 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1242.22,1243.43 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1243.43,1245.4 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1249.22,1250.43 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1250.43,1252.4 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1269.15,1272.41 3 1 +github.com/hashicorp/consul/agent/consul/server.go:1308.3,1308.12 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1272.41,1278.41 3 1 +github.com/hashicorp/consul/agent/consul/server.go:1284.4,1285.58 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1278.41,1280.10 2 0 +github.com/hashicorp/consul/agent/consul/server.go:1285.58,1286.31 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1286.31,1288.11 2 0 +github.com/hashicorp/consul/agent/consul/server.go:1308.12,1310.4 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1319.55,1320.22 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1324.2,1324.54 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1328.2,1328.36 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1320.22,1322.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1324.54,1326.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1334.71,1335.29 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1338.2,1338.62 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1335.29,1337.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1342.76,1343.29 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1346.2,1346.41 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1343.29,1345.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1351.73,1352.29 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1352.29,1354.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1359.61,1360.29 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1363.2,1363.59 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1360.29,1362.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1367.49,1369.2 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1374.61,1376.2 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1379.45,1380.22 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1383.2,1383.28 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1380.22,1382.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1387.54,1389.2 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1392.95,1394.11 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1400.2,1404.55 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1408.2,1408.61 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1394.11,1396.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1396.8,1398.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1404.55,1406.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1412.101,1414.11 2 0 +github.com/hashicorp/consul/agent/consul/server.go:1420.2,1420.59 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1414.11,1416.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1416.8,1418.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1424.34,1426.2 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1430.48,1432.2 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1435.51,1438.2 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1441.51,1443.2 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1445.60,1447.2 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1457.64,1460.2 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1462.62,1467.2 4 1 +github.com/hashicorp/consul/agent/consul/server.go:1469.81,1470.22 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1474.2,1477.12 4 1 +github.com/hashicorp/consul/agent/consul/server.go:1470.22,1473.3 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1480.36,1482.2 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1485.80,1500.50 3 1 +github.com/hashicorp/consul/agent/consul/server.go:1504.2,1504.56 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1507.2,1507.18 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1500.50,1503.3 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1504.56,1506.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1513.41,1523.50 2 0 +github.com/hashicorp/consul/agent/consul/server.go:1529.2,1531.16 3 0 +github.com/hashicorp/consul/agent/consul/server.go:1534.2,1534.15 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1541.2,1541.20 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1548.2,1548.16 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1553.2,1553.12 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1523.50,1526.3 2 0 +github.com/hashicorp/consul/agent/consul/server.go:1531.16,1533.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1534.15,1535.38 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1535.38,1537.4 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1541.20,1542.41 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1542.41,1544.4 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1548.16,1549.47 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1549.47,1551.4 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1557.75,1560.2 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1562.33,1564.2 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1568.55,1569.36 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1572.2,1586.26 3 0 +github.com/hashicorp/consul/agent/consul/server.go:1592.2,1592.22 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1596.2,1598.14 2 0 +github.com/hashicorp/consul/agent/consul/server.go:1569.36,1571.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1586.26,1588.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1588.8,1590.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1592.22,1594.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1615.64,1617.16 2 0 +github.com/hashicorp/consul/agent/consul/server.go:1621.2,1622.58 2 0 +github.com/hashicorp/consul/agent/consul/server.go:1626.2,1626.16 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1617.16,1619.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1622.58,1624.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1629.44,1631.2 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1635.62,1639.53 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1643.2,1649.18 4 1 +github.com/hashicorp/consul/agent/consul/server.go:1655.2,1655.12 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1639.53,1641.3 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1649.18,1653.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1663.81,1675.39 3 1 +github.com/hashicorp/consul/agent/consul/server.go:1678.2,1678.38 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1681.2,1681.34 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1684.2,1684.51 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1687.2,1687.50 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1690.2,1690.16 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1675.39,1677.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1678.38,1680.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1681.34,1683.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1684.51,1686.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1687.50,1689.3 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1694.43,1696.2 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1699.45,1701.2 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1704.51,1706.2 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1710.39,1712.76 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1716.2,1718.6 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1712.76,1715.3 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1718.6,1719.10 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1720.23,1722.11 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1727.4,1731.29 3 1 +github.com/hashicorp/consul/agent/consul/server.go:1732.23,1734.10 2 1 +github.com/hashicorp/consul/agent/consul/server.go:1722.11,1724.13 2 0 +github.com/hashicorp/consul/agent/consul/server.go:1741.64,1742.72 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1742.72,1751.21 8 1 +github.com/hashicorp/consul/agent/consul/server.go:1770.3,1774.28 5 1 +github.com/hashicorp/consul/agent/consul/server.go:1778.3,1786.31 8 1 +github.com/hashicorp/consul/agent/consul/server.go:1790.3,1790.21 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1751.21,1754.19 3 0 +github.com/hashicorp/consul/agent/consul/server.go:1762.4,1767.78 6 0 +github.com/hashicorp/consul/agent/consul/server.go:1754.19,1757.19 2 0 +github.com/hashicorp/consul/agent/consul/server.go:1757.19,1760.6 1 0 +github.com/hashicorp/consul/agent/consul/server.go:1774.28,1776.4 1 1 +github.com/hashicorp/consul/agent/consul/server.go:1786.31,1788.4 1 0 +github.com/hashicorp/consul/agent/consul/server_overview.go:27.118,34.2 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:36.71,40.2 3 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:42.52,46.6 3 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:46.6,47.10 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:48.21,49.10 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:50.19,53.18 3 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:58.4,61.14 4 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:53.18,55.13 2 0 +github.com/hashicorp/consul/agent/consul/server_overview.go:69.83,74.72 4 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:81.2,81.39 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:106.2,107.39 2 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:136.2,137.37 2 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:162.2,163.46 2 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:166.2,166.49 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:169.2,169.47 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:173.2,173.73 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:184.2,188.16 4 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:74.72,76.3 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:81.39,84.10 3 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:91.3,94.28 3 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:84.10,89.4 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:94.28,97.4 2 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:97.9,100.4 2 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:107.39,110.10 3 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:118.3,120.67 3 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:129.3,130.43 2 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:110.10,115.4 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:120.67,121.73 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:124.4,124.43 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:121.73,123.5 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:124.43,126.5 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:137.37,139.10 2 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:146.3,148.45 3 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:157.3,158.42 2 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:139.10,143.4 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:148.45,149.73 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:152.4,152.43 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:149.73,151.5 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:152.43,154.5 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:163.46,165.3 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:166.49,168.3 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:169.47,171.3 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:173.73,174.30 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:174.30,175.65 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:178.4,178.65 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:181.4,181.40 1 1 +github.com/hashicorp/consul/agent/consul/server_overview.go:175.65,177.5 1 0 +github.com/hashicorp/consul/agent/consul/server_overview.go:178.65,180.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/health_snapshot.go:28.100,31.31 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/health_snapshot.go:44.2,48.31 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/health_snapshot.go:83.2,83.13 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/health_snapshot.go:31.31,38.39 5 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/health_snapshot.go:38.39,41.4 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/health_snapshot.go:48.31,49.31 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/health_snapshot.go:52.3,53.10 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/health_snapshot.go:61.3,61.32 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/health_snapshot.go:64.3,67.10 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/health_snapshot.go:75.3,75.37 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/health_snapshot.go:49.31,50.63 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/health_snapshot.go:53.10,59.4 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/health_snapshot.go:61.32,62.64 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/health_snapshot.go:67.10,73.4 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/health_snapshot.go:75.37,76.23 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/health_snapshot.go:79.4,79.33 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/health_snapshot.go:76.23,77.63 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/mock_ACLResolver.go:20.145,24.106 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/mock_ACLResolver.go:30.2,31.96 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/mock_ACLResolver.go:37.2,37.15 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/mock_ACLResolver.go:24.106,26.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/mock_ACLResolver.go:26.8,28.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/mock_ACLResolver.go:31.96,33.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/mock_ACLResolver.go:33.8,35.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/mock_ACLResolver.go:41.56,45.19 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/mock_ACLResolver.go:47.2,47.13 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/mock_ACLResolver.go:45.19,45.49 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:64.24,80.2 4 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:83.123,96.29 7 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:104.2,106.23 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:96.29,100.3 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:109.126,110.6 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:110.6,113.10 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:114.21,115.10 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:116.29,117.60 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:117.60,121.13 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:127.117,128.18 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:132.2,132.9 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:291.2,291.12 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:128.18,130.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:133.49,137.10 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:141.3,145.30 4 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:149.3,154.17 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:158.3,161.39 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:163.62,165.10 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:172.3,179.38 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:190.3,190.38 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:196.3,200.63 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:203.3,203.50 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:205.58,207.10 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:211.3,213.31 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:217.3,217.55 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:222.3,225.38 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:236.3,236.38 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:251.3,255.30 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:263.3,263.50 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:265.36,267.10 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:270.3,271.79 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:275.3,275.50 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:277.41,279.10 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:282.3,283.83 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:287.3,287.50 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:288.10,289.67 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:137.10,139.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:145.30,147.4 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:154.17,156.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:165.10,167.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:179.38,187.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:190.38,194.4 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:200.63,202.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:207.10,209.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:213.31,215.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:217.55,219.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:225.38,233.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:236.38,242.72 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:242.72,248.5 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:255.30,257.55 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:257.55,259.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:267.10,269.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:271.79,273.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:279.10,281.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:283.83,285.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:294.72,296.28 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:321.2,321.23 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:296.28,299.61 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:303.3,303.71 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:310.3,310.61 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:319.3,319.35 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:299.61,300.12 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:303.71,306.12 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:310.61,317.4 4 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:328.3,330.9 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:336.2,338.6 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:331.32,331.32 0 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:332.20,333.9 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:338.6,343.47 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:351.3,351.10 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:343.47,345.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:345.9,345.92 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:345.92,347.4 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:347.9,349.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:352.21,353.10 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:354.11,354.11 0 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:368.19,376.16 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:379.2,381.6 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:376.16,378.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:381.6,383.10 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:407.3,407.25 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:411.3,416.29 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:420.3,421.10 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:425.3,426.40 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:430.3,438.4 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:384.49,388.11 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:393.4,393.19 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:394.41,395.17 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:396.49,397.17 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:398.19,399.64 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:389.36,390.12 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:391.12,391.12 0 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:407.25,408.12 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:416.29,417.12 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:421.10,423.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:426.40,428.4 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:446.3,451.31 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:470.2,470.49 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:451.31,454.46 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:459.3,460.81 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:466.3,466.38 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:454.46,456.12 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:460.81,463.12 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:470.49,471.30 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:471.30,474.4 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:482.3,484.44 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:495.2,495.47 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:484.44,485.81 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:489.3,491.74 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:485.81,486.12 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:495.47,496.43 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:500.3,502.31 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:496.43,497.12 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:502.31,510.18 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:510.18,512.13 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:523.3,524.52 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:528.2,528.57 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:533.2,547.16 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:524.52,526.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:528.57,530.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:547.16,549.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:558.39,562.2 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:617.2,618.26 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:661.2,664.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:562.2,600.49 6 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:600.49,601.43 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:601.43,610.51 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:610.51,612.6 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:618.26,627.25 7 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:634.3,658.35 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:627.25,632.4 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:673.28,674.22 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:678.2,679.29 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:685.2,685.21 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:689.2,700.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:674.22,676.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:679.29,680.38 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:680.38,682.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:685.21,687.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:715.9,718.2 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:728.85,730.2 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:737.3,739.9 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:745.2,750.19 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:752.2,753.6 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:740.31,740.31 0 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:741.20,742.9 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:750.20,750.21 0 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:753.6,754.10 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:755.21,757.10 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:759.34,761.34 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:764.4,764.85 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:771.4,775.19 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:761.34,763.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:764.85,766.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:766.10,768.5 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:775.19,777.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:777.10,779.5 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:784.101,788.132 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:797.2,797.17 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:788.132,790.17 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:794.3,794.23 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:790.17,793.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:800.120,801.131 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:801.131,803.17 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:807.3,808.29 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:812.3,812.29 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:817.3,819.9 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:803.17,805.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:808.29,811.4 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:812.29,814.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:823.116,834.6 4 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:834.6,838.17 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:850.3,850.42 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:838.17,840.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:840.9,840.54 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:840.54,843.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:843.9,843.92 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:843.92,846.4 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:846.9,846.24 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:846.24,849.4 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:850.42,852.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:860.19,868.16 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:871.2,873.6 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:868.16,870.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:873.6,875.10 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:885.3,885.29 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:894.3,894.25 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:898.3,901.10 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:905.3,907.31 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:920.3,920.28 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:925.3,932.10 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:876.41,877.17 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:878.19,879.19 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:885.29,886.12 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:894.25,895.12 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:901.10,903.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:907.31,908.28 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:911.4,914.77 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:917.4,918.47 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:908.28,909.13 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:914.77,916.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:920.28,922.12 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:933.21,934.23 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_manager.go:935.22,935.22 0 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:46.74,54.2 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:60.3,61.44 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:61.44,66.37 4 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:71.3,79.10 4 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:66.37,68.12 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:80.32,80.32 0 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:81.21,81.21 0 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:86.71,87.34 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:87.34,89.10 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:119.3,119.12 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:90.35,91.15 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:93.31,94.15 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:96.35,97.15 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:99.36,100.15 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:102.54,106.42 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:110.61,114.42 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:106.42,108.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:114.42,116.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:119.12,122.4 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:146.86,148.9 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:152.2,153.16 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:157.2,164.12 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:148.9,150.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:153.16,155.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:167.54,173.16 5 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:176.2,179.44 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_state.go:173.16,175.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:29.126,40.2 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:43.64,45.2 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:47.63,48.19 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:52.2,52.40 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:48.19,50.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:56.85,61.60 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:76.2,85.51 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:61.60,75.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:92.128,94.2 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:97.48,99.2 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:113.54,117.2 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:120.40,122.2 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:125.74,126.31 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:142.2,142.12 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:126.31,128.27 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:133.3,134.27 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:128.27,131.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:135.39,136.48 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:138.41,139.23 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:147.65,152.31 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:155.2,157.16 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:152.31,154.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:161.67,162.48 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_view.go:162.48,164.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:24.69,27.2 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:29.71,31.2 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:33.99,34.9 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:35.24,36.18 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:37.41,38.16 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:39.25,40.21 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:44.30,46.2 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:48.53,52.2 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:56.48,58.20 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:58.20,62.99 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:66.3,66.98 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:62.99,64.4 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:66.98,68.4 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:82.64,88.2 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:91.69,94.2 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:97.71,99.14 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:102.2,102.15 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:99.14,101.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:106.48,108.2 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:111.51,113.2 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:116.51,118.2 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:121.51,123.2 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:126.52,128.2 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:131.47,131.48 0 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:143.43,151.2 5 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:156.54,157.11 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:160.2,165.24 4 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/testing.go:157.11,158.59 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:36.54,38.9 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:42.2,43.16 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:47.2,48.55 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:53.2,60.8 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:38.9,40.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:43.16,45.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:48.55,51.3 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:66.103,69.9 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:73.2,78.16 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:82.2,87.8 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:69.9,71.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:78.16,80.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:92.54,94.16 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:98.2,103.8 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:94.16,96.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:108.54,110.16 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:114.2,119.8 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:110.16,112.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:126.75,128.9 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:132.2,133.16 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:136.2,136.22 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:128.9,131.3 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:133.16,135.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:144.45,145.50 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:154.2,154.22 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:164.2,164.24 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:145.50,153.3 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:154.22,162.3 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:165.47,166.27 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:176.3,176.126 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:185.3,185.57 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:187.10,189.73 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:194.3,199.24 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:166.27,174.4 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:176.126,183.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:189.73,191.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:191.9,193.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:210.9,211.37 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:215.2,215.21 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:211.37,213.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:216.47,218.54 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:222.3,223.17 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:227.3,227.13 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:228.43,233.54 4 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:237.3,238.17 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:242.3,242.13 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:244.46,246.53 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:250.3,250.57 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:252.50,254.53 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:258.3,258.63 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:259.10,260.63 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:218.54,220.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:223.17,225.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:233.54,235.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:238.17,240.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:246.53,248.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:254.53,256.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:269.9,272.42 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:284.2,287.16 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:290.2,290.33 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:300.2,302.12 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:272.42,283.3 7 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:287.16,289.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:290.33,291.41 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:291.41,294.18 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:294.18,296.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:319.9,322.16 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:326.2,327.19 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:335.2,338.38 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:404.2,421.38 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:499.2,499.37 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:514.2,514.32 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:536.2,536.12 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:322.16,324.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:327.19,329.17 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:329.17,331.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:338.38,341.61 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:347.3,348.14 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:355.3,355.45 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:370.3,374.45 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:389.3,389.20 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:341.61,342.40 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:342.40,344.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:348.14,349.58 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:349.58,351.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:355.45,357.106 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:363.4,363.15 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:357.106,358.46 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:358.46,360.6 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:363.15,365.59 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:365.59,367.6 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:374.45,375.37 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:375.37,377.105 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:383.5,383.16 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:377.105,378.23 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:378.23,380.7 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:383.16,385.6 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:389.20,391.58 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:391.58,393.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:421.38,422.46 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:447.3,448.60 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:466.3,466.34 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:422.46,435.18 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:443.4,443.12 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:435.18,437.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:448.60,455.18 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:462.4,462.12 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:455.18,459.5 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:466.34,467.81 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:467.81,470.28 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:483.5,489.19 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:470.28,477.14 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:489.19,493.6 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:499.37,507.17 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:507.17,510.4 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:514.32,517.17 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:520.3,520.41 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:526.3,531.17 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:517.17,519.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:520.41,522.12 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:531.17,534.4 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:543.9,552.2 4 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:558.9,564.16 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:567.2,567.45 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:572.2,578.36 4 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:564.16,566.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:567.45,569.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:581.79,586.2 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:588.114,590.45 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:597.2,601.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:590.45,595.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:605.108,611.2 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:614.111,620.2 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:635.83,640.2 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:642.102,648.2 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:650.187,655.38 4 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:662.2,662.40 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:655.38,658.34 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/replication.go:658.34,660.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/server.go:55.36,60.26 4 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/server.go:63.2,63.40 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/server.go:66.2,66.39 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/server.go:69.2,72.3 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/server.go:60.26,61.34 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/server.go:63.40,65.3 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/server.go:66.39,68.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/server.go:75.48,76.14 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/server.go:76.14,77.31 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/server.go:83.52,85.2 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:40.141,55.75 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:60.2,60.27 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:64.2,68.16 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:71.2,71.140 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:75.2,76.16 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:80.2,95.16 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:99.2,99.68 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:55.75,59.3 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:60.27,62.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:68.16,70.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:71.140,73.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:76.16,78.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:95.16,97.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:102.60,104.16 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:107.2,107.16 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:104.16,106.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:111.101,120.27 4 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:136.2,137.16 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:145.2,146.16 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:149.2,152.22 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:156.2,158.16 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:162.2,162.14 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:166.2,167.9 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:171.2,171.19 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:188.2,189.16 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:193.2,193.20 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:199.2,200.69 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:208.2,208.87 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:235.2,235.17 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:239.2,241.20 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:245.2,254.16 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:259.2,260.12 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:120.27,127.17 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:127.17,130.4 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:130.9,132.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:137.16,140.3 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:146.16,148.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:152.22,154.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:158.16,161.3 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:162.14,164.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:167.9,169.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:171.19,174.51 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:185.3,185.86 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:174.51,184.4 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:189.16,192.3 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:193.20,196.3 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:200.69,201.82 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:201.82,203.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:208.87,211.83 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:214.3,231.17 5 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:211.83,213.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:231.17,233.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:235.17,237.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:241.20,243.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:254.16,257.3 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:280.48,282.2 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:287.55,288.6 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:288.6,290.46 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:290.46,291.21 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:295.4,295.9 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:291.21,294.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:302.68,303.54 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:308.2,309.12 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:303.54,306.3 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:314.72,327.16 6 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:331.2,332.22 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:341.2,359.65 5 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:383.2,389.29 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:394.2,394.40 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:406.2,412.12 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:429.2,429.12 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:452.2,457.15 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:462.2,465.6 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:327.16,329.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:332.22,336.17 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:336.17,338.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:359.65,368.31 5 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:380.3,380.13 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:368.31,369.18 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:369.18,370.58 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:375.5,375.39 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:370.58,374.6 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:376.10,378.5 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:389.29,391.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:394.40,399.41 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:399.41,402.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:412.12,413.7 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:413.7,415.18 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:419.4,420.11 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:415.18,418.5 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:421.23,421.23 0 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:422.34,423.11 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:429.12,433.7 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:433.7,434.11 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:435.34,436.11 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:438.18,444.49 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:444.49,446.6 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:457.15,459.3 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:465.6,466.10 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:468.24,476.43 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:483.4,486.14 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:489.27,490.21 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:500.4,501.14 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:504.38,505.42 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:507.24,511.29 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:526.4,526.43 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:612.4,612.46 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:629.4,629.48 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:639.4,639.33 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:655.26,657.11 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:692.4,692.19 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:697.4,701.47 4 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:476.43,481.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:490.21,497.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:497.10,499.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:511.29,518.19 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:518.19,521.6 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:521.11,523.6 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:526.43,527.52 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:562.5,562.56 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:593.5,593.12 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:609.5,609.13 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:527.52,529.6 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:562.56,566.33 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:577.6,577.33 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:580.6,580.26 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:584.6,584.53 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:587.6,588.14 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:566.33,567.63 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:567.63,575.8 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:577.33,579.7 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:580.26,582.7 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:584.53,586.7 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:594.27,596.23 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:598.27,601.102 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:603.13,603.13 0 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:612.46,614.19 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:622.5,622.45 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:626.5,626.13 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:614.19,617.6 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:617.11,619.6 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:622.45,624.6 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:629.48,633.121 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:636.5,636.15 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:633.121,635.6 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:639.33,653.5 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:658.73,660.19 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:665.69,667.19 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:673.43,675.19 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:681.48,683.19 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:688.12,690.13 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:660.19,663.14 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:667.19,670.14 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:675.19,678.14 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:683.19,685.14 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:692.19,693.13 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:701.47,704.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:709.76,711.9 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:719.2,719.69 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:712.18,714.82 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:715.18,717.86 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:722.72,724.2 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:727.62,729.2 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:731.58,733.2 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:735.58,737.2 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:739.74,740.23 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:744.2,745.14 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:750.2,751.26 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:768.2,772.16 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:776.2,776.72 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:740.23,742.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:745.14,747.3 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:752.40,756.29 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:760.45,765.18 4 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:756.29,759.4 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:772.16,774.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:795.68,800.2 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:803.77,806.2 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:811.74,812.44 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:815.2,821.13 4 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:812.44,814.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:826.90,828.2 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:830.92,831.46 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:834.2,836.11 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_resources.go:831.46,833.3 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:25.58,26.27 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:29.2,33.3 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:26.27,28.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:37.52,38.18 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:38.18,40.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:40.8,42.3 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:46.63,51.2 4 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:53.97,55.9 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:60.2,60.27 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:55.9,59.3 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:65.64,69.2 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:71.70,73.16 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:79.2,79.26 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:82.2,84.20 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:73.16,75.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:75.8,75.28 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:75.28,77.3 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:79.26,81.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:88.53,92.37 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:92.37,94.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:98.67,102.37 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:102.37,104.3 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:107.69,112.9 4 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:117.2,117.28 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:112.9,116.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:120.63,125.38 4 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:130.2,130.13 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:125.38,126.27 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:126.27,128.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:133.43,138.2 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:148.44,152.59 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:158.2,158.22 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:162.2,164.52 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:170.2,170.38 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:174.2,176.58 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:180.2,180.13 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:152.59,154.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:158.22,160.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:164.52,166.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:170.38,172.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:176.58,178.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:251.52,253.2 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:255.52,257.2 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:259.76,268.2 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:270.48,272.2 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:274.36,278.2 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:280.54,285.2 4 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:287.44,291.2 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:294.52,298.2 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:301.46,305.2 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:307.54,312.2 4 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:314.47,319.2 4 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:321.42,327.2 5 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:331.55,337.2 5 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:341.67,347.2 5 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:349.44,357.2 5 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:359.44,365.2 4 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:367.81,373.34 4 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:373.34,375.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:378.56,383.2 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:385.81,391.34 4 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:391.34,393.3 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:396.56,401.2 3 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/stream_tracker.go:403.25,405.2 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:21.125,23.9 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:31.2,31.135 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:24.27,24.27 0 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:25.20,26.9 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:31.135,34.17 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:38.3,38.19 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:34.17,36.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:43.127,45.9 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:51.2,51.131 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:46.27,46.27 0 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:47.20,48.9 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:51.131,55.17 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:58.3,58.15 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:63.3,67.29 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:71.3,71.21 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:55.17,57.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:58.15,60.4 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:67.29,69.4 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:81.3,90.21 3 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:94.2,96.23 2 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:90.21,92.3 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:96.23,101.57 4 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:101.57,103.84 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:106.4,107.20 2 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:103.84,105.5 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:108.9,109.11 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:116.4,116.20 1 1 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:110.22,111.11 1 0 +github.com/hashicorp/consul/agent/grpc-external/services/peerstream/subscription_blocking.go:112.85,113.19 1 1 +github.com/hashicorp/consul/command/debug/debug.go:58.26,69.2 4 1 +github.com/hashicorp/consul/command/debug/debug.go:113.22,141.31 12 1 +github.com/hashicorp/consul/command/debug/debug.go:141.31,143.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:146.38,150.44 3 1 +github.com/hashicorp/consul/command/debug/debug.go:155.2,155.29 1 1 +github.com/hashicorp/consul/command/debug/debug.go:161.2,162.16 2 1 +github.com/hashicorp/consul/command/debug/debug.go:166.2,169.16 3 1 +github.com/hashicorp/consul/command/debug/debug.go:174.2,176.15 2 1 +github.com/hashicorp/consul/command/debug/debug.go:180.2,195.16 9 1 +github.com/hashicorp/consul/command/debug/debug.go:200.2,200.102 1 1 +github.com/hashicorp/consul/command/debug/debug.go:215.2,222.84 2 1 +github.com/hashicorp/consul/command/debug/debug.go:228.2,228.15 1 1 +github.com/hashicorp/consul/command/debug/debug.go:237.2,239.10 2 1 +github.com/hashicorp/consul/command/debug/debug.go:150.44,153.3 2 0 +github.com/hashicorp/consul/command/debug/debug.go:155.29,158.3 2 0 +github.com/hashicorp/consul/command/debug/debug.go:162.16,165.3 2 0 +github.com/hashicorp/consul/command/debug/debug.go:169.16,172.3 2 0 +github.com/hashicorp/consul/command/debug/debug.go:176.15,178.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:195.16,197.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:200.102,202.21 2 1 +github.com/hashicorp/consul/command/debug/debug.go:205.3,205.21 1 1 +github.com/hashicorp/consul/command/debug/debug.go:208.3,209.17 2 1 +github.com/hashicorp/consul/command/debug/debug.go:202.21,204.4 1 1 +github.com/hashicorp/consul/command/debug/debug.go:205.21,207.4 1 1 +github.com/hashicorp/consul/command/debug/debug.go:209.17,211.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:222.84,225.3 2 0 +github.com/hashicorp/consul/command/debug/debug.go:228.15,231.17 2 0 +github.com/hashicorp/consul/command/debug/debug.go:231.17,234.4 2 0 +github.com/hashicorp/consul/command/debug/debug.go:243.53,245.22 1 1 +github.com/hashicorp/consul/command/debug/debug.go:260.2,261.16 2 1 +github.com/hashicorp/consul/command/debug/debug.go:265.2,266.9 2 1 +github.com/hashicorp/consul/command/debug/debug.go:272.2,272.25 1 1 +github.com/hashicorp/consul/command/debug/debug.go:277.2,278.9 2 1 +github.com/hashicorp/consul/command/debug/debug.go:281.2,281.18 1 1 +github.com/hashicorp/consul/command/debug/debug.go:292.2,292.30 1 1 +github.com/hashicorp/consul/command/debug/debug.go:298.2,298.53 1 1 +github.com/hashicorp/consul/command/debug/debug.go:307.2,307.21 1 1 +github.com/hashicorp/consul/command/debug/debug.go:245.22,246.36 1 0 +github.com/hashicorp/consul/command/debug/debug.go:250.3,250.36 1 0 +github.com/hashicorp/consul/command/debug/debug.go:254.3,254.30 1 0 +github.com/hashicorp/consul/command/debug/debug.go:246.36,248.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:250.36,252.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:254.30,256.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:261.16,263.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:266.9,268.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:272.25,274.3 1 1 +github.com/hashicorp/consul/command/debug/debug.go:278.9,280.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:281.18,283.32 2 1 +github.com/hashicorp/consul/command/debug/debug.go:283.32,284.24 1 1 +github.com/hashicorp/consul/command/debug/debug.go:284.24,288.5 3 1 +github.com/hashicorp/consul/command/debug/debug.go:292.30,293.24 1 1 +github.com/hashicorp/consul/command/debug/debug.go:293.24,295.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:298.53,300.17 2 1 +github.com/hashicorp/consul/command/debug/debug.go:300.17,302.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:303.8,305.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:312.37,315.33 2 1 +github.com/hashicorp/consul/command/debug/debug.go:325.2,325.34 1 1 +github.com/hashicorp/consul/command/debug/debug.go:335.2,335.36 1 1 +github.com/hashicorp/consul/command/debug/debug.go:344.2,344.13 1 1 +github.com/hashicorp/consul/command/debug/debug.go:315.33,317.17 2 1 +github.com/hashicorp/consul/command/debug/debug.go:320.3,320.90 1 1 +github.com/hashicorp/consul/command/debug/debug.go:317.17,319.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:320.90,322.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:325.34,327.17 2 1 +github.com/hashicorp/consul/command/debug/debug.go:330.3,330.92 1 1 +github.com/hashicorp/consul/command/debug/debug.go:327.17,329.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:330.92,332.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:335.36,337.17 2 1 +github.com/hashicorp/consul/command/debug/debug.go:340.3,340.96 1 1 +github.com/hashicorp/consul/command/debug/debug.go:337.17,339.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:340.96,342.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:347.64,349.16 2 1 +github.com/hashicorp/consul/command/debug/debug.go:352.2,352.48 1 1 +github.com/hashicorp/consul/command/debug/debug.go:349.16,351.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:358.58,367.16 7 1 +github.com/hashicorp/consul/command/debug/debug.go:370.2,371.6 2 1 +github.com/hashicorp/consul/command/debug/debug.go:367.16,369.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:371.6,372.10 1 1 +github.com/hashicorp/consul/command/debug/debug.go:373.29,376.18 3 1 +github.com/hashicorp/consul/command/debug/debug.go:379.4,379.82 1 1 +github.com/hashicorp/consul/command/debug/debug.go:380.22,382.14 2 1 +github.com/hashicorp/consul/command/debug/debug.go:383.21,384.67 1 0 +github.com/hashicorp/consul/command/debug/debug.go:376.18,378.5 1 0 +github.com/hashicorp/consul/command/debug/debug.go:389.38,392.37 2 1 +github.com/hashicorp/consul/command/debug/debug.go:406.2,406.17 1 1 +github.com/hashicorp/consul/command/debug/debug.go:392.37,394.17 2 0 +github.com/hashicorp/consul/command/debug/debug.go:398.3,398.21 1 0 +github.com/hashicorp/consul/command/debug/debug.go:402.3,402.21 1 0 +github.com/hashicorp/consul/command/debug/debug.go:394.17,396.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:398.21,400.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:402.21,404.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:409.66,411.47 2 0 +github.com/hashicorp/consul/command/debug/debug.go:414.2,414.17 1 0 +github.com/hashicorp/consul/command/debug/debug.go:411.47,413.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:417.61,420.37 2 1 +github.com/hashicorp/consul/command/debug/debug.go:431.2,431.33 1 1 +github.com/hashicorp/consul/command/debug/debug.go:438.2,438.36 1 1 +github.com/hashicorp/consul/command/debug/debug.go:446.2,446.17 1 1 +github.com/hashicorp/consul/command/debug/debug.go:420.37,421.21 1 0 +github.com/hashicorp/consul/command/debug/debug.go:426.3,426.21 1 0 +github.com/hashicorp/consul/command/debug/debug.go:421.21,424.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:426.21,429.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:431.33,432.21 1 1 +github.com/hashicorp/consul/command/debug/debug.go:432.21,436.4 3 1 +github.com/hashicorp/consul/command/debug/debug.go:438.36,439.21 1 1 +github.com/hashicorp/consul/command/debug/debug.go:439.21,443.4 3 1 +github.com/hashicorp/consul/command/debug/debug.go:449.57,451.16 2 0 +github.com/hashicorp/consul/command/debug/debug.go:455.2,455.75 1 0 +github.com/hashicorp/consul/command/debug/debug.go:451.16,453.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:458.69,460.16 2 0 +github.com/hashicorp/consul/command/debug/debug.go:463.2,467.16 4 0 +github.com/hashicorp/consul/command/debug/debug.go:470.2,472.12 3 0 +github.com/hashicorp/consul/command/debug/debug.go:460.16,462.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:467.16,469.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:475.68,477.16 2 0 +github.com/hashicorp/consul/command/debug/debug.go:480.2,484.16 4 0 +github.com/hashicorp/consul/command/debug/debug.go:487.2,489.12 3 0 +github.com/hashicorp/consul/command/debug/debug.go:477.16,479.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:484.16,486.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:492.51,494.16 2 0 +github.com/hashicorp/consul/command/debug/debug.go:498.2,498.72 1 0 +github.com/hashicorp/consul/command/debug/debug.go:494.16,496.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:501.54,503.16 2 1 +github.com/hashicorp/consul/command/debug/debug.go:508.2,509.16 2 1 +github.com/hashicorp/consul/command/debug/debug.go:512.2,514.6 2 1 +github.com/hashicorp/consul/command/debug/debug.go:503.16,505.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:509.16,511.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:514.6,515.10 1 1 +github.com/hashicorp/consul/command/debug/debug.go:516.23,517.17 1 1 +github.com/hashicorp/consul/command/debug/debug.go:520.4,520.54 1 1 +github.com/hashicorp/consul/command/debug/debug.go:523.21,524.14 1 1 +github.com/hashicorp/consul/command/debug/debug.go:517.17,519.5 1 0 +github.com/hashicorp/consul/command/debug/debug.go:520.54,522.5 1 0 +github.com/hashicorp/consul/command/debug/debug.go:529.57,531.16 2 1 +github.com/hashicorp/consul/command/debug/debug.go:534.2,537.16 3 1 +github.com/hashicorp/consul/command/debug/debug.go:540.2,544.61 4 1 +github.com/hashicorp/consul/command/debug/debug.go:547.2,547.12 1 1 +github.com/hashicorp/consul/command/debug/debug.go:531.16,533.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:537.16,539.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:544.61,546.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:552.40,553.36 1 1 +github.com/hashicorp/consul/command/debug/debug.go:558.2,558.38 1 0 +github.com/hashicorp/consul/command/debug/debug.go:563.2,563.14 1 0 +github.com/hashicorp/consul/command/debug/debug.go:553.36,554.19 1 1 +github.com/hashicorp/consul/command/debug/debug.go:554.19,556.4 1 1 +github.com/hashicorp/consul/command/debug/debug.go:558.38,559.18 1 0 +github.com/hashicorp/consul/command/debug/debug.go:559.18,561.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:567.49,568.31 1 1 +github.com/hashicorp/consul/command/debug/debug.go:576.2,576.14 1 1 +github.com/hashicorp/consul/command/debug/debug.go:568.31,569.19 1 1 +github.com/hashicorp/consul/command/debug/debug.go:572.3,572.53 1 1 +github.com/hashicorp/consul/command/debug/debug.go:569.19,571.4 1 1 +github.com/hashicorp/consul/command/debug/debug.go:572.53,574.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:581.37,585.16 3 0 +github.com/hashicorp/consul/command/debug/debug.go:589.2,589.50 1 0 +github.com/hashicorp/consul/command/debug/debug.go:593.2,593.44 1 0 +github.com/hashicorp/consul/command/debug/debug.go:598.2,598.47 1 0 +github.com/hashicorp/consul/command/debug/debug.go:602.2,602.12 1 0 +github.com/hashicorp/consul/command/debug/debug.go:585.16,587.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:589.50,591.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:593.44,595.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:598.47,600.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:605.39,607.16 2 0 +github.com/hashicorp/consul/command/debug/debug.go:610.2,612.17 2 0 +github.com/hashicorp/consul/command/debug/debug.go:607.16,609.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:615.75,620.16 4 0 +github.com/hashicorp/consul/command/debug/debug.go:624.2,629.45 4 0 +github.com/hashicorp/consul/command/debug/debug.go:637.2,637.83 1 0 +github.com/hashicorp/consul/command/debug/debug.go:670.2,670.16 1 0 +github.com/hashicorp/consul/command/debug/debug.go:676.2,676.34 1 0 +github.com/hashicorp/consul/command/debug/debug.go:679.2,679.34 1 0 +github.com/hashicorp/consul/command/debug/debug.go:684.2,684.33 1 0 +github.com/hashicorp/consul/command/debug/debug.go:689.2,689.34 1 0 +github.com/hashicorp/consul/command/debug/debug.go:693.2,693.22 1 0 +github.com/hashicorp/consul/command/debug/debug.go:620.16,622.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:629.45,635.3 5 0 +github.com/hashicorp/consul/command/debug/debug.go:637.83,638.17 1 0 +github.com/hashicorp/consul/command/debug/debug.go:642.3,643.17 2 0 +github.com/hashicorp/consul/command/debug/debug.go:647.3,649.47 2 0 +github.com/hashicorp/consul/command/debug/debug.go:654.3,654.29 1 0 +github.com/hashicorp/consul/command/debug/debug.go:658.3,659.17 2 0 +github.com/hashicorp/consul/command/debug/debug.go:663.3,663.42 1 0 +github.com/hashicorp/consul/command/debug/debug.go:667.3,667.19 1 0 +github.com/hashicorp/consul/command/debug/debug.go:638.17,640.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:643.17,645.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:649.47,651.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:654.29,656.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:659.17,661.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:663.42,665.4 1 0 +github.com/hashicorp/consul/command/debug/debug.go:670.16,672.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:676.34,678.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:679.34,681.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:684.33,686.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:689.34,691.3 1 0 +github.com/hashicorp/consul/command/debug/debug.go:719.33,721.2 1 0 +github.com/hashicorp/consul/command/debug/debug.go:723.29,725.2 1 0 diff --git a/.github/pr-labeler.yml b/.github/pr-labeler.yml index 1e371d5f9013..759130301bfb 100644 --- a/.github/pr-labeler.yml +++ b/.github/pr-labeler.yml @@ -57,7 +57,7 @@ theme/ui: # thinking: # type/bug: type/ci: - - .circleci/* + - .github/workflows/* # type/crash: type/docs: - website/**/* diff --git a/.github/scripts/changelog_checker.sh b/.github/scripts/changelog_checker.sh new file mode 100755 index 000000000000..e46030da1e16 --- /dev/null +++ b/.github/scripts/changelog_checker.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -euo pipefail + +# check if there is a diff in the .changelog directory +# for PRs against the main branch, the changelog file name should match the PR number +if [ "$GITHUB_BASE_REF" = "$GITHUB_DEFAULT_BRANCH" ]; then + enforce_matching_pull_request_number="matching this PR number " + changelog_file_path=".changelog/(_)?$PR_NUMBER.txt" +else + changelog_file_path=".changelog/[_0-9]*.txt" +fi + +changelog_files=$(git --no-pager diff --name-only HEAD "$(git merge-base HEAD "origin/main")" | egrep "${changelog_file_path}") + +# If we do not find a file in .changelog/, we fail the check +if [ -z "$changelog_files" ]; then + # Fail status check when no .changelog entry was found on the PR + echo "Did not find a .changelog entry ${enforce_matching_pull_request_number}and the 'pr/no-changelog' label was not applied. Reference - https://github.com/hashicorp/consul/pull/8387" + exit 1 +else + echo "Found .changelog entry in PR!" +fi diff --git a/.github/scripts/get_runner_classes.sh b/.github/scripts/get_runner_classes.sh new file mode 100755 index 000000000000..5eb56ff172be --- /dev/null +++ b/.github/scripts/get_runner_classes.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# +# This script generates tag-sets that can be used as runs-on: values to select runners. + +set -euo pipefail + +case "$GITHUB_REPOSITORY" in +*-enterprise) + # shellcheck disable=SC2129 + echo "compute-small=['self-hosted', 'linux', 'small']" >>"$GITHUB_OUTPUT" + echo "compute-medium=['self-hosted', 'linux', 'medium']" >>"$GITHUB_OUTPUT" + echo "compute-large=['self-hosted', 'linux', 'large']" >>"$GITHUB_OUTPUT" + # m5d.8xlarge is equivalent to our xl custom runner in CE + echo "compute-xl=['self-hosted', 'ondemand', 'linux', 'type=m6a.2xlarge']" >>"$GITHUB_OUTPUT" + ;; +*) + # shellcheck disable=SC2129 + echo "compute-small=['custom-linux-s-consul-latest']" >>"$GITHUB_OUTPUT" + echo "compute-medium=['custom-linux-m-consul-latest']" >>"$GITHUB_OUTPUT" + echo "compute-large=['custom-linux-l-consul-latest']" >>"$GITHUB_OUTPUT" + echo "compute-xl=['custom-linux-xl-consul-latest']" >>"$GITHUB_OUTPUT" + ;; +esac diff --git a/.github/scripts/license_checker.sh b/.github/scripts/license_checker.sh new file mode 100755 index 000000000000..6ba026f04fdd --- /dev/null +++ b/.github/scripts/license_checker.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: BUSL-1.1 + + +busl_files=$(grep -r 'SPDX-License-Identifier: BUSL' . --exclude-dir .github) + +# If we do not find a file in .changelog/, we fail the check +if [ -n "$busl_files" ]; then + echo "Found BUSL occurrences in the PR branch! (See NET-5258 for details)" + echo -n "$busl_files" + exit 1 +else + echo "Did not find any occurrences of BUSL in the PR branch" + exit 0 +fi diff --git a/.github/scripts/notify_slack.sh b/.github/scripts/notify_slack.sh new file mode 100755 index 000000000000..b3dcdb210dc6 --- /dev/null +++ b/.github/scripts/notify_slack.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +set -uo pipefail + +# This script is used in GitHub Actions pipelines to notify Slack of a job failure. + +if [[ $GITHUB_REF_NAME == "main" ]]; then + GITHUB_ENDPOINT="https://github.com/${GITHUB_REPOSITORY}/commit/${GITHUB_SHA}" + GITHUB_ACTIONS_ENDPOINT="https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" + COMMIT_MESSAGE=$(git log -1 --pretty=%B | head -n1) + SHORT_REF=$(git rev-parse --short "${GITHUB_SHA}") + curl -X POST -H 'Content-type: application/json' \ + --data \ + "{ \ + \"attachments\": [ \ + { \ + \"fallback\": \"GitHub Actions workflow failed!\", \ + \"text\": \"❌ Failed: \`${GITHUB_ACTOR}\`'s <${GITHUB_ACTIONS_ENDPOINT}|${GITHUB_JOB}> job failed for commit <${GITHUB_ENDPOINT}|${SHORT_REF}> on \`${GITHUB_REF_NAME}\`!\n\n- <${COMMIT_MESSAGE}\", \ + \"footer\": \"${GITHUB_REPOSITORY}\", \ + \"ts\": \"$(date +%s)\", \ + \"color\": \"danger\" \ + } \ + ] \ + }" "${FEED_CONSUL_GH_URL}" +else + echo "Not posting slack failure notifications for non-main branch" +fi diff --git a/.circleci/scripts/rerun-fails-report.sh b/.github/scripts/rerun_fails_report.sh similarity index 65% rename from .circleci/scripts/rerun-fails-report.sh rename to .github/scripts/rerun_fails_report.sh index 959f0708e685..ac6b7cf2ff9d 100755 --- a/.circleci/scripts/rerun-fails-report.sh +++ b/.github/scripts/rerun_fails_report.sh @@ -1,4 +1,7 @@ #!/usr/bin/env bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + # # Add a comment on the github PR if there were any rerun tests. # @@ -11,11 +14,11 @@ if [ ! -s "$report_filename" ]; then fi function report { - echo ":repeat: gotestsum re-ran some tests in $CIRCLE_BUILD_URL" + echo ":repeat: gotestsum re-ran some tests in https://github.com/hashicorp/consul/actions/run/$GITHUB_RUN_ID" echo echo '```' cat "$report_filename" echo '```' } -report \ No newline at end of file +report diff --git a/.github/scripts/set_test_package_matrix.sh b/.github/scripts/set_test_package_matrix.sh new file mode 100755 index 000000000000..a9a21c747e57 --- /dev/null +++ b/.github/scripts/set_test_package_matrix.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +export RUNNER_COUNT=$1 + +# set matrix var to list of unique packages containing tests +matrix="$(go list -json="ImportPath,TestGoFiles" ./... | jq --compact-output '. | select(.TestGoFiles != null) | .ImportPath' | jq --slurp --compact-output '.' | jq --argjson runnercount $RUNNER_COUNT -cM '[_nwise(length / $runnercount | floor)]'))" + +echo "matrix=${matrix}" >> "${GITHUB_OUTPUT}" diff --git a/.github/workflows/backport-assistant.yml b/.github/workflows/backport-assistant.yml index b68e41e61269..d842f1b16730 100644 --- a/.github/workflows/backport-assistant.yml +++ b/.github/workflows/backport-assistant.yml @@ -16,11 +16,11 @@ jobs: backport: if: github.event.pull_request.merged runs-on: ubuntu-latest - container: hashicorpdev/backport-assistant:0.2.5 + container: hashicorpdev/backport-assistant:0.3.4 steps: - name: Run Backport Assistant for stable-website run: | - backport-assistant backport -merge-method=squash -automerge + backport-assistant backport -merge-method=squash -gh-automerge env: BACKPORT_LABEL_REGEXP: "type/docs-(?Pcherrypick)" BACKPORT_TARGET_TEMPLATE: "stable-website" @@ -41,14 +41,27 @@ jobs: # set BACKPORT_TARGET_TEMPLATE for backport-assistant # trims backport/ from the beginning with parameter substitution export BACKPORT_TARGET_TEMPLATE="release/${latest_backport_label#backport/}.x" - backport-assistant backport -merge-method=squash -automerge + backport-assistant backport -merge-method=squash -gh-automerge env: BACKPORT_LABEL_REGEXP: "type/docs-(?Pcherrypick)" GITHUB_TOKEN: ${{ secrets.ELEVATED_GITHUB_TOKEN }} - name: Run Backport Assistant for release branches run: | - backport-assistant backport -merge-method=squash -automerge + backport-assistant backport -merge-method=squash -gh-automerge env: BACKPORT_LABEL_REGEXP: "backport/(?P\\d+\\.\\d+)" BACKPORT_TARGET_TEMPLATE: "release/{{.target}}.x" GITHUB_TOKEN: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + handle-failure: + needs: + - backport + if: always() && needs.backport.result == 'failure' + runs-on: ubuntu-latest + steps: + - name: Comment on PR + run: | + github_message="Backport failed @${{ github.event.sender.login }}. Run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + curl -s -H "Authorization: token ${{ secrets.PR_COMMENT_TOKEN }}" \ + -X POST \ + -d "{ \"body\": \"${github_message}\"}" \ + "https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/${{ github.event.pull_request.number }}/comments" diff --git a/.github/workflows/backport-checker.yml b/.github/workflows/backport-checker.yml new file mode 100644 index 000000000000..c9af23ea9717 --- /dev/null +++ b/.github/workflows/backport-checker.yml @@ -0,0 +1,32 @@ +# This workflow checks that there is either a 'pr/no-backport' label applied to a PR +# or there is a backport/* label indicating a backport has been set + +name: Backport Checker + +on: + pull_request: + types: [opened, synchronize, labeled] + # Runs on PRs to main and all release branches + branches: + - main + - release/* + +jobs: + # checks that a backport label is present for a PR + backport-check: + # If there's a `pr/no-backport` label we ignore this check. Also, we ignore PRs created by the bot assigned to `backport-assistant` + if: "! ( contains(github.event.pull_request.labels.*.name, 'pr/no-backport') || github.event.pull_request.user.login == 'hc-github-team-consul-core' )" + runs-on: ubuntu-latest + + steps: + - name: Check for Backport Label + run: | + labels="${{join(github.event.pull_request.labels.*.name, ', ') }}" + if [[ "$labels" =~ .*"backport/".* ]]; then + echo "Found backport label!" + exit 0 + fi + # Fail status check when no backport label was found on the PR + echo "Did not find a backport label matching the pattern 'backport/*' and the 'pr/no-backport' label was not applied. Reference - https://github.com/hashicorp/consul/pull/16567" + exit 1 + diff --git a/.github/workflows/backport-reminder.yml b/.github/workflows/backport-reminder.yml deleted file mode 100644 index 359451269d7a..000000000000 --- a/.github/workflows/backport-reminder.yml +++ /dev/null @@ -1,26 +0,0 @@ -# This workflow sends a reminder comment to PRs that have labels starting with -# `backport/` to check that the backport has run successfully. - -name: Backport Assistant Reminder - -on: - pull_request: - types: [ labeled ] - # Runs on PRs to main and all release branches - branches: - - main - - release/* - -jobs: - backport-label-check: - if: "startsWith(github.event.label.name, 'backport/')" - runs-on: ubuntu-latest - - steps: - - name: Comment on PR - run: | - github_message="After merging, confirm that you see linked PRs AND check them for CI errors." - curl -s -H "Authorization: token ${{ secrets.PR_COMMENT_TOKEN }}" \ - -X POST \ - -d "{ \"body\": \"${github_message}\"}" \ - "https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/${{ github.event.pull_request.number }}/comments" diff --git a/.github/workflows/bot-auto-approve.yaml b/.github/workflows/bot-auto-approve.yaml new file mode 100644 index 000000000000..7731e4553ce8 --- /dev/null +++ b/.github/workflows/bot-auto-approve.yaml @@ -0,0 +1,13 @@ +name: Bot Auto Approve + +on: pull_request_target + +jobs: + auto-approve: + runs-on: ubuntu-latest + if: github.actor == 'hc-github-team-consul-core' + steps: + - uses: hmarr/auto-approve-action@v3 + with: + review-message: "Auto approved Consul Bot automated PR" + github-token: ${{ secrets.MERGE_APPROVE_TOKEN }} diff --git a/.github/workflows/build-distros.yml b/.github/workflows/build-distros.yml new file mode 100644 index 000000000000..6f5722a82ab9 --- /dev/null +++ b/.github/workflows/build-distros.yml @@ -0,0 +1,149 @@ +# NOTE: this workflow builds Consul binaries on multiple architectures for PRs. +# It is aimed at checking new commits don't introduce any breaking build changes. +name: build-distros + +on: + pull_request: + push: + branches: + # Push events on the main branch + - main + - release/** + +permissions: + contents: read + +env: + GOTAGS: ${{ endsWith(github.repository, '-enterprise') && 'consulent' || '' }} + +jobs: + setup: + name: Setup + runs-on: ubuntu-latest + outputs: + compute-small: ${{ steps.setup-outputs.outputs.compute-small }} + compute-medium: ${{ steps.setup-outputs.outputs.compute-medium }} + compute-large: ${{ steps.setup-outputs.outputs.compute-large }} + compute-xl: ${{ steps.setup-outputs.outputs.compute-xl }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + - id: setup-outputs + name: Setup outputs + run: ./.github/scripts/get_runner_classes.sh + + check-go-mod: + needs: + - setup + uses: ./.github/workflows/reusable-check-go-mod.yml + with: + runs-on: ${{ needs.setup.outputs.compute-medium }} + repository-name: ${{ github.repository }} + secrets: + elevated-github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + + build-386: + needs: + - setup + - check-go-mod + env: + XC_OS: "freebsd linux windows" + runs-on: ${{ fromJSON(needs.setup.outputs.compute-xl) }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + + # NOTE: This step is specifically needed for ENT. It allows us to access the required private HashiCorp repos. + - name: Setup Git + if: ${{ endsWith(github.repository, '-enterprise') }} + run: git config --global url."https://${{ secrets.ELEVATED_GITHUB_TOKEN }}:@github.com".insteadOf "https://github.com" + + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v3.5.0 + with: + go-version-file: 'go.mod' + - name: Build + run: | + for os in $XC_OS; do + GOOS="$os" GOARCH=386 CGO_ENABLED=0 go build -tags "${{ env.GOTAGS }}" + done + + build-amd64: + needs: + - setup + - check-go-mod + env: + XC_OS: "darwin freebsd linux solaris windows" + runs-on: ${{ fromJSON(needs.setup.outputs.compute-xl) }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + + # NOTE: This step is specifically needed for ENT. It allows us to access the required private HashiCorp repos. + - name: Setup Git + if: ${{ endsWith(github.repository, '-enterprise') }} + run: git config --global url."https://${{ secrets.ELEVATED_GITHUB_TOKEN }}:@github.com".insteadOf "https://github.com" + + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v3.5.0 + with: + go-version-file: 'go.mod' + - name: Build + run: | + for os in $XC_OS; do + GOOS="$os" GOARCH=amd64 CGO_ENABLED=0 go build -tags "${{ env.GOTAGS }}" + done + + build-arm: + needs: + - setup + - check-go-mod + runs-on: ${{ fromJSON(needs.setup.outputs.compute-xl) }} + env: + CGO_ENABLED: 1 + GOOS: linux + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + + # NOTE: This step is specifically needed for ENT. It allows us to access the required private HashiCorp repos. + - name: Setup Git + if: ${{ endsWith(github.repository, '-enterprise') }} + run: git config --global url."https://${{ secrets.ELEVATED_GITHUB_TOKEN }}:@github.com".insteadOf "https://github.com" + + + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v3.5.0 + with: + go-version-file: 'go.mod' + - run: | + sudo apt-get update --allow-releaseinfo-change-suite --allow-releaseinfo-change-version && sudo apt-get install -y gcc-arm-linux-gnueabi gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu + + - run: CC=arm-linux-gnueabi-gcc GOARCH=arm GOARM=5 go build -tags "${{ env.GOTAGS }}" + - run: CC=arm-linux-gnueabihf-gcc GOARCH=arm GOARM=6 go build -tags "${{ env.GOTAGS }}" + - run: CC=aarch64-linux-gnu-gcc GOARCH=arm64 go build -tags "${{ env.GOTAGS }}" + + # This is job is required for branch protection as a required gihub check + # because GitHub actions show up as checks at the job level and not the + # workflow level. This is currently a feature request: + # https://github.com/orgs/community/discussions/12395 + # + # This job must: + # - be placed after the fanout of a workflow so that everything fans back in + # to this job. + # - "need" any job that is part of the fan out / fan in + # - implement the if logic because we have conditional jobs + # (go-test-enteprise) that this job needs and this would potentially get + # skipped if a previous job got skipped. So we use the if clause to make + # sure it does not get skipped. + + build-distros-success: + needs: + - setup + - check-go-mod + - build-386 + - build-amd64 + - build-arm + runs-on: ${{ fromJSON(needs.setup.outputs.compute-small) }} + if: ${{ always() }} + steps: + - name: evaluate upstream job results + run: | + # exit 1 if failure or cancelled result for any upstream job + if printf '${{ toJSON(needs) }}' | grep -E -i '\"result\": \"(failure|cancelled)\"'; then + printf "Tests failed or workflow cancelled:\n\n${{ toJSON(needs) }}" + exit 1 + fi diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cd31d26b520c..7f741c3b9ede 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,89 +10,94 @@ on: env: PKG_NAME: consul + # TODO(spatel): CE refactor + METADATA: oss jobs: - get-product-version: + set-product-version: runs-on: ubuntu-latest outputs: - product-version: ${{ steps.get-product-version.outputs.product-version }} + product-version: ${{ steps.set-product-version.outputs.product-version }} + base-product-version: ${{ steps.set-product-version.outputs.base-product-version }} product-date: ${{ steps.get-product-version.outputs.product-date }} - pre-version: ${{ steps.get-product-version.outputs.pre-version }} - pkg-version: ${{ steps.get-product-version.outputs.pkg-version }} + pre-version: ${{ steps.set-product-version.outputs.prerelease-product-version }} shared-ldflags: ${{ steps.shared-ldflags.outputs.shared-ldflags }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + - name: set product version + id: set-product-version + uses: hashicorp/actions-set-product-version@v1 - name: get product version id: get-product-version run: | - CONSUL_VERSION=$(build-support/scripts/version.sh -r) CONSUL_DATE=$(build-support/scripts/build-date.sh) ## TODO: This assumes `make version` outputs 1.1.1+ent-prerel - IFS="+" read VERSION _other <<< "$CONSUL_VERSION" - IFS="-" read _other PREREL_VERSION <<< "$CONSUL_VERSION" - ## TODO: this assumes `version.sh` outputs in the expected ordering of - ## [version]+ent{-prerelease} If we need to transition to - ## [version]{-prerelease}+ent before then, we'll need to add - ## logic to handle presense/absence of the prerelease - echo "::set-output name=product-version::${CONSUL_VERSION}" - echo "::set-output name=product-date::${CONSUL_DATE}" - echo "::set-output name=pre-version::${PREREL_VERSION}" - echo "::set-output name=pkg-version::${VERSION}" + echo "product-date=${CONSUL_DATE}" >> "$GITHUB_OUTPUT" - name: Set shared -ldflags id: shared-ldflags run: | T="github.com/hashicorp/consul/version" - echo "::set-output name=shared-ldflags::-X ${T}.GitCommit=${GITHUB_SHA::8} -X ${T}.GitDescribe=${{ steps.get-product-version.outputs.product-version }} -X ${T}.BuildDate=${{ steps.get-product-version.outputs.product-date }}" + echo "shared-ldflags=-X ${T}.GitCommit=${GITHUB_SHA::8} \ + -X ${T}.GitDescribe=${{ steps.set-product-version.outputs.product-version }} \ + -X ${T}.BuildDate=${{ steps.get-product-version.outputs.product-date }} \ + " >> "$GITHUB_OUTPUT" + validate-outputs: + needs: set-product-version + runs-on: ubuntu-latest + steps: + - name: Validate Outputs + run: | + echo "Product Version: ${{ needs.set-product-version.outputs.product-version }}" + echo "Base Product Version: ${{ needs.set-product-version.outputs.base-product-version }}" + echo "Product Metadata: ${{ env.METADATA }}" + echo "Product Date: ${{ needs.set-product-version.outputs.product-date }}" + echo "Prerelease Version: ${{ needs.set-product-version.outputs.pre-version }}" + echo "Ldflags: ${{ needs.set-product-version.outputs.shared-ldflags }}" generate-metadata-file: - needs: get-product-version + needs: set-product-version runs-on: ubuntu-latest outputs: filepath: ${{ steps.generate-metadata-file.outputs.filepath }} steps: - name: 'Checkout directory' - uses: actions/checkout@v2 + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - name: Generate metadata file id: generate-metadata-file uses: hashicorp/actions-generate-metadata@v1 with: - version: ${{ needs.get-product-version.outputs.product-version }} + version: ${{ needs.set-product-version.outputs.product-version }} product: ${{ env.PKG_NAME }} - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # pin@3.1.2 with: name: metadata.json path: ${{ steps.generate-metadata-file.outputs.filepath }} build: - needs: get-product-version + needs: set-product-version runs-on: ubuntu-latest strategy: matrix: include: - - {go: "1.18.1", goos: "linux", goarch: "386"} - - {go: "1.18.1", goos: "linux", goarch: "amd64"} - - {go: "1.18.1", goos: "linux", goarch: "arm"} - - {go: "1.18.1", goos: "linux", goarch: "arm64"} - - {go: "1.18.1", goos: "freebsd", goarch: "386"} - - {go: "1.18.1", goos: "freebsd", goarch: "amd64"} - - {go: "1.18.1", goos: "windows", goarch: "386"} - - {go: "1.18.1", goos: "windows", goarch: "amd64"} - - {go: "1.18.1", goos: "solaris", goarch: "amd64"} + - {go: "1.20.8", goos: "linux", goarch: "386"} + - {go: "1.20.8", goos: "linux", goarch: "amd64"} + - {go: "1.20.8", goos: "linux", goarch: "arm"} + - {go: "1.20.8", goos: "linux", goarch: "arm64"} + - {go: "1.20.8", goos: "freebsd", goarch: "386"} + - {go: "1.20.8", goos: "freebsd", goarch: "amd64"} + - {go: "1.20.8", goos: "windows", goarch: "386"} + - {go: "1.20.8", goos: "windows", goarch: "amd64"} + - {go: "1.20.8", goos: "solaris", goarch: "amd64"} fail-fast: true name: Go ${{ matrix.go }} ${{ matrix.goos }} ${{ matrix.goarch }} build steps: - - uses: actions/checkout@v2 - - - name: Setup go - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go }} + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - name: Setup with node and yarn - uses: actions/setup-node@v2 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # pin@v3.6.0 with: node-version: '14' cache: 'yarn' @@ -100,8 +105,8 @@ jobs: - name: Build UI run: | - CONSUL_VERSION=${{ needs.get-product-version.outputs.product-version }} - CONSUL_DATE=${{ needs.get-product-version.outputs.product-date }} + CONSUL_VERSION=${{ needs.set-product-version.outputs.product-version }} + CONSUL_DATE=${{ needs.set-product-version.outputs.product-date }} CONSUL_BINARY_TYPE=${CONSUL_BINARY_TYPE} CONSUL_COPYRIGHT_YEAR=$(git show -s --format=%cd --date=format:%Y HEAD) echo "consul_version is ${CONSUL_VERSION}" @@ -111,22 +116,23 @@ jobs: cd ui && make && cd .. rm -rf agent/uiserver/dist mv ui/packages/consul-ui/dist agent/uiserver/ - - name: Build + - name: Go Build env: - GOOS: ${{ matrix.goos }} - GOARCH: ${{ matrix.goarch }} - CGO_ENABLED: 0 - GOLDFLAGS: "${{needs.get-product-version.outputs.shared-ldflags}}" - run: | - mkdir dist out - go build -ldflags="$GOLDFLAGS" -o dist/ . - zip -r -j out/${{ env.PKG_NAME }}_${{ needs.get-product-version.outputs.product-version }}_${{ matrix.goos }}_${{ matrix.goarch }}.zip dist/ - - - uses: actions/upload-artifact@v2 + PRODUCT_VERSION: ${{ needs.set-product-version.outputs.product-version }} + PRERELEASE_VERSION: ${{ needs.set-product-version.outputs.pre-version }} + CGO_ENABLED: "0" + GOLDFLAGS: "${{needs.set-product-version.outputs.shared-ldflags}}" + uses: hashicorp/actions-go-build@v0.1.7 with: - name: ${{ env.PKG_NAME }}_${{ needs.get-product-version.outputs.product-version }}_${{ matrix.goos }}_${{ matrix.goarch }}.zip - path: out/${{ env.PKG_NAME }}_${{ needs.get-product-version.outputs.product-version }}_${{ matrix.goos }}_${{ matrix.goarch }}.zip - + product_name: ${{ env.PKG_NAME }} + product_version: ${{ needs.set-product-version.outputs.product-version }} + go_version: ${{ matrix.go }} + os: ${{ matrix.goos }} + arch: ${{ matrix.goarch }} + reproducible: report + instructions: |- + go build -ldflags="$GOLDFLAGS" -o "$BIN_PATH" -trimpath -buildvcs=false + - name: Package if: ${{ matrix.goos == 'linux' }} uses: hashicorp/actions-packaging-linux@v1 @@ -134,7 +140,7 @@ jobs: name: ${{ github.event.repository.name }} description: "Consul is a distributed, highly available, and data center aware solution to connect and configure applications across dynamic, distributed infrastructure. " arch: ${{ matrix.goarch }} - version: ${{ needs.get-product-version.outputs.product-version }} + version: ${{ needs.set-product-version.outputs.product-version }} maintainer: "HashiCorp" homepage: "https://github.com/hashicorp/consul" license: "MPL-2.0" @@ -153,39 +159,34 @@ jobs: echo "RPM_PACKAGE=$(basename out/*.rpm)" >> $GITHUB_ENV echo "DEB_PACKAGE=$(basename out/*.deb)" >> $GITHUB_ENV - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # pin@3.1.2 if: ${{ matrix.goos == 'linux' }} with: name: ${{ env.RPM_PACKAGE }} path: out/${{ env.RPM_PACKAGE }} - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # pin@3.1.2 if: ${{ matrix.goos == 'linux' }} with: name: ${{ env.DEB_PACKAGE }} path: out/${{ env.DEB_PACKAGE }} build-darwin: - needs: get-product-version + needs: set-product-version runs-on: macos-latest strategy: matrix: goos: [ darwin ] goarch: [ "amd64", "arm64" ] - go: [ "1.18.1" ] + go: [ "1.20.8" ] fail-fast: true name: Go ${{ matrix.go }} ${{ matrix.goos }} ${{ matrix.goarch }} build steps: - - uses: actions/checkout@v2 - - - name: Setup go - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go }} + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - name: Setup with node and yarn - uses: actions/setup-node@v2 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # pin@v3.6.0 with: node-version: '14' cache: 'yarn' @@ -193,7 +194,7 @@ jobs: - name: Build UI run: | - CONSUL_VERSION=${{ needs.get-product-version.outputs.product-version }} + CONSUL_VERSION=${{ needs.set-product-version.outputs.product-version }} CONSUL_BINARY_TYPE=${CONSUL_BINARY_TYPE} CONSUL_COPYRIGHT_YEAR=$(git show -s --format=%cd --date=format:%Y HEAD) echo "consul_version is ${CONSUL_VERSION}" @@ -203,25 +204,27 @@ jobs: rm -rf agent/uiserver/dist mv ui/packages/consul-ui/dist agent/uiserver/ - - name: Build + - name: Go Build env: - GOOS: ${{ matrix.goos }} - GOARCH: ${{ matrix.goarch }} - GOLDFLAGS: "${{ needs.get-product-version.outputs.shared-ldflags }}" - run: | - mkdir dist out - go build -ldflags="$GOLDFLAGS" -tags netcgo -o dist/ . - zip -r -j out/${{ env.PKG_NAME }}_${{ needs.get-product-version.outputs.product-version }}_${{ matrix.goos }}_${{ matrix.goarch }}.zip dist/ - - - uses: actions/upload-artifact@v2 + PRODUCT_VERSION: ${{ needs.set-product-version.outputs.product-version }} + PRERELEASE_VERSION: ${{ needs.set-product-version.outputs.pre-version }} + CGO_ENABLED: "0" + GOLDFLAGS: "${{needs.set-product-version.outputs.shared-ldflags}}" + uses: hashicorp/actions-go-build@v0.1.7 with: - name: ${{ env.PKG_NAME }}_${{ needs.get-product-version.outputs.product-version }}_${{ matrix.goos }}_${{ matrix.goarch }}.zip - path: out/${{ env.PKG_NAME }}_${{ needs.get-product-version.outputs.product-version }}_${{ matrix.goos }}_${{ matrix.goarch }}.zip + product_name: ${{ env.PKG_NAME }} + product_version: ${{ needs.set-product-version.outputs.product-version }} + go_version: ${{ matrix.go }} + os: ${{ matrix.goos }} + arch: ${{ matrix.goarch }} + reproducible: report + instructions: |- + go build -ldflags="$GOLDFLAGS" -tags netcgo -o "$BIN_PATH" -trimpath -buildvcs=false build-docker: name: Docker ${{ matrix.arch }} build needs: - - get-product-version + - set-product-version - build runs-on: ubuntu-latest strategy: @@ -229,10 +232,10 @@ jobs: arch: ["386", "amd64", "arm", "arm64"] env: repo: ${{github.event.repository.name}} - version: ${{needs.get-product-version.outputs.product-version}} + version: ${{needs.set-product-version.outputs.product-version}} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 # Strip everything but MAJOR.MINOR from the version string and add a `-dev` suffix # This naming convention will be used ONLY for per-commit dev images @@ -258,15 +261,15 @@ jobs: build-docker-ubi-redhat: name: Docker Build UBI Image for RedHat Registry needs: - - get-product-version + - set-product-version - build runs-on: ubuntu-latest env: repo: ${{github.event.repository.name}} - version: ${{needs.get-product-version.outputs.product-version}} + version: ${{needs.set-product-version.outputs.product-version}} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - uses: hashicorp/actions-docker-build@v1 with: version: ${{env.version}} @@ -278,15 +281,15 @@ jobs: build-docker-ubi-dockerhub: name: Docker Build UBI Image for DockerHub needs: - - get-product-version + - set-product-version - build runs-on: ubuntu-latest env: repo: ${{github.event.repository.name}} - version: ${{needs.get-product-version.outputs.product-version}} + version: ${{needs.set-product-version.outputs.product-version}} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 # Strip everything but MAJOR.MINOR from the version string and add a `-dev` suffix # This naming convention will be used ONLY for per-commit dev images @@ -310,7 +313,7 @@ jobs: verify-linux: needs: - - get-product-version + - set-product-version - build runs-on: ubuntu-latest strategy: @@ -318,20 +321,20 @@ jobs: arch: ["386", "amd64", "arm", "arm64"] fail-fast: true env: - version: ${{ needs.get-product-version.outputs.product-version }} - zip_name: consul_${{ needs.get-product-version.outputs.product-version }}_linux_${{ matrix.arch }}.zip + version: ${{ needs.set-product-version.outputs.product-version }} + zip_name: consul_${{ needs.set-product-version.outputs.product-version }}_linux_${{ matrix.arch }}.zip name: Verify ${{ matrix.arch }} linux binary steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - name: Download ${{ matrix.arch }} zip - uses: actions/download-artifact@v3 + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # pin@v3.0.2 with: name: ${{ env.zip_name }} - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # pin@v2.1.0 if: ${{ matrix.arch == 'arm' || matrix.arch == 'arm64' }} with: # this should be a comma-separated string as opposed to an array @@ -342,21 +345,21 @@ jobs: verify-darwin: needs: - - get-product-version + - set-product-version - build-darwin runs-on: macos-latest strategy: fail-fast: true env: - version: ${{needs.get-product-version.outputs.product-version}} - zip_name: consul_${{ needs.get-product-version.outputs.product-version }}_darwin_amd64.zip + version: ${{needs.set-product-version.outputs.product-version}} + zip_name: consul_${{ needs.set-product-version.outputs.product-version }}_darwin_amd64.zip name: Verify amd64 darwin binary steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - name: Download amd64 darwin zip - uses: actions/download-artifact@v3 + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # pin@v3.0.2 with: name: ${{ env.zip_name }} @@ -369,34 +372,34 @@ jobs: verify-linux-packages-deb: needs: - build - - get-product-version + - set-product-version runs-on: ubuntu-latest strategy: matrix: arch: ["i386", "amd64", "armhf", "arm64"] # fail-fast: true env: - version: ${{ needs.get-product-version.outputs.product-version }} + version: ${{ needs.set-product-version.outputs.product-version }} name: Verify ${{ matrix.arch }} debian package steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - name: Set package version run: | - echo "pkg_version=$(echo ${{ needs.get-product-version.outputs.product-version }} | sed 's/\-/~/g')" >> $GITHUB_ENV + echo "pkg_version=$(echo ${{ needs.set-product-version.outputs.product-version }} | sed 's/\-/~/g')" >> $GITHUB_ENV - name: Set package name run: | echo "pkg_name=consul_${{ env.pkg_version }}-1_${{ matrix.arch }}.deb" >> $GITHUB_ENV - name: Download workflow artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # pin@v3.0.2 with: name: ${{ env.pkg_name }} - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # pin@v2.1.0 with: platforms: all @@ -406,34 +409,34 @@ jobs: verify-linux-packages-rpm: needs: - build - - get-product-version + - set-product-version runs-on: ubuntu-latest strategy: matrix: # TODO(eculver): re-enable when there is a smaller verification container available arch: ["i386", "x86_64"] #, "armv7hl", "aarch64"] env: - version: ${{ needs.get-product-version.outputs.product-version }} + version: ${{ needs.set-product-version.outputs.product-version }} name: Verify ${{ matrix.arch }} rpm steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - name: Set package version run: | - echo "pkg_version=$(echo ${{ needs.get-product-version.outputs.product-version }} | sed 's/\-/~/g')" >> $GITHUB_ENV + echo "pkg_version=$(echo ${{ needs.set-product-version.outputs.product-version }} | sed 's/\-/~/g')" >> $GITHUB_ENV - name: Set package name run: | echo "pkg_name=consul-${{ env.pkg_version }}-1.${{ matrix.arch }}.rpm" >> $GITHUB_ENV - name: Download workflow artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # pin@v3.0.2 with: name: ${{ env.pkg_name }} - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # pin@v2.1.0 with: platforms: all diff --git a/.github/workflows/oss-merge-trigger.yml b/.github/workflows/ce-merge-trigger.yml similarity index 83% rename from .github/workflows/oss-merge-trigger.yml rename to .github/workflows/ce-merge-trigger.yml index 4d08442d90fb..3a62146631aa 100644 --- a/.github/workflows/oss-merge-trigger.yml +++ b/.github/workflows/ce-merge-trigger.yml @@ -1,4 +1,4 @@ -name: Trigger OSS to Enterprise Merge +name: Trigger Community Edition to Enterprise Merge on: pull_request_target: types: @@ -8,8 +8,8 @@ on: - 'release/*.*.x' jobs: - trigger-oss-merge: - # run this only on merge events in OSS repo + trigger-ce-merge: + # run this only on merge events in CE repo if: ${{ github.event.pull_request.merged && github.repository == 'hashicorp/consul' }} runs-on: ubuntu-latest steps: @@ -19,6 +19,7 @@ jobs: GIT_SHA: ${{ github.sha }} GH_PAT: ${{ secrets.ELEVATED_GITHUB_TOKEN }} GIT_ACTOR: ${{ github.actor }} + # TODO(spatel): CE refactor run: | curl -H "Authorization: token $GH_PAT" \ -H 'Accept: application/json' \ diff --git a/.github/workflows/changelog-checker.yml b/.github/workflows/changelog-checker.yml index c4f467a3e0b2..c81eb8a7a041 100644 --- a/.github/workflows/changelog-checker.yml +++ b/.github/workflows/changelog-checker.yml @@ -15,7 +15,7 @@ jobs: # checks that a .changelog entry is present for a PR changelog-check: # If there a `pr/no-changelog` label we ignore this check. Also, we ignore PRs created by the bot assigned to `backport-assistant` - if: "! ( contains(github.event.pull_request.labels.*.name, 'pr/no-changelog') || github.event.pull_request.user.login == 'hc-github-team-consul-core' )" + if: "! ( contains(github.event.pull_request.labels.*.name, 'pr/no-changelog') || github.event.pull_request.user.login == 'hc-github-team-consul-core' )" runs-on: ubuntu-latest steps: @@ -24,23 +24,8 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 # by default the checkout action doesn't checkout all branches - name: Check for changelog entry in diff - run: | - # check if there is a diff in the .changelog directory - # for PRs against the main branch, the changelog file name should match the PR number - if [ "${{ github.event.pull_request.base.ref }}" = "${{ github.event.repository.default_branch }}" ]; then - enforce_matching_pull_request_number="matching this PR number " - changelog_file_path=".changelog/${{ github.event.pull_request.number }}.txt" - else - changelog_file_path=".changelog/*.txt" - fi - - changelog_files=$(git --no-pager diff --name-only HEAD "$(git merge-base HEAD "origin/main")" -- ${changelog_file_path}) - - # If we do not find a file in .changelog/, we fail the check - if [ -z "$changelog_files" ]; then - # Fail status check when no .changelog entry was found on the PR - echo "Did not find a .changelog entry ${enforce_matching_pull_request_number}and the 'pr/no-changelog' label was not applied. Reference - https://github.com/hashicorp/consul/pull/8387" - exit 1 - else - echo "Found .changelog entry in PR!" - fi + run: ./.github/scripts/changelog_checker.sh + env: + GITHUB_BASE_REF: ${{ github.event.pull_request.base.ref }} + GITHUB_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + PR_NUMBER: ${{ github.event.pull_request.number }} diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml new file mode 100644 index 000000000000..defd0b22e380 --- /dev/null +++ b/.github/workflows/frontend.yml @@ -0,0 +1,144 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +name: frontend + +on: + push: + branches: + - main + - ui/** + - backport/ui/** + +permissions: + contents: read + +jobs: + setup: + name: Setup + runs-on: ubuntu-latest + outputs: + compute-small: ${{ steps.setup-outputs.outputs.compute-small }} + compute-medium: ${{ steps.setup-outputs.outputs.compute-medium }} + compute-large: ${{ steps.setup-outputs.outputs.compute-large }} + compute-xl: ${{ steps.setup-outputs.outputs.compute-xl }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + - id: setup-outputs + name: Setup outputs + run: ./.github/scripts/get_runner_classes.sh + + workspace-tests: + needs: setup + runs-on: ${{ fromJSON(needs.setup.outputs.compute-small) }} + defaults: + run: + working-directory: ui + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + + - uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # pin@v3.6.0 + with: + node-version: '16' + + - name: Install Yarn + run: npm install -g yarn + + # Install dependencies. + - name: install yarn packages + working-directory: ui + run: make deps + + - run: make test-workspace + + node-tests: + needs: setup + runs-on: ${{ fromJSON(needs.setup.outputs.compute-small) }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + + - uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # pin@v3.6.0 + with: + node-version: '16' + + - name: Install Yarn + run: npm install -g yarn + + # Install dependencies. + - name: install yarn packages + working-directory: ui + run: make deps + + - run: make test-node + working-directory: ui/packages/consul-ui + + ember-build-test: + needs: setup + runs-on: ${{ fromJSON(needs.setup.outputs.compute-large) }} + strategy: + matrix: + partition: [1, 2, 3, 4] + env: + EMBER_TEST_REPORT: test-results/report-ce.xml # outputs test report for CI test summary + EMBER_TEST_PARALLEL: true # enables test parallelization with ember-exam + CONSUL_NSPACES_ENABLED: ${{ endsWith(github.repository, '-enterprise') && 1 || 0 }} # NOTE: this should be 1 in ENT. + JOBS: 2 # limit parallelism for broccoli-babel-transpiler + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + + - uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # pin@v3.6.0 + with: + node-version: '16' + + - name: Install Yarn + run: npm install -g yarn + + - name: Install Chrome + uses: browser-actions/setup-chrome@29abc1a83d1d71557708563b4bc962d0f983a376 # pin@v1.2.1 + + - name: Install dependencies + working-directory: ui + run: make deps + + - name: Build CI + working-directory: ui/packages/consul-ui + run: make build-ci + + - name: Ember exam + working-directory: ui/packages/consul-ui + run: node_modules/.bin/ember exam --split=4 --partition=${{ matrix.partition }} --path dist --silent -r xunit + + - name: Test Coverage CI + working-directory: ui/packages/consul-ui + run: make test-coverage-ci + + # This is job is required for branch protection as a required gihub check + # because GitHub actions show up as checks at the job level and not the + # workflow level. This is currently a feature request: + # https://github.com/orgs/community/discussions/12395 + # + # This job must: + # - be placed after the fanout of a workflow so that everything fans back in + # to this job. + # - "need" any job that is part of the fan out / fan in + # - implement the if logic because we have conditional jobs + # (go-test-enteprise) that this job needs and this would potentially get + # skipped if a previous job got skipped. So we use the if clause to make + # sure it does not get skipped. + + frontend-success: + needs: + - setup + - workspace-tests + - node-tests + - ember-build-test + runs-on: ${{ fromJSON(needs.setup.outputs.compute-small) }} + if: ${{ always() }} + steps: + - name: evaluate upstream job results + run: | + # exit 1 if failure or cancelled result for any upstream job + if printf '${{ toJSON(needs) }}' | grep -E -i '\"result\": \"(failure|cancelled)\"'; then + printf "Tests failed or workflow cancelled:\n\n${{ toJSON(needs) }}" + exit 1 + fi diff --git a/.github/workflows/go-tests.yml b/.github/workflows/go-tests.yml new file mode 100644 index 000000000000..054c3f45ad23 --- /dev/null +++ b/.github/workflows/go-tests.yml @@ -0,0 +1,411 @@ +name: go-tests + +on: + pull_request: + branches-ignore: + - stable-website + - 'docs/**' + - 'ui/**' + - 'mktg-**' # Digital Team Terraform-generated branches' prefix + - 'backport/docs/**' + - 'backport/ui/**' + - 'backport/mktg-**' + push: + branches: + # Push events on the main branch + - main + - release/** + +permissions: + contents: read + +env: + TEST_RESULTS: /tmp/test-results + +# concurrency +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + setup: + name: Setup + runs-on: ubuntu-latest + outputs: + compute-small: ${{ steps.setup-outputs.outputs.compute-small }} + compute-medium: ${{ steps.setup-outputs.outputs.compute-medium }} + compute-large: ${{ steps.setup-outputs.outputs.compute-large }} + compute-xl: ${{ steps.setup-outputs.outputs.compute-xl }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + - id: setup-outputs + name: Setup outputs + run: ./.github/scripts/get_runner_classes.sh + + check-go-mod: + needs: + - setup + uses: ./.github/workflows/reusable-check-go-mod.yml + with: + runs-on: ${{ needs.setup.outputs.compute-small }} + repository-name: ${{ github.repository }} + secrets: + elevated-github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + + check-generated-protobuf: + needs: + - setup + runs-on: ${{ fromJSON(needs.setup.outputs.compute-small) }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + # NOTE: This step is specifically needed for ENT. It allows us to access the required private HashiCorp repos. + - name: Setup Git + if: ${{ endsWith(github.repository, '-enterprise') }} + run: git config --global url."https://${{ secrets.ELEVATED_GITHUB_TOKEN }}:@github.com".insteadOf "https://github.com" + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v3.5.0 + with: + go-version-file: 'go.mod' + - run: make proto-tools + name: Install protobuf + - run: make proto-format + name: "Protobuf Format" + - run: make --always-make proto + - run: | + if ! git diff --exit-code; then + echo "Generated code was not updated correctly" + exit 1 + fi + - run: make proto-lint + name: "Protobuf Lint" + - name: Notify Slack + if: ${{ failure() }} + run: .github/scripts/notify_slack.sh + check-generated-deep-copy: + needs: + - setup + runs-on: ${{ fromJSON(needs.setup.outputs.compute-large) }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + # NOTE: This step is specifically needed for ENT. It allows us to access the required private HashiCorp repos. + - name: Setup Git + if: ${{ endsWith(github.repository, '-enterprise') }} + run: git config --global url."https://${{ secrets.ELEVATED_GITHUB_TOKEN }}:@github.com".insteadOf "https://github.com" + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v3.5.0 + with: + go-version-file: 'go.mod' + - run: make codegen-tools + name: Install deep-copy + - run: make --always-make deep-copy + - run: | + if ! git diff --exit-code; then + echo "Generated code was not updated correctly" + exit 1 + fi + - name: Notify Slack + if: ${{ failure() }} + run: .github/scripts/notify_slack.sh + + lint-enums: + needs: + - setup + runs-on: ${{ fromJSON(needs.setup.outputs.compute-large) }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + # NOTE: This step is specifically needed for ENT. It allows us to access the required private HashiCorp repos. + - name: Setup Git + if: ${{ endsWith(github.repository, '-enterprise') }} + run: git config --global url."https://${{ secrets.ELEVATED_GITHUB_TOKEN }}:@github.com".insteadOf "https://github.com" + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v3.5.0 + with: + go-version-file: 'go.mod' + - run: go install github.com/reillywatson/enumcover/cmd/enumcover@master && enumcover ./... + - name: Notify Slack + if: ${{ failure() }} + run: .github/scripts/notify_slack.sh + + lint-consul-retry: + needs: + - setup + runs-on: ${{ fromJSON(needs.setup.outputs.compute-small) }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + # NOTE: This step is specifically needed for ENT. It allows us to access the required private HashiCorp repos. + - name: Setup Git + if: ${{ endsWith(github.repository, '-enterprise') }} + run: git config --global url."https://${{ secrets.ELEVATED_GITHUB_TOKEN }}:@github.com".insteadOf "https://github.com" + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v3.5.0 + with: + go-version-file: 'go.mod' + - run: go install github.com/hashicorp/lint-consul-retry@master && lint-consul-retry + - name: Notify Slack + if: ${{ failure() }} + run: .github/scripts/notify_slack.sh + + lint: + needs: + - setup + uses: ./.github/workflows/reusable-lint.yml + with: + runs-on: ${{ needs.setup.outputs.compute-large }} + repository-name: ${{ github.repository }} + secrets: + elevated-github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + + lint-32bit: + needs: + - setup + uses: ./.github/workflows/reusable-lint.yml + with: + go-arch: "386" + runs-on: ${{ needs.setup.outputs.compute-large }} + repository-name: ${{ github.repository }} + secrets: + elevated-github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + + # create a development build + dev-build: + needs: + - setup + uses: ./.github/workflows/reusable-dev-build.yml + with: + runs-on: ${{ needs.setup.outputs.compute-large }} + repository-name: ${{ github.repository }} + secrets: + elevated-github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + + # dev-build-arm64: + # # only run on enterprise because GHA does not have arm64 runners in CE + # if: ${{ endsWith(github.repository, '-enterprise') }} + # needs: + # - setup + # uses: ./.github/workflows/reusable-dev-build.yml + # with: + # uploaded-binary-name: 'consul-bin-arm64' + # runs-on: ${{ needs.setup.outputs.compute-large }} + # go-arch: "arm64" + # repository-name: ${{ github.repository }} + # secrets: + # elevated-github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + + # go-test-arm64: + # # only run on enterprise because GHA does not have arm64 runners in CE + # if: ${{ endsWith(github.repository, '-enterprise') }} + # needs: + # - setup + # - dev-build-arm64 + # uses: ./.github/workflows/reusable-unit-split.yml + # with: + # directory: . + # uploaded-binary-name: 'consul-bin-arm64' + # runner-count: 12 + # runs-on: "['self-hosted', 'ondemand', 'os=macos-arm', 'arm64']" + # go-test-flags: 'if ! [[ "$GITHUB_REF_NAME" =~ ^main$|^release/ ]]; then export GO_TEST_FLAGS="-short"; fi' + # repository-name: ${{ github.repository }} + # secrets: + # elevated-github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + # consul-license: ${{secrets.CONSUL_LICENSE}} + # datadog-api-key: "${{ !endsWith(github.repository, '-enterprise') && secrets.DATADOG_API_KEY || '' }}" + + go-test-ce: + needs: + - setup + - dev-build + uses: ./.github/workflows/reusable-unit-split.yml + with: + directory: . + runner-count: 12 + runs-on: ${{ needs.setup.outputs.compute-large }} + repository-name: ${{ github.repository }} + go-tags: "" + permissions: + id-token: write # NOTE: this permission is explicitly required for Vault auth. + contents: read + secrets: + elevated-github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + consul-license: ${{secrets.CONSUL_LICENSE}} + datadog-api-key: "${{ !endsWith(github.repository, '-enterprise') && secrets.DATADOG_API_KEY || '' }}" + + go-test-enterprise: + if: ${{ endsWith(github.repository, '-enterprise') }} + needs: + - setup + - dev-build + uses: ./.github/workflows/reusable-unit-split.yml + with: + directory: . + runner-count: 12 + runs-on: ${{ needs.setup.outputs.compute-large }} + repository-name: ${{ github.repository }} + go-tags: "${{ github.event.repository.name == 'consul-enterprise' && 'consulent consulprem consuldev' || '' }}" + permissions: + id-token: write # NOTE: this permission is explicitly required for Vault auth. + contents: read + secrets: + elevated-github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + consul-license: ${{secrets.CONSUL_LICENSE}} + datadog-api-key: "${{ !endsWith(github.repository, '-enterprise') && secrets.DATADOG_API_KEY || '' }}" + + go-test-race: + needs: + - setup + - dev-build + uses: ./.github/workflows/reusable-unit.yml + with: + directory: . + go-test-flags: 'GO_TEST_FLAGS="-race -gcflags=all=-d=checkptr=0"' + package-names-command: "go list ./... | grep -E -v '^github.com/hashicorp/consul/agent(/consul|/local|/routine-leak-checker)?$' | grep -E -v '^github.com/hashicorp/consul(/command|/connect|/snapshot)'" + runs-on: ${{ needs.setup.outputs.compute-large }} + repository-name: ${{ github.repository }} + go-tags: "${{ github.event.repository.name == 'consul-enterprise' && 'consulent consulprem consuldev' || '' }}" + permissions: + id-token: write # NOTE: this permission is explicitly required for Vault auth. + contents: read + secrets: + elevated-github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + consul-license: ${{secrets.CONSUL_LICENSE}} + datadog-api-key: "${{ !endsWith(github.repository, '-enterprise') && secrets.DATADOG_API_KEY || '' }}" + + go-test-32bit: + needs: + - setup + - dev-build + uses: ./.github/workflows/reusable-unit.yml + with: + directory: . + go-arch: "386" + go-test-flags: 'export GO_TEST_FLAGS="-short"' + runs-on: ${{ needs.setup.outputs.compute-large }} + repository-name: ${{ github.repository }} + go-tags: "${{ github.event.repository.name == 'consul-enterprise' && 'consulent consulprem consuldev' || '' }}" + permissions: + id-token: write # NOTE: this permission is explicitly required for Vault auth. + contents: read + secrets: + elevated-github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + consul-license: ${{secrets.CONSUL_LICENSE}} + datadog-api-key: "${{ !endsWith(github.repository, '-enterprise') && secrets.DATADOG_API_KEY || '' }}" + + go-test-api-1-19: + needs: + - setup + - dev-build + uses: ./.github/workflows/reusable-unit.yml + with: + directory: api + runs-on: ${{ needs.setup.outputs.compute-large }} + repository-name: ${{ github.repository }} + go-tags: "${{ github.event.repository.name == 'consul-enterprise' && 'consulent consulprem consuldev' || '' }}" + go-version: "1.19" + permissions: + id-token: write # NOTE: this permission is explicitly required for Vault auth. + contents: read + secrets: + elevated-github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + consul-license: ${{secrets.CONSUL_LICENSE}} + datadog-api-key: "${{ !endsWith(github.repository, '-enterprise') && secrets.DATADOG_API_KEY || '' }}" + + go-test-api-1-20: + needs: + - setup + - dev-build + uses: ./.github/workflows/reusable-unit.yml + with: + directory: api + runs-on: ${{ needs.setup.outputs.compute-large }} + repository-name: ${{ github.repository }} + go-tags: "${{ github.event.repository.name == 'consul-enterprise' && 'consulent consulprem consuldev' || '' }}" + go-version: "1.20" + permissions: + id-token: write # NOTE: this permission is explicitly required for Vault auth. + contents: read + secrets: + elevated-github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + consul-license: ${{secrets.CONSUL_LICENSE}} + datadog-api-key: "${{ !endsWith(github.repository, '-enterprise') && secrets.DATADOG_API_KEY || '' }}" + + go-test-sdk-1-19: + needs: + - setup + - dev-build + uses: ./.github/workflows/reusable-unit.yml + with: + directory: sdk + runs-on: ${{ needs.setup.outputs.compute-large }} + repository-name: ${{ github.repository }} + go-tags: "${{ github.event.repository.name == 'consul-enterprise' && 'consulent consulprem consuldev' || '' }}" + go-version: "1.19" + permissions: + id-token: write # NOTE: this permission is explicitly required for Vault auth. + contents: read + secrets: + elevated-github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + consul-license: ${{secrets.CONSUL_LICENSE}} + datadog-api-key: "${{ !endsWith(github.repository, '-enterprise') && secrets.DATADOG_API_KEY || '' }}" + + go-test-sdk-1-20: + needs: + - setup + - dev-build + uses: ./.github/workflows/reusable-unit.yml + with: + directory: sdk + runs-on: ${{ needs.setup.outputs.compute-large }} + repository-name: ${{ github.repository }} + go-tags: "${{ github.event.repository.name == 'consul-enterprise' && 'consulent consulprem consuldev' || '' }}" + go-version: "1.20" + permissions: + id-token: write # NOTE: this permission is explicitly required for Vault auth. + contents: read + secrets: + elevated-github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + consul-license: ${{secrets.CONSUL_LICENSE}} + datadog-api-key: "${{ !endsWith(github.repository, '-enterprise') && secrets.DATADOG_API_KEY || '' }}" + + noop: + runs-on: ubuntu-latest + steps: + - run: "echo ok" + + # This is job is required for branch protection as a required gihub check + # because GitHub actions show up as checks at the job level and not the + # workflow level. This is currently a feature request: + # https://github.com/orgs/community/discussions/12395 + # + # This job must: + # - be placed after the fanout of a workflow so that everything fans back in + # to this job. + # - "need" any job that is part of the fan out / fan in + # - implement the if logic because we have conditional jobs + # (go-test-enteprise) that this job needs and this would potentially get + # skipped if a previous job got skipped. So we use the if clause to make + # sure it does not get skipped. + + go-tests-success: + needs: + - setup + - check-generated-deep-copy + - check-generated-protobuf + - check-go-mod + - lint-consul-retry + - lint-enums + - lint + - lint-32bit + # - go-test-arm64 + - go-test-enterprise + - go-test-ce + - go-test-race + - go-test-api-1-19 + - go-test-api-1-20 + - go-test-sdk-1-19 + - go-test-sdk-1-20 + - go-test-32bit + runs-on: ${{ fromJSON(needs.setup.outputs.compute-small) }} + if: ${{ always() }} + steps: + - name: evaluate upstream job results + run: | + # exit 1 if failure or cancelled result for any upstream job + if printf '${{ toJSON(needs) }}' | grep -E -i '\"result\": \"(failure|cancelled)\"'; then + printf "Tests failed or workflow cancelled:\n\n${{ toJSON(needs) }}" + exit 1 + fi diff --git a/.github/workflows/license-checker.yml b/.github/workflows/license-checker.yml new file mode 100644 index 000000000000..747f81490e6a --- /dev/null +++ b/.github/workflows/license-checker.yml @@ -0,0 +1,27 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +# This workflow checks that the BUSL license is not mentioned anywhere in +# a PR targeting a release that should maintain the MPL-2.0 license. +name: License Checker + +on: + pull_request: + types: [opened, synchronize] + branches: + - release/1.14.* + - release/1.15.* + - release/1.16.* + +jobs: + # checks that the diff does not contain any reference to + # the BUSL license and thus retains the MPL-2.0 license + license-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 # by default the checkout action doesn't checkout all branches + - name: Check for BUSL text in diff + run: ./.github/scripts/license_checker.sh diff --git a/.github/workflows/load-test.yml b/.github/workflows/load-test.yml deleted file mode 100644 index ab7d793e7945..000000000000 --- a/.github/workflows/load-test.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: Load Test - -on: - pull_request: - branches: - - main - types: [labeled] - workflow_dispatch: {} - -jobs: - trigger-load-test: - if: ${{ github.event.label.name == 'pr/load-test' }} - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - with: - ref: ${{ github.event.pull_request.head.sha }} - - name: Trigger CircleCI Load Test Pipeline - run: | - # build json payload to trigger CircleCI Load Test Pipeline - # This only runs the load test pipeline on the 'main' branch - jsonData=$(jq --null-input -r --arg commit ${{ github.event.pull_request.head.sha }} \ - '{branch:"main", parameters: {"commit": $commit, "trigger-load-test": true}}') - echo "Passing JSON data to CircleCI API: $jsonData" - load_test_pipeline_id=$(curl -X POST \ - -H "Circle-Token: ${{ secrets.CIRCLE_TOKEN }}" \ - -H "Content-Type: application/json" \ - -d "$jsonData" \ - "https://circleci.com/api/v2/project/gh/${GITHUB_REPOSITORY}/pipeline" | jq -r '.id') - echo "LOAD_TEST_PIPELINE_ID=$load_test_pipeline_id" >> $GITHUB_ENV - - name: Post Load Test URL to PR - env: - PR_COMMENT_URL: ${{ github.event.pull_request.comments_url }} - run: | - echo "LOAD_TEST_PIPELINE_ID is: $LOAD_TEST_PIPELINE_ID" - # get load-test workflow - workflow= - # wait up to a minute for load-test workflow to start - until [ $SECONDS -ge 60 ] && exit 1; do - workflow=$(curl -s -X GET \ - -H "Circle-Token: ${{ secrets.CIRCLE_TOKEN }}" \ - -H "Content-Type: application/json" \ - "https://circleci.com/api/v2/pipeline/${LOAD_TEST_PIPELINE_ID}/workflow" | jq '.items[] | select(.name=="load-test")') - # if we found a workflow we exit - if [ -n "$workflow" ]; then - break - fi - echo -n "." - sleep 5 - done - echo "$workflow" - # get pipeline number - pipeline_number=$(echo "$workflow" | jq -r '.pipeline_number') - # get workflow id - workflow_id=$(echo "$workflow" | jq -r '.id') - # get project slug - project_slug=$(echo "$workflow" | jq -r '.project_slug') - # build load test URL - load_test_url="https://app.circleci.com/pipelines/${project_slug}/${pipeline_number}/workflows/${workflow_id}" - # comment URL to pull request - curl -X POST \ - -H "Authorization: token ${{ secrets.PR_COMMENT_TOKEN }}" \ - -H "Content-Type: application/json" \ - -d "{\"body\": \"Load Test Pipeline Started at: $load_test_url\"}" \ - "$PR_COMMENT_URL" diff --git a/.github/workflows/nightly-test-1.11.x.yaml b/.github/workflows/nightly-test-1.11.x.yaml index cd913d4eca49..e913dd0aaf59 100644 --- a/.github/workflows/nightly-test-1.11.x.yaml +++ b/.github/workflows/nightly-test-1.11.x.yaml @@ -39,7 +39,7 @@ jobs: working-directory: ./ui/packages/consul-ui run: make test-node - frontend-build-oss: + frontend-build-ce: runs-on: ubuntu-latest env: JOBS: 2 @@ -61,27 +61,27 @@ jobs: working-directory: ./ui run: make deps - - name: Ember Build OSS - id: build-oss + - name: Ember Build CE + id: build-ce working-directory: ./ui/packages/consul-ui run: make build-ci - - name: Upload OSS Frontend + - name: Upload CE Frontend uses: actions/upload-artifact@v3 with: - name: frontend-oss-${{ env.BRANCH_NAME }} + name: frontend-ce-${{ env.BRANCH_NAME }} path: ./ui/packages/consul-ui/dist if-no-files-found: error - frontend-test-oss: + frontend-test-ce: runs-on: ubuntu-latest - needs: [frontend-build-oss] + needs: [frontend-build-ce] strategy: matrix: partition: [ 1, 2, 3, 4 ] env: CONSUL_NSPACES_ENABLED: 0 - EMBER_TEST_REPORT: test-results/report-oss.xml #outputs test report for CircleCI test summary + EMBER_TEST_REPORT: test-results/report-ce.xml #outputs test report for CI test summary EMBER_TEST_PARALLEL: true #enables test parallelization with ember-exam steps: - uses: actions/checkout@v2 @@ -100,13 +100,13 @@ jobs: working-directory: ./ui run: make deps - - name: Download OSS Frontend + - name: Download CE Frontend uses: actions/download-artifact@v3 with: - name: frontend-oss-${{ env.BRANCH_NAME }} + name: frontend-ce-${{ env.BRANCH_NAME }} path: ./ui/packages/consul-ui/dist - - name: Ember Test OSS + - name: Ember Test CE id: cache working-directory: ./ui/packages/consul-ui run: node_modules/.bin/ember exam --split=$EMBER_PARTITION_TOTAL --partition=${{ matrix.partition }} --path dist --silent -r xunit @@ -134,7 +134,7 @@ jobs: run: make deps - name: Ember Build ENT - id: build-oss + id: build-ce working-directory: ./ui/packages/consul-ui run: make build-ci @@ -153,7 +153,7 @@ jobs: partition: [ 1, 2, 3, 4 ] env: CONSUL_NSPACES_ENABLED: 1 - EMBER_TEST_REPORT: test-results/report-oss.xml #outputs test report for CircleCI test summary + EMBER_TEST_REPORT: test-results/report-ce.xml #outputs test report for CI test summary EMBER_TEST_PARALLEL: true #enables test parallelization with ember-exam steps: - uses: actions/checkout@v2 @@ -215,7 +215,7 @@ jobs: slack-failure-notification: runs-on: ubuntu-latest - needs: [frontend-test-oss, frontend-test-ent] + needs: [frontend-test-ce, frontend-test-ent] if: ${{ failure() }} steps: - name: Slack Notification diff --git a/.github/workflows/nightly-test-1.12.x.yaml b/.github/workflows/nightly-test-1.12.x.yaml index 906f2ba8fb35..4d4fbde750ad 100644 --- a/.github/workflows/nightly-test-1.12.x.yaml +++ b/.github/workflows/nightly-test-1.12.x.yaml @@ -39,7 +39,7 @@ jobs: working-directory: ./ui/packages/consul-ui run: make test-node - frontend-build-oss: + frontend-build-ce: runs-on: ubuntu-latest env: JOBS: 2 @@ -61,27 +61,27 @@ jobs: working-directory: ./ui run: make deps - - name: Ember Build OSS - id: build-oss + - name: Ember Build CE + id: build-ce working-directory: ./ui/packages/consul-ui run: make build-ci - - name: Upload OSS Frontend + - name: Upload CE Frontend uses: actions/upload-artifact@v3 with: - name: frontend-oss-${{ env.BRANCH_NAME }} + name: frontend-ce-${{ env.BRANCH_NAME }} path: ./ui/packages/consul-ui/dist if-no-files-found: error - frontend-test-oss: + frontend-test-ce: runs-on: ubuntu-latest - needs: [frontend-build-oss] + needs: [frontend-build-ce] strategy: matrix: partition: [ 1, 2, 3, 4 ] env: CONSUL_NSPACES_ENABLED: 0 - EMBER_TEST_REPORT: test-results/report-oss.xml #outputs test report for CircleCI test summary + EMBER_TEST_REPORT: test-results/report-ce.xml #outputs test report for CI test summary EMBER_TEST_PARALLEL: true #enables test parallelization with ember-exam steps: - uses: actions/checkout@v2 @@ -100,13 +100,13 @@ jobs: working-directory: ./ui run: make deps - - name: Download OSS Frontend + - name: Download CE Frontend uses: actions/download-artifact@v3 with: - name: frontend-oss-${{ env.BRANCH_NAME }} + name: frontend-ce-${{ env.BRANCH_NAME }} path: ./ui/packages/consul-ui/dist - - name: Ember Test OSS + - name: Ember Test CE id: cache working-directory: ./ui/packages/consul-ui run: node_modules/.bin/ember exam --split=$EMBER_PARTITION_TOTAL --partition=${{ matrix.partition }} --path dist --silent -r xunit @@ -134,7 +134,7 @@ jobs: run: make deps - name: Ember Build ENT - id: build-oss + id: build-ce working-directory: ./ui/packages/consul-ui run: make build-ci @@ -153,7 +153,7 @@ jobs: partition: [ 1, 2, 3, 4 ] env: CONSUL_NSPACES_ENABLED: 1 - EMBER_TEST_REPORT: test-results/report-oss.xml #outputs test report for CircleCI test summary + EMBER_TEST_REPORT: test-results/report-ce.xml #outputs test report for CI test summary EMBER_TEST_PARALLEL: true #enables test parallelization with ember-exam steps: - uses: actions/checkout@v2 @@ -215,7 +215,7 @@ jobs: slack-failure-notification: runs-on: ubuntu-latest - needs: [frontend-test-oss, frontend-test-ent] + needs: [frontend-test-ce, frontend-test-ent] if: ${{ failure() }} steps: - name: Slack Notification diff --git a/.github/workflows/nightly-test-1.13.x.yaml b/.github/workflows/nightly-test-1.13.x.yaml index 2df70ff68807..c1e9d035be05 100644 --- a/.github/workflows/nightly-test-1.13.x.yaml +++ b/.github/workflows/nightly-test-1.13.x.yaml @@ -39,7 +39,7 @@ jobs: working-directory: ./ui/packages/consul-ui run: make test-node - frontend-build-oss: + frontend-build-ce: runs-on: ubuntu-latest env: JOBS: 2 @@ -61,27 +61,27 @@ jobs: working-directory: ./ui run: make deps - - name: Ember Build OSS - id: build-oss + - name: Ember Build CE + id: build-ce working-directory: ./ui/packages/consul-ui run: make build-ci - - name: Upload OSS Frontend + - name: Upload CE Frontend uses: actions/upload-artifact@v3 with: - name: frontend-oss-${{ env.BRANCH_NAME }} + name: frontend-ce-${{ env.BRANCH_NAME }} path: ./ui/packages/consul-ui/dist if-no-files-found: error - frontend-test-oss: + frontend-test-ce: runs-on: ubuntu-latest - needs: [frontend-build-oss] + needs: [frontend-build-ce] strategy: matrix: partition: [ 1, 2, 3, 4 ] env: CONSUL_NSPACES_ENABLED: 0 - EMBER_TEST_REPORT: test-results/report-oss.xml #outputs test report for CircleCI test summary + EMBER_TEST_REPORT: test-results/report-ce.xml #outputs test report for CI test summary EMBER_TEST_PARALLEL: true #enables test parallelization with ember-exam steps: - uses: actions/checkout@v2 @@ -100,13 +100,13 @@ jobs: working-directory: ./ui run: make deps - - name: Download OSS Frontend + - name: Download CE Frontend uses: actions/download-artifact@v3 with: - name: frontend-oss-${{ env.BRANCH_NAME }} + name: frontend-ce-${{ env.BRANCH_NAME }} path: ./ui/packages/consul-ui/dist - - name: Ember Test OSS + - name: Ember Test CE id: cache working-directory: ./ui/packages/consul-ui run: node_modules/.bin/ember exam --split=$EMBER_PARTITION_TOTAL --partition=${{ matrix.partition }} --path dist --silent -r xunit @@ -134,7 +134,7 @@ jobs: run: make deps - name: Ember Build ENT - id: build-oss + id: build-ce working-directory: ./ui/packages/consul-ui run: make build-ci @@ -153,7 +153,7 @@ jobs: partition: [ 1, 2, 3, 4 ] env: CONSUL_NSPACES_ENABLED: 1 - EMBER_TEST_REPORT: test-results/report-oss.xml #outputs test report for CircleCI test summary + EMBER_TEST_REPORT: test-results/report-ce.xml #outputs test report for CI test summary EMBER_TEST_PARALLEL: true #enables test parallelization with ember-exam steps: - uses: actions/checkout@v2 @@ -215,7 +215,7 @@ jobs: slack-failure-notification: runs-on: ubuntu-latest - needs: [frontend-test-oss, frontend-test-ent] + needs: [frontend-test-ce, frontend-test-ent] if: ${{ failure() }} steps: - name: Slack Notification diff --git a/.github/workflows/nightly-test-main.yaml b/.github/workflows/nightly-test-main.yaml index e823bac7b562..33b2a8b62216 100644 --- a/.github/workflows/nightly-test-main.yaml +++ b/.github/workflows/nightly-test-main.yaml @@ -39,7 +39,7 @@ jobs: working-directory: ./ui/packages/consul-ui run: make test-node - frontend-build-oss: + frontend-build-ce: runs-on: ubuntu-latest env: JOBS: 2 @@ -61,27 +61,27 @@ jobs: working-directory: ./ui run: make deps - - name: Ember Build OSS - id: build-oss + - name: Ember Build CE + id: build-ce working-directory: ./ui/packages/consul-ui run: make build-ci - - name: Upload OSS Frontend + - name: Upload CE Frontend uses: actions/upload-artifact@v3 with: - name: frontend-oss-${{ env.BRANCH_NAME }} + name: frontend-ce-${{ env.BRANCH_NAME }} path: ./ui/packages/consul-ui/dist if-no-files-found: error - frontend-test-oss: + frontend-test-ce: runs-on: ubuntu-latest - needs: [frontend-build-oss] + needs: [frontend-build-ce] strategy: matrix: partition: [ 1, 2, 3, 4 ] env: CONSUL_NSPACES_ENABLED: 0 - EMBER_TEST_REPORT: test-results/report-oss.xml #outputs test report for CircleCI test summary + EMBER_TEST_REPORT: test-results/report-ce.xml #outputs test report for CI test summary EMBER_TEST_PARALLEL: true #enables test parallelization with ember-exam steps: - uses: actions/checkout@v2 @@ -100,13 +100,13 @@ jobs: working-directory: ./ui run: make deps - - name: Download OSS Frontend + - name: Download CE Frontend uses: actions/download-artifact@v3 with: - name: frontend-oss-${{ env.BRANCH_NAME }} + name: frontend-ce-${{ env.BRANCH_NAME }} path: ./ui/packages/consul-ui/dist - - name: Ember Test OSS + - name: Ember Test CE id: cache working-directory: ./ui/packages/consul-ui run: node_modules/.bin/ember exam --split=$EMBER_PARTITION_TOTAL --partition=${{ matrix.partition }} --path dist --silent -r xunit @@ -134,7 +134,7 @@ jobs: run: make deps - name: Ember Build ENT - id: build-oss + id: build-ce working-directory: ./ui/packages/consul-ui run: make build-ci @@ -153,7 +153,7 @@ jobs: partition: [ 1, 2, 3, 4 ] env: CONSUL_NSPACES_ENABLED: 1 - EMBER_TEST_REPORT: test-results/report-oss.xml #outputs test report for CircleCI test summary + EMBER_TEST_REPORT: test-results/report-ce.xml #outputs test report for CI test summary EMBER_TEST_PARALLEL: true #enables test parallelization with ember-exam steps: - uses: actions/checkout@v2 @@ -215,7 +215,7 @@ jobs: slack-failure-notification: runs-on: ubuntu-latest - needs: [frontend-test-oss, frontend-test-ent] + needs: [frontend-test-ce, frontend-test-ent] if: ${{ failure() }} steps: - name: Slack Notification diff --git a/.github/workflows/reusable-check-go-mod.yml b/.github/workflows/reusable-check-go-mod.yml new file mode 100644 index 000000000000..2078b0c3217d --- /dev/null +++ b/.github/workflows/reusable-check-go-mod.yml @@ -0,0 +1,38 @@ +name: check-go-mod + +on: + workflow_call: + inputs: + runs-on: + description: An expression indicating which kind of runners to use. + required: true + type: string + repository-name: + required: true + type: string + secrets: + elevated-github-token: + required: true +jobs: + check-go-mod: + runs-on: ${{ fromJSON(inputs.runs-on) }} + + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + # NOTE: This step is specifically needed for ENT. It allows us to access the required private HashiCorp repos. + - name: Setup Git + if: ${{ endsWith(inputs.repository-name, '-enterprise') }} + run: git config --global url."https://${{ secrets.elevated-github-token }}:@github.com".insteadOf "https://github.com" + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v3.5.0 + with: + go-version-file: 'go.mod' + - run: go mod tidy + - run: | + if [[ -n $(git status -s) ]]; then + echo "Git directory has changes" + git status -s + exit 1 + fi + - name: Notify Slack + if: ${{ failure() }} + run: .github/scripts/notify_slack.sh diff --git a/.github/workflows/reusable-dev-build.yml b/.github/workflows/reusable-dev-build.yml new file mode 100644 index 000000000000..ba28b1227588 --- /dev/null +++ b/.github/workflows/reusable-dev-build.yml @@ -0,0 +1,47 @@ +name: reusable-dev-build + +on: + workflow_call: + inputs: + uploaded-binary-name: + required: false + type: string + default: "consul-bin" + runs-on: + description: An expression indicating which kind of runners to use. + required: true + type: string + repository-name: + required: true + type: string + go-arch: + required: false + type: string + default: "" + secrets: + elevated-github-token: + required: true +jobs: + build: + runs-on: ${{ fromJSON(inputs.runs-on) }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + # NOTE: This step is specifically needed for ENT. It allows us to access the required private HashiCorp repos. + - name: Setup Git + if: ${{ endsWith(inputs.repository-name, '-enterprise') }} + run: git config --global url."https://${{ secrets.elevated-github-token }}:@github.com".insteadOf "https://github.com" + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v3.5.0 + with: + go-version-file: 'go.mod' + - name: Build + env: + GOARCH: ${{ inputs.goarch }} + run: make dev + # save dev build to pass to downstream jobs + - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # pin@v3.1.2 + with: + name: ${{inputs.uploaded-binary-name}} + path: ./bin/consul + - name: Notify Slack + if: ${{ failure() }} + run: .github/scripts/notify_slack.sh diff --git a/.github/workflows/reusable-lint.yml b/.github/workflows/reusable-lint.yml new file mode 100644 index 000000000000..3cee2abd7a66 --- /dev/null +++ b/.github/workflows/reusable-lint.yml @@ -0,0 +1,53 @@ +name: reusable-lint + +on: + workflow_call: + inputs: + go-arch: + required: false + type: string + default: "" + runs-on: + description: An expression indicating which kind of runners to use. + required: true + type: string + repository-name: + required: true + type: string + secrets: + elevated-github-token: + required: true +env: + GOTAGS: "${{ github.event.repository.name == 'consul-enterprise' && 'consulent consulprem consuldev' || '' }}" + GOARCH: ${{inputs.go-arch}} + +jobs: + lint: + runs-on: ${{ fromJSON(inputs.runs-on) }} + strategy: + matrix: + directory: + - "" + - "api" + - "sdk" + fail-fast: true + name: lint ${{ matrix.directory }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + # NOTE: This step is specifically needed for ENT. It allows us to access the required private HashiCorp repos. + - name: Setup Git + if: ${{ endsWith(inputs.repository-name, '-enterprise') }} + run: git config --global url."https://${{ secrets.elevated-github-token }}:@github.com".insteadOf "https://github.com" + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v3.5.0 + with: + go-version-file: 'go.mod' + - run: go env + - name: lint-${{ matrix.directory }} + uses: golangci/golangci-lint-action@08e2f20817b15149a52b5b3ebe7de50aff2ba8c5 # pin@v3.4.0 + with: + working-directory: ${{ matrix.directory }} + version: v1.51.1 + args: --build-tags="${{ env.GOTAGS }}" -v + - name: Notify Slack + if: ${{ failure() }} + run: .github/scripts/notify_slack.sh diff --git a/.github/workflows/reusable-unit-split.yml b/.github/workflows/reusable-unit-split.yml new file mode 100644 index 000000000000..6c13670e742e --- /dev/null +++ b/.github/workflows/reusable-unit-split.yml @@ -0,0 +1,179 @@ +name: reusable-unit-split + +on: + workflow_call: + inputs: + directory: + required: true + type: string + runs-on: + description: An expression indicating which kind of runners to use. + required: true + type: string + go-arch: + required: false + type: string + default: "" + uploaded-binary-name: + required: false + type: string + default: "consul-bin" + args: + required: false + type: string + default: "" + runner-count: + required: false + type: number + default: 1 + go-test-flags: + required: false + type: string + default: "" + repository-name: + required: true + type: string + go-tags: + required: false + type: string + default: "" + secrets: + elevated-github-token: + required: true + consul-license: + required: true + datadog-api-key: + required: true +env: + TEST_RESULTS: /tmp/test-results + GOTESTSUM_VERSION: "1.10.1" + GOARCH: ${{inputs.go-arch}} + TOTAL_RUNNERS: ${{inputs.runner-count}} + CONSUL_LICENSE: ${{secrets.consul-license}} + GOTAGS: ${{ inputs.go-tags}} + DATADOG_API_KEY: ${{secrets.datadog-api-key}} + +jobs: + set-test-package-matrix: + runs-on: ubuntu-latest + outputs: + package-matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v3.5.0 + with: + go-version-file: 'go.mod' + - id: set-matrix + run: ./.github/scripts/set_test_package_matrix.sh ${{env.TOTAL_RUNNERS}} + + go-test: + runs-on: ${{ fromJSON(inputs.runs-on) }} + name: "go-test" + needs: + - set-test-package-matrix + strategy: + fail-fast: false + matrix: + package: ${{ fromJson(needs.set-test-package-matrix.outputs.package-matrix) }} + steps: + - name: ulimit + run: | + echo "Soft limits" + ulimit -Sa + echo "Hard limits" + ulimit -Ha + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + # NOTE: This step is specifically needed for ENT. It allows us to access the required private HashiCorp repos. + - name: Setup Git + if: ${{ endsWith(inputs.repository-name, '-enterprise') }} + run: git config --global url."https://${{ secrets.elevated-github-token }}:@github.com".insteadOf "https://github.com" + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v3.5.0 + with: + go-version-file: 'go.mod' + cache: true + - run: mkdir -p ${{env.TEST_RESULTS}} + - name: go mod download + working-directory: ${{inputs.directory}} + run: go mod download + - name: Download consul + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # pin@v3.0.2 + with: + name: ${{inputs.uploaded-binary-name}} + path: ${{inputs.directory}} + - name: Display downloaded file + run: ls -ld consul + working-directory: ${{inputs.directory}} + - run: echo "$GITHUB_WORKSPACE/${{inputs.directory}}" >> $GITHUB_PATH + - name: Make sure consul is executable + run: chmod +x $GITHUB_WORKSPACE/${{inputs.directory}}/consul + - run: go env + - name: Run tests + working-directory: ${{inputs.directory}} + run: | + # separate the list + PACKAGE_NAMES="${{ join(matrix.package, ' ') }}" + # PACKAGE_NAMES="${{ matrix.package }}" + + ${{inputs.go-test-flags}} + + # some tests expect this umask, and arm images have a different default + umask 0022 + + go run gotest.tools/gotestsum@v${{env.GOTESTSUM_VERSION}} \ + --format=short-verbose \ + --jsonfile /tmp/jsonfile/go-test.log \ + --debug \ + --rerun-fails=3 \ + --rerun-fails-max-failures=40 \ + --rerun-fails-report=/tmp/gotestsum-rerun-fails \ + --packages="$PACKAGE_NAMES" \ + --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- \ + -tags="${{env.GOTAGS}}" -p 2 \ + ${GO_TEST_FLAGS-} \ + -cover -coverprofile=coverage.txt + + # NOTE: ENT specific step as we store secrets in Vault. + - name: Authenticate to Vault + if: ${{ endsWith(github.repository, '-enterprise') }} + id: vault-auth + run: vault-auth + + # NOTE: ENT specific step as we store secrets in Vault. + - name: Fetch Secrets + if: ${{ endsWith(github.repository, '-enterprise') }} + id: secrets + uses: hashicorp/vault-action@v2.5.0 + with: + url: ${{ steps.vault-auth.outputs.addr }} + caCertificate: ${{ steps.vault-auth.outputs.ca_certificate }} + token: ${{ steps.vault-auth.outputs.token }} + secrets: | + kv/data/github/${{ github.repository }}/datadog apikey | DATADOG_API_KEY; + + - name: prepare datadog-ci + if: ${{ !endsWith(github.repository, '-enterprise') }} + run: | + curl -L --fail "https://github.com/DataDog/datadog-ci/releases/latest/download/datadog-ci_linux-x64" --output "/usr/local/bin/datadog-ci" + chmod +x /usr/local/bin/datadog-ci + + - name: upload coverage + # do not run on forks + if: ${{ env.DATADOG_API_KEY}} + env: + DD_ENV: ci + run: datadog-ci junit upload --service "$GITHUB_REPOSITORY" ${{env.TEST_RESULTS}}/gotestsum-report.xml + + - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # pin@v3.1.2 + with: + name: test-results + path: ${{env.TEST_RESULTS}} + - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # pin@v3.1.2 + with: + name: jsonfile + path: /tmp/jsonfile + - name: "Re-run fails report" + run: | + .github/scripts/rerun_fails_report.sh /tmp/gotestsum-rerun-fails + - name: Notify Slack + if: ${{ failure() }} + run: .github/scripts/notify_slack.sh diff --git a/.github/workflows/reusable-unit.yml b/.github/workflows/reusable-unit.yml new file mode 100644 index 000000000000..c49a6291fa2e --- /dev/null +++ b/.github/workflows/reusable-unit.yml @@ -0,0 +1,157 @@ +name: reusable-unit + +on: + workflow_call: + inputs: + directory: + required: true + type: string + runs-on: + description: An expression indicating which kind of runners to use. + required: true + type: string + go-arch: + required: false + type: string + default: "" + uploaded-binary-name: + required: false + type: string + default: "consul-bin" + package-names-command: + required: false + type: string + default: 'go list -tags "$GOTAGS" ./...' + go-test-flags: + required: false + type: string + default: "" + repository-name: + required: true + type: string + go-tags: + required: false + type: string + default: "" + go-version: + required: false + type: string + default: "" + secrets: + elevated-github-token: + required: true + consul-license: + required: true + datadog-api-key: + required: true +env: + TEST_RESULTS: /tmp/test-results + GOTESTSUM_VERSION: "1.10.1" + GOARCH: ${{inputs.go-arch}} + CONSUL_LICENSE: ${{secrets.consul-license}} + GOTAGS: ${{ inputs.go-tags}} + DATADOG_API_KEY: ${{secrets.datadog-api-key}} + +jobs: + go-test: + runs-on: ${{ fromJSON(inputs.runs-on) }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + # NOTE: This step is specifically needed for ENT. It allows us to access the required private HashiCorp repos. + - name: Setup Git + if: ${{ endsWith(inputs.repository-name, '-enterprise') }} + run: git config --global url."https://${{ secrets.elevated-github-token }}:@github.com".insteadOf "https://github.com" + - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1 + if: ${{ inputs.go-version != '' }} + with: + go-version: ${{ inputs.go-version }} + cache: true + - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1 + if: ${{ inputs.go-version == '' }} + with: + go-version-file: 'go.mod' + cache: true + - run: mkdir -p ${{env.TEST_RESULTS}} + - name: go mod download + working-directory: ${{inputs.directory}} + run: go mod download + - name: Download consul + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # pin@v3.0.2 + with: + name: ${{inputs.uploaded-binary-name}} + path: ${{inputs.directory}} + - name: Display downloaded file + run: ls -ld consul + working-directory: ${{inputs.directory}} + - run: echo "$GITHUB_WORKSPACE/${{inputs.directory}}" >> $GITHUB_PATH + - name: Make sure consul is executable + run: chmod +x $GITHUB_WORKSPACE/${{inputs.directory}}/consul + - run: go env + - name: Run tests + working-directory: ${{inputs.directory}} + run: | + PACKAGE_NAMES=$(${{inputs.package-names-command}}) + + # some tests expect this umask, and arm images have a different default + umask 0022 + + ${{inputs.go-test-flags}} + + go run gotest.tools/gotestsum@v${{env.GOTESTSUM_VERSION}} \ + --format=short-verbose \ + --jsonfile /tmp/jsonfile/go-test.log \ + --debug \ + --rerun-fails=3 \ + --rerun-fails-max-failures=40 \ + --rerun-fails-report=/tmp/gotestsum-rerun-fails \ + --packages="$PACKAGE_NAMES" \ + --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- \ + -tags="${{env.GOTAGS}}" \ + ${GO_TEST_FLAGS-} \ + -cover -coverprofile=coverage.txt + + # NOTE: ENT specific step as we store secrets in Vault. + - name: Authenticate to Vault + if: ${{ endsWith(github.repository, '-enterprise') }} + id: vault-auth + run: vault-auth + + # NOTE: ENT specific step as we store secrets in Vault. + - name: Fetch Secrets + if: ${{ endsWith(github.repository, '-enterprise') }} + id: secrets + uses: hashicorp/vault-action@v2.5.0 + with: + url: ${{ steps.vault-auth.outputs.addr }} + caCertificate: ${{ steps.vault-auth.outputs.ca_certificate }} + token: ${{ steps.vault-auth.outputs.token }} + secrets: | + kv/data/github/${{ github.repository }}/datadog apikey | DATADOG_API_KEY; + + - name: prepare datadog-ci + if: ${{ !endsWith(github.repository, '-enterprise') }} + run: | + curl -L --fail "https://github.com/DataDog/datadog-ci/releases/latest/download/datadog-ci_linux-x64" --output "/usr/local/bin/datadog-ci" + chmod +x /usr/local/bin/datadog-ci + + - name: upload coverage + # do not run on forks + if: ${{ env.DATADOG_API_KEY}} + env: + DD_ENV: ci + run: datadog-ci junit upload --service "$GITHUB_REPOSITORY" ${{env.TEST_RESULTS}}/gotestsum-report.xml + + - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # pin@v3.1.2 + with: + name: test-results + path: ${{env.TEST_RESULTS}} + - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # pin@v3.1.2 + with: + name: jsonfile + path: /tmp/jsonfile + - name: "Re-run fails report" + run: | + .github/scripts/rerun_fails_report.sh /tmp/gotestsum-rerun-fails + - name: Notify Slack + if: ${{ failure() }} + run: .github/scripts/notify_slack.sh diff --git a/.github/workflows/test-integrations.yml b/.github/workflows/test-integrations.yml new file mode 100644 index 000000000000..c6d8b9f9833d --- /dev/null +++ b/.github/workflows/test-integrations.yml @@ -0,0 +1,580 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +name: test-integrations + +on: + pull_request: + branches-ignore: + - stable-website + - 'docs/**' + - 'ui/**' + - 'mktg-**' # Digital Team Terraform-generated branch prefix + - 'backport/docs/**' + - 'backport/ui/**' + - 'backport/mktg-**' + +env: + TEST_RESULTS_DIR: /tmp/test-results + TEST_RESULTS_ARTIFACT_NAME: test-results + CONSUL_LICENSE: ${{ secrets.CONSUL_LICENSE }} + GOTAGS: ${{ endsWith(github.repository, '-enterprise') && 'consulent' || '' }} + GOTESTSUM_VERSION: "1.10.1" + CONSUL_BINARY_UPLOAD_NAME: consul-bin + # strip the hashicorp/ off the front of github.repository for consul + CONSUL_LATEST_IMAGE_NAME: ${{ github.repository }} + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + setup: + runs-on: ubuntu-latest + name: Setup + outputs: + compute-small: ${{ steps.runners.outputs.compute-small }} + compute-medium: ${{ steps.runners.outputs.compute-medium }} + compute-large: ${{ steps.runners.outputs.compute-large }} + compute-xl: ${{ steps.runners.outputs.compute-xl }} + enterprise: ${{ steps.runners.outputs.enterprise }} + steps: + - uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0 + - id: runners + run: .github/scripts/get_runner_classes.sh + + dev-build: + needs: [setup] + uses: ./.github/workflows/reusable-dev-build.yml + with: + runs-on: ${{ needs.setup.outputs.compute-large }} + repository-name: ${{ github.repository }} + uploaded-binary-name: 'consul-bin' + secrets: + elevated-github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + + nomad-integration-test: + runs-on: ${{ fromJSON(needs.setup.outputs.compute-large) }} + needs: + - setup + - dev-build + permissions: + id-token: write # NOTE: this permission is explicitly required for Vault auth. + contents: read + strategy: + matrix: + nomad-version: ['v1.3.3', 'v1.2.10', 'v1.1.16'] + steps: + - name: Checkout Nomad + uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0 + with: + repository: hashicorp/nomad + ref: ${{ matrix.nomad-version }} + + - name: Install Go + uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + with: + go-version-file: 'go.mod' + + - name: Fetch Consul binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: '${{ env.CONSUL_BINARY_UPLOAD_NAME }}' + path: ./bin + - name: Restore Consul permissions + run: | + chmod +x ./bin/consul + echo "$(pwd)/bin" >> $GITHUB_PATH + + - name: Make Nomad dev build + run: make pkg/linux_amd64/nomad + + - name: Run integration tests + run: | + go install gotest.tools/gotestsum@v${{env.GOTESTSUM_VERSION}} && \ + gotestsum \ + --format=short-verbose \ + --rerun-fails \ + --rerun-fails-report=/tmp/gotestsum-rerun-fails \ + --packages="./command/agent/consul" \ + --junitfile $TEST_RESULTS_DIR/results.xml -- \ + -run TestConsul + + # NOTE: ENT specific step as we store secrets in Vault. + - name: Authenticate to Vault + if: ${{ endsWith(github.repository, '-enterprise') }} + id: vault-auth + run: vault-auth + + # NOTE: ENT specific step as we store secrets in Vault. + - name: Fetch Secrets + if: ${{ endsWith(github.repository, '-enterprise') }} + id: secrets + uses: hashicorp/vault-action@v2.5.0 + with: + url: ${{ steps.vault-auth.outputs.addr }} + caCertificate: ${{ steps.vault-auth.outputs.ca_certificate }} + token: ${{ steps.vault-auth.outputs.token }} + secrets: | + kv/data/github/${{ github.repository }}/datadog apikey | DATADOG_API_KEY; + + - name: prepare datadog-ci + if: ${{ !endsWith(github.repository, '-enterprise') }} + run: | + curl -L --fail "https://github.com/DataDog/datadog-ci/releases/latest/download/datadog-ci_linux-x64" --output "/usr/local/bin/datadog-ci" + chmod +x /usr/local/bin/datadog-ci + + - name: upload coverage + # do not run on forks + if: github.event.pull_request.head.repo.full_name == github.repository + env: + DATADOG_API_KEY: "${{ endsWith(github.repository, '-enterprise') && env.DATADOG_API_KEY || secrets.DATADOG_API_KEY }}" + DD_ENV: ci + run: datadog-ci junit upload --service "$GITHUB_REPOSITORY" $TEST_RESULTS_DIR/results.xml + + vault-integration-test: + runs-on: ${{ fromJSON(needs.setup.outputs.compute-large) }} + needs: + - setup + - dev-build + permissions: + id-token: write # NOTE: this permission is explicitly required for Vault auth. + contents: read + strategy: + matrix: + vault-version: ["1.13.1", "1.12.5", "1.11.9", "1.10.11"] + env: + VAULT_BINARY_VERSION: ${{ matrix.vault-version }} + steps: + - uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0 + + # NOTE: This step is specifically needed for ENT. It allows us to access the required private HashiCorp repos. + - name: Setup Git + if: ${{ endsWith(github.repository, '-enterprise') }} + run: git config --global url."https://${{ secrets.ELEVATED_GITHUB_TOKEN }}:@github.com".insteadOf "https://github.com" + + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + with: + go-version-file: 'go.mod' + + - name: Install Vault + run: | + wget -q -O /tmp/vault.zip "https://releases.hashicorp.com/vault/${{ env.VAULT_BINARY_VERSION }}/vault_${{ env.VAULT_BINARY_VERSION }}_linux_amd64.zip" + unzip -d /tmp /tmp/vault.zip + echo "/tmp" >> $GITHUB_PATH + + - name: Run Connect CA Provider Tests + run: | + mkdir -p "${{ env.TEST_RESULTS_DIR }}" + go run gotest.tools/gotestsum@v${{env.GOTESTSUM_VERSION}} \ + --format=short-verbose \ + --junitfile "${{ env.TEST_RESULTS_DIR }}/gotestsum-report.xml" \ + -- -tags "${{ env.GOTAGS }}" -cover -coverprofile=coverage.txt ./agent/connect/ca + # Run leader tests that require Vault + go run gotest.tools/gotestsum@v${{env.GOTESTSUM_VERSION}} \ + --format=short-verbose \ + --junitfile "${{ env.TEST_RESULTS_DIR }}/gotestsum-report-leader.xml" \ + -- -tags "${{ env.GOTAGS }}" -cover -coverprofile=coverage-leader.txt -run Vault ./agent/consul + # Run agent tests that require Vault + go run gotest.tools/gotestsum@v${{env.GOTESTSUM_VERSION}} \ + --format=short-verbose \ + --junitfile "${{ env.TEST_RESULTS_DIR }}/gotestsum-report-agent.xml" \ + -- -tags "${{ env.GOTAGS }}" -cover -coverprofile=coverage-agent.txt -run Vault ./agent + + # NOTE: ENT specific step as we store secrets in Vault. + - name: Authenticate to Vault + if: ${{ endsWith(github.repository, '-enterprise') }} + id: vault-auth + run: vault-auth + + # NOTE: ENT specific step as we store secrets in Vault. + - name: Fetch Secrets + if: ${{ endsWith(github.repository, '-enterprise') }} + id: secrets + uses: hashicorp/vault-action@v2.5.0 + with: + url: ${{ steps.vault-auth.outputs.addr }} + caCertificate: ${{ steps.vault-auth.outputs.ca_certificate }} + token: ${{ steps.vault-auth.outputs.token }} + secrets: | + kv/data/github/${{ github.repository }}/datadog apikey | DATADOG_API_KEY; + + - name: prepare datadog-ci + if: ${{ !endsWith(github.repository, '-enterprise') }} + run: | + curl -L --fail "https://github.com/DataDog/datadog-ci/releases/latest/download/datadog-ci_linux-x64" --output "/usr/local/bin/datadog-ci" + chmod +x /usr/local/bin/datadog-ci + + - name: upload coverage + # do not run on forks + if: github.event.pull_request.head.repo.full_name == github.repository + env: + DATADOG_API_KEY: "${{ endsWith(github.repository, '-enterprise') && env.DATADOG_API_KEY || secrets.DATADOG_API_KEY }}" + DD_ENV: ci + run: datadog-ci junit upload --service "$GITHUB_REPOSITORY" "${{ env.TEST_RESULTS_DIR }}/gotestsum-report.xml" + + - name: upload leader coverage + # do not run on forks + if: github.event.pull_request.head.repo.full_name == github.repository + env: + DATADOG_API_KEY: "${{ endsWith(github.repository, '-enterprise') && env.DATADOG_API_KEY || secrets.DATADOG_API_KEY }}" + DD_ENV: ci + run: datadog-ci junit upload --service "$GITHUB_REPOSITORY" "${{ env.TEST_RESULTS_DIR }}/gotestsum-report-leader.xml" + + - name: upload agent coverage + # do not run on forks + if: github.event.pull_request.head.repo.full_name == github.repository + env: + DATADOG_API_KEY: "${{ endsWith(github.repository, '-enterprise') && env.DATADOG_API_KEY || secrets.DATADOG_API_KEY }}" + DD_ENV: ci + run: datadog-ci junit upload --service "$GITHUB_REPOSITORY" "${{ env.TEST_RESULTS_DIR }}/gotestsum-report-agent.xml" + + generate-envoy-job-matrices: + needs: [setup] + runs-on: ${{ fromJSON(needs.setup.outputs.compute-small) }} + name: Generate Envoy Job Matrices + outputs: + envoy-matrix: ${{ steps.set-matrix.outputs.envoy-matrix }} + steps: + - uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0 + - name: Generate Envoy Job Matrix + id: set-matrix + env: + # this is further going to multiplied in envoy-integration tests by the + # other dimensions in the matrix. Currently TOTAL_RUNNERS would be + # multiplied by 8 based on these values: + # envoy-version: ["1.21.6", "1.22.11", "1.23.12", "1.24.10"] + # xds-target: ["server", "client"] + TOTAL_RUNNERS: 4 + JQ_SLICER: '[ inputs ] | [_nwise(length / $runnercount | floor)]' + run: | + NUM_RUNNERS=$TOTAL_RUNNERS + NUM_DIRS=$(find ./test/integration/connect/envoy -mindepth 1 -maxdepth 1 -type d | wc -l) + + if [ "$NUM_DIRS" -lt "$NUM_RUNNERS" ]; then + echo "TOTAL_RUNNERS is larger than the number of tests/packages to split." + NUM_RUNNERS=$((NUM_DIRS-1)) + fi + # fix issue where test splitting calculation generates 1 more split than TOTAL_RUNNERS. + NUM_RUNNERS=$((NUM_RUNNERS-1)) + { + echo -n "envoy-matrix=" + find ./test/integration/connect/envoy -maxdepth 1 -type d -print0 \ + | xargs -0 -n 1 basename \ + | jq --raw-input --argjson runnercount "$NUM_RUNNERS" "$JQ_SLICER" \ + | jq --compact-output 'map(join("|"))' + } >> "$GITHUB_OUTPUT" + + envoy-integration-test: + runs-on: ${{ fromJSON(needs.setup.outputs.compute-large) }} + needs: + - setup + - generate-envoy-job-matrices + - dev-build + permissions: + id-token: write # NOTE: this permission is explicitly required for Vault auth. + contents: read + strategy: + fail-fast: false + matrix: + envoy-version: ["1.21.6", "1.22.11", "1.23.12", "1.24.10"] + xds-target: ["server", "client"] + test-cases: ${{ fromJSON(needs.generate-envoy-job-matrices.outputs.envoy-matrix) }} + env: + ENVOY_VERSION: ${{ matrix.envoy-version }} + XDS_TARGET: ${{ matrix.xds-target }} + AWS_LAMBDA_REGION: us-west-2 + steps: + - uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0 + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + with: + go-version-file: 'go.mod' + + - name: fetch binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: '${{ env.CONSUL_BINARY_UPLOAD_NAME }}' + path: ./bin + - name: restore mode+x + run: chmod +x ./bin/consul + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@f03ac48505955848960e80bbb68046aa35c7b9e7 # v2.4.1 + + - name: Docker build + run: docker build -t consul:local -f ./build-support/docker/Consul-Dev.dockerfile ./bin + + - name: Envoy Integration Tests + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running $(sed 's,|, ,g' <<< "${{ matrix.test-cases }}" |wc -w) subtests" + # shellcheck disable=SC2001 + sed 's,|,\n,g' <<< "${{ matrix.test-cases }}" + go run gotest.tools/gotestsum@v${{env.GOTESTSUM_VERSION}} \ + --debug \ + --rerun-fails \ + --rerun-fails-report=/tmp/gotestsum-rerun-fails \ + --jsonfile /tmp/jsonfile/go-test.log \ + --packages=./test/integration/connect/envoy \ + -- -timeout=30m -tags integration -run="TestEnvoy/(${{ matrix.test-cases }})" + + # NOTE: ENT specific step as we store secrets in Vault. + - name: Authenticate to Vault + if: ${{ endsWith(github.repository, '-enterprise') }} + id: vault-auth + run: vault-auth + + # NOTE: ENT specific step as we store secrets in Vault. + - name: Fetch Secrets + if: ${{ endsWith(github.repository, '-enterprise') }} + id: secrets + uses: hashicorp/vault-action@v2.5.0 + with: + url: ${{ steps.vault-auth.outputs.addr }} + caCertificate: ${{ steps.vault-auth.outputs.ca_certificate }} + token: ${{ steps.vault-auth.outputs.token }} + secrets: | + kv/data/github/${{ github.repository }}/datadog apikey | DATADOG_API_KEY; + + - name: prepare datadog-ci + if: ${{ !endsWith(github.repository, '-enterprise') }} + run: | + curl -L --fail "https://github.com/DataDog/datadog-ci/releases/latest/download/datadog-ci_linux-x64" --output "/usr/local/bin/datadog-ci" + chmod +x /usr/local/bin/datadog-ci + + - name: upload coverage + # do not run on forks + if: github.event.pull_request.head.repo.full_name == github.repository + env: + DATADOG_API_KEY: "${{ endsWith(github.repository, '-enterprise') && env.DATADOG_API_KEY || secrets.DATADOG_API_KEY }}" + DD_ENV: ci + run: datadog-ci junit upload --service "$GITHUB_REPOSITORY" $TEST_RESULTS_DIR/results.xml + + compatibility-integration-test: + runs-on: ${{ fromJSON(needs.setup.outputs.compute-large) }} + needs: + - setup + - dev-build + permissions: + id-token: write # NOTE: this permission is explicitly required for Vault auth. + contents: read + steps: + - uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0 + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + with: + # pinning this to 1.20.5 because this issue in go-testcontainers occurs + # in 1.20.6 with the error "http: invalid Host header, host port waiting failed" + # https://github.com/testcontainers/testcontainers-go/issues/1359 + # go-version-file: 'go.mod' + go-version: '1.20.5' + - run: go env + + # Build the consul:local image from the already built binary + - name: fetch binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: '${{ env.CONSUL_BINARY_UPLOAD_NAME }}' + path: . + - name: restore mode+x + run: chmod +x consul + + - name: Build consul:local image + run: docker build -t ${{ env.CONSUL_LATEST_IMAGE_NAME }}:local -f ./build-support/docker/Consul-Dev.dockerfile . + - name: Configure GH workaround for ipv6 loopback + if: ${{ !endsWith(github.repository, '-enterprise') }} + run: | + cat /etc/hosts && echo "-----------" + sudo sed -i 's/::1 *localhost ip6-localhost ip6-loopback/::1 ip6-localhost ip6-loopback/g' /etc/hosts + cat /etc/hosts + - name: Compatibility Integration Tests + run: | + mkdir -p "/tmp/test-results" + cd ./test/integration/consul-container + docker run --rm ${{ env.CONSUL_LATEST_IMAGE_NAME }}:local consul version + go run gotest.tools/gotestsum@v${{env.GOTESTSUM_VERSION}} \ + --raw-command \ + --format=standard-verbose \ + --debug \ + --rerun-fails=3 \ + -- \ + go test \ + -p=4 \ + -tags "${{ env.GOTAGS }}" \ + -timeout=30m \ + -json \ + `go list ./... | grep -v upgrade` \ + --target-image ${{ env.CONSUL_LATEST_IMAGE_NAME }} \ + --target-version local \ + --latest-image ${{ env.CONSUL_LATEST_IMAGE_NAME }} \ + --latest-version latest + ls -lrt + env: + # this is needed because of incompatibility between RYUK container and GHA + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + # tput complains if this isn't set to something. + TERM: ansi + + # NOTE: ENT specific step as we store secrets in Vault. + - name: Authenticate to Vault + if: ${{ endsWith(github.repository, '-enterprise') }} + id: vault-auth + run: vault-auth + + # NOTE: ENT specific step as we store secrets in Vault. + - name: Fetch Secrets + if: ${{ endsWith(github.repository, '-enterprise') }} + id: secrets + uses: hashicorp/vault-action@v2.5.0 + with: + url: ${{ steps.vault-auth.outputs.addr }} + caCertificate: ${{ steps.vault-auth.outputs.ca_certificate }} + token: ${{ steps.vault-auth.outputs.token }} + secrets: | + kv/data/github/${{ github.repository }}/datadog apikey | DATADOG_API_KEY; + + - name: prepare datadog-ci + if: ${{ !endsWith(github.repository, '-enterprise') }} + run: | + curl -L --fail "https://github.com/DataDog/datadog-ci/releases/latest/download/datadog-ci_linux-x64" --output "/usr/local/bin/datadog-ci" + chmod +x /usr/local/bin/datadog-ci + + - name: upload coverage + # do not run on forks + if: github.event.pull_request.head.repo.full_name == github.repository + env: + DATADOG_API_KEY: "${{ endsWith(github.repository, '-enterprise') && env.DATADOG_API_KEY || secrets.DATADOG_API_KEY }}" + DD_ENV: ci + run: datadog-ci junit upload --service "$GITHUB_REPOSITORY" $TEST_RESULTS_DIR/results.xml + + + upgrade-integration-test: + runs-on: ${{ fromJSON(needs.setup.outputs.compute-large) }} + permissions: + id-token: write # NOTE: this permission is explicitly required for Vault auth. + contents: read + needs: + - setup + - dev-build + strategy: + fail-fast: false + matrix: + consul-version: ["1.14"] + env: + CONSUL_LATEST_VERSION: ${{ matrix.consul-version }} + steps: + - uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0 + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + with: + # pinning this to 1.20.5 because this issue in go-testcontainers occurs + # in 1.20.6 with the error "http: invalid Host header, host port waiting failed" + # https://github.com/testcontainers/testcontainers-go/issues/1359 + # go-version-file: 'go.mod' + go-version: '1.20.5' + - run: go env + + # NOTE: ENT specific step as we store secrets in Vault. + - name: Authenticate to Vault + if: ${{ endsWith(github.repository, '-enterprise') }} + id: vault-auth + run: vault-auth + + # NOTE: ENT specific step as we store secrets in Vault. + - name: Fetch Secrets + if: ${{ endsWith(github.repository, '-enterprise') }} + id: secrets + uses: hashicorp/vault-action@v2.5.0 + with: + url: ${{ steps.vault-auth.outputs.addr }} + caCertificate: ${{ steps.vault-auth.outputs.ca_certificate }} + token: ${{ steps.vault-auth.outputs.token }} + secrets: | + kv/data/github/${{ github.repository }}/dockerhub username | DOCKERHUB_USERNAME; + kv/data/github/${{ github.repository }}/dockerhub token | DOCKERHUB_TOKEN; + + # NOTE: conditional specific logic as we store secrets in Vault in ENT and use GHA secrets in OSS. + - name: Login to Docker Hub + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # pin@v2.1.0 + with: + username: ${{ endsWith(github.repository, '-enterprise') && steps.secrets.outputs.DOCKERHUB_USERNAME || secrets.DOCKERHUB_USERNAME }} + password: ${{ endsWith(github.repository, '-enterprise') && steps.secrets.outputs.DOCKERHUB_TOKEN || secrets.DOCKERHUB_TOKEN }} + + + # Get go binary from workspace + - name: fetch binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: '${{ env.CONSUL_BINARY_UPLOAD_NAME }}' + path: . + - name: restore mode+x + run: chmod +x consul + - name: Build consul:local image + run: docker build -t ${{ env.CONSUL_LATEST_IMAGE_NAME }}:local -f ./build-support/docker/Consul-Dev.dockerfile . + - name: Configure GH workaround for ipv6 loopback + if: ${{ !endsWith(github.repository, '-enterprise') }} + run: | + cat /etc/hosts && echo "-----------" + sudo sed -i 's/::1 *localhost ip6-localhost ip6-loopback/::1 ip6-localhost ip6-loopback/g' /etc/hosts + cat /etc/hosts + - name: Upgrade Integration Tests + run: | + mkdir -p "${{ env.TEST_RESULTS_DIR }}" + cd ./test/integration/consul-container/test/upgrade + docker run --rm ${{ env.CONSUL_LATEST_IMAGE_NAME }}:local consul version + go run gotest.tools/gotestsum@v${{env.GOTESTSUM_VERSION}} \ + --raw-command \ + --format=short-verbose \ + --debug \ + --rerun-fails=3 \ + --packages="./..." \ + -- \ + go test \ + -p=4 \ + -tags "${{ env.GOTAGS }}" \ + -timeout=30m \ + -json ./... \ + --target-image ${{ env.CONSUL_LATEST_IMAGE_NAME }} \ + --target-version local \ + --latest-image ${{ env.CONSUL_LATEST_IMAGE_NAME }} \ + --latest-version "${{ env.CONSUL_LATEST_VERSION }}" + ls -lrt + env: + # this is needed because of incompatibility between RYUK container and GHA + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + # tput complains if this isn't set to something. + TERM: ansi + - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + with: + name: ${{ env.TEST_RESULTS_ARTIFACT_NAME }} + path: ${{ env.TEST_RESULTS_DIR }} + + test-integrations-success: + needs: + - setup + - dev-build + - nomad-integration-test + - vault-integration-test + - generate-envoy-job-matrices + - envoy-integration-test + - compatibility-integration-test + - upgrade-integration-test + runs-on: ${{ fromJSON(needs.setup.outputs.compute-small) }} + if: ${{ always() }} + steps: + - name: evaluate upstream job results + run: | + # exit 1 if failure or cancelled result for any upstream job + if printf '${{ toJSON(needs) }}' | grep -E -i '\"result\": \"(failure|cancelled)\"'; then + printf "Tests failed or workflow cancelled:\n\n${{ toJSON(needs) }}" + exit 1 + fi diff --git a/.github/workflows/verify-ci.yml b/.github/workflows/verify-ci.yml new file mode 100644 index 000000000000..4bd4536add1a --- /dev/null +++ b/.github/workflows/verify-ci.yml @@ -0,0 +1,23 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +# verify-ci is a no-op workflow that must run on every PR. It is used in a +# branch protection rule to detect when CI workflows are not running. +name: verify-ci + +permissions: + contents: read + +on: + pull_request: + push: + branches: + # Push events on the main branch + - main + - release/** + +jobs: + verify-ci-success: + runs-on: ubuntu-latest + steps: + - run: echo "verify-ci succeeded" diff --git a/.golangci.yml b/.golangci.yml index d71c93d163c1..0bfc46209405 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -23,10 +23,10 @@ issues: text: 'SA9004:' - linters: [staticcheck] - text: 'SA1019: Package github.com/golang/protobuf/jsonpb is deprecated' + text: 'SA1019: "github.com/golang/protobuf/jsonpb" is deprecated: Use the "google.golang.org/protobuf/encoding/protojson" package instead.' - linters: [staticcheck] - text: 'SA1019: Package github.com/golang/protobuf/proto is deprecated' + text: 'SA1019: "github.com/golang/protobuf/proto" is deprecated: Use the "google.golang.org/protobuf/proto" package instead.' - linters: [staticcheck] text: 'SA1019: ptypes.MarshalAny is deprecated' @@ -35,7 +35,10 @@ issues: text: 'SA1019: ptypes.UnmarshalAny is deprecated' - linters: [staticcheck] - text: 'SA1019: package github.com/golang/protobuf/ptypes is deprecated' + text: 'SA1019: "github.com/golang/protobuf/ptypes" is deprecated: Well-known types have specialized functionality directly injected into the generated packages for each message type. See the deprecation notice for each function for the suggested alternative.' + + - linters: [staticcheck] + text: 'SA1019: "io/ioutil" has been deprecated since Go 1.19' # An argument that always receives the same value is often not a problem. - linters: [unparam] @@ -60,13 +63,21 @@ issues: - linters: [unparam] text: '`(t|resp|req|entMeta)` is unused' - # Temp ignore everything in _oss(_test).go and _ent(_test).go. Many of these + # Temp ignore everything in _ce(_test).go and _ent(_test).go. Many of these # could use underscore to ignore the unused arguments, but the "always returns" - # issue will likely remain in oss, and will need to be excluded. + # issue will likely remain in CE, and will need to be excluded. - linters: [unparam] - path: '(_oss.go|_oss_test.go|_ent.go|_ent_test.go)' + path: "(_ce.go|_ce_test.go|_ent.go|_ent_test.go)" linters-settings: + govet: + check-shadowing: true + enable-all: true + disable: + - fieldalignment + - nilness + - shadow + - unusedwrite gofmt: simplify: true forbidigo: diff --git a/.release/ci.hcl b/.release/ci.hcl index ea205acd11d1..a2f1e88df39f 100644 --- a/.release/ci.hcl +++ b/.release/ci.hcl @@ -17,7 +17,6 @@ project "consul" { } event "build" { - depends = ["merge"] action "build" { organization = "hashicorp" repository = "crt-workflows-common" @@ -25,68 +24,13 @@ event "build" { } } -event "upload-dev" { +event "prepare" { depends = ["build"] - action "upload-dev" { - organization = "hashicorp" - repository = "crt-workflows-common" - workflow = "upload-dev" - depends = ["build"] - } - - notification { - on = "fail" - } -} - -event "security-scan-binaries" { - depends = ["upload-dev"] - action "security-scan-binaries" { - organization = "hashicorp" - repository = "crt-workflows-common" - workflow = "security-scan-binaries" - config = "security-scan.hcl" - } - - notification { - on = "fail" - } -} - -event "security-scan-containers" { - depends = ["security-scan-binaries"] - action "security-scan-containers" { - organization = "hashicorp" - repository = "crt-workflows-common" - workflow = "security-scan-containers" - config = "security-scan.hcl" - } - - notification { - on = "fail" - } -} - -event "notarize-darwin-amd64" { - depends = ["security-scan-containers"] - action "notarize-darwin-amd64" { - organization = "hashicorp" - repository = "crt-workflows-common" - workflow = "notarize-darwin-amd64" - - } - - notification { - on = "fail" - } -} - -event "notarize-darwin-arm64" { - depends = ["notarize-darwin-amd64"] - action "notarize-darwin-arm64" { + action "prepare" { organization = "hashicorp" repository = "crt-workflows-common" - workflow = "notarize-darwin-arm64" + workflow = "prepare" + depends = ["build"] } notification { @@ -94,96 +38,6 @@ event "notarize-darwin-arm64" { } } -event "notarize-windows-386" { - depends = ["notarize-darwin-arm64"] - action "notarize-windows-386" { - organization = "hashicorp" - repository = "crt-workflows-common" - workflow = "notarize-windows-386" - - } - - notification { - on = "fail" - } -} - -event "notarize-windows-amd64" { - depends = ["notarize-windows-386"] - action "notarize-windows-amd64" { - organization = "hashicorp" - repository = "crt-workflows-common" - workflow = "notarize-windows-amd64" - } - - notification { - on = "fail" - } -} - -event "sign" { - depends = ["notarize-windows-amd64"] - action "sign" { - organization = "hashicorp" - repository = "crt-workflows-common" - workflow = "sign" - - } - - notification { - on = "fail" - } -} - -event "sign-linux-rpms" { - depends = ["sign"] - action "sign-linux-rpms" { - organization = "hashicorp" - repository = "crt-workflows-common" - workflow = "sign-linux-rpms" - } - - notification { - on = "fail" - } -} - -event "verify" { - depends = ["sign-linux-rpms"] - action "verify" { - organization = "hashicorp" - repository = "crt-workflows-common" - workflow = "verify" - } - - notification { - on = "fail" - } -} - -event "promote-dev-docker" { - depends = ["verify"] - action "promote-dev-docker" { - organization = "hashicorp" - repository = "crt-workflows-common" - workflow = "promote-dev-docker" - depends = ["verify"] - } - - notification { - on = "fail" - } -} - -event "fossa-scan" { - depends = ["promote-dev-docker"] - action "fossa-scan" { - organization = "hashicorp" - repository = "crt-workflows-common" - workflow = "fossa-scan" - } -} - ## These are promotion and post-publish events ## they should be added to the end of the file after the verify event stanza. @@ -275,9 +129,21 @@ event "post-publish-website" { on = "always" } } +event "bump-version" { + depends = ["post-publish-website"] + action "bump-version" { + organization = "hashicorp" + repository = "crt-workflows-common" + workflow = "bump-version" + } + + notification { + on = "fail" + } +} event "update-ironbank" { - depends = ["post-publish-website"] + depends = ["bump-version"] action "update-ironbank" { organization = "hashicorp" repository = "crt-workflows-common" @@ -287,4 +153,4 @@ event "update-ironbank" { notification { on = "fail" } -} +} \ No newline at end of file diff --git a/.release/linux/package/usr/lib/systemd/system/consul.service b/.release/linux/package/usr/lib/systemd/system/consul.service index 1bbf51a7a102..65eca696e1a1 100644 --- a/.release/linux/package/usr/lib/systemd/system/consul.service +++ b/.release/linux/package/usr/lib/systemd/system/consul.service @@ -6,6 +6,7 @@ After=network-online.target ConditionFileNotEmpty=/etc/consul.d/consul.hcl [Service] +Type=notify EnvironmentFile=-/etc/consul.d/consul.env User=consul Group=consul diff --git a/.release/security-scan.hcl b/.release/security-scan.hcl index 490ddd274635..97124dd4eb32 100644 --- a/.release/security-scan.hcl +++ b/.release/security-scan.hcl @@ -8,6 +8,7 @@ binary { secrets = false go_modules = false osv = true + # TODO(spatel): CE refactor oss_index = true nvd = true } diff --git a/CHANGELOG.md b/CHANGELOG.md index df9ea0528147..cf5adfb6f50a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,328 @@ +## 1.14.9 (August 8, 2023) + +SECURITY: + +* Update `golang.org/x/net` to v0.13.0 to address [CVE-2023-3978](https://nvd.nist.gov/vuln/detail/CVE-2023-3978). [[GH-18358](https://github.com/hashicorp/consul/issues/18358)] +* Upgrade golang.org/x/net to address [CVE-2023-29406](https://nvd.nist.gov/vuln/detail/CVE-2023-29406) [[GH-18186](https://github.com/hashicorp/consul/issues/18186)] +* Upgrade to use Go 1.20.6. +This resolves [CVE-2023-29406](https://github.com/advisories/GHSA-f8f7-69v5-w4vx)(`net/http`) for uses of the standard library. +A separate change updates dependencies on `golang.org/x/net` to use `0.12.0`. [[GH-18190](https://github.com/hashicorp/consul/issues/18190)] +* Upgrade to use Go 1.20.7. +This resolves vulnerability [CVE-2023-29409](https://nvd.nist.gov/vuln/detail/CVE-2023-29409)(`crypto/tls`). [[GH-18358](https://github.com/hashicorp/consul/issues/18358)] + +FEATURES: + +* cli: `consul members` command uses `-filter` expression to filter members based on bexpr. [[GH-18223](https://github.com/hashicorp/consul/issues/18223)] +* cli: `consul watch` command uses `-filter` expression to filter response from checks, services, nodes, and service. [[GH-17780](https://github.com/hashicorp/consul/issues/17780)] +* reloadable config: Made enable_debug config reloadable and enable pprof command to work when config toggles to true [[GH-17565](https://github.com/hashicorp/consul/issues/17565)] + +IMPROVEMENTS: + +* Fix some typos in metrics docs [[GH-18080](https://github.com/hashicorp/consul/issues/18080)] +* acl: added builtin ACL policy that provides global read-only access (builtin/global-read-only) [[GH-18319](https://github.com/hashicorp/consul/issues/18319)] +* acl: allow for a single slash character in policy names [[GH-18319](https://github.com/hashicorp/consul/issues/18319)] +* connect: update supported envoy versions to 1.21.6, 1.22.11, 1.23.12, 1.24.10 [[GH-18305](https://github.com/hashicorp/consul/issues/18305)] +* hcp: Removes requirement for HCP to provide a management token [[GH-18140](https://github.com/hashicorp/consul/issues/18140)] +* xds: Explicitly enable WebSocket connection upgrades in HTTP connection manager [[GH-18150](https://github.com/hashicorp/consul/issues/18150)] + +BUG FIXES: + +* Fix a bug that wrongly trims domains when there is an overlap with DC name. [[GH-17160](https://github.com/hashicorp/consul/issues/17160)] +* connect/ca: Fixes a bug preventing CA configuration updates in secondary datacenters [[GH-17846](https://github.com/hashicorp/consul/issues/17846)] +* connect: Fix incorrect protocol config merging for transparent proxy implicit upstreams. [[GH-17894](https://github.com/hashicorp/consul/issues/17894)] +* connect: fix a bug with Envoy potentially starting with incomplete configuration by not waiting enough for initial xDS configuration. [[GH-18024](https://github.com/hashicorp/consul/issues/18024)] +* snapshot: fix access denied and handle is invalid when we call snapshot save on windows - skip sync() for folders in windows in +https://github.com/rboyer/safeio/pull/3 [[GH-18302](https://github.com/hashicorp/consul/issues/18302)] + +## 1.14.8 (June 26, 2023) + +SECURITY: + +* Update to UBI base image to 9.2. [[GH-17513](https://github.com/hashicorp/consul/issues/17513)] + +FEATURES: + +* cli: `consul operator raft list-peers` command shows the number of commits each follower is trailing the leader by to aid in troubleshooting. [[GH-17582](https://github.com/hashicorp/consul/issues/17582)] +* server: **(Enterprise Only)** allow automatic license utilization reporting. [[GH-5102](https://github.com/hashicorp/consul/issues/5102)] + +IMPROVEMENTS: + +* connect: update supported envoy versions to 1.21.6, 1.22.11, 1.23.9, 1.24.7 [[GH-17547](https://github.com/hashicorp/consul/issues/17547)] +* debug: change default setting of consul debug command. now default duration is 5ms and default log level is 'TRACE' [[GH-17596](https://github.com/hashicorp/consul/issues/17596)] +* fix metric names in /docs/agent/telemetry [[GH-17577](https://github.com/hashicorp/consul/issues/17577)] +* peering: gRPC queries for TrustBundleList, TrustBundleRead, PeeringList, and PeeringRead now support blocking semantics, + reducing network and CPU demand. + The HTTP APIs for Peering List and Read have been updated to support blocking. [[GH-17426](https://github.com/hashicorp/consul/issues/17426)] +* raft: Remove expensive reflection from raft/mesh hot path [[GH-16552](https://github.com/hashicorp/consul/issues/16552)] +* systemd: set service type to notify. [[GH-16845](https://github.com/hashicorp/consul/issues/16845)] + +BUG FIXES: + +* cache: fix a few minor goroutine leaks in leaf certs and the agent cache [[GH-17636](https://github.com/hashicorp/consul/issues/17636)] +* connect: reverts #17317 fix that caused a downstream error for Ingress/Mesh/Terminating GWs when their respective config entry does not already exist. [[GH-17541](https://github.com/hashicorp/consul/issues/17541)] +* namespaces: **(Enterprise only)** fixes a bug where agent health checks stop syncing for all services on a node if the namespace of any service has been removed from the server. +* namespaces: **(Enterprise only)** fixes a bug where namespaces are stuck in a deferred deletion state indefinitely under some conditions. + Also fixes the Consul query metadata present in the HTTP headers of the namespace read and list endpoints. +* namespaces: adjusts the return type from HTTP list API to return the `api` module representation of a namespace. + This fixes an error with the `consul namespace list` command when a namespace has a deferred deletion timestamp. +* peering: Fix a bug that caused server agents to continue cleaning up peering resources even after loss of leadership. [[GH-17483](https://github.com/hashicorp/consul/issues/17483)] +* peering: Fix issue where modifying the list of exported services did not correctly replicate changes for services that exist in a non-default namespace. [[GH-17456](https://github.com/hashicorp/consul/issues/17456)] + +## 1.14.7 (May 16, 2023) + +SECURITY: + +* Upgrade to use Go 1.20.4. + This resolves vulnerabilities [CVE-2023-24537](https://github.com/advisories/GHSA-9f7g-gqwh-jpf5)(`go/scanner`), + [CVE-2023-24538](https://github.com/advisories/GHSA-v4m2-x4rp-hv22)(`html/template`), + [CVE-2023-24534](https://github.com/advisories/GHSA-8v5j-pwr7-w5f8)(`net/textproto`) and + [CVE-2023-24536](https://github.com/advisories/GHSA-9f7g-gqwh-jpf5)(`mime/multipart`). + Also, `golang.org/x/net` has been updated to v0.7.0 to resolve CVEs [CVE-2022-41721 + ](https://github.com/advisories/GHSA-fxg5-wq6x-vr4w + ), [CVE-2022-27664](https://github.com/advisories/GHSA-69cg-p879-7622) and [CVE-2022-41723 + ](https://github.com/advisories/GHSA-vvpx-j8f3-3w6h + .) [[GH-17240](https://github.com/hashicorp/consul/issues/17240)] + +IMPROVEMENTS: + +* connect: update supported envoy versions to 1.21.6, 1.22.11, 1.23.8, 1.24.6 [[GH-16888](https://github.com/hashicorp/consul/issues/16888)] +* envoy: add `MaxEjectionPercent` and `BaseEjectionTime` to passive health check configs. [[GH-15979](https://github.com/hashicorp/consul/issues/15979)] +* hcp: Add support for linking existing Consul clusters to HCP management plane. [[GH-16916](https://github.com/hashicorp/consul/issues/16916)] +* logging: change snapshot log header from `agent.server.snapshot` to `agent.server.raft.snapshot` [[GH-17236](https://github.com/hashicorp/consul/issues/17236)] +* peering: allow re-establishing terminated peering from new token without deleting existing peering first. [[GH-16776](https://github.com/hashicorp/consul/issues/16776)] + +BUG FIXES: + +* Fix an bug where decoding some Config structs with unset pointer fields could fail with `reflect: call of reflect.Value.Type on zero Value`. [[GH-17048](https://github.com/hashicorp/consul/issues/17048)] +* acl: **(Enterprise only)** Check permissions in correct partition/namespace when resolving service in non-default partition/namespace +* acls: Fix ACL bug that can result in sidecar proxies having incorrect endpoints. +* connect: Fix multiple inefficient behaviors when querying service health. [[GH-17241](https://github.com/hashicorp/consul/issues/17241)] +* connect: fix a bug with Envoy potentially starting with incomplete configuration by not waiting enough for initial xDS configuration. [[GH-17317](https://github.com/hashicorp/consul/issues/17317)] +* grpc: ensure grpc resolver correctly uses lan/wan addresses on servers [[GH-17270](https://github.com/hashicorp/consul/issues/17270)] +* peering: Fix issue where peer streams could incorrectly deregister services in various scenarios. [[GH-17235](https://github.com/hashicorp/consul/issues/17235)] +* proxycfg: ensure that an irrecoverable error in proxycfg closes the xds session and triggers a replacement proxycfg watcher [[GH-16497](https://github.com/hashicorp/consul/issues/16497)] +* xds: Fix possible panic that can when generating clusters before the root certificates have been fetched. [[GH-17185](https://github.com/hashicorp/consul/issues/17185)] + +## 1.14.6 (March 30, 2023) +BUG FIXES: +* audit-logging: (Enterprise only) Fix a bug where `/agent/monitor` and `/agent/metrics` endpoints return a `Streaming not supported` error when audit logs are enabled. This also fixes the delay receiving logs when running `consul monitor` against an agent with audit logs enabled. [[GH-16700](https://github.com/hashicorp/consul/issues/16700)] +* ca: Fixes a bug where updating Vault CA Provider config would cause TLS issues in the service mesh [[GH-16592](https://github.com/hashicorp/consul/issues/16592)] +* peering: **(Consul Enterprise only)** Fix issue where connect-enabled services with peer upstreams incorrectly required `service:write` access in the `default` namespace to query data, which was too restrictive. Now having `service:write` to any namespace is sufficient to query the peering data. +* peering: **(Consul Enterprise only)** Fix issue where resolvers, routers, and splitters referencing peer targets may not work correctly for non-default partitions and namespaces. Enterprise customers leveraging peering are encouraged to upgrade both servers and agents to avoid this problem. +* peering: Fix issue resulting in prepared query failover to cluster peers never un-failing over. [[GH-16729](https://github.com/hashicorp/consul/issues/16729)] +* peering: Fixes a bug that can lead to peering service deletes impacting the state of local services [[GH-16570](https://github.com/hashicorp/consul/issues/16570)] +* peering: Fixes a bug where the importing partition was not added to peered failover targets, which causes issues when the importing partition is a non-default partition. [[GH-16693](https://github.com/hashicorp/consul/issues/16693)] +* ui: fix PUT token request with adding missed AccessorID property to requestBody [[GH-16660](https://github.com/hashicorp/consul/issues/16660)] + +## 1.14.5 (March 7, 2023) + +SECURITY: + +* Upgrade to use Go 1.20.1. +This resolves vulnerabilities [CVE-2022-41724](https://go.dev/issue/58001) in `crypto/tls` and [CVE-2022-41723](https://go.dev/issue/57855) in `net/http`. [[GH-16263](https://github.com/hashicorp/consul/issues/16263)] + +IMPROVEMENTS: + +* container: Upgrade container image to use to Alpine 3.17. [[GH-16358](https://github.com/hashicorp/consul/issues/16358)] +* mesh: Add ServiceResolver RequestTimeout for route timeouts to make request timeouts configurable [[GH-16495](https://github.com/hashicorp/consul/issues/16495)] + +BUG FIXES: + +* mesh: Fix resolution of service resolvers with subsets for external upstreams [[GH-16499](https://github.com/hashicorp/consul/issues/16499)] +* peering: Fix bug where services were incorrectly imported as connect-enabled. [[GH-16339](https://github.com/hashicorp/consul/issues/16339)] +* peering: Fix issue where mesh gateways would use the wrong address when contacting a remote peer with the same datacenter name. [[GH-16257](https://github.com/hashicorp/consul/issues/16257)] +* peering: Fix issue where secondary wan-federated datacenters could not be used as peering acceptors. [[GH-16230](https://github.com/hashicorp/consul/issues/16230)] +* proxycfg: fix a bug where terminating gateways were not cleaning up deleted service resolvers for their referenced services [[GH-16498](https://github.com/hashicorp/consul/issues/16498)] + +## 1.14.4 (January 26, 2023) + +BREAKING CHANGES: + +* connect: Fix configuration merging for transparent proxy upstreams. Proxy-defaults and service-defaults config entries were not correctly merged for implicit upstreams in transparent proxy mode and would result in some configuration not being applied. To avoid issues when upgrading, ensure that any proxy-defaults or service-defaults have correct configuration for upstreams, since all fields will now be properly used to configure proxies. [[GH-16000](https://github.com/hashicorp/consul/issues/16000)] +* peering: Newly created peering connections must use only lowercase characters in the `name` field. Existing peerings with uppercase characters will not be modified, but they may encounter issues in various circumstances. To maintain forward compatibility and avoid issues, it is recommended to destroy and re-create any invalid peering connections so that they do not have a name containing uppercase characters. [[GH-15697](https://github.com/hashicorp/consul/issues/15697)] + +FEATURES: + +* connect: add flags `envoy-ready-bind-port` and `envoy-ready-bind-address` to the `consul connect envoy` command that allows configuration of readiness probe on proxy for any service kind. [[GH-16015](https://github.com/hashicorp/consul/issues/16015)] +* deps: update to latest go-discover to provide ECS auto-discover capabilities. [[GH-13782](https://github.com/hashicorp/consul/issues/13782)] + +IMPROVEMENTS: + +* acl: relax permissions on the `WatchServers`, `WatchRoots` and `GetSupportedDataplaneFeatures` gRPC endpoints to accept *any* valid ACL token [[GH-15346](https://github.com/hashicorp/consul/issues/15346)] +* connect: Add support for ConsulResolver to specifies a filter expression [[GH-15659](https://github.com/hashicorp/consul/issues/15659)] +* grpc: Use new balancer implementation to reduce periodic WARN logs when shuffling servers. [[GH-15701](https://github.com/hashicorp/consul/issues/15701)] +* partition: **(Consul Enterprise only)** when loading service from on-disk config file or sending API request to agent endpoint, +if the partition is unspecified, consul will default the partition in the request to agent's partition [[GH-16024](https://github.com/hashicorp/consul/issues/16024)] + +BUG FIXES: + +* agent: Fix assignment of error when auto-reloading cert and key file changes. [[GH-15769](https://github.com/hashicorp/consul/issues/15769)] +* agent: Fix issue where the agent cache would incorrectly mark protobuf objects as updated. [[GH-15866](https://github.com/hashicorp/consul/issues/15866)] +* cli: Fix issue where `consul connect envoy` was unable to configure TLS over unix-sockets to gRPC. [[GH-15913](https://github.com/hashicorp/consul/issues/15913)] +* connect: **(Consul Enterprise only)** Fix issue where upstream configuration from proxy-defaults and service-defaults was not properly merged. This could occur when a mixture of empty-strings and "default" were used for the namespace or partition fields. +* connect: Fix issue where service-resolver protocol checks incorrectly errored for failover peer targets. [[GH-15833](https://github.com/hashicorp/consul/issues/15833)] +* connect: Fix issue where watches on upstream failover peer targets did not always query the correct data. [[GH-15865](https://github.com/hashicorp/consul/issues/15865)] +* xds: fix bug where sessions for locally-managed services could fail with "this server has too many xDS streams open" [[GH-15789](https://github.com/hashicorp/consul/issues/15789)] + +## 1.14.3 (December 13, 2022) + +SECURITY: + +* Upgrade to use Go 1.19.4. This resolves a vulnerability where restricted files can be read on Windows. [CVE-2022-41720](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-41720) [[GH-15705](https://github.com/hashicorp/consul/issues/15705)] +* Upgrades `golang.org/x/net` to prevent a denial of service by excessive memory usage caused by HTTP2 requests. [CVE-2022-41717](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-41717) [[GH-15737](https://github.com/hashicorp/consul/issues/15737)] + +FEATURES: + +* ui: Add field for fallback server addresses to peer token generation form [[GH-15555](https://github.com/hashicorp/consul/issues/15555)] + +IMPROVEMENTS: + +* connect: ensure all vault connect CA tests use limited privilege tokens [[GH-15669](https://github.com/hashicorp/consul/issues/15669)] + +BUG FIXES: + +* agent: **(Enterprise Only)** Ensure configIntentionsConvertToList does not compare empty strings with populated strings when filtering intentions created prior to AdminPartitions. +* connect: Fix issue where DialedDirectly configuration was not used by Consul Dataplane. [[GH-15760](https://github.com/hashicorp/consul/issues/15760)] +* connect: Fix peering failovers ignoring local mesh gateway configuration. [[GH-15690](https://github.com/hashicorp/consul/issues/15690)] +* connect: Fixed issue where using Vault 1.11+ as CA provider in a secondary datacenter would eventually break Intermediate CAs [[GH-15661](https://github.com/hashicorp/consul/issues/15661)] + +## 1.14.2 (November 30, 2022) + +FEATURES: + +* connect: Add local_idle_timeout_ms to allow configuring the Envoy route idle timeout on local_app +connect: Add IdleTimeout to service-router to allow configuring the Envoy route idle timeout [[GH-14340](https://github.com/hashicorp/consul/issues/14340)] +* snapshot: **(Enterprise Only)** Add support for the snapshot agent to use an IAM role for authentication/authorization when managing snapshots in S3. + +IMPROVEMENTS: + +* dns: Add support for cluster peering `.service` and `.node` DNS queries. [[GH-15596](https://github.com/hashicorp/consul/issues/15596)] + +BUG FIXES: + +* acl: avoid debug log spam in secondary datacenter servers due to management token not being initialized. [[GH-15610](https://github.com/hashicorp/consul/issues/15610)] +* agent: Fixed issue where blocking queries with short waits could timeout on the client [[GH-15541](https://github.com/hashicorp/consul/issues/15541)] +* ca: Fixed issue where using Vault as Connect CA with Vault-managed policies would error on start-up if the intermediate PKI mount existed but was empty [[GH-15525](https://github.com/hashicorp/consul/issues/15525)] +* cli: **(Enterprise Only)** Fix issue where `consul partition update` subcommand was not registered and therefore not available through the cli. +* connect: Fixed issue where using Vault 1.11+ as CA provider would eventually break Intermediate CAs [[GH-15217](https://github.com/hashicorp/consul/issues/15217)] [[GH-15253](https://github.com/hashicorp/consul/issues/15253)] +* namespace: **(Enterprise Only)** Fix a bug that caused blocking queries during namespace replication to timeout +* peering: better represent non-passing states during peer check flattening [[GH-15615](https://github.com/hashicorp/consul/issues/15615)] +* peering: fix the limit of replication gRPC message; set to 8MB [[GH-15503](https://github.com/hashicorp/consul/issues/15503)] + +## 1.14.1 (November 21, 2022) + +BUG FIXES: + +* cli: Fix issue where `consul connect envoy` incorrectly uses the HTTPS API configuration for xDS connections. [[GH-15466](https://github.com/hashicorp/consul/issues/15466)] +* sdk: Fix SDK testutil backwards compatibility by only configuring grpc_tls port for new Consul versions. [[GH-15423](https://github.com/hashicorp/consul/issues/15423)] + +## 1.14.0 (November 15, 2022) + +KNOWN ISSUES: + +* cli: `consul connect envoy` incorrectly enables TLS for gRPC connections when the HTTP API is TLS-enabled. + +BREAKING CHANGES: + +* config: Add new `ports.grpc_tls` configuration option. +Introduce a new port to better separate TLS config from the existing `ports.grpc` config. +The new `ports.grpc_tls` only supports TLS encrypted communication. +The existing `ports.grpc` now only supports plain-text communication. [[GH-15339](https://github.com/hashicorp/consul/issues/15339)] +* config: update 1.14 config defaults: Enable `peering` and `connect` by default. [[GH-15302](https://github.com/hashicorp/consul/issues/15302)] +* config: update 1.14 config defaults: Set gRPC TLS port default value to 8503 [[GH-15302](https://github.com/hashicorp/consul/issues/15302)] +* connect: Removes support for Envoy 1.20 [[GH-15093](https://github.com/hashicorp/consul/issues/15093)] +* peering: Rename `PeerName` to `Peer` on prepared queries and exported services. [[GH-14854](https://github.com/hashicorp/consul/issues/14854)] +* xds: Convert service mesh failover to use Envoy's aggregate clusters. This +changes the names of some [Envoy dynamic HTTP metrics](https://www.envoyproxy.io/docs/envoy/latest/configuration/upstream/cluster_manager/cluster_stats#dynamic-http-statistics). [[GH-14178](https://github.com/hashicorp/consul/issues/14178)] + +SECURITY: + +* Ensure that data imported from peers is filtered by ACLs at the UI Nodes/Services endpoints [CVE-2022-3920](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-3920) [[GH-15356](https://github.com/hashicorp/consul/issues/15356)] + +FEATURES: + +* DNS-proxy support via gRPC request. [[GH-14811](https://github.com/hashicorp/consul/issues/14811)] +* cli: Add -node-name flag to redirect-traffic command to support running in environments without client agents. [[GH-14933](https://github.com/hashicorp/consul/issues/14933)] +* cli: Add `-consul-dns-port` flag to the `consul connect redirect-traffic` command to allow forwarding DNS traffic to a specific Consul DNS port. [[GH-15050](https://github.com/hashicorp/consul/issues/15050)] +* connect: Add Envoy connection balancing configuration fields. [[GH-14616](https://github.com/hashicorp/consul/issues/14616)] +* grpc: Added metrics for external gRPC server. Added `server_type=internal|external` label to gRPC metrics. [[GH-14922](https://github.com/hashicorp/consul/issues/14922)] +* http: Add new `get-or-empty` operation to the txn api. Refer to the [API docs](https://www.consul.io/api-docs/txn#kv-operations) for more information. [[GH-14474](https://github.com/hashicorp/consul/issues/14474)] +* peering: Add mesh gateway local mode support for cluster peering. [[GH-14817](https://github.com/hashicorp/consul/issues/14817)] +* peering: Add support for stale queries for trust bundle lookups [[GH-14724](https://github.com/hashicorp/consul/issues/14724)] +* peering: Add support to failover to services running on cluster peers. [[GH-14396](https://github.com/hashicorp/consul/issues/14396)] +* peering: Add support to redirect to services running on cluster peers with service resolvers. [[GH-14445](https://github.com/hashicorp/consul/issues/14445)] +* peering: Ensure un-exported services get deleted even if the un-export happens while cluster peering replication is down. [[GH-14797](https://github.com/hashicorp/consul/issues/14797)] +* peering: add support for routine peering control-plane traffic through mesh gateways [[GH-14981](https://github.com/hashicorp/consul/issues/14981)] +* sdk: Configure `iptables` to forward DNS traffic to a specific DNS port. [[GH-15050](https://github.com/hashicorp/consul/issues/15050)] +* telemetry: emit memberlist size metrics and broadcast queue depth metric. [[GH-14873](https://github.com/hashicorp/consul/issues/14873)] +* ui: Added support for central config merging [[GH-14604](https://github.com/hashicorp/consul/issues/14604)] +* ui: Create peerings detail page [[GH-14947](https://github.com/hashicorp/consul/issues/14947)] +* ui: Detect a TokenSecretID cookie and passthrough to localStorage [[GH-14495](https://github.com/hashicorp/consul/issues/14495)] +* ui: Display notice banner on nodes index page if synthetic nodes are being filtered. [[GH-14971](https://github.com/hashicorp/consul/issues/14971)] +* ui: Filter agentless (synthetic) nodes from the nodes list page. [[GH-14970](https://github.com/hashicorp/consul/issues/14970)] +* ui: Filter out node health checks on agentless service instances [[GH-14986](https://github.com/hashicorp/consul/issues/14986)] +* ui: Remove node meta on service instances when using agentless and consolidate external-source labels on service instances page if they all match. [[GH-14921](https://github.com/hashicorp/consul/issues/14921)] +* ui: Removed reference to node name on service instance page when using agentless [[GH-14903](https://github.com/hashicorp/consul/issues/14903)] +* ui: Use withCredentials for all HTTP API requests [[GH-14343](https://github.com/hashicorp/consul/issues/14343)] +* xds: servers will limit the number of concurrent xDS streams they can handle to balance the load across all servers [[GH-14397](https://github.com/hashicorp/consul/issues/14397)] + +IMPROVEMENTS: + +* peering: Add peering datacenter and partition to initial handshake. [[GH-14889](https://github.com/hashicorp/consul/issues/14889)] +* xds: Added a rate limiter to the delivery of proxy config updates, to prevent updates to "global" resources such as wildcard intentions from overwhelming servers (see: `xds.update_max_per_second` config field) [[GH-14960](https://github.com/hashicorp/consul/issues/14960)] +* xds: Removed a bottleneck in Envoy config generation, enabling a higher number of dataplanes per server [[GH-14934](https://github.com/hashicorp/consul/issues/14934)] +* agent/hcp: add initial HashiCorp Cloud Platform integration [[GH-14723](https://github.com/hashicorp/consul/issues/14723)] +* agent: Added configuration option cloud.scada_address. [[GH-14936](https://github.com/hashicorp/consul/issues/14936)] +* api: Add filtering support to Catalog's List Services (v1/catalog/services) [[GH-11742](https://github.com/hashicorp/consul/issues/11742)] +* api: Increase max number of operations inside a transaction for requests to /v1/txn (128) [[GH-14599](https://github.com/hashicorp/consul/issues/14599)] +* auto-config: Relax the validation on auto-config JWT authorization to allow non-whitespace, non-quote characters in node names. [[GH-15370](https://github.com/hashicorp/consul/issues/15370)] +* config-entry: Validate that service-resolver `Failover`s and `Redirect`s only +specify `Partition` and `Namespace` on Consul Enterprise. This prevents scenarios +where OSS Consul would save service-resolvers that require Consul Enterprise. [[GH-14162](https://github.com/hashicorp/consul/issues/14162)] +* connect: Add Envoy 1.24.0 to support matrix [[GH-15093](https://github.com/hashicorp/consul/issues/15093)] +* connect: Bump Envoy 1.20 to 1.20.7, 1.21 to 1.21.5 and 1.22 to 1.22.5 [[GH-14831](https://github.com/hashicorp/consul/issues/14831)] +* connect: service-router destinations have gained a `RetryOn` field for specifying the conditions when Envoy should retry requests beyond specific status codes and generic connection failure which already exists. [[GH-12890](https://github.com/hashicorp/consul/issues/12890)] +* dns/peering: **(Enterprise Only)** Support addresses in the formats `.virtual..ns..ap..peer.consul` and `.virtual..ap..peer.consul`. This longer form address that allows specifying `.peer` would need to be used for tproxy DNS requests made within non-default partitions for imported services. +* dns: **(Enterprise Only)** All enterprise locality labels are now optional in DNS lookups. For example, service lookups support the following format: `[.].service[..ns][..ap][..dc]`. [[GH-14679](https://github.com/hashicorp/consul/issues/14679)] +* integ test: fix flakiness due to test condition from retry app endoint [[GH-15233](https://github.com/hashicorp/consul/issues/15233)] +* metrics: Service RPC calls less than 1ms are now emitted as a decimal number. [[GH-12905](https://github.com/hashicorp/consul/issues/12905)] +* peering: adds an internally managed server certificate for automatic TLS between servers in peer clusters. [[GH-14556](https://github.com/hashicorp/consul/issues/14556)] +* peering: require TLS for peering connections using server cert signed by Connect CA [[GH-14796](https://github.com/hashicorp/consul/issues/14796)] +* peering: return information about the health of the peering when the leader is queried to read a peering. [[GH-14747](https://github.com/hashicorp/consul/issues/14747)] +* raft: Allow nonVoter to initiate an election to avoid having an election infinite loop when a Voter is converted to NonVoter [[GH-14897](https://github.com/hashicorp/consul/issues/14897)] +* raft: Cap maximum grpc wait time when heartbeating to heartbeatTimeout/2 [[GH-14897](https://github.com/hashicorp/consul/issues/14897)] +* raft: Fix a race condition where the snapshot file is closed without being opened [[GH-14897](https://github.com/hashicorp/consul/issues/14897)] +* telemetry: Added a `consul.xds.server.streamStart` metric to measure time taken to first generate xDS resources for an xDS stream. [[GH-14957](https://github.com/hashicorp/consul/issues/14957)] +* ui: Improve guidance around topology visualisation [[GH-14527](https://github.com/hashicorp/consul/issues/14527)] +* xds: Set `max_ejection_percent` on Envoy's outlier detection to 100% for peered services. [[GH-14373](https://github.com/hashicorp/consul/issues/14373)] +* xds: configure Envoy `alpn_protocols` for connect-proxy and ingress-gateway based on service protocol. + +BUG FIXES: + +* checks: Do not set interval as timeout value [[GH-14619](https://github.com/hashicorp/consul/issues/14619)] +* checks: If set, use proxy address for automatically added sidecar check instead of service address. [[GH-14433](https://github.com/hashicorp/consul/issues/14433)] +* cli: Fix Consul kv CLI 'GET' flags 'keys' and 'recurse' to be set together [[GH-13493](https://github.com/hashicorp/consul/issues/13493)] +* connect: Fix issue where mesh-gateway settings were not properly inherited from configuration entries. [[GH-15186](https://github.com/hashicorp/consul/issues/15186)] +* connect: fixed bug where endpoint updates for new xDS clusters could block for 15s before being sent to Envoy. [[GH-15083](https://github.com/hashicorp/consul/issues/15083)] +* connect: strip port from DNS SANs for ingress gateway leaf certificate to avoid an invalid hostname error when using the Vault provider. [[GH-15320](https://github.com/hashicorp/consul/issues/15320)] +* debug: fixed bug that caused consul debug CLI to error on ACL-disabled clusters [[GH-15155](https://github.com/hashicorp/consul/issues/15155)] +* deps: update go-memdb, fixing goroutine leak [[GH-15010](https://github.com/hashicorp/consul/issues/15010)] [[GH-15068](https://github.com/hashicorp/consul/issues/15068)] +* grpc: Merge proxy-defaults and service-defaults in GetEnvoyBootstrapParams response. [[GH-14869](https://github.com/hashicorp/consul/issues/14869)] +* metrics: Add duplicate metrics that have only a single "consul_" prefix for all existing metrics with double ("consul_consul_") prefix, with the intent to standardize on single prefixes. [[GH-14475](https://github.com/hashicorp/consul/issues/14475)] +* namespace: **(Enterprise Only)** Fixed a bug where a client may incorrectly log that namespaces were not enabled in the local datacenter +* peering: Fix a bug that resulted in /v1/agent/metrics returning an error. [[GH-15178](https://github.com/hashicorp/consul/issues/15178)] +* peering: fix nil pointer in calling handleUpdateService [[GH-15160](https://github.com/hashicorp/consul/issues/15160)] +* peering: fix the error of wan address isn't taken by the peering token. [[GH-15065](https://github.com/hashicorp/consul/issues/15065)] +* peering: when wan address is set, peering stream should use the wan address. [[GH-15108](https://github.com/hashicorp/consul/issues/15108)] +* proxycfg(mesh-gateway): Fix issue where deregistered services are not removed from mesh-gateway clusters. [[GH-15272](https://github.com/hashicorp/consul/issues/15272)] +* server: fix goroutine/memory leaks in the xDS subsystem (these were present regardless of whether or not xDS was in-use) [[GH-14916](https://github.com/hashicorp/consul/issues/14916)] +* server: fixes the error trying to source proxy configuration for http checks, in case of proxies using consul-dataplane. [[GH-14924](https://github.com/hashicorp/consul/issues/14924)] +* xds: Central service configuration (proxy-defaults and service-defaults) is now correctly applied to Consul Dataplane proxies [[GH-14962](https://github.com/hashicorp/consul/issues/14962)] + +NOTES: + +* deps: Upgrade to use Go 1.19.2 [[GH-15090](https://github.com/hashicorp/consul/issues/15090)] + ## 1.13.3 (October 19, 2022) FEATURES: diff --git a/Dockerfile b/Dockerfile index 8e127254fe27..f5550f8f14d2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ # Official docker image that includes binaries from releases.hashicorp.com. This # downloads the release from releases.hashicorp.com and therefore requires that # the release is published before building the Docker image. -FROM docker.mirror.hashicorp.services/alpine:3.15 as official +FROM docker.mirror.hashicorp.services/alpine:3.17 as official # This is the release of Consul to pull in. ARG VERSION @@ -109,7 +109,7 @@ CMD ["agent", "-dev", "-client", "0.0.0.0"] # Production docker image that uses CI built binaries. # Remember, this image cannot be built locally. -FROM docker.mirror.hashicorp.services/alpine:3.15 as default +FROM docker.mirror.hashicorp.services/alpine:3.17 as default ARG PRODUCT_VERSION ARG BIN_NAME @@ -198,7 +198,7 @@ CMD ["agent", "-dev", "-client", "0.0.0.0"] # Red Hat UBI-based image # This target is used to build a Consul image for use on OpenShift. -FROM registry.access.redhat.com/ubi8/ubi-minimal:8.6 as ubi +FROM registry.access.redhat.com/ubi9-minimal:9.2 as ubi ARG PRODUCT_NAME ARG PRODUCT_VERSION @@ -233,7 +233,7 @@ COPY LICENSE /licenses/mozilla.txt # Its shasum is hardcoded. If you upgrade the dumb-init verion you'll need to # also update the shasum. RUN set -eux && \ - microdnf install -y ca-certificates curl gnupg libcap openssl iputils jq iptables wget unzip tar && \ + microdnf install -y ca-certificates shadow-utils gnupg libcap openssl iputils jq iptables wget unzip tar && \ wget -O /usr/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_x86_64 && \ echo 'e874b55f3279ca41415d290c512a7ba9d08f98041b28ae7c2acb19a545f1c4df /usr/bin/dumb-init' > dumb-init-shasum && \ sha256sum --check dumb-init-shasum && \ diff --git a/GNUmakefile b/GNUmakefile index cfa3191e57d0..8bcbf67f6369 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -7,12 +7,13 @@ SHELL = bash # These version variables can either be a valid string for "go install @" # or the string @DEV to imply use what is currently installed locally. ### -GOLANGCI_LINT_VERSION='v1.46.2' -MOCKERY_VERSION='v2.12.2' +GOLANGCI_LINT_VERSION='v1.51.1' +MOCKERY_VERSION='v2.20.0' BUF_VERSION='v1.4.0' PROTOC_GEN_GO_GRPC_VERSION="v1.2.0" -MOG_VERSION='v0.3.0' +MOG_VERSION='v0.4.0' PROTOC_GO_INJECT_TAG_VERSION='v1.3.0' +PROTOC_GEN_GO_BINARY_VERSION="v0.0.1" DEEP_COPY_VERSION='bc3f5aa5735d8a54961580a3a24422c308c831c2' MOCKED_PB_DIRS= pbdns @@ -153,12 +154,13 @@ dev-build: rm -f ./bin/consul cp ${MAIN_GOPATH}/bin/consul ./bin/consul -dev-docker: linux +dev-docker: linux dev-build @echo "Pulling consul container image - $(CONSUL_IMAGE_VERSION)" - @docker pull consul:$(CONSUL_IMAGE_VERSION) >/dev/null + @docker pull hashicorp/consul:$(CONSUL_IMAGE_VERSION) >/dev/null @echo "Building Consul Development container - $(CONSUL_DEV_IMAGE)" - # 'consul:local' tag is needed to run the integration tests - @docker buildx use default && docker buildx build -t 'consul:local' \ + @# 'consul:local' tag is needed to run the integration tests + @# 'consul-dev:latest' is needed by older workflows + @docker buildx use default && docker buildx build -t 'consul:local' -t '$(CONSUL_DEV_IMAGE)' \ --platform linux/$(GOARCH) \ --build-arg CONSUL_IMAGE_VERSION=$(CONSUL_IMAGE_VERSION) \ --load \ @@ -173,7 +175,7 @@ remote-docker: check-remote-dev-image-env $(MAKE) GOARCH=amd64 linux $(MAKE) GOARCH=arm64 linux @echo "Pulling consul container image - $(CONSUL_IMAGE_VERSION)" - @docker pull consul:$(CONSUL_IMAGE_VERSION) >/dev/null + @docker pull hashicorp/consul:$(CONSUL_IMAGE_VERSION) >/dev/null @echo "Building and Pushing Consul Development container - $(REMOTE_DEV_IMAGE)" @docker buildx use default && docker buildx build -t '$(REMOTE_DEV_IMAGE)' \ --platform linux/amd64,linux/arm64 \ @@ -181,11 +183,11 @@ remote-docker: check-remote-dev-image-env --push \ -f $(CURDIR)/build-support/docker/Consul-Dev-Multiarch.dockerfile $(CURDIR)/pkg/bin/ -# In CircleCI, the linux binary will be attached from a previous step at bin/. This make target +# In CI, the linux binary will be attached from a previous step at bin/. This make target # should only run in CI and not locally. ci.dev-docker: @echo "Pulling consul container image - $(CONSUL_IMAGE_VERSION)" - @docker pull consul:$(CONSUL_IMAGE_VERSION) >/dev/null + @docker pull hashicorp/consul:$(CONSUL_IMAGE_VERSION) >/dev/null @echo "Building Consul Development container - $(CI_DEV_DOCKER_IMAGE_NAME)" @docker build $(NOCACHE) $(QUIET) -t '$(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):$(GIT_COMMIT)' \ --build-arg CONSUL_IMAGE_VERSION=$(CONSUL_IMAGE_VERSION) \ @@ -332,6 +334,8 @@ codegen-tools: deep-copy: @$(SHELL) $(CURDIR)/agent/structs/deep-copy.sh @$(SHELL) $(CURDIR)/agent/proxycfg/deep-copy.sh + @$(SHELL) $(CURDIR)/agent/consul/state/deep-copy.sh + @$(SHELL) $(CURDIR)/agent/config/deep-copy.sh version: @echo -n "Version: " @@ -354,6 +358,7 @@ ui-build-image: @echo "Building UI build container" @docker build $(NOCACHE) $(QUIET) -t $(UI_BUILD_TAG) - < build-support/docker/Build-UI.dockerfile +# Builds consul in a docker container and then dumps executable into ./pkg/bin/... consul-docker: go-build-image @$(SHELL) $(CURDIR)/build-support/scripts/build-docker.sh consul @@ -399,20 +404,10 @@ test-metrics-integ: dev-docker go test -v -timeout=7m ./metrics --target-version local test-connect-ca-providers: -ifeq ("$(CIRCLECI)","true") -# Run in CI - gotestsum --format=short-verbose --junitfile "$(TEST_RESULTS_DIR)/gotestsum-report.xml" -- -cover -coverprofile=coverage.txt ./agent/connect/ca -# Run leader tests that require Vault - gotestsum --format=short-verbose --junitfile "$(TEST_RESULTS_DIR)/gotestsum-report-leader.xml" -- -cover -coverprofile=coverage-leader.txt -run Vault ./agent/consul -# Run agent tests that require Vault - gotestsum --format=short-verbose --junitfile "$(TEST_RESULTS_DIR)/gotestsum-report-agent.xml" -- -cover -coverprofile=coverage-agent.txt -run Vault ./agent -else -# Run locally @echo "Running /agent/connect/ca tests in verbose mode" @go test -v ./agent/connect/ca @go test -v ./agent/consul -run Vault @go test -v ./agent -run Vault -endif .PHONY: proto proto: proto-tools proto-gen proto-mocks @@ -475,6 +470,11 @@ envoy-regen: @find "command/connect/envoy/testdata" -name '*.golden' -delete @go test -tags '$(GOTAGS)' ./command/connect/envoy -update +# Point your web browser to http://localhost:3000/consul to live render docs from ./website/ +.PHONY: docs +docs: + make -C website + .PHONY: help help: $(info available make targets) diff --git a/LICENSE b/LICENSE index c33dcc7c928c..c72625e4cc88 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,5 @@ +Copyright (c) 2013 HashiCorp, Inc. + Mozilla Public License, version 2.0 1. Definitions diff --git a/acl/acl.go b/acl/acl.go index d56383d9f14c..c46677f6fe72 100644 --- a/acl/acl.go +++ b/acl/acl.go @@ -2,6 +2,8 @@ package acl const ( WildcardName = "*" + + ReservedBuiltinPrefix = "builtin/" ) // Config encapsulates all of the generic configuration parameters used for @@ -20,6 +22,10 @@ type ExportFetcher interface { } type ExportedServices struct { + // Data is a map of [namespace] -> [service] -> [list of partitions the service is exported to] + // This includes both the names of typical service instances and their corresponding sidecar proxy + // instance names. Meaning that if "web" is exported, "web-sidecar-proxy" instances will also be + // shown as exported. Data map[string]map[string][]string } diff --git a/acl/acl_oss.go b/acl/acl_ce.go similarity index 95% rename from acl/acl_oss.go rename to acl/acl_ce.go index 48f671ac7ae2..264855035647 100644 --- a/acl/acl_oss.go +++ b/acl/acl_ce.go @@ -14,7 +14,7 @@ const ( const DefaultNamespaceName = "default" type EnterpriseConfig struct { - // no fields in OSS + // no fields in CE } func (_ *EnterpriseConfig) Close() { diff --git a/acl/authorizer_ce.go b/acl/authorizer_ce.go new file mode 100644 index 000000000000..e448c84589e0 --- /dev/null +++ b/acl/authorizer_ce.go @@ -0,0 +1,25 @@ +//go:build !consulent +// +build !consulent + +package acl + +// AuthorizerContext contains extra information that can be +// used in the determination of an ACL enforcement decision. +type AuthorizerContext struct { + // Peer is the name of the peer that the resource was imported from. + Peer string +} + +func (c *AuthorizerContext) PeerOrEmpty() string { + if c == nil { + return "" + } + return c.Peer +} + +// enterpriseAuthorizer stub interface +type enterpriseAuthorizer interface{} + +func enforceEnterprise(_ Authorizer, _ Resource, _ string, _ string, _ *AuthorizerContext) (bool, EnforcementDecision, error) { + return false, Deny, nil +} diff --git a/acl/authorizer_oss.go b/acl/authorizer_oss.go deleted file mode 100644 index 6870a042d3fa..000000000000 --- a/acl/authorizer_oss.go +++ /dev/null @@ -1,14 +0,0 @@ -//go:build !consulent -// +build !consulent - -package acl - -// AuthorizerContext stub -type AuthorizerContext struct{} - -// enterpriseAuthorizer stub interface -type enterpriseAuthorizer interface{} - -func enforceEnterprise(_ Authorizer, _ Resource, _ string, _ string, _ *AuthorizerContext) (bool, EnforcementDecision, error) { - return false, Deny, nil -} diff --git a/acl/enterprisemeta_oss.go b/acl/enterprisemeta_ce.go similarity index 100% rename from acl/enterprisemeta_oss.go rename to acl/enterprisemeta_ce.go diff --git a/acl/errors.go b/acl/errors.go index 7c88704b3444..6e6b483daad0 100644 --- a/acl/errors.go +++ b/acl/errors.go @@ -63,7 +63,6 @@ func IsErrPermissionDenied(err error) bool { // Arguably this should be some sort of union type. // The usage of Cause and the rest of the fields is entirely disjoint. -// type PermissionDeniedError struct { Cause string diff --git a/acl/errors_oss.go b/acl/errors_ce.go similarity index 100% rename from acl/errors_oss.go rename to acl/errors_ce.go diff --git a/acl/policy_authorizer.go b/acl/policy_authorizer.go index 4a24b6bd03cb..7de30d029a9f 100644 --- a/acl/policy_authorizer.go +++ b/acl/policy_authorizer.go @@ -741,7 +741,18 @@ func (p *policyAuthorizer) OperatorWrite(*AuthorizerContext) EnforcementDecision } // NodeRead checks if reading (discovery) of a node is allowed -func (p *policyAuthorizer) NodeRead(name string, _ *AuthorizerContext) EnforcementDecision { +func (p *policyAuthorizer) NodeRead(name string, ctx *AuthorizerContext) EnforcementDecision { + // When reading a node imported from a peer we consider it to be allowed when: + // - The request comes from a locally authenticated service, meaning that it + // has service:write permissions on some name. + // - The requester has permissions to read all nodes in its local cluster, + // therefore it can also read imported nodes. + if ctx.PeerOrEmpty() != "" { + if p.ServiceWriteAny(nil) == Allow { + return Allow + } + return p.NodeReadAll(nil) + } if rule, ok := getPolicy(name, p.nodeRules); ok { return enforce(rule.access, AccessRead) } @@ -779,7 +790,18 @@ func (p *policyAuthorizer) PreparedQueryWrite(prefix string, _ *AuthorizerContex } // ServiceRead checks if reading (discovery) of a service is allowed -func (p *policyAuthorizer) ServiceRead(name string, _ *AuthorizerContext) EnforcementDecision { +func (p *policyAuthorizer) ServiceRead(name string, ctx *AuthorizerContext) EnforcementDecision { + // When reading a service imported from a peer we consider it to be allowed when: + // - The request comes from a locally authenticated service, meaning that it + // has service:write permissions on some name. + // - The requester has permissions to read all services in its local cluster, + // therefore it can also read imported services. + if ctx.PeerOrEmpty() != "" { + if p.ServiceWriteAny(nil) == Allow { + return Allow + } + return p.ServiceReadAll(nil) + } if rule, ok := getPolicy(name, p.serviceRules); ok { return enforce(rule.access, AccessRead) } diff --git a/acl/policy_authorizer_oss.go b/acl/policy_authorizer_ce.go similarity index 100% rename from acl/policy_authorizer_oss.go rename to acl/policy_authorizer_ce.go diff --git a/acl/policy_authorizer_test.go b/acl/policy_authorizer_test.go index 57f41993ae05..0f5f9ca8b6a6 100644 --- a/acl/policy_authorizer_test.go +++ b/acl/policy_authorizer_test.go @@ -20,8 +20,9 @@ func TestPolicyAuthorizer(t *testing.T) { } type aclTest struct { - policy *Policy - checks []aclCheck + policy *Policy + authzContext *AuthorizerContext + checks []aclCheck } cases := map[string]aclTest{ @@ -64,6 +65,101 @@ func TestPolicyAuthorizer(t *testing.T) { {name: "DefaultSnapshot", prefix: "foo", check: checkDefaultSnapshot}, }, }, + "Defaults - from peer": { + policy: &Policy{}, + authzContext: &AuthorizerContext{Peer: "some-peer"}, + checks: []aclCheck{ + {name: "DefaultNodeRead", prefix: "foo", check: checkDefaultNodeRead}, + {name: "DefaultServiceRead", prefix: "foo", check: checkDefaultServiceRead}, + }, + }, + "Peering - ServiceRead allowed with service:write": { + policy: &Policy{PolicyRules: PolicyRules{ + Services: []*ServiceRule{ + { + Name: "foo", + Policy: PolicyWrite, + Intentions: PolicyWrite, + }, + }, + }}, + authzContext: &AuthorizerContext{Peer: "some-peer"}, + checks: []aclCheck{ + {name: "ServiceWriteAny", prefix: "imported-svc", check: checkAllowServiceRead}, + }, + }, + "Peering - ServiceRead allowed with service:read on all": { + policy: &Policy{PolicyRules: PolicyRules{ + ServicePrefixes: []*ServiceRule{ + { + Name: "", + Policy: PolicyRead, + Intentions: PolicyRead, + }, + }, + }}, + authzContext: &AuthorizerContext{Peer: "some-peer"}, + checks: []aclCheck{ + {name: "ServiceReadAll", prefix: "imported-svc", check: checkAllowServiceRead}, + }, + }, + "Peering - ServiceRead not allowed with service:read on single service": { + policy: &Policy{PolicyRules: PolicyRules{ + Services: []*ServiceRule{ + { + Name: "same-name-as-imported", + Policy: PolicyRead, + Intentions: PolicyRead, + }, + }, + }}, + authzContext: &AuthorizerContext{Peer: "some-peer"}, + checks: []aclCheck{ + {name: "ServiceReadAll", prefix: "same-name-as-imported", check: checkDefaultServiceRead}, + }, + }, + "Peering - NodeRead allowed with service:write": { + policy: &Policy{PolicyRules: PolicyRules{ + Services: []*ServiceRule{ + { + Name: "foo", + Policy: PolicyWrite, + }, + }, + }}, + authzContext: &AuthorizerContext{Peer: "some-peer"}, + checks: []aclCheck{ + {name: "ServiceWriteAny", prefix: "imported-svc", check: checkAllowNodeRead}, + }, + }, + "Peering - NodeRead allowed with node:read on all": { + policy: &Policy{PolicyRules: PolicyRules{ + NodePrefixes: []*NodeRule{ + { + Name: "", + Policy: PolicyRead, + }, + }, + }}, + authzContext: &AuthorizerContext{Peer: "some-peer"}, + checks: []aclCheck{ + {name: "NodeReadAll", prefix: "imported-svc", check: checkAllowNodeRead}, + }, + }, + "Peering - NodeRead not allowed with node:read on single service": { + policy: &Policy{PolicyRules: PolicyRules{ + Nodes: []*NodeRule{ + { + Name: "same-name-as-imported", + Policy: PolicyRead, + }, + }, + }}, + authzContext: &AuthorizerContext{Peer: "some-peer"}, + checks: []aclCheck{ + {name: "NodeReadAll", prefix: "same-name-as-imported", check: checkDefaultNodeRead}, + }, + }, "Prefer Exact Matches": { policy: &Policy{PolicyRules: PolicyRules{ Agents: []*AgentRule{ @@ -461,7 +557,7 @@ func TestPolicyAuthorizer(t *testing.T) { t.Run(checkName, func(t *testing.T) { check := check - check.check(t, authz, check.prefix, nil) + check.check(t, authz, check.prefix, tcase.authzContext) }) } }) diff --git a/acl/policy_oss.go b/acl/policy_ce.go similarity index 100% rename from acl/policy_oss.go rename to acl/policy_ce.go diff --git a/acl/policy_merger_oss.go b/acl/policy_merger_ce.go similarity index 100% rename from acl/policy_merger_oss.go rename to acl/policy_merger_ce.go diff --git a/acl/validation.go b/acl/validation.go index 816ec0cae1fb..a8151e121d09 100644 --- a/acl/validation.go +++ b/acl/validation.go @@ -1,16 +1,21 @@ package acl -import "regexp" +import ( + "fmt" + "regexp" + "strings" +) const ( ServiceIdentityNameMaxLength = 256 NodeIdentityNameMaxLength = 256 + PolicyNameMaxLength = 128 ) var ( validServiceIdentityName = regexp.MustCompile(`^[a-z0-9]([a-z0-9\-_]*[a-z0-9])?$`) validNodeIdentityName = regexp.MustCompile(`^[a-z0-9]([a-z0-9\-_]*[a-z0-9])?$`) - validPolicyName = regexp.MustCompile(`^[A-Za-z0-9\-_]{1,128}$`) + validPolicyName = regexp.MustCompile(`^[A-Za-z0-9\-_]+\/?[A-Za-z0-9\-_]*$`) validRoleName = regexp.MustCompile(`^[A-Za-z0-9\-_]{1,256}$`) validAuthMethodName = regexp.MustCompile(`^[A-Za-z0-9\-_]{1,128}$`) ) @@ -37,10 +42,21 @@ func IsValidNodeIdentityName(name string) bool { return validNodeIdentityName.MatchString(name) } -// IsValidPolicyName returns true if the provided name can be used as an -// ACLPolicy Name. -func IsValidPolicyName(name string) bool { - return validPolicyName.MatchString(name) +// ValidatePolicyName returns nil if the provided name can be used as an +// ACLPolicy Name otherwise a useful error is returned. +func ValidatePolicyName(name string) error { + if len(name) < 1 || len(name) > PolicyNameMaxLength { + return fmt.Errorf("Invalid Policy: invalid Name. Length must be greater than 0 and less than %d", PolicyNameMaxLength) + } + + if strings.HasPrefix(name, "/") || strings.HasPrefix(name, ReservedBuiltinPrefix) { + return fmt.Errorf("Invalid Policy: invalid Name. Names cannot be prefixed with '/' or '%s'", ReservedBuiltinPrefix) + } + + if !validPolicyName.MatchString(name) { + return fmt.Errorf("Invalid Policy: invalid Name. Only alphanumeric characters, a single '/', '-' and '_' are allowed") + } + return nil } // IsValidRoleName returns true if the provided name can be used as an diff --git a/acl/validation_test.go b/acl/validation_test.go new file mode 100644 index 000000000000..d5d01e0e9054 --- /dev/null +++ b/acl/validation_test.go @@ -0,0 +1,78 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package acl + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_ValidatePolicyName(t *testing.T) { + for _, tc := range []struct { + description string + name string + valid bool + }{ + { + description: "valid policy", + name: "this-is-valid", + valid: true, + }, + { + description: "empty policy", + name: "", + valid: false, + }, + { + description: "with slash", + name: "policy/with-slash", + valid: true, + }, + { + description: "leading slash", + name: "/no-leading-slash", + valid: false, + }, + { + description: "too many slashes", + name: "too/many/slashes", + valid: false, + }, + { + description: "no double-slash", + name: "no//double-slash", + valid: false, + }, + { + description: "builtin prefix", + name: "builtin/prefix-cannot-be-used", + valid: false, + }, + { + description: "long", + name: "this-policy-name-is-very-very-long-but-it-is-okay-because-it-is-the-max-length-that-we-allow-here-in-a-policy-name-which-is-good", + valid: true, + }, + { + description: "too long", + name: "this-is-a-policy-that-has-one-character-too-many-it-is-way-too-long-for-a-policy-we-do-not-want-a-policy-of-this-length-because-1", + valid: false, + }, + { + description: "invalid start character", + name: "!foo", + valid: false, + }, + { + description: "invalid character", + name: "this%is%bad", + valid: false, + }, + } { + t.Run(tc.description, func(t *testing.T) { + require.Equal(t, tc.valid, ValidatePolicyName(tc.name) == nil) + }) + } +} diff --git a/agent/acl_oss.go b/agent/acl_ce.go similarity index 100% rename from agent/acl_oss.go rename to agent/acl_ce.go diff --git a/agent/acl_endpoint.go b/agent/acl_endpoint.go index 23e43ba5c4aa..9d328263f0d0 100644 --- a/agent/acl_endpoint.go +++ b/agent/acl_endpoint.go @@ -3,6 +3,7 @@ package agent import ( "fmt" "net/http" + "net/url" "strings" "github.com/hashicorp/consul/acl" @@ -131,6 +132,12 @@ func (s *HTTPHandlers) ACLPolicyCRUD(resp http.ResponseWriter, req *http.Request } func (s *HTTPHandlers) ACLPolicyRead(resp http.ResponseWriter, req *http.Request, policyID, policyName string) (interface{}, error) { + // policy name needs to be unescaped in case there were `/` characters + policyName, err := url.QueryUnescape(policyName) + if err != nil { + return nil, err + } + args := structs.ACLPolicyGetRequest{ Datacenter: s.agent.config.Datacenter, PolicyID: policyID, @@ -268,6 +275,7 @@ func (s *HTTPHandlers) ACLTokenList(resp http.ResponseWriter, req *http.Request) args.Policy = req.URL.Query().Get("policy") args.Role = req.URL.Query().Get("role") args.AuthMethod = req.URL.Query().Get("authmethod") + args.ServiceName = req.URL.Query().Get("servicename") if err := parseACLAuthMethodEnterpriseMeta(req, &args.ACLAuthMethodEnterpriseMeta); err != nil { return nil, err } diff --git a/agent/acl_endpoint_test.go b/agent/acl_endpoint_test.go index 5cffef6ee3e6..1538038a6441 100644 --- a/agent/acl_endpoint_test.go +++ b/agent/acl_endpoint_test.go @@ -366,8 +366,8 @@ func TestACL_HTTP(t *testing.T) { policies, ok := raw.(structs.ACLPolicyListStubs) require.True(t, ok) - // 2 we just created + global management - require.Len(t, policies, 3) + // 2 we just created + builtin policies + require.Len(t, policies, 2+len(structs.ACLBuiltinPolicies)) for policyID, expected := range policyMap { found := false @@ -1177,6 +1177,38 @@ func TestACL_HTTP(t *testing.T) { require.Error(t, err) testutil.RequireErrorContains(t, err, "Only lowercase alphanumeric") }) + + t.Run("Create with valid service identity", func(t *testing.T) { + tokenInput := &structs.ACLToken{ + Description: "token for service identity sn1", + ServiceIdentities: []*structs.ACLServiceIdentity{ + { + ServiceName: "sn1", + }, + }, + } + + req, _ := http.NewRequest("PUT", "/v1/acl/token", jsonBody(tokenInput)) + req.Header.Add("X-Consul-Token", "root") + resp := httptest.NewRecorder() + _, err := a.srv.ACLTokenCreate(resp, req) + require.NoError(t, err) + }) + + t.Run("List by ServiceName", func(t *testing.T) { + req, _ := http.NewRequest("GET", "/v1/acl/tokens?servicename=sn1", nil) + req.Header.Add("X-Consul-Token", "root") + resp := httptest.NewRecorder() + raw, err := a.srv.ACLTokenList(resp, req) + require.NoError(t, err) + tokens, ok := raw.(structs.ACLTokenListStubs) + require.True(t, ok) + require.Len(t, tokens, 1) + token := tokens[0] + require.Equal(t, "token for service identity sn1", token.Description) + require.Len(t, token.ServiceIdentities, 1) + require.Equal(t, "sn1", token.ServiceIdentities[0].ServiceName) + }) }) } diff --git a/agent/agent.go b/agent/agent.go index 6d386cd9f754..e4b507535d3e 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -16,6 +16,7 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "time" "github.com/armon/go-metrics" @@ -43,6 +44,7 @@ import ( "github.com/hashicorp/consul/agent/dns" external "github.com/hashicorp/consul/agent/grpc-external" grpcDNS "github.com/hashicorp/consul/agent/grpc-external/services/dns" + middleware "github.com/hashicorp/consul/agent/grpc-middleware" "github.com/hashicorp/consul/agent/hcp/scada" libscada "github.com/hashicorp/consul/agent/hcp/scada" "github.com/hashicorp/consul/agent/local" @@ -399,6 +401,8 @@ type Agent struct { // enterpriseAgent embeds fields that we only access in consul-enterprise builds enterpriseAgent + + enableDebug atomic.Bool } // New process the desired options and creates a new Agent. @@ -554,6 +558,8 @@ func (a *Agent) Start(ctx context.Context) error { c.NodeID = a.config.NodeID a.config = c + a.enableDebug.Store(c.EnableDebug) + if err := a.tlsConfigurator.Update(a.config.TLS); err != nil { return fmt.Errorf("Failed to load TLS configurations after applying auto-config settings: %w", err) } @@ -563,6 +569,7 @@ func (a *Agent) Start(ctx context.Context) error { a.externalGRPCServer = external.NewServer( a.logger.Named("grpc.external"), metrics.Default(), + a.tlsConfigurator, ) if err := a.startLicenseManager(ctx); err != nil { @@ -699,11 +706,12 @@ func (a *Agent) Start(ctx context.Context) error { go localproxycfg.Sync( &lib.StopChannelContext{StopCh: a.shutdownCh}, localproxycfg.SyncConfig{ - Manager: a.proxyConfig, - State: a.State, - Logger: a.proxyConfig.Logger.Named("agent-state"), - Tokens: a.baseDeps.Tokens, - NodeName: a.config.NodeName, + Manager: a.proxyConfig, + State: a.State, + Logger: a.proxyConfig.Logger.Named("agent-state"), + Tokens: a.baseDeps.Tokens, + NodeName: a.config.NodeName, + ResyncFrequency: a.config.LocalProxyConfigResyncInterval, }, ) @@ -770,12 +778,6 @@ func (a *Agent) Start(ctx context.Context) error { go m.Monitor(&lib.StopChannelContext{StopCh: a.shutdownCh}) } - // consul version metric with labels - metrics.SetGaugeWithLabels([]string{"version"}, 1, []metrics.Label{ - {Name: "version", Value: a.config.VersionWithMetadata()}, - {Name: "pre_release", Value: a.config.VersionPrerelease}, - }) - // start a go routine to reload config based on file watcher events if a.configFileWatcher != nil { a.baseDeps.Logger.Debug("starting file watcher") @@ -833,6 +835,7 @@ func (a *Agent) listenAndServeGRPC() error { Manager: a.proxyConfig, GetStore: func() catalogproxycfg.Store { return server.FSM().State() }, Logger: a.proxyConfig.Logger.Named("server-catalog"), + SessionLimiter: a.baseDeps.XDSStreamLimiter, }) go func() { <-a.shutdownCh @@ -849,13 +852,12 @@ func (a *Agent) listenAndServeGRPC() error { return a.delegate.ResolveTokenAndDefaultMeta(id, nil, nil) }, a, - a.baseDeps.XDSStreamLimiter, ) a.xdsServer.Register(a.externalGRPCServer) // Attempt to spawn listeners var listeners []net.Listener - start := func(port_name string, addrs []net.Addr, tlsConf *tls.Config) error { + start := func(port_name string, addrs []net.Addr, protocol middleware.Protocol) error { if len(addrs) < 1 { return nil } @@ -865,10 +867,7 @@ func (a *Agent) listenAndServeGRPC() error { return err } for i := range ln { - // Wrap with TLS, if provided. - if tlsConf != nil { - ln[i] = tls.NewListener(ln[i], tlsConf) - } + ln[i] = middleware.LabelledListener{Listener: ln[i], Protocol: protocol} listeners = append(listeners, ln[i]) } @@ -888,23 +887,16 @@ func (a *Agent) listenAndServeGRPC() error { return nil } - // The original grpc port may spawn in either plain-text or TLS mode (for backwards compatibility). - // TODO: Simplify this block to only spawn plain-text after 1.14 when deprecated TLS support is removed. + // Only allow grpc to spawn with a plain-text listener. if a.config.GRPCPort > 0 { - // Only allow the grpc port to spawn TLS connections if the other grpc_tls port is NOT defined. - var tlsConf *tls.Config = nil - if a.config.GRPCTLSPort <= 0 && a.tlsConfigurator.GRPCServerUseTLS() { - a.logger.Warn("deprecated gRPC TLS configuration detected. Consider using `ports.grpc_tls` instead") - tlsConf = a.tlsConfigurator.IncomingGRPCConfig() - } - if err := start("grpc", a.config.GRPCAddrs, tlsConf); err != nil { + if err := start("grpc", a.config.GRPCAddrs, middleware.ProtocolPlaintext); err != nil { closeListeners(listeners) return err } } // Only allow grpc_tls to spawn with a TLS listener. if a.config.GRPCTLSPort > 0 { - if err := start("grpc_tls", a.config.GRPCTLSAddrs, a.tlsConfigurator.IncomingGRPCConfig()); err != nil { + if err := start("grpc_tls", a.config.GRPCTLSAddrs, middleware.ProtocolTLS); err != nil { closeListeners(listeners) return err } @@ -1040,7 +1032,8 @@ func (a *Agent) listenHTTP() ([]apiServer, error) { for _, l := range listeners { var tlscfg *tls.Config _, isTCP := l.(*tcpKeepAliveListener) - if isTCP && proto == "https" { + isUnix := l.Addr().Network() == "unix" + if (isTCP || isUnix) && proto == "https" { tlscfg = a.tlsConfigurator.IncomingHTTPSConfig() l = tls.NewListener(l, tlscfg) } @@ -1055,13 +1048,13 @@ func (a *Agent) listenHTTP() ([]apiServer, error) { httpServer := &http.Server{ Addr: l.Addr().String(), TLSConfig: tlscfg, - Handler: srv.handler(a.config.EnableDebug), + Handler: srv.handler(), MaxHeaderBytes: a.config.HTTPMaxHeaderBytes, } if libscada.IsCapability(l.Addr()) { // wrap in http2 server handler - httpServer.Handler = h2c.NewHandler(srv.handler(a.config.EnableDebug), &http2.Server{}) + httpServer.Handler = h2c.NewHandler(srv.handler(), &http2.Server{}) } // Load the connlimit helper into the server @@ -1477,7 +1470,12 @@ func newConsulConfig(runtimeCfg *config.RuntimeConfig, logger hclog.Logger) (*co cfg.PeeringEnabled = runtimeCfg.PeeringEnabled cfg.PeeringTestAllowPeerRegistrations = runtimeCfg.PeeringTestAllowPeerRegistrations + cfg.Cloud.ManagementToken = runtimeCfg.Cloud.ManagementToken + + cfg.Reporting.License.Enabled = runtimeCfg.Reporting.License.Enabled + enterpriseConsulConfig(cfg, runtimeCfg) + return cfg, nil } @@ -2193,7 +2191,9 @@ func (a *Agent) readPersistedServiceConfigs() (map[structs.ServiceID]*structs.Se } } - if !acl.EqualPartitions(a.AgentEnterpriseMeta().PartitionOrDefault(), p.PartitionOrDefault()) { + if acl.EqualPartitions("", p.PartitionOrEmpty()) { + p.OverridePartition(a.AgentEnterpriseMeta().PartitionOrDefault()) + } else if !acl.EqualPartitions(a.AgentEnterpriseMeta().PartitionOrDefault(), p.PartitionOrDefault()) { a.logger.Info("Purging service config file in wrong partition", "file", file, "partition", p.PartitionOrDefault(), @@ -3539,6 +3539,11 @@ func (a *Agent) loadServices(conf *config.RuntimeConfig, snap map[structs.CheckI // Register the services from config for _, service := range conf.Services { + // Default service partition to the same as agent + if service.EnterpriseMeta.PartitionOrEmpty() == "" { + service.EnterpriseMeta.OverridePartition(a.AgentEnterpriseMeta().PartitionOrDefault()) + } + ns := service.NodeService() chkTypes, err := service.CheckTypes() if err != nil { @@ -3648,7 +3653,11 @@ func (a *Agent) loadServices(conf *config.RuntimeConfig, snap map[structs.CheckI } } - if !acl.EqualPartitions(a.AgentEnterpriseMeta().PartitionOrDefault(), p.Service.PartitionOrDefault()) { + if acl.EqualPartitions("", p.Service.PartitionOrEmpty()) { + // NOTE: in case loading a service with empty partition (e.g., CE -> ENT), + // we always default the service partition to the agent's partition. + p.Service.OverridePartition(a.AgentEnterpriseMeta().PartitionOrDefault()) + } else if !acl.EqualPartitions(a.AgentEnterpriseMeta().PartitionOrDefault(), p.Service.PartitionOrDefault()) { a.logger.Info("Purging service file in wrong partition", "file", file, "partition", p.Service.EnterpriseMeta.PartitionOrDefault(), @@ -4032,13 +4041,13 @@ func (a *Agent) reloadConfig(autoReload bool) error { {a.config.TLS.HTTPS, newCfg.TLS.HTTPS}, } { if f.oldCfg.KeyFile != f.newCfg.KeyFile { - a.configFileWatcher.Replace(f.oldCfg.KeyFile, f.newCfg.KeyFile) + err = a.configFileWatcher.Replace(f.oldCfg.KeyFile, f.newCfg.KeyFile) if err != nil { return err } } if f.oldCfg.CertFile != f.newCfg.CertFile { - a.configFileWatcher.Replace(f.oldCfg.CertFile, f.newCfg.CertFile) + err = a.configFileWatcher.Replace(f.oldCfg.CertFile, f.newCfg.CertFile) if err != nil { return err } @@ -4153,6 +4162,11 @@ func (a *Agent) reloadConfigInternal(newCfg *config.RuntimeConfig) error { HeartbeatTimeout: newCfg.ConsulRaftHeartbeatTimeout, ElectionTimeout: newCfg.ConsulRaftElectionTimeout, RaftTrailingLogs: newCfg.RaftTrailingLogs, + Reporting: consul.Reporting{ + License: consul.License{ + Enabled: newCfg.Reporting.License.Enabled, + }, + }, } if err := a.delegate.ReloadConfig(cc); err != nil { return err @@ -4178,6 +4192,12 @@ func (a *Agent) reloadConfigInternal(newCfg *config.RuntimeConfig) error { a.proxyConfig.SetUpdateRateLimit(newCfg.XDSUpdateRateLimit) + a.enableDebug.Store(newCfg.EnableDebug) + a.config.EnableDebug = newCfg.EnableDebug + + // update Agent config with new config + a.config = newCfg.DeepCopy() + return nil } diff --git a/agent/agent_oss.go b/agent/agent_ce.go similarity index 100% rename from agent/agent_oss.go rename to agent/agent_ce.go diff --git a/agent/agent_ce_test.go b/agent/agent_ce_test.go new file mode 100644 index 000000000000..ceb90beb0634 --- /dev/null +++ b/agent/agent_ce_test.go @@ -0,0 +1,46 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +//go:build !consulent +// +build !consulent + +package agent + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestAgent_consulConfig_Reporting(t *testing.T) { + if testing.Short() { + t.Skip("too slow for testing.Short") + } + + t.Parallel() + hcl := ` + reporting { + license { + enabled = true + } + } + ` + a := NewTestAgent(t, hcl) + defer a.Shutdown() + require.Equal(t, false, a.consulConfig().Reporting.License.Enabled) +} + +func TestAgent_consulConfig_Reporting_Default(t *testing.T) { + if testing.Short() { + t.Skip("too slow for testing.Short") + } + + t.Parallel() + hcl := ` + reporting { + } + ` + a := NewTestAgent(t, hcl) + defer a.Shutdown() + require.Equal(t, false, a.consulConfig().Reporting.License.Enabled) +} diff --git a/agent/agent_endpoint.go b/agent/agent_endpoint.go index 08324c2c43ba..5191fb1fbc4f 100644 --- a/agent/agent_endpoint.go +++ b/agent/agent_endpoint.go @@ -341,6 +341,7 @@ func (s *HTTPHandlers) AgentServices(resp http.ResponseWriter, req *http.Request var filterExpression string s.parseFilter(req, &filterExpression) + s.defaultMetaPartitionToAgent(&entMeta) authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, &entMeta, nil) if err != nil { return nil, err @@ -425,6 +426,7 @@ func (s *HTTPHandlers) AgentService(resp http.ResponseWriter, req *http.Request) } // need to resolve to default the meta + s.defaultMetaPartitionToAgent(&entMeta) _, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, &entMeta, nil) if err != nil { return nil, err @@ -498,6 +500,7 @@ func (s *HTTPHandlers) AgentChecks(resp http.ResponseWriter, req *http.Request) return nil, err } + s.defaultMetaPartitionToAgent(&entMeta) authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, &entMeta, nil) if err != nil { return nil, err @@ -611,6 +614,21 @@ func (s *HTTPHandlers) AgentMembers(resp http.ResponseWriter, req *http.Request) } } + // filter the members by parsed filter expression + var filterExpression string + s.parseFilter(req, &filterExpression) + if filterExpression != "" { + filter, err := bexpr.CreateFilter(filterExpression, nil, members) + if err != nil { + return nil, err + } + raw, err := filter.Execute(members) + if err != nil { + return nil, err + } + members = raw.([]serf.Member) + } + total := len(members) if err := s.agent.filterMembers(token, &members); err != nil { return nil, err @@ -760,6 +778,7 @@ func (s *HTTPHandlers) AgentRegisterCheck(resp http.ResponseWriter, req *http.Re return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "Bad check status"} } + s.defaultMetaPartitionToAgent(&args.EnterpriseMeta) authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, &args.EnterpriseMeta, nil) if err != nil { return nil, err @@ -808,7 +827,9 @@ func (s *HTTPHandlers) AgentRegisterCheck(resp http.ResponseWriter, req *http.Re func (s *HTTPHandlers) AgentDeregisterCheck(resp http.ResponseWriter, req *http.Request) (interface{}, error) { id := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/deregister/") - checkID := structs.NewCheckID(types.CheckID(id), nil) + + entMeta := acl.NewEnterpriseMetaWithPartition(s.agent.config.PartitionOrDefault(), "") + checkID := structs.NewCheckID(types.CheckID(id), &entMeta) // Get the provided token, if any, and vet against any ACL policies. var token string @@ -900,7 +921,8 @@ func (s *HTTPHandlers) AgentCheckUpdate(resp http.ResponseWriter, req *http.Requ } func (s *HTTPHandlers) agentCheckUpdate(resp http.ResponseWriter, req *http.Request, checkID types.CheckID, status string, output string) (interface{}, error) { - cid := structs.NewCheckID(checkID, nil) + entMeta := acl.NewEnterpriseMetaWithPartition(s.agent.config.PartitionOrDefault(), "") + cid := structs.NewCheckID(checkID, &entMeta) // Get the provided token, if any, and vet against any ACL policies. var token string @@ -990,6 +1012,7 @@ func (s *HTTPHandlers) AgentHealthServiceByID(resp http.ResponseWriter, req *htt s.parseToken(req, &token) // need to resolve to default the meta + s.defaultMetaPartitionToAgent(&entMeta) var authzContext acl.AuthorizerContext authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, &entMeta, &authzContext) if err != nil { @@ -1047,6 +1070,7 @@ func (s *HTTPHandlers) AgentHealthServiceByName(resp http.ResponseWriter, req *h var token string s.parseToken(req, &token) + s.defaultMetaPartitionToAgent(&entMeta) // need to resolve to default the meta var authzContext acl.AuthorizerContext authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, &entMeta, &authzContext) @@ -1124,6 +1148,7 @@ func (s *HTTPHandlers) AgentRegisterService(resp http.ResponseWriter, req *http. var token string s.parseToken(req, &token) + s.defaultMetaPartitionToAgent(&args.EnterpriseMeta) authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, &args.EnterpriseMeta, nil) if err != nil { return nil, err @@ -1240,7 +1265,8 @@ func (s *HTTPHandlers) AgentRegisterService(resp http.ResponseWriter, req *http. func (s *HTTPHandlers) AgentDeregisterService(resp http.ResponseWriter, req *http.Request) (interface{}, error) { serviceID := strings.TrimPrefix(req.URL.Path, "/v1/agent/service/deregister/") - sid := structs.NewServiceID(serviceID, nil) + entMeta := acl.NewEnterpriseMetaWithPartition(s.agent.config.PartitionOrDefault(), "") + sid := structs.NewServiceID(serviceID, &entMeta) // Get the provided token, if any, and vet against any ACL policies. var token string @@ -1276,7 +1302,8 @@ func (s *HTTPHandlers) AgentDeregisterService(resp http.ResponseWriter, req *htt func (s *HTTPHandlers) AgentServiceMaintenance(resp http.ResponseWriter, req *http.Request) (interface{}, error) { // Ensure we have a service ID serviceID := strings.TrimPrefix(req.URL.Path, "/v1/agent/service/maintenance/") - sid := structs.NewServiceID(serviceID, nil) + entMeta := acl.NewEnterpriseMetaWithPartition(s.agent.config.PartitionOrDefault(), "") + sid := structs.NewServiceID(serviceID, &entMeta) if sid.ID == "" { return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "Missing service ID"} diff --git a/agent/agent_endpoint_oss.go b/agent/agent_endpoint_ce.go similarity index 73% rename from agent/agent_endpoint_oss.go rename to agent/agent_endpoint_ce.go index b775b5e79fc4..b54b9df99fa6 100644 --- a/agent/agent_endpoint_oss.go +++ b/agent/agent_endpoint_ce.go @@ -12,3 +12,6 @@ import ( func (s *HTTPHandlers) validateRequestPartition(_ http.ResponseWriter, _ *acl.EnterpriseMeta) bool { return true } + +func (s *HTTPHandlers) defaultMetaPartitionToAgent(entMeta *acl.EnterpriseMeta) { +} diff --git a/agent/agent_endpoint_oss_test.go b/agent/agent_endpoint_ce_test.go similarity index 100% rename from agent/agent_endpoint_oss_test.go rename to agent/agent_endpoint_ce_test.go diff --git a/agent/agent_endpoint_test.go b/agent/agent_endpoint_test.go index 6e52157dfe88..527cf4bdd414 100644 --- a/agent/agent_endpoint_test.go +++ b/agent/agent_endpoint_test.go @@ -1607,7 +1607,7 @@ func TestHTTPHandlers_AgentMetricsStream_ACLDeny(t *testing.T) { resp := httptest.NewRecorder() req, err := http.NewRequestWithContext(ctx, http.MethodGet, "/v1/agent/metrics/stream", nil) require.NoError(t, err) - handle := h.handler(false) + handle := h.handler() handle.ServeHTTP(resp, req) require.Equal(t, http.StatusForbidden, resp.Code) require.Contains(t, resp.Body.String(), "Permission denied") @@ -1644,7 +1644,7 @@ func TestHTTPHandlers_AgentMetricsStream(t *testing.T) { resp := httptest.NewRecorder() req, err := http.NewRequestWithContext(ctx, http.MethodGet, "/v1/agent/metrics/stream", nil) require.NoError(t, err) - handle := h.handler(false) + handle := h.handler() handle.ServeHTTP(resp, req) require.Equal(t, http.StatusOK, resp.Code) @@ -1804,7 +1804,7 @@ func TestAgent_ReloadDoesNotTriggerWatch(t *testing.T) { for i := 1; i < 7; i++ { contents, err := ioutil.ReadFile(tmpFile) if err != nil { - t.Fatalf("should be able to read file, but had: %#v", err) + r.Fatalf("should be able to read file, but had: %#v", err) } contentsStr = string(contents) if contentsStr != "" { @@ -1891,14 +1891,14 @@ func TestAgent_ReloadDoesNotTriggerWatch(t *testing.T) { ensureNothingCritical(r, "red-is-dead") if err := a.reloadConfigInternal(cfg2); err != nil { - t.Fatalf("got error %v want nil", err) + r.Fatalf("got error %v want nil", err) } // We check that reload does not go to critical ensureNothingCritical(r, "red-is-dead") ensureNothingCritical(r, "testing-agent-reload-001") - require.NoError(t, a.updateTTLCheck(checkID, api.HealthPassing, "testing-agent-reload-002")) + require.NoError(r, a.updateTTLCheck(checkID, api.HealthPassing, "testing-agent-reload-002")) ensureNothingCritical(r, "red-is-dead") }) @@ -2887,7 +2887,7 @@ func TestAgent_RegisterCheck_ACLDeny(t *testing.T) { req, _ := http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(nodeCheck)) resp := httptest.NewRecorder() a.srv.h.ServeHTTP(resp, req) - require.Equal(t, http.StatusForbidden, resp.Code) + require.Equal(r, http.StatusForbidden, resp.Code) }) }) @@ -2896,7 +2896,7 @@ func TestAgent_RegisterCheck_ACLDeny(t *testing.T) { req, _ := http.NewRequest("PUT", "/v1/agent/check/register?token="+svcToken.SecretID, jsonReader(nodeCheck)) resp := httptest.NewRecorder() a.srv.h.ServeHTTP(resp, req) - require.Equal(t, http.StatusForbidden, resp.Code) + require.Equal(r, http.StatusForbidden, resp.Code) }) }) @@ -2905,7 +2905,7 @@ func TestAgent_RegisterCheck_ACLDeny(t *testing.T) { req, _ := http.NewRequest("PUT", "/v1/agent/check/register?token="+nodeToken.SecretID, jsonReader(nodeCheck)) resp := httptest.NewRecorder() a.srv.h.ServeHTTP(resp, req) - require.Equal(t, http.StatusOK, resp.Code) + require.Equal(r, http.StatusOK, resp.Code) }) }) @@ -2914,7 +2914,7 @@ func TestAgent_RegisterCheck_ACLDeny(t *testing.T) { req, _ := http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(svcCheck)) resp := httptest.NewRecorder() a.srv.h.ServeHTTP(resp, req) - require.Equal(t, http.StatusForbidden, resp.Code) + require.Equal(r, http.StatusForbidden, resp.Code) }) }) @@ -2923,7 +2923,7 @@ func TestAgent_RegisterCheck_ACLDeny(t *testing.T) { req, _ := http.NewRequest("PUT", "/v1/agent/check/register?token="+nodeToken.SecretID, jsonReader(svcCheck)) resp := httptest.NewRecorder() a.srv.h.ServeHTTP(resp, req) - require.Equal(t, http.StatusForbidden, resp.Code) + require.Equal(r, http.StatusForbidden, resp.Code) }) }) @@ -2932,7 +2932,7 @@ func TestAgent_RegisterCheck_ACLDeny(t *testing.T) { req, _ := http.NewRequest("PUT", "/v1/agent/check/register?token="+svcToken.SecretID, jsonReader(svcCheck)) resp := httptest.NewRecorder() a.srv.h.ServeHTTP(resp, req) - require.Equal(t, http.StatusOK, resp.Code) + require.Equal(r, http.StatusOK, resp.Code) }) }) } @@ -5913,17 +5913,17 @@ func TestAgent_Monitor(t *testing.T) { res := httptest.NewRecorder() a.srv.h.ServeHTTP(res, registerReq) if http.StatusOK != res.Code { - t.Fatalf("expected 200 but got %v", res.Code) + r.Fatalf("expected 200 but got %v", res.Code) } // Wait until we have received some type of logging output - require.Eventually(t, func() bool { + require.Eventually(r, func() bool { return len(resp.Body.Bytes()) > 0 }, 3*time.Second, 100*time.Millisecond) cancelFunc() code := <-codeCh - require.Equal(t, http.StatusOK, code) + require.Equal(r, http.StatusOK, code) got := resp.Body.String() // Only check a substring that we are highly confident in finding @@ -5947,8 +5947,10 @@ func TestAgent_Monitor(t *testing.T) { cancelCtx, cancelFunc := context.WithCancel(context.Background()) req = req.WithContext(cancelCtx) + a.enableDebug.Store(true) + resp := httptest.NewRecorder() - handler := a.srv.handler(true) + handler := a.srv.handler() go handler.ServeHTTP(resp, req) args := &structs.ServiceDefinition{ @@ -5963,11 +5965,11 @@ func TestAgent_Monitor(t *testing.T) { res := httptest.NewRecorder() a.srv.h.ServeHTTP(res, registerReq) if http.StatusOK != res.Code { - t.Fatalf("expected 200 but got %v", res.Code) + r.Fatalf("expected 200 but got %v", res.Code) } // Wait until we have received some type of logging output - require.Eventually(t, func() bool { + require.Eventually(r, func() bool { return len(resp.Body.Bytes()) > 0 }, 3*time.Second, 100*time.Millisecond) cancelFunc() @@ -6000,24 +6002,24 @@ func TestAgent_Monitor(t *testing.T) { res := httptest.NewRecorder() a.srv.h.ServeHTTP(res, registerReq) if http.StatusOK != res.Code { - t.Fatalf("expected 200 but got %v", res.Code) + r.Fatalf("expected 200 but got %v", res.Code) } // Wait until we have received some type of logging output - require.Eventually(t, func() bool { + require.Eventually(r, func() bool { return len(resp.Body.Bytes()) > 0 }, 3*time.Second, 100*time.Millisecond) cancelFunc() code := <-codeCh - require.Equal(t, http.StatusOK, code) + require.Equal(r, http.StatusOK, code) // Each line is output as a separate JSON object, we grab the first and // make sure it can be unmarshalled. firstLine := bytes.Split(resp.Body.Bytes(), []byte("\n"))[0] var output map[string]interface{} if err := json.Unmarshal(firstLine, &output); err != nil { - t.Fatalf("err: %v", err) + r.Fatalf("err: %v", err) } }) }) @@ -6578,7 +6580,7 @@ func TestAgentConnectCARoots_list(t *testing.T) { dec := json.NewDecoder(resp.Body) value := &structs.IndexedCARoots{} - require.NoError(t, dec.Decode(value)) + require.NoError(r, dec.Decode(value)) if ca.ID != value.ActiveRootID { r.Fatalf("%s != %s", ca.ID, value.ActiveRootID) } @@ -6979,7 +6981,7 @@ func TestAgentConnectCALeafCert_goodNotLocal(t *testing.T) { dec := json.NewDecoder(resp.Body) issued2 := &structs.IssuedCert{} - require.NoError(t, dec.Decode(issued2)) + require.NoError(r, dec.Decode(issued2)) if issued.CertPEM == issued2.CertPEM { r.Fatalf("leaf has not updated") } @@ -6991,9 +6993,9 @@ func TestAgentConnectCALeafCert_goodNotLocal(t *testing.T) { } // Verify that the cert is signed by the new CA - requireLeafValidUnderCA(t, issued2, ca) + requireLeafValidUnderCA(r, issued2, ca) - require.NotEqual(t, issued, issued2) + require.NotEqual(r, issued, issued2) }) } } @@ -7096,7 +7098,12 @@ func TestAgentConnectCALeafCert_Vault_doesNotChurnLeafCertsAtIdle(t *testing.T) t.Parallel() testVault := ca.NewTestVaultServer(t) - defer testVault.Stop() + + vaultToken := ca.CreateVaultTokenWithAttrs(t, testVault.Client(), &ca.VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + }) a := StartTestAgent(t, TestAgent{Overrides: fmt.Sprintf(` connect { @@ -7109,7 +7116,7 @@ func TestAgentConnectCALeafCert_Vault_doesNotChurnLeafCertsAtIdle(t *testing.T) intermediate_pki_path = "pki-intermediate/" } } - `, testVault.Addr, testVault.RootToken)}) + `, testVault.Addr, vaultToken)}) defer a.Shutdown() testrpc.WaitForTestAgent(t, a.RPC, "dc1") testrpc.WaitForActiveCARoot(t, a.RPC, "dc1", nil) @@ -7365,11 +7372,11 @@ func TestAgentConnectCALeafCert_secondaryDC_good(t *testing.T) { // Try and sign again (note no index/wait arg since cache should update in // background even if we aren't actively blocking) a2.srv.h.ServeHTTP(resp, req) - require.Equal(t, http.StatusOK, resp.Code) + require.Equal(r, http.StatusOK, resp.Code) dec := json.NewDecoder(resp.Body) issued2 := &structs.IssuedCert{} - require.NoError(t, dec.Decode(issued2)) + require.NoError(r, dec.Decode(issued2)) if issued.CertPEM == issued2.CertPEM { r.Fatalf("leaf has not updated") } @@ -7381,9 +7388,9 @@ func TestAgentConnectCALeafCert_secondaryDC_good(t *testing.T) { } // Verify that the cert is signed by the new CA - requireLeafValidUnderCA(t, issued2, dc1_ca2) + requireLeafValidUnderCA(r, issued2, dc1_ca2) - require.NotEqual(t, issued, issued2) + require.NotEqual(r, issued, issued2) }) } @@ -7393,12 +7400,12 @@ func waitForActiveCARoot(t *testing.T, srv *HTTPHandlers, expect *structs.CARoot resp := httptest.NewRecorder() srv.h.ServeHTTP(resp, req) if http.StatusOK != resp.Code { - t.Fatalf("expected 200 but got %v", resp.Code) + r.Fatalf("expected 200 but got %v", resp.Code) } dec := json.NewDecoder(resp.Body) roots := &structs.IndexedCARoots{} - require.NoError(t, dec.Decode(roots)) + require.NoError(r, dec.Decode(roots)) var root *structs.CARoot for _, r := range roots.Roots { @@ -8024,3 +8031,59 @@ func TestAgent_Services_ExposeConfig(t *testing.T) { } require.Equal(t, srv1.Proxy.ToAPI(), actual.Proxy) } + +func TestAgent_Self_Reload(t *testing.T) { + if testing.Short() { + t.Skip("too slow for testing.Short") + } + + t.Parallel() + + // create new test agent + a := NewTestAgent(t, ` + log_level = "info" + raft_snapshot_threshold = 100 + `) + defer a.Shutdown() + + testrpc.WaitForTestAgent(t, a.RPC, "dc1") + req, _ := http.NewRequest("GET", "/v1/agent/self", nil) + resp := httptest.NewRecorder() + a.srv.h.ServeHTTP(resp, req) + + dec := json.NewDecoder(resp.Body) + val := &Self{} + require.NoError(t, dec.Decode(val)) + + require.Equal(t, "info", val.DebugConfig["Logging"].(map[string]interface{})["LogLevel"]) + require.Equal(t, float64(100), val.DebugConfig["RaftSnapshotThreshold"].(float64)) + + // reload with new config + shim := &delegateConfigReloadShim{delegate: a.delegate} + a.delegate = shim + newCfg := TestConfig(testutil.Logger(t), config.FileSource{ + Name: "Reload", + Format: "hcl", + Data: ` + data_dir = "` + a.Config.DataDir + `" + log_level = "debug" + raft_snapshot_threshold = 200 + `, + }) + if err := a.reloadConfigInternal(newCfg); err != nil { + t.Fatalf("got error %v want nil", err) + } + require.Equal(t, 200, shim.newCfg.RaftSnapshotThreshold) + + // validate new config is reflected in API response + req, _ = http.NewRequest("GET", "/v1/agent/self", nil) + resp = httptest.NewRecorder() + a.srv.h.ServeHTTP(resp, req) + + dec = json.NewDecoder(resp.Body) + val = &Self{} + require.NoError(t, dec.Decode(val)) + require.Equal(t, "debug", val.DebugConfig["Logging"].(map[string]interface{})["LogLevel"]) + require.Equal(t, float64(200), val.DebugConfig["RaftSnapshotThreshold"].(float64)) + +} diff --git a/agent/agent_test.go b/agent/agent_test.go index 2c941e905866..c3037a493dab 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -4,13 +4,14 @@ import ( "bytes" "context" "crypto/md5" + "crypto/rand" "crypto/tls" "crypto/x509" "encoding/base64" "encoding/json" "fmt" "io/ioutil" - "math/rand" + mathrand "math/rand" "net" "net/http" "net/http/httptest" @@ -326,7 +327,9 @@ func TestAgent_HTTPMaxHeaderBytes(t *testing.T) { }, Cache: cache.New(cache.Options{}), } - bd, err = initEnterpriseBaseDeps(bd, nil) + + cfg := config.RuntimeConfig{BuildDate: time.Date(2000, 1, 1, 0, 0, 1, 0, time.UTC)} + bd, err = initEnterpriseBaseDeps(bd, &cfg) require.NoError(t, err) a, err := New(bd) @@ -751,7 +754,7 @@ func testAgent_AddServices_AliasUpdateCheckNotReverted(t *testing.T, extraHCL st func test_createAlias(t *testing.T, agent *TestAgent, chk *structs.CheckType, expectedResult string) func(r *retry.R) { t.Helper() - serviceNum := rand.Int() + serviceNum := mathrand.Int() srv := &structs.NodeService{ Service: fmt.Sprintf("serviceAlias-%d", serviceNum), Tags: []string{"tag1"}, @@ -4178,6 +4181,39 @@ func TestAgent_ReloadConfig_XDSUpdateRateLimit(t *testing.T) { require.Equal(t, rate.Limit(1000), a.proxyConfig.UpdateRateLimit()) } +func TestAgent_ReloadConfig_EnableDebug(t *testing.T) { + if testing.Short() { + t.Skip("too slow for testing.Short") + } + + cfg := fmt.Sprintf(`data_dir = %q`, testutil.TempDir(t, "agent")) + + a := NewTestAgent(t, cfg) + defer a.Shutdown() + + c := TestConfig( + testutil.Logger(t), + config.FileSource{ + Name: t.Name(), + Format: "hcl", + Data: cfg + ` enable_debug = true`, + }, + ) + require.NoError(t, a.reloadConfigInternal(c)) + require.Equal(t, true, a.enableDebug.Load()) + + c = TestConfig( + testutil.Logger(t), + config.FileSource{ + Name: t.Name(), + Format: "hcl", + Data: cfg + ` enable_debug = false`, + }, + ) + require.NoError(t, a.reloadConfigInternal(c)) + require.Equal(t, false, a.enableDebug.Load()) +} + func TestAgent_consulConfig_AutoEncryptAllowTLS(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short") @@ -5418,7 +5454,8 @@ func TestAgent_ListenHTTP_MultipleAddresses(t *testing.T) { Cache: cache.New(cache.Options{}), } - bd, err = initEnterpriseBaseDeps(bd, nil) + cfg := config.RuntimeConfig{BuildDate: time.Date(2000, 1, 1, 0, 0, 1, 0, time.UTC)} + bd, err = initEnterpriseBaseDeps(bd, &cfg) require.NoError(t, err) agent, err := New(bd) @@ -6003,7 +6040,7 @@ func TestAgent_startListeners(t *testing.T) { Cache: cache.New(cache.Options{}), } - bd, err := initEnterpriseBaseDeps(bd, nil) + bd, err := initEnterpriseBaseDeps(bd, &config.RuntimeConfig{}) require.NoError(t, err) agent, err := New(bd) @@ -6134,7 +6171,8 @@ func TestAgent_startListeners_scada(t *testing.T) { Cache: cache.New(cache.Options{}), } - bd, err := initEnterpriseBaseDeps(bd, nil) + cfg := config.RuntimeConfig{BuildDate: time.Date(2000, 1, 1, 0, 0, 1, 0, time.UTC)} + bd, err := initEnterpriseBaseDeps(bd, &cfg) require.NoError(t, err) agent, err := New(bd) diff --git a/agent/auto-config/auto_config.go b/agent/auto-config/auto_config.go index 631ccc75d382..9abbd4bb7f7c 100644 --- a/agent/auto-config/auto_config.go +++ b/agent/auto-config/auto_config.go @@ -225,7 +225,7 @@ func (ac *AutoConfig) introToken() (string, error) { // recordInitialConfiguration is responsible for recording the AutoConfigResponse from // the AutoConfig.InitialConfiguration RPC. It is an all-in-one function to do the following -// * update the Agent token in the token store +// - update the Agent token in the token store func (ac *AutoConfig) recordInitialConfiguration(resp *pbautoconf.AutoConfigResponse) error { ac.autoConfigResponse = resp diff --git a/agent/auto-config/auto_config_oss.go b/agent/auto-config/auto_config_ce.go similarity index 85% rename from agent/auto-config/auto_config_oss.go rename to agent/auto-config/auto_config_ce.go index 95b38aa056ff..29f626568fdb 100644 --- a/agent/auto-config/auto_config_oss.go +++ b/agent/auto-config/auto_config_ce.go @@ -3,7 +3,7 @@ package autoconf -// AutoConfigEnterprise has no fields in OSS +// AutoConfigEnterprise has no fields in CE type AutoConfigEnterprise struct{} // newAutoConfigEnterprise initializes the enterprise AutoConfig struct diff --git a/agent/auto-config/auto_config_oss_test.go b/agent/auto-config/auto_config_ce_test.go similarity index 100% rename from agent/auto-config/auto_config_oss_test.go rename to agent/auto-config/auto_config_ce_test.go diff --git a/agent/auto-config/config_oss.go b/agent/auto-config/config_ce.go similarity index 88% rename from agent/auto-config/config_oss.go rename to agent/auto-config/config_ce.go index a8048954a183..dbd7d90eb3c2 100644 --- a/agent/auto-config/config_oss.go +++ b/agent/auto-config/config_ce.go @@ -6,7 +6,7 @@ package autoconf // EnterpriseConfig stub - only populated in Consul Enterprise type EnterpriseConfig struct{} -// finalize is a noop for OSS +// finalize is a noop for CE func (_ *EnterpriseConfig) validateAndFinalize() error { return nil } diff --git a/agent/auto-config/mock_oss_test.go b/agent/auto-config/mock_ce_test.go similarity index 85% rename from agent/auto-config/mock_oss_test.go rename to agent/auto-config/mock_ce_test.go index 0518753bbbee..1a7acaa48378 100644 --- a/agent/auto-config/mock_oss_test.go +++ b/agent/auto-config/mock_ce_test.go @@ -7,7 +7,7 @@ import ( "testing" ) -// mockedEnterpriseConfig is pretty much just a stub in OSS +// mockedEnterpriseConfig is pretty much just a stub in CE. // It does contain an enterprise config for compatibility // purposes but that in and of itself is just a stub. type mockedEnterpriseConfig struct { diff --git a/agent/blockingquery/blockingquery.go b/agent/blockingquery/blockingquery.go new file mode 100644 index 000000000000..cb46110222de --- /dev/null +++ b/agent/blockingquery/blockingquery.go @@ -0,0 +1,208 @@ +package blockingquery + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/armon/go-metrics" + "github.com/hashicorp/go-memdb" + + "github.com/hashicorp/consul/agent/consul/state" + "github.com/hashicorp/consul/lib" +) + +// Sentinel errors that must be used with blockingQuery +var ( + ErrNotFound = fmt.Errorf("no data found for query") + ErrNotChanged = fmt.Errorf("data did not change for query") +) + +// QueryFn is used to perform a query operation. See Server.blockingQuery for +// the requirements of this function. +type QueryFn func(memdb.WatchSet, *state.Store) error + +// RequestOptions are options used by Server.blockingQuery to modify the +// behaviour of the query operation, or to populate response metadata. +type RequestOptions interface { + GetToken() string + GetMinQueryIndex() uint64 + GetMaxQueryTime() (time.Duration, error) + GetRequireConsistent() bool +} + +// ResponseMeta is an interface used to populate the response struct +// with metadata about the query and the state of the server. +type ResponseMeta interface { + SetLastContact(time.Duration) + SetKnownLeader(bool) + GetIndex() uint64 + SetIndex(uint64) + SetResultsFilteredByACLs(bool) +} + +// FSMServer is interface into the stateful components of a Consul server, such +// as memdb or raft leadership. +type FSMServer interface { + ConsistentRead() error + DecrementBlockingQueries() uint64 + GetShutdownChannel() chan struct{} + GetState() *state.Store + IncrementBlockingQueries() uint64 + RPCQueryTimeout(time.Duration) time.Duration + SetQueryMeta(ResponseMeta, string) +} + +// Query performs a blocking query if opts.GetMinQueryIndex is +// greater than 0, otherwise performs a non-blocking query. Blocking queries will +// block until responseMeta.Index is greater than opts.GetMinQueryIndex, +// or opts.GetMaxQueryTime is reached. Non-blocking queries return immediately +// after performing the query. +// +// If opts.GetRequireConsistent is true, blockingQuery will first verify it is +// still the cluster leader before performing the query. +// +// The query function is expected to be a closure that has access to responseMeta +// so that it can set the Index. The actual result of the query is opaque to blockingQuery. +// +// The query function can return ErrNotFound, which is a sentinel error. Returning +// ErrNotFound indicates that the query found no results, which allows +// blockingQuery to keep blocking until the query returns a non-nil error. +// The query function must take care to set the actual result of the query to +// nil in these cases, otherwise when blockingQuery times out it may return +// a previous result. ErrNotFound will never be returned to the caller, it is +// converted to nil before returning. +// +// The query function can return ErrNotChanged, which is a sentinel error. This +// can only be returned on calls AFTER the first call, as it would not be +// possible to detect the absence of a change on the first call. Returning +// ErrNotChanged indicates that the query results are identical to the prior +// results which allows blockingQuery to keep blocking until the query returns +// a real changed result. +// +// The query function must take care to ensure the actual result of the query +// is either left unmodified or explicitly left in a good state before +// returning, otherwise when blockingQuery times out it may return an +// incomplete or unexpected result. ErrNotChanged will never be returned to the +// caller, it is converted to nil before returning. +// +// If query function returns any other error, the error is returned to the caller +// immediately. +// +// The query function must follow these rules: +// +// 1. to access data it must use the passed in state.Store. +// 2. it must set the responseMeta.Index to an index greater than +// opts.GetMinQueryIndex if the results return by the query have changed. +// 3. any channels added to the memdb.WatchSet must unblock when the results +// returned by the query have changed. +// +// To ensure optimal performance of the query, the query function should make a +// best-effort attempt to follow these guidelines: +// +// 1. only set responseMeta.Index to an index greater than +// opts.GetMinQueryIndex when the results returned by the query have changed. +// 2. any channels added to the memdb.WatchSet should only unblock when the +// results returned by the query have changed. +func Query( + fsmServer FSMServer, + requestOpts RequestOptions, + responseMeta ResponseMeta, + query QueryFn, +) error { + var ctx context.Context = &lib.StopChannelContext{StopCh: fsmServer.GetShutdownChannel()} + + metrics.IncrCounter([]string{"rpc", "query"}, 1) + + minQueryIndex := requestOpts.GetMinQueryIndex() + // Perform a non-blocking query + if minQueryIndex == 0 { + if requestOpts.GetRequireConsistent() { + if err := fsmServer.ConsistentRead(); err != nil { + return err + } + } + + var ws memdb.WatchSet + err := query(ws, fsmServer.GetState()) + fsmServer.SetQueryMeta(responseMeta, requestOpts.GetToken()) + if errors.Is(err, ErrNotFound) || errors.Is(err, ErrNotChanged) { + return nil + } + return err + } + + maxQueryTimeout, err := requestOpts.GetMaxQueryTime() + if err != nil { + return err + } + timeout := fsmServer.RPCQueryTimeout(maxQueryTimeout) + ctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + count := fsmServer.IncrementBlockingQueries() + metrics.SetGauge([]string{"rpc", "queries_blocking"}, float32(count)) + // decrement the count when the function returns. + defer fsmServer.DecrementBlockingQueries() + + var ( + notFound bool + ranOnce bool + ) + + for { + if requestOpts.GetRequireConsistent() { + if err := fsmServer.ConsistentRead(); err != nil { + return err + } + } + + // Operate on a consistent set of state. This makes sure that the + // abandon channel goes with the state that the caller is using to + // build watches. + store := fsmServer.GetState() + + ws := memdb.NewWatchSet() + // This channel will be closed if a snapshot is restored and the + // whole state store is abandoned. + ws.Add(store.AbandonCh()) + + err := query(ws, store) + fsmServer.SetQueryMeta(responseMeta, requestOpts.GetToken()) + + switch { + case errors.Is(err, ErrNotFound): + if notFound { + // query result has not changed + minQueryIndex = responseMeta.GetIndex() + } + notFound = true + case errors.Is(err, ErrNotChanged): + if ranOnce { + // query result has not changed + minQueryIndex = responseMeta.GetIndex() + } + case err != nil: + return err + } + ranOnce = true + + if responseMeta.GetIndex() > minQueryIndex { + return nil + } + + // block until something changes, or the timeout + if err := ws.WatchCtx(ctx); err != nil { + // exit if we've reached the timeout, or other cancellation + return nil + } + + // exit if the state store has been abandoned + select { + case <-store.AbandonCh(): + return nil + default: + } + } +} diff --git a/agent/blockingquery/blockingquery_test.go b/agent/blockingquery/blockingquery_test.go new file mode 100644 index 000000000000..6cfc07c114aa --- /dev/null +++ b/agent/blockingquery/blockingquery_test.go @@ -0,0 +1,4 @@ +package blockingquery + +// TODO: move tests from the consul package, rpc_test.go, TestServer_blockingQuery +// here using mock for FSMServer w/ structs.QueryOptions and structs.QueryOptions diff --git a/agent/cache-types/connect_ca_leaf.go b/agent/cache-types/connect_ca_leaf.go index 0e326e0549ff..4d146c586c88 100644 --- a/agent/cache-types/connect_ca_leaf.go +++ b/agent/cache-types/connect_ca_leaf.go @@ -12,12 +12,11 @@ import ( "github.com/mitchellh/hashstructure" "github.com/hashicorp/consul/acl" - "github.com/hashicorp/consul/lib" - "github.com/hashicorp/consul/agent/cache" "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/consul" "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/lib" ) // Recommended name for registration. @@ -262,10 +261,10 @@ func (c *ConnectCALeaf) rootWatcher(ctx context.Context) { // // Somewhat arbitrarily the current strategy looks like this: // -// 0 60% 90% -// Issued [------------------------------|===============|!!!!!] Expires -// 72h TTL: 0 ~43h ~65h -// 1h TTL: 0 36m 54m +// 0 60% 90% +// Issued [------------------------------|===============|!!!!!] Expires +// 72h TTL: 0 ~43h ~65h +// 1h TTL: 0 36m 54m // // Where |===| is the soft renewal period where we jitter for the first attempt // and |!!!| is the danger zone where we just try immediately. @@ -424,20 +423,25 @@ func (c *ConnectCALeaf) Fetch(opts cache.FetchOptions, req cache.Request) (cache // Setup the timeout chan outside the loop so we don't keep bumping the timeout // later if we loop around. - timeoutCh := time.After(opts.Timeout) + timeoutTimer := time.NewTimer(opts.Timeout) + defer timeoutTimer.Stop() // Setup initial expiry chan. We may change this if root update occurs in the // loop below. - expiresCh := time.After(expiresAt.Sub(now)) + expiresTimer := time.NewTimer(expiresAt.Sub(now)) + defer func() { + // Resolve the timer reference at defer time, so we use the latest one each time. + expiresTimer.Stop() + }() // Current cert is valid so just wait until it expires or we time out. for { select { - case <-timeoutCh: + case <-timeoutTimer.C: // We timed out the request with same cert. return lastResultWithNewState(), nil - case <-expiresCh: + case <-expiresTimer.C: // Cert expired or was force-expired by a root change. return c.generateNewLeaf(reqReal, lastResultWithNewState()) @@ -478,7 +482,9 @@ func (c *ConnectCALeaf) Fetch(opts cache.FetchOptions, req cache.Request) (cache // loop back around, we'll wait at most delay until generating a new cert. if state.forceExpireAfter.Before(expiresAt) { expiresAt = state.forceExpireAfter - expiresCh = time.After(delay) + // Stop the former one and create a new one. + expiresTimer.Stop() + expiresTimer = time.NewTimer(delay) } continue } diff --git a/agent/cache-types/connect_ca_leaf_oss.go b/agent/cache-types/connect_ca_leaf_ce.go similarity index 100% rename from agent/cache-types/connect_ca_leaf_oss.go rename to agent/cache-types/connect_ca_leaf_ce.go diff --git a/agent/cache-types/peerings.go b/agent/cache-types/peerings.go index 7ecbb183e874..9f587598844a 100644 --- a/agent/cache-types/peerings.go +++ b/agent/cache-types/peerings.go @@ -4,22 +4,24 @@ import ( "context" "fmt" "strconv" - "time" - external "github.com/hashicorp/consul/agent/grpc-external" - "github.com/hashicorp/consul/proto/pbpeering" "github.com/mitchellh/hashstructure" "google.golang.org/grpc" "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "github.com/hashicorp/consul/agent/cache" + external "github.com/hashicorp/consul/agent/grpc-external" "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/proto/pbpeering" ) // PeeringListName is the recommended name for registration. const PeeringListName = "peers" +// PeeringListRequest represents the combination of request payload +// and options that would normally be sent over headers. type PeeringListRequest struct { Request *pbpeering.PeeringListRequest structs.QueryOptions @@ -29,13 +31,10 @@ func (r *PeeringListRequest) CacheInfo() cache.RequestInfo { info := cache.RequestInfo{ Token: r.Token, Datacenter: "", - MinIndex: 0, - Timeout: 0, - MustRevalidate: false, - - // OPTIMIZE(peering): Cache.notifyPollingQuery polls at this interval. We need to revisit how that polling works. - // Using an exponential backoff when the result hasn't changed may be preferable. - MaxAge: 1 * time.Second, + MinIndex: r.MinQueryIndex, + Timeout: r.MaxQueryTime, + MaxAge: r.MaxAge, + MustRevalidate: r.MustRevalidate, } v, err := hashstructure.Hash([]interface{}{ @@ -53,7 +52,7 @@ func (r *PeeringListRequest) CacheInfo() cache.RequestInfo { // Peerings supports fetching the list of peers for a given partition or wildcard-specifier. type Peerings struct { - RegisterOptionsNoRefresh + RegisterOptionsBlockingRefresh Client PeeringLister } @@ -64,7 +63,7 @@ type PeeringLister interface { ) (*pbpeering.PeeringListResponse, error) } -func (t *Peerings) Fetch(_ cache.FetchOptions, req cache.Request) (cache.FetchResult, error) { +func (t *Peerings) Fetch(opts cache.FetchOptions, req cache.Request) (cache.FetchResult, error) { var result cache.FetchResult // The request should be a PeeringListRequest. @@ -76,10 +75,17 @@ func (t *Peerings) Fetch(_ cache.FetchOptions, req cache.Request) (cache.FetchRe "Internal cache failure: request wrong type: %T", req) } - // Always allow stale - there's no point in hitting leader if the request is - // going to be served from cache and end up arbitrarily stale anyway. This - // allows cached service-discover to automatically read scale across all - // servers too. + // Lightweight copy this object so that manipulating QueryOptions doesn't race. + dup := *reqReal + reqReal = &dup + + // Set the minimum query index to our current index, so we block + reqReal.QueryOptions.MinQueryIndex = opts.MinIndex + reqReal.QueryOptions.MaxQueryTime = opts.Timeout + + // We allow stale queries here to spread out the RPC load, but peerstream information, including the STATUS, + // will not be returned. Right now this is fine for the watch in proxycfg/mesh_gateway.go, + // but it could be a problem for a future consumer. reqReal.QueryOptions.SetAllowStale(true) ctx, err := external.ContextWithQueryOptions(context.Background(), reqReal.QueryOptions) @@ -88,7 +94,8 @@ func (t *Peerings) Fetch(_ cache.FetchOptions, req cache.Request) (cache.FetchRe } // Fetch - reply, err := t.Client.PeeringList(ctx, reqReal.Request) + var header metadata.MD + reply, err := t.Client.PeeringList(ctx, reqReal.Request, grpc.Header(&header)) if err != nil { // Return an empty result if the error is due to peering being disabled. // This allows mesh gateways to receive an update and confirm that the watch is set. @@ -100,8 +107,19 @@ func (t *Peerings) Fetch(_ cache.FetchOptions, req cache.Request) (cache.FetchRe return result, err } + // This first case is using the legacy index field + // It should be removed in a future version in favor of the index from QueryMeta + if reply.OBSOLETE_Index != 0 { + result.Index = reply.OBSOLETE_Index + } else { + meta, err := external.QueryMetaFromGRPCMeta(header) + if err != nil { + return result, fmt.Errorf("could not convert gRPC metadata to query meta: %w", err) + } + result.Index = meta.GetIndex() + } + result.Value = reply - result.Index = reply.Index return result, nil } diff --git a/agent/cache-types/peerings_test.go b/agent/cache-types/peerings_test.go index e96e6256e931..525de96ed885 100644 --- a/agent/cache-types/peerings_test.go +++ b/agent/cache-types/peerings_test.go @@ -5,14 +5,16 @@ import ( "testing" "time" - "github.com/mitchellh/copystructure" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" grpcstatus "google.golang.org/grpc/status" "github.com/hashicorp/consul/agent/cache" + external "github.com/hashicorp/consul/agent/grpc-external" + "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/proto/pbpeering" ) @@ -21,7 +23,6 @@ func TestPeerings(t *testing.T) { typ := &Peerings{Client: client} resp := &pbpeering.PeeringListResponse{ - Index: 48, Peerings: []*pbpeering.Peering{ { Name: "peer1", @@ -33,12 +34,38 @@ func TestPeerings(t *testing.T) { } // Expect the proper call. - // This also returns the canned response above. - client.On("PeeringList", mock.Anything, mock.Anything). - Return(resp, nil) + // This also set the gRPC metadata returned by pointer. + client.On("PeeringList", mock.Anything, mock.Anything, mock.Anything). + Return(resp, nil). + Run(func(args mock.Arguments) { + // Validate Query Options + ctx := args.Get(0).(context.Context) + out, ok := metadata.FromOutgoingContext(ctx) + require.True(t, ok) + ctx = metadata.NewIncomingContext(ctx, out) + + options, err := external.QueryOptionsFromContext(ctx) + require.NoError(t, err) + require.Equal(t, uint64(28), options.MinQueryIndex) + require.Equal(t, time.Duration(1100), options.MaxQueryTime) + require.True(t, options.AllowStale) + + // Send back Query Meta on pointer of header + header := args.Get(2).(grpc.HeaderCallOption) + qm := structs.QueryMeta{ + Index: 48, + } + + md, err := external.GRPCMetadataFromQueryMeta(qm) + require.NoError(t, err) + *header.HeaderAddr = md + }) // Fetch and assert against the result. - result, err := typ.Fetch(cache.FetchOptions{}, &PeeringListRequest{ + result, err := typ.Fetch(cache.FetchOptions{ + MinIndex: 28, + Timeout: time.Duration(1100), + }, &PeeringListRequest{ Request: &pbpeering.PeeringListRequest{}, }) require.NoError(t, err) @@ -55,7 +82,7 @@ func TestPeerings_PeeringDisabled(t *testing.T) { var resp *pbpeering.PeeringListResponse // Expect the proper call, but return the peering disabled error - client.On("PeeringList", mock.Anything, mock.Anything). + client.On("PeeringList", mock.Anything, mock.Anything, mock.Anything). Return(resp, grpcstatus.Error(codes.FailedPrecondition, "peering must be enabled to use this endpoint")) // Fetch and assert against the result. @@ -78,54 +105,3 @@ func TestPeerings_badReqType(t *testing.T) { require.Error(t, err) require.Contains(t, err.Error(), "wrong type") } - -// This test asserts that we can continuously poll this cache type, given that it doesn't support blocking. -func TestPeerings_MultipleUpdates(t *testing.T) { - c := cache.New(cache.Options{}) - - client := NewMockPeeringLister(t) - - // On each mock client call to PeeringList we will increment the index by 1 - // to simulate new data arriving. - resp := &pbpeering.PeeringListResponse{ - Index: uint64(0), - } - - client.On("PeeringList", mock.Anything, mock.Anything). - Return(func(ctx context.Context, in *pbpeering.PeeringListRequest, opts ...grpc.CallOption) *pbpeering.PeeringListResponse { - resp.Index++ - // Avoids triggering the race detection by copying the output - copyResp, err := copystructure.Copy(resp) - require.NoError(t, err) - output := copyResp.(*pbpeering.PeeringListResponse) - return output - }, nil) - - c.RegisterType(PeeringListName, &Peerings{Client: client}) - - ch := make(chan cache.UpdateEvent) - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - t.Cleanup(cancel) - - require.NoError(t, c.Notify(ctx, PeeringListName, &PeeringListRequest{ - Request: &pbpeering.PeeringListRequest{}, - }, "updates", ch)) - - i := uint64(1) - for { - select { - case <-ctx.Done(): - t.Fatal("context deadline exceeded") - return - case update := <-ch: - // Expect to receive updates for increasing indexes serially. - actual := update.Result.(*pbpeering.PeeringListResponse) - require.Equal(t, i, actual.Index) - i++ - - if i > 3 { - return - } - } - } -} diff --git a/agent/cache-types/rpc.go b/agent/cache-types/rpc.go index cc0a4a8e5406..445ca204630d 100644 --- a/agent/cache-types/rpc.go +++ b/agent/cache-types/rpc.go @@ -3,6 +3,7 @@ package cachetype // RPC is an interface that an RPC client must implement. This is a helper // interface that is implemented by the agent delegate so that Type // implementations can request RPC access. +// //go:generate mockery --name RPC --inpackage type RPC interface { RPC(method string, args interface{}, reply interface{}) error diff --git a/agent/cache-types/trust_bundle.go b/agent/cache-types/trust_bundle.go index addc65ac94c0..f9015d9d259d 100644 --- a/agent/cache-types/trust_bundle.go +++ b/agent/cache-types/trust_bundle.go @@ -4,10 +4,10 @@ import ( "context" "fmt" "strconv" - "time" "github.com/mitchellh/hashstructure" "google.golang.org/grpc" + "google.golang.org/grpc/metadata" "github.com/hashicorp/consul/agent/cache" external "github.com/hashicorp/consul/agent/grpc-external" @@ -18,6 +18,8 @@ import ( // Recommended name for registration. const TrustBundleReadName = "peer-trust-bundle" +// TrustBundleReadRequest represents the combination of request payload +// and options that would normally be sent over headers. type TrustBundleReadRequest struct { Request *pbpeering.TrustBundleReadRequest structs.QueryOptions @@ -27,13 +29,10 @@ func (r *TrustBundleReadRequest) CacheInfo() cache.RequestInfo { info := cache.RequestInfo{ Token: r.Token, Datacenter: "", - MinIndex: 0, - Timeout: 0, - MustRevalidate: false, - - // OPTIMIZE(peering): Cache.notifyPollingQuery polls at this interval. We need to revisit how that polling works. - // Using an exponential backoff when the result hasn't changed may be preferable. - MaxAge: 1 * time.Second, + MinIndex: r.MinQueryIndex, + Timeout: r.MaxQueryTime, + MaxAge: r.MaxAge, + MustRevalidate: r.MustRevalidate, } v, err := hashstructure.Hash([]interface{}{ @@ -53,7 +52,7 @@ func (r *TrustBundleReadRequest) CacheInfo() cache.RequestInfo { // TrustBundle supports fetching discovering service instances via prepared // queries. type TrustBundle struct { - RegisterOptionsNoRefresh + RegisterOptionsBlockingRefresh Client TrustBundleReader } @@ -64,7 +63,7 @@ type TrustBundleReader interface { ) (*pbpeering.TrustBundleReadResponse, error) } -func (t *TrustBundle) Fetch(_ cache.FetchOptions, req cache.Request) (cache.FetchResult, error) { +func (t *TrustBundle) Fetch(opts cache.FetchOptions, req cache.Request) (cache.FetchResult, error) { var result cache.FetchResult // The request should be a TrustBundleReadRequest. @@ -76,6 +75,14 @@ func (t *TrustBundle) Fetch(_ cache.FetchOptions, req cache.Request) (cache.Fetc "Internal cache failure: request wrong type: %T", req) } + // Lightweight copy this object so that manipulating QueryOptions doesn't race. + dup := *reqReal + reqReal = &dup + + // Set the minimum query index to our current index, so we block + reqReal.QueryOptions.MinQueryIndex = opts.MinIndex + reqReal.QueryOptions.MaxQueryTime = opts.Timeout + // Always allow stale - there's no point in hitting leader if the request is // going to be served from cache and end up arbitrarily stale anyway. This // allows cached service-discover to automatically read scale across all @@ -88,13 +95,25 @@ func (t *TrustBundle) Fetch(_ cache.FetchOptions, req cache.Request) (cache.Fetc return result, err } - reply, err := t.Client.TrustBundleRead(ctx, reqReal.Request) + var header metadata.MD + reply, err := t.Client.TrustBundleRead(ctx, reqReal.Request, grpc.Header(&header)) if err != nil { return result, err } + // This first case is using the legacy index field + // It should be removed in a future version in favor of the index from QueryMeta + if reply.OBSOLETE_Index != 0 { + result.Index = reply.OBSOLETE_Index + } else { + meta, err := external.QueryMetaFromGRPCMeta(header) + if err != nil { + return result, fmt.Errorf("could not convert gRPC metadata to query meta: %w", err) + } + result.Index = meta.GetIndex() + } + result.Value = reply - result.Index = reply.Index return result, nil } diff --git a/agent/cache-types/trust_bundle_test.go b/agent/cache-types/trust_bundle_test.go index ea36e8d8a7cf..80347132e722 100644 --- a/agent/cache-types/trust_bundle_test.go +++ b/agent/cache-types/trust_bundle_test.go @@ -7,8 +7,12 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" "github.com/hashicorp/consul/agent/cache" + external "github.com/hashicorp/consul/agent/grpc-external" + "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/proto/pbpeering" ) @@ -17,7 +21,6 @@ func TestTrustBundle(t *testing.T) { typ := &TrustBundle{Client: client} resp := &pbpeering.TrustBundleReadResponse{ - Index: 48, Bundle: &pbpeering.PeeringTrustBundle{ PeerName: "peer1", RootPEMs: []string{"peer1-roots"}, @@ -26,15 +29,41 @@ func TestTrustBundle(t *testing.T) { // Expect the proper call. // This also returns the canned response above. - client.On("TrustBundleRead", mock.Anything, mock.Anything). + client.On("TrustBundleRead", mock.Anything, mock.Anything, mock.Anything). Run(func(args mock.Arguments) { + // Validate Query Options + ctx := args.Get(0).(context.Context) + out, ok := metadata.FromOutgoingContext(ctx) + require.True(t, ok) + ctx = metadata.NewIncomingContext(ctx, out) + + options, err := external.QueryOptionsFromContext(ctx) + require.NoError(t, err) + require.Equal(t, uint64(28), options.MinQueryIndex) + require.Equal(t, time.Duration(1100), options.MaxQueryTime) + require.True(t, options.AllowStale) + + // Validate Request req := args.Get(1).(*pbpeering.TrustBundleReadRequest) require.Equal(t, "foo", req.Name) + + // Send back Query Meta on pointer of header + header := args.Get(2).(grpc.HeaderCallOption) + qm := structs.QueryMeta{ + Index: 48, + } + + md, err := external.GRPCMetadataFromQueryMeta(qm) + require.NoError(t, err) + *header.HeaderAddr = md }). Return(resp, nil) // Fetch and assert against the result. - result, err := typ.Fetch(cache.FetchOptions{}, &TrustBundleReadRequest{ + result, err := typ.Fetch(cache.FetchOptions{ + MinIndex: 28, + Timeout: time.Duration(1100), + }, &TrustBundleReadRequest{ Request: &pbpeering.TrustBundleReadRequest{ Name: "foo", }, @@ -56,55 +85,3 @@ func TestTrustBundle_badReqType(t *testing.T) { require.Error(t, err) require.Contains(t, err.Error(), "wrong type") } - -// This test asserts that we can continuously poll this cache type, given that it doesn't support blocking. -func TestTrustBundle_MultipleUpdates(t *testing.T) { - c := cache.New(cache.Options{}) - - client := NewMockTrustBundleReader(t) - - // On each mock client call to TrustBundleList by service we will increment the index by 1 - // to simulate new data arriving. - resp := &pbpeering.TrustBundleReadResponse{ - Index: uint64(0), - } - - client.On("TrustBundleRead", mock.Anything, mock.Anything). - Run(func(args mock.Arguments) { - req := args.Get(1).(*pbpeering.TrustBundleReadRequest) - require.Equal(t, "foo", req.Name) - - // Increment on each call. - resp.Index++ - }). - Return(resp, nil) - - c.RegisterType(TrustBundleReadName, &TrustBundle{Client: client}) - - ch := make(chan cache.UpdateEvent) - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - t.Cleanup(cancel) - - err := c.Notify(ctx, TrustBundleReadName, &TrustBundleReadRequest{ - Request: &pbpeering.TrustBundleReadRequest{Name: "foo"}, - }, "updates", ch) - require.NoError(t, err) - - i := uint64(1) - for { - select { - case <-ctx.Done(): - t.Fatal("context deadline exceeded") - return - case update := <-ch: - // Expect to receive updates for increasing indexes serially. - actual := update.Result.(*pbpeering.TrustBundleReadResponse) - require.Equal(t, i, actual.Index) - i++ - - if i > 3 { - return - } - } - } -} diff --git a/agent/cache-types/trust_bundles.go b/agent/cache-types/trust_bundles.go index 47f411f02fe4..010848f5b865 100644 --- a/agent/cache-types/trust_bundles.go +++ b/agent/cache-types/trust_bundles.go @@ -4,11 +4,11 @@ import ( "context" "fmt" "strconv" - "time" "github.com/mitchellh/hashstructure" "google.golang.org/grpc" "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "github.com/hashicorp/consul/agent/cache" @@ -20,6 +20,8 @@ import ( // Recommended name for registration. const TrustBundleListName = "trust-bundles" +// TrustBundleListRequest represents the combination of request payload +// and options that would normally be sent over headers. type TrustBundleListRequest struct { Request *pbpeering.TrustBundleListByServiceRequest structs.QueryOptions @@ -29,13 +31,10 @@ func (r *TrustBundleListRequest) CacheInfo() cache.RequestInfo { info := cache.RequestInfo{ Token: r.Token, Datacenter: "", - MinIndex: 0, - Timeout: 0, - MustRevalidate: false, - - // OPTIMIZE(peering): Cache.notifyPollingQuery polls at this interval. We need to revisit how that polling works. - // Using an exponential backoff when the result hasn't changed may be preferable. - MaxAge: 1 * time.Second, + MinIndex: r.MinQueryIndex, + Timeout: r.MaxQueryTime, + MaxAge: r.MaxAge, + MustRevalidate: r.MustRevalidate, } v, err := hashstructure.Hash([]interface{}{ @@ -57,7 +56,7 @@ func (r *TrustBundleListRequest) CacheInfo() cache.RequestInfo { // TrustBundles supports fetching discovering service instances via prepared // queries. type TrustBundles struct { - RegisterOptionsNoRefresh + RegisterOptionsBlockingRefresh Client TrustBundleLister } @@ -68,7 +67,7 @@ type TrustBundleLister interface { ) (*pbpeering.TrustBundleListByServiceResponse, error) } -func (t *TrustBundles) Fetch(_ cache.FetchOptions, req cache.Request) (cache.FetchResult, error) { +func (t *TrustBundles) Fetch(opts cache.FetchOptions, req cache.Request) (cache.FetchResult, error) { var result cache.FetchResult // The request should be a TrustBundleListRequest. @@ -80,6 +79,14 @@ func (t *TrustBundles) Fetch(_ cache.FetchOptions, req cache.Request) (cache.Fet "Internal cache failure: request wrong type: %T", req) } + // Lightweight copy this object so that manipulating QueryOptions doesn't race. + dup := *reqReal + reqReal = &dup + + // Set the minimum query index to our current index, so we block + reqReal.QueryOptions.MinQueryIndex = opts.MinIndex + reqReal.QueryOptions.MaxQueryTime = opts.Timeout + // Always allow stale - there's no point in hitting leader if the request is // going to be served from cache and end up arbitrarily stale anyway. This // allows cached service-discover to automatically read scale across all @@ -92,20 +99,32 @@ func (t *TrustBundles) Fetch(_ cache.FetchOptions, req cache.Request) (cache.Fet return result, err } - reply, err := t.Client.TrustBundleListByService(ctx, reqReal.Request) + var header metadata.MD + reply, err := t.Client.TrustBundleListByService(ctx, reqReal.Request, grpc.Header(&header)) if err != nil { // Return an empty result if the error is due to peering being disabled. // This allows mesh gateways to receive an update and confirm that the watch is set. if e, ok := status.FromError(err); ok && e.Code() == codes.FailedPrecondition { result.Index = 1 - result.Value = &pbpeering.TrustBundleListByServiceResponse{Index: 1} + result.Value = &pbpeering.TrustBundleListByServiceResponse{OBSOLETE_Index: 1} return result, nil } return result, err } + // This first case is using the legacy index field + // It should be removed in a future version in favor of the index from QueryMeta + if reply.OBSOLETE_Index != 0 { + result.Index = reply.OBSOLETE_Index + } else { + meta, err := external.QueryMetaFromGRPCMeta(header) + if err != nil { + return result, fmt.Errorf("could not convert gRPC metadata to query meta: %w", err) + } + result.Index = meta.GetIndex() + } + result.Value = reply - result.Index = reply.Index return result, nil } diff --git a/agent/cache-types/trust_bundles_test.go b/agent/cache-types/trust_bundles_test.go index 733becdd60b2..0f104253ef5e 100644 --- a/agent/cache-types/trust_bundles_test.go +++ b/agent/cache-types/trust_bundles_test.go @@ -7,10 +7,14 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "google.golang.org/grpc" "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" grpcstatus "google.golang.org/grpc/status" "github.com/hashicorp/consul/agent/cache" + external "github.com/hashicorp/consul/agent/grpc-external" + "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/proto/pbpeering" ) @@ -19,7 +23,6 @@ func TestTrustBundles(t *testing.T) { typ := &TrustBundles{Client: client} resp := &pbpeering.TrustBundleListByServiceResponse{ - Index: 48, Bundles: []*pbpeering.PeeringTrustBundle{ { PeerName: "peer1", @@ -30,15 +33,41 @@ func TestTrustBundles(t *testing.T) { // Expect the proper call. // This also returns the canned response above. - client.On("TrustBundleListByService", mock.Anything, mock.Anything). + client.On("TrustBundleListByService", mock.Anything, mock.Anything, mock.Anything). Run(func(args mock.Arguments) { + // Validate Query Options + ctx := args.Get(0).(context.Context) + out, ok := metadata.FromOutgoingContext(ctx) + require.True(t, ok) + ctx = metadata.NewIncomingContext(ctx, out) + + options, err := external.QueryOptionsFromContext(ctx) + require.NoError(t, err) + require.Equal(t, uint64(28), options.MinQueryIndex) + require.Equal(t, time.Duration(1100), options.MaxQueryTime) + require.True(t, options.AllowStale) + + // Validate Request req := args.Get(1).(*pbpeering.TrustBundleListByServiceRequest) require.Equal(t, "foo", req.ServiceName) + + // Send back Query Meta on pointer of header + header := args.Get(2).(grpc.HeaderCallOption) + qm := structs.QueryMeta{ + Index: 48, + } + + md, err := external.GRPCMetadataFromQueryMeta(qm) + require.NoError(t, err) + *header.HeaderAddr = md }). Return(resp, nil) // Fetch and assert against the result. - result, err := typ.Fetch(cache.FetchOptions{}, &TrustBundleListRequest{ + result, err := typ.Fetch(cache.FetchOptions{ + MinIndex: 28, + Timeout: time.Duration(1100), + }, &TrustBundleListRequest{ Request: &pbpeering.TrustBundleListByServiceRequest{ ServiceName: "foo", }, @@ -58,7 +87,7 @@ func TestTrustBundles_PeeringDisabled(t *testing.T) { // Expect the proper call. // This also returns the canned response above. - client.On("TrustBundleListByService", mock.Anything, mock.Anything). + client.On("TrustBundleListByService", mock.Anything, mock.Anything, mock.Anything). Return(resp, grpcstatus.Error(codes.FailedPrecondition, "peering must be enabled to use this endpoint")) // Fetch and assert against the result. @@ -83,55 +112,3 @@ func TestTrustBundles_badReqType(t *testing.T) { require.Error(t, err) require.Contains(t, err.Error(), "wrong type") } - -// This test asserts that we can continuously poll this cache type, given that it doesn't support blocking. -func TestTrustBundles_MultipleUpdates(t *testing.T) { - c := cache.New(cache.Options{}) - - client := NewMockTrustBundleLister(t) - - // On each mock client call to TrustBundleList by service we will increment the index by 1 - // to simulate new data arriving. - resp := &pbpeering.TrustBundleListByServiceResponse{ - Index: uint64(0), - } - - client.On("TrustBundleListByService", mock.Anything, mock.Anything). - Run(func(args mock.Arguments) { - req := args.Get(1).(*pbpeering.TrustBundleListByServiceRequest) - require.Equal(t, "foo", req.ServiceName) - - // Increment on each call. - resp.Index++ - }). - Return(resp, nil) - - c.RegisterType(TrustBundleListName, &TrustBundles{Client: client}) - - ch := make(chan cache.UpdateEvent) - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - t.Cleanup(cancel) - - err := c.Notify(ctx, TrustBundleListName, &TrustBundleListRequest{ - Request: &pbpeering.TrustBundleListByServiceRequest{ServiceName: "foo"}, - }, "updates", ch) - require.NoError(t, err) - - i := uint64(1) - for { - select { - case <-ctx.Done(): - t.Fatal("context deadline exceeded") - return - case update := <-ch: - // Expect to receive updates for increasing indexes serially. - resp := update.Result.(*pbpeering.TrustBundleListByServiceResponse) - require.Equal(t, i, resp.Index) - i++ - - if i > 3 { - return - } - } - } -} diff --git a/agent/cache/cache.go b/agent/cache/cache.go index ea537cc9e6f7..5871d826fde4 100644 --- a/agent/cache/cache.go +++ b/agent/cache/cache.go @@ -91,7 +91,7 @@ const ( // rate limiter settings. // DefaultEntryFetchRate is the default rate at which cache entries can - // be fetch. This defaults to not being unlimited + // be fetch. This defaults to not being limited DefaultEntryFetchRate = rate.Inf // DefaultEntryFetchMaxBurst is the number of cache entry fetches that can @@ -533,7 +533,10 @@ RETRY_GET: // Set our timeout channel if we must if r.Info.Timeout > 0 && timeoutCh == nil { - timeoutCh = time.After(r.Info.Timeout) + timeoutTimer := time.NewTimer(r.Info.Timeout) + defer timeoutTimer.Stop() + + timeoutCh = timeoutTimer.C } // At this point, we know we either don't have a value at all or the diff --git a/agent/cache/mock_Request.go b/agent/cache/mock_Request.go index dd585c57e026..30fda56461c0 100644 --- a/agent/cache/mock_Request.go +++ b/agent/cache/mock_Request.go @@ -1,12 +1,8 @@ -// Code generated by mockery v2.12.2. DO NOT EDIT. +// Code generated by mockery v2.15.0. DO NOT EDIT. package cache -import ( - testing "testing" - - mock "github.com/stretchr/testify/mock" -) +import mock "github.com/stretchr/testify/mock" // MockRequest is an autogenerated mock type for the Request type type MockRequest struct { @@ -27,8 +23,13 @@ func (_m *MockRequest) CacheInfo() RequestInfo { return r0 } -// NewMockRequest creates a new instance of MockRequest. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockRequest(t testing.TB) *MockRequest { +type mockConstructorTestingTNewMockRequest interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockRequest creates a new instance of MockRequest. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockRequest(t mockConstructorTestingTNewMockRequest) *MockRequest { mock := &MockRequest{} mock.Mock.Test(t) diff --git a/agent/cache/mock_Type.go b/agent/cache/mock_Type.go index 76642bb5ce0d..9f1a32422214 100644 --- a/agent/cache/mock_Type.go +++ b/agent/cache/mock_Type.go @@ -1,12 +1,8 @@ -// Code generated by mockery v2.12.2. DO NOT EDIT. +// Code generated by mockery v2.15.0. DO NOT EDIT. package cache -import ( - testing "testing" - - mock "github.com/stretchr/testify/mock" -) +import mock "github.com/stretchr/testify/mock" // MockType is an autogenerated mock type for the Type type type MockType struct { @@ -48,8 +44,13 @@ func (_m *MockType) RegisterOptions() RegisterOptions { return r0 } -// NewMockType creates a new instance of MockType. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockType(t testing.TB) *MockType { +type mockConstructorTestingTNewMockType interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockType creates a new instance of MockType. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockType(t mockConstructorTestingTNewMockType) *MockType { mock := &MockType{} mock.Mock.Test(t) diff --git a/agent/cache/request.go b/agent/cache/request.go index 48023882d464..3dc4ea86f8af 100644 --- a/agent/cache/request.go +++ b/agent/cache/request.go @@ -8,6 +8,7 @@ import ( // // This interface is typically implemented by request structures in // the agent/structs package. +// //go:generate mockery --name Request --inpackage type Request interface { // CacheInfo returns information used for caching this request. diff --git a/agent/cache/type.go b/agent/cache/type.go index 05b28ad1b592..fbe6978aa2f9 100644 --- a/agent/cache/type.go +++ b/agent/cache/type.go @@ -5,6 +5,7 @@ import ( ) // Type implements the logic to fetch certain types of data. +// //go:generate mockery --name Type --inpackage type Type interface { // Fetch fetches a single unique item. diff --git a/agent/cache/watch.go b/agent/cache/watch.go index f99f85c04ba4..abd247c4f1c5 100644 --- a/agent/cache/watch.go +++ b/agent/cache/watch.go @@ -7,6 +7,7 @@ import ( "time" "github.com/hashicorp/consul/lib" + "google.golang.org/protobuf/proto" ) // UpdateEvent is a struct summarizing an update to a cache entry @@ -181,7 +182,7 @@ func (c *Cache) notifyPollingQuery(ctx context.Context, r getOptions, correlatio } // Check for a change in the value or an index change - if index < meta.Index || !reflect.DeepEqual(lastValue, res) { + if index < meta.Index || !isEqual(lastValue, res) { cb(ctx, UpdateEvent{correlationID, res, meta, err}) // Update index and lastValue @@ -251,3 +252,20 @@ func (c *Cache) notifyPollingQuery(ctx context.Context, r getOptions, correlatio } } } + +// isEqual compares two values for deep equality. Protobuf objects +// require us to use a special comparison because cloned structs +// may have non-exported fields that differ. For non-protobuf objects, +// we use reflect.DeepEqual(). +func isEqual(a, b interface{}) bool { + // TODO move this logic into an interface so that each type can determine + // its own logic for equality, rather than a centralized type-cast like this. + if a != nil && b != nil { + a, aok := a.(proto.Message) + b, bok := b.(proto.Message) + if aok && bok { + return proto.Equal(a, b) + } + } + return reflect.DeepEqual(a, b) +} diff --git a/agent/cache/watch_test.go b/agent/cache/watch_test.go index e635aa452d6b..0fddcad1d542 100644 --- a/agent/cache/watch_test.go +++ b/agent/cache/watch_test.go @@ -4,12 +4,15 @@ import ( "context" "errors" "fmt" + "reflect" "sync/atomic" "testing" "time" + "github.com/golang/protobuf/proto" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/timestamppb" ) // Test that a type registered with a periodic refresh can be watched. @@ -401,3 +404,44 @@ OUT: actual := atomic.LoadUint32(&retries) require.True(t, actual < 10, fmt.Sprintf("actual: %d", actual)) } + +func Test_isEqual(t *testing.T) { + s1 := time.Now() + s2 := s1 + + var pb1 proto.Message = timestamppb.New(s1) + var pb2 proto.Message = ×tamppb.Timestamp{} + + // Marshal and unmarshal the proto object + b, err := proto.Marshal(pb1) + require.NoError(t, err) + require.NoError(t, proto.Unmarshal(b, pb2)) + + // Sanity-check that protobuf comparisons fail reflect.DeepEqual + require.False(t, reflect.DeepEqual(pb1, pb2)) + + tests := []struct { + equal bool + v1 interface{} + v2 interface{} + }{ + // Test protobuf message comparisons work. + {true, nil, nil}, + {true, pb1, pb2}, + {false, nil, pb2}, + {false, pb1, nil}, + {false, pb1, timestamppb.New(s1.Add(time.Second))}, + // Test normal struct comparisons + {true, s1, s2}, + {true, &s1, &s2}, + {false, s1, nil}, + {false, &s1, nil}, + {false, nil, s2}, + {false, nil, &s2}, + {false, s1, s1.Add(time.Second)}, + } + + for _, tc := range tests { + require.Equal(t, tc.equal, isEqual(tc.v1, tc.v2)) + } +} diff --git a/agent/catalog_endpoint_oss.go b/agent/catalog_endpoint_ce.go similarity index 100% rename from agent/catalog_endpoint_oss.go rename to agent/catalog_endpoint_ce.go diff --git a/agent/checks/check_test.go b/agent/checks/check_test.go index b8f16d890f02..120810b82b95 100644 --- a/agent/checks/check_test.go +++ b/agent/checks/check_test.go @@ -17,16 +17,17 @@ import ( "testing" "time" + "github.com/hashicorp/go-uuid" + "github.com/stretchr/testify/require" + "golang.org/x/net/http2" + "golang.org/x/net/http2/h2c" + "github.com/hashicorp/consul/agent/mock" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/sdk/freeport" "github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/sdk/testutil/retry" - "github.com/hashicorp/go-uuid" - "github.com/stretchr/testify/require" - http2 "golang.org/x/net/http2" - "golang.org/x/net/http2/h2c" ) func uniqueID() string { @@ -300,8 +301,6 @@ func TestCheckHTTP(t *testing.T) { {code: 429, status: api.HealthWarning}, // critical - {code: 150, status: api.HealthCritical}, - {code: 199, status: api.HealthCritical}, {code: 300, status: api.HealthCritical}, {code: 400, status: api.HealthCritical}, {code: 500, status: api.HealthCritical}, @@ -1138,9 +1137,6 @@ func TestCheckTCPPassing(t *testing.T) { if os.Getenv("TRAVIS") == "true" { t.Skip("IPV6 not supported on travis-ci") } - if os.Getenv("CIRCLECI") == "true" { - t.Skip("IPV6 not supported on CircleCI") - } tcpServer = mockTCPServer(`tcp6`) expectTCPStatus(t, tcpServer.Addr().String(), api.HealthPassing) tcpServer.Close() diff --git a/agent/checks/grpc.go b/agent/checks/grpc.go index d1bf6b900a2a..578b496f55ed 100644 --- a/agent/checks/grpc.go +++ b/agent/checks/grpc.go @@ -37,6 +37,7 @@ func NewGrpcHealthProbe(target string, timeout time.Duration, tlsConfig *tls.Con if tlsConfig != nil { dialOptions = append(dialOptions, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))) } else { + //nolint:staticcheck dialOptions = append(dialOptions, grpc.WithInsecure()) } diff --git a/agent/config/builder.go b/agent/config/builder.go index 6ee7e8d9e6d5..ee89f5f8bd29 100644 --- a/agent/config/builder.go +++ b/agent/config/builder.go @@ -436,6 +436,10 @@ func (b *builder) build() (rt RuntimeConfig, err error) { serverPort := b.portVal("ports.server", c.Ports.Server) grpcPort := b.portVal("ports.grpc", c.Ports.GRPC) grpcTlsPort := b.portVal("ports.grpc_tls", c.Ports.GRPCTLS) + // default gRPC TLS port for servers is 8503 + if c.Ports.GRPCTLS == nil && boolVal(c.ServerMode) { + grpcTlsPort = 8503 + } serfPortLAN := b.portVal("ports.serf_lan", c.Ports.SerfLAN) serfPortWAN := b.portVal("ports.serf_wan", c.Ports.SerfWAN) proxyMinPort := b.portVal("ports.proxy_min_port", c.Ports.ProxyMinPort) @@ -1035,7 +1039,7 @@ func (b *builder) build() (rt RuntimeConfig, err error) { RPCMaxBurst: intVal(c.Limits.RPCMaxBurst), RPCMaxConnsPerClient: intVal(c.Limits.RPCMaxConnsPerClient), RPCProtocol: intVal(c.RPCProtocol), - RPCRateLimit: rate.Limit(float64Val(c.Limits.RPCRate)), + RPCRateLimit: limitVal(c.Limits.RPCRate), RPCConfig: consul.RPCConfig{EnableStreaming: boolValWithDefault(c.RPC.EnableStreaming, serverMode)}, RaftProtocol: intVal(c.RaftProtocol), RaftSnapshotThreshold: intVal(c.RaftSnapshotThreshold), @@ -1079,6 +1083,7 @@ func (b *builder) build() (rt RuntimeConfig, err error) { Watches: c.Watches, XDSUpdateRateLimit: rate.Limit(float64Val(c.XDS.UpdateMaxPerSecond)), AutoReloadConfigCoalesceInterval: 1 * time.Second, + LocalProxyConfigResyncInterval: 30 * time.Second, } rt.TLS, err = b.buildTLSConfig(rt, c.TLS) @@ -1086,6 +1091,16 @@ func (b *builder) build() (rt RuntimeConfig, err error) { return RuntimeConfig{}, err } + // `ports.grpc` previously supported TLS, but this was changed for Consul 1.14. + // This check is done to warn users that a config change is mandatory. + if rt.TLS.GRPC.CertFile != "" || (rt.TLS.AutoTLS && rt.TLS.GRPC.UseAutoCert) { + // If only `ports.grpc` is enabled, and the gRPC TLS port is not explicitly defined by the user, + // check the grpc TLS settings for incompatibilities. + if rt.GRPCPort > 0 && c.Ports.GRPCTLS == nil { + return RuntimeConfig{}, fmt.Errorf("the `ports.grpc` listener no longer supports TLS. Use `ports.grpc_tls` instead. This message is appearing because GRPC is configured to use TLS, but `ports.grpc_tls` is not defined") + } + } + rt.UseStreamingBackend = boolValWithDefault(c.UseStreamingBackend, true) if c.RaftBoltDBConfig != nil { @@ -1245,6 +1260,10 @@ func (b *builder) validate(rt RuntimeConfig) error { b.warn("Node name %q will not be discoverable "+ "via DNS due to invalid characters. Valid characters include "+ "all alpha-numerics and dashes.", rt.NodeName) + case consul.InvalidNodeName.MatchString(rt.NodeName): + // todo(kyhavlov): Add stronger validation here for node names. + b.warn("Found invalid characters in node name %q - whitespace and quotes "+ + "(', \", `) cannot be used with auto-config.", rt.NodeName) case len(rt.NodeName) > dns.MaxLabelLength: b.warn("Node name %q will not be discoverable "+ "via DNS due to it being too long. Valid lengths are between "+ @@ -1978,6 +1997,14 @@ func float64Val(v *float64) float64 { return float64ValWithDefault(v, 0) } +func limitVal(v *float64) rate.Limit { + f := float64Val(v) + if f < 0 { + return rate.Inf + } + return rate.Limit(f) +} + func (b *builder) cidrsVal(name string, v []string) (nets []*net.IPNet) { if v == nil { return @@ -2453,18 +2480,23 @@ func validateAutoConfigAuthorizer(rt RuntimeConfig) error { return nil } -func (b *builder) cloudConfigVal(v *CloudConfigRaw) (val hcpconfig.CloudConfig) { +func (b *builder) cloudConfigVal(v *CloudConfigRaw) hcpconfig.CloudConfig { + val := hcpconfig.CloudConfig{ + ResourceID: os.Getenv("HCP_RESOURCE_ID"), + } if v == nil { return val } - val.ResourceID = stringVal(v.ResourceID) val.ClientID = stringVal(v.ClientID) val.ClientSecret = stringVal(v.ClientSecret) val.AuthURL = stringVal(v.AuthURL) val.Hostname = stringVal(v.Hostname) val.ScadaAddress = stringVal(v.ScadaAddress) + if resourceID := stringVal(v.ResourceID); resourceID != "" { + val.ResourceID = resourceID + } return val } diff --git a/agent/config/builder_oss.go b/agent/config/builder_ce.go similarity index 92% rename from agent/config/builder_oss.go rename to agent/config/builder_ce.go index ce6e8d44ce0b..cfe05b5fd9d1 100644 --- a/agent/config/builder_oss.go +++ b/agent/config/builder_ce.go @@ -10,7 +10,7 @@ import ( // validateEnterpriseConfig is a function to validate the enterprise specific // configuration items after Parsing but before merging into the overall // configuration. The original intent is to use it to ensure that we warn -// for enterprise configurations used in OSS. +// for enterprise configurations used in CE. func validateEnterpriseConfigKeys(config *Config) []error { var result []error add := func(k string) { @@ -57,6 +57,10 @@ func validateEnterpriseConfigKeys(config *Config) []error { add("license_path") config.LicensePath = nil } + if config.Reporting.License.Enabled != nil { + add("reporting.license.enabled") + config.Reporting.License.Enabled = nil + } return result } diff --git a/agent/config/builder_oss_test.go b/agent/config/builder_ce_test.go similarity index 91% rename from agent/config/builder_oss_test.go rename to agent/config/builder_ce_test.go index 2fd5f50ad7c3..1fdba09e6028 100644 --- a/agent/config/builder_oss_test.go +++ b/agent/config/builder_ce_test.go @@ -107,6 +107,19 @@ func TestValidateEnterpriseConfigKeys(t *testing.T) { require.Empty(t, c.LicensePath) }, }, + "reporting.license.enabled": { + config: Config{ + Reporting: Reporting{ + License: License{ + Enabled: &boolVal, + }, + }, + }, + badKeys: []string{"reporting.license.enabled"}, + check: func(t *testing.T, c *Config) { + require.Nil(t, c.Reporting.License.Enabled) + }, + }, "multi": { config: Config{ ReadReplica: &boolVal, diff --git a/agent/config/builder_test.go b/agent/config/builder_test.go index abb7be0e1d54..c3afbd1fd004 100644 --- a/agent/config/builder_test.go +++ b/agent/config/builder_test.go @@ -366,6 +366,90 @@ func TestBuilder_tlsVersion(t *testing.T) { require.Contains(t, b.err.Error(), invalidTLSVersion) } +func TestBuilder_WarnGRPCTLS(t *testing.T) { + tests := []struct { + name string + hcl string + expectErr bool + }{ + { + name: "success", + hcl: ``, + expectErr: false, + }, + { + name: "grpc_tls is disabled but explicitly defined", + hcl: ` + ports { grpc_tls = -1 } + tls { grpc { cert_file = "defined" }} + `, + // This behavior is a little strange, but it allows users + // to setup TLS and disable the port if they wish. + expectErr: false, + }, + { + name: "grpc is disabled", + hcl: ` + ports { grpc = -1 } + tls { grpc { cert_file = "defined" }} + `, + expectErr: false, + }, + { + name: "grpc_tls is undefined with default manual cert", + hcl: ` + tls { defaults { cert_file = "defined" }} + `, + expectErr: true, + }, + { + name: "grpc_tls is undefined with manual cert", + hcl: ` + tls { grpc { cert_file = "defined" }} + `, + expectErr: true, + }, + { + name: "grpc_tls is undefined with auto encrypt", + hcl: ` + auto_encrypt { tls = true } + tls { grpc { use_auto_cert = true }} + `, + expectErr: true, + }, + { + name: "grpc_tls is undefined with auto config", + hcl: ` + auto_config { enabled = true } + tls { grpc { use_auto_cert = true }} + `, + expectErr: true, + }, + } + for _, tc := range tests { + // using dev mode skips the need for a data dir + // and enables both grpc ports by default. + devMode := true + builderOpts := LoadOpts{ + DevMode: &devMode, + Overrides: []Source{ + FileSource{ + Name: "overrides", + Format: "hcl", + Data: tc.hcl, + }, + }, + } + _, err := Load(builderOpts) + if tc.expectErr { + require.Error(t, err) + require.Contains(t, err.Error(), "listener no longer supports TLS") + } else { + require.NoError(t, err) + } + } +} + func TestBuilder_tlsCipherSuites(t *testing.T) { b := builder{} diff --git a/agent/config/config.deepcopy.go b/agent/config/config.deepcopy.go new file mode 100644 index 000000000000..4f5129fb0e08 --- /dev/null +++ b/agent/config/config.deepcopy.go @@ -0,0 +1,1133 @@ +// generated by deep-copy -pointer-receiver -o ./config.deepcopy.go -type RuntimeConfig ./; DO NOT EDIT. + +package config + +import ( + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" + "github.com/armon/go-metrics" + "github.com/armon/go-metrics/prometheus" + "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/types" + "math/big" + "net" + "net/url" + "time" +) + +// DeepCopy generates a deep copy of *RuntimeConfig +func (o *RuntimeConfig) DeepCopy() *RuntimeConfig { + var cp RuntimeConfig = *o + if o.Cloud.TLSConfig != nil { + cp.Cloud.TLSConfig = new(tls.Config) + *cp.Cloud.TLSConfig = *o.Cloud.TLSConfig + if o.Cloud.TLSConfig.Certificates != nil { + cp.Cloud.TLSConfig.Certificates = make([]tls.Certificate, len(o.Cloud.TLSConfig.Certificates)) + copy(cp.Cloud.TLSConfig.Certificates, o.Cloud.TLSConfig.Certificates) + for i5 := range o.Cloud.TLSConfig.Certificates { + if o.Cloud.TLSConfig.Certificates[i5].Certificate != nil { + cp.Cloud.TLSConfig.Certificates[i5].Certificate = make([][]byte, len(o.Cloud.TLSConfig.Certificates[i5].Certificate)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Certificate, o.Cloud.TLSConfig.Certificates[i5].Certificate) + for i7 := range o.Cloud.TLSConfig.Certificates[i5].Certificate { + if o.Cloud.TLSConfig.Certificates[i5].Certificate[i7] != nil { + cp.Cloud.TLSConfig.Certificates[i5].Certificate[i7] = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].Certificate[i7])) + copy(cp.Cloud.TLSConfig.Certificates[i5].Certificate[i7], o.Cloud.TLSConfig.Certificates[i5].Certificate[i7]) + } + } + } + if o.Cloud.TLSConfig.Certificates[i5].SupportedSignatureAlgorithms != nil { + cp.Cloud.TLSConfig.Certificates[i5].SupportedSignatureAlgorithms = make([]tls.SignatureScheme, len(o.Cloud.TLSConfig.Certificates[i5].SupportedSignatureAlgorithms)) + copy(cp.Cloud.TLSConfig.Certificates[i5].SupportedSignatureAlgorithms, o.Cloud.TLSConfig.Certificates[i5].SupportedSignatureAlgorithms) + } + if o.Cloud.TLSConfig.Certificates[i5].OCSPStaple != nil { + cp.Cloud.TLSConfig.Certificates[i5].OCSPStaple = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].OCSPStaple)) + copy(cp.Cloud.TLSConfig.Certificates[i5].OCSPStaple, o.Cloud.TLSConfig.Certificates[i5].OCSPStaple) + } + if o.Cloud.TLSConfig.Certificates[i5].SignedCertificateTimestamps != nil { + cp.Cloud.TLSConfig.Certificates[i5].SignedCertificateTimestamps = make([][]byte, len(o.Cloud.TLSConfig.Certificates[i5].SignedCertificateTimestamps)) + copy(cp.Cloud.TLSConfig.Certificates[i5].SignedCertificateTimestamps, o.Cloud.TLSConfig.Certificates[i5].SignedCertificateTimestamps) + for i7 := range o.Cloud.TLSConfig.Certificates[i5].SignedCertificateTimestamps { + if o.Cloud.TLSConfig.Certificates[i5].SignedCertificateTimestamps[i7] != nil { + cp.Cloud.TLSConfig.Certificates[i5].SignedCertificateTimestamps[i7] = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].SignedCertificateTimestamps[i7])) + copy(cp.Cloud.TLSConfig.Certificates[i5].SignedCertificateTimestamps[i7], o.Cloud.TLSConfig.Certificates[i5].SignedCertificateTimestamps[i7]) + } + } + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf = new(x509.Certificate) + *cp.Cloud.TLSConfig.Certificates[i5].Leaf = *o.Cloud.TLSConfig.Certificates[i5].Leaf + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Raw != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Raw = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Raw)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Raw, o.Cloud.TLSConfig.Certificates[i5].Leaf.Raw) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.RawTBSCertificate != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.RawTBSCertificate = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.RawTBSCertificate)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.RawTBSCertificate, o.Cloud.TLSConfig.Certificates[i5].Leaf.RawTBSCertificate) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.RawSubjectPublicKeyInfo != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.RawSubjectPublicKeyInfo = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.RawSubjectPublicKeyInfo)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.RawSubjectPublicKeyInfo, o.Cloud.TLSConfig.Certificates[i5].Leaf.RawSubjectPublicKeyInfo) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.RawSubject != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.RawSubject = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.RawSubject)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.RawSubject, o.Cloud.TLSConfig.Certificates[i5].Leaf.RawSubject) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.RawIssuer != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.RawIssuer = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.RawIssuer)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.RawIssuer, o.Cloud.TLSConfig.Certificates[i5].Leaf.RawIssuer) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Signature != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Signature = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Signature)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Signature, o.Cloud.TLSConfig.Certificates[i5].Leaf.Signature) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.SerialNumber != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.SerialNumber = new(big.Int) + *cp.Cloud.TLSConfig.Certificates[i5].Leaf.SerialNumber = *o.Cloud.TLSConfig.Certificates[i5].Leaf.SerialNumber + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Country != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Country = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Country)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Country, o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Country) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Organization != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Organization = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Organization)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Organization, o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Organization) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.OrganizationalUnit != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.OrganizationalUnit = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.OrganizationalUnit)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.OrganizationalUnit, o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.OrganizationalUnit) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Locality != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Locality = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Locality)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Locality, o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Locality) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Province != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Province = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Province)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Province, o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Province) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.StreetAddress != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.StreetAddress = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.StreetAddress)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.StreetAddress, o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.StreetAddress) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.PostalCode != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.PostalCode = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.PostalCode)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.PostalCode, o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.PostalCode) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Names != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Names = make([]pkix.AttributeTypeAndValue, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Names)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Names, o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Names) + for i10 := range o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Names { + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Names[i10].Type != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Names[i10].Type = make([]int, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Names[i10].Type)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Names[i10].Type, o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.Names[i10].Type) + } + } + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.ExtraNames != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.ExtraNames = make([]pkix.AttributeTypeAndValue, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.ExtraNames)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.ExtraNames, o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.ExtraNames) + for i10 := range o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.ExtraNames { + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.ExtraNames[i10].Type != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.ExtraNames[i10].Type = make([]int, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.ExtraNames[i10].Type)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.ExtraNames[i10].Type, o.Cloud.TLSConfig.Certificates[i5].Leaf.Issuer.ExtraNames[i10].Type) + } + } + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Country != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Country = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Country)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Country, o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Country) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Organization != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Organization = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Organization)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Organization, o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Organization) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.OrganizationalUnit != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.OrganizationalUnit = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.OrganizationalUnit)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.OrganizationalUnit, o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.OrganizationalUnit) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Locality != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Locality = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Locality)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Locality, o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Locality) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Province != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Province = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Province)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Province, o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Province) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.StreetAddress != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.StreetAddress = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.StreetAddress)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.StreetAddress, o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.StreetAddress) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.PostalCode != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.PostalCode = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.PostalCode)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.PostalCode, o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.PostalCode) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Names != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Names = make([]pkix.AttributeTypeAndValue, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Names)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Names, o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Names) + for i10 := range o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Names { + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Names[i10].Type != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Names[i10].Type = make([]int, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Names[i10].Type)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Names[i10].Type, o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.Names[i10].Type) + } + } + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.ExtraNames != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.ExtraNames = make([]pkix.AttributeTypeAndValue, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.ExtraNames)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.ExtraNames, o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.ExtraNames) + for i10 := range o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.ExtraNames { + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.ExtraNames[i10].Type != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.ExtraNames[i10].Type = make([]int, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.ExtraNames[i10].Type)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.ExtraNames[i10].Type, o.Cloud.TLSConfig.Certificates[i5].Leaf.Subject.ExtraNames[i10].Type) + } + } + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Extensions != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Extensions = make([]pkix.Extension, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Extensions)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Extensions, o.Cloud.TLSConfig.Certificates[i5].Leaf.Extensions) + for i9 := range o.Cloud.TLSConfig.Certificates[i5].Leaf.Extensions { + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Extensions[i9].Id != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Extensions[i9].Id = make([]int, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Extensions[i9].Id)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Extensions[i9].Id, o.Cloud.TLSConfig.Certificates[i5].Leaf.Extensions[i9].Id) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.Extensions[i9].Value != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.Extensions[i9].Value = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.Extensions[i9].Value)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.Extensions[i9].Value, o.Cloud.TLSConfig.Certificates[i5].Leaf.Extensions[i9].Value) + } + } + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.ExtraExtensions != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExtraExtensions = make([]pkix.Extension, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.ExtraExtensions)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExtraExtensions, o.Cloud.TLSConfig.Certificates[i5].Leaf.ExtraExtensions) + for i9 := range o.Cloud.TLSConfig.Certificates[i5].Leaf.ExtraExtensions { + if o.Cloud.TLSConfig.Certificates[i5].Leaf.ExtraExtensions[i9].Id != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExtraExtensions[i9].Id = make([]int, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.ExtraExtensions[i9].Id)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExtraExtensions[i9].Id, o.Cloud.TLSConfig.Certificates[i5].Leaf.ExtraExtensions[i9].Id) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.ExtraExtensions[i9].Value != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExtraExtensions[i9].Value = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.ExtraExtensions[i9].Value)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExtraExtensions[i9].Value, o.Cloud.TLSConfig.Certificates[i5].Leaf.ExtraExtensions[i9].Value) + } + } + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.UnhandledCriticalExtensions != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.UnhandledCriticalExtensions = make([]asn1.ObjectIdentifier, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.UnhandledCriticalExtensions)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.UnhandledCriticalExtensions, o.Cloud.TLSConfig.Certificates[i5].Leaf.UnhandledCriticalExtensions) + for i9 := range o.Cloud.TLSConfig.Certificates[i5].Leaf.UnhandledCriticalExtensions { + if o.Cloud.TLSConfig.Certificates[i5].Leaf.UnhandledCriticalExtensions[i9] != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.UnhandledCriticalExtensions[i9] = make([]int, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.UnhandledCriticalExtensions[i9])) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.UnhandledCriticalExtensions[i9], o.Cloud.TLSConfig.Certificates[i5].Leaf.UnhandledCriticalExtensions[i9]) + } + } + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.ExtKeyUsage != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExtKeyUsage = make([]x509.ExtKeyUsage, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.ExtKeyUsage)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExtKeyUsage, o.Cloud.TLSConfig.Certificates[i5].Leaf.ExtKeyUsage) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.UnknownExtKeyUsage != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.UnknownExtKeyUsage = make([]asn1.ObjectIdentifier, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.UnknownExtKeyUsage)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.UnknownExtKeyUsage, o.Cloud.TLSConfig.Certificates[i5].Leaf.UnknownExtKeyUsage) + for i9 := range o.Cloud.TLSConfig.Certificates[i5].Leaf.UnknownExtKeyUsage { + if o.Cloud.TLSConfig.Certificates[i5].Leaf.UnknownExtKeyUsage[i9] != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.UnknownExtKeyUsage[i9] = make([]int, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.UnknownExtKeyUsage[i9])) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.UnknownExtKeyUsage[i9], o.Cloud.TLSConfig.Certificates[i5].Leaf.UnknownExtKeyUsage[i9]) + } + } + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.SubjectKeyId != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.SubjectKeyId = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.SubjectKeyId)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.SubjectKeyId, o.Cloud.TLSConfig.Certificates[i5].Leaf.SubjectKeyId) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.AuthorityKeyId != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.AuthorityKeyId = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.AuthorityKeyId)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.AuthorityKeyId, o.Cloud.TLSConfig.Certificates[i5].Leaf.AuthorityKeyId) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.OCSPServer != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.OCSPServer = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.OCSPServer)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.OCSPServer, o.Cloud.TLSConfig.Certificates[i5].Leaf.OCSPServer) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.IssuingCertificateURL != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.IssuingCertificateURL = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.IssuingCertificateURL)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.IssuingCertificateURL, o.Cloud.TLSConfig.Certificates[i5].Leaf.IssuingCertificateURL) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.DNSNames != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.DNSNames = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.DNSNames)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.DNSNames, o.Cloud.TLSConfig.Certificates[i5].Leaf.DNSNames) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.EmailAddresses != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.EmailAddresses = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.EmailAddresses)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.EmailAddresses, o.Cloud.TLSConfig.Certificates[i5].Leaf.EmailAddresses) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.IPAddresses != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.IPAddresses = make([]net.IP, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.IPAddresses)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.IPAddresses, o.Cloud.TLSConfig.Certificates[i5].Leaf.IPAddresses) + for i9 := range o.Cloud.TLSConfig.Certificates[i5].Leaf.IPAddresses { + if o.Cloud.TLSConfig.Certificates[i5].Leaf.IPAddresses[i9] != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.IPAddresses[i9] = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.IPAddresses[i9])) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.IPAddresses[i9], o.Cloud.TLSConfig.Certificates[i5].Leaf.IPAddresses[i9]) + } + } + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.URIs != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.URIs = make([]*url.URL, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.URIs)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.URIs, o.Cloud.TLSConfig.Certificates[i5].Leaf.URIs) + for i9 := range o.Cloud.TLSConfig.Certificates[i5].Leaf.URIs { + if o.Cloud.TLSConfig.Certificates[i5].Leaf.URIs[i9] != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.URIs[i9] = new(url.URL) + *cp.Cloud.TLSConfig.Certificates[i5].Leaf.URIs[i9] = *o.Cloud.TLSConfig.Certificates[i5].Leaf.URIs[i9] + if o.Cloud.TLSConfig.Certificates[i5].Leaf.URIs[i9].User != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.URIs[i9].User = new(url.Userinfo) + *cp.Cloud.TLSConfig.Certificates[i5].Leaf.URIs[i9].User = *o.Cloud.TLSConfig.Certificates[i5].Leaf.URIs[i9].User + } + } + } + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedDNSDomains != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedDNSDomains = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedDNSDomains)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedDNSDomains, o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedDNSDomains) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedDNSDomains != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedDNSDomains = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedDNSDomains)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedDNSDomains, o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedDNSDomains) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges = make([]*net.IPNet, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges, o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges) + for i9 := range o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges { + if o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges[i9] != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges[i9] = new(net.IPNet) + *cp.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges[i9] = *o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges[i9] + if o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges[i9].IP != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges[i9].IP = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges[i9].IP)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges[i9].IP, o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges[i9].IP) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges[i9].Mask != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges[i9].Mask = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges[i9].Mask)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges[i9].Mask, o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedIPRanges[i9].Mask) + } + } + } + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges = make([]*net.IPNet, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges, o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges) + for i9 := range o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges { + if o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges[i9] != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges[i9] = new(net.IPNet) + *cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges[i9] = *o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges[i9] + if o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges[i9].IP != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges[i9].IP = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges[i9].IP)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges[i9].IP, o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges[i9].IP) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges[i9].Mask != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges[i9].Mask = make([]byte, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges[i9].Mask)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges[i9].Mask, o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedIPRanges[i9].Mask) + } + } + } + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedEmailAddresses != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedEmailAddresses = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedEmailAddresses)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedEmailAddresses, o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedEmailAddresses) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedEmailAddresses != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedEmailAddresses = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedEmailAddresses)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedEmailAddresses, o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedEmailAddresses) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedURIDomains != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedURIDomains = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedURIDomains)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedURIDomains, o.Cloud.TLSConfig.Certificates[i5].Leaf.PermittedURIDomains) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedURIDomains != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedURIDomains = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedURIDomains)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedURIDomains, o.Cloud.TLSConfig.Certificates[i5].Leaf.ExcludedURIDomains) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.CRLDistributionPoints != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.CRLDistributionPoints = make([]string, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.CRLDistributionPoints)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.CRLDistributionPoints, o.Cloud.TLSConfig.Certificates[i5].Leaf.CRLDistributionPoints) + } + if o.Cloud.TLSConfig.Certificates[i5].Leaf.PolicyIdentifiers != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.PolicyIdentifiers)) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.PolicyIdentifiers, o.Cloud.TLSConfig.Certificates[i5].Leaf.PolicyIdentifiers) + for i9 := range o.Cloud.TLSConfig.Certificates[i5].Leaf.PolicyIdentifiers { + if o.Cloud.TLSConfig.Certificates[i5].Leaf.PolicyIdentifiers[i9] != nil { + cp.Cloud.TLSConfig.Certificates[i5].Leaf.PolicyIdentifiers[i9] = make([]int, len(o.Cloud.TLSConfig.Certificates[i5].Leaf.PolicyIdentifiers[i9])) + copy(cp.Cloud.TLSConfig.Certificates[i5].Leaf.PolicyIdentifiers[i9], o.Cloud.TLSConfig.Certificates[i5].Leaf.PolicyIdentifiers[i9]) + } + } + } + } + } + } + if o.Cloud.TLSConfig.NameToCertificate != nil { + cp.Cloud.TLSConfig.NameToCertificate = make(map[string]*tls.Certificate, len(o.Cloud.TLSConfig.NameToCertificate)) + for k5, v5 := range o.Cloud.TLSConfig.NameToCertificate { + var cp_Cloud_TLSConfig_NameToCertificate_v5 *tls.Certificate + if v5 != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5 = new(tls.Certificate) + *cp_Cloud_TLSConfig_NameToCertificate_v5 = *v5 + if v5.Certificate != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Certificate = make([][]byte, len(v5.Certificate)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Certificate, v5.Certificate) + for i8 := range v5.Certificate { + if v5.Certificate[i8] != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Certificate[i8] = make([]byte, len(v5.Certificate[i8])) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Certificate[i8], v5.Certificate[i8]) + } + } + } + if v5.SupportedSignatureAlgorithms != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.SupportedSignatureAlgorithms = make([]tls.SignatureScheme, len(v5.SupportedSignatureAlgorithms)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.SupportedSignatureAlgorithms, v5.SupportedSignatureAlgorithms) + } + if v5.OCSPStaple != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.OCSPStaple = make([]byte, len(v5.OCSPStaple)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.OCSPStaple, v5.OCSPStaple) + } + if v5.SignedCertificateTimestamps != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.SignedCertificateTimestamps = make([][]byte, len(v5.SignedCertificateTimestamps)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.SignedCertificateTimestamps, v5.SignedCertificateTimestamps) + for i8 := range v5.SignedCertificateTimestamps { + if v5.SignedCertificateTimestamps[i8] != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.SignedCertificateTimestamps[i8] = make([]byte, len(v5.SignedCertificateTimestamps[i8])) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.SignedCertificateTimestamps[i8], v5.SignedCertificateTimestamps[i8]) + } + } + } + if v5.Leaf != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf = new(x509.Certificate) + *cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf = *v5.Leaf + if v5.Leaf.Raw != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Raw = make([]byte, len(v5.Leaf.Raw)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Raw, v5.Leaf.Raw) + } + if v5.Leaf.RawTBSCertificate != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.RawTBSCertificate = make([]byte, len(v5.Leaf.RawTBSCertificate)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.RawTBSCertificate, v5.Leaf.RawTBSCertificate) + } + if v5.Leaf.RawSubjectPublicKeyInfo != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.RawSubjectPublicKeyInfo = make([]byte, len(v5.Leaf.RawSubjectPublicKeyInfo)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.RawSubjectPublicKeyInfo, v5.Leaf.RawSubjectPublicKeyInfo) + } + if v5.Leaf.RawSubject != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.RawSubject = make([]byte, len(v5.Leaf.RawSubject)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.RawSubject, v5.Leaf.RawSubject) + } + if v5.Leaf.RawIssuer != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.RawIssuer = make([]byte, len(v5.Leaf.RawIssuer)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.RawIssuer, v5.Leaf.RawIssuer) + } + if v5.Leaf.Signature != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Signature = make([]byte, len(v5.Leaf.Signature)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Signature, v5.Leaf.Signature) + } + if v5.Leaf.SerialNumber != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.SerialNumber = new(big.Int) + *cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.SerialNumber = *v5.Leaf.SerialNumber + } + if v5.Leaf.Issuer.Country != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.Country = make([]string, len(v5.Leaf.Issuer.Country)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.Country, v5.Leaf.Issuer.Country) + } + if v5.Leaf.Issuer.Organization != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.Organization = make([]string, len(v5.Leaf.Issuer.Organization)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.Organization, v5.Leaf.Issuer.Organization) + } + if v5.Leaf.Issuer.OrganizationalUnit != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.OrganizationalUnit = make([]string, len(v5.Leaf.Issuer.OrganizationalUnit)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.OrganizationalUnit, v5.Leaf.Issuer.OrganizationalUnit) + } + if v5.Leaf.Issuer.Locality != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.Locality = make([]string, len(v5.Leaf.Issuer.Locality)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.Locality, v5.Leaf.Issuer.Locality) + } + if v5.Leaf.Issuer.Province != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.Province = make([]string, len(v5.Leaf.Issuer.Province)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.Province, v5.Leaf.Issuer.Province) + } + if v5.Leaf.Issuer.StreetAddress != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.StreetAddress = make([]string, len(v5.Leaf.Issuer.StreetAddress)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.StreetAddress, v5.Leaf.Issuer.StreetAddress) + } + if v5.Leaf.Issuer.PostalCode != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.PostalCode = make([]string, len(v5.Leaf.Issuer.PostalCode)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.PostalCode, v5.Leaf.Issuer.PostalCode) + } + if v5.Leaf.Issuer.Names != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.Names = make([]pkix.AttributeTypeAndValue, len(v5.Leaf.Issuer.Names)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.Names, v5.Leaf.Issuer.Names) + for i11 := range v5.Leaf.Issuer.Names { + if v5.Leaf.Issuer.Names[i11].Type != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.Names[i11].Type = make([]int, len(v5.Leaf.Issuer.Names[i11].Type)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.Names[i11].Type, v5.Leaf.Issuer.Names[i11].Type) + } + } + } + if v5.Leaf.Issuer.ExtraNames != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.ExtraNames = make([]pkix.AttributeTypeAndValue, len(v5.Leaf.Issuer.ExtraNames)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.ExtraNames, v5.Leaf.Issuer.ExtraNames) + for i11 := range v5.Leaf.Issuer.ExtraNames { + if v5.Leaf.Issuer.ExtraNames[i11].Type != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.ExtraNames[i11].Type = make([]int, len(v5.Leaf.Issuer.ExtraNames[i11].Type)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Issuer.ExtraNames[i11].Type, v5.Leaf.Issuer.ExtraNames[i11].Type) + } + } + } + if v5.Leaf.Subject.Country != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.Country = make([]string, len(v5.Leaf.Subject.Country)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.Country, v5.Leaf.Subject.Country) + } + if v5.Leaf.Subject.Organization != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.Organization = make([]string, len(v5.Leaf.Subject.Organization)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.Organization, v5.Leaf.Subject.Organization) + } + if v5.Leaf.Subject.OrganizationalUnit != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.OrganizationalUnit = make([]string, len(v5.Leaf.Subject.OrganizationalUnit)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.OrganizationalUnit, v5.Leaf.Subject.OrganizationalUnit) + } + if v5.Leaf.Subject.Locality != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.Locality = make([]string, len(v5.Leaf.Subject.Locality)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.Locality, v5.Leaf.Subject.Locality) + } + if v5.Leaf.Subject.Province != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.Province = make([]string, len(v5.Leaf.Subject.Province)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.Province, v5.Leaf.Subject.Province) + } + if v5.Leaf.Subject.StreetAddress != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.StreetAddress = make([]string, len(v5.Leaf.Subject.StreetAddress)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.StreetAddress, v5.Leaf.Subject.StreetAddress) + } + if v5.Leaf.Subject.PostalCode != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.PostalCode = make([]string, len(v5.Leaf.Subject.PostalCode)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.PostalCode, v5.Leaf.Subject.PostalCode) + } + if v5.Leaf.Subject.Names != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.Names = make([]pkix.AttributeTypeAndValue, len(v5.Leaf.Subject.Names)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.Names, v5.Leaf.Subject.Names) + for i11 := range v5.Leaf.Subject.Names { + if v5.Leaf.Subject.Names[i11].Type != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.Names[i11].Type = make([]int, len(v5.Leaf.Subject.Names[i11].Type)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.Names[i11].Type, v5.Leaf.Subject.Names[i11].Type) + } + } + } + if v5.Leaf.Subject.ExtraNames != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.ExtraNames = make([]pkix.AttributeTypeAndValue, len(v5.Leaf.Subject.ExtraNames)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.ExtraNames, v5.Leaf.Subject.ExtraNames) + for i11 := range v5.Leaf.Subject.ExtraNames { + if v5.Leaf.Subject.ExtraNames[i11].Type != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.ExtraNames[i11].Type = make([]int, len(v5.Leaf.Subject.ExtraNames[i11].Type)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Subject.ExtraNames[i11].Type, v5.Leaf.Subject.ExtraNames[i11].Type) + } + } + } + if v5.Leaf.Extensions != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Extensions = make([]pkix.Extension, len(v5.Leaf.Extensions)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Extensions, v5.Leaf.Extensions) + for i10 := range v5.Leaf.Extensions { + if v5.Leaf.Extensions[i10].Id != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Extensions[i10].Id = make([]int, len(v5.Leaf.Extensions[i10].Id)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Extensions[i10].Id, v5.Leaf.Extensions[i10].Id) + } + if v5.Leaf.Extensions[i10].Value != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Extensions[i10].Value = make([]byte, len(v5.Leaf.Extensions[i10].Value)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.Extensions[i10].Value, v5.Leaf.Extensions[i10].Value) + } + } + } + if v5.Leaf.ExtraExtensions != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExtraExtensions = make([]pkix.Extension, len(v5.Leaf.ExtraExtensions)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExtraExtensions, v5.Leaf.ExtraExtensions) + for i10 := range v5.Leaf.ExtraExtensions { + if v5.Leaf.ExtraExtensions[i10].Id != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExtraExtensions[i10].Id = make([]int, len(v5.Leaf.ExtraExtensions[i10].Id)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExtraExtensions[i10].Id, v5.Leaf.ExtraExtensions[i10].Id) + } + if v5.Leaf.ExtraExtensions[i10].Value != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExtraExtensions[i10].Value = make([]byte, len(v5.Leaf.ExtraExtensions[i10].Value)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExtraExtensions[i10].Value, v5.Leaf.ExtraExtensions[i10].Value) + } + } + } + if v5.Leaf.UnhandledCriticalExtensions != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.UnhandledCriticalExtensions = make([]asn1.ObjectIdentifier, len(v5.Leaf.UnhandledCriticalExtensions)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.UnhandledCriticalExtensions, v5.Leaf.UnhandledCriticalExtensions) + for i10 := range v5.Leaf.UnhandledCriticalExtensions { + if v5.Leaf.UnhandledCriticalExtensions[i10] != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.UnhandledCriticalExtensions[i10] = make([]int, len(v5.Leaf.UnhandledCriticalExtensions[i10])) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.UnhandledCriticalExtensions[i10], v5.Leaf.UnhandledCriticalExtensions[i10]) + } + } + } + if v5.Leaf.ExtKeyUsage != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExtKeyUsage = make([]x509.ExtKeyUsage, len(v5.Leaf.ExtKeyUsage)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExtKeyUsage, v5.Leaf.ExtKeyUsage) + } + if v5.Leaf.UnknownExtKeyUsage != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.UnknownExtKeyUsage = make([]asn1.ObjectIdentifier, len(v5.Leaf.UnknownExtKeyUsage)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.UnknownExtKeyUsage, v5.Leaf.UnknownExtKeyUsage) + for i10 := range v5.Leaf.UnknownExtKeyUsage { + if v5.Leaf.UnknownExtKeyUsage[i10] != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.UnknownExtKeyUsage[i10] = make([]int, len(v5.Leaf.UnknownExtKeyUsage[i10])) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.UnknownExtKeyUsage[i10], v5.Leaf.UnknownExtKeyUsage[i10]) + } + } + } + if v5.Leaf.SubjectKeyId != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.SubjectKeyId = make([]byte, len(v5.Leaf.SubjectKeyId)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.SubjectKeyId, v5.Leaf.SubjectKeyId) + } + if v5.Leaf.AuthorityKeyId != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.AuthorityKeyId = make([]byte, len(v5.Leaf.AuthorityKeyId)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.AuthorityKeyId, v5.Leaf.AuthorityKeyId) + } + if v5.Leaf.OCSPServer != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.OCSPServer = make([]string, len(v5.Leaf.OCSPServer)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.OCSPServer, v5.Leaf.OCSPServer) + } + if v5.Leaf.IssuingCertificateURL != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.IssuingCertificateURL = make([]string, len(v5.Leaf.IssuingCertificateURL)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.IssuingCertificateURL, v5.Leaf.IssuingCertificateURL) + } + if v5.Leaf.DNSNames != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.DNSNames = make([]string, len(v5.Leaf.DNSNames)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.DNSNames, v5.Leaf.DNSNames) + } + if v5.Leaf.EmailAddresses != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.EmailAddresses = make([]string, len(v5.Leaf.EmailAddresses)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.EmailAddresses, v5.Leaf.EmailAddresses) + } + if v5.Leaf.IPAddresses != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.IPAddresses = make([]net.IP, len(v5.Leaf.IPAddresses)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.IPAddresses, v5.Leaf.IPAddresses) + for i10 := range v5.Leaf.IPAddresses { + if v5.Leaf.IPAddresses[i10] != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.IPAddresses[i10] = make([]byte, len(v5.Leaf.IPAddresses[i10])) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.IPAddresses[i10], v5.Leaf.IPAddresses[i10]) + } + } + } + if v5.Leaf.URIs != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.URIs = make([]*url.URL, len(v5.Leaf.URIs)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.URIs, v5.Leaf.URIs) + for i10 := range v5.Leaf.URIs { + if v5.Leaf.URIs[i10] != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.URIs[i10] = new(url.URL) + *cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.URIs[i10] = *v5.Leaf.URIs[i10] + if v5.Leaf.URIs[i10].User != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.URIs[i10].User = new(url.Userinfo) + *cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.URIs[i10].User = *v5.Leaf.URIs[i10].User + } + } + } + } + if v5.Leaf.PermittedDNSDomains != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PermittedDNSDomains = make([]string, len(v5.Leaf.PermittedDNSDomains)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PermittedDNSDomains, v5.Leaf.PermittedDNSDomains) + } + if v5.Leaf.ExcludedDNSDomains != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExcludedDNSDomains = make([]string, len(v5.Leaf.ExcludedDNSDomains)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExcludedDNSDomains, v5.Leaf.ExcludedDNSDomains) + } + if v5.Leaf.PermittedIPRanges != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PermittedIPRanges = make([]*net.IPNet, len(v5.Leaf.PermittedIPRanges)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PermittedIPRanges, v5.Leaf.PermittedIPRanges) + for i10 := range v5.Leaf.PermittedIPRanges { + if v5.Leaf.PermittedIPRanges[i10] != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PermittedIPRanges[i10] = new(net.IPNet) + *cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PermittedIPRanges[i10] = *v5.Leaf.PermittedIPRanges[i10] + if v5.Leaf.PermittedIPRanges[i10].IP != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PermittedIPRanges[i10].IP = make([]byte, len(v5.Leaf.PermittedIPRanges[i10].IP)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PermittedIPRanges[i10].IP, v5.Leaf.PermittedIPRanges[i10].IP) + } + if v5.Leaf.PermittedIPRanges[i10].Mask != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PermittedIPRanges[i10].Mask = make([]byte, len(v5.Leaf.PermittedIPRanges[i10].Mask)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PermittedIPRanges[i10].Mask, v5.Leaf.PermittedIPRanges[i10].Mask) + } + } + } + } + if v5.Leaf.ExcludedIPRanges != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExcludedIPRanges = make([]*net.IPNet, len(v5.Leaf.ExcludedIPRanges)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExcludedIPRanges, v5.Leaf.ExcludedIPRanges) + for i10 := range v5.Leaf.ExcludedIPRanges { + if v5.Leaf.ExcludedIPRanges[i10] != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExcludedIPRanges[i10] = new(net.IPNet) + *cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExcludedIPRanges[i10] = *v5.Leaf.ExcludedIPRanges[i10] + if v5.Leaf.ExcludedIPRanges[i10].IP != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExcludedIPRanges[i10].IP = make([]byte, len(v5.Leaf.ExcludedIPRanges[i10].IP)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExcludedIPRanges[i10].IP, v5.Leaf.ExcludedIPRanges[i10].IP) + } + if v5.Leaf.ExcludedIPRanges[i10].Mask != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExcludedIPRanges[i10].Mask = make([]byte, len(v5.Leaf.ExcludedIPRanges[i10].Mask)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExcludedIPRanges[i10].Mask, v5.Leaf.ExcludedIPRanges[i10].Mask) + } + } + } + } + if v5.Leaf.PermittedEmailAddresses != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PermittedEmailAddresses = make([]string, len(v5.Leaf.PermittedEmailAddresses)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PermittedEmailAddresses, v5.Leaf.PermittedEmailAddresses) + } + if v5.Leaf.ExcludedEmailAddresses != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExcludedEmailAddresses = make([]string, len(v5.Leaf.ExcludedEmailAddresses)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExcludedEmailAddresses, v5.Leaf.ExcludedEmailAddresses) + } + if v5.Leaf.PermittedURIDomains != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PermittedURIDomains = make([]string, len(v5.Leaf.PermittedURIDomains)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PermittedURIDomains, v5.Leaf.PermittedURIDomains) + } + if v5.Leaf.ExcludedURIDomains != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExcludedURIDomains = make([]string, len(v5.Leaf.ExcludedURIDomains)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.ExcludedURIDomains, v5.Leaf.ExcludedURIDomains) + } + if v5.Leaf.CRLDistributionPoints != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.CRLDistributionPoints = make([]string, len(v5.Leaf.CRLDistributionPoints)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.CRLDistributionPoints, v5.Leaf.CRLDistributionPoints) + } + if v5.Leaf.PolicyIdentifiers != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(v5.Leaf.PolicyIdentifiers)) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PolicyIdentifiers, v5.Leaf.PolicyIdentifiers) + for i10 := range v5.Leaf.PolicyIdentifiers { + if v5.Leaf.PolicyIdentifiers[i10] != nil { + cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PolicyIdentifiers[i10] = make([]int, len(v5.Leaf.PolicyIdentifiers[i10])) + copy(cp_Cloud_TLSConfig_NameToCertificate_v5.Leaf.PolicyIdentifiers[i10], v5.Leaf.PolicyIdentifiers[i10]) + } + } + } + } + } + cp.Cloud.TLSConfig.NameToCertificate[k5] = cp_Cloud_TLSConfig_NameToCertificate_v5 + } + } + if o.Cloud.TLSConfig.RootCAs != nil { + cp.Cloud.TLSConfig.RootCAs = new(x509.CertPool) + *cp.Cloud.TLSConfig.RootCAs = *o.Cloud.TLSConfig.RootCAs + } + if o.Cloud.TLSConfig.NextProtos != nil { + cp.Cloud.TLSConfig.NextProtos = make([]string, len(o.Cloud.TLSConfig.NextProtos)) + copy(cp.Cloud.TLSConfig.NextProtos, o.Cloud.TLSConfig.NextProtos) + } + if o.Cloud.TLSConfig.ClientCAs != nil { + cp.Cloud.TLSConfig.ClientCAs = new(x509.CertPool) + *cp.Cloud.TLSConfig.ClientCAs = *o.Cloud.TLSConfig.ClientCAs + } + if o.Cloud.TLSConfig.CipherSuites != nil { + cp.Cloud.TLSConfig.CipherSuites = make([]uint16, len(o.Cloud.TLSConfig.CipherSuites)) + copy(cp.Cloud.TLSConfig.CipherSuites, o.Cloud.TLSConfig.CipherSuites) + } + if o.Cloud.TLSConfig.CurvePreferences != nil { + cp.Cloud.TLSConfig.CurvePreferences = make([]tls.CurveID, len(o.Cloud.TLSConfig.CurvePreferences)) + copy(cp.Cloud.TLSConfig.CurvePreferences, o.Cloud.TLSConfig.CurvePreferences) + } + } + if o.DNSServiceTTL != nil { + cp.DNSServiceTTL = make(map[string]time.Duration, len(o.DNSServiceTTL)) + for k2, v2 := range o.DNSServiceTTL { + cp.DNSServiceTTL[k2] = v2 + } + } + if o.DNSRecursors != nil { + cp.DNSRecursors = make([]string, len(o.DNSRecursors)) + copy(cp.DNSRecursors, o.DNSRecursors) + } + if o.HTTPBlockEndpoints != nil { + cp.HTTPBlockEndpoints = make([]string, len(o.HTTPBlockEndpoints)) + copy(cp.HTTPBlockEndpoints, o.HTTPBlockEndpoints) + } + if o.AllowWriteHTTPFrom != nil { + cp.AllowWriteHTTPFrom = make([]*net.IPNet, len(o.AllowWriteHTTPFrom)) + copy(cp.AllowWriteHTTPFrom, o.AllowWriteHTTPFrom) + for i2 := range o.AllowWriteHTTPFrom { + if o.AllowWriteHTTPFrom[i2] != nil { + cp.AllowWriteHTTPFrom[i2] = new(net.IPNet) + *cp.AllowWriteHTTPFrom[i2] = *o.AllowWriteHTTPFrom[i2] + if o.AllowWriteHTTPFrom[i2].IP != nil { + cp.AllowWriteHTTPFrom[i2].IP = make([]byte, len(o.AllowWriteHTTPFrom[i2].IP)) + copy(cp.AllowWriteHTTPFrom[i2].IP, o.AllowWriteHTTPFrom[i2].IP) + } + if o.AllowWriteHTTPFrom[i2].Mask != nil { + cp.AllowWriteHTTPFrom[i2].Mask = make([]byte, len(o.AllowWriteHTTPFrom[i2].Mask)) + copy(cp.AllowWriteHTTPFrom[i2].Mask, o.AllowWriteHTTPFrom[i2].Mask) + } + } + } + } + if o.HTTPResponseHeaders != nil { + cp.HTTPResponseHeaders = make(map[string]string, len(o.HTTPResponseHeaders)) + for k2, v2 := range o.HTTPResponseHeaders { + cp.HTTPResponseHeaders[k2] = v2 + } + } + if o.Telemetry.DogstatsdTags != nil { + cp.Telemetry.DogstatsdTags = make([]string, len(o.Telemetry.DogstatsdTags)) + copy(cp.Telemetry.DogstatsdTags, o.Telemetry.DogstatsdTags) + } + if o.Telemetry.AllowedPrefixes != nil { + cp.Telemetry.AllowedPrefixes = make([]string, len(o.Telemetry.AllowedPrefixes)) + copy(cp.Telemetry.AllowedPrefixes, o.Telemetry.AllowedPrefixes) + } + if o.Telemetry.BlockedPrefixes != nil { + cp.Telemetry.BlockedPrefixes = make([]string, len(o.Telemetry.BlockedPrefixes)) + copy(cp.Telemetry.BlockedPrefixes, o.Telemetry.BlockedPrefixes) + } + if o.Telemetry.PrometheusOpts.GaugeDefinitions != nil { + cp.Telemetry.PrometheusOpts.GaugeDefinitions = make([]prometheus.GaugeDefinition, len(o.Telemetry.PrometheusOpts.GaugeDefinitions)) + copy(cp.Telemetry.PrometheusOpts.GaugeDefinitions, o.Telemetry.PrometheusOpts.GaugeDefinitions) + for i4 := range o.Telemetry.PrometheusOpts.GaugeDefinitions { + if o.Telemetry.PrometheusOpts.GaugeDefinitions[i4].Name != nil { + cp.Telemetry.PrometheusOpts.GaugeDefinitions[i4].Name = make([]string, len(o.Telemetry.PrometheusOpts.GaugeDefinitions[i4].Name)) + copy(cp.Telemetry.PrometheusOpts.GaugeDefinitions[i4].Name, o.Telemetry.PrometheusOpts.GaugeDefinitions[i4].Name) + } + if o.Telemetry.PrometheusOpts.GaugeDefinitions[i4].ConstLabels != nil { + cp.Telemetry.PrometheusOpts.GaugeDefinitions[i4].ConstLabels = make([]metrics.Label, len(o.Telemetry.PrometheusOpts.GaugeDefinitions[i4].ConstLabels)) + copy(cp.Telemetry.PrometheusOpts.GaugeDefinitions[i4].ConstLabels, o.Telemetry.PrometheusOpts.GaugeDefinitions[i4].ConstLabels) + } + } + } + if o.Telemetry.PrometheusOpts.SummaryDefinitions != nil { + cp.Telemetry.PrometheusOpts.SummaryDefinitions = make([]prometheus.SummaryDefinition, len(o.Telemetry.PrometheusOpts.SummaryDefinitions)) + copy(cp.Telemetry.PrometheusOpts.SummaryDefinitions, o.Telemetry.PrometheusOpts.SummaryDefinitions) + for i4 := range o.Telemetry.PrometheusOpts.SummaryDefinitions { + if o.Telemetry.PrometheusOpts.SummaryDefinitions[i4].Name != nil { + cp.Telemetry.PrometheusOpts.SummaryDefinitions[i4].Name = make([]string, len(o.Telemetry.PrometheusOpts.SummaryDefinitions[i4].Name)) + copy(cp.Telemetry.PrometheusOpts.SummaryDefinitions[i4].Name, o.Telemetry.PrometheusOpts.SummaryDefinitions[i4].Name) + } + if o.Telemetry.PrometheusOpts.SummaryDefinitions[i4].ConstLabels != nil { + cp.Telemetry.PrometheusOpts.SummaryDefinitions[i4].ConstLabels = make([]metrics.Label, len(o.Telemetry.PrometheusOpts.SummaryDefinitions[i4].ConstLabels)) + copy(cp.Telemetry.PrometheusOpts.SummaryDefinitions[i4].ConstLabels, o.Telemetry.PrometheusOpts.SummaryDefinitions[i4].ConstLabels) + } + } + } + if o.Telemetry.PrometheusOpts.CounterDefinitions != nil { + cp.Telemetry.PrometheusOpts.CounterDefinitions = make([]prometheus.CounterDefinition, len(o.Telemetry.PrometheusOpts.CounterDefinitions)) + copy(cp.Telemetry.PrometheusOpts.CounterDefinitions, o.Telemetry.PrometheusOpts.CounterDefinitions) + for i4 := range o.Telemetry.PrometheusOpts.CounterDefinitions { + if o.Telemetry.PrometheusOpts.CounterDefinitions[i4].Name != nil { + cp.Telemetry.PrometheusOpts.CounterDefinitions[i4].Name = make([]string, len(o.Telemetry.PrometheusOpts.CounterDefinitions[i4].Name)) + copy(cp.Telemetry.PrometheusOpts.CounterDefinitions[i4].Name, o.Telemetry.PrometheusOpts.CounterDefinitions[i4].Name) + } + if o.Telemetry.PrometheusOpts.CounterDefinitions[i4].ConstLabels != nil { + cp.Telemetry.PrometheusOpts.CounterDefinitions[i4].ConstLabels = make([]metrics.Label, len(o.Telemetry.PrometheusOpts.CounterDefinitions[i4].ConstLabels)) + copy(cp.Telemetry.PrometheusOpts.CounterDefinitions[i4].ConstLabels, o.Telemetry.PrometheusOpts.CounterDefinitions[i4].ConstLabels) + } + } + } + if o.AdvertiseAddrLAN != nil { + cp.AdvertiseAddrLAN = new(net.IPAddr) + *cp.AdvertiseAddrLAN = *o.AdvertiseAddrLAN + if o.AdvertiseAddrLAN.IP != nil { + cp.AdvertiseAddrLAN.IP = make([]byte, len(o.AdvertiseAddrLAN.IP)) + copy(cp.AdvertiseAddrLAN.IP, o.AdvertiseAddrLAN.IP) + } + } + if o.AdvertiseAddrWAN != nil { + cp.AdvertiseAddrWAN = new(net.IPAddr) + *cp.AdvertiseAddrWAN = *o.AdvertiseAddrWAN + if o.AdvertiseAddrWAN.IP != nil { + cp.AdvertiseAddrWAN.IP = make([]byte, len(o.AdvertiseAddrWAN.IP)) + copy(cp.AdvertiseAddrWAN.IP, o.AdvertiseAddrWAN.IP) + } + } + if o.BindAddr != nil { + cp.BindAddr = new(net.IPAddr) + *cp.BindAddr = *o.BindAddr + if o.BindAddr.IP != nil { + cp.BindAddr.IP = make([]byte, len(o.BindAddr.IP)) + copy(cp.BindAddr.IP, o.BindAddr.IP) + } + } + if o.Checks != nil { + cp.Checks = make([]*structs.CheckDefinition, len(o.Checks)) + copy(cp.Checks, o.Checks) + for i2 := range o.Checks { + if o.Checks[i2] != nil { + cp.Checks[i2] = new(structs.CheckDefinition) + *cp.Checks[i2] = *o.Checks[i2] + if o.Checks[i2].ScriptArgs != nil { + cp.Checks[i2].ScriptArgs = make([]string, len(o.Checks[i2].ScriptArgs)) + copy(cp.Checks[i2].ScriptArgs, o.Checks[i2].ScriptArgs) + } + if o.Checks[i2].Header != nil { + cp.Checks[i2].Header = make(map[string][]string, len(o.Checks[i2].Header)) + for k5, v5 := range o.Checks[i2].Header { + var cp_Checks_i2_Header_v5 []string + if v5 != nil { + cp_Checks_i2_Header_v5 = make([]string, len(v5)) + copy(cp_Checks_i2_Header_v5, v5) + } + cp.Checks[i2].Header[k5] = cp_Checks_i2_Header_v5 + } + } + } + } + } + if o.ClientAddrs != nil { + cp.ClientAddrs = make([]*net.IPAddr, len(o.ClientAddrs)) + copy(cp.ClientAddrs, o.ClientAddrs) + for i2 := range o.ClientAddrs { + if o.ClientAddrs[i2] != nil { + cp.ClientAddrs[i2] = new(net.IPAddr) + *cp.ClientAddrs[i2] = *o.ClientAddrs[i2] + if o.ClientAddrs[i2].IP != nil { + cp.ClientAddrs[i2].IP = make([]byte, len(o.ClientAddrs[i2].IP)) + copy(cp.ClientAddrs[i2].IP, o.ClientAddrs[i2].IP) + } + } + } + } + if o.ConfigEntryBootstrap != nil { + cp.ConfigEntryBootstrap = make([]structs.ConfigEntry, len(o.ConfigEntryBootstrap)) + copy(cp.ConfigEntryBootstrap, o.ConfigEntryBootstrap) + } + if o.AutoEncryptDNSSAN != nil { + cp.AutoEncryptDNSSAN = make([]string, len(o.AutoEncryptDNSSAN)) + copy(cp.AutoEncryptDNSSAN, o.AutoEncryptDNSSAN) + } + if o.AutoEncryptIPSAN != nil { + cp.AutoEncryptIPSAN = make([]net.IP, len(o.AutoEncryptIPSAN)) + copy(cp.AutoEncryptIPSAN, o.AutoEncryptIPSAN) + for i2 := range o.AutoEncryptIPSAN { + if o.AutoEncryptIPSAN[i2] != nil { + cp.AutoEncryptIPSAN[i2] = make([]byte, len(o.AutoEncryptIPSAN[i2])) + copy(cp.AutoEncryptIPSAN[i2], o.AutoEncryptIPSAN[i2]) + } + } + } + if o.AutoConfig.ServerAddresses != nil { + cp.AutoConfig.ServerAddresses = make([]string, len(o.AutoConfig.ServerAddresses)) + copy(cp.AutoConfig.ServerAddresses, o.AutoConfig.ServerAddresses) + } + if o.AutoConfig.DNSSANs != nil { + cp.AutoConfig.DNSSANs = make([]string, len(o.AutoConfig.DNSSANs)) + copy(cp.AutoConfig.DNSSANs, o.AutoConfig.DNSSANs) + } + if o.AutoConfig.IPSANs != nil { + cp.AutoConfig.IPSANs = make([]net.IP, len(o.AutoConfig.IPSANs)) + copy(cp.AutoConfig.IPSANs, o.AutoConfig.IPSANs) + for i3 := range o.AutoConfig.IPSANs { + if o.AutoConfig.IPSANs[i3] != nil { + cp.AutoConfig.IPSANs[i3] = make([]byte, len(o.AutoConfig.IPSANs[i3])) + copy(cp.AutoConfig.IPSANs[i3], o.AutoConfig.IPSANs[i3]) + } + } + } + if o.AutoConfig.Authorizer.AuthMethod.Config != nil { + cp.AutoConfig.Authorizer.AuthMethod.Config = make(map[string]interface{}, len(o.AutoConfig.Authorizer.AuthMethod.Config)) + for k5, v5 := range o.AutoConfig.Authorizer.AuthMethod.Config { + cp.AutoConfig.Authorizer.AuthMethod.Config[k5] = v5 + } + } + if o.AutoConfig.Authorizer.ClaimAssertions != nil { + cp.AutoConfig.Authorizer.ClaimAssertions = make([]string, len(o.AutoConfig.Authorizer.ClaimAssertions)) + copy(cp.AutoConfig.Authorizer.ClaimAssertions, o.AutoConfig.Authorizer.ClaimAssertions) + } + if o.ConnectCAConfig != nil { + cp.ConnectCAConfig = make(map[string]interface{}, len(o.ConnectCAConfig)) + for k2, v2 := range o.ConnectCAConfig { + cp.ConnectCAConfig[k2] = v2 + } + } + if o.DNSAddrs != nil { + cp.DNSAddrs = make([]net.Addr, len(o.DNSAddrs)) + copy(cp.DNSAddrs, o.DNSAddrs) + } + if o.GRPCAddrs != nil { + cp.GRPCAddrs = make([]net.Addr, len(o.GRPCAddrs)) + copy(cp.GRPCAddrs, o.GRPCAddrs) + } + if o.GRPCTLSAddrs != nil { + cp.GRPCTLSAddrs = make([]net.Addr, len(o.GRPCTLSAddrs)) + copy(cp.GRPCTLSAddrs, o.GRPCTLSAddrs) + } + if o.HTTPAddrs != nil { + cp.HTTPAddrs = make([]net.Addr, len(o.HTTPAddrs)) + copy(cp.HTTPAddrs, o.HTTPAddrs) + } + if o.HTTPSAddrs != nil { + cp.HTTPSAddrs = make([]net.Addr, len(o.HTTPSAddrs)) + copy(cp.HTTPSAddrs, o.HTTPSAddrs) + } + if o.NodeMeta != nil { + cp.NodeMeta = make(map[string]string, len(o.NodeMeta)) + for k2, v2 := range o.NodeMeta { + cp.NodeMeta[k2] = v2 + } + } + if o.PrimaryGateways != nil { + cp.PrimaryGateways = make([]string, len(o.PrimaryGateways)) + copy(cp.PrimaryGateways, o.PrimaryGateways) + } + if o.RPCAdvertiseAddr != nil { + cp.RPCAdvertiseAddr = new(net.TCPAddr) + *cp.RPCAdvertiseAddr = *o.RPCAdvertiseAddr + if o.RPCAdvertiseAddr.IP != nil { + cp.RPCAdvertiseAddr.IP = make([]byte, len(o.RPCAdvertiseAddr.IP)) + copy(cp.RPCAdvertiseAddr.IP, o.RPCAdvertiseAddr.IP) + } + } + if o.RPCBindAddr != nil { + cp.RPCBindAddr = new(net.TCPAddr) + *cp.RPCBindAddr = *o.RPCBindAddr + if o.RPCBindAddr.IP != nil { + cp.RPCBindAddr.IP = make([]byte, len(o.RPCBindAddr.IP)) + copy(cp.RPCBindAddr.IP, o.RPCBindAddr.IP) + } + } + if o.RetryJoinLAN != nil { + cp.RetryJoinLAN = make([]string, len(o.RetryJoinLAN)) + copy(cp.RetryJoinLAN, o.RetryJoinLAN) + } + if o.RetryJoinWAN != nil { + cp.RetryJoinWAN = make([]string, len(o.RetryJoinWAN)) + copy(cp.RetryJoinWAN, o.RetryJoinWAN) + } + if o.Segments != nil { + cp.Segments = make([]structs.NetworkSegment, len(o.Segments)) + copy(cp.Segments, o.Segments) + for i2 := range o.Segments { + if o.Segments[i2].Bind != nil { + cp.Segments[i2].Bind = new(net.TCPAddr) + *cp.Segments[i2].Bind = *o.Segments[i2].Bind + if o.Segments[i2].Bind.IP != nil { + cp.Segments[i2].Bind.IP = make([]byte, len(o.Segments[i2].Bind.IP)) + copy(cp.Segments[i2].Bind.IP, o.Segments[i2].Bind.IP) + } + } + if o.Segments[i2].Advertise != nil { + cp.Segments[i2].Advertise = new(net.TCPAddr) + *cp.Segments[i2].Advertise = *o.Segments[i2].Advertise + if o.Segments[i2].Advertise.IP != nil { + cp.Segments[i2].Advertise.IP = make([]byte, len(o.Segments[i2].Advertise.IP)) + copy(cp.Segments[i2].Advertise.IP, o.Segments[i2].Advertise.IP) + } + } + } + } + if o.SerfAdvertiseAddrLAN != nil { + cp.SerfAdvertiseAddrLAN = new(net.TCPAddr) + *cp.SerfAdvertiseAddrLAN = *o.SerfAdvertiseAddrLAN + if o.SerfAdvertiseAddrLAN.IP != nil { + cp.SerfAdvertiseAddrLAN.IP = make([]byte, len(o.SerfAdvertiseAddrLAN.IP)) + copy(cp.SerfAdvertiseAddrLAN.IP, o.SerfAdvertiseAddrLAN.IP) + } + } + if o.SerfAdvertiseAddrWAN != nil { + cp.SerfAdvertiseAddrWAN = new(net.TCPAddr) + *cp.SerfAdvertiseAddrWAN = *o.SerfAdvertiseAddrWAN + if o.SerfAdvertiseAddrWAN.IP != nil { + cp.SerfAdvertiseAddrWAN.IP = make([]byte, len(o.SerfAdvertiseAddrWAN.IP)) + copy(cp.SerfAdvertiseAddrWAN.IP, o.SerfAdvertiseAddrWAN.IP) + } + } + if o.SerfAllowedCIDRsLAN != nil { + cp.SerfAllowedCIDRsLAN = make([]net.IPNet, len(o.SerfAllowedCIDRsLAN)) + copy(cp.SerfAllowedCIDRsLAN, o.SerfAllowedCIDRsLAN) + for i2 := range o.SerfAllowedCIDRsLAN { + if o.SerfAllowedCIDRsLAN[i2].IP != nil { + cp.SerfAllowedCIDRsLAN[i2].IP = make([]byte, len(o.SerfAllowedCIDRsLAN[i2].IP)) + copy(cp.SerfAllowedCIDRsLAN[i2].IP, o.SerfAllowedCIDRsLAN[i2].IP) + } + if o.SerfAllowedCIDRsLAN[i2].Mask != nil { + cp.SerfAllowedCIDRsLAN[i2].Mask = make([]byte, len(o.SerfAllowedCIDRsLAN[i2].Mask)) + copy(cp.SerfAllowedCIDRsLAN[i2].Mask, o.SerfAllowedCIDRsLAN[i2].Mask) + } + } + } + if o.SerfAllowedCIDRsWAN != nil { + cp.SerfAllowedCIDRsWAN = make([]net.IPNet, len(o.SerfAllowedCIDRsWAN)) + copy(cp.SerfAllowedCIDRsWAN, o.SerfAllowedCIDRsWAN) + for i2 := range o.SerfAllowedCIDRsWAN { + if o.SerfAllowedCIDRsWAN[i2].IP != nil { + cp.SerfAllowedCIDRsWAN[i2].IP = make([]byte, len(o.SerfAllowedCIDRsWAN[i2].IP)) + copy(cp.SerfAllowedCIDRsWAN[i2].IP, o.SerfAllowedCIDRsWAN[i2].IP) + } + if o.SerfAllowedCIDRsWAN[i2].Mask != nil { + cp.SerfAllowedCIDRsWAN[i2].Mask = make([]byte, len(o.SerfAllowedCIDRsWAN[i2].Mask)) + copy(cp.SerfAllowedCIDRsWAN[i2].Mask, o.SerfAllowedCIDRsWAN[i2].Mask) + } + } + } + if o.SerfBindAddrLAN != nil { + cp.SerfBindAddrLAN = new(net.TCPAddr) + *cp.SerfBindAddrLAN = *o.SerfBindAddrLAN + if o.SerfBindAddrLAN.IP != nil { + cp.SerfBindAddrLAN.IP = make([]byte, len(o.SerfBindAddrLAN.IP)) + copy(cp.SerfBindAddrLAN.IP, o.SerfBindAddrLAN.IP) + } + } + if o.SerfBindAddrWAN != nil { + cp.SerfBindAddrWAN = new(net.TCPAddr) + *cp.SerfBindAddrWAN = *o.SerfBindAddrWAN + if o.SerfBindAddrWAN.IP != nil { + cp.SerfBindAddrWAN.IP = make([]byte, len(o.SerfBindAddrWAN.IP)) + copy(cp.SerfBindAddrWAN.IP, o.SerfBindAddrWAN.IP) + } + } + if o.Services != nil { + cp.Services = make([]*structs.ServiceDefinition, len(o.Services)) + copy(cp.Services, o.Services) + for i2 := range o.Services { + if o.Services[i2] != nil { + cp.Services[i2] = o.Services[i2].DeepCopy() + } + } + } + if o.StartJoinAddrsLAN != nil { + cp.StartJoinAddrsLAN = make([]string, len(o.StartJoinAddrsLAN)) + copy(cp.StartJoinAddrsLAN, o.StartJoinAddrsLAN) + } + if o.StartJoinAddrsWAN != nil { + cp.StartJoinAddrsWAN = make([]string, len(o.StartJoinAddrsWAN)) + copy(cp.StartJoinAddrsWAN, o.StartJoinAddrsWAN) + } + if o.TLS.InternalRPC.CipherSuites != nil { + cp.TLS.InternalRPC.CipherSuites = make([]types.TLSCipherSuite, len(o.TLS.InternalRPC.CipherSuites)) + copy(cp.TLS.InternalRPC.CipherSuites, o.TLS.InternalRPC.CipherSuites) + } + if o.TLS.GRPC.CipherSuites != nil { + cp.TLS.GRPC.CipherSuites = make([]types.TLSCipherSuite, len(o.TLS.GRPC.CipherSuites)) + copy(cp.TLS.GRPC.CipherSuites, o.TLS.GRPC.CipherSuites) + } + if o.TLS.HTTPS.CipherSuites != nil { + cp.TLS.HTTPS.CipherSuites = make([]types.TLSCipherSuite, len(o.TLS.HTTPS.CipherSuites)) + copy(cp.TLS.HTTPS.CipherSuites, o.TLS.HTTPS.CipherSuites) + } + if o.TaggedAddresses != nil { + cp.TaggedAddresses = make(map[string]string, len(o.TaggedAddresses)) + for k2, v2 := range o.TaggedAddresses { + cp.TaggedAddresses[k2] = v2 + } + } + if o.UIConfig.MetricsProviderFiles != nil { + cp.UIConfig.MetricsProviderFiles = make([]string, len(o.UIConfig.MetricsProviderFiles)) + copy(cp.UIConfig.MetricsProviderFiles, o.UIConfig.MetricsProviderFiles) + } + if o.UIConfig.MetricsProxy.AddHeaders != nil { + cp.UIConfig.MetricsProxy.AddHeaders = make([]UIMetricsProxyAddHeader, len(o.UIConfig.MetricsProxy.AddHeaders)) + copy(cp.UIConfig.MetricsProxy.AddHeaders, o.UIConfig.MetricsProxy.AddHeaders) + } + if o.UIConfig.MetricsProxy.PathAllowlist != nil { + cp.UIConfig.MetricsProxy.PathAllowlist = make([]string, len(o.UIConfig.MetricsProxy.PathAllowlist)) + copy(cp.UIConfig.MetricsProxy.PathAllowlist, o.UIConfig.MetricsProxy.PathAllowlist) + } + if o.UIConfig.DashboardURLTemplates != nil { + cp.UIConfig.DashboardURLTemplates = make(map[string]string, len(o.UIConfig.DashboardURLTemplates)) + for k3, v3 := range o.UIConfig.DashboardURLTemplates { + cp.UIConfig.DashboardURLTemplates[k3] = v3 + } + } + if o.Watches != nil { + cp.Watches = make([]map[string]interface{}, len(o.Watches)) + copy(cp.Watches, o.Watches) + for i2 := range o.Watches { + if o.Watches[i2] != nil { + cp.Watches[i2] = make(map[string]interface{}, len(o.Watches[i2])) + for k3, v3 := range o.Watches[i2] { + cp.Watches[i2][k3] = v3 + } + } + } + } + return &cp +} diff --git a/agent/config/config.go b/agent/config/config.go index 9aabab82b784..c6a4d4fa1a04 100644 --- a/agent/config/config.go +++ b/agent/config/config.go @@ -133,168 +133,171 @@ type Cache struct { // configuration it should be treated as an external API which cannot be // changed and refactored at will since this will break existing setups. type Config struct { - ACL ACL `mapstructure:"acl"` - Addresses Addresses `mapstructure:"addresses"` - AdvertiseAddrLAN *string `mapstructure:"advertise_addr"` - AdvertiseAddrLANIPv4 *string `mapstructure:"advertise_addr_ipv4"` - AdvertiseAddrLANIPv6 *string `mapstructure:"advertise_addr_ipv6"` - AdvertiseAddrWAN *string `mapstructure:"advertise_addr_wan"` - AdvertiseAddrWANIPv4 *string `mapstructure:"advertise_addr_wan_ipv4"` - AdvertiseAddrWANIPv6 *string `mapstructure:"advertise_addr_wan_ipv6"` - AdvertiseReconnectTimeout *string `mapstructure:"advertise_reconnect_timeout"` - AutoConfig AutoConfigRaw `mapstructure:"auto_config"` - Autopilot Autopilot `mapstructure:"autopilot"` - BindAddr *string `mapstructure:"bind_addr"` - Bootstrap *bool `mapstructure:"bootstrap"` - BootstrapExpect *int `mapstructure:"bootstrap_expect"` - Cache Cache `mapstructure:"cache"` - Check *CheckDefinition `mapstructure:"check"` // needs to be a pointer to avoid partial merges - CheckOutputMaxSize *int `mapstructure:"check_output_max_size"` - CheckUpdateInterval *string `mapstructure:"check_update_interval"` - Checks []CheckDefinition `mapstructure:"checks"` - ClientAddr *string `mapstructure:"client_addr"` - Cloud *CloudConfigRaw `mapstructure:"cloud"` - ConfigEntries ConfigEntries `mapstructure:"config_entries"` - AutoEncrypt AutoEncrypt `mapstructure:"auto_encrypt"` - Connect Connect `mapstructure:"connect"` - DNS DNS `mapstructure:"dns_config"` - DNSDomain *string `mapstructure:"domain"` - DNSAltDomain *string `mapstructure:"alt_domain"` - DNSRecursors []string `mapstructure:"recursors"` - DataDir *string `mapstructure:"data_dir"` - Datacenter *string `mapstructure:"datacenter"` - DefaultQueryTime *string `mapstructure:"default_query_time"` - DisableAnonymousSignature *bool `mapstructure:"disable_anonymous_signature"` - DisableCoordinates *bool `mapstructure:"disable_coordinates"` - DisableHostNodeID *bool `mapstructure:"disable_host_node_id"` - DisableHTTPUnprintableCharFilter *bool `mapstructure:"disable_http_unprintable_char_filter"` - DisableKeyringFile *bool `mapstructure:"disable_keyring_file"` - DisableRemoteExec *bool `mapstructure:"disable_remote_exec"` - DisableUpdateCheck *bool `mapstructure:"disable_update_check"` - DiscardCheckOutput *bool `mapstructure:"discard_check_output"` - DiscoveryMaxStale *string `mapstructure:"discovery_max_stale"` - EnableAgentTLSForChecks *bool `mapstructure:"enable_agent_tls_for_checks"` - EnableCentralServiceConfig *bool `mapstructure:"enable_central_service_config"` - EnableDebug *bool `mapstructure:"enable_debug"` - EnableScriptChecks *bool `mapstructure:"enable_script_checks"` - EnableLocalScriptChecks *bool `mapstructure:"enable_local_script_checks"` - EnableSyslog *bool `mapstructure:"enable_syslog"` - EncryptKey *string `mapstructure:"encrypt"` - EncryptVerifyIncoming *bool `mapstructure:"encrypt_verify_incoming"` - EncryptVerifyOutgoing *bool `mapstructure:"encrypt_verify_outgoing"` - GossipLAN GossipLANConfig `mapstructure:"gossip_lan"` - GossipWAN GossipWANConfig `mapstructure:"gossip_wan"` - HTTPConfig HTTPConfig `mapstructure:"http_config"` - LeaveOnTerm *bool `mapstructure:"leave_on_terminate"` - LicensePath *string `mapstructure:"license_path"` - Limits Limits `mapstructure:"limits"` - LogLevel *string `mapstructure:"log_level"` - LogJSON *bool `mapstructure:"log_json"` - LogFile *string `mapstructure:"log_file"` - LogRotateDuration *string `mapstructure:"log_rotate_duration"` - LogRotateBytes *int `mapstructure:"log_rotate_bytes"` - LogRotateMaxFiles *int `mapstructure:"log_rotate_max_files"` - MaxQueryTime *string `mapstructure:"max_query_time"` - NodeID *string `mapstructure:"node_id"` - NodeMeta map[string]string `mapstructure:"node_meta"` - NodeName *string `mapstructure:"node_name"` - Peering Peering `mapstructure:"peering"` - Performance Performance `mapstructure:"performance"` - PidFile *string `mapstructure:"pid_file"` - Ports Ports `mapstructure:"ports"` - PrimaryDatacenter *string `mapstructure:"primary_datacenter"` - PrimaryGateways []string `mapstructure:"primary_gateways"` - PrimaryGatewaysInterval *string `mapstructure:"primary_gateways_interval"` - RPCProtocol *int `mapstructure:"protocol"` - RaftProtocol *int `mapstructure:"raft_protocol"` - RaftSnapshotThreshold *int `mapstructure:"raft_snapshot_threshold"` - RaftSnapshotInterval *string `mapstructure:"raft_snapshot_interval"` - RaftTrailingLogs *int `mapstructure:"raft_trailing_logs"` - ReconnectTimeoutLAN *string `mapstructure:"reconnect_timeout"` - ReconnectTimeoutWAN *string `mapstructure:"reconnect_timeout_wan"` - RejoinAfterLeave *bool `mapstructure:"rejoin_after_leave"` - AutoReloadConfig *bool `mapstructure:"auto_reload_config"` - RetryJoinIntervalLAN *string `mapstructure:"retry_interval"` - RetryJoinIntervalWAN *string `mapstructure:"retry_interval_wan"` - RetryJoinLAN []string `mapstructure:"retry_join"` - RetryJoinMaxAttemptsLAN *int `mapstructure:"retry_max"` - RetryJoinMaxAttemptsWAN *int `mapstructure:"retry_max_wan"` - RetryJoinWAN []string `mapstructure:"retry_join_wan"` - SerfAllowedCIDRsLAN []string `mapstructure:"serf_lan_allowed_cidrs"` - SerfAllowedCIDRsWAN []string `mapstructure:"serf_wan_allowed_cidrs"` - SerfBindAddrLAN *string `mapstructure:"serf_lan"` - SerfBindAddrWAN *string `mapstructure:"serf_wan"` - ServerMode *bool `mapstructure:"server"` - ServerName *string `mapstructure:"server_name"` - Service *ServiceDefinition `mapstructure:"service"` - Services []ServiceDefinition `mapstructure:"services"` - SessionTTLMin *string `mapstructure:"session_ttl_min"` - SkipLeaveOnInt *bool `mapstructure:"skip_leave_on_interrupt"` - StartJoinAddrsLAN []string `mapstructure:"start_join"` - StartJoinAddrsWAN []string `mapstructure:"start_join_wan"` - SyslogFacility *string `mapstructure:"syslog_facility"` - TLS TLS `mapstructure:"tls"` - TaggedAddresses map[string]string `mapstructure:"tagged_addresses"` - Telemetry Telemetry `mapstructure:"telemetry"` - TranslateWANAddrs *bool `mapstructure:"translate_wan_addrs"` - XDS XDS `mapstructure:"xds"` + ACL ACL `mapstructure:"acl" json:"-"` + Addresses Addresses `mapstructure:"addresses" json:"-"` + AdvertiseAddrLAN *string `mapstructure:"advertise_addr" json:"advertise_addr,omitempty"` + AdvertiseAddrLANIPv4 *string `mapstructure:"advertise_addr_ipv4" json:"advertise_addr_ipv4,omitempty"` + AdvertiseAddrLANIPv6 *string `mapstructure:"advertise_addr_ipv6" json:"advertise_addr_ipv6,omitempty"` + AdvertiseAddrWAN *string `mapstructure:"advertise_addr_wan" json:"advertise_addr_wan,omitempty"` + AdvertiseAddrWANIPv4 *string `mapstructure:"advertise_addr_wan_ipv4" json:"advertise_addr_wan_ipv4,omitempty"` + AdvertiseAddrWANIPv6 *string `mapstructure:"advertise_addr_wan_ipv6" json:"advertise_addr_wan_ipv6,omitempty"` + AdvertiseReconnectTimeout *string `mapstructure:"advertise_reconnect_timeout" json:"-"` + AutoConfig AutoConfigRaw `mapstructure:"auto_config" json:"-"` + Autopilot Autopilot `mapstructure:"autopilot" json:"-"` + BindAddr *string `mapstructure:"bind_addr" json:"bind_addr,omitempty"` + Bootstrap *bool `mapstructure:"bootstrap" json:"bootstrap,omitempty"` + BootstrapExpect *int `mapstructure:"bootstrap_expect" json:"bootstrap_expect,omitempty"` + Cache Cache `mapstructure:"cache" json:"-"` + Check *CheckDefinition `mapstructure:"check" json:"-"` // needs to be a pointer to avoid partial merges + CheckOutputMaxSize *int `mapstructure:"check_output_max_size" json:"check_output_max_size,omitempty"` + CheckUpdateInterval *string `mapstructure:"check_update_interval" json:"check_update_interval,omitempty"` + Checks []CheckDefinition `mapstructure:"checks" json:"-"` + ClientAddr *string `mapstructure:"client_addr" json:"client_addr,omitempty"` + Cloud *CloudConfigRaw `mapstructure:"cloud" json:"-"` + ConfigEntries ConfigEntries `mapstructure:"config_entries" json:"-"` + AutoEncrypt AutoEncrypt `mapstructure:"auto_encrypt" json:"auto_encrypt,omitempty"` + Connect Connect `mapstructure:"connect" json:"connect,omitempty"` + DNS DNS `mapstructure:"dns_config" json:"-"` + DNSDomain *string `mapstructure:"domain" json:"domain,omitempty"` + DNSAltDomain *string `mapstructure:"alt_domain" json:"alt_domain,omitempty"` + DNSRecursors []string `mapstructure:"recursors" json:"recursors,omitempty"` + DataDir *string `mapstructure:"data_dir" json:"data_dir,omitempty"` + Datacenter *string `mapstructure:"datacenter" json:"datacenter,omitempty"` + DefaultQueryTime *string `mapstructure:"default_query_time" json:"default_query_time,omitempty"` + DisableAnonymousSignature *bool `mapstructure:"disable_anonymous_signature" json:"disable_anonymous_signature,omitempty"` + DisableCoordinates *bool `mapstructure:"disable_coordinates" json:"disable_coordinates,omitempty"` + DisableHostNodeID *bool `mapstructure:"disable_host_node_id" json:"disable_host_node_id,omitempty"` + DisableHTTPUnprintableCharFilter *bool `mapstructure:"disable_http_unprintable_char_filter" json:"disable_http_unprintable_char_filter,omitempty"` + DisableKeyringFile *bool `mapstructure:"disable_keyring_file" json:"disable_keyring_file,omitempty"` + DisableRemoteExec *bool `mapstructure:"disable_remote_exec" json:"disable_remote_exec,omitempty"` + DisableUpdateCheck *bool `mapstructure:"disable_update_check" json:"disable_update_check,omitempty"` + DiscardCheckOutput *bool `mapstructure:"discard_check_output" json:"discard_check_output,omitempty"` + DiscoveryMaxStale *string `mapstructure:"discovery_max_stale" json:"discovery_max_stale,omitempty"` + EnableAgentTLSForChecks *bool `mapstructure:"enable_agent_tls_for_checks" json:"enable_agent_tls_for_checks,omitempty"` + EnableCentralServiceConfig *bool `mapstructure:"enable_central_service_config" json:"enable_central_service_config,omitempty"` + EnableDebug *bool `mapstructure:"enable_debug" json:"enable_debug,omitempty"` + EnableScriptChecks *bool `mapstructure:"enable_script_checks" json:"enable_script_checks,omitempty"` + EnableLocalScriptChecks *bool `mapstructure:"enable_local_script_checks" json:"enable_local_script_checks,omitempty"` + EnableSyslog *bool `mapstructure:"enable_syslog" json:"enable_syslog,omitempty"` + EncryptKey *string `mapstructure:"encrypt" json:"encrypt,omitempty"` + EncryptVerifyIncoming *bool `mapstructure:"encrypt_verify_incoming" json:"encrypt_verify_incoming,omitempty"` + EncryptVerifyOutgoing *bool `mapstructure:"encrypt_verify_outgoing" json:"encrypt_verify_outgoing,omitempty"` + GossipLAN GossipLANConfig `mapstructure:"gossip_lan" json:"-"` + GossipWAN GossipWANConfig `mapstructure:"gossip_wan" json:"-"` + HTTPConfig HTTPConfig `mapstructure:"http_config" json:"-"` + LeaveOnTerm *bool `mapstructure:"leave_on_terminate" json:"leave_on_terminate,omitempty"` + LicensePath *string `mapstructure:"license_path" json:"license_path,omitempty"` + Limits Limits `mapstructure:"limits" json:"-"` + LogLevel *string `mapstructure:"log_level" json:"log_level,omitempty"` + LogJSON *bool `mapstructure:"log_json" json:"log_json,omitempty"` + LogFile *string `mapstructure:"log_file" json:"log_file,omitempty"` + LogRotateDuration *string `mapstructure:"log_rotate_duration" json:"log_rotate_duration,omitempty"` + LogRotateBytes *int `mapstructure:"log_rotate_bytes" json:"log_rotate_bytes,omitempty"` + LogRotateMaxFiles *int `mapstructure:"log_rotate_max_files" json:"log_rotate_max_files,omitempty"` + MaxQueryTime *string `mapstructure:"max_query_time" json:"max_query_time,omitempty"` + NodeID *string `mapstructure:"node_id" json:"node_id,omitempty"` + NodeMeta map[string]string `mapstructure:"node_meta" json:"node_meta,omitempty"` + NodeName *string `mapstructure:"node_name" json:"node_name,omitempty"` + Peering Peering `mapstructure:"peering" json:"peering,omitempty"` + Performance Performance `mapstructure:"performance" json:"-"` + PidFile *string `mapstructure:"pid_file" json:"pid_file,omitempty"` + Ports Ports `mapstructure:"ports" json:"ports,omitempty"` + PrimaryDatacenter *string `mapstructure:"primary_datacenter" json:"primary_datacenter,omitempty"` + PrimaryGateways []string `mapstructure:"primary_gateways" json:"primary_gateways,omitempty"` + PrimaryGatewaysInterval *string `mapstructure:"primary_gateways_interval" json:"primary_gateways_interval,omitempty"` + RPCProtocol *int `mapstructure:"protocol" json:"protocol,omitempty"` + RaftProtocol *int `mapstructure:"raft_protocol" json:"raft_protocol,omitempty"` + RaftSnapshotThreshold *int `mapstructure:"raft_snapshot_threshold" json:"raft_snapshot_threshold,omitempty"` + RaftSnapshotInterval *string `mapstructure:"raft_snapshot_interval" json:"raft_snapshot_interval,omitempty"` + RaftTrailingLogs *int `mapstructure:"raft_trailing_logs" json:"raft_trailing_logs,omitempty"` + ReconnectTimeoutLAN *string `mapstructure:"reconnect_timeout" json:"reconnect_timeout,omitempty"` + ReconnectTimeoutWAN *string `mapstructure:"reconnect_timeout_wan" json:"reconnect_timeout_wan,omitempty"` + RejoinAfterLeave *bool `mapstructure:"rejoin_after_leave" json:"rejoin_after_leave,omitempty"` + AutoReloadConfig *bool `mapstructure:"auto_reload_config" json:"auto_reload_config,omitempty"` + RetryJoinIntervalLAN *string `mapstructure:"retry_interval" json:"retry_interval,omitempty"` + RetryJoinIntervalWAN *string `mapstructure:"retry_interval_wan" json:"retry_interval_wan,omitempty"` + RetryJoinLAN []string `mapstructure:"retry_join" json:"retry_join,omitempty"` + RetryJoinMaxAttemptsLAN *int `mapstructure:"retry_max" json:"retry_max,omitempty"` + RetryJoinMaxAttemptsWAN *int `mapstructure:"retry_max_wan" json:"retry_max_wan,omitempty"` + RetryJoinWAN []string `mapstructure:"retry_join_wan" json:"retry_join_wan,omitempty"` + SerfAllowedCIDRsLAN []string `mapstructure:"serf_lan_allowed_cidrs" json:"serf_lan_allowed_cidrs,omitempty"` + SerfAllowedCIDRsWAN []string `mapstructure:"serf_wan_allowed_cidrs" json:"serf_wan_allowed_cidrs,omitempty"` + SerfBindAddrLAN *string `mapstructure:"serf_lan" json:"serf_lan,omitempty"` + SerfBindAddrWAN *string `mapstructure:"serf_wan" json:"serf_wan,omitempty"` + ServerMode *bool `mapstructure:"server" json:"server,omitempty"` + ServerName *string `mapstructure:"server_name" json:"server_name,omitempty"` + Service *ServiceDefinition `mapstructure:"service" json:"-"` + Services []ServiceDefinition `mapstructure:"services" json:"-"` + SessionTTLMin *string `mapstructure:"session_ttl_min" json:"session_ttl_min,omitempty"` + SkipLeaveOnInt *bool `mapstructure:"skip_leave_on_interrupt" json:"skip_leave_on_interrupt,omitempty"` + StartJoinAddrsLAN []string `mapstructure:"start_join" json:"start_join,omitempty"` + StartJoinAddrsWAN []string `mapstructure:"start_join_wan" json:"start_join_wan,omitempty"` + SyslogFacility *string `mapstructure:"syslog_facility" json:"syslog_facility,omitempty"` + TLS TLS `mapstructure:"tls" json:"tls,omitempty"` + TaggedAddresses map[string]string `mapstructure:"tagged_addresses" json:"tagged_addresses,omitempty"` + Telemetry Telemetry `mapstructure:"telemetry" json:"telemetry,omitempty"` + TranslateWANAddrs *bool `mapstructure:"translate_wan_addrs" json:"translate_wan_addrs,omitempty"` + XDS XDS `mapstructure:"xds" json:"-"` // DEPRECATED (ui-config) - moved to the ui_config stanza - UI *bool `mapstructure:"ui"` + UI *bool `mapstructure:"ui" json:"-"` // DEPRECATED (ui-config) - moved to the ui_config stanza - UIContentPath *string `mapstructure:"ui_content_path"` + UIContentPath *string `mapstructure:"ui_content_path" json:"-"` // DEPRECATED (ui-config) - moved to the ui_config stanza - UIDir *string `mapstructure:"ui_dir"` - UIConfig RawUIConfig `mapstructure:"ui_config"` + UIDir *string `mapstructure:"ui_dir" json:"-"` + UIConfig RawUIConfig `mapstructure:"ui_config" json:"-"` - UnixSocket UnixSocket `mapstructure:"unix_sockets"` - Watches []map[string]interface{} `mapstructure:"watches"` + UnixSocket UnixSocket `mapstructure:"unix_sockets" json:"-"` + Watches []map[string]interface{} `mapstructure:"watches" json:"-"` - RPC RPC `mapstructure:"rpc"` + RPC RPC `mapstructure:"rpc" json:"-"` - RaftBoltDBConfig *consul.RaftBoltDBConfig `mapstructure:"raft_boltdb"` + RaftBoltDBConfig *consul.RaftBoltDBConfig `mapstructure:"raft_boltdb" json:"-"` // UseStreamingBackend instead of blocking queries for service health and // any other endpoints which support streaming. - UseStreamingBackend *bool `mapstructure:"use_streaming_backend"` + UseStreamingBackend *bool `mapstructure:"use_streaming_backend" json:"-"` // This isn't used by Consul but we've documented a feature where users // can deploy their snapshot agent configs alongside their Consul configs // so we have a placeholder here so it can be parsed but this doesn't // manifest itself in any way inside the runtime config. - SnapshotAgent map[string]interface{} `mapstructure:"snapshot_agent"` + SnapshotAgent map[string]interface{} `mapstructure:"snapshot_agent" json:"-"` // non-user configurable values - AEInterval *string `mapstructure:"ae_interval"` - CheckDeregisterIntervalMin *string `mapstructure:"check_deregister_interval_min"` - CheckReapInterval *string `mapstructure:"check_reap_interval"` - Consul Consul `mapstructure:"consul"` - Revision *string `mapstructure:"revision"` - SegmentLimit *int `mapstructure:"segment_limit"` - SegmentNameLimit *int `mapstructure:"segment_name_limit"` - SyncCoordinateIntervalMin *string `mapstructure:"sync_coordinate_interval_min"` - SyncCoordinateRateTarget *float64 `mapstructure:"sync_coordinate_rate_target"` - Version *string `mapstructure:"version"` - VersionPrerelease *string `mapstructure:"version_prerelease"` - VersionMetadata *string `mapstructure:"version_metadata"` - BuildDate *time.Time `mapstructure:"build_date"` + AEInterval *string `mapstructure:"ae_interval" json:"-"` + CheckDeregisterIntervalMin *string `mapstructure:"check_deregister_interval_min" json:"-"` + CheckReapInterval *string `mapstructure:"check_reap_interval" json:"-"` + Consul Consul `mapstructure:"consul" json:"-"` + Revision *string `mapstructure:"revision" json:"-"` + SegmentLimit *int `mapstructure:"segment_limit" json:"-"` + SegmentNameLimit *int `mapstructure:"segment_name_limit" json:"-"` + SyncCoordinateIntervalMin *string `mapstructure:"sync_coordinate_interval_min" json:"-"` + SyncCoordinateRateTarget *float64 `mapstructure:"sync_coordinate_rate_target" json:"-"` + Version *string `mapstructure:"version" json:"-"` + VersionPrerelease *string `mapstructure:"version_prerelease" json:"-"` + VersionMetadata *string `mapstructure:"version_metadata" json:"-"` + BuildDate *time.Time `mapstructure:"build_date" json:"-"` // Enterprise Only - Audit Audit `mapstructure:"audit"` + Audit Audit `mapstructure:"audit" json:"-"` // Enterprise Only - ReadReplica *bool `mapstructure:"read_replica" alias:"non_voting_server"` + ReadReplica *bool `mapstructure:"read_replica" alias:"non_voting_server" json:"-"` // Enterprise Only - SegmentName *string `mapstructure:"segment"` + SegmentName *string `mapstructure:"segment" json:"-"` // Enterprise Only - Segments []Segment `mapstructure:"segments"` + Segments []Segment `mapstructure:"segments" json:"-"` // Enterprise Only - Partition *string `mapstructure:"partition"` + Partition *string `mapstructure:"partition" json:"-"` // Enterprise Only - not user configurable - LicensePollBaseTime *string `mapstructure:"license_poll_base_time"` - LicensePollMaxTime *string `mapstructure:"license_poll_max_time"` - LicenseUpdateBaseTime *string `mapstructure:"license_update_base_time"` - LicenseUpdateMaxTime *string `mapstructure:"license_update_max_time"` + LicensePollBaseTime *string `mapstructure:"license_poll_base_time" json:"-"` + LicensePollMaxTime *string `mapstructure:"license_poll_max_time" json:"-"` + LicenseUpdateBaseTime *string `mapstructure:"license_update_base_time" json:"-"` + LicenseUpdateMaxTime *string `mapstructure:"license_update_max_time" json:"-"` + + // license reporting + Reporting Reporting `mapstructure:"reporting" json:"-"` } type GossipLANConfig struct { @@ -592,33 +595,33 @@ type ExposePath struct { // AutoEncrypt is the agent-global auto_encrypt configuration. type AutoEncrypt struct { // TLS enables receiving certificates for clients from servers - TLS *bool `mapstructure:"tls"` + TLS *bool `mapstructure:"tls" json:"tls,omitempty"` // Additional DNS SAN entries that clients request for their certificates. - DNSSAN []string `mapstructure:"dns_san"` + DNSSAN []string `mapstructure:"dns_san" json:"dns_san,omitempty"` // Additional IP SAN entries that clients request for their certificates. - IPSAN []string `mapstructure:"ip_san"` + IPSAN []string `mapstructure:"ip_san" json:"ip_san,omitempty"` // AllowTLS enables the RPC endpoint on the server to answer // AutoEncrypt.Sign requests. - AllowTLS *bool `mapstructure:"allow_tls"` + AllowTLS *bool `mapstructure:"allow_tls" json:"allow_tls,omitempty"` } // Connect is the agent-global connect configuration. type Connect struct { // Enabled opts the agent into connect. It should be set on all clients and // servers in a cluster for correct connect operation. - Enabled *bool `mapstructure:"enabled"` - CAProvider *string `mapstructure:"ca_provider"` - CAConfig map[string]interface{} `mapstructure:"ca_config"` - MeshGatewayWANFederationEnabled *bool `mapstructure:"enable_mesh_gateway_wan_federation"` - EnableServerlessPlugin *bool `mapstructure:"enable_serverless_plugin"` + Enabled *bool `mapstructure:"enabled" json:"enabled,omitempty"` + CAProvider *string `mapstructure:"ca_provider" json:"ca_provider,omitempty"` + CAConfig map[string]interface{} `mapstructure:"ca_config" json:"ca_config,omitempty"` + MeshGatewayWANFederationEnabled *bool `mapstructure:"enable_mesh_gateway_wan_federation" json:"enable_mesh_gateway_wan_federation,omitempty"` + EnableServerlessPlugin *bool `mapstructure:"enable_serverless_plugin" json:"enable_serverless_plugin,omitempty"` // TestCALeafRootChangeSpread controls how long after a CA roots change before new leaf certs will be generated. // This is only tuned in tests, generally set to 1ns to make tests deterministic with when to expect updated leaf // certs by. This configuration is not exposed to users (not documented, and agent/config/default.go will override it) - TestCALeafRootChangeSpread *string `mapstructure:"test_ca_leaf_root_change_spread"` + TestCALeafRootChangeSpread *string `mapstructure:"test_ca_leaf_root_change_spread" json:"test_ca_leaf_root_change_spread,omitempty"` } // SOA is the configuration of SOA for DNS @@ -665,46 +668,46 @@ type Performance struct { } type Telemetry struct { - CirconusAPIApp *string `mapstructure:"circonus_api_app"` - CirconusAPIToken *string `mapstructure:"circonus_api_token"` - CirconusAPIURL *string `mapstructure:"circonus_api_url"` - CirconusBrokerID *string `mapstructure:"circonus_broker_id"` - CirconusBrokerSelectTag *string `mapstructure:"circonus_broker_select_tag"` - CirconusCheckDisplayName *string `mapstructure:"circonus_check_display_name"` - CirconusCheckForceMetricActivation *string `mapstructure:"circonus_check_force_metric_activation"` - CirconusCheckID *string `mapstructure:"circonus_check_id"` - CirconusCheckInstanceID *string `mapstructure:"circonus_check_instance_id"` - CirconusCheckSearchTag *string `mapstructure:"circonus_check_search_tag"` - CirconusCheckTags *string `mapstructure:"circonus_check_tags"` - CirconusSubmissionInterval *string `mapstructure:"circonus_submission_interval"` - CirconusSubmissionURL *string `mapstructure:"circonus_submission_url"` - DisableHostname *bool `mapstructure:"disable_hostname"` - DogstatsdAddr *string `mapstructure:"dogstatsd_addr"` - DogstatsdTags []string `mapstructure:"dogstatsd_tags"` - RetryFailedConfiguration *bool `mapstructure:"retry_failed_connection"` - FilterDefault *bool `mapstructure:"filter_default"` - PrefixFilter []string `mapstructure:"prefix_filter"` - MetricsPrefix *string `mapstructure:"metrics_prefix"` - PrometheusRetentionTime *string `mapstructure:"prometheus_retention_time"` - StatsdAddr *string `mapstructure:"statsd_address"` - StatsiteAddr *string `mapstructure:"statsite_address"` + CirconusAPIApp *string `mapstructure:"circonus_api_app" json:"circonus_api_app,omitempty"` + CirconusAPIToken *string `mapstructure:"circonus_api_token" json:"circonus_api_token,omitempty"` + CirconusAPIURL *string `mapstructure:"circonus_api_url" json:"circonus_api_url,omitempty"` + CirconusBrokerID *string `mapstructure:"circonus_broker_id" json:"circonus_broker_id,omitempty"` + CirconusBrokerSelectTag *string `mapstructure:"circonus_broker_select_tag" json:"circonus_broker_select_tag,omitempty"` + CirconusCheckDisplayName *string `mapstructure:"circonus_check_display_name" json:"circonus_check_display_name,omitempty"` + CirconusCheckForceMetricActivation *string `mapstructure:"circonus_check_force_metric_activation" json:"circonus_check_force_metric_activation,omitempty"` + CirconusCheckID *string `mapstructure:"circonus_check_id" json:"circonus_check_id,omitempty"` + CirconusCheckInstanceID *string `mapstructure:"circonus_check_instance_id" json:"circonus_check_instance_id,omitempty"` + CirconusCheckSearchTag *string `mapstructure:"circonus_check_search_tag" json:"circonus_check_search_tag,omitempty"` + CirconusCheckTags *string `mapstructure:"circonus_check_tags" json:"circonus_check_tags,omitempty"` + CirconusSubmissionInterval *string `mapstructure:"circonus_submission_interval" json:"circonus_submission_interval,omitempty"` + CirconusSubmissionURL *string `mapstructure:"circonus_submission_url" json:"circonus_submission_url,omitempty"` + DisableHostname *bool `mapstructure:"disable_hostname" json:"disable_hostname,omitempty"` + DogstatsdAddr *string `mapstructure:"dogstatsd_addr" json:"dogstatsd_addr,omitempty"` + DogstatsdTags []string `mapstructure:"dogstatsd_tags" json:"dogstatsd_tags,omitempty"` + RetryFailedConfiguration *bool `mapstructure:"retry_failed_connection" json:"retry_failed_connection,omitempty"` + FilterDefault *bool `mapstructure:"filter_default" json:"filter_default,omitempty"` + PrefixFilter []string `mapstructure:"prefix_filter" json:"prefix_filter,omitempty"` + MetricsPrefix *string `mapstructure:"metrics_prefix" json:"metrics_prefix,omitempty"` + PrometheusRetentionTime *string `mapstructure:"prometheus_retention_time" json:"prometheus_retention_time,omitempty"` + StatsdAddr *string `mapstructure:"statsd_address" json:"statsd_address,omitempty"` + StatsiteAddr *string `mapstructure:"statsite_address" json:"statsite_address,omitempty"` } type Ports struct { - DNS *int `mapstructure:"dns"` - HTTP *int `mapstructure:"http"` - HTTPS *int `mapstructure:"https"` - SerfLAN *int `mapstructure:"serf_lan"` - SerfWAN *int `mapstructure:"serf_wan"` - Server *int `mapstructure:"server"` - GRPC *int `mapstructure:"grpc"` - GRPCTLS *int `mapstructure:"grpc_tls"` - ProxyMinPort *int `mapstructure:"proxy_min_port"` - ProxyMaxPort *int `mapstructure:"proxy_max_port"` - SidecarMinPort *int `mapstructure:"sidecar_min_port"` - SidecarMaxPort *int `mapstructure:"sidecar_max_port"` - ExposeMinPort *int `mapstructure:"expose_min_port"` - ExposeMaxPort *int `mapstructure:"expose_max_port"` + DNS *int `mapstructure:"dns" json:"dns,omitempty"` + HTTP *int `mapstructure:"http" json:"http,omitempty"` + HTTPS *int `mapstructure:"https" json:"https,omitempty"` + SerfLAN *int `mapstructure:"serf_lan" json:"serf_lan,omitempty"` + SerfWAN *int `mapstructure:"serf_wan" json:"serf_wan,omitempty"` + Server *int `mapstructure:"server" json:"server,omitempty"` + GRPC *int `mapstructure:"grpc" json:"grpc,omitempty"` + GRPCTLS *int `mapstructure:"grpc_tls" json:"grpc_tls,omitempty"` + ProxyMinPort *int `mapstructure:"proxy_min_port" json:"proxy_min_port,omitempty"` + ProxyMaxPort *int `mapstructure:"proxy_max_port" json:"proxy_max_port,omitempty"` + SidecarMinPort *int `mapstructure:"sidecar_min_port" json:"sidecar_min_port,omitempty"` + SidecarMaxPort *int `mapstructure:"sidecar_max_port" json:"sidecar_max_port,omitempty"` + ExposeMinPort *int `mapstructure:"expose_min_port" json:"expose_min_port,omitempty" ` + ExposeMaxPort *int `mapstructure:"expose_max_port" json:"expose_max_port,omitempty"` } type UnixSocket struct { @@ -873,23 +876,23 @@ type CloudConfigRaw struct { } type TLSProtocolConfig struct { - CAFile *string `mapstructure:"ca_file"` - CAPath *string `mapstructure:"ca_path"` - CertFile *string `mapstructure:"cert_file"` - KeyFile *string `mapstructure:"key_file"` - TLSMinVersion *string `mapstructure:"tls_min_version"` - TLSCipherSuites *string `mapstructure:"tls_cipher_suites"` - VerifyIncoming *bool `mapstructure:"verify_incoming"` - VerifyOutgoing *bool `mapstructure:"verify_outgoing"` - VerifyServerHostname *bool `mapstructure:"verify_server_hostname"` - UseAutoCert *bool `mapstructure:"use_auto_cert"` + CAFile *string `mapstructure:"ca_file" json:"ca_file,omitempty"` + CAPath *string `mapstructure:"ca_path" json:"ca_path,omitempty"` + CertFile *string `mapstructure:"cert_file" json:"cert_file,omitempty"` + KeyFile *string `mapstructure:"key_file" json:"key_file,omitempty"` + TLSMinVersion *string `mapstructure:"tls_min_version" json:"tls_min_version,omitempty"` + TLSCipherSuites *string `mapstructure:"tls_cipher_suites" json:"tls_cipher_suites,omitempty"` + VerifyIncoming *bool `mapstructure:"verify_incoming" json:"verify_incoming,omitempty"` + VerifyOutgoing *bool `mapstructure:"verify_outgoing" json:"verify_outgoing,omitempty"` + VerifyServerHostname *bool `mapstructure:"verify_server_hostname" json:"verify_server_hostname,omitempty"` + UseAutoCert *bool `mapstructure:"use_auto_cert" json:"use_auto_cert,omitempty"` } type TLS struct { - Defaults TLSProtocolConfig `mapstructure:"defaults"` - InternalRPC TLSProtocolConfig `mapstructure:"internal_rpc"` - HTTPS TLSProtocolConfig `mapstructure:"https"` - GRPC TLSProtocolConfig `mapstructure:"grpc"` + Defaults TLSProtocolConfig `mapstructure:"defaults" json:"defaults,omitempty"` + InternalRPC TLSProtocolConfig `mapstructure:"internal_rpc" json:"internal_rpc,omitempty"` + HTTPS TLSProtocolConfig `mapstructure:"https" json:"https,omitempty"` + GRPC TLSProtocolConfig `mapstructure:"grpc" json:"grpc,omitempty"` // GRPCModifiedByDeprecatedConfig is a flag used to indicate that GRPC was // modified by the deprecated field mapping (as apposed to a user-provided @@ -902,17 +905,25 @@ type TLS struct { // // Note: we use a *struct{} here because a simple bool isn't supported by our // config merging logic. - GRPCModifiedByDeprecatedConfig *struct{} `mapstructure:"-"` + GRPCModifiedByDeprecatedConfig *struct{} `mapstructure:"-" json:"-"` } type Peering struct { - Enabled *bool `mapstructure:"enabled"` + Enabled *bool `mapstructure:"enabled" json:"enabled,omitempty"` // TestAllowPeerRegistrations controls whether CatalogRegister endpoints allow registrations for objects with `PeerName` // This always gets overridden in NonUserSource() - TestAllowPeerRegistrations *bool `mapstructure:"test_allow_peer_registrations"` + TestAllowPeerRegistrations *bool `mapstructure:"test_allow_peer_registrations" json:"test_allow_peer_registrations,omitempty"` } type XDS struct { UpdateMaxPerSecond *float64 `mapstructure:"update_max_per_second"` } + +type License struct { + Enabled *bool `mapstructure:"enabled"` +} + +type Reporting struct { + License License `mapstructure:"license"` +} diff --git a/agent/config/config_oss.go b/agent/config/config_ce.go similarity index 100% rename from agent/config/config_oss.go rename to agent/config/config_ce.go diff --git a/agent/config/deep-copy.sh b/agent/config/deep-copy.sh new file mode 100644 index 000000000000..f69b95da931d --- /dev/null +++ b/agent/config/deep-copy.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +readonly PACKAGE_DIR="$(dirname "${BASH_SOURCE[0]}")" +cd $PACKAGE_DIR + +# Uses: https://github.com/globusdigital/deep-copy +deep-copy \ + -pointer-receiver \ + -o ./config.deepcopy.go \ + -type RuntimeConfig \ + ./ diff --git a/agent/config/default.go b/agent/config/default.go index 62f39f6cc903..e80a0d6c3140 100644 --- a/agent/config/default.go +++ b/agent/config/default.go @@ -139,6 +139,14 @@ func DefaultSource() Source { xds { update_max_per_second = 250 } + + connect = { + enabled = true + } + + peering = { + enabled = true + } `, } } @@ -176,6 +184,11 @@ func DevSource() Source { connect = { enabled = true } + + peering = { + enabled = true + } + performance = { raft_multiplier = 1 } diff --git a/agent/config/default_oss.go b/agent/config/default_ce.go similarity index 100% rename from agent/config/default_oss.go rename to agent/config/default_ce.go diff --git a/agent/config/file_watcher.go b/agent/config/file_watcher.go index d62d1903542c..f0458af5f55c 100644 --- a/agent/config/file_watcher.go +++ b/agent/config/file_watcher.go @@ -47,7 +47,7 @@ type FileWatcherEvent struct { Filenames []string } -//NewFileWatcher create a file watcher that will watch all the files/folders from configFiles +// NewFileWatcher create a file watcher that will watch all the files/folders from configFiles // if success a fileWatcher will be returned and a nil error // otherwise an error and a nil fileWatcher are returned func NewFileWatcher(configFiles []string, logger hclog.Logger) (Watcher, error) { diff --git a/agent/config/runtime.go b/agent/config/runtime.go index 5388f3d7c6fa..93784ff42ee2 100644 --- a/agent/config/runtime.go +++ b/agent/config/runtime.go @@ -1465,9 +1465,23 @@ type RuntimeConfig struct { // AutoReloadConfigCoalesceInterval Coalesce Interval for auto reload config AutoReloadConfigCoalesceInterval time.Duration + Reporting ReportingConfig + + // LocalProxyConfigResyncInterval is not a user-configurable value and exists + // here so that tests can use a smaller value. + LocalProxyConfigResyncInterval time.Duration + EnterpriseRuntimeConfig } +type LicenseConfig struct { + Enabled bool +} + +type ReportingConfig struct { + License LicenseConfig +} + type AutoConfig struct { Enabled bool IntroToken string @@ -1709,6 +1723,9 @@ func (c *RuntimeConfig) Sanitized() map[string]interface{} { // IsCloudEnabled returns true if a cloud.resource_id is set and the server mode is enabled func (c *RuntimeConfig) IsCloudEnabled() bool { + if c == nil { + return false + } return c.ServerMode && c.Cloud.ResourceID != "" } diff --git a/agent/config/runtime_oss.go b/agent/config/runtime_ce.go similarity index 100% rename from agent/config/runtime_oss.go rename to agent/config/runtime_ce.go diff --git a/agent/config/runtime_oss_test.go b/agent/config/runtime_ce_test.go similarity index 53% rename from agent/config/runtime_oss_test.go rename to agent/config/runtime_ce_test.go index f60a1c740c3e..19a96328abb0 100644 --- a/agent/config/runtime_oss_test.go +++ b/agent/config/runtime_ce_test.go @@ -5,10 +5,12 @@ package config import ( "fmt" + "net" "os" "testing" "github.com/hashicorp/consul/sdk/testutil" + "github.com/stretchr/testify/require" ) var testRuntimeConfigSanitizeExpectedFilename = "TestRuntimeConfig_Sanitize.golden" @@ -27,11 +29,12 @@ var enterpriseConfigKeyWarnings = []string{ enterpriseConfigKeyError{key: "acl.msp_disable_bootstrap"}.Error(), enterpriseConfigKeyError{key: "acl.tokens.managed_service_provider"}.Error(), enterpriseConfigKeyError{key: "audit"}.Error(), + enterpriseConfigKeyError{key: "reporting.license.enabled"}.Error(), } -// OSS-only equivalent of TestConfigFlagsAndEdgecases +// CE-only equivalent of TestConfigFlagsAndEdgecases // used for flags validated in ent-only code -func TestLoad_IntegrationWithFlags_OSS(t *testing.T) { +func TestLoad_IntegrationWithFlags_CE(t *testing.T) { dataDir := testutil.TempDir(t, "consul") defer os.RemoveAll(dataDir) @@ -70,6 +73,8 @@ func TestLoad_IntegrationWithFlags_OSS(t *testing.T) { rt.LeaveOnTerm = false rt.SkipLeaveOnInt = true rt.RPCConfig.EnableStreaming = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} }, }, } @@ -81,3 +86,82 @@ func TestLoad_IntegrationWithFlags_OSS(t *testing.T) { } } } + +func TestLoad_ReportingConfig(t *testing.T) { + dir := testutil.TempDir(t, t.Name()) + + t.Run("load from JSON defaults to false", func(t *testing.T) { + content := `{ + "reporting": {} + }` + + opts := LoadOpts{ + FlagValues: Config{ + DataDir: &dir, + }, + Overrides: []Source{ + FileSource{ + Name: "reporting.json", + Format: "json", + Data: content, + }, + }, + } + patchLoadOptsShims(&opts) + result, err := Load(opts) + require.NoError(t, err) + require.Len(t, result.Warnings, 0) + require.Equal(t, false, result.RuntimeConfig.Reporting.License.Enabled) + }) + + t.Run("load from HCL defaults to false", func(t *testing.T) { + content := ` + reporting {} + ` + + opts := LoadOpts{ + FlagValues: Config{ + DataDir: &dir, + }, + Overrides: []Source{ + FileSource{ + Name: "reporting.hcl", + Format: "hcl", + Data: content, + }, + }, + } + patchLoadOptsShims(&opts) + result, err := Load(opts) + require.NoError(t, err) + require.Len(t, result.Warnings, 0) + require.Equal(t, false, result.RuntimeConfig.Reporting.License.Enabled) + }) + + t.Run("with value set returns warning and defaults to false", func(t *testing.T) { + content := `reporting { + license { + enabled = true + } + }` + + opts := LoadOpts{ + FlagValues: Config{ + DataDir: &dir, + }, + Overrides: []Source{ + FileSource{ + Name: "reporting.hcl", + Format: "hcl", + Data: content, + }, + }, + } + patchLoadOptsShims(&opts) + result, err := Load(opts) + require.NoError(t, err) + require.Len(t, result.Warnings, 1) + require.Contains(t, result.Warnings[0], "\"reporting.license.enabled\" is a Consul Enterprise configuration and will have no effect") + require.Equal(t, false, result.RuntimeConfig.Reporting.License.Enabled) + }) +} diff --git a/agent/config/runtime_test.go b/agent/config/runtime_test.go index 3228dea0e775..470fd44d41ef 100644 --- a/agent/config/runtime_test.go +++ b/agent/config/runtime_test.go @@ -9,6 +9,7 @@ import ( "fmt" "io/ioutil" "net" + "net/netip" "os" "path/filepath" "reflect" @@ -57,6 +58,8 @@ func (tc testCase) source(format string) []string { return tc.json } +var defaultGrpcTlsAddr = net.TCPAddrFromAddrPort(netip.MustParseAddrPort("127.0.0.1:8503")) + // TestConfigFlagsAndEdgecases tests the command line flags and // edgecases for the config parsing. It provides a test structure which // checks for warnings on deprecated fields and flags. These tests @@ -184,6 +187,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { rt.SkipLeaveOnInt = true rt.DataDir = dataDir rt.RPCConfig.EnableStreaming = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} }, expectedWarnings: []string{"bootstrap = true: do not enable unless necessary"}, }) @@ -202,6 +207,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { rt.SkipLeaveOnInt = true rt.DataDir = dataDir rt.RPCConfig.EnableStreaming = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} }, expectedWarnings: []string{"bootstrap_expect > 0: expecting 3 servers"}, }) @@ -348,6 +355,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { rt.GRPCPort = 8502 rt.GRPCAddrs = []net.Addr{tcpAddr("127.0.0.1:8502")} rt.RPCConfig.EnableStreaming = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} }, }) run(t, testCase{ @@ -669,6 +678,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { rt.LeaveOnTerm = false rt.SkipLeaveOnInt = true rt.RPCConfig.EnableStreaming = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} }, }) run(t, testCase{ @@ -853,6 +864,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { rt.SkipLeaveOnInt = true rt.DataDir = dataDir rt.RPCConfig.EnableStreaming = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} }, }) run(t, testCase{ @@ -1893,6 +1906,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { rt.SkipLeaveOnInt = true rt.DataDir = dataDir rt.RPCConfig.EnableStreaming = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} }, expectedWarnings: []string{"BootstrapExpect is set to 1; this is the same as Bootstrap mode.", "bootstrap = true: do not enable unless necessary"}, }) @@ -1911,6 +1926,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { rt.SkipLeaveOnInt = true rt.DataDir = dataDir rt.RPCConfig.EnableStreaming = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} }, expectedWarnings: []string{ `bootstrap_expect = 2: A cluster with 2 servers will provide no failure tolerance. See https://www.consul.io/docs/internals/consensus.html#deployment-table`, @@ -1932,6 +1949,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { rt.SkipLeaveOnInt = true rt.DataDir = dataDir rt.RPCConfig.EnableStreaming = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} }, expectedWarnings: []string{ `bootstrap_expect is even number: A cluster with an even number of servers does not achieve optimum fault tolerance. See https://www.consul.io/docs/internals/consensus.html#deployment-table`, @@ -2257,6 +2276,74 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { rt.HTTPUseCache = false }, }) + run(t, testCase{ + desc: "cloud resource id from env", + args: []string{ + `-server`, + `-data-dir=` + dataDir, + }, + setup: func() { + os.Setenv("HCP_RESOURCE_ID", "env-id") + t.Cleanup(func() { + os.Unsetenv("HCP_RESOURCE_ID") + }) + }, + expected: func(rt *RuntimeConfig) { + rt.DataDir = dataDir + rt.Cloud = hcpconfig.CloudConfig{ + // ID is only populated from env if not populated from other sources. + ResourceID: "env-id", + } + + // server things + rt.ServerMode = true + rt.TLS.ServerMode = true + rt.LeaveOnTerm = false + rt.SkipLeaveOnInt = true + rt.RPCConfig.EnableStreaming = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} + }, + }) + run(t, testCase{ + desc: "cloud resource id from file", + args: []string{ + `-server`, + `-data-dir=` + dataDir, + }, + setup: func() { + os.Setenv("HCP_RESOURCE_ID", "env-id") + t.Cleanup(func() { + os.Unsetenv("HCP_RESOURCE_ID") + }) + }, + json: []string{`{ + "cloud": { + "resource_id": "file-id" + } + }`}, + hcl: []string{` + cloud = { + resource_id = "file-id" + } + `}, + expected: func(rt *RuntimeConfig) { + rt.DataDir = dataDir + rt.Cloud = hcpconfig.CloudConfig{ + // ID is only populated from env if not populated from other sources. + ResourceID: "file-id", + } + + // server things + rt.ServerMode = true + rt.TLS.ServerMode = true + rt.LeaveOnTerm = false + rt.SkipLeaveOnInt = true + rt.RPCConfig.EnableStreaming = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} + }, + }) run(t, testCase{ desc: "sidecar_service can't have ID", args: []string{ @@ -3106,6 +3193,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { rt.LeaveOnTerm = false rt.SkipLeaveOnInt = true rt.RPCConfig.EnableStreaming = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} }, }) run(t, testCase{ @@ -3138,6 +3227,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { rt.LeaveOnTerm = false rt.SkipLeaveOnInt = true rt.RPCConfig.EnableStreaming = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} }, }) run(t, testCase{ @@ -3167,6 +3258,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { rt.LeaveOnTerm = false rt.SkipLeaveOnInt = true rt.RPCConfig.EnableStreaming = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} }, }) run(t, testCase{ @@ -3193,6 +3286,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { rt.LeaveOnTerm = false rt.SkipLeaveOnInt = true rt.RPCConfig.EnableStreaming = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} }, }) run(t, testCase{ @@ -3239,6 +3334,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { rt.TLS.ServerMode = true rt.LeaveOnTerm = false rt.SkipLeaveOnInt = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} }, }) run(t, testCase{ @@ -3658,6 +3755,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { rt.LeaveOnTerm = false rt.SkipLeaveOnInt = true rt.RPCConfig.EnableStreaming = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} }, }) @@ -4077,6 +4176,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { "namespace" : "leek", "prefix_rewrite" : "/alternate", "request_timeout" : "99s", + "idle_timeout" : "99s", "num_retries" : 12345, "retry_on_connect_failure": true, "retry_on_status_codes" : [401, 209] @@ -4165,6 +4265,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { namespace = "leek" prefix_rewrite = "/alternate" request_timeout = "99s" + idle_timeout = "99s" num_retries = 12345 retry_on_connect_failure = true retry_on_status_codes = [401, 209] @@ -4254,6 +4355,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { Partition: acl.DefaultPartitionName, PrefixRewrite: "/alternate", RequestTimeout: 99 * time.Second, + IdleTimeout: 99 * time.Second, NumRetries: 12345, RetryOnConnectFailure: true, RetryOnStatusCodes: []uint32{401, 209}, @@ -5082,6 +5184,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { rt.SkipLeaveOnInt = true rt.TLS.InternalRPC.CertFile = "foo" rt.RPCConfig.EnableStreaming = true + rt.GRPCTLSPort = 8503 + rt.GRPCTLSAddrs = []net.Addr{defaultGrpcTlsAddr} }, }) // UI Config tests @@ -5792,12 +5896,13 @@ func TestLoad_FullConfig(t *testing.T) { nodeEntMeta := structs.NodeEnterpriseMetaInDefaultPartition() expected := &RuntimeConfig{ // non-user configurable values - AEInterval: time.Minute, - CheckDeregisterIntervalMin: time.Minute, - CheckReapInterval: 30 * time.Second, - SegmentNameLimit: 64, - SyncCoordinateIntervalMin: 15 * time.Second, - SyncCoordinateRateTarget: 64, + AEInterval: time.Minute, + CheckDeregisterIntervalMin: time.Minute, + CheckReapInterval: 30 * time.Second, + SegmentNameLimit: 64, + SyncCoordinateIntervalMin: 15 * time.Second, + SyncCoordinateRateTarget: 64, + LocalProxyConfigResyncInterval: 30 * time.Second, Revision: "JNtPSav3", Version: "R909Hblt", diff --git a/agent/config/segment_oss.go b/agent/config/segment_ce.go similarity index 100% rename from agent/config/segment_oss.go rename to agent/config/segment_ce.go diff --git a/agent/config/segment_oss_test.go b/agent/config/segment_ce_test.go similarity index 95% rename from agent/config/segment_oss_test.go rename to agent/config/segment_ce_test.go index 52b4a0964cda..e31a9602b416 100644 --- a/agent/config/segment_oss_test.go +++ b/agent/config/segment_ce_test.go @@ -15,7 +15,7 @@ func TestSegments(t *testing.T) { tests := []testCase{ { - desc: "segment name not in OSS", + desc: "segment name not in CE", args: []string{ `-data-dir=` + dataDir, }, @@ -39,7 +39,7 @@ func TestSegments(t *testing.T) { }, }, { - desc: "segments not in OSS", + desc: "segments not in CE", args: []string{ `-data-dir=` + dataDir, }, diff --git a/agent/config/testdata/TestRuntimeConfig_Sanitize.golden b/agent/config/testdata/TestRuntimeConfig_Sanitize.golden index a4c35e4b97e7..3b7498881929 100644 --- a/agent/config/testdata/TestRuntimeConfig_Sanitize.golden +++ b/agent/config/testdata/TestRuntimeConfig_Sanitize.golden @@ -108,9 +108,9 @@ "Method": "", "Name": "zoo", "Notes": "", + "OSService": "", "OutputMaxSize": 4096, "ScriptArgs": [], - "OSService": "", "ServiceID": "", "Shell": "", "Status": "", @@ -130,8 +130,10 @@ "ClientID": "id", "ClientSecret": "hidden", "Hostname": "", + "ManagementToken": "hidden", "ResourceID": "cluster1", - "ScadaAddress": "" + "ScadaAddress": "", + "TLSConfig": null }, "ConfigEntryBootstrap": [], "ConnectCAConfig": {}, @@ -231,6 +233,7 @@ "KVMaxValueSize": 1234567800000000, "LeaveDrainTime": "0s", "LeaveOnTerm": false, + "LocalProxyConfigResyncInterval": "0s", "Logging": { "EnableSyslog": false, "LogFilePath": "", @@ -256,6 +259,7 @@ "PrimaryGatewaysInterval": "0s", "RPCAdvertiseAddr": "", "RPCBindAddr": "", + "RPCClientTimeout": "0s", "RPCConfig": { "EnableStreaming": false }, @@ -265,7 +269,6 @@ "RPCMaxConnsPerClient": 0, "RPCProtocol": 0, "RPCRateLimit": 0, - "RPCClientTimeout": "0s", "RaftBoltDBConfig": { "NoFreelistSync": false }, @@ -277,6 +280,11 @@ "ReconnectTimeoutLAN": "0s", "ReconnectTimeoutWAN": "0s", "RejoinAfterLeave": false, + "Reporting": { + "License": { + "Enabled": false + } + }, "RetryJoinIntervalLAN": "0s", "RetryJoinIntervalWAN": "0s", "RetryJoinLAN": [ @@ -329,6 +337,7 @@ "Method": "", "Name": "blurb", "Notes": "", + "OSService": "", "OutputMaxSize": 4096, "ProxyGRPC": "", "ProxyHTTP": "", @@ -336,7 +345,6 @@ "Shell": "", "Status": "", "SuccessBeforePassing": 0, - "OSService": "", "TCP": "", "TLSServerName": "", "TLSSkipVerify": false, diff --git a/agent/config/testdata/full-config.hcl b/agent/config/testdata/full-config.hcl index 1e38cd48edd3..212829cd98d4 100644 --- a/agent/config/testdata/full-config.hcl +++ b/agent/config/testdata/full-config.hcl @@ -357,6 +357,11 @@ reconnect_timeout = "23739s" reconnect_timeout_wan = "26694s" recursors = [ "63.38.39.58", "92.49.18.18" ] rejoin_after_leave = true +reporting = { + license = { + enabled = false + } +} retry_interval = "8067s" retry_interval_wan = "28866s" retry_join = [ "pbsSFY7U", "l0qLtWij" ] diff --git a/agent/config/testdata/full-config.json b/agent/config/testdata/full-config.json index 507aef157d04..c6b9c4b7479e 100644 --- a/agent/config/testdata/full-config.json +++ b/agent/config/testdata/full-config.json @@ -355,6 +355,11 @@ "reconnect_timeout_wan": "26694s", "recursors": [ "63.38.39.58", "92.49.18.18" ], "rejoin_after_leave": true, + "reporting": { + "license": { + "enabled": false + } + }, "retry_interval": "8067s", "retry_interval_wan": "28866s", "retry_join": [ "pbsSFY7U", "l0qLtWij" ], diff --git a/agent/configentry/config_entry.go b/agent/configentry/config_entry.go index a34a197c4877..7bf308c36f1f 100644 --- a/agent/configentry/config_entry.go +++ b/agent/configentry/config_entry.go @@ -6,9 +6,12 @@ import ( ) // KindName is a value type useful for maps. You can use: -// map[KindName]Payload +// +// map[KindName]Payload +// // instead of: -// map[string]map[string]Payload +// +// map[string]map[string]Payload type KindName struct { Kind string Name string diff --git a/agent/configentry/merge_service_config.go b/agent/configentry/merge_service_config.go index f11d96fcc5d0..94e9d5e869c1 100644 --- a/agent/configentry/merge_service_config.go +++ b/agent/configentry/merge_service_config.go @@ -150,7 +150,7 @@ func MergeServiceConfig(defaults *structs.ServiceConfigResponse, service *struct // localUpstreams stores the upstreams seen from the local registration so that we can merge in the synthetic entries. // In transparent proxy mode ns.Proxy.Upstreams will likely be empty because users do not need to define upstreams explicitly. - // So to store upstream-specific flags from central config, we add entries to ns.Proxy.Upstream with those values. + // So to store upstream-specific flags from central config, we add entries to ns.Proxy.Upstreams with those values. localUpstreams := make(map[structs.ServiceID]struct{}) // Merge upstream defaults into the local registration @@ -173,11 +173,21 @@ func MergeServiceConfig(defaults *structs.ServiceConfigResponse, service *struct us.MeshGateway.Mode = remoteCfg.MeshGateway.Mode } + preMergeProtocol, found := us.Config["protocol"] // Merge in everything else that is read from the map if err := mergo.Merge(&us.Config, remoteCfg.Config); err != nil { return nil, err } + // Reset the protocol to its pre-merged version for peering upstreams. + if us.DestinationPeer != "" { + if found { + us.Config["protocol"] = preMergeProtocol + } else { + delete(us.Config, "protocol") + } + } + // Delete the mesh gateway key from opaque config since this is the value that was resolved from // the servers and NOT the final merged value for this upstream. // Note that we use the "mesh_gateway" key and not other variants like "MeshGateway" because diff --git a/agent/configentry/merge_service_config_test.go b/agent/configentry/merge_service_config_test.go index eb5e97d42053..6e6d46d8b0cd 100644 --- a/agent/configentry/merge_service_config_test.go +++ b/agent/configentry/merge_service_config_test.go @@ -447,6 +447,98 @@ func Test_MergeServiceConfig_UpstreamOverrides(t *testing.T) { }, }, }, + { + name: "peering upstreams ignore protocol overrides", + args: args{ + defaults: &structs.ServiceConfigResponse{ + UpstreamIDConfigs: structs.OpaqueUpstreamConfigs{ + { + Upstream: structs.ServiceID{ + ID: "zap", + EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(), + }, + Config: map[string]interface{}{ + "protocol": "http", + }, + }, + }, + }, + service: &structs.NodeService{ + ID: "foo-proxy", + Service: "foo-proxy", + Proxy: structs.ConnectProxyConfig{ + Upstreams: structs.Upstreams{ + structs.Upstream{ + DestinationPeer: "some-peer", + DestinationName: "zap", + Config: map[string]interface{}{ + "protocol": "tcp", + }, + }, + }, + }, + }, + }, + want: &structs.NodeService{ + ID: "foo-proxy", + Service: "foo-proxy", + Proxy: structs.ConnectProxyConfig{ + Upstreams: structs.Upstreams{ + structs.Upstream{ + DestinationPeer: "some-peer", + DestinationName: "zap", + Config: map[string]interface{}{ + "protocol": "tcp", + }, + }, + }, + }, + }, + }, + { + name: "peering upstreams ignore protocol overrides with unset value", + args: args{ + defaults: &structs.ServiceConfigResponse{ + UpstreamIDConfigs: structs.OpaqueUpstreamConfigs{ + { + Upstream: structs.ServiceID{ + ID: "zap", + EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(), + }, + Config: map[string]interface{}{ + "protocol": "http", + }, + }, + }, + }, + service: &structs.NodeService{ + ID: "foo-proxy", + Service: "foo-proxy", + Proxy: structs.ConnectProxyConfig{ + Upstreams: structs.Upstreams{ + structs.Upstream{ + DestinationPeer: "some-peer", + DestinationName: "zap", + Config: map[string]interface{}{}, + }, + }, + }, + }, + }, + want: &structs.NodeService{ + ID: "foo-proxy", + Service: "foo-proxy", + Proxy: structs.ConnectProxyConfig{ + Upstreams: structs.Upstreams{ + structs.Upstream{ + DestinationPeer: "some-peer", + DestinationName: "zap", + Config: map[string]interface{}{}, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/agent/configentry/resolve.go b/agent/configentry/resolve.go index e3f7e54fbec9..e554ec3c3bb4 100644 --- a/agent/configentry/resolve.go +++ b/agent/configentry/resolve.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/hashicorp/go-hclog" + "github.com/imdario/mergo" "github.com/mitchellh/copystructure" "github.com/hashicorp/consul/agent/structs" @@ -20,10 +21,18 @@ func ComputeResolvedServiceConfig( thisReply.MeshGateway.Mode = structs.MeshGatewayModeDefault + // Store the upstream defaults under a wildcard key so that they can be applied to + // upstreams that are inferred from intentions and do not have explicit upstream configuration. + wildcard := structs.NewServiceID(structs.WildcardSpecifier, args.WithWildcardNamespace()) + wildcardUpstreamDefaults := make(map[string]interface{}) + // resolvedConfigs stores the opaque config map for each upstream and is keyed on the upstream's ID. + resolvedConfigs := make(map[structs.ServiceID]map[string]interface{}) + // TODO(freddy) Refactor this into smaller set of state store functions // Pass the WatchSet to both the service and proxy config lookups. If either is updated during the // blocking query, this function will be rerun and these state store lookups will both be current. // We use the default enterprise meta to look up the global proxy defaults because they are not namespaced. + var proxyConfGlobalProtocol string proxyConf := entries.GetProxyDefaults(args.PartitionOrDefault()) if proxyConf != nil { @@ -32,21 +41,47 @@ func ComputeResolvedServiceConfig( if err != nil { return nil, fmt.Errorf("failed to copy global proxy-defaults: %v", err) } + thisReply.ProxyConfig = mapCopy.(map[string]interface{}) thisReply.Mode = proxyConf.Mode thisReply.TransparentProxy = proxyConf.TransparentProxy thisReply.MeshGateway = proxyConf.MeshGateway thisReply.Expose = proxyConf.Expose - // Extract the global protocol from proxyConf for upstream configs. - rawProtocol := proxyConf.Config["protocol"] - if rawProtocol != nil { - var ok bool - proxyConfGlobalProtocol, ok = rawProtocol.(string) - if !ok { - return nil, fmt.Errorf("invalid protocol type %T", rawProtocol) - } + // Only MeshGateway and Protocol should affect upstreams. + // MeshGateway is strange. It's marshaled into UpstreamConfigs via the arbitrary map, but it + // uses concrete fields everywhere else. We always take the explicit definition here for + // wildcard upstreams and discard the user setting it via arbitrary map in proxy-defaults. + if mgw, ok := thisReply.ProxyConfig["mesh_gateway"]; ok { + wildcardUpstreamDefaults["mesh_gateway"] = mgw + } + if !proxyConf.MeshGateway.IsZero() { + wildcardUpstreamDefaults["mesh_gateway"] = proxyConf.MeshGateway + } + + // We explicitly DO NOT merge the protocol from proxy-defaults into the wildcard upstream here. + // TProxy will try to use the data from the `wildcardUpstreamDefaults` as a source of truth, which is + // normally correct to inherit from proxy-defaults. However, it is NOT correct for protocol. + // + // This edge-case is different for `protocol` from other fields, since the protocol can be + // set on both the local `ServiceDefaults.UpstreamOverrides` and upstream `ServiceDefaults.Protocol`. + // This means that when proxy-defaults is set, it would always be treated as an explicit override, + // and take precedence over the protocol that is set on the discovery chain (which comes from the + // service's preference in its service-defaults), which is wrong. + // + // When the upstream is not explicitly defined, we should only get the protocol from one of these locations: + // 1. For tproxy non-peering services, it can be fetched via the discovery chain. + // The chain compiler merges the proxy-defaults protocol with the upstream's preferred service-defaults protocol. + // 2. For tproxy non-peering services with default upstream overrides, it will come from the wildcard upstream overrides. + // 3. For tproxy non-peering services with specific upstream overrides, it will come from the specific upstream override defined. + // 4. For tproxy peering services, they do not honor the proxy-defaults, since they reside in a different cluster. + // The data will come from a separate peerMeta field. + // In all of these cases, it is not necessary for the proxy-defaults to exist in the wildcard upstream. + parsed, err := structs.ParseUpstreamConfigNoDefaults(mapCopy.(map[string]interface{})) + if err != nil { + return nil, fmt.Errorf("failed to parse upstream config map for proxy-defaults: %v", err) } + proxyConfGlobalProtocol = parsed.Protocol } serviceConf := entries.GetServiceDefaults( @@ -62,6 +97,7 @@ func ComputeResolvedServiceConfig( } if serviceConf.MeshGateway.Mode != structs.MeshGatewayModeDefault { thisReply.MeshGateway.Mode = serviceConf.MeshGateway.Mode + wildcardUpstreamDefaults["mesh_gateway"] = serviceConf.MeshGateway } if serviceConf.TransparentProxy.OutboundListenerPort != 0 { thisReply.TransparentProxy.OutboundListenerPort = serviceConf.TransparentProxy.OutboundListenerPort @@ -127,17 +163,13 @@ func ComputeResolvedServiceConfig( // First store all upstreams that were provided in the request for _, sid := range upstreamIDs { - if _, ok := seenUpstreams[sid]; !ok { - seenUpstreams[sid] = struct{}{} - } + seenUpstreams[sid] = struct{}{} } // Then store upstreams inferred from service-defaults and mapify the overrides. var ( - upstreamConfigs = make(map[structs.ServiceID]*structs.UpstreamConfig) - upstreamDefaults *structs.UpstreamConfig - // usConfigs stores the opaque config map for each upstream and is keyed on the upstream's ID. - usConfigs = make(map[structs.ServiceID]map[string]interface{}) + upstreamDefaults *structs.UpstreamConfig + upstreamOverrides = make(map[structs.ServiceID]*structs.UpstreamConfig) ) if serviceConf != nil && serviceConf.UpstreamConfig != nil { for i, override := range serviceConf.UpstreamConfig.Overrides { @@ -152,19 +184,28 @@ func ComputeResolvedServiceConfig( continue // skip this impossible condition } seenUpstreams[override.ServiceID()] = struct{}{} - upstreamConfigs[override.ServiceID()] = override + upstreamOverrides[override.ServiceID()] = override } if serviceConf.UpstreamConfig.Defaults != nil { upstreamDefaults = serviceConf.UpstreamConfig.Defaults + if upstreamDefaults.MeshGateway.Mode == structs.MeshGatewayModeDefault { + upstreamDefaults.MeshGateway.Mode = thisReply.MeshGateway.Mode + } + upstreamDefaults.MergeInto(wildcardUpstreamDefaults) + // Always add the wildcard upstream if a service-defaults default-upstream was configured. + resolvedConfigs[wildcard] = wildcardUpstreamDefaults + } + } - // Store the upstream defaults under a wildcard key so that they can be applied to - // upstreams that are inferred from intentions and do not have explicit upstream configuration. - cfgMap := make(map[string]interface{}) - upstreamDefaults.MergeInto(cfgMap) + if !args.MeshGateway.IsZero() { + wildcardUpstreamDefaults["mesh_gateway"] = args.MeshGateway + } - wildcard := structs.NewServiceID(structs.WildcardSpecifier, args.WithWildcardNamespace()) - usConfigs[wildcard] = cfgMap - } + // Add the wildcard upstream if any fields were populated (it may have been already + // added if a service-defaults exists). We likely could always add it without issues, + // but this has been existing behavior, and many unit tests would break. + if len(wildcardUpstreamDefaults) > 0 { + resolvedConfigs[wildcard] = wildcardUpstreamDefaults } for upstream := range seenUpstreams { @@ -175,49 +216,66 @@ func ComputeResolvedServiceConfig( // 2. Protocol for upstream service defined in its service-defaults (how the upstream wants to be addressed) // 3. Protocol defined for the upstream in the service-defaults.(upstream_config.defaults|upstream_config.overrides) of the downstream // (how the downstream wants to address it) - protocol := proxyConfGlobalProtocol + if proxyConfGlobalProtocol != "" { + resolvedCfg["protocol"] = proxyConfGlobalProtocol + } + + if err := mergo.MergeWithOverwrite(&resolvedCfg, wildcardUpstreamDefaults); err != nil { + return nil, fmt.Errorf("failed to merge wildcard defaults into upstream: %v", err) + } upstreamSvcDefaults := entries.GetServiceDefaults( structs.NewServiceID(upstream.ID, &upstream.EnterpriseMeta), ) if upstreamSvcDefaults != nil { if upstreamSvcDefaults.Protocol != "" { - protocol = upstreamSvcDefaults.Protocol + resolvedCfg["protocol"] = upstreamSvcDefaults.Protocol } } - if protocol != "" { - resolvedCfg["protocol"] = protocol + // When dialing an upstream, the goal is to flatten the mesh gateway mode in this order + // (larger number wins): + // 1. Value from the proxy-defaults + // 2. Value from top-level of service-defaults (ServiceDefaults.MeshGateway) + // 3. Value from centralized upstream defaults (ServiceDefaults.UpstreamConfig.Defaults) + // 4. Value from local proxy registration (NodeService.Proxy.MeshGateway) + // 5. Value from centralized upstream override (ServiceDefaults.UpstreamConfig.Overrides) + // 6. Value from local upstream definition (NodeService.Proxy.Upstreams[].MeshGateway) + // + // The MeshGateway value from upstream definitions in the proxy registration override + // the one from UpstreamConfig.Defaults and UpstreamConfig.Overrides because they are + // specific to the proxy instance. + // + // Step 6 is handled by the dialer's ServiceManager in MergeServiceConfig. + + // Start with the merged value from proxyConf and serviceConf. (steps 1-2) + if !thisReply.MeshGateway.IsZero() { + resolvedCfg["mesh_gateway"] = thisReply.MeshGateway } - // Merge centralized defaults for all upstreams before configuration for specific upstreams + // Merge in the upstream defaults (step 3). if upstreamDefaults != nil { upstreamDefaults.MergeInto(resolvedCfg) } - // The MeshGateway value from the proxy registration overrides the one from upstream_defaults - // because it is specific to the proxy instance. - // - // The goal is to flatten the mesh gateway mode in this order: - // 0. Value from centralized upstream_defaults - // 1. Value from local proxy registration - // 2. Value from centralized upstream_config - // 3. Value from local upstream definition. This last step is done in the client's service manager. + // Merge in the top-level mode from the proxy instance (step 4). if !args.MeshGateway.IsZero() { + // This means each upstream inherits the value from the `NodeService.Proxy.MeshGateway` field. resolvedCfg["mesh_gateway"] = args.MeshGateway } - if upstreamConfigs[upstream] != nil { - upstreamConfigs[upstream].MergeInto(resolvedCfg) + // Merge in Overrides for the upstream (step 5). + if upstreamOverrides[upstream] != nil { + upstreamOverrides[upstream].MergeInto(resolvedCfg) } if len(resolvedCfg) > 0 { - usConfigs[upstream] = resolvedCfg + resolvedConfigs[upstream] = resolvedCfg } } // don't allocate the slices just to not fill them - if len(usConfigs) == 0 { + if len(resolvedConfigs) == 0 { return &thisReply, nil } @@ -225,14 +283,14 @@ func ComputeResolvedServiceConfig( // For legacy upstreams we return a map that is only keyed on the string ID, since they precede namespaces thisReply.UpstreamConfigs = make(map[string]map[string]interface{}) - for us, conf := range usConfigs { + for us, conf := range resolvedConfigs { thisReply.UpstreamConfigs[us.ID] = conf } } else { - thisReply.UpstreamIDConfigs = make(structs.OpaqueUpstreamConfigs, 0, len(usConfigs)) + thisReply.UpstreamIDConfigs = make(structs.OpaqueUpstreamConfigs, 0, len(resolvedConfigs)) - for us, conf := range usConfigs { + for us, conf := range resolvedConfigs { thisReply.UpstreamIDConfigs = append(thisReply.UpstreamIDConfigs, structs.OpaqueUpstreamConfig{Upstream: us, Config: conf}) } diff --git a/agent/configentry/resolve_test.go b/agent/configentry/resolve_test.go index a023dca40007..14a72093254c 100644 --- a/agent/configentry/resolve_test.go +++ b/agent/configentry/resolve_test.go @@ -1,10 +1,12 @@ package configentry import ( + "sort" "testing" "github.com/stretchr/testify/require" + "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/structs" ) @@ -17,8 +19,19 @@ func Test_ComputeResolvedServiceConfig(t *testing.T) { sid := structs.ServiceID{ ID: "sid", - EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(), + EnterpriseMeta: *acl.DefaultEnterpriseMeta(), } + uid := structs.ServiceID{ + ID: "upstream1", + EnterpriseMeta: *acl.DefaultEnterpriseMeta(), + } + uids := []structs.ServiceID{uid} + wildcard := structs.NewServiceID(structs.WildcardSpecifier, acl.WildcardEnterpriseMeta()) + + localMeshGW := structs.MeshGatewayConfig{Mode: structs.MeshGatewayModeLocal} + remoteMeshGW := structs.MeshGatewayConfig{Mode: structs.MeshGatewayModeRemote} + noneMeshGW := structs.MeshGatewayConfig{Mode: structs.MeshGatewayModeNone} + tests := []struct { name string args args @@ -88,12 +101,320 @@ func Test_ComputeResolvedServiceConfig(t *testing.T) { }, }, }, + { + name: "proxy upstream mesh-gateway inherits proxy-defaults", + args: args{ + scReq: &structs.ServiceConfigRequest{ + Name: "sid", + UpstreamIDs: uids, + }, + upstreamIDs: uids, + entries: &ResolvedServiceConfigSet{ + ProxyDefaults: map[string]*structs.ProxyConfigEntry{ + acl.DefaultEnterpriseMeta().PartitionOrDefault(): { + MeshGateway: remoteMeshGW, // applied 1st + }, + }, + }, + }, + want: &structs.ServiceConfigResponse{ + MeshGateway: remoteMeshGW, + UpstreamIDConfigs: structs.OpaqueUpstreamConfigs{ + { + Upstream: wildcard, + Config: map[string]interface{}{ + "mesh_gateway": structs.MeshGatewayConfig{ + Mode: structs.MeshGatewayModeRemote, + }, + }, + }, + { + Upstream: uid, + Config: map[string]interface{}{ + "mesh_gateway": remoteMeshGW, + }, + }, + }, + }, + }, + { + name: "proxy inherits kitchen sink from proxy-defaults", + args: args{ + scReq: &structs.ServiceConfigRequest{ + Name: "sid", + UpstreamIDs: uids, + }, + upstreamIDs: uids, + entries: &ResolvedServiceConfigSet{ + ProxyDefaults: map[string]*structs.ProxyConfigEntry{ + acl.DefaultEnterpriseMeta().PartitionOrDefault(): { + Config: map[string]interface{}{ + "foo": "bar", + }, + Expose: structs.ExposeConfig{ + Checks: true, + Paths: []structs.ExposePath{}, + }, + Mode: structs.ProxyModeTransparent, + MeshGateway: remoteMeshGW, + TransparentProxy: structs.TransparentProxyConfig{ + OutboundListenerPort: 6666, + DialedDirectly: true, + }, + }, + }, + }, + }, + want: &structs.ServiceConfigResponse{ + ProxyConfig: map[string]interface{}{ + "foo": "bar", + }, + Expose: structs.ExposeConfig{ + Checks: true, + Paths: []structs.ExposePath{}, + }, + Mode: structs.ProxyModeTransparent, + MeshGateway: remoteMeshGW, + TransparentProxy: structs.TransparentProxyConfig{ + OutboundListenerPort: 6666, + DialedDirectly: true, + }, + UpstreamIDConfigs: structs.OpaqueUpstreamConfigs{ + { + Upstream: wildcard, + Config: map[string]interface{}{ + "mesh_gateway": remoteMeshGW, + }, + }, + { + Upstream: uid, + Config: map[string]interface{}{ + "mesh_gateway": remoteMeshGW, + }, + }, + }, + }, + }, + { + name: "proxy upstream mesh-gateway inherits service-defaults", + args: args{ + scReq: &structs.ServiceConfigRequest{ + Name: "sid", + UpstreamIDs: uids, + }, + upstreamIDs: uids, + entries: &ResolvedServiceConfigSet{ + ProxyDefaults: map[string]*structs.ProxyConfigEntry{ + acl.DefaultEnterpriseMeta().PartitionOrDefault(): { + MeshGateway: localMeshGW, // applied 1st + }, + }, + ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{ + sid: { + MeshGateway: noneMeshGW, // applied 2nd + }, + }, + }, + }, + want: &structs.ServiceConfigResponse{ + MeshGateway: noneMeshGW, // service-defaults has a higher precedence. + UpstreamIDConfigs: structs.OpaqueUpstreamConfigs{ + { + Upstream: wildcard, + Config: map[string]interface{}{ + "mesh_gateway": noneMeshGW, + }, + }, + { + Upstream: uid, + Config: map[string]interface{}{ + "mesh_gateway": noneMeshGW, + }, + }, + }, + }, + }, + { + name: "proxy wildcard upstream mesh-gateway inherits proxy-defaults", + args: args{ + scReq: &structs.ServiceConfigRequest{ + Name: "sid", + Mode: structs.ProxyModeTransparent, + }, + entries: &ResolvedServiceConfigSet{ + ProxyDefaults: map[string]*structs.ProxyConfigEntry{ + acl.DefaultEnterpriseMeta().PartitionOrDefault(): { + MeshGateway: localMeshGW, + }, + }, + ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{ + sid: { + UpstreamConfig: &structs.UpstreamConfiguration{ + Defaults: &structs.UpstreamConfig{ + Protocol: "http", + }, + }, + }, + }, + }, + }, + want: &structs.ServiceConfigResponse{ + MeshGateway: localMeshGW, + UpstreamIDConfigs: structs.OpaqueUpstreamConfigs{ + { + Upstream: wildcard, + Config: map[string]interface{}{ + "mesh_gateway": localMeshGW, // From proxy-defaults + "protocol": "http", + }, + }, + }, + }, + }, + { + name: "proxy upstream mesh-gateway inherits upstream defaults", + args: args{ + scReq: &structs.ServiceConfigRequest{ + Name: "sid", + UpstreamIDs: uids, + }, + upstreamIDs: uids, + entries: &ResolvedServiceConfigSet{ + ProxyDefaults: map[string]*structs.ProxyConfigEntry{ + acl.DefaultEnterpriseMeta().PartitionOrDefault(): { + MeshGateway: localMeshGW, + }, + }, + ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{ + sid: { + MeshGateway: noneMeshGW, + UpstreamConfig: &structs.UpstreamConfiguration{ + Defaults: &structs.UpstreamConfig{ + MeshGateway: remoteMeshGW, + }, + }, + }, + }, + }, + }, + want: &structs.ServiceConfigResponse{ + MeshGateway: noneMeshGW, // Merged from proxy-defaults + service-defaults + UpstreamIDConfigs: structs.OpaqueUpstreamConfigs{ + { + Upstream: wildcard, + Config: map[string]interface{}{ + // Wildcard stores the values from UpstreamConfig.Defaults directly + "mesh_gateway": remoteMeshGW, + }, + }, + { + Upstream: uid, + Config: map[string]interface{}{ + // Upstream-specific config comes from UpstreamConfig.Defaults + "mesh_gateway": remoteMeshGW, + }, + }, + }, + }, + }, + { + name: "proxy upstream mesh-gateway inherits value from node-service", + args: args{ + scReq: &structs.ServiceConfigRequest{ + Name: "sid", + UpstreamIDs: uids, + + // MeshGateway from NodeService is received in the request + MeshGateway: remoteMeshGW, + }, + upstreamIDs: uids, + entries: &ResolvedServiceConfigSet{ + ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{ + sid: { + UpstreamConfig: &structs.UpstreamConfiguration{ + Defaults: &structs.UpstreamConfig{ + MeshGateway: noneMeshGW, + }, + }, + }, + }, + }, + }, + want: &structs.ServiceConfigResponse{ + UpstreamIDConfigs: structs.OpaqueUpstreamConfigs{ + { + Upstream: wildcard, + Config: map[string]interface{}{ + // NodeService.Proxy.MeshGateway has a higher precedence than centralized + // UpstreamConfig.Defaults, since it's specific to a service instance. + "mesh_gateway": remoteMeshGW, + }, + }, + { + Upstream: uid, + Config: map[string]interface{}{ + "mesh_gateway": remoteMeshGW, + }, + }, + }, + }, + }, + { + name: "proxy upstream mesh-gateway inherits value from service-defaults override", + args: args{ + scReq: &structs.ServiceConfigRequest{ + Name: "sid", + UpstreamIDs: uids, + MeshGateway: localMeshGW, // applied 2nd + }, + upstreamIDs: uids, + entries: &ResolvedServiceConfigSet{ + ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{ + sid: { + UpstreamConfig: &structs.UpstreamConfiguration{ + Defaults: &structs.UpstreamConfig{ + MeshGateway: localMeshGW, // applied 1st + }, + Overrides: []*structs.UpstreamConfig{ + { + Name: uid.ID, + MeshGateway: remoteMeshGW, // applied 3rd + }, + }, + }, + }, + }, + }, + }, + want: &structs.ServiceConfigResponse{ + UpstreamIDConfigs: structs.OpaqueUpstreamConfigs{ + { + Upstream: wildcard, + Config: map[string]interface{}{ + // Wildcard stores the values from UpstreamConfig.Defaults directly + "mesh_gateway": localMeshGW, + }, + }, + { + Upstream: uid, + Config: map[string]interface{}{ + // UpstreamConfig.Overrides has a higher precedence than UpstreamConfig.Defaults + "mesh_gateway": remoteMeshGW, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := ComputeResolvedServiceConfig(tt.args.scReq, tt.args.upstreamIDs, false, tt.args.entries, nil) require.NoError(t, err) + // This is needed because map iteration is random and determines the order of some outputs. + sort.Slice(got.UpstreamIDConfigs, func(i, j int) bool { + return got.UpstreamIDConfigs[i].Upstream.ID < got.UpstreamIDConfigs[j].Upstream.ID + }) require.Equal(t, tt.want, got) }) } diff --git a/agent/connect/ca/mock_Provider.go b/agent/connect/ca/mock_Provider.go index bdc5d9c8e609..50136cbc74a2 100644 --- a/agent/connect/ca/mock_Provider.go +++ b/agent/connect/ca/mock_Provider.go @@ -1,13 +1,11 @@ -// Code generated by mockery v2.11.0. DO NOT EDIT. +// Code generated by mockery v2.15.0. DO NOT EDIT. package ca import ( - testing "testing" + x509 "crypto/x509" mock "github.com/stretchr/testify/mock" - - x509 "crypto/x509" ) // MockProvider is an autogenerated mock type for the Provider type @@ -107,7 +105,7 @@ func (_m *MockProvider) GenerateIntermediate() (string, error) { } // GenerateIntermediateCSR provides a mock function with given fields: -func (_m *MockProvider) GenerateIntermediateCSR() (string, error) { +func (_m *MockProvider) GenerateIntermediateCSR() (string, string, error) { ret := _m.Called() var r0 string @@ -117,14 +115,21 @@ func (_m *MockProvider) GenerateIntermediateCSR() (string, error) { r0 = ret.Get(0).(string) } - var r1 error - if rf, ok := ret.Get(1).(func() error); ok { + var r1 string + if rf, ok := ret.Get(1).(func() string); ok { r1 = rf() } else { - r1 = ret.Error(1) + r1 = ret.Get(1).(string) } - return r0, r1 + var r2 error + if rf, ok := ret.Get(2).(func() error); ok { + r2 = rf() + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 } // GenerateRoot provides a mock function with given fields: @@ -148,13 +153,13 @@ func (_m *MockProvider) GenerateRoot() (RootResult, error) { return r0, r1 } -// SetIntermediate provides a mock function with given fields: intermediatePEM, rootPEM -func (_m *MockProvider) SetIntermediate(intermediatePEM string, rootPEM string) error { - ret := _m.Called(intermediatePEM, rootPEM) +// SetIntermediate provides a mock function with given fields: intermediatePEM, rootPEM, opaque +func (_m *MockProvider) SetIntermediate(intermediatePEM string, rootPEM string, opaque string) error { + ret := _m.Called(intermediatePEM, rootPEM, opaque) var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(intermediatePEM, rootPEM) + if rf, ok := ret.Get(0).(func(string, string, string) error); ok { + r0 = rf(intermediatePEM, rootPEM, opaque) } else { r0 = ret.Error(0) } @@ -248,9 +253,15 @@ func (_m *MockProvider) SupportsCrossSigning() (bool, error) { return r0, r1 } -// NewMockProvider creates a new instance of MockProvider. It also registers a cleanup function to assert the mocks expectations. -func NewMockProvider(t testing.TB) *MockProvider { +type mockConstructorTestingTNewMockProvider interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockProvider creates a new instance of MockProvider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockProvider(t mockConstructorTestingTNewMockProvider) *MockProvider { mock := &MockProvider{} + mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) diff --git a/agent/connect/ca/provider.go b/agent/connect/ca/provider.go index 6d585490fad6..c80ccd82be95 100644 --- a/agent/connect/ca/provider.go +++ b/agent/connect/ca/provider.go @@ -179,14 +179,17 @@ type SecondaryProvider interface { // // After the certificate is signed, SecondaryProvider.SetIntermediate will // be called to store the intermediate CA. - GenerateIntermediateCSR() (string, error) + // + // The second return value is an opaque string meant to be passed back to + // the subsequent call to SetIntermediate. + GenerateIntermediateCSR() (string, string, error) // SetIntermediate is called to store a newly signed leaf signing certificate and // the chain of certificates back to the root CA certificate. // // The provider should save the certificates and use them to // Provider.Sign leaf certificates. - SetIntermediate(intermediatePEM, rootPEM string) error + SetIntermediate(intermediatePEM, rootPEM, opaque string) error } // RootResult is the result returned by PrimaryProvider.GenerateRoot. diff --git a/agent/connect/ca/provider_aws.go b/agent/connect/ca/provider_aws.go index cef0c7ddbea1..97e075b114a6 100644 --- a/agent/connect/ca/provider_aws.go +++ b/agent/connect/ca/provider_aws.go @@ -75,6 +75,8 @@ type AWSProvider struct { logger hclog.Logger } +var _ Provider = (*AWSProvider)(nil) + // NewAWSProvider returns a new AWSProvider func NewAWSProvider(logger hclog.Logger) *AWSProvider { return &AWSProvider{logger: logger} @@ -498,23 +500,24 @@ func (a *AWSProvider) signCSR(csrPEM string, templateARN string, ttl time.Durati } // GenerateIntermediateCSR implements Provider -func (a *AWSProvider) GenerateIntermediateCSR() (string, error) { +func (a *AWSProvider) GenerateIntermediateCSR() (string, string, error) { if a.isPrimary { - return "", fmt.Errorf("provider is the root certificate authority, " + + return "", "", fmt.Errorf("provider is the root certificate authority, " + "cannot generate an intermediate CSR") } err := a.ensureCA() if err != nil { - return "", err + return "", "", err } // We should have the CA created now and should be able to generate the CSR. - return a.getCACSR() + pem, err := a.getCACSR() + return pem, "", err } // SetIntermediate implements Provider -func (a *AWSProvider) SetIntermediate(intermediatePEM string, rootPEM string) error { +func (a *AWSProvider) SetIntermediate(intermediatePEM string, rootPEM string, _ string) error { err := a.ensureCA() if err != nil { return err diff --git a/agent/connect/ca/provider_aws_test.go b/agent/connect/ca/provider_aws_test.go index b73d4a95d54f..f6105d3dc834 100644 --- a/agent/connect/ca/provider_aws_test.go +++ b/agent/connect/ca/provider_aws_test.go @@ -216,7 +216,7 @@ func TestAWSBootstrapAndSignSecondary(t *testing.T) { "ExistingARN": p2State[AWSStateCAARNKey], }) p2 = testAWSProvider(t, cfg2) - require.NoError(t, p2.SetIntermediate(newIntPEM, newRootPEM)) + require.NoError(t, p2.SetIntermediate(newIntPEM, newRootPEM, "")) root, err = p1.GenerateRoot() require.NoError(t, err) diff --git a/agent/connect/ca/provider_consul.go b/agent/connect/ca/provider_consul.go index 40eb2f44570e..0493fffe75a6 100644 --- a/agent/connect/ca/provider_consul.go +++ b/agent/connect/ca/provider_consul.go @@ -49,6 +49,8 @@ type ConsulProvider struct { sync.RWMutex } +var _ Provider = (*ConsulProvider)(nil) + // NewConsulProvider returns a new ConsulProvider that is ready to be used. func NewConsulProvider(delegate ConsulProviderStateDelegate, logger hclog.Logger) *ConsulProvider { return &ConsulProvider{Delegate: delegate, logger: logger} @@ -205,26 +207,26 @@ func (c *ConsulProvider) GenerateRoot() (RootResult, error) { // GenerateIntermediateCSR creates a private key and generates a CSR // for another datacenter's root to sign. -func (c *ConsulProvider) GenerateIntermediateCSR() (string, error) { +func (c *ConsulProvider) GenerateIntermediateCSR() (string, string, error) { providerState, err := c.getState() if err != nil { - return "", err + return "", "", err } if c.isPrimary { - return "", fmt.Errorf("provider is the root certificate authority, " + + return "", "", fmt.Errorf("provider is the root certificate authority, " + "cannot generate an intermediate CSR") } // Create a new private key and CSR. signer, pk, err := connect.GeneratePrivateKeyWithConfig(c.config.PrivateKeyType, c.config.PrivateKeyBits) if err != nil { - return "", err + return "", "", err } csr, err := connect.CreateCACSR(c.spiffeID, signer) if err != nil { - return "", err + return "", "", err } // Write the new provider state to the store. @@ -235,15 +237,15 @@ func (c *ConsulProvider) GenerateIntermediateCSR() (string, error) { ProviderState: &newState, } if _, err := c.Delegate.ApplyCARequest(args); err != nil { - return "", err + return "", "", err } - return csr, nil + return csr, "", nil } // SetIntermediate validates that the given intermediate is for the right private key // and writes the given intermediate and root certificates to the state. -func (c *ConsulProvider) SetIntermediate(intermediatePEM, rootPEM string) error { +func (c *ConsulProvider) SetIntermediate(intermediatePEM, rootPEM, _ string) error { providerState, err := c.getState() if err != nil { return err diff --git a/agent/connect/ca/provider_consul_test.go b/agent/connect/ca/provider_consul_test.go index a4df05b76729..9845eea74c98 100644 --- a/agent/connect/ca/provider_consul_test.go +++ b/agent/connect/ca/provider_consul_test.go @@ -375,6 +375,30 @@ func testCrossSignProviders(t *testing.T, provider1, provider2 Provider) { } } +func testCrossSignProvidersShouldFail(t *testing.T, provider1, provider2 Provider) { + t.Helper() + + // Get the root from the new provider to be cross-signed. + root, err := provider2.GenerateRoot() + require.NoError(t, err) + + newRoot, err := connect.ParseCert(root.PEM) + require.NoError(t, err) + requireNotEncoded(t, newRoot.SubjectKeyId) + requireNotEncoded(t, newRoot.AuthorityKeyId) + + newInterPEM, err := provider2.ActiveIntermediate() + require.NoError(t, err) + newIntermediate, err := connect.ParseCert(newInterPEM) + require.NoError(t, err) + requireNotEncoded(t, newIntermediate.SubjectKeyId) + requireNotEncoded(t, newIntermediate.AuthorityKeyId) + + // Have provider1 cross sign our new root cert. + _, err = provider1.CrossSignCA(newRoot) + require.Error(t, err) +} + func TestConsulProvider_SignIntermediate(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short") @@ -417,7 +441,7 @@ func TestConsulProvider_SignIntermediate(t *testing.T) { func testSignIntermediateCrossDC(t *testing.T, provider1, provider2 Provider) { // Get the intermediate CSR from provider2. - csrPEM, err := provider2.GenerateIntermediateCSR() + csrPEM, opaque, err := provider2.GenerateIntermediateCSR() require.NoError(t, err) csr, err := connect.ParseCSR(csrPEM) require.NoError(t, err) @@ -430,7 +454,7 @@ func testSignIntermediateCrossDC(t *testing.T, provider1, provider2 Provider) { rootPEM := root.PEM // Give the new intermediate to provider2 to use. - require.NoError(t, provider2.SetIntermediate(intermediatePEM, rootPEM)) + require.NoError(t, provider2.SetIntermediate(intermediatePEM, rootPEM, opaque)) // Have provider2 sign a leaf cert and make sure the chain is correct. spiffeService := &connect.SpiffeIDService{ diff --git a/agent/connect/ca/provider_vault.go b/agent/connect/ca/provider_vault.go index f3168a17f5ba..2f1862da66ad 100644 --- a/agent/connect/ca/provider_vault.go +++ b/agent/connect/ca/provider_vault.go @@ -70,8 +70,17 @@ type VaultProvider struct { clusterID string spiffeID *connect.SpiffeIDSigning logger hclog.Logger + + // isConsulMountedIntermediate is used to determine if we should tune the + // mount if the VaultProvider is ever reconfigured. This is at most a + // "best guess" to determine whether this instance of Consul created the + // intermediate mount but will not be able to tell if an existing mount + // was created by Consul (in a previous running instance) or was external. + isConsulMountedIntermediate bool } +var _ Provider = (*VaultProvider)(nil) + func NewVaultProvider(logger hclog.Logger) *VaultProvider { return &VaultProvider{ stopWatcher: func() {}, @@ -310,9 +319,10 @@ func (v *VaultProvider) GenerateRoot() (RootResult, error) { }, }) if err != nil { - return RootResult{}, err + return RootResult{}, fmt.Errorf("failed to mount root CA backend: %w", err) } + // We want to initialize afterwards fallthrough case ErrBackendNotInitialized: uid, err := connect.CompactUID() @@ -326,7 +336,7 @@ func (v *VaultProvider) GenerateRoot() (RootResult, error) { "key_bits": v.config.PrivateKeyBits, }) if err != nil { - return RootResult{}, err + return RootResult{}, fmt.Errorf("failed to initialize root CA: %w", err) } var ok bool rootPEM, ok = resp.Data["certificate"].(string) @@ -336,7 +346,7 @@ func (v *VaultProvider) GenerateRoot() (RootResult, error) { default: if err != nil { - return RootResult{}, err + return RootResult{}, fmt.Errorf("unexpected error while setting root PKI backend: %w", err) } } @@ -357,9 +367,9 @@ func (v *VaultProvider) GenerateRoot() (RootResult, error) { // GenerateIntermediateCSR creates a private key and generates a CSR // for another datacenter's root to sign, overwriting the intermediate backend // in the process. -func (v *VaultProvider) GenerateIntermediateCSR() (string, error) { +func (v *VaultProvider) GenerateIntermediateCSR() (string, string, error) { if v.isPrimary { - return "", fmt.Errorf("provider is the root certificate authority, " + + return "", "", fmt.Errorf("provider is the root certificate authority, " + "cannot generate an intermediate CSR") } @@ -380,19 +390,51 @@ func (v *VaultProvider) setupIntermediatePKIPath() error { Config: mountConfig, }) if err != nil { - return err + return fmt.Errorf("failed to mount intermediate PKI backend: %w", err) } + // Required to determine if we should tune the mount + // if the VaultProvider is ever reconfigured. + v.isConsulMountedIntermediate = true + + } else if err == ErrBackendNotInitialized { + // If this is the first time calling setupIntermediatePKIPath, the backend + // will not have been initialized. Since the mount is ready we can suppress + // this error. } else { - return err + return fmt.Errorf("unexpected error while fetching intermediate CA: %w", err) } } else { + v.logger.Info("Found existing Intermediate PKI path mount", + "namespace", v.config.IntermediatePKINamespace, + "path", v.config.IntermediatePKIPath, + ) + + // This codepath requires the Vault policy: + // + // path "/sys/mounts//tune" { + // capabilities = [ "update" ] + // } + // err := v.tuneMountNamespaced(v.config.IntermediatePKINamespace, v.config.IntermediatePKIPath, &mountConfig) if err != nil { - v.logger.Warn("Could not update intermediate PKI mount settings", "path", v.config.IntermediatePKIPath, "error", err) + if v.isConsulMountedIntermediate { + v.logger.Warn("Intermediate PKI path was mounted by Consul but could not be tuned", + "namespace", v.config.IntermediatePKINamespace, + "path", v.config.IntermediatePKIPath, + "error", err, + ) + } else { + v.logger.Debug("Failed to tune Intermediate PKI mount. 403 Forbidden is expected if Consul does not have tune capabilities for the Intermediate PKI mount (i.e. using Vault-managed policies)", + "namespace", v.config.IntermediatePKINamespace, + "path", v.config.IntermediatePKIPath, + "error", err, + ) + } + } } - // Create the role for issuing leaf certs if it doesn't exist yet + // Create the role for issuing leaf certs rolePath := v.config.IntermediatePKIPath + "roles/" + VaultCALeafCertRole _, err = v.writeNamespaced(v.config.IntermediatePKINamespace, rolePath, map[string]interface{}{ "allow_any_name": true, @@ -406,11 +448,13 @@ func (v *VaultProvider) setupIntermediatePKIPath() error { return err } -func (v *VaultProvider) generateIntermediateCSR() (string, error) { +// generateIntermediateCSR returns the CSR and key_id (only present in +// Vault 1.11+) or any errors encountered. +func (v *VaultProvider) generateIntermediateCSR() (string, string, error) { // Generate a new intermediate CSR for the root to sign. uid, err := connect.CompactUID() if err != nil { - return "", err + return "", "", err } data, err := v.writeNamespaced(v.config.IntermediatePKINamespace, v.config.IntermediatePKIPath+"intermediate/generate/internal", map[string]interface{}{ "common_name": connect.CACN("vault", uid, v.clusterID, v.isPrimary), @@ -419,22 +463,31 @@ func (v *VaultProvider) generateIntermediateCSR() (string, error) { "uri_sans": v.spiffeID.URI().String(), }) if err != nil { - return "", err + return "", "", err } if data == nil || data.Data["csr"] == "" { - return "", fmt.Errorf("got empty value when generating intermediate CSR") + return "", "", fmt.Errorf("got empty value when generating intermediate CSR") } csr, ok := data.Data["csr"].(string) if !ok { - return "", fmt.Errorf("csr result is not a string") + return "", "", fmt.Errorf("csr result is not a string") } - - return csr, nil + // Vault 1.11+ will return a "key_id" field which helps + // identify the correct issuer to set as default. + // https://github.com/hashicorp/vault/blob/e445c8b4f58dc20a0316a7fd1b5725b401c3b17a/builtin/logical/pki/path_intermediate.go#L154 + if rawkeyId, ok := data.Data["key_id"]; ok { + keyId, ok := rawkeyId.(string) + if !ok { + return "", "", fmt.Errorf("key_id is not a string") + } + return csr, keyId, nil + } + return csr, "", nil } // SetIntermediate writes the incoming intermediate and root certificates to the // intermediate backend (as a chain). -func (v *VaultProvider) SetIntermediate(intermediatePEM, rootPEM string) error { +func (v *VaultProvider) SetIntermediate(intermediatePEM, rootPEM, keyId string) error { if v.isPrimary { return fmt.Errorf("cannot set an intermediate using another root in the primary datacenter") } @@ -444,13 +497,21 @@ func (v *VaultProvider) SetIntermediate(intermediatePEM, rootPEM string) error { return err } - _, err = v.writeNamespaced(v.config.IntermediatePKINamespace, v.config.IntermediatePKIPath+"intermediate/set-signed", map[string]interface{}{ + importResp, err := v.writeNamespaced(v.config.IntermediatePKINamespace, v.config.IntermediatePKIPath+"intermediate/set-signed", map[string]interface{}{ "certificate": intermediatePEM, }) if err != nil { return err } + // Vault 1.11+ will return a non-nil response from intermediate/set-signed + if importResp != nil { + err := v.setDefaultIntermediateIssuer(importResp, keyId) + if err != nil { + return fmt.Errorf("failed to update default intermediate issuer: %w", err) + } + } + return nil } @@ -531,7 +592,7 @@ func (v *VaultProvider) getCAChain(namespace, path string) (string, error) { // necessary, then generates and signs a new CA CSR using the root PKI backend // and updates the intermediate backend to use that new certificate. func (v *VaultProvider) GenerateIntermediate() (string, error) { - csr, err := v.generateIntermediateCSR() + csr, keyId, err := v.generateIntermediateCSR() if err != nil { return "", err } @@ -551,16 +612,81 @@ func (v *VaultProvider) GenerateIntermediate() (string, error) { } // Set the intermediate backend to use the new certificate. - _, err = v.writeNamespaced(v.config.IntermediatePKINamespace, v.config.IntermediatePKIPath+"intermediate/set-signed", map[string]interface{}{ + importResp, err := v.writeNamespaced(v.config.IntermediatePKINamespace, v.config.IntermediatePKIPath+"intermediate/set-signed", map[string]interface{}{ "certificate": intermediate.Data["certificate"], }) if err != nil { return "", err } + // Vault 1.11+ will return a non-nil response from intermediate/set-signed + if importResp != nil { + err := v.setDefaultIntermediateIssuer(importResp, keyId) + if err != nil { + return "", fmt.Errorf("failed to update default intermediate issuer: %w", err) + } + } + return v.ActiveIntermediate() } +// setDefaultIntermediateIssuer updates the default issuer for +// intermediate CA since Vault, as part of its 1.11+ support for +// multiple issuers, no longer overwrites the default issuer when +// generateIntermediateCSR (intermediate/generate/internal) is called. +// +// The response we get from calling [/intermediate/set-signed] +// should contain a "mapping" data field we can use to cross-reference +// with the keyId returned when calling [/intermediate/generate/internal]. +// +// [/intermediate/set-signed]: https://developer.hashicorp.com/vault/api-docs/secret/pki#import-ca-certificates-and-keys +// [/intermediate/generate/internal]: https://developer.hashicorp.com/vault/api-docs/secret/pki#generate-intermediate-csr +func (v *VaultProvider) setDefaultIntermediateIssuer(vaultResp *vaultapi.Secret, keyId string) error { + if vaultResp.Data["mapping"] == nil { + return fmt.Errorf("expected Vault response data to have a 'mapping' key") + } + if keyId == "" { + return fmt.Errorf("expected non-empty keyId") + } + + mapping, ok := vaultResp.Data["mapping"].(map[string]any) + if !ok { + return fmt.Errorf("unexpected type for 'mapping' value in Vault response") + } + + var intermediateId string + // The value in this KV pair is called "key" + for issuer, key := range mapping { + if key == keyId { + // Expect to find the key_id we got from Vault when we + // generated the intermediate CSR. + intermediateId = issuer + break + } + } + if intermediateId == "" { + return fmt.Errorf("could not find key_id %q in response from vault", keyId) + } + + // For Vault 1.11+ it is important to GET then POST to avoid clobbering fields + // like `default_follows_latest_issuer`. + // https://developer.hashicorp.com/vault/api-docs/secret/pki#default_follows_latest_issuer + resp, err := v.readNamespaced(v.config.IntermediatePKINamespace, v.config.IntermediatePKIPath+"config/issuers") + if err != nil { + return fmt.Errorf("could not read from /config/issuers: %w", err) + } + issuersConf := resp.Data + // Overwrite the default issuer + issuersConf["default"] = intermediateId + + _, err = v.writeNamespaced(v.config.IntermediatePKINamespace, v.config.IntermediatePKIPath+"config/issuers", issuersConf) + if err != nil { + return fmt.Errorf("could not write default issuer to /config/issuers: %w", err) + } + + return nil +} + // Sign calls the configured role in the intermediate PKI backend to issue // a new leaf certificate based on the provided CSR, with the issuing // intermediate CA cert attached. @@ -633,7 +759,7 @@ func (v *VaultProvider) SignIntermediate(csr *x509.CertificateRequest) (string, func (v *VaultProvider) CrossSignCA(cert *x509.Certificate) (string, error) { rootPEM, err := v.getCA(v.config.RootPKINamespace, v.config.RootPKIPath) if err != nil { - return "", err + return "", fmt.Errorf("failed to get root CA: %w", err) } rootCert, err := connect.ParseCert(rootPEM) if err != nil { @@ -759,14 +885,12 @@ func makePathHelper(namespace, path string) string { func (v *VaultProvider) readNamespaced(namespace string, resource string) (*vaultapi.Secret, error) { defer v.setNamespace(namespace)() - result, err := v.client.Logical().Read(resource) - return result, err + return v.client.Logical().Read(resource) } func (v *VaultProvider) writeNamespaced(namespace string, resource string, data map[string]interface{}) (*vaultapi.Secret, error) { defer v.setNamespace(namespace)() - result, err := v.client.Logical().Write(resource, data) - return result, err + return v.client.Logical().Write(resource, data) } func (v *VaultProvider) setNamespace(namespace string) func() { diff --git a/agent/connect/ca/provider_vault_test.go b/agent/connect/ca/provider_vault_test.go index ff9637325d52..ab0575eabef6 100644 --- a/agent/connect/ca/provider_vault_test.go +++ b/agent/connect/ca/provider_vault_test.go @@ -16,35 +16,40 @@ import ( "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/sdk/testutil/retry" ) -const pkiTestPolicy = ` +const pkiTestPolicyBase = ` path "sys/mounts" { capabilities = ["read"] } -path "sys/mounts/pki-root" +path "sys/mounts/%[1]s" { capabilities = ["create", "read", "update", "delete", "list"] } -path "sys/mounts/pki-intermediate" +path "sys/mounts/%[2]s" { capabilities = ["create", "read", "update", "delete", "list"] } -path "sys/mounts/pki-intermediate/tune" +path "sys/mounts/%[2]s/tune" { capabilities = ["update"] } -path "pki-root/*" +path "%[1]s/*" { capabilities = ["create", "read", "update", "delete", "list"] } -path "pki-intermediate/*" +path "%[2]s/*" { capabilities = ["create", "read", "update", "delete", "list"] }` +func pkiTestPolicy(rootPath, intermediatePath string) string { + return fmt.Sprintf(pkiTestPolicyBase, rootPath, intermediatePath) +} + func TestVaultCAProvider_ParseVaultCAConfig(t *testing.T) { cases := map[string]struct { rawConfig map[string]interface{} @@ -156,12 +161,15 @@ func TestVaultCAProvider_Configure(t *testing.T) { testcases := []struct { name string - rawConfig map[string]interface{} + rawConfig map[string]any expectedValue func(t *testing.T, v *VaultProvider) }{ { - name: "DefaultConfig", - rawConfig: map[string]interface{}{}, + name: "DefaultConfig", + rawConfig: map[string]any{ + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }, expectedValue: func(t *testing.T, v *VaultProvider) { headers := v.client.Headers() require.Equal(t, "", headers.Get(vaultconst.NamespaceHeaderName)) @@ -170,8 +178,12 @@ func TestVaultCAProvider_Configure(t *testing.T) { }, }, { - name: "TestConfigWithNamespace", - rawConfig: map[string]interface{}{"namespace": "ns1"}, + name: "TestConfigWithNamespace", + rawConfig: map[string]any{ + "namespace": "ns1", + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }, expectedValue: func(t *testing.T, v *VaultProvider) { h := v.client.Headers() @@ -182,8 +194,16 @@ func TestVaultCAProvider_Configure(t *testing.T) { for _, testcase := range testcases { t.Run(testcase.name, func(t *testing.T) { - provider, _ := testVaultProviderWithConfig(t, true, testcase.rawConfig) + testVault := NewTestVaultServer(t) + + attr := &VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + } + token := CreateVaultTokenWithAttrs(t, testVault.client, attr) + provider := createVaultProvider(t, true, testVault.Addr, token, testcase.rawConfig) testcase.expectedValue(t, provider) }) } @@ -192,11 +212,23 @@ func TestVaultCAProvider_Configure(t *testing.T) { } func TestVaultCAProvider_SecondaryActiveIntermediate(t *testing.T) { - SkipIfVaultNotPresent(t) - provider, testVault := testVaultProviderWithConfig(t, false, nil) - defer testVault.Stop() + t.Parallel() + + testVault := NewTestVaultServer(t) + + attr := &VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + } + token := CreateVaultTokenWithAttrs(t, testVault.client, attr) + + provider := createVaultProvider(t, false, testVault.Addr, token, map[string]any{ + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }) cert, err := provider.ActiveIntermediate() require.Empty(t, cert) @@ -204,12 +236,11 @@ func TestVaultCAProvider_SecondaryActiveIntermediate(t *testing.T) { } func TestVaultCAProvider_RenewToken(t *testing.T) { - SkipIfVaultNotPresent(t) - testVault, err := runTestVault(t) - require.NoError(t, err) - testVault.WaitUntilReady(t) + t.Parallel() + + testVault := NewTestVaultServer(t) // Create a token with a short TTL to be renewed by the provider. ttl := 1 * time.Second @@ -220,8 +251,10 @@ func TestVaultCAProvider_RenewToken(t *testing.T) { require.NoError(t, err) providerToken := secret.Auth.ClientToken - _, err = createVaultProvider(t, true, testVault.Addr, providerToken, nil) - require.NoError(t, err) + _ = createVaultProvider(t, true, testVault.Addr, providerToken, map[string]any{ + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }) // Check the last renewal time. secret, err = testVault.client.Auth().Token().Lookup(providerToken) @@ -240,12 +273,11 @@ func TestVaultCAProvider_RenewToken(t *testing.T) { } func TestVaultCAProvider_RenewTokenStopWatcherOnConfigure(t *testing.T) { - SkipIfVaultNotPresent(t) - testVault, err := runTestVault(t) - require.NoError(t, err) - testVault.WaitUntilReady(t) + t.Parallel() + + testVault := NewTestVaultServer(t) // Create a token with a short TTL to be renewed by the provider. ttl := 1 * time.Second @@ -256,8 +288,10 @@ func TestVaultCAProvider_RenewTokenStopWatcherOnConfigure(t *testing.T) { require.NoError(t, err) providerToken := secret.Auth.ClientToken - provider, err := createVaultProvider(t, true, testVault.Addr, providerToken, nil) - require.NoError(t, err) + provider := createVaultProvider(t, true, testVault.Addr, providerToken, map[string]any{ + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }) var gotStopped = uint32(0) provider.stopWatcher = func() { @@ -279,63 +313,48 @@ func TestVaultCAProvider_RenewTokenStopWatcherOnConfigure(t *testing.T) { require.Greater(r, lastRenewal, firstRenewal) }) - providerConfig := vaultProviderConfig(t, testVault.Addr, providerToken, nil) + providerConfig := vaultProviderConfig(t, testVault.Addr, providerToken, map[string]any{ + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }) require.NoError(t, provider.Configure(providerConfig)) require.Equal(t, uint32(1), atomic.LoadUint32(&gotStopped)) } func TestVaultCAProvider_Bootstrap(t *testing.T) { - SkipIfVaultNotPresent(t) - providerWDefaultRootCertTtl, testvault1 := testVaultProviderWithConfig(t, true, map[string]interface{}{ - "LeafCertTTL": "1h", - }) - defer testvault1.Stop() - client1 := testvault1.client - - providerCustomRootCertTtl, testvault2 := testVaultProviderWithConfig(t, true, map[string]interface{}{ - "LeafCertTTL": "1h", - "RootCertTTL": "8761h", - }) - defer testvault2.Stop() - client2 := testvault2.client + t.Parallel() - cases := []struct { - certFunc func() (string, error) + type testcase struct { + name string + caConfig map[string]any + certFunc func(*VaultProvider) (string, error) backendPath string rootCaCreation bool - provider *VaultProvider - client *vaultapi.Client expectedRootCertTTL string - }{ - { - certFunc: func() (string, error) { - root, err := providerWDefaultRootCertTtl.GenerateRoot() - return root.PEM, err - }, - backendPath: "pki-root/", - rootCaCreation: true, - client: client1, - provider: providerWDefaultRootCertTtl, - expectedRootCertTTL: structs.DefaultRootCertTTL, - }, - { - certFunc: providerCustomRootCertTtl.ActiveIntermediate, - backendPath: "pki-intermediate/", - rootCaCreation: false, - provider: providerCustomRootCertTtl, - client: client2, - expectedRootCertTTL: "8761h", - }, } - // Verify the root and intermediate certs match the ones in the vault backends - for _, tc := range cases { - provider := tc.provider - client := tc.client - cert, err := tc.certFunc() + run := func(t *testing.T, tc testcase) { + t.Parallel() + + tc.caConfig["RootPKIPath"] = "pki-root/" + tc.caConfig["IntermediatePKIPath"] = "pki-intermediate/" + + testVault := NewTestVaultServer(t) + + attr := &VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + } + token := CreateVaultTokenWithAttrs(t, testVault.client, attr) + + provider := createVaultProvider(t, true, testVault.Addr, token, tc.caConfig) + client := testVault.client + + cert, err := tc.certFunc(provider) require.NoError(t, err) req := client.NewRequest("GET", "/v1/"+tc.backendPath+"ca/pem") resp, err := client.RawRequest(req) @@ -360,6 +379,42 @@ func TestVaultCAProvider_Bootstrap(t *testing.T) { require.WithinDuration(t, expectedNotAfter, parsed.NotAfter, 10*time.Minute, "expected parsed cert ttl to be the same as the value configured") } } + + cases := []testcase{ + { + name: "default-root-cert-ttl", + caConfig: map[string]any{ + "LeafCertTTL": "1h", + }, + certFunc: func(provider *VaultProvider) (string, error) { + root, err := provider.GenerateRoot() + return root.PEM, err + }, + backendPath: "pki-root/", + rootCaCreation: true, + expectedRootCertTTL: structs.DefaultRootCertTTL, + }, + { + name: "custom-root-cert-ttl", + caConfig: map[string]any{ + "LeafCertTTL": "1h", + "RootCertTTL": "8761h", + }, + certFunc: func(provider *VaultProvider) (string, error) { + return provider.ActiveIntermediate() + }, + backendPath: "pki-intermediate/", + rootCaCreation: false, + expectedRootCertTTL: "8761h", + }, + } + + // Verify the root and intermediate certs match the ones in the vault backends + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + run(t, tc) + }) + } } func assertCorrectKeyType(t *testing.T, want, certPEM string) { @@ -379,178 +434,272 @@ func assertCorrectKeyType(t *testing.T, want, certPEM string) { } func TestVaultCAProvider_SignLeaf(t *testing.T) { - SkipIfVaultNotPresent(t) - for _, tc := range KeyTestCases { - tc := tc - t.Run(tc.Desc, func(t *testing.T) { - provider, testVault := testVaultProviderWithConfig(t, true, map[string]interface{}{ - "LeafCertTTL": "1h", - "PrivateKeyType": tc.KeyType, - "PrivateKeyBits": tc.KeyBits, - }) - defer testVault.Stop() + t.Parallel() - spiffeService := &connect.SpiffeIDService{ - Host: "node1", - Namespace: "default", - Datacenter: "dc1", - Service: "foo", - } + run := func(t *testing.T, tc KeyTestCase) { + t.Parallel() - root, err := provider.GenerateRoot() - require.NoError(t, err) - rootPEM := root.PEM - assertCorrectKeyType(t, tc.KeyType, rootPEM) + testVault := NewTestVaultServer(t) - intPEM, err := provider.ActiveIntermediate() - require.NoError(t, err) - assertCorrectKeyType(t, tc.KeyType, intPEM) + attr := &VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + } + token := CreateVaultTokenWithAttrs(t, testVault.client, attr) - // Generate a leaf cert for the service. - var firstSerial uint64 - { - raw, _ := connect.TestCSR(t, spiffeService) + provider := createVaultProvider(t, true, testVault.Addr, token, map[string]any{ + "LeafCertTTL": "1h", + "PrivateKeyType": tc.KeyType, + "PrivateKeyBits": tc.KeyBits, + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }) - csr, err := connect.ParseCSR(raw) - require.NoError(t, err) + spiffeService := &connect.SpiffeIDService{ + Host: "node1", + Namespace: "default", + Datacenter: "dc1", + Service: "foo", + } - cert, err := provider.Sign(csr) - require.NoError(t, err) + root, err := provider.GenerateRoot() + require.NoError(t, err) + rootPEM := root.PEM + assertCorrectKeyType(t, tc.KeyType, rootPEM) - parsed, err := connect.ParseCert(cert) - require.NoError(t, err) - require.Equal(t, parsed.URIs[0], spiffeService.URI()) - firstSerial = parsed.SerialNumber.Uint64() + intPEM, err := provider.ActiveIntermediate() + require.NoError(t, err) + assertCorrectKeyType(t, tc.KeyType, intPEM) - // Ensure the cert is valid now and expires within the correct limit. - now := time.Now() - require.True(t, parsed.NotAfter.Sub(now) < time.Hour) - require.True(t, parsed.NotBefore.Before(now)) + // Generate a leaf cert for the service. + var firstSerial uint64 + { + raw, _ := connect.TestCSR(t, spiffeService) - // Make sure we can validate the cert as expected. - require.NoError(t, connect.ValidateLeaf(rootPEM, cert, []string{intPEM})) - requireTrailingNewline(t, cert) - } + csr, err := connect.ParseCSR(raw) + require.NoError(t, err) - // Generate a new cert for another service and make sure - // the serial number is unique. - spiffeService.Service = "bar" - { - raw, _ := connect.TestCSR(t, spiffeService) + cert, err := provider.Sign(csr) + require.NoError(t, err) - csr, err := connect.ParseCSR(raw) - require.NoError(t, err) + parsed, err := connect.ParseCert(cert) + require.NoError(t, err) + require.Equal(t, parsed.URIs[0], spiffeService.URI()) + firstSerial = parsed.SerialNumber.Uint64() - cert, err := provider.Sign(csr) - require.NoError(t, err) + // Ensure the cert is valid now and expires within the correct limit. + now := time.Now() + require.True(t, parsed.NotAfter.Sub(now) < time.Hour) + require.True(t, parsed.NotBefore.Before(now)) - parsed, err := connect.ParseCert(cert) - require.NoError(t, err) - require.Equal(t, parsed.URIs[0], spiffeService.URI()) - require.NotEqual(t, firstSerial, parsed.SerialNumber.Uint64()) + // Make sure we can validate the cert as expected. + require.NoError(t, connect.ValidateLeaf(rootPEM, cert, []string{intPEM})) + requireTrailingNewline(t, cert) + } - // Ensure the cert is valid now and expires within the correct limit. - require.True(t, time.Until(parsed.NotAfter) < time.Hour) - require.True(t, parsed.NotBefore.Before(time.Now())) + // Generate a new cert for another service and make sure + // the serial number is unique. + spiffeService.Service = "bar" + { + raw, _ := connect.TestCSR(t, spiffeService) - // Make sure we can validate the cert as expected. - require.NoError(t, connect.ValidateLeaf(rootPEM, cert, []string{intPEM})) - } + csr, err := connect.ParseCSR(raw) + require.NoError(t, err) + + cert, err := provider.Sign(csr) + require.NoError(t, err) + + parsed, err := connect.ParseCert(cert) + require.NoError(t, err) + require.Equal(t, parsed.URIs[0], spiffeService.URI()) + require.NotEqual(t, firstSerial, parsed.SerialNumber.Uint64()) + + // Ensure the cert is valid now and expires within the correct limit. + require.True(t, time.Until(parsed.NotAfter) < time.Hour) + require.True(t, parsed.NotBefore.Before(time.Now())) + + // Make sure we can validate the cert as expected. + require.NoError(t, connect.ValidateLeaf(rootPEM, cert, []string{intPEM})) + } + } + + for _, tc := range KeyTestCases { + t.Run(tc.Desc, func(t *testing.T) { + run(t, tc) }) } } func TestVaultCAProvider_CrossSignCA(t *testing.T) { - SkipIfVaultNotPresent(t) + t.Parallel() + tests := CASigningKeyTypeCases() - for _, tc := range tests { - tc := tc - t.Run(tc.Desc, func(t *testing.T) { + run := func(t *testing.T, tc CASigningKeyTypes, withSudo, expectFailure bool) { + t.Parallel() - if tc.SigningKeyType != tc.CSRKeyType { - // See https://github.com/hashicorp/vault/issues/7709 - t.Skip("Vault doesn't support cross-signing different key types yet.") - } - provider1, testVault1 := testVaultProviderWithConfig(t, true, map[string]interface{}{ - "LeafCertTTL": "1h", - "PrivateKeyType": tc.SigningKeyType, - "PrivateKeyBits": tc.SigningKeyBits, - }) - defer testVault1.Stop() + if tc.SigningKeyType != tc.CSRKeyType { + // TODO: uncomment since the bug is closed + // See https://github.com/hashicorp/vault/issues/7709 + t.Skip("Vault doesn't support cross-signing different key types yet.") + } - { - root, err := provider1.GenerateRoot() - require.NoError(t, err) - assertCorrectKeyType(t, tc.SigningKeyType, root.PEM) + testVault1 := NewTestVaultServer(t) - intPEM, err := provider1.ActiveIntermediate() - require.NoError(t, err) - assertCorrectKeyType(t, tc.SigningKeyType, intPEM) - } + attr1 := &VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + WithSudo: withSudo, + } + token1 := CreateVaultTokenWithAttrs(t, testVault1.client, attr1) - provider2, testVault2 := testVaultProviderWithConfig(t, true, map[string]interface{}{ - "LeafCertTTL": "1h", - "PrivateKeyType": tc.CSRKeyType, - "PrivateKeyBits": tc.CSRKeyBits, - }) - defer testVault2.Stop() + provider1 := createVaultProvider(t, true, testVault1.Addr, token1, map[string]any{ + "LeafCertTTL": "1h", + "PrivateKeyType": tc.SigningKeyType, + "PrivateKeyBits": tc.SigningKeyBits, + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }) - { - root, err := provider2.GenerateRoot() - require.NoError(t, err) - assertCorrectKeyType(t, tc.CSRKeyType, root.PEM) + testutil.RunStep(t, "init", func(t *testing.T) { + root, err := provider1.GenerateRoot() + require.NoError(t, err) + assertCorrectKeyType(t, tc.SigningKeyType, root.PEM) - intPEM, err := provider2.ActiveIntermediate() - require.NoError(t, err) - assertCorrectKeyType(t, tc.CSRKeyType, intPEM) + intPEM, err := provider1.ActiveIntermediate() + require.NoError(t, err) + assertCorrectKeyType(t, tc.SigningKeyType, intPEM) + }) + + testVault2 := NewTestVaultServer(t) + + attr2 := &VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + WithSudo: false, // irrelevant for the new CA provider + } + token2 := CreateVaultTokenWithAttrs(t, testVault2.client, attr2) + + provider2 := createVaultProvider(t, true, testVault2.Addr, token2, map[string]any{ + "LeafCertTTL": "1h", + "PrivateKeyType": tc.CSRKeyType, + "PrivateKeyBits": tc.CSRKeyBits, + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }) + + testutil.RunStep(t, "swap", func(t *testing.T) { + root, err := provider2.GenerateRoot() + require.NoError(t, err) + assertCorrectKeyType(t, tc.CSRKeyType, root.PEM) + + intPEM, err := provider2.ActiveIntermediate() + require.NoError(t, err) + assertCorrectKeyType(t, tc.CSRKeyType, intPEM) + + if expectFailure { + testCrossSignProvidersShouldFail(t, provider1, provider2) + } else { + testCrossSignProviders(t, provider1, provider2) } + }) + } - testCrossSignProviders(t, provider1, provider2) + for _, tc := range tests { + t.Run(tc.Desc, func(t *testing.T) { + t.Run("without sudo", func(t *testing.T) { + run(t, tc, false, true) + }) + t.Run("with sudo", func(t *testing.T) { + run(t, tc, true, false) + }) }) } } func TestVaultProvider_SignIntermediate(t *testing.T) { - SkipIfVaultNotPresent(t) + t.Parallel() + tests := CASigningKeyTypeCases() - for _, tc := range tests { - tc := tc - t.Run(tc.Desc, func(t *testing.T) { - provider1, testVault1 := testVaultProviderWithConfig(t, true, map[string]interface{}{ - "LeafCertTTL": "1h", - "PrivateKeyType": tc.SigningKeyType, - "PrivateKeyBits": tc.SigningKeyBits, - }) - defer testVault1.Stop() + run := func(t *testing.T, tc CASigningKeyTypes) { + t.Parallel() - provider2, testVault2 := testVaultProviderWithConfig(t, false, map[string]interface{}{ - "LeafCertTTL": "1h", - "PrivateKeyType": tc.CSRKeyType, - "PrivateKeyBits": tc.CSRKeyBits, - }) - defer testVault2.Stop() + testVault1 := NewTestVaultServer(t) + + attr1 := &VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + } + token1 := CreateVaultTokenWithAttrs(t, testVault1.client, attr1) + + provider1 := createVaultProvider(t, true, testVault1.Addr, token1, map[string]any{ + "LeafCertTTL": "1h", + "PrivateKeyType": tc.SigningKeyType, + "PrivateKeyBits": tc.SigningKeyBits, + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }) + + testVault2 := NewTestVaultServer(t) + + attr2 := &VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + } + token2 := CreateVaultTokenWithAttrs(t, testVault2.client, attr2) + + provider2 := createVaultProvider(t, false, testVault2.Addr, token2, map[string]any{ + "LeafCertTTL": "1h", + "PrivateKeyType": tc.CSRKeyType, + "PrivateKeyBits": tc.CSRKeyBits, + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }) + + testSignIntermediateCrossDC(t, provider1, provider2) + } - testSignIntermediateCrossDC(t, provider1, provider2) + for _, tc := range tests { + t.Run(tc.Desc, func(t *testing.T) { + run(t, tc) }) } } func TestVaultProvider_SignIntermediateConsul(t *testing.T) { - SkipIfVaultNotPresent(t) + t.Parallel() + // primary = Vault, secondary = Consul t.Run("pri=vault,sec=consul", func(t *testing.T) { - provider1, testVault1 := testVaultProviderWithConfig(t, true, nil) - defer testVault1.Stop() + t.Parallel() + + testVault1 := NewTestVaultServer(t) + + attr1 := &VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + } + token1 := CreateVaultTokenWithAttrs(t, testVault1.client, attr1) + + provider1 := createVaultProvider(t, true, testVault1.Addr, token1, map[string]any{ + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }) conf := testConsulCAConfig() delegate := newMockDelegate(t, conf) @@ -565,6 +714,8 @@ func TestVaultProvider_SignIntermediateConsul(t *testing.T) { // primary = Consul, secondary = Vault t.Run("pri=consul,sec=vault", func(t *testing.T) { + t.Parallel() + conf := testConsulCAConfig() delegate := newMockDelegate(t, conf) provider1 := TestConsulProvider(t, delegate) @@ -577,29 +728,46 @@ func TestVaultProvider_SignIntermediateConsul(t *testing.T) { intermediateCertTTL := getIntermediateCertTTL(t, conf) leafCertTTL := intermediateCertTTL - 4*time.Hour - overrideConf := map[string]interface{}{ - "LeafCertTTL": []uint8(leafCertTTL.String()), + overrideConf := map[string]any{ + "LeafCertTTL": []uint8(leafCertTTL.String()), + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", } - provider2, testVault2 := testVaultProviderWithConfig(t, false, overrideConf) - defer testVault2.Stop() + testVault2 := NewTestVaultServer(t) + + attr2 := &VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + } + token2 := CreateVaultTokenWithAttrs(t, testVault2.client, attr2) + + provider2 := createVaultProvider(t, false, testVault2.Addr, token2, overrideConf) testSignIntermediateCrossDC(t, provider1, provider2) }) } func TestVaultProvider_Cleanup(t *testing.T) { - SkipIfVaultNotPresent(t) - testVault, err := runTestVault(t) - require.NoError(t, err) + t.Parallel() - testVault.WaitUntilReady(t) + testVault := NewTestVaultServer(t) t.Run("provider-change", func(t *testing.T) { - provider, err := createVaultProvider(t, true, testVault.Addr, testVault.RootToken, nil) - require.NoError(t, err) + attr := &VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + } + token := CreateVaultTokenWithAttrs(t, testVault.client, attr) + + provider := createVaultProvider(t, true, testVault.Addr, token, map[string]any{ + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }) // ensure that the intermediate PKI mount exists mounts, err := provider.client.Sys().ListMounts() @@ -616,8 +784,17 @@ func TestVaultProvider_Cleanup(t *testing.T) { }) t.Run("pki-path-change", func(t *testing.T) { - provider, err := createVaultProvider(t, true, testVault.Addr, testVault.RootToken, nil) - require.NoError(t, err) + attr := &VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + } + token := CreateVaultTokenWithAttrs(t, testVault.client, attr) + + provider := createVaultProvider(t, true, testVault.Addr, token, map[string]any{ + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }) // ensure that the intermediate PKI mount exists mounts, err := provider.client.Sys().ListMounts() @@ -625,12 +802,12 @@ func TestVaultProvider_Cleanup(t *testing.T) { require.Contains(t, mounts, provider.config.IntermediatePKIPath) // call cleanup with an intermediate pki path change - this should cause removal of the mount - require.NoError(t, provider.Cleanup(false, map[string]interface{}{ + require.NoError(t, provider.Cleanup(false, map[string]any{ "Address": testVault.Addr, - "Token": testVault.RootToken, + "Token": token, "RootPKIPath": "pki-root/", // - "IntermediatePKIPath": "pki-intermediate2/", + "IntermediatePKIPath": "pki-intermediate-2/", // Tests duration parsing after msgpack type mangling during raft apply. "LeafCertTTL": []uint8("72h"), })) @@ -642,8 +819,17 @@ func TestVaultProvider_Cleanup(t *testing.T) { }) t.Run("pki-path-unchanged", func(t *testing.T) { - provider, err := createVaultProvider(t, true, testVault.Addr, testVault.RootToken, nil) - require.NoError(t, err) + attr := &VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + } + token := CreateVaultTokenWithAttrs(t, testVault.client, attr) + + provider := createVaultProvider(t, true, testVault.Addr, token, map[string]any{ + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }) // ensure that the intermediate PKI mount exists mounts, err := provider.client.Sys().ListMounts() @@ -651,9 +837,9 @@ func TestVaultProvider_Cleanup(t *testing.T) { require.Contains(t, mounts, provider.config.IntermediatePKIPath) // call cleanup with no config changes - this should not cause removal of the intermediate pki path - require.NoError(t, provider.Cleanup(false, map[string]interface{}{ + require.NoError(t, provider.Cleanup(false, map[string]any{ "Address": testVault.Addr, - "Token": testVault.RootToken, + "Token": token, "RootPKIPath": "pki-root/", "IntermediatePKIPath": "pki-intermediate/", // Tests duration parsing after msgpack type mangling during raft apply. @@ -668,7 +854,6 @@ func TestVaultProvider_Cleanup(t *testing.T) { } func TestVaultProvider_ConfigureWithAuthMethod(t *testing.T) { - SkipIfVaultNotPresent(t) cases := []struct { @@ -722,12 +907,12 @@ func TestVaultProvider_ConfigureWithAuthMethod(t *testing.T) { err := testVault.Client().Sys().EnableAuthWithOptions(c.authMethodType, &vaultapi.EnableAuthOptions{Type: c.authMethodType}) require.NoError(t, err) - err = testVault.Client().Sys().PutPolicy("pki", pkiTestPolicy) + err = testVault.Client().Sys().PutPolicy("pki", pkiTestPolicy("pki-root", "pki-intermediate")) require.NoError(t, err) authMethodConf := c.configureAuthMethodFunc(t, testVault.Client()) - conf := map[string]interface{}{ + conf := map[string]any{ "Address": testVault.Addr, "RootPKIPath": "pki-root/", "IntermediatePKIPath": "pki-intermediate/", @@ -751,12 +936,13 @@ func TestVaultProvider_ConfigureWithAuthMethod(t *testing.T) { } func TestVaultProvider_RotateAuthMethodToken(t *testing.T) { - SkipIfVaultNotPresent(t) + t.Parallel() + testVault := NewTestVaultServer(t) - err := testVault.Client().Sys().PutPolicy("pki", pkiTestPolicy) + err := testVault.Client().Sys().PutPolicy("pki", pkiTestPolicy("pki-root", "pki-intermediate")) require.NoError(t, err) err = testVault.Client().Sys().EnableAuthWithOptions("approle", &vaultapi.EnableAuthOptions{Type: "approle"}) @@ -777,7 +963,7 @@ func TestVaultProvider_RotateAuthMethodToken(t *testing.T) { require.NoError(t, err) secretID := resp.Data["secret_id"] - conf := map[string]interface{}{ + conf := map[string]any{ "Address": testVault.Addr, "RootPKIPath": "pki-root/", "IntermediatePKIPath": "pki-intermediate/", @@ -813,6 +999,8 @@ func TestVaultProvider_RotateAuthMethodToken(t *testing.T) { func TestVaultProvider_ReconfigureIntermediateTTL(t *testing.T) { SkipIfVaultNotPresent(t) + t.Parallel() + // Set up a standard policy without any sys/mounts/pki-intermediate/tune permissions. policy := ` path "sys/mounts" @@ -848,7 +1036,7 @@ func TestVaultProvider_ReconfigureIntermediateTTL(t *testing.T) { providerToken := secret.Auth.ClientToken makeProviderConfWithTTL := func(ttl string) ProviderConfig { - conf := map[string]interface{}{ + conf := map[string]any{ "Address": testVault.Addr, "RootPKIPath": "pki-root/", "IntermediatePKIPath": "pki-intermediate/", @@ -902,6 +1090,223 @@ func TestVaultProvider_ReconfigureIntermediateTTL(t *testing.T) { require.Equal(t, 333*3600, mountConfig.MaxLeaseTTL) } +func TestVaultCAProvider_GenerateIntermediate(t *testing.T) { + SkipIfVaultNotPresent(t) + + t.Parallel() + + testVault := NewTestVaultServer(t) + + attr := &VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + } + token := CreateVaultTokenWithAttrs(t, testVault.client, attr) + + provider := createVaultProvider(t, true, testVault.Addr, token, map[string]any{ + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }) + + orig, err := provider.ActiveIntermediate() + require.NoError(t, err) + + // This test was created to ensure that our calls to Vault + // returns a new Intermediate certificate and further calls + // to ActiveIntermediate return the same new cert. + new, err := provider.GenerateIntermediate() + require.NoError(t, err) + + newActive, err := provider.ActiveIntermediate() + require.NoError(t, err) + + require.Equal(t, new, newActive) + require.NotEqual(t, orig, new) +} + +func TestVaultCAProvider_GenerateIntermediate_inSecondary(t *testing.T) { + SkipIfVaultNotPresent(t) + + t.Parallel() + + // Primary DC will be a consul provider. + conf := testConsulCAConfig() + delegate := newMockDelegate(t, conf) + primaryProvider := TestConsulProvider(t, delegate) + require.NoError(t, primaryProvider.Configure(testProviderConfig(conf))) + _, err := primaryProvider.GenerateRoot() + require.NoError(t, err) + + // Ensure that we don't configure vault to try and mint leafs that + // outlive their CA during the test (which hard fails in vault). + intermediateCertTTL := getIntermediateCertTTL(t, conf) + leafCertTTL := intermediateCertTTL - 4*time.Hour + + testVault := NewTestVaultServer(t) + + attr := &VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + } + token := CreateVaultTokenWithAttrs(t, testVault.client, attr) + + provider := createVaultProvider(t, false, testVault.Addr, token, map[string]any{ + "LeafCertTTL": []uint8(leafCertTTL.String()), + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }) + + var origIntermediate string + testutil.RunStep(t, "initialize secondary provider", func(t *testing.T) { + // Get the intermediate CSR from provider. + csrPEM, issuerID, err := provider.GenerateIntermediateCSR() + require.NoError(t, err) + csr, err := connect.ParseCSR(csrPEM) + require.NoError(t, err) + + // Sign the CSR with primaryProvider. + intermediatePEM, err := primaryProvider.SignIntermediate(csr) + require.NoError(t, err) + root, err := primaryProvider.GenerateRoot() + require.NoError(t, err) + rootPEM := root.PEM + + // Give the new intermediate to provider to use. + require.NoError(t, provider.SetIntermediate(intermediatePEM, rootPEM, issuerID)) + + origIntermediate, err = provider.ActiveIntermediate() + require.NoError(t, err) + }) + + testutil.RunStep(t, "renew secondary provider", func(t *testing.T) { + // Get the intermediate CSR from provider. + csrPEM, issuerID, err := provider.GenerateIntermediateCSR() + require.NoError(t, err) + csr, err := connect.ParseCSR(csrPEM) + require.NoError(t, err) + + // Sign the CSR with primaryProvider. + intermediatePEM, err := primaryProvider.SignIntermediate(csr) + require.NoError(t, err) + root, err := primaryProvider.GenerateRoot() + require.NoError(t, err) + rootPEM := root.PEM + + // Give the new intermediate to provider to use. + require.NoError(t, provider.SetIntermediate(intermediatePEM, rootPEM, issuerID)) + + // This test was created to ensure that our calls to Vault + // returns a new Intermediate certificate and further calls + // to ActiveIntermediate return the same new cert. + newActiveIntermediate, err := provider.ActiveIntermediate() + require.NoError(t, err) + + require.NotEqual(t, origIntermediate, newActiveIntermediate) + require.Equal(t, intermediatePEM, newActiveIntermediate) + }) +} + +func TestVaultCAProvider_VaultManaged(t *testing.T) { + SkipIfVaultNotPresent(t) + + const vaultManagedPKIPolicy = ` +path "/pki-root/" { + capabilities = [ "read" ] +} + +path "/pki-root/root/sign-intermediate" { + capabilities = [ "update" ] +} + +path "/pki-intermediate/*" { + capabilities = [ "create", "read", "update", "delete", "list" ] +} + +path "auth/token/renew-self" { + capabilities = [ "update" ] +} + +path "auth/token/lookup-self" { + capabilities = [ "read" ] +} +` + + testVault := NewTestVaultServer(t) + + client := testVault.Client() + + client.SetToken("root") + + // Mount pki root externally + require.NoError(t, client.Sys().Mount("pki-root", &vaultapi.MountInput{ + Type: "pki", + Description: "root CA backend for Consul Connect", + Config: vaultapi.MountConfigInput{ + MaxLeaseTTL: "12m", + }, + })) + _, err := client.Logical().Write("pki-root/root/generate/internal", map[string]interface{}{ + "common_name": "testconsul", + }) + require.NoError(t, err) + + // Mount pki intermediate externally + require.NoError(t, client.Sys().Mount("pki-intermediate", &vaultapi.MountInput{ + Type: "pki", + Description: "intermediate CA backend for Consul Connect", + Config: vaultapi.MountConfigInput{ + MaxLeaseTTL: "6m", + }, + })) + + // Generate a policy and token for the VaultProvider to use + require.NoError(t, client.Sys().PutPolicy("consul-ca", vaultManagedPKIPolicy)) + tcr := &vaultapi.TokenCreateRequest{ + Policies: []string{"consul-ca"}, + } + secret, err := testVault.client.Auth().Token().Create(tcr) + require.NoError(t, err) + providerToken := secret.Auth.ClientToken + + // We want to test the provider.Configure() step + + _ = createVaultProvider(t, true, testVault.Addr, providerToken, map[string]any{ + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }) +} + +func TestVaultCAProvider_ConsulManaged(t *testing.T) { + SkipIfVaultNotPresent(t) + + testVault := NewTestVaultServer(t) + + client := testVault.Client() + + client.SetToken("root") + + // We do not configure any mounts and instead let Consul + // be responsible for mounting root and intermediate PKI + + // Generate a policy and token for the VaultProvider to use + require.NoError(t, client.Sys().PutPolicy("consul-ca", pkiTestPolicy("pki-root", "pki-intermediate"))) + tcr := &vaultapi.TokenCreateRequest{ + Policies: []string{"consul-ca"}, + } + secret, err := testVault.client.Auth().Token().Create(tcr) + require.NoError(t, err) + providerToken := secret.Auth.ClientToken + + // We want to test the provider.Configure() step + + _ = createVaultProvider(t, true, testVault.Addr, providerToken, map[string]any{ + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + }) +} + func getIntermediateCertTTL(t *testing.T, caConf *structs.CAConfiguration) time.Duration { t.Helper() @@ -921,23 +1326,8 @@ func getIntermediateCertTTL(t *testing.T, caConf *structs.CAConfiguration) time. return dur } -func testVaultProviderWithConfig(t *testing.T, isPrimary bool, rawConf map[string]interface{}) (*VaultProvider, *TestVaultServer) { - testVault, err := runTestVault(t) - if err != nil { - t.Fatalf("err: %v", err) - } - - testVault.WaitUntilReady(t) - - provider, err := createVaultProvider(t, isPrimary, testVault.Addr, testVault.RootToken, rawConf) - if err != nil { - testVault.Stop() - t.Fatalf("err: %v", err) - } - return provider, testVault -} - -func createVaultProvider(t *testing.T, isPrimary bool, addr, token string, rawConf map[string]interface{}) (*VaultProvider, error) { +func createVaultProvider(t *testing.T, isPrimary bool, addr, token string, rawConf map[string]any) *VaultProvider { + t.Helper() cfg := vaultProviderConfig(t, addr, token, rawConf) provider := NewVaultProvider(hclog.New(nil)) @@ -956,18 +1346,34 @@ func createVaultProvider(t *testing.T, isPrimary bool, addr, token string, rawCo require.NoError(t, err) } - return provider, nil + return provider } -func vaultProviderConfig(t *testing.T, addr, token string, rawConf map[string]interface{}) ProviderConfig { - conf := map[string]interface{}{ - "Address": addr, - "Token": token, - "RootPKIPath": "pki-root/", - "IntermediatePKIPath": "pki-intermediate/", +func vaultProviderConfig(t *testing.T, addr, token string, rawConf map[string]any) ProviderConfig { + t.Helper() + require.NotEmpty(t, rawConf, "config map is required with at least %q and %q set", + "RootPKIPath", + "IntermediatePKIPath") + + conf := map[string]any{ + "Address": addr, + "Token": token, // Tests duration parsing after msgpack type mangling during raft apply. "LeafCertTTL": []uint8("72h"), } + + hasRequired := false + if rawConf != nil { + _, ok1 := rawConf["RootPKIPath"] + _, ok2 := rawConf["IntermediatePKIPath"] + hasRequired = ok1 && ok2 + } + if !hasRequired { + t.Fatalf("The caller must provide both %q and %q config settings to avoid an incidental collision", + "RootPKIPath", + "IntermediatePKIPath") + } + for k, v := range rawConf { conf[k] = v } diff --git a/agent/connect/ca/testing.go b/agent/connect/ca/testing.go index 97c28871d468..bcba2bbcc170 100644 --- a/agent/connect/ca/testing.go +++ b/agent/connect/ca/testing.go @@ -10,8 +10,10 @@ import ( "sync" "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-uuid" vaultapi "github.com/hashicorp/vault/api" "github.com/mitchellh/go-testing-interface" + "github.com/stretchr/testify/require" "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/sdk/freeport" @@ -27,11 +29,7 @@ import ( // these types of old CA key. // - SignIntermediate muse bt able to sign all the types of secondary // intermediate CA key with all these types of primary CA key -var KeyTestCases = []struct { - Desc string - KeyType string - KeyBits int -}{ +var KeyTestCases = []KeyTestCase{ { Desc: "Default Key Type (EC 256)", KeyType: connect.DefaultPrivateKeyType, @@ -44,6 +42,12 @@ var KeyTestCases = []struct { }, } +type KeyTestCase struct { + Desc string + KeyType string + KeyBits int +} + // CASigningKeyTypes is a struct with params for tests that sign one CA CSR with // another CA key. type CASigningKeyTypes struct { @@ -106,17 +110,6 @@ func SkipIfVaultNotPresent(t testing.T) { } func NewTestVaultServer(t testing.T) *TestVaultServer { - testVault, err := runTestVault(t) - if err != nil { - t.Fatalf("err: %v", err) - } - - testVault.WaitUntilReady(t) - - return testVault -} - -func runTestVault(t testing.T) (*TestVaultServer, error) { vaultBinaryName := os.Getenv("VAULT_BINARY_NAME") if vaultBinaryName == "" { vaultBinaryName = "vault" @@ -124,7 +117,7 @@ func runTestVault(t testing.T) (*TestVaultServer, error) { path, err := exec.LookPath(vaultBinaryName) if err != nil || path == "" { - return nil, fmt.Errorf("%q not found on $PATH", vaultBinaryName) + t.Fatalf("%q not found on $PATH", vaultBinaryName) } ports := freeport.GetN(t, 2) @@ -138,9 +131,7 @@ func runTestVault(t testing.T) (*TestVaultServer, error) { client, err := vaultapi.NewClient(&vaultapi.Config{ Address: "http://" + clientAddr, }) - if err != nil { - return nil, err - } + require.NoError(t, err) client.SetToken(token) args := []string{ @@ -152,14 +143,18 @@ func runTestVault(t testing.T) (*TestVaultServer, error) { clientAddr, "-address", clusterAddr, + // We pass '-dev-no-store-token' to avoid having multiple vaults oddly + // interact and fail like this: + // + // Error initializing Dev mode: rename /.vault-token.tmp /.vault-token: no such file or directory + // + "-dev-no-store-token", } cmd := exec.Command(vaultBinaryName, args...) cmd.Stdout = ioutil.Discard cmd.Stderr = ioutil.Discard - if err := cmd.Start(); err != nil { - return nil, err - } + require.NoError(t, cmd.Start()) testVault := &TestVaultServer{ RootToken: token, @@ -173,7 +168,9 @@ func runTestVault(t testing.T) (*TestVaultServer, error) { } }) - return testVault, nil + testVault.WaitUntilReady(t) + + return testVault } type TestVaultServer struct { @@ -224,6 +221,9 @@ func (v *TestVaultServer) Stop() error { // wait for the process to exit to be sure that the data dir can be // deleted on all platforms. if err := v.cmd.Wait(); err != nil { + if strings.Contains(err.Error(), "exec: Wait was already called") { + return nil + } return err } return nil @@ -238,3 +238,127 @@ func requireTrailingNewline(t testing.T, leafPEM string) { t.Fatalf("cert do not end with a new line") } } + +// The zero value implies unprivileged. +type VaultTokenAttributes struct { + RootPath, IntermediatePath string + + ConsulManaged bool + VaultManaged bool + WithSudo bool + + CustomRules string +} + +func (a *VaultTokenAttributes) DisplayName() string { + switch { + case a == nil: + return "unprivileged" + case a.CustomRules != "": + return "custom" + case a.ConsulManaged: + return "consul-managed" + case a.VaultManaged: + return "vault-managed" + default: + return "unprivileged" + } +} + +func (a *VaultTokenAttributes) Rules(t testing.T) string { + switch { + case a == nil: + return "" + + case a.CustomRules != "": + return a.CustomRules + + case a.RootPath == "": + t.Fatal("missing required RootPath") + return "" // dead code + + case a.IntermediatePath == "": + t.Fatal("missing required IntermediatePath") + return "" // dead code + + case a.ConsulManaged: + // Consul Managed PKI Mounts + rules := fmt.Sprintf(` +path "sys/mounts" { + capabilities = [ "read" ] +} + +path "sys/mounts/%[1]s" { + capabilities = [ "create", "read", "update", "delete", "list" ] +} + +path "sys/mounts/%[2]s" { + capabilities = [ "create", "read", "update", "delete", "list" ] +} + +# Needed for Consul 1.11+ +path "sys/mounts/%[2]s/tune" { + capabilities = [ "update" ] +} + +# vault token renewal +path "auth/token/renew-self" { + capabilities = [ "update" ] +} +path "auth/token/lookup-self" { + capabilities = [ "read" ] +} + +path "%[1]s/*" { + capabilities = [ "create", "read", "update", "delete", "list" ] +} + +path "%[2]s/*" { + capabilities = [ "create", "read", "update", "delete", "list" ] +} +`, a.RootPath, a.IntermediatePath) + + if a.WithSudo { + rules += fmt.Sprintf(` + +path "%[1]s/root/sign-self-issued" { + capabilities = [ "sudo", "update" ] +} +`, a.RootPath) + } + + return rules + + case a.VaultManaged: + // Vault-managed PKI root. + t.Fatal("TODO: implement this and use it in tests") + return "" + + default: + // zero value + return "" + } +} + +func CreateVaultTokenWithAttrs(t testing.T, client *vaultapi.Client, attr *VaultTokenAttributes) string { + policyName, err := uuid.GenerateUUID() + require.NoError(t, err) + + rules := attr.Rules(t) + + token := createVaultTokenAndPolicy(t, client, policyName, rules) + // t.Logf("created vault token with scope %q: %s", attr.DisplayName(), token) + return token +} + +func createVaultTokenAndPolicy(t testing.T, client *vaultapi.Client, policyName, policyRules string) string { + require.NoError(t, client.Sys().PutPolicy(policyName, policyRules)) + + renew := true + tok, err := client.Auth().Token().Create(&vaultapi.TokenCreateRequest{ + Policies: []string{policyName}, + Renewable: &renew, + }) + require.NoError(t, err) + return tok.Auth.ClientToken +} diff --git a/agent/connect/common_names.go b/agent/connect/common_names.go index 2915de217119..641831b24f36 100644 --- a/agent/connect/common_names.go +++ b/agent/connect/common_names.go @@ -45,9 +45,10 @@ func CompactUID() (string, error) { // specific purpose. // // Format is: -// {provider}-{uniqueID_first8}.{pri|sec}.ca..consul // -// trust domain is truncated to keep the whole name short +// {provider}-{uniqueID_first8}.{pri|sec}.ca..consul +// +// trust domain is truncated to keep the whole name short func CACN(provider, uniqueID, trustDomain string, primaryDC bool) string { providerSan := invalidDNSNameChars.ReplaceAllString(strings.ToLower(provider), "") typ := "pri" diff --git a/agent/connect/csr.go b/agent/connect/csr.go index f699a5879298..63ba59476bf6 100644 --- a/agent/connect/csr.go +++ b/agent/connect/csr.go @@ -12,6 +12,7 @@ import ( "fmt" "net" "net/url" + "strings" ) // SigAlgoForKey returns the preferred x509.SignatureAlgorithm for a given key @@ -47,11 +48,28 @@ func SigAlgoForKeyType(keyType string) x509.SignatureAlgorithm { // along with the PEM-encoded private key for this certificate. func CreateCSR(uri CertURI, privateKey crypto.Signer, dnsNames []string, ipAddresses []net.IP, extensions ...pkix.Extension) (string, error) { + + // Drop everything after the ':' from the name when constructing the DNS SANs. + uniqueNames := make(map[string]struct{}) + formattedDNSNames := make([]string, 0) + for _, host := range dnsNames { + hostSegments := strings.Split(host, ":") + if len(hostSegments) == 0 || hostSegments[0] == "" { + continue + } + + formattedHost := hostSegments[0] + if _, ok := uniqueNames[formattedHost]; !ok { + formattedDNSNames = append(formattedDNSNames, formattedHost) + uniqueNames[formattedHost] = struct{}{} + } + } + template := &x509.CertificateRequest{ URIs: []*url.URL{uri.URI()}, SignatureAlgorithm: SigAlgoForKey(privateKey), ExtraExtensions: extensions, - DNSNames: dnsNames, + DNSNames: formattedDNSNames, IPAddresses: ipAddresses, } HackSANExtensionForCSR(template) diff --git a/agent/connect/csr_test.go b/agent/connect/csr_test.go new file mode 100644 index 000000000000..322585840ebb --- /dev/null +++ b/agent/connect/csr_test.go @@ -0,0 +1,36 @@ +package connect + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestCreateCSR_FormatDNSSANs(t *testing.T) { + pk, _, err := GeneratePrivateKey() + require.NoError(t, err) + spiffeID := &SpiffeIDService{ + Host: "7528f42f-92e5-4db4-b84c-3405c3ca91e6", + Service: "srv1", + Datacenter: "dc1", + } + csr, err := CreateCSR(spiffeID, pk, []string{ + "foo.example.com", + "foo.example.com:8080", + "bar.example.com", + "*.example.com", + ":8080", + "", + }, nil) + require.NoError(t, err) + + req, err := ParseCSR(csr) + require.NoError(t, err) + require.Len(t, req.URIs, 1) + require.Equal(t, spiffeID.URI(), req.URIs[0]) + require.Equal(t, []string{ + "foo.example.com", + "bar.example.com", + "*.example.com", + }, req.DNSNames) +} diff --git a/agent/connect/sni.go b/agent/connect/sni.go index 17fce7e27c45..b78c9f92c81d 100644 --- a/agent/connect/sni.go +++ b/agent/connect/sni.go @@ -28,7 +28,7 @@ func UpstreamSNI(u *structs.Upstream, subset string, dc string, trustDomain stri func GatewaySNI(dc string, partition, trustDomain string) string { if partition == "" { - // TODO(partitions) Make default available in OSS as a constant for uses like this one + // TODO(partitions) Make default available in CE as a constant for uses like this one partition = "default" } @@ -45,7 +45,7 @@ func ServiceSNI(service string, subset string, namespace string, partition strin namespace = structs.IntentionDefaultNamespace } if partition == "" { - // TODO(partitions) Make default available in OSS as a constant for uses like this one + // TODO(partitions) Make default available in CE as a constant for uses like this one partition = "default" } @@ -73,7 +73,7 @@ func PeeredServiceSNI(service, namespace, partition, peerName, trustDomain strin namespace = structs.IntentionDefaultNamespace } if partition == "" { - // TODO(partitions) Make default available in OSS as a constant for uses like this one + // TODO(partitions) Make default available in CE as a constant for uses like this one partition = "default" } diff --git a/agent/connect/uri_agent_oss.go b/agent/connect/uri_agent_ce.go similarity index 86% rename from agent/connect/uri_agent_oss.go rename to agent/connect/uri_agent_ce.go index e24f9b560989..fdfb075a8d4b 100644 --- a/agent/connect/uri_agent_oss.go +++ b/agent/connect/uri_agent_ce.go @@ -10,7 +10,7 @@ import ( ) // GetEnterpriseMeta will synthesize an EnterpriseMeta struct from the SpiffeIDAgent. -// in OSS this just returns an empty (but never nil) struct pointer +// in CE this just returns an empty (but never nil) struct pointer func (id SpiffeIDAgent) GetEnterpriseMeta() *acl.EnterpriseMeta { return &acl.EnterpriseMeta{} } diff --git a/agent/connect/uri_agent_oss_test.go b/agent/connect/uri_agent_ce_test.go similarity index 100% rename from agent/connect/uri_agent_oss_test.go rename to agent/connect/uri_agent_ce_test.go diff --git a/agent/connect/uri_mesh_gateway_oss.go b/agent/connect/uri_mesh_gateway_ce.go similarity index 85% rename from agent/connect/uri_mesh_gateway_oss.go rename to agent/connect/uri_mesh_gateway_ce.go index 8865b97f94fa..a92d0fc7ffca 100644 --- a/agent/connect/uri_mesh_gateway_oss.go +++ b/agent/connect/uri_mesh_gateway_ce.go @@ -10,7 +10,7 @@ import ( ) // GetEnterpriseMeta will synthesize an EnterpriseMeta struct from the SpiffeIDAgent. -// in OSS this just returns an empty (but never nil) struct pointer +// in CE this just returns an empty (but never nil) struct pointer func (id SpiffeIDMeshGateway) GetEnterpriseMeta() *acl.EnterpriseMeta { return &acl.EnterpriseMeta{} } diff --git a/agent/connect/uri_mesh_gateway_oss_test.go b/agent/connect/uri_mesh_gateway_ce_test.go similarity index 100% rename from agent/connect/uri_mesh_gateway_oss_test.go rename to agent/connect/uri_mesh_gateway_ce_test.go diff --git a/agent/connect/uri_service.go b/agent/connect/uri_service.go index 685498b1afbd..e3ed1b28895a 100644 --- a/agent/connect/uri_service.go +++ b/agent/connect/uri_service.go @@ -40,10 +40,10 @@ func (id SpiffeIDService) uriPath() string { id.Service, ) - // Although OSS has no support for partitions, it still needs to be able to + // Although CE has no support for partitions, it still needs to be able to // handle exportedPartition from peered Consul Enterprise clusters in order // to generate the correct SpiffeID. - // We intentionally avoid using pbpartition.DefaultName here to be OSS friendly. + // We intentionally avoid using pbpartition.DefaultName here to be CE friendly. if ap := id.PartitionOrDefault(); ap != "" && ap != "default" { return "/ap/" + ap + path } diff --git a/agent/connect/uri_service_oss.go b/agent/connect/uri_service_ce.go similarity index 72% rename from agent/connect/uri_service_oss.go rename to agent/connect/uri_service_ce.go index 63a51bf7003b..7eedecade676 100644 --- a/agent/connect/uri_service_oss.go +++ b/agent/connect/uri_service_ce.go @@ -10,13 +10,13 @@ import ( ) // GetEnterpriseMeta will synthesize an EnterpriseMeta struct from the SpiffeIDService. -// in OSS this just returns an empty (but never nil) struct pointer +// in CE this just returns an empty (but never nil) struct pointer func (id SpiffeIDService) GetEnterpriseMeta() *acl.EnterpriseMeta { return &acl.EnterpriseMeta{} } -// PartitionOrDefault breaks from OSS's pattern of returning empty strings. -// Although OSS has no support for partitions, it still needs to be able to +// PartitionOrDefault breaks from CE's pattern of returning empty strings. +// Although CE has no support for partitions, it still needs to be able to // handle exportedPartition from peered Consul Enterprise clusters in order // to generate the correct SpiffeID. func (id SpiffeIDService) PartitionOrDefault() string { diff --git a/agent/connect/uri_service_oss_test.go b/agent/connect/uri_service_ce_test.go similarity index 100% rename from agent/connect/uri_service_oss_test.go rename to agent/connect/uri_service_ce_test.go diff --git a/agent/consul/acl.go b/agent/consul/acl.go index bf7972e5d4f1..e063d96cac65 100644 --- a/agent/consul/acl.go +++ b/agent/consul/acl.go @@ -225,19 +225,19 @@ type ACLResolverSettings struct { // - Resolving roles remotely via an ACL.RoleResolve RPC // // Remote Resolution: -// Remote resolution can be done synchronously or asynchronously depending -// on the ACLDownPolicy in the Config passed to the resolver. // -// When the down policy is set to async-cache and we have already cached values -// then go routines will be spawned to perform the RPCs in the background -// and then will update the cache with either the positive or negative result. +// Remote resolution can be done synchronously or asynchronously depending +// on the ACLDownPolicy in the Config passed to the resolver. // -// When the down policy is set to extend-cache or the token/policy/role is not already -// cached then the same go routines are spawned to do the RPCs in the background. -// However in this mode channels are created to receive the results of the RPC -// and are registered with the resolver. Those channels are immediately read/blocked -// upon. +// When the down policy is set to async-cache and we have already cached values +// then go routines will be spawned to perform the RPCs in the background +// and then will update the cache with either the positive or negative result. // +// When the down policy is set to extend-cache or the token/policy/role is not already +// cached then the same go routines are spawned to do the RPCs in the background. +// However in this mode channels are created to receive the results of the RPC +// and are registered with the resolver. Those channels are immediately read/blocked +// upon. type ACLResolver struct { config ACLResolverSettings logger hclog.Logger @@ -1068,20 +1068,10 @@ func (r *ACLResolver) ACLsEnabled() bool { return true } -// TODO(peering): fix all calls to use the new signature and rename it back func (r *ACLResolver) ResolveTokenAndDefaultMeta( token string, entMeta *acl.EnterpriseMeta, authzContext *acl.AuthorizerContext, -) (resolver.Result, error) { - return r.ResolveTokenAndDefaultMetaWithPeerName(token, entMeta, structs.DefaultPeerKeyword, authzContext) -} - -func (r *ACLResolver) ResolveTokenAndDefaultMetaWithPeerName( - token string, - entMeta *acl.EnterpriseMeta, - peerName string, - authzContext *acl.AuthorizerContext, ) (resolver.Result, error) { result, err := r.ResolveToken(token) if err != nil { @@ -1095,8 +1085,9 @@ func (r *ACLResolver) ResolveTokenAndDefaultMetaWithPeerName( // Default the EnterpriseMeta based on the Tokens meta or actual defaults // in the case of unknown identity switch { - case peerName == "" && result.ACLIdentity != nil: + case authzContext.PeerOrEmpty() == "" && result.ACLIdentity != nil: entMeta.Merge(result.ACLIdentity.EnterpriseMetadata()) + case result.ACLIdentity != nil: // We _do not_ normalize the enterprise meta from the token when a peer // name was specified because namespaces across clusters are not diff --git a/agent/consul/acl_authmethod_oss.go b/agent/consul/acl_authmethod_ce.go similarity index 100% rename from agent/consul/acl_authmethod_oss.go rename to agent/consul/acl_authmethod_ce.go diff --git a/agent/consul/acl_oss.go b/agent/consul/acl_ce.go similarity index 95% rename from agent/consul/acl_oss.go rename to agent/consul/acl_ce.go index 1fe4fbbf817f..85555c57fc3e 100644 --- a/agent/consul/acl_oss.go +++ b/agent/consul/acl_ce.go @@ -33,13 +33,13 @@ func (r *ACLResolver) resolveEnterpriseDefaultsForIdentity(identity structs.ACLI // resolveEnterpriseIdentityAndRoles will resolve an enterprise identity to an additional set of roles func (_ *ACLResolver) resolveEnterpriseIdentityAndRoles(_ structs.ACLIdentity) (structs.ACLIdentity, structs.ACLRoles, error) { - // this function does nothing in OSS + // this function does nothing in CE return nil, nil, nil } // resolveEnterpriseIdentityAndPolicies will resolve an enterprise identity to an additional set of policies func (_ *ACLResolver) resolveEnterpriseIdentityAndPolicies(_ structs.ACLIdentity) (structs.ACLIdentity, structs.ACLPolicies, error) { - // this function does nothing in OSS + // this function does nothing in CE return nil, nil, nil } diff --git a/agent/consul/acl_oss_test.go b/agent/consul/acl_ce_test.go similarity index 100% rename from agent/consul/acl_oss_test.go rename to agent/consul/acl_ce_test.go diff --git a/agent/consul/acl_endpoint.go b/agent/consul/acl_endpoint.go index 1c5731833808..7e047ca22175 100644 --- a/agent/consul/acl_endpoint.go +++ b/agent/consul/acl_endpoint.go @@ -13,8 +13,8 @@ import ( "github.com/armon/go-metrics/prometheus" "github.com/hashicorp/go-bexpr" "github.com/hashicorp/go-hclog" - memdb "github.com/hashicorp/go-memdb" - uuid "github.com/hashicorp/go-uuid" + "github.com/hashicorp/go-memdb" + "github.com/hashicorp/go-uuid" "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/acl/resolver" @@ -108,19 +108,18 @@ type ACL struct { // fileBootstrapResetIndex retrieves the reset index specified by the administrator from // the file on disk. // -// Q: What is the bootstrap reset index? -// A: If you happen to lose acess to all tokens capable of ACL management you need a way -// to get back into your system. This allows an admin to write the current -// bootstrap "index" into a special file on disk to override the mechanism preventing -// a second token bootstrap. The index will be retrieved by a API call to /v1/acl/bootstrap -// When already bootstrapped this API will return the reset index necessary within -// the error response. Once set in the file, the bootstrap API can be used again to -// get a new token. -// -// Q: Why is the reset index not in the config? -// A: We want to be able to remove the reset index once we have used it. This prevents -// accidentally allowing bootstrapping yet again after a snapshot restore. +// Q: What is the bootstrap reset index? +// A: If you happen to lose acess to all tokens capable of ACL management you need a way +// to get back into your system. This allows an admin to write the current +// bootstrap "index" into a special file on disk to override the mechanism preventing +// a second token bootstrap. The index will be retrieved by a API call to /v1/acl/bootstrap +// When already bootstrapped this API will return the reset index necessary within +// the error response. Once set in the file, the bootstrap API can be used again to +// get a new token. // +// Q: Why is the reset index not in the config? +// A: We want to be able to remove the reset index once we have used it. This prevents +// accidentally allowing bootstrapping yet again after a snapshot restore. func (a *ACL) fileBootstrapResetIndex() uint64 { // Determine the file path to check path := filepath.Join(a.srv.config.DataDir, aclBootstrapReset) @@ -657,8 +656,18 @@ func (a *ACL) TokenList(args *structs.ACLTokenListRequest, reply *structs.ACLTok } return a.srv.blockingQuery(&args.QueryOptions, &reply.QueryMeta, - func(ws memdb.WatchSet, state *state.Store) error { - index, tokens, err := state.ACLTokenList(ws, args.IncludeLocal, args.IncludeGlobal, args.Policy, args.Role, args.AuthMethod, methodMeta, &args.EnterpriseMeta) + func(ws memdb.WatchSet, s *state.Store) error { + index, tokens, err := s.ACLTokenListWithParameters(ws, state.ACLTokenListParameters{ + Local: args.IncludeLocal, + Global: args.IncludeGlobal, + Policy: args.Policy, + Role: args.Role, + MethodName: args.AuthMethod, + ServiceName: args.ServiceName, + MethodMeta: methodMeta, + EnterpriseMeta: &args.EnterpriseMeta, + }) + if err != nil { return err } @@ -846,8 +855,8 @@ func (a *ACL) PolicySet(args *structs.ACLPolicySetRequest, reply *structs.ACLPol return fmt.Errorf("Invalid Policy: no Name is set") } - if !acl.IsValidPolicyName(policy.Name) { - return fmt.Errorf("Invalid Policy: invalid Name. Only alphanumeric characters, '-' and '_' are allowed") + if err := acl.ValidatePolicyName(policy.Name); err != nil { + return err } var idMatch *structs.ACLPolicy @@ -892,13 +901,13 @@ func (a *ACL) PolicySet(args *structs.ACLPolicySetRequest, reply *structs.ACLPol return fmt.Errorf("Invalid Policy: A policy with name %q already exists", policy.Name) } - if policy.ID == structs.ACLPolicyGlobalManagementID { + if builtinPolicy, ok := structs.ACLBuiltinPolicies[policy.ID]; ok { if policy.Datacenters != nil || len(policy.Datacenters) > 0 { - return fmt.Errorf("Changing the Datacenters of the builtin global-management policy is not permitted") + return fmt.Errorf("Changing the Datacenters of the %s policy is not permitted", builtinPolicy.Name) } if policy.Rules != idMatch.Rules { - return fmt.Errorf("Changing the Rules for the builtin global-management policy is not permitted") + return fmt.Errorf("Changing the Rules for the builtin %s policy is not permitted", builtinPolicy.Name) } } } @@ -973,8 +982,8 @@ func (a *ACL) PolicyDelete(args *structs.ACLPolicyDeleteRequest, reply *string) return nil } - if policy.ID == structs.ACLPolicyGlobalManagementID { - return fmt.Errorf("Delete operation not permitted on the builtin global-management policy") + if builtinPolicy, ok := structs.ACLBuiltinPolicies[policy.ID]; ok { + return fmt.Errorf("Delete operation not permitted on the builtin %s policy", builtinPolicy.Name) } req := structs.ACLPolicyBatchDeleteRequest{ @@ -1087,7 +1096,7 @@ func (a *ACL) PolicyResolve(args *structs.ACLPolicyBatchGetRequest, reply *struc } } - a.srv.setQueryMeta(&reply.QueryMeta, args.Token) + a.srv.SetQueryMeta(&reply.QueryMeta, args.Token) return nil } @@ -1491,7 +1500,7 @@ func (a *ACL) RoleResolve(args *structs.ACLRoleBatchGetRequest, reply *structs.A } } - a.srv.setQueryMeta(&reply.QueryMeta, args.Token) + a.srv.SetQueryMeta(&reply.QueryMeta, args.Token) return nil } diff --git a/agent/consul/acl_endpoint_oss.go b/agent/consul/acl_endpoint_ce.go similarity index 100% rename from agent/consul/acl_endpoint_oss.go rename to agent/consul/acl_endpoint_ce.go diff --git a/agent/consul/acl_endpoint_test.go b/agent/consul/acl_endpoint_test.go index 79846beaa543..84bb3bc2828d 100644 --- a/agent/consul/acl_endpoint_test.go +++ b/agent/consul/acl_endpoint_test.go @@ -15,7 +15,6 @@ import ( msgpackrpc "github.com/hashicorp/consul-net-rpc/net-rpc-msgpackrpc" "github.com/hashicorp/consul-net-rpc/net/rpc" - "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/consul/authmethod/kubeauth" "github.com/hashicorp/consul/agent/consul/authmethod/testauth" @@ -94,7 +93,7 @@ func TestACLEndpoint_ReplicationStatus(t *testing.T) { retry.Run(t, func(r *retry.R) { var status structs.ACLReplicationStatus err := msgpackrpc.CallWithCodec(codec, "ACL.ReplicationStatus", &getR, &status) - require.NoError(t, err) + require.NoError(r, err) require.True(r, status.Enabled) require.True(r, status.Running) @@ -2123,7 +2122,7 @@ func TestACLEndpoint_PolicySet_CustomID(t *testing.T) { require.Error(t, err) } -func TestACLEndpoint_PolicySet_globalManagement(t *testing.T) { +func TestACLEndpoint_PolicySet_builtins(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short") } @@ -2135,47 +2134,50 @@ func TestACLEndpoint_PolicySet_globalManagement(t *testing.T) { acl := ACL{srv: srv} - // Can't change the rules - { - req := structs.ACLPolicySetRequest{ - Datacenter: "dc1", - Policy: structs.ACLPolicy{ - ID: structs.ACLPolicyGlobalManagementID, - Name: "foobar", // This is required to get past validation - Rules: "service \"\" { policy = \"write\" }", - }, - WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken}, - } - resp := structs.ACLPolicy{} + for _, builtinPolicy := range structs.ACLBuiltinPolicies { + name := fmt.Sprintf("foobar-%s", builtinPolicy.Name) // This is required to get past validation - err := acl.PolicySet(&req, &resp) - require.EqualError(t, err, "Changing the Rules for the builtin global-management policy is not permitted") - } + // Can't change the rules + { + req := structs.ACLPolicySetRequest{ + Datacenter: "dc1", + Policy: structs.ACLPolicy{ + ID: builtinPolicy.ID, + Name: name, + Rules: "service \"\" { policy = \"write\" }", + }, + WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken}, + } + resp := structs.ACLPolicy{} - // Can rename it - { - req := structs.ACLPolicySetRequest{ - Datacenter: "dc1", - Policy: structs.ACLPolicy{ - ID: structs.ACLPolicyGlobalManagementID, - Name: "foobar", - Rules: structs.ACLPolicyGlobalManagement, - }, - WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken}, + err := acl.PolicySet(&req, &resp) + require.EqualError(t, err, fmt.Sprintf("Changing the Rules for the builtin %s policy is not permitted", builtinPolicy.Name)) } - resp := structs.ACLPolicy{} - err := acl.PolicySet(&req, &resp) - require.NoError(t, err) + // Can rename it + { + req := structs.ACLPolicySetRequest{ + Datacenter: "dc1", + Policy: structs.ACLPolicy{ + ID: builtinPolicy.ID, + Name: name, + Rules: builtinPolicy.Rules, + }, + WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken}, + } + resp := structs.ACLPolicy{} - // Get the policy again - policyResp, err := retrieveTestPolicy(codec, TestDefaultInitialManagementToken, "dc1", structs.ACLPolicyGlobalManagementID) - require.NoError(t, err) - policy := policyResp.Policy + err := acl.PolicySet(&req, &resp) + require.NoError(t, err) - require.Equal(t, policy.ID, structs.ACLPolicyGlobalManagementID) - require.Equal(t, policy.Name, "foobar") + // Get the policy again + policyResp, err := retrieveTestPolicy(codec, TestDefaultInitialManagementToken, "dc1", builtinPolicy.ID) + require.NoError(t, err) + policy := policyResp.Policy + require.Equal(t, policy.ID, builtinPolicy.ID) + require.Equal(t, policy.Name, name) + } } } @@ -2211,7 +2213,7 @@ func TestACLEndpoint_PolicyDelete(t *testing.T) { require.Nil(t, tokenResp.Policy) } -func TestACLEndpoint_PolicyDelete_globalManagement(t *testing.T) { +func TestACLEndpoint_PolicyDelete_builtins(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short") } @@ -2222,16 +2224,17 @@ func TestACLEndpoint_PolicyDelete_globalManagement(t *testing.T) { waitForLeaderEstablishment(t, srv) acl := ACL{srv: srv} - req := structs.ACLPolicyDeleteRequest{ - Datacenter: "dc1", - PolicyID: structs.ACLPolicyGlobalManagementID, - WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken}, - } - var resp string - - err := acl.PolicyDelete(&req, &resp) + for _, builtinPolicy := range structs.ACLBuiltinPolicies { + req := structs.ACLPolicyDeleteRequest{ + Datacenter: "dc1", + PolicyID: builtinPolicy.ID, + WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken}, + } + var resp string - require.EqualError(t, err, "Delete operation not permitted on the builtin global-management policy") + err := acl.PolicyDelete(&req, &resp) + require.EqualError(t, err, fmt.Sprintf("Delete operation not permitted on the builtin %s policy", builtinPolicy.Name)) + } } func TestACLEndpoint_PolicyList(t *testing.T) { @@ -2264,6 +2267,7 @@ func TestACLEndpoint_PolicyList(t *testing.T) { policies := []string{ structs.ACLPolicyGlobalManagementID, + structs.ACLPolicyGlobalReadOnlyID, p1.ID, p2.ID, } @@ -5626,6 +5630,7 @@ func deleteTestAuthMethod(codec rpc.ClientCodec, initialManagementToken string, err := msgpackrpc.CallWithCodec(codec, "ACL.AuthMethodDelete", &arg, &ignored) return err } + func upsertTestAuthMethod( codec rpc.ClientCodec, initialManagementToken string, datacenter string, sessionID string, diff --git a/agent/consul/acl_replication_test.go b/agent/consul/acl_replication_test.go index 102a7b4b2603..623b68380c2f 100644 --- a/agent/consul/acl_replication_test.go +++ b/agent/consul/acl_replication_test.go @@ -379,8 +379,10 @@ func TestACLReplication_Tokens(t *testing.T) { checkSame := func(t *retry.R) { // only account for global tokens - local tokens shouldn't be replicated + // nolint:staticcheck index, remote, err := s1.fsm.State().ACLTokenList(nil, false, true, "", "", "", nil, nil) require.NoError(t, err) + // nolint:staticcheck _, local, err := s2.fsm.State().ACLTokenList(nil, false, true, "", "", "", nil, nil) require.NoError(t, err) @@ -484,6 +486,7 @@ func TestACLReplication_Tokens(t *testing.T) { }) // verify dc2 local tokens didn't get blown away + // nolint:staticcheck _, local, err := s2.fsm.State().ACLTokenList(nil, true, false, "", "", "", nil, nil) require.NoError(t, err) require.Len(t, local, 50) @@ -822,9 +825,11 @@ func TestACLReplication_AllTypes(t *testing.T) { checkSameTokens := func(t *retry.R) { // only account for global tokens - local tokens shouldn't be replicated + // nolint:staticcheck index, remote, err := s1.fsm.State().ACLTokenList(nil, false, true, "", "", "", nil, nil) require.NoError(t, err) // Query for all of them, so that we can prove that no globals snuck in. + // nolint:staticcheck _, local, err := s2.fsm.State().ACLTokenList(nil, true, true, "", "", "", nil, nil) require.NoError(t, err) diff --git a/agent/consul/acl_replication_types.go b/agent/consul/acl_replication_types.go index a395270d6e17..20e4456988ee 100644 --- a/agent/consul/acl_replication_types.go +++ b/agent/consul/acl_replication_types.go @@ -35,6 +35,7 @@ func (r *aclTokenReplicator) FetchRemote(srv *Server, lastRemoteIndex uint64) (i func (r *aclTokenReplicator) FetchLocal(srv *Server) (int, uint64, error) { r.local = nil + // nolint:staticcheck idx, local, err := srv.fsm.State().ACLTokenList(nil, false, true, "", "", "", nil, srv.replicationEnterpriseMeta()) if err != nil { return 0, 0, err diff --git a/agent/consul/acl_server.go b/agent/consul/acl_server.go index 8e14d502a40e..364077c4a586 100644 --- a/agent/consul/acl_server.go +++ b/agent/consul/acl_server.go @@ -87,7 +87,7 @@ func (s *Server) checkBindingRuleUUID(id string) (bool, error) { } func (s *Server) InPrimaryDatacenter() bool { - return s.config.PrimaryDatacenter == "" || s.config.Datacenter == s.config.PrimaryDatacenter + return s.config.InPrimaryDatacenter() } func (s *Server) LocalTokensEnabled() bool { @@ -110,13 +110,12 @@ type serverACLResolverBackend struct { } func (s *serverACLResolverBackend) IsServerManagementToken(token string) bool { - mgmt, err := s.getSystemMetadata(structs.ServerManagementTokenAccessorID) + mgmt, err := s.GetSystemMetadata(structs.ServerManagementTokenAccessorID) if err != nil { s.logger.Debug("failed to fetch server management token: %w", err) return false } if mgmt == "" { - s.logger.Debug("server management token has not been initialized") return false } return subtle.ConstantTimeCompare([]byte(mgmt), []byte(token)) == 1 diff --git a/agent/consul/acl_server_oss.go b/agent/consul/acl_server_ce.go similarity index 100% rename from agent/consul/acl_server_oss.go rename to agent/consul/acl_server_ce.go diff --git a/agent/consul/auth/binder_oss.go b/agent/consul/auth/binder_ce.go similarity index 100% rename from agent/consul/auth/binder_oss.go rename to agent/consul/auth/binder_ce.go diff --git a/agent/consul/auth/mock_ACLCache.go b/agent/consul/auth/mock_ACLCache.go index e8e5c68283b7..2df0b0e382d2 100644 --- a/agent/consul/auth/mock_ACLCache.go +++ b/agent/consul/auth/mock_ACLCache.go @@ -1,12 +1,8 @@ -// Code generated by mockery v2.12.0. DO NOT EDIT. +// Code generated by mockery v2.15.0. DO NOT EDIT. package auth -import ( - testing "testing" - - mock "github.com/stretchr/testify/mock" -) +import mock "github.com/stretchr/testify/mock" // MockACLCache is an autogenerated mock type for the ACLCache type type MockACLCache struct { @@ -18,8 +14,13 @@ func (_m *MockACLCache) RemoveIdentityWithSecretToken(secretToken string) { _m.Called(secretToken) } -// NewMockACLCache creates a new instance of MockACLCache. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockACLCache(t testing.TB) *MockACLCache { +type mockConstructorTestingTNewMockACLCache interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockACLCache creates a new instance of MockACLCache. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockACLCache(t mockConstructorTestingTNewMockACLCache) *MockACLCache { mock := &MockACLCache{} mock.Mock.Test(t) diff --git a/agent/consul/auth/token_writer.go b/agent/consul/auth/token_writer.go index ae59570454a0..c6516f93d0b9 100644 --- a/agent/consul/auth/token_writer.go +++ b/agent/consul/auth/token_writer.go @@ -241,7 +241,7 @@ func (w *TokenWriter) Delete(secretID string, fromLogout bool) error { func validateTokenID(id string) error { if structs.ACLIDReserved(id) { - return fmt.Errorf("UUIDs with the prefix %q are reserved", structs.ACLReservedPrefix) + return fmt.Errorf("UUIDs with the prefix %q are reserved", structs.ACLReservedIDPrefix) } if _, err := uuid.ParseUUID(id); err != nil { return errors.New("not a valid UUID") diff --git a/agent/consul/auth/token_writer_oss.go b/agent/consul/auth/token_writer_ce.go similarity index 100% rename from agent/consul/auth/token_writer_oss.go rename to agent/consul/auth/token_writer_ce.go diff --git a/agent/consul/auth/token_writer_test.go b/agent/consul/auth/token_writer_test.go index b04edef8a90b..ec6e7b6620aa 100644 --- a/agent/consul/auth/token_writer_test.go +++ b/agent/consul/auth/token_writer_test.go @@ -38,7 +38,7 @@ func TestTokenWriter_Create_Validation(t *testing.T) { errorContains: "not a valid UUID", }, "AccessorID is reserved": { - token: structs.ACLToken{AccessorID: structs.ACLReservedPrefix + generateID(t)}, + token: structs.ACLToken{AccessorID: structs.ACLReservedIDPrefix + generateID(t)}, errorContains: "reserved", }, "AccessorID already in use (as AccessorID)": { @@ -54,7 +54,7 @@ func TestTokenWriter_Create_Validation(t *testing.T) { errorContains: "not a valid UUID", }, "SecretID is reserved": { - token: structs.ACLToken{SecretID: structs.ACLReservedPrefix + generateID(t)}, + token: structs.ACLToken{SecretID: structs.ACLReservedIDPrefix + generateID(t)}, errorContains: "reserved", }, "SecretID already in use (as AccessorID)": { diff --git a/agent/consul/authmethod/authmethods_oss.go b/agent/consul/authmethod/authmethods_ce.go similarity index 100% rename from agent/consul/authmethod/authmethods_oss.go rename to agent/consul/authmethod/authmethods_ce.go diff --git a/agent/consul/authmethod/kubeauth/k8s_oss.go b/agent/consul/authmethod/kubeauth/k8s_ce.go similarity index 100% rename from agent/consul/authmethod/kubeauth/k8s_oss.go rename to agent/consul/authmethod/kubeauth/k8s_ce.go diff --git a/agent/consul/authmethod/kubeauth/testing.go b/agent/consul/authmethod/kubeauth/testing.go index 4b15378fd208..87938f406bad 100644 --- a/agent/consul/authmethod/kubeauth/testing.go +++ b/agent/consul/authmethod/kubeauth/testing.go @@ -27,7 +27,6 @@ import ( // // - POST /apis/authentication.k8s.io/v1/tokenreviews // - GET /api/v1/namespaces//serviceaccounts/ -// type TestAPIServer struct { srv *httptest.Server caCert string diff --git a/agent/consul/authmethod/ssoauth/sso_oss.go b/agent/consul/authmethod/ssoauth/sso_ce.go similarity index 100% rename from agent/consul/authmethod/ssoauth/sso_oss.go rename to agent/consul/authmethod/ssoauth/sso_ce.go diff --git a/agent/consul/authmethod/testauth/testing_oss.go b/agent/consul/authmethod/testauth/testing_ce.go similarity index 100% rename from agent/consul/authmethod/testauth/testing_oss.go rename to agent/consul/authmethod/testauth/testing_ce.go diff --git a/agent/consul/auto_config_endpoint.go b/agent/consul/auto_config_endpoint.go index 7eda55b67d68..e33fb19d49e7 100644 --- a/agent/consul/auto_config_endpoint.go +++ b/agent/consul/auto_config_endpoint.go @@ -57,6 +57,7 @@ type jwtAuthorizer struct { // This includes an extra single-quote character not specified in the grammar for safety in case it is later added. // https://github.com/hashicorp/go-bexpr/blob/v0.1.11/grammar/grammar.peg#L188-L191 var invalidSegmentName = regexp.MustCompile("[`'\"\\s]+") +var InvalidNodeName = invalidSegmentName func (a *jwtAuthorizer) Authorize(req *pbautoconf.AutoConfigRequest) (AutoConfigOptions, error) { // perform basic JWT Authorization @@ -70,7 +71,7 @@ func (a *jwtAuthorizer) Authorize(req *pbautoconf.AutoConfigRequest) (AutoConfig // This is not the cleanest way to prevent this behavior. Ideally, the bexpr would allow us to // inject a variable on the RHS for comparison as well, but it would be a complex change to implement // that would likely break backwards-compatibility in certain circumstances. - if dns.InvalidNameRe.MatchString(req.Node) { + if InvalidNodeName.MatchString(req.Node) { return AutoConfigOptions{}, fmt.Errorf("Invalid request field. %v = `%v`", "node", req.Node) } if invalidSegmentName.MatchString(req.Segment) { diff --git a/agent/consul/auto_config_endpoint_test.go b/agent/consul/auto_config_endpoint_test.go index 1036044fabca..2a18b5e480c7 100644 --- a/agent/consul/auto_config_endpoint_test.go +++ b/agent/consul/auto_config_endpoint_test.go @@ -3,13 +3,12 @@ package consul import ( "bytes" "crypto" - crand "crypto/rand" + "crypto/rand" "crypto/x509" "encoding/base64" "encoding/pem" "fmt" "io/ioutil" - "math/rand" "net" "net/url" "path" @@ -884,7 +883,7 @@ func TestAutoConfig_parseAutoConfigCSR(t *testing.T) { // customizations to allow for better unit testing. createCSR := func(tmpl *x509.CertificateRequest, privateKey crypto.Signer) (string, error) { connect.HackSANExtensionForCSR(tmpl) - bs, err := x509.CreateCertificateRequest(crand.Reader, tmpl, privateKey) + bs, err := x509.CreateCertificateRequest(rand.Reader, tmpl, privateKey) require.NoError(t, err) var csrBuf bytes.Buffer err = pem.Encode(&csrBuf, &pem.Block{Type: "CERTIFICATE REQUEST", Bytes: bs}) diff --git a/agent/consul/autopilot_oss.go b/agent/consul/autopilot_ce.go similarity index 100% rename from agent/consul/autopilot_oss.go rename to agent/consul/autopilot_ce.go diff --git a/agent/consul/autopilotevents/mock_Publisher_test.go b/agent/consul/autopilotevents/mock_Publisher_test.go index c0a736be3d2e..aeaf39f5b49d 100644 --- a/agent/consul/autopilotevents/mock_Publisher_test.go +++ b/agent/consul/autopilotevents/mock_Publisher_test.go @@ -1,10 +1,8 @@ -// Code generated by mockery v2.12.2. DO NOT EDIT. +// Code generated by mockery v2.15.0. DO NOT EDIT. package autopilotevents import ( - testing "testing" - stream "github.com/hashicorp/consul/agent/consul/stream" mock "github.com/stretchr/testify/mock" ) @@ -19,8 +17,13 @@ func (_m *MockPublisher) Publish(_a0 []stream.Event) { _m.Called(_a0) } -// NewMockPublisher creates a new instance of MockPublisher. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockPublisher(t testing.TB) *MockPublisher { +type mockConstructorTestingTNewMockPublisher interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockPublisher creates a new instance of MockPublisher. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockPublisher(t mockConstructorTestingTNewMockPublisher) *MockPublisher { mock := &MockPublisher{} mock.Mock.Test(t) diff --git a/agent/consul/autopilotevents/mock_StateStore_test.go b/agent/consul/autopilotevents/mock_StateStore_test.go index dd048e58eb67..9391f21da93a 100644 --- a/agent/consul/autopilotevents/mock_StateStore_test.go +++ b/agent/consul/autopilotevents/mock_StateStore_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.12.2. DO NOT EDIT. +// Code generated by mockery v2.15.0. DO NOT EDIT. package autopilotevents @@ -10,8 +10,6 @@ import ( structs "github.com/hashicorp/consul/agent/structs" - testing "testing" - types "github.com/hashicorp/consul/types" ) @@ -80,8 +78,13 @@ func (_m *MockStateStore) NodeService(ws memdb.WatchSet, nodeName string, servic return r0, r1, r2 } -// NewMockStateStore creates a new instance of MockStateStore. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockStateStore(t testing.TB) *MockStateStore { +type mockConstructorTestingTNewMockStateStore interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockStateStore creates a new instance of MockStateStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockStateStore(t mockConstructorTestingTNewMockStateStore) *MockStateStore { mock := &MockStateStore{} mock.Mock.Test(t) diff --git a/agent/consul/autopilotevents/mock_timeProvider_test.go b/agent/consul/autopilotevents/mock_timeProvider_test.go index 4640fadde057..ccc312df3e18 100644 --- a/agent/consul/autopilotevents/mock_timeProvider_test.go +++ b/agent/consul/autopilotevents/mock_timeProvider_test.go @@ -1,13 +1,11 @@ -// Code generated by mockery v2.12.2. DO NOT EDIT. +// Code generated by mockery v2.15.0. DO NOT EDIT. package autopilotevents import ( - testing "testing" + time "time" mock "github.com/stretchr/testify/mock" - - time "time" ) // mockTimeProvider is an autogenerated mock type for the timeProvider type @@ -29,8 +27,13 @@ func (_m *mockTimeProvider) Now() time.Time { return r0 } -// newMockTimeProvider creates a new instance of mockTimeProvider. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func newMockTimeProvider(t testing.TB) *mockTimeProvider { +type mockConstructorTestingTnewMockTimeProvider interface { + mock.TestingT + Cleanup(func()) +} + +// newMockTimeProvider creates a new instance of mockTimeProvider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func newMockTimeProvider(t mockConstructorTestingTnewMockTimeProvider) *mockTimeProvider { mock := &mockTimeProvider{} mock.Mock.Test(t) diff --git a/agent/consul/catalog_endpoint.go b/agent/consul/catalog_endpoint.go index bf0492a7b988..e2be8d9f45bf 100644 --- a/agent/consul/catalog_endpoint.go +++ b/agent/consul/catalog_endpoint.go @@ -1,6 +1,7 @@ package consul import ( + "errors" "fmt" "sort" "strings" @@ -446,7 +447,7 @@ func vetDeregisterWithACL( } // This order must match the code in applyDeregister() in - // fsm/commands_oss.go since it also evaluates things in this order, + // fsm/commands_ce.go since it also evaluates things in this order, // and will ignore fields based on this precedence. This lets us also // ignore them from an ACL perspective. if subj.ServiceID != "" { @@ -557,6 +558,14 @@ func (c *Catalog) ListServices(args *structs.DCSpecificRequest, reply *structs.I return err } + // Supporting querying by PeerName in this API would require modifying the return type or the ACL + // filtering logic so that it can be made aware that the data queried is coming from a peer. + // Currently the ACL filter will receive plain name strings with no awareness of the peer name, + // which means that authz will be done as if these were local service names. + if args.PeerName != structs.DefaultPeerKeyword { + return errors.New("listing service names imported from a peer is not supported") + } + authz, err := c.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, nil) if err != nil { return err @@ -705,7 +714,9 @@ func (c *Catalog) ServiceNodes(args *structs.ServiceSpecificRequest, reply *stru } } - var authzContext acl.AuthorizerContext + authzContext := acl.AuthorizerContext{ + Peer: args.PeerName, + } authz, err := c.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext) if err != nil { return err @@ -1087,7 +1098,9 @@ func (c *Catalog) VirtualIPForService(args *structs.ServiceSpecificRequest, repl return err } - var authzContext acl.AuthorizerContext + authzContext := acl.AuthorizerContext{ + Peer: args.PeerName, + } authz, err := c.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext) if err != nil { return err diff --git a/agent/consul/client_test.go b/agent/consul/client_test.go index 530fd6b89234..ed7b9fddb9a0 100644 --- a/agent/consul/client_test.go +++ b/agent/consul/client_test.go @@ -174,7 +174,7 @@ func TestClient_LANReap(t *testing.T) { retry.Run(t, func(r *retry.R) { require.Len(r, c1.LANMembersInAgentPartition(), 1) server := c1.router.FindLANServer() - require.Nil(t, server) + require.Nil(r, server) }) } @@ -499,11 +499,15 @@ func newClient(t *testing.T, config *Config) *Client { return client } -func newTestResolverConfig(t *testing.T, suffix string) resolver.Config { +func newTestResolverConfig(t *testing.T, suffix string, dc, agentType string) resolver.Config { n := t.Name() s := strings.Replace(n, "/", "", -1) s = strings.Replace(s, "_", "", -1) - return resolver.Config{Authority: strings.ToLower(s) + "-" + suffix} + return resolver.Config{ + Datacenter: dc, + AgentType: agentType, + Authority: strings.ToLower(s) + "-" + suffix, + } } func newDefaultDeps(t *testing.T, c *Config) Deps { @@ -518,7 +522,7 @@ func newDefaultDeps(t *testing.T, c *Config) Deps { tls, err := tlsutil.NewConfigurator(c.TLSConfig, logger) require.NoError(t, err, "failed to create tls configuration") - builder := resolver.NewServerResolverBuilder(newTestResolverConfig(t, c.NodeName+"-"+c.Datacenter)) + builder := resolver.NewServerResolverBuilder(newTestResolverConfig(t, c.NodeName+"-"+c.Datacenter, c.Datacenter, "server")) r := router.NewRouter(logger, c.Datacenter, fmt.Sprintf("%s.%s", c.NodeName, c.Datacenter), builder) resolver.Register(builder) @@ -532,6 +536,7 @@ func newDefaultDeps(t *testing.T, c *Config) Deps { Datacenter: c.Datacenter, DefaultQueryTime: c.DefaultQueryTime, MaxQueryTime: c.MaxQueryTime, + RPCHoldTimeout: c.RPCHoldTimeout, } connPool.SetRPCClientTimeout(c.RPCClientTimeout) return Deps{ @@ -881,8 +886,9 @@ func TestClient_RPC_Timeout(t *testing.T) { c.Datacenter = "dc1" c.NodeName = uniqueNodeName(t.Name()) c.RPCClientTimeout = 10 * time.Millisecond - c.DefaultQueryTime = 100 * time.Millisecond + c.DefaultQueryTime = 150 * time.Millisecond c.MaxQueryTime = 200 * time.Millisecond + c.RPCHoldTimeout = 50 * time.Millisecond }) joinLAN(t, c1, s1) @@ -897,8 +903,8 @@ func TestClient_RPC_Timeout(t *testing.T) { require.NoError(t, s1.RegisterEndpoint("Short", &waiter{duration: 5 * time.Millisecond})) t.Run("non-blocking query times out after RPCClientTimeout", func(t *testing.T) { - // Requests with QueryOptions have a default timeout of RPCClientTimeout (10ms) - // so we expect the RPC call to timeout. + // Requests with QueryOptions have a default timeout of + // RPCClientTimeout (10ms) so we expect the RPC call to timeout. var out struct{} err := c1.RPC("Long.Wait", &structs.NodeSpecificRequest{}, &out) require.Error(t, err) @@ -931,8 +937,30 @@ func TestClient_RPC_Timeout(t *testing.T) { }, &out)) }) - t.Run("blocking query with short MaxQueryTime fails", func(t *testing.T) { + t.Run("blocking query with MaxQueryTime succeeds", func(t *testing.T) { + var out struct{} + // Although we set MaxQueryTime to 100ms, the client is adding maximum + // jitter (100ms / 16 = 6.25ms) as well as RPCHoldTimeout (50ms). + // Client waits 156.25ms while the server waits 106.25ms (artifically + // adds maximum jitter) so the server will always return first. + require.NoError(t, c1.RPC("Long.Wait", &structs.NodeSpecificRequest{ + QueryOptions: structs.QueryOptions{ + MinQueryIndex: 1, + MaxQueryTime: 100 * time.Millisecond, + }, + }, &out)) + }) + + // This following scenario should not occur in practice since the server + // should be aware of RPC timeouts and always return blocking queries before + // the client closes the connection. But this is just a hypothetical case + // to show waiter can fail since it does not consider QueryOptions. + t.Run("blocking query with low MaxQueryTime fails", func(t *testing.T) { var out struct{} + // Although we set MaxQueryTime to 20ms, the client is adding maximum + // jitter (20ms / 16 = 1.25ms) as well as RPCHoldTimeout (50ms). + // Client waits 71.25ms while the server waits 106.25ms (artifically + // adds maximum jitter) so the client will error first. err := c1.RPC("Long.Wait", &structs.NodeSpecificRequest{ QueryOptions: structs.QueryOptions{ MinQueryIndex: 1, diff --git a/agent/consul/config.go b/agent/consul/config.go index 85cddbb2ad5f..36c654882339 100644 --- a/agent/consul/config.go +++ b/agent/consul/config.go @@ -411,10 +411,18 @@ type Config struct { PeeringTestAllowPeerRegistrations bool + Cloud CloudConfig + + Reporting Reporting + // Embedded Consul Enterprise specific configuration *EnterpriseConfig } +func (c *Config) InPrimaryDatacenter() bool { + return c.PrimaryDatacenter == "" || c.Datacenter == c.PrimaryDatacenter +} + // CheckProtocolVersion validates the protocol version. func (c *Config) CheckProtocolVersion() error { if c.ProtocolVersion < ProtocolVersionMin { @@ -629,8 +637,17 @@ type ReloadableConfig struct { RaftTrailingLogs int HeartbeatTimeout time.Duration ElectionTimeout time.Duration + Reporting Reporting } type RaftBoltDBConfig struct { NoFreelistSync bool } + +type License struct { + Enabled bool +} + +type Reporting struct { + License License +} diff --git a/agent/consul/config_oss.go b/agent/consul/config_ce.go similarity index 100% rename from agent/consul/config_oss.go rename to agent/consul/config_ce.go diff --git a/agent/consul/config_cloud.go b/agent/consul/config_cloud.go new file mode 100644 index 000000000000..b0780052f668 --- /dev/null +++ b/agent/consul/config_cloud.go @@ -0,0 +1,5 @@ +package consul + +type CloudConfig struct { + ManagementToken string +} diff --git a/agent/consul/config_endpoint_test.go b/agent/consul/config_endpoint_test.go index aaf7cba94d0a..f2d2921b70b8 100644 --- a/agent/consul/config_endpoint_test.go +++ b/agent/consul/config_endpoint_test.go @@ -1025,8 +1025,9 @@ func TestConfigEntry_ResolveServiceConfig(t *testing.T) { // Create a dummy proxy/service config in the state store to look up. state := s1.fsm.State() require.NoError(t, state.EnsureConfigEntry(1, &structs.ProxyConfigEntry{ - Kind: structs.ProxyDefaults, - Name: structs.ProxyConfigGlobal, + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + MeshGateway: structs.MeshGatewayConfig{Mode: structs.MeshGatewayModeLocal}, Config: map[string]interface{}{ "foo": 1, }, @@ -1056,9 +1057,25 @@ func TestConfigEntry_ResolveServiceConfig(t *testing.T) { "foo": int64(1), "protocol": "http", }, + MeshGateway: structs.MeshGatewayConfig{ + Mode: structs.MeshGatewayModeLocal, + }, UpstreamConfigs: map[string]map[string]interface{}{ + "*": { + "mesh_gateway": map[string]interface{}{ + "Mode": "local", + }, + }, "bar": { "protocol": "grpc", + "mesh_gateway": map[string]interface{}{ + "Mode": "local", + }, + }, + "baz": { + "mesh_gateway": map[string]interface{}{ + "Mode": "local", + }, }, }, Meta: map[string]string{"foo": "bar"}, @@ -1361,7 +1378,7 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) { Upstream: wildcard, Config: map[string]interface{}{ "mesh_gateway": map[string]interface{}{ - "Mode": "remote", + "Mode": "none", }, }, }, @@ -1402,6 +1419,8 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) { Interval: 10, MaxFailures: 2, EnforcingConsecutive5xx: uintPointer(60), + MaxEjectionPercent: uintPointer(61), + BaseEjectionTime: durationPointer(62 * time.Second), }, }, Overrides: []*structs.UpstreamConfig{ @@ -1436,9 +1455,11 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) { "Interval": int64(10), "MaxFailures": int64(2), "EnforcingConsecutive5xx": int64(60), + "MaxEjectionPercent": int64(61), + "BaseEjectionTime": uint64(62 * time.Second), }, "mesh_gateway": map[string]interface{}{ - "Mode": "remote", + "Mode": "none", }, "protocol": "http", }, @@ -1450,6 +1471,8 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) { "Interval": int64(10), "MaxFailures": int64(2), "EnforcingConsecutive5xx": int64(60), + "MaxEjectionPercent": int64(61), + "BaseEjectionTime": uint64(62 * time.Second), }, "mesh_gateway": map[string]interface{}{ "Mode": "local", @@ -2514,3 +2537,7 @@ func Test_gateWriteToSecondary_AllowedKinds(t *testing.T) { func uintPointer(v uint32) *uint32 { return &v } + +func durationPointer(d time.Duration) *time.Duration { + return &d +} diff --git a/agent/consul/connect_ca_endpoint_test.go b/agent/consul/connect_ca_endpoint_test.go index ee7d34d4dfc3..8e0cd6d3739c 100644 --- a/agent/consul/connect_ca_endpoint_test.go +++ b/agent/consul/connect_ca_endpoint_test.go @@ -9,11 +9,10 @@ import ( "testing" "time" + msgpackrpc "github.com/hashicorp/consul-net-rpc/net-rpc-msgpackrpc" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - msgpackrpc "github.com/hashicorp/consul-net-rpc/net-rpc-msgpackrpc" - "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/connect" ca "github.com/hashicorp/consul/agent/connect/ca" @@ -560,10 +559,23 @@ func TestConnectCAConfig_Vault_TriggerRotation_Fails(t *testing.T) { testVault := ca.NewTestVaultServer(t) - newConfig := func(keyType string, keyBits int) map[string]interface{} { - return map[string]interface{}{ + token1 := ca.CreateVaultTokenWithAttrs(t, testVault.Client(), &ca.VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-primary", + ConsulManaged: true, + WithSudo: true, + }) + + token2 := ca.CreateVaultTokenWithAttrs(t, testVault.Client(), &ca.VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + }) + + newConfig := func(token string, keyType string, keyBits int) map[string]any { + return map[string]any{ "Address": testVault.Addr, - "Token": testVault.RootToken, + "Token": token, "RootPKIPath": "pki-root/", "IntermediatePKIPath": "pki-intermediate/", "PrivateKeyType": keyType, @@ -574,7 +586,7 @@ func TestConnectCAConfig_Vault_TriggerRotation_Fails(t *testing.T) { _, s1 := testServerWithConfig(t, func(c *Config) { c.CAConfig = &structs.CAConfiguration{ Provider: "vault", - Config: newConfig(connect.DefaultPrivateKeyType, connect.DefaultPrivateKeyBits), + Config: newConfig(token1, connect.DefaultPrivateKeyType, connect.DefaultPrivateKeyBits), } }) testrpc.WaitForTestAgent(t, s1.RPC, "dc1") @@ -592,7 +604,7 @@ func TestConnectCAConfig_Vault_TriggerRotation_Fails(t *testing.T) { configFn: func() *structs.CAConfiguration { return &structs.CAConfiguration{ Provider: "vault", - Config: newConfig("rsa", 4096), + Config: newConfig(token2, "rsa", 4096), ForceWithoutCrossSigning: true, } }, @@ -602,7 +614,7 @@ func TestConnectCAConfig_Vault_TriggerRotation_Fails(t *testing.T) { configFn: func() *structs.CAConfiguration { return &structs.CAConfiguration{ Provider: "vault", - Config: newConfig("rsa", 2048), + Config: newConfig(token2, "rsa", 2048), ForceWithoutCrossSigning: true, } }, @@ -613,7 +625,7 @@ func TestConnectCAConfig_Vault_TriggerRotation_Fails(t *testing.T) { configFn: func() *structs.CAConfiguration { return &structs.CAConfiguration{ Provider: "vault", - Config: newConfig("ec", 256), + Config: newConfig(token2, "ec", 256), ForceWithoutCrossSigning: true, } }, @@ -624,7 +636,7 @@ func TestConnectCAConfig_Vault_TriggerRotation_Fails(t *testing.T) { configFn: func() *structs.CAConfiguration { return &structs.CAConfiguration{ Provider: "vault", - Config: newConfig("rsa", 4096), + Config: newConfig(token2, "rsa", 4096), ForceWithoutCrossSigning: true, } }, @@ -632,7 +644,7 @@ func TestConnectCAConfig_Vault_TriggerRotation_Fails(t *testing.T) { } for _, tc := range testSteps { - t.Run(tc.name, func(t *testing.T) { + testutil.RunStep(t, tc.name, func(t *testing.T) { args := &structs.CARequest{ Datacenter: "dc1", Config: tc.configFn(), diff --git a/agent/consul/discoverychain/compile.go b/agent/consul/discoverychain/compile.go index 3a9a1f0ed7a7..313785da3065 100644 --- a/agent/consul/discoverychain/compile.go +++ b/agent/consul/discoverychain/compile.go @@ -704,10 +704,21 @@ func (c *compiler) newTarget(opts structs.DiscoveryTargetOpts) *structs.Discover } else { // Don't allow Peer and Datacenter. opts.Datacenter = "" - // Peer and Partition cannot both be set. - opts.Partition = acl.PartitionOrDefault("") + // Since discovery targets (for peering) are ONLY used to query the catalog, and + // not to generate the SNI it is more correct to switch this to the calling-side + // of the peering's partition as that matches where the replicated data is stored + // in the catalog. This is done to simplify the usage of peer targets in both + // the xds and proxycfg packages. + // + // The peer info data attached to service instances will have the embedded opaque + // SNI/SAN information generated by the remote side and that will have the + // OTHER partition properly specified. + opts.Partition = acl.PartitionOrDefault(c.evaluateInPartition) // Default to "default" rather than c.evaluateInNamespace. - opts.Namespace = acl.PartitionOrDefault(opts.Namespace) + // Note that the namespace is not swapped out, because it should + // always match the value in the remote cluster (and shouldn't + // have been changed anywhere). + opts.Namespace = acl.NamespaceOrDefault(opts.Namespace) } t := structs.NewDiscoveryTarget(opts) @@ -874,8 +885,14 @@ RESOLVE_AGAIN: targetID := target.ServiceID() - if err := c.recordServiceProtocol(targetID); err != nil { - return nil, err + // Only validate protocol if it is not a peered service. + // TODO: Add in remote peer protocol validation when building a chain. + // This likely would require querying the imported services, which + // shouldn't belong in the discovery chain compilation here. + if target.Peer == "" { + if err := c.recordServiceProtocol(targetID); err != nil { + return nil, err + } } // Fetch the config entry. @@ -957,6 +974,7 @@ RESOLVE_AGAIN: Default: resolver.IsDefault(), Target: target.ID, ConnectTimeout: connectTimeout, + RequestTimeout: resolver.RequestTimeout, }, LoadBalancer: resolver.LoadBalancer, } @@ -1007,10 +1025,16 @@ RESOLVE_AGAIN: // Default mesh gateway settings if serviceDefault := c.entries.GetService(targetID); serviceDefault != nil { target.MeshGateway = serviceDefault.MeshGateway + target.TransparentProxy.DialedDirectly = serviceDefault.TransparentProxy.DialedDirectly } proxyDefault := c.entries.GetProxyDefaults(targetID.PartitionOrDefault()) - if proxyDefault != nil && target.MeshGateway.Mode == structs.MeshGatewayModeDefault { - target.MeshGateway.Mode = proxyDefault.MeshGateway.Mode + if proxyDefault != nil { + if target.MeshGateway.Mode == structs.MeshGatewayModeDefault { + target.MeshGateway.Mode = proxyDefault.MeshGateway.Mode + } + if !target.TransparentProxy.DialedDirectly { + target.TransparentProxy.DialedDirectly = proxyDefault.TransparentProxy.DialedDirectly + } } if c.overrideMeshGateway.Mode != structs.MeshGatewayModeDefault { diff --git a/agent/consul/discoverychain/compile_oss.go b/agent/consul/discoverychain/compile_ce.go similarity index 100% rename from agent/consul/discoverychain/compile_oss.go rename to agent/consul/discoverychain/compile_ce.go diff --git a/agent/consul/discoverychain/compile_test.go b/agent/consul/discoverychain/compile_test.go index a4c9c65ed779..6710fb4ebd5d 100644 --- a/agent/consul/discoverychain/compile_test.go +++ b/agent/consul/discoverychain/compile_test.go @@ -40,6 +40,8 @@ func TestCompile(t *testing.T) { "service and subset redirect": testcase_ServiceAndSubsetRedirect(), "datacenter redirect": testcase_DatacenterRedirect(), "redirect to cluster peer": testcase_PeerRedirect(), + "redirect to cluster peer http proxy-defaults": testcase_PeerRedirectProxyDefHTTP(), + "redirect to cluster peer http service-defaults": testcase_PeerRedirectSvcDefHTTP(), "datacenter redirect with mesh gateways": testcase_DatacenterRedirect_WithMeshGateways(), "service failover": testcase_ServiceFailover(), "service failover through redirect": testcase_ServiceFailoverThroughRedirect(), @@ -82,6 +84,11 @@ func TestCompile(t *testing.T) { // circular references "circular resolver redirect": testcase_Resolver_CircularRedirect(), "circular split": testcase_CircularSplit(), + + // tproxy + "tproxy service defaults only": testcase_ServiceDefaultsTProxy(), + "tproxy proxy defaults only": testcase_ProxyDefaultsTProxy(), + "tproxy service defaults override": testcase_ServiceDefaultsOverrideTProxy(), } for name, tc := range cases { @@ -1126,6 +1133,102 @@ func testcase_PeerRedirect() compileTestCase { return compileTestCase{entries: entries, expect: expect} } +func testcase_PeerRedirectProxyDefHTTP() compileTestCase { + entries := newEntries() + entries.AddProxyDefaults(&structs.ProxyConfigEntry{ + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + Config: map[string]interface{}{ + "Protocol": "http", + }, + }) + entries.AddResolvers( + &structs.ServiceResolverConfigEntry{ + Kind: "service-resolver", + Name: "main", + Redirect: &structs.ServiceResolverRedirect{ + Service: "other", + Peer: "cluster-01", + }, + }, + ) + + expect := &structs.CompiledDiscoveryChain{ + Protocol: "http", + StartNode: "resolver:other.default.default.external.cluster-01", + Nodes: map[string]*structs.DiscoveryGraphNode{ + "resolver:other.default.default.external.cluster-01": { + Type: structs.DiscoveryGraphNodeTypeResolver, + Name: "other.default.default.external.cluster-01", + Resolver: &structs.DiscoveryResolver{ + Default: true, + ConnectTimeout: 5 * time.Second, + Target: "other.default.default.external.cluster-01", + }, + }, + }, + Targets: map[string]*structs.DiscoveryTarget{ + "other.default.default.external.cluster-01": newTarget(structs.DiscoveryTargetOpts{ + Service: "other", + Peer: "cluster-01", + }, func(t *structs.DiscoveryTarget) { + t.SNI = "" + t.Name = "" + t.Datacenter = "" + }), + }, + } + return compileTestCase{entries: entries, expect: expect} +} + +func testcase_PeerRedirectSvcDefHTTP() compileTestCase { + entries := newEntries() + entries.AddServices( + &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "main", + Protocol: "http", + }, + ) + entries.AddResolvers( + &structs.ServiceResolverConfigEntry{ + Kind: "service-resolver", + Name: "main", + Redirect: &structs.ServiceResolverRedirect{ + Service: "other", + Peer: "cluster-01", + }, + }, + ) + + expect := &structs.CompiledDiscoveryChain{ + Protocol: "http", + StartNode: "resolver:other.default.default.external.cluster-01", + Nodes: map[string]*structs.DiscoveryGraphNode{ + "resolver:other.default.default.external.cluster-01": { + Type: structs.DiscoveryGraphNodeTypeResolver, + Name: "other.default.default.external.cluster-01", + Resolver: &structs.DiscoveryResolver{ + Default: true, + ConnectTimeout: 5 * time.Second, + Target: "other.default.default.external.cluster-01", + }, + }, + }, + Targets: map[string]*structs.DiscoveryTarget{ + "other.default.default.external.cluster-01": newTarget(structs.DiscoveryTargetOpts{ + Service: "other", + Peer: "cluster-01", + }, func(t *structs.DiscoveryTarget) { + t.SNI = "" + t.Name = "" + t.Datacenter = "" + }), + }, + } + return compileTestCase{entries: entries, expect: expect} +} + func testcase_DatacenterRedirect_WithMeshGateways() compileTestCase { entries := newEntries() entries.AddProxyDefaults(&structs.ProxyConfigEntry{ @@ -2942,6 +3045,119 @@ func testcase_LBResolver() compileTestCase { return compileTestCase{entries: entries, expect: expect} } +func testcase_ServiceDefaultsTProxy() compileTestCase { + entries := newEntries() + entries.AddServices( + &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "main", + TransparentProxy: structs.TransparentProxyConfig{ + DialedDirectly: true, + }, + }, + ) + + expect := &structs.CompiledDiscoveryChain{ + Protocol: "tcp", + Default: true, + StartNode: "resolver:main.default.default.dc1", + Nodes: map[string]*structs.DiscoveryGraphNode{ + "resolver:main.default.default.dc1": { + Type: structs.DiscoveryGraphNodeTypeResolver, + Name: "main.default.default.dc1", + Resolver: &structs.DiscoveryResolver{ + Default: true, + ConnectTimeout: 5 * time.Second, + Target: "main.default.default.dc1", + }, + }, + }, + Targets: map[string]*structs.DiscoveryTarget{ + "main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, func(t *structs.DiscoveryTarget) { + t.TransparentProxy.DialedDirectly = true + }), + }, + } + return compileTestCase{entries: entries, expect: expect} +} + +func testcase_ProxyDefaultsTProxy() compileTestCase { + entries := newEntries() + entries.AddProxyDefaults(&structs.ProxyConfigEntry{ + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + TransparentProxy: structs.TransparentProxyConfig{ + DialedDirectly: true, + }, + }) + + expect := &structs.CompiledDiscoveryChain{ + Protocol: "tcp", + Default: true, + StartNode: "resolver:main.default.default.dc1", + Nodes: map[string]*structs.DiscoveryGraphNode{ + "resolver:main.default.default.dc1": { + Type: structs.DiscoveryGraphNodeTypeResolver, + Name: "main.default.default.dc1", + Resolver: &structs.DiscoveryResolver{ + Default: true, + ConnectTimeout: 5 * time.Second, + Target: "main.default.default.dc1", + }, + }, + }, + Targets: map[string]*structs.DiscoveryTarget{ + "main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, func(t *structs.DiscoveryTarget) { + t.TransparentProxy.DialedDirectly = true + }), + }, + } + return compileTestCase{entries: entries, expect: expect} +} + +func testcase_ServiceDefaultsOverrideTProxy() compileTestCase { + entries := newEntries() + entries.AddProxyDefaults(&structs.ProxyConfigEntry{ + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + TransparentProxy: structs.TransparentProxyConfig{ + DialedDirectly: false, + }, + }) + entries.AddServices( + &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "main", + TransparentProxy: structs.TransparentProxyConfig{ + DialedDirectly: true, + }, + }, + ) + + expect := &structs.CompiledDiscoveryChain{ + Protocol: "tcp", + Default: true, + StartNode: "resolver:main.default.default.dc1", + Nodes: map[string]*structs.DiscoveryGraphNode{ + "resolver:main.default.default.dc1": { + Type: structs.DiscoveryGraphNodeTypeResolver, + Name: "main.default.default.dc1", + Resolver: &structs.DiscoveryResolver{ + Default: true, + ConnectTimeout: 5 * time.Second, + Target: "main.default.default.dc1", + }, + }, + }, + Targets: map[string]*structs.DiscoveryTarget{ + "main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, func(t *structs.DiscoveryTarget) { + t.TransparentProxy.DialedDirectly = true + }), + }, + } + return compileTestCase{entries: entries, expect: expect} +} + func newSimpleRoute(name string, muts ...func(*structs.ServiceRoute)) structs.ServiceRoute { r := structs.ServiceRoute{ Match: &structs.ServiceRouteMatch{ diff --git a/agent/consul/enterprise_client_oss.go b/agent/consul/enterprise_client_ce.go similarity index 100% rename from agent/consul/enterprise_client_oss.go rename to agent/consul/enterprise_client_ce.go diff --git a/agent/consul/enterprise_config_oss.go b/agent/consul/enterprise_config_ce.go similarity index 100% rename from agent/consul/enterprise_config_oss.go rename to agent/consul/enterprise_config_ce.go diff --git a/agent/consul/enterprise_server_oss.go b/agent/consul/enterprise_server_ce.go similarity index 98% rename from agent/consul/enterprise_server_oss.go rename to agent/consul/enterprise_server_ce.go index d6e07ddd8ce5..b0a8129ad5f3 100644 --- a/agent/consul/enterprise_server_oss.go +++ b/agent/consul/enterprise_server_ce.go @@ -74,7 +74,7 @@ func (s *Server) validateEnterpriseIntentionPartition(partition string) error { return nil } - // No special handling for wildcard partitions as they are pointless in OSS. + // No special handling for wildcard partitions as they are pointless in CE. return errors.New("Partitions is a Consul Enterprise feature") } @@ -86,7 +86,7 @@ func (s *Server) validateEnterpriseIntentionNamespace(ns string, _ bool) error { return nil } - // No special handling for wildcard namespaces as they are pointless in OSS. + // No special handling for wildcard namespaces as they are pointless in CE. return errors.New("Namespaces is a Consul Enterprise feature") } diff --git a/agent/consul/enterprise_server_oss_test.go b/agent/consul/enterprise_server_ce_test.go similarity index 100% rename from agent/consul/enterprise_server_oss_test.go rename to agent/consul/enterprise_server_ce_test.go diff --git a/agent/consul/filter.go b/agent/consul/filter.go index 92126a0d86b7..217af4400767 100644 --- a/agent/consul/filter.go +++ b/agent/consul/filter.go @@ -46,14 +46,17 @@ func (t *txnResultsFilter) Filter(i int) bool { case result.KV != nil: result.KV.EnterpriseMeta.FillAuthzContext(&authzContext) return t.authorizer.KeyRead(result.KV.Key, &authzContext) != acl.Allow + case result.Node != nil: (*structs.Node)(result.Node).FillAuthzContext(&authzContext) return t.authorizer.NodeRead(result.Node.Node, &authzContext) != acl.Allow + case result.Service != nil: - result.Service.EnterpriseMeta.FillAuthzContext(&authzContext) + (*structs.NodeService)(result.Service).FillAuthzContext(&authzContext) return t.authorizer.ServiceRead(result.Service.Service, &authzContext) != acl.Allow + case result.Check != nil: - result.Check.EnterpriseMeta.FillAuthzContext(&authzContext) + (*structs.HealthCheck)(result.Check).FillAuthzContext(&authzContext) if result.Check.ServiceName != "" { return t.authorizer.ServiceRead(result.Check.ServiceName, &authzContext) != acl.Allow } diff --git a/agent/consul/fsm/commands_oss.go b/agent/consul/fsm/commands_ce.go similarity index 100% rename from agent/consul/fsm/commands_oss.go rename to agent/consul/fsm/commands_ce.go diff --git a/agent/consul/fsm/commands_oss_test.go b/agent/consul/fsm/commands_ce_test.go similarity index 100% rename from agent/consul/fsm/commands_oss_test.go rename to agent/consul/fsm/commands_ce_test.go diff --git a/agent/consul/fsm/fsm.go b/agent/consul/fsm/fsm.go index 432e64631767..641aee42e5ce 100644 --- a/agent/consul/fsm/fsm.go +++ b/agent/consul/fsm/fsm.go @@ -197,7 +197,11 @@ func (c *FSM) Restore(old io.ReadCloser) error { return err } default: - return fmt.Errorf("Unrecognized msg type %d", msg) + if msg >= 64 { + return fmt.Errorf("msg type <%d> is a Consul Enterprise log entry. Consul CE cannot restore it", msg) + } else { + return fmt.Errorf("Unrecognized msg type %d", msg) + } } return nil } @@ -331,4 +335,11 @@ func (c *FSM) registerStreamSnapshotHandlers() { if err != nil { panic(fmt.Errorf("fatal error encountered registering streaming snapshot handlers: %w", err)) } + + err = c.deps.Publisher.RegisterHandler(state.EventTopicServiceDefaults, func(req stream.SubscribeRequest, buf stream.SnapshotAppender) (uint64, error) { + return c.State().ServiceDefaultsSnapshot(req, buf) + }, true) + if err != nil { + panic(fmt.Errorf("fatal error encountered registering streaming snapshot handlers: %w", err)) + } } diff --git a/agent/consul/fsm/snapshot_oss.go b/agent/consul/fsm/snapshot_ce.go similarity index 99% rename from agent/consul/fsm/snapshot_oss.go rename to agent/consul/fsm/snapshot_ce.go index 7fa53381a7dc..9899440da39e 100644 --- a/agent/consul/fsm/snapshot_oss.go +++ b/agent/consul/fsm/snapshot_ce.go @@ -14,7 +14,7 @@ import ( ) func init() { - registerPersister(persistOSS) + registerPersister(persistCE) registerRestorer(structs.RegisterRequestType, restoreRegistration) registerRestorer(structs.KVSRequestType, restoreKV) @@ -45,7 +45,7 @@ func init() { registerRestorer(structs.PeeringSecretsWriteType, restorePeeringSecrets) } -func persistOSS(s *snapshot, sink raft.SnapshotSink, encoder *codec.Encoder) error { +func persistCE(s *snapshot, sink raft.SnapshotSink, encoder *codec.Encoder) error { if err := s.persistVirtualIPs(sink, encoder); err != nil { return err } diff --git a/agent/consul/fsm/snapshot_ce_test.go b/agent/consul/fsm/snapshot_ce_test.go new file mode 100644 index 000000000000..13c5b1dcc402 --- /dev/null +++ b/agent/consul/fsm/snapshot_ce_test.go @@ -0,0 +1,48 @@ +//go:build !consulent +// +build !consulent + +package fsm + +import ( + "bytes" + "testing" + + "github.com/hashicorp/consul-net-rpc/go-msgpack/codec" + "github.com/stretchr/testify/require" + + "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/sdk/testutil" +) + +func TestRestoreFromEnterprise(t *testing.T) { + + logger := testutil.Logger(t) + fsm, err := New(nil, logger) + require.NoError(t, err) + // To verify if a proper message is displayed when Consul CE tries to + // unsuccessfully restore entries from a Consul Ent snapshot. + buf := bytes.NewBuffer(nil) + sink := &MockSink{buf, false} + + type EntMock struct { + ID int + Type string + } + + entMockEntry := EntMock{ + ID: 65, + Type: "A Consul Ent Log Type", + } + + // Write the header + header := SnapshotHeader{ + LastIndex: 0, + } + encoder := codec.NewEncoder(sink, structs.MsgpackHandle) + encoder.Encode(&header) + sink.Write([]byte{byte(structs.MessageType(entMockEntry.ID))}) + encoder.Encode(entMockEntry) + + require.EqualError(t, fsm.Restore(sink), "msg type <65> is a Consul Enterprise log entry. Consul CE cannot restore it") + sink.Cancel() +} diff --git a/agent/consul/fsm/snapshot_oss_test.go b/agent/consul/fsm/snapshot_test.go similarity index 98% rename from agent/consul/fsm/snapshot_oss_test.go rename to agent/consul/fsm/snapshot_test.go index 2b2d3e87015c..05f65db66f46 100644 --- a/agent/consul/fsm/snapshot_oss_test.go +++ b/agent/consul/fsm/snapshot_test.go @@ -23,7 +23,7 @@ import ( "github.com/hashicorp/consul/sdk/testutil" ) -func TestFSM_SnapshotRestore_OSS(t *testing.T) { +func TestFSM_SnapshotRestore_CE(t *testing.T) { t.Parallel() logger := testutil.Logger(t) @@ -85,8 +85,8 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) { policy := &structs.ACLPolicy{ ID: structs.ACLPolicyGlobalManagementID, Name: "global-management", - Description: "Builtin Policy that grants unlimited access", - Rules: structs.ACLPolicyGlobalManagement, + Description: structs.ACLPolicyGlobalManagementDesc, + Rules: structs.ACLPolicyGlobalManagementRules, Syntax: acl.SyntaxCurrent, } policy.SetHash(true) @@ -482,7 +482,7 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) { require.NoError(t, fsm.state.PeeringWrite(31, &pbpeering.PeeringWriteRequest{ Peering: &pbpeering.Peering{ ID: "1fabcd52-1d46-49b0-b1d8-71559aee47f5", - Name: "baz", + Name: "qux", }, SecretsRequest: &pbpeering.SecretsWriteRequest{ PeerID: "1fabcd52-1d46-49b0-b1d8-71559aee47f5", @@ -821,12 +821,12 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) { // Verify peering is restored idx, prngRestored, err := fsm2.state.PeeringRead(nil, state.Query{ - Value: "baz", + Value: "qux", }) require.NoError(t, err) - require.Equal(t, uint64(31), idx) + require.Equal(t, uint64(32), idx) // This is the index of the PTB write, which updates the peering require.NotNil(t, prngRestored) - require.Equal(t, "baz", prngRestored.Name) + require.Equal(t, "qux", prngRestored.Name) // Verify peering secrets are restored secretsRestored, err := fsm2.state.PeeringSecretsRead(nil, "1fabcd52-1d46-49b0-b1d8-71559aee47f5") @@ -901,7 +901,7 @@ func convertACLTokenToLegacy(tok *structs.ACLToken) (*LegacyACL, error) { return compat, nil } -func TestFSM_BadRestore_OSS(t *testing.T) { +func TestFSM_BadRestore_CE(t *testing.T) { t.Parallel() // Create an FSM with some state. logger := testutil.Logger(t) diff --git a/agent/consul/gateway_locator.go b/agent/consul/gateway_locator.go index ab72fdce3d78..756592bce716 100644 --- a/agent/consul/gateway_locator.go +++ b/agent/consul/gateway_locator.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/go-hclog" memdb "github.com/hashicorp/go-memdb" + "github.com/hashicorp/consul/agent/blockingquery" "github.com/hashicorp/consul/agent/consul/state" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/api" @@ -270,7 +271,7 @@ func getRandomItem(items []string) string { } type serverDelegate interface { - blockingQuery(queryOpts blockingQueryOptions, queryMeta blockingQueryResponseMeta, fn queryFn) error + blockingQuery(requestOpts blockingquery.RequestOptions, responseMeta blockingquery.ResponseMeta, query blockingquery.QueryFn) error IsLeader() bool LeaderLastContact() time.Time setDatacenterSupportsFederationStates() diff --git a/agent/consul/gateway_locator_test.go b/agent/consul/gateway_locator_test.go index 8f32acb86afa..622445e2261f 100644 --- a/agent/consul/gateway_locator_test.go +++ b/agent/consul/gateway_locator_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/hashicorp/consul/agent/blockingquery" "github.com/hashicorp/consul/agent/consul/state" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/api" @@ -472,6 +473,8 @@ func TestGatewayLocator(t *testing.T) { }) } +var _ serverDelegate = (*testServerDelegate)(nil) + type testServerDelegate struct { dcSupportsFederationStates int32 // atomically accessed, at start to prevent alignment issues @@ -493,9 +496,9 @@ func (d *testServerDelegate) datacenterSupportsFederationStates() bool { // This is just enough to exercise the logic. func (d *testServerDelegate) blockingQuery( - queryOpts blockingQueryOptions, - queryMeta blockingQueryResponseMeta, - fn queryFn, + queryOpts blockingquery.RequestOptions, + queryMeta blockingquery.ResponseMeta, + fn blockingquery.QueryFn, ) error { minQueryIndex := queryOpts.GetMinQueryIndex() diff --git a/agent/consul/health_endpoint.go b/agent/consul/health_endpoint.go index 28823d95858d..9e97a1d62ce3 100644 --- a/agent/consul/health_endpoint.go +++ b/agent/consul/health_endpoint.go @@ -211,7 +211,9 @@ func (h *Health) ServiceNodes(args *structs.ServiceSpecificRequest, reply *struc f = h.serviceNodesDefault } - var authzContext acl.AuthorizerContext + authzContext := acl.AuthorizerContext{ + Peer: args.PeerName, + } authz, err := h.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext) if err != nil { return err @@ -221,16 +223,6 @@ func (h *Health) ServiceNodes(args *structs.ServiceSpecificRequest, reply *struc return err } - // If we're doing a connect or ingress query, we need read access to the service - // we're trying to find proxies for, so check that. - if args.Connect || args.Ingress { - // TODO(acl-error-enhancements) Look for ways to percolate this information up to give any feedback to the user. - if authz.ServiceRead(args.ServiceName, &authzContext) != acl.Allow { - // Just return nil, which will return an empty response (tested) - return nil - } - } - filter, err := bexpr.CreateFilter(args.Filter, nil, reply.Nodes) if err != nil { return err @@ -252,6 +244,17 @@ func (h *Health) ServiceNodes(args *structs.ServiceSpecificRequest, reply *struc return err } + // If we're doing a connect or ingress query, we need read access to the service + // we're trying to find proxies for, so check that. + if args.Connect || args.Ingress { + // TODO(acl-error-enhancements) Look for ways to percolate this information up to give any feedback to the user. + if authz.ServiceRead(args.ServiceName, &authzContext) != acl.Allow { + // Return the index here so that the agent cache does not infinitely loop. + reply.Index = index + return nil + } + } + resolvedNodes := nodes if args.MergeCentralConfig { for _, node := range resolvedNodes { diff --git a/agent/consul/health_endpoint_test.go b/agent/consul/health_endpoint_test.go index 77fd64f4e61b..e31263a98718 100644 --- a/agent/consul/health_endpoint_test.go +++ b/agent/consul/health_endpoint_test.go @@ -1124,6 +1124,7 @@ node "foo" { var resp structs.IndexedCheckServiceNodes assert.Nil(t, msgpackrpc.CallWithCodec(codec, "Health.ServiceNodes", &req, &resp)) assert.Len(t, resp.Nodes, 0) + assert.Greater(t, resp.Index, uint64(0)) // List w/ token. This should work since we're requesting "foo", but should // also only contain the proxies with names that adhere to our ACL. @@ -1764,5 +1765,11 @@ func TestHealth_RPC_Filter(t *testing.T) { out = new(structs.IndexedHealthChecks) require.NoError(t, msgpackrpc.CallWithCodec(codec, "Health.ChecksInState", &args, out)) require.Len(t, out.HealthChecks, 1) + + args.State = api.HealthAny + args.Filter = "connect in ServiceTags and v2 in ServiceTags" + out = new(structs.IndexedHealthChecks) + require.NoError(t, msgpackrpc.CallWithCodec(codec, "Health.ChecksInState", &args, out)) + require.Len(t, out.HealthChecks, 1) }) } diff --git a/agent/consul/helper_test.go b/agent/consul/helper_test.go index 0f89856d74aa..d21bb5d64b7e 100644 --- a/agent/consul/helper_test.go +++ b/agent/consul/helper_test.go @@ -127,7 +127,7 @@ type clientOrServer interface { // joinLAN is a convenience function for // -// member.JoinLAN("127.0.0.1:"+leader.config.SerfLANConfig.MemberlistConfig.BindPort) +// member.JoinLAN("127.0.0.1:"+leader.config.SerfLANConfig.MemberlistConfig.BindPort) func joinLAN(t *testing.T, member clientOrServer, leader *Server) { t.Helper() joinLANWithOptions(t, member, leader, true) @@ -184,7 +184,7 @@ func joinLANWithOptions(t *testing.T, member clientOrServer, leader *Server, doM // joinWAN is a convenience function for // -// member.JoinWAN("127.0.0.1:"+leader.config.SerfWANConfig.MemberlistConfig.BindPort) +// member.JoinWAN("127.0.0.1:"+leader.config.SerfWANConfig.MemberlistConfig.BindPort) func joinWAN(t *testing.T, member, leader *Server) { t.Helper() joinWANWithOptions(t, member, leader, true) diff --git a/agent/consul/internal_endpoint.go b/agent/consul/internal_endpoint.go index 85a36dff0162..cec2f5cbcecf 100644 --- a/agent/consul/internal_endpoint.go +++ b/agent/consul/internal_endpoint.go @@ -619,8 +619,7 @@ func (m *Internal) ExportedPeeredServices(args *structs.DCSpecificRequest, reply return err } - var authzCtx acl.AuthorizerContext - authz, err := m.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzCtx) + authz, err := m.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, nil) if err != nil { return err } @@ -761,7 +760,7 @@ func (m *Internal) EventFire(args *structs.EventFireRequest, } // Set the query meta data - m.srv.setQueryMeta(&reply.QueryMeta, args.Token) + m.srv.SetQueryMeta(&reply.QueryMeta, args.Token) // Add the consul prefix to the event name eventName := userEventName(args.Name) diff --git a/agent/consul/internal_endpoint_test.go b/agent/consul/internal_endpoint_test.go index e0aa941b90e5..181de4ed82c2 100644 --- a/agent/consul/internal_endpoint_test.go +++ b/agent/consul/internal_endpoint_test.go @@ -1,9 +1,9 @@ package consul import ( + "crypto/rand" "encoding/base64" "fmt" - "math/rand" "os" "strings" "testing" diff --git a/agent/consul/leader.go b/agent/consul/leader.go index 94aeeb3bb4e6..8c86c6ef6417 100644 --- a/agent/consul/leader.go +++ b/agent/consul/leader.go @@ -334,6 +334,10 @@ func (s *Server) establishLeadership(ctx context.Context) error { s.setConsistentReadReady() + if s.config.Reporting.License.Enabled && s.reportingManager != nil { + s.reportingManager.StartReportingAgent() + } + s.logger.Debug("successfully established leadership", "duration", time.Since(start)) return nil } @@ -350,6 +354,8 @@ func (s *Server) revokeLeadership() { s.revokeEnterpriseLeadership() + s.stopDeferredDeletion() + s.stopFederationStateAntiEntropy() s.stopFederationStateReplication() @@ -369,6 +375,8 @@ func (s *Server) revokeLeadership() { s.resetConsistentReadReady() s.autopilot.DisableReconciliation() + + s.reportingManager.StopReportingAgent() } // initializeACLs is used to setup the ACLs if we are the leader @@ -404,100 +412,26 @@ func (s *Server) initializeACLs(ctx context.Context) error { if s.InPrimaryDatacenter() { s.logger.Info("initializing acls") - // Create/Upgrade the builtin global-management policy - _, policy, err := s.fsm.State().ACLPolicyGetByID(nil, structs.ACLPolicyGlobalManagementID, structs.DefaultEnterpriseMetaInDefaultPartition()) - if err != nil { - return fmt.Errorf("failed to get the builtin global-management policy") - } - if policy == nil || policy.Rules != structs.ACLPolicyGlobalManagement { - newPolicy := structs.ACLPolicy{ - ID: structs.ACLPolicyGlobalManagementID, - Name: "global-management", - Description: "Builtin Policy that grants unlimited access", - Rules: structs.ACLPolicyGlobalManagement, - Syntax: acl.SyntaxCurrent, - EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(), - } - if policy != nil { - newPolicy.Name = policy.Name - newPolicy.Description = policy.Description - } - - newPolicy.SetHash(true) - - req := structs.ACLPolicyBatchSetRequest{ - Policies: structs.ACLPolicies{&newPolicy}, - } - _, err := s.raftApply(structs.ACLPolicySetRequestType, &req) - if err != nil { - return fmt.Errorf("failed to create global-management policy: %v", err) + // Create/Upgrade the builtin policies + for _, policy := range structs.ACLBuiltinPolicies { + if err := s.writeBuiltinACLPolicy(policy); err != nil { + return err } - s.logger.Info("Created ACL 'global-management' policy") } // Check for configured initial management token. if initialManagement := s.config.ACLInitialManagementToken; len(initialManagement) > 0 { - state := s.fsm.State() - if _, err := uuid.ParseUUID(initialManagement); err != nil { - s.logger.Warn("Configuring a non-UUID initial management token is deprecated") - } - - _, token, err := state.ACLTokenGetBySecret(nil, initialManagement, nil) + err := s.initializeManagementToken("Initial Management Token", initialManagement) if err != nil { - return fmt.Errorf("failed to get initial management token: %v", err) + return fmt.Errorf("failed to initialize initial management token: %w", err) } - // Ignoring expiration times to avoid an insertion collision. - if token == nil { - accessor, err := lib.GenerateUUID(s.checkTokenUUID) - if err != nil { - return fmt.Errorf("failed to generate the accessor ID for the initial management token: %v", err) - } - - token := structs.ACLToken{ - AccessorID: accessor, - SecretID: initialManagement, - Description: "Initial Management Token", - Policies: []structs.ACLTokenPolicyLink{ - { - ID: structs.ACLPolicyGlobalManagementID, - }, - }, - CreateTime: time.Now(), - Local: false, - EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(), - } - - token.SetHash(true) - - done := false - if canBootstrap, _, err := state.CanBootstrapACLToken(); err == nil && canBootstrap { - req := structs.ACLTokenBootstrapRequest{ - Token: token, - ResetIndex: 0, - } - if _, err := s.raftApply(structs.ACLBootstrapRequestType, &req); err == nil { - s.logger.Info("Bootstrapped ACL initial management token from configuration") - done = true - } else { - if err.Error() != structs.ACLBootstrapNotAllowedErr.Error() && - err.Error() != structs.ACLBootstrapInvalidResetIndexErr.Error() { - return fmt.Errorf("failed to bootstrap initial management token: %v", err) - } - } - } - - if !done { - // either we didn't attempt to or setting the token with a bootstrap request failed. - req := structs.ACLTokenBatchSetRequest{ - Tokens: structs.ACLTokens{&token}, - CAS: false, - } - if _, err := s.raftApply(structs.ACLTokenSetRequestType, &req); err != nil { - return fmt.Errorf("failed to create initial management token: %v", err) - } + } - s.logger.Info("Created ACL initial management token from configuration") - } + // Check for configured management token from HCP. It MUST NOT override the user-provided initial management token. + if hcpManagement := s.config.Cloud.ManagementToken; len(hcpManagement) > 0 { + err := s.initializeManagementToken("HCP Management Token", hcpManagement) + if err != nil { + return fmt.Errorf("failed to initialize HCP management token: %w", err) } } @@ -529,30 +463,127 @@ func (s *Server) initializeACLs(ctx context.Context) error { s.logger.Info("Created ACL anonymous token from configuration") } - // Generate or rotate the server management token on leadership transitions. - // This token is used by Consul servers for authn/authz when making - // requests to themselves through public APIs such as the agent cache. - // It is stored as system metadata because it is internally - // managed and users are not meant to see it or interact with it. - secretID, err := lib.GenerateUUID(nil) - if err != nil { - return fmt.Errorf("failed to generate the secret ID for the server management token: %w", err) - } - if err := s.setSystemMetadataKey(structs.ServerManagementTokenAccessorID, secretID); err != nil { - return fmt.Errorf("failed to persist server management token: %w", err) - } - // launch the upgrade go routine to generate accessors for everything s.startACLUpgrade(ctx) } else { s.startACLReplication(ctx) } + // Generate or rotate the server management token on leadership transitions. + // This token is used by Consul servers for authn/authz when making + // requests to themselves through public APIs such as the agent cache. + // It is stored as system metadata because it is internally + // managed and users are not meant to see it or interact with it. + secretID, err := lib.GenerateUUID(nil) + if err != nil { + return fmt.Errorf("failed to generate the secret ID for the server management token: %w", err) + } + if err := s.SetSystemMetadataKey(structs.ServerManagementTokenAccessorID, secretID); err != nil { + return fmt.Errorf("failed to persist server management token: %w", err) + } + s.startACLTokenReaping(ctx) return nil } +// writeBuiltinACLPolicy writes the given built-in policy to Raft if the policy +// is not found or if the policy rules have been changed. The name and +// description of a built-in policy are user-editable and must be preserved +// during updates. This function must only be called in a primary datacenter. +func (s *Server) writeBuiltinACLPolicy(newPolicy structs.ACLPolicy) error { + _, policy, err := s.fsm.State().ACLPolicyGetByID(nil, newPolicy.ID, structs.DefaultEnterpriseMetaInDefaultPartition()) + if err != nil { + return fmt.Errorf("failed to get the builtin %s policy", newPolicy.Name) + } + if policy == nil || policy.Rules != newPolicy.Rules { + if policy != nil { + newPolicy.Name = policy.Name + newPolicy.Description = policy.Description + } + + newPolicy.EnterpriseMeta = *structs.DefaultEnterpriseMetaInDefaultPartition() + newPolicy.SetHash(true) + + req := structs.ACLPolicyBatchSetRequest{ + Policies: structs.ACLPolicies{&newPolicy}, + } + _, err := s.raftApply(structs.ACLPolicySetRequestType, &req) + if err != nil { + return fmt.Errorf("failed to create %s policy: %v", newPolicy.Name, err) + } + s.logger.Info(fmt.Sprintf("Created ACL '%s' policy", newPolicy.Name)) + } + return nil +} + +func (s *Server) initializeManagementToken(name, secretID string) error { + state := s.fsm.State() + if _, err := uuid.ParseUUID(secretID); err != nil { + s.logger.Warn("Configuring a non-UUID management token is deprecated") + } + + _, token, err := state.ACLTokenGetBySecret(nil, secretID, nil) + if err != nil { + return fmt.Errorf("failed to get %s: %v", name, err) + } + // Ignoring expiration times to avoid an insertion collision. + if token == nil { + accessor, err := lib.GenerateUUID(s.checkTokenUUID) + if err != nil { + return fmt.Errorf("failed to generate the accessor ID for %s: %v", name, err) + } + + token := structs.ACLToken{ + AccessorID: accessor, + SecretID: secretID, + Description: name, + Policies: []structs.ACLTokenPolicyLink{ + { + ID: structs.ACLPolicyGlobalManagementID, + }, + }, + CreateTime: time.Now(), + Local: false, + EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(), + } + + token.SetHash(true) + + done := false + if canBootstrap, _, err := state.CanBootstrapACLToken(); err == nil && canBootstrap { + req := structs.ACLTokenBootstrapRequest{ + Token: token, + ResetIndex: 0, + } + if _, err := s.raftApply(structs.ACLBootstrapRequestType, &req); err == nil { + s.logger.Info("Bootstrapped ACL token from configuration", "description", name) + done = true + } else { + if err.Error() != structs.ACLBootstrapNotAllowedErr.Error() && + err.Error() != structs.ACLBootstrapInvalidResetIndexErr.Error() { + return fmt.Errorf("failed to bootstrap with %s: %v", name, err) + } + } + } + + if !done { + // either we didn't attempt to or setting the token with a bootstrap request failed. + req := structs.ACLTokenBatchSetRequest{ + Tokens: structs.ACLTokens{&token}, + CAS: false, + } + if _, err := s.raftApply(structs.ACLTokenSetRequestType, &req); err != nil { + return fmt.Errorf("failed to create %s: %v", name, err) + } + + s.logger.Info("Created ACL token from configuration", "description", name) + } + } + + return nil +} + // legacyACLTokenUpgrade runs a single time to upgrade any tokens that may // have been created immediately before the Consul upgrade, or any legacy tokens // from a restored snapshot. diff --git a/agent/consul/leader_oss_test.go b/agent/consul/leader_ce_test.go similarity index 100% rename from agent/consul/leader_oss_test.go rename to agent/consul/leader_ce_test.go diff --git a/agent/consul/leader_connect.go b/agent/consul/leader_connect.go index 79162603ac7c..0f74e27767e9 100644 --- a/agent/consul/leader_connect.go +++ b/agent/consul/leader_connect.go @@ -172,7 +172,7 @@ func (s *Server) setVirtualIPFlags() (bool, error) { } func (s *Server) setVirtualIPVersionFlag() (bool, error) { - val, err := s.getSystemMetadata(structs.SystemMetadataVirtualIPsEnabled) + val, err := s.GetSystemMetadata(structs.SystemMetadataVirtualIPsEnabled) if err != nil { return false, err } @@ -185,7 +185,7 @@ func (s *Server) setVirtualIPVersionFlag() (bool, error) { minVirtualIPVersion.String()) } - if err := s.setSystemMetadataKey(structs.SystemMetadataVirtualIPsEnabled, "true"); err != nil { + if err := s.SetSystemMetadataKey(structs.SystemMetadataVirtualIPsEnabled, "true"); err != nil { return false, nil } @@ -193,7 +193,7 @@ func (s *Server) setVirtualIPVersionFlag() (bool, error) { } func (s *Server) setVirtualIPTerminatingGatewayVersionFlag() (bool, error) { - val, err := s.getSystemMetadata(structs.SystemMetadataTermGatewayVirtualIPsEnabled) + val, err := s.GetSystemMetadata(structs.SystemMetadataTermGatewayVirtualIPsEnabled) if err != nil { return false, err } @@ -206,7 +206,7 @@ func (s *Server) setVirtualIPTerminatingGatewayVersionFlag() (bool, error) { minVirtualIPTerminatingGatewayVersion.String()) } - if err := s.setSystemMetadataKey(structs.SystemMetadataTermGatewayVirtualIPsEnabled, "true"); err != nil { + if err := s.SetSystemMetadataKey(structs.SystemMetadataTermGatewayVirtualIPsEnabled, "true"); err != nil { return false, nil } diff --git a/agent/consul/leader_connect_ca.go b/agent/consul/leader_connect_ca.go index 8d2bf9cb863b..39defb752b0a 100644 --- a/agent/consul/leader_connect_ca.go +++ b/agent/consul/leader_connect_ca.go @@ -12,18 +12,17 @@ import ( "time" "github.com/hashicorp/go-hclog" - uuid "github.com/hashicorp/go-uuid" + "github.com/hashicorp/go-uuid" "golang.org/x/time/rate" "github.com/hashicorp/consul/acl" - "github.com/hashicorp/consul/lib/semaphore" - "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/connect/ca" "github.com/hashicorp/consul/agent/consul/state" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/lib/routine" + "github.com/hashicorp/consul/lib/semaphore" ) type caState string @@ -273,7 +272,7 @@ func newCARoot(pemValue, provider, clusterID string) (*structs.CARoot, error) { ExternalTrustDomain: clusterID, NotBefore: primaryCert.NotBefore, NotAfter: primaryCert.NotAfter, - RootCert: pemValue, + RootCert: lib.EnsureTrailingNewline(pemValue), PrivateKeyType: keyType, PrivateKeyBits: keyBits, Active: true, @@ -755,7 +754,9 @@ func shouldPersistNewRootAndConfig(newActiveRoot *structs.CARoot, oldConfig, new if newConfig == nil { return false } - return newConfig.Provider == oldConfig.Provider && reflect.DeepEqual(newConfig.Config, oldConfig.Config) + + // Do not persist if the new provider and config are the same as the old + return !(newConfig.Provider == oldConfig.Provider && reflect.DeepEqual(newConfig.Config, oldConfig.Config)) } func (c *CAManager) UpdateConfiguration(args *structs.CARequest) (reterr error) { @@ -888,6 +889,23 @@ func (c *CAManager) primaryUpdateRootCA(newProvider ca.Provider, args *structs.C return err } + // TODO: https://github.com/hashicorp/consul/issues/12386 + intermediate, err := newProvider.ActiveIntermediate() + if err != nil { + return fmt.Errorf("error fetching active intermediate: %w", err) + } + if intermediate == "" { + intermediate, err = newProvider.GenerateIntermediate() + if err != nil { + return fmt.Errorf("error generating intermediate: %w", err) + } + } + if intermediate != newRootPEM { + if err := setLeafSigningCert(newActiveRoot, intermediate); err != nil { + return err + } + } + // See if the provider needs to persist any state along with the config pState, err := newProvider.State() if err != nil { @@ -971,19 +989,9 @@ func (c *CAManager) primaryUpdateRootCA(newProvider ca.Provider, args *structs.C } // Add the cross signed cert to the new CA's intermediates (to be attached - // to leaf certs). - newActiveRoot.IntermediateCerts = []string{xcCert} - } - } - - // TODO: https://github.com/hashicorp/consul/issues/12386 - intermediate, err := newProvider.GenerateIntermediate() - if err != nil { - return err - } - if intermediate != newRootPEM { - if err := setLeafSigningCert(newActiveRoot, intermediate); err != nil { - return err + // to leaf certs). We do not want it to be the last cert if there are any + // existing intermediate certs so we push to the front. + newActiveRoot.IntermediateCerts = append([]string{xcCert}, newActiveRoot.IntermediateCerts...) } } @@ -1052,7 +1060,7 @@ func (c *CAManager) primaryRenewIntermediate(provider ca.Provider, newActiveRoot // provider. // Should only be called while the state lock is held by setting the state to non-ready. func (c *CAManager) secondaryRequestNewSigningCert(provider ca.Provider, newActiveRoot *structs.CARoot) error { - csr, err := provider.GenerateIntermediateCSR() + csr, opaque, err := provider.GenerateIntermediateCSR() if err != nil { return err } @@ -1064,12 +1072,12 @@ func (c *CAManager) secondaryRequestNewSigningCert(provider ca.Provider, newActi return nil } - if err := provider.SetIntermediate(intermediatePEM, newActiveRoot.RootCert); err != nil { + if err := provider.SetIntermediate(intermediatePEM, newActiveRoot.RootCert, opaque); err != nil { return fmt.Errorf("Failed to set the intermediate certificate with the CA provider: %v", err) } if err := setLeafSigningCert(newActiveRoot, intermediatePEM); err != nil { - return err + return fmt.Errorf("Failed to set the leaf signing cert to the intermediate: %w", err) } c.logger.Info("received new intermediate certificate from primary datacenter") @@ -1117,15 +1125,13 @@ func pruneExpiredIntermediates(caRoot *structs.CARoot) error { // runRenewIntermediate periodically attempts to renew the intermediate cert. func (c *CAManager) runRenewIntermediate(ctx context.Context) error { - isPrimary := c.serverConf.Datacenter == c.serverConf.PrimaryDatacenter - for { select { case <-ctx.Done(): return nil case <-time.After(structs.IntermediateCertRenewInterval): retryLoopBackoffAbortOnSuccess(ctx, func() error { - return c.RenewIntermediate(ctx, isPrimary) + return c.RenewIntermediate(ctx) }, func(err error) { c.logger.Error("error renewing intermediate certs", "routine", intermediateCertRenewWatchRoutineName, @@ -1139,7 +1145,15 @@ func (c *CAManager) runRenewIntermediate(ctx context.Context) error { // RenewIntermediate checks the intermediate cert for // expiration. If more than half the time a cert is valid has passed, // it will try to renew it. -func (c *CAManager) RenewIntermediate(ctx context.Context, isPrimary bool) error { +func (c *CAManager) RenewIntermediate(ctx context.Context) error { + return c.renewIntermediate(ctx, false) +} + +func (c *CAManager) renewIntermediateNow(ctx context.Context) error { + return c.renewIntermediate(ctx, true) +} + +func (c *CAManager) renewIntermediate(ctx context.Context, forceNow bool) error { // Grab the 'lock' right away so the provider/config can't be changed out while we check // the intermediate. if _, err := c.setState(caStateRenewIntermediate, true); err != nil { @@ -1147,6 +1161,8 @@ func (c *CAManager) RenewIntermediate(ctx context.Context, isPrimary bool) error } defer c.setState(caStateInitialized, false) + isPrimary := c.serverConf.InPrimaryDatacenter() + provider, _ := c.getCAProvider() if provider == nil { // this happens when leadership is being revoked and this go routine will be stopped @@ -1184,8 +1200,10 @@ func (c *CAManager) RenewIntermediate(ctx context.Context, isPrimary bool) error return fmt.Errorf("error parsing active intermediate cert: %v", err) } - if lessThanHalfTimePassed(c.timeNow(), intermediateCert.NotBefore, intermediateCert.NotAfter) { - return nil + if !forceNow { + if lessThanHalfTimePassed(c.timeNow(), intermediateCert.NotBefore, intermediateCert.NotAfter) { + return nil + } } // Enough time has passed, go ahead with getting a new intermediate. @@ -1193,19 +1211,27 @@ func (c *CAManager) RenewIntermediate(ctx context.Context, isPrimary bool) error if !isPrimary { renewalFunc = c.secondaryRequestNewSigningCert } - errCh := make(chan error, 1) - go func() { - errCh <- renewalFunc(provider, activeRoot) - }() - // Wait for the renewal func to return or for the context to be canceled. - select { - case <-ctx.Done(): - return ctx.Err() - case err := <-errCh: + if forceNow { + err := renewalFunc(provider, activeRoot) if err != nil { return err } + } else { + errCh := make(chan error, 1) + go func() { + errCh <- renewalFunc(provider, activeRoot) + }() + + // Wait for the renewal func to return or for the context to be canceled. + select { + case <-ctx.Done(): + return ctx.Err() + case err := <-errCh: + if err != nil { + return err + } + } } if err := c.persistNewRootAndConfig(provider, activeRoot, nil); err != nil { diff --git a/agent/consul/leader_connect_ca_test.go b/agent/consul/leader_connect_ca_test.go index d78f38d9ec18..fbfc642c7e09 100644 --- a/agent/consul/leader_connect_ca_test.go +++ b/agent/consul/leader_connect_ca_test.go @@ -16,17 +16,16 @@ import ( "testing" "time" + msgpackrpc "github.com/hashicorp/consul-net-rpc/net-rpc-msgpackrpc" + "github.com/hashicorp/consul-net-rpc/net/rpc" vaultapi "github.com/hashicorp/vault/api" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" - msgpackrpc "github.com/hashicorp/consul-net-rpc/net-rpc-msgpackrpc" - "github.com/hashicorp/consul-net-rpc/net/rpc" - "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/connect" - ca "github.com/hashicorp/consul/agent/connect/ca" + "github.com/hashicorp/consul/agent/connect/ca" "github.com/hashicorp/consul/agent/consul/fsm" "github.com/hashicorp/consul/agent/consul/state" "github.com/hashicorp/consul/agent/structs" @@ -48,12 +47,24 @@ func TestCAManager_Initialize_Vault_Secondary_SharedVault(t *testing.T) { vault := ca.NewTestVaultServer(t) + primaryVaultToken := ca.CreateVaultTokenWithAttrs(t, vault.Client(), &ca.VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-primary", + ConsulManaged: true, + }) + + secondaryVaultToken := ca.CreateVaultTokenWithAttrs(t, vault.Client(), &ca.VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-secondary", + ConsulManaged: true, + }) + _, serverDC1 := testServerWithConfig(t, func(c *Config) { c.CAConfig = &structs.CAConfiguration{ Provider: "vault", Config: map[string]interface{}{ "Address": vault.Addr, - "Token": vault.RootToken, + "Token": primaryVaultToken, "RootPKIPath": "pki-root/", "IntermediatePKIPath": "pki-primary/", }, @@ -81,7 +92,7 @@ func TestCAManager_Initialize_Vault_Secondary_SharedVault(t *testing.T) { Provider: "vault", Config: map[string]interface{}{ "Address": vault.Addr, - "Token": vault.RootToken, + "Token": secondaryVaultToken, "RootPKIPath": "pki-root/", "IntermediatePKIPath": "pki-secondary/", }, @@ -248,11 +259,11 @@ func (m *mockCAProvider) State() (map[string]string, error) { return nil, ni func (m *mockCAProvider) GenerateRoot() (ca.RootResult, error) { return ca.RootResult{PEM: m.rootPEM}, nil } -func (m *mockCAProvider) GenerateIntermediateCSR() (string, error) { +func (m *mockCAProvider) GenerateIntermediateCSR() (string, string, error) { m.callbackCh <- "provider/GenerateIntermediateCSR" - return "", nil + return "", "", nil } -func (m *mockCAProvider) SetIntermediate(intermediatePEM, rootPEM string) error { +func (m *mockCAProvider) SetIntermediate(intermediatePEM, rootPEM, _ string) error { m.callbackCh <- "provider/SetIntermediate" return nil } @@ -393,7 +404,7 @@ func TestCAManager_UpdateConfigWhileRenewIntermediate(t *testing.T) { // happen in the expected order. errCh := make(chan error) go func() { - errCh <- manager.RenewIntermediate(context.TODO(), false) + errCh <- manager.RenewIntermediate(context.TODO()) }() waitForCh(t, delegate.callbackCh, "provider/GenerateIntermediateCSR") @@ -570,7 +581,14 @@ func TestCAManager_Initialize_Logging(t *testing.T) { func TestCAManager_UpdateConfiguration_Vault_Primary(t *testing.T) { ca.SkipIfVaultNotPresent(t) + vault := ca.NewTestVaultServer(t) + vaultToken := ca.CreateVaultTokenWithAttrs(t, vault.Client(), &ca.VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + WithSudo: true, + }) _, s1 := testServerWithConfig(t, func(c *Config) { c.PrimaryDatacenter = "dc1" @@ -578,7 +596,7 @@ func TestCAManager_UpdateConfiguration_Vault_Primary(t *testing.T) { Provider: "vault", Config: map[string]interface{}{ "Address": vault.Addr, - "Token": vault.RootToken, + "Token": vaultToken, "RootPKIPath": "pki-root/", "IntermediatePKIPath": "pki-intermediate/", }, @@ -594,33 +612,72 @@ func TestCAManager_UpdateConfiguration_Vault_Primary(t *testing.T) { _, origRoot, err := s1.fsm.State().CARootActive(nil) require.NoError(t, err) require.Len(t, origRoot.IntermediateCerts, 1) + origRoot.CreateIndex = s1.caManager.providerRoot.CreateIndex + origRoot.ModifyIndex = s1.caManager.providerRoot.ModifyIndex + require.Equal(t, s1.caManager.providerRoot, origRoot) cert, err := connect.ParseCert(s1.caManager.getLeafSigningCertFromRoot(origRoot)) require.NoError(t, err) require.Equal(t, connect.HexString(cert.SubjectKeyId), origRoot.SigningKeyID) - err = s1.caManager.UpdateConfiguration(&structs.CARequest{ - Config: &structs.CAConfiguration{ - Provider: "vault", - Config: map[string]interface{}{ - "Address": vault.Addr, - "Token": vault.RootToken, - "RootPKIPath": "pki-root-2/", - "IntermediatePKIPath": "pki-intermediate-2/", + t.Run("update config without changing root", func(t *testing.T) { + err = s1.caManager.UpdateConfiguration(&structs.CARequest{ + Config: &structs.CAConfiguration{ + Provider: "vault", + Config: map[string]interface{}{ + "Address": vault.Addr, + "Token": vaultToken, + "RootPKIPath": "pki-root/", + "IntermediatePKIPath": "pki-intermediate/", + "CSRMaxPerSecond": 100, + }, }, - }, + }) + require.NoError(t, err) + _, sameRoot, err := s1.fsm.State().CARootActive(nil) + require.NoError(t, err) + require.Len(t, sameRoot.IntermediateCerts, 1) + sameRoot.CreateIndex = s1.caManager.providerRoot.CreateIndex + sameRoot.ModifyIndex = s1.caManager.providerRoot.ModifyIndex + + cert, err := connect.ParseCert(s1.caManager.getLeafSigningCertFromRoot(sameRoot)) + require.NoError(t, err) + require.Equal(t, connect.HexString(cert.SubjectKeyId), sameRoot.SigningKeyID) + + require.Equal(t, origRoot, sameRoot) + require.Equal(t, sameRoot, s1.caManager.providerRoot) }) - require.NoError(t, err) - _, newRoot, err := s1.fsm.State().CARootActive(nil) - require.NoError(t, err) - require.Len(t, newRoot.IntermediateCerts, 2, - "expected one cross-sign cert and one local leaf sign cert") - require.NotEqual(t, origRoot.ID, newRoot.ID) + t.Run("update config and change root", func(t *testing.T) { + vaultToken2 := ca.CreateVaultTokenWithAttrs(t, vault.Client(), &ca.VaultTokenAttributes{ + RootPath: "pki-root-2", + IntermediatePath: "pki-intermediate-2", + ConsulManaged: true, + }) - cert, err = connect.ParseCert(s1.caManager.getLeafSigningCertFromRoot(newRoot)) - require.NoError(t, err) - require.Equal(t, connect.HexString(cert.SubjectKeyId), newRoot.SigningKeyID) + err = s1.caManager.UpdateConfiguration(&structs.CARequest{ + Config: &structs.CAConfiguration{ + Provider: "vault", + Config: map[string]interface{}{ + "Address": vault.Addr, + "Token": vaultToken2, + "RootPKIPath": "pki-root-2/", + "IntermediatePKIPath": "pki-intermediate-2/", + }, + }, + }) + require.NoError(t, err) + + _, newRoot, err := s1.fsm.State().CARootActive(nil) + require.NoError(t, err) + require.Len(t, newRoot.IntermediateCerts, 2, + "expected one cross-sign cert and one local leaf sign cert") + require.NotEqual(t, origRoot.ID, newRoot.ID) + + cert, err = connect.ParseCert(s1.caManager.getLeafSigningCertFromRoot(newRoot)) + require.NoError(t, err) + require.Equal(t, connect.HexString(cert.SubjectKeyId), newRoot.SigningKeyID) + }) } func TestCAManager_Initialize_Vault_WithIntermediateAsPrimaryCA(t *testing.T) { @@ -636,12 +693,18 @@ func TestCAManager_Initialize_Vault_WithIntermediateAsPrimaryCA(t *testing.T) { meshRootPath := "pki-root" primaryCert := setupPrimaryCA(t, vclient, meshRootPath, "") + primaryVaultToken := ca.CreateVaultTokenWithAttrs(t, vault.Client(), &ca.VaultTokenAttributes{ + RootPath: meshRootPath, + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + }) + _, s1 := testServerWithConfig(t, func(c *Config) { c.CAConfig = &structs.CAConfiguration{ Provider: "vault", Config: map[string]interface{}{ "Address": vault.Addr, - "Token": vault.RootToken, + "Token": primaryVaultToken, "RootPKIPath": meshRootPath, "IntermediatePKIPath": "pki-intermediate/", }, @@ -665,6 +728,12 @@ func TestCAManager_Initialize_Vault_WithIntermediateAsPrimaryCA(t *testing.T) { // TODO: renew primary leaf signing cert // TODO: rotate root + secondaryVaultToken := ca.CreateVaultTokenWithAttrs(t, vault.Client(), &ca.VaultTokenAttributes{ + RootPath: meshRootPath, + IntermediatePath: "pki-secondary", + ConsulManaged: true, + }) + testutil.RunStep(t, "run secondary DC", func(t *testing.T) { _, sDC2 := testServerWithConfig(t, func(c *Config) { c.Datacenter = "dc2" @@ -673,7 +742,7 @@ func TestCAManager_Initialize_Vault_WithIntermediateAsPrimaryCA(t *testing.T) { Provider: "vault", Config: map[string]interface{}{ "Address": vault.Addr, - "Token": vault.RootToken, + "Token": secondaryVaultToken, "RootPKIPath": meshRootPath, "IntermediatePKIPath": "pki-secondary/", }, @@ -704,12 +773,18 @@ func TestCAManager_Verify_Vault_NoChangeToSecondaryConfig(t *testing.T) { vault := ca.NewTestVaultServer(t) + primaryVaultToken := ca.CreateVaultTokenWithAttrs(t, vault.Client(), &ca.VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + }) + _, sDC1 := testServerWithConfig(t, func(c *Config) { c.CAConfig = &structs.CAConfiguration{ Provider: "vault", Config: map[string]interface{}{ "Address": vault.Addr, - "Token": vault.RootToken, + "Token": primaryVaultToken, "RootPKIPath": "pki-root/", "IntermediatePKIPath": "pki-intermediate/", }, @@ -718,6 +793,12 @@ func TestCAManager_Verify_Vault_NoChangeToSecondaryConfig(t *testing.T) { defer sDC1.Shutdown() testrpc.WaitForActiveCARoot(t, sDC1.RPC, "dc1", nil) + secondaryVaultToken := ca.CreateVaultTokenWithAttrs(t, vault.Client(), &ca.VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate-2", + ConsulManaged: true, + }) + _, sDC2 := testServerWithConfig(t, func(c *Config) { c.Datacenter = "dc2" c.PrimaryDatacenter = "dc1" @@ -725,7 +806,7 @@ func TestCAManager_Verify_Vault_NoChangeToSecondaryConfig(t *testing.T) { Provider: "vault", Config: map[string]interface{}{ "Address": vault.Addr, - "Token": vault.RootToken, + "Token": secondaryVaultToken, "RootPKIPath": "pki-root/", "IntermediatePKIPath": "pki-intermediate-2/", }, @@ -740,7 +821,7 @@ func TestCAManager_Verify_Vault_NoChangeToSecondaryConfig(t *testing.T) { err := msgpackrpc.CallWithCodec(codec, "ConnectCA.ConfigurationGet", &structs.DCSpecificRequest{}, &configBefore) require.NoError(t, err) - renewLeafSigningCert(t, sDC1.caManager, sDC1.caManager.primaryRenewIntermediate) + require.NoError(t, sDC1.caManager.renewIntermediateNow(context.Background())) // Give the secondary some time to notice the update time.Sleep(100 * time.Millisecond) @@ -778,37 +859,62 @@ func TestCAManager_Initialize_Vault_WithExternalTrustedCA(t *testing.T) { vault := ca.NewTestVaultServer(t) vclient := vault.Client() + rootPEM := generateExternalRootCA(t, vclient) primaryCAPath := "pki-primary" primaryCert := setupPrimaryCA(t, vclient, primaryCAPath, rootPEM) + primaryVaultToken := ca.CreateVaultTokenWithAttrs(t, vault.Client(), &ca.VaultTokenAttributes{ + RootPath: primaryCAPath, + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + WithSudo: true, + }) + _, serverDC1 := testServerWithConfig(t, func(c *Config) { c.CAConfig = &structs.CAConfiguration{ Provider: "vault", Config: map[string]interface{}{ "Address": vault.Addr, - "Token": vault.RootToken, + "Token": primaryVaultToken, "RootPKIPath": primaryCAPath, "IntermediatePKIPath": "pki-intermediate/", }, } }) testrpc.WaitForTestAgent(t, serverDC1.RPC, "dc1") + testrpc.WaitForActiveCARoot(t, serverDC1.RPC, "dc1", nil) - var origLeaf string + var ( + origLeaf string + primaryLeafSigningCert string + ) roots := structs.IndexedCARoots{} testutil.RunStep(t, "verify primary DC", func(t *testing.T) { codec := rpcClient(t, serverDC1) err := msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots) require.NoError(t, err) - require.Len(t, roots.Roots, 1) - require.Equal(t, primaryCert, roots.Roots[0].RootCert) + + // Verify CA trust heirarchy is expected. + require.Len(t, roots.Roots, 1, "should have one because there's no provider rotation yet") + require.Equal(t, primaryCert, roots.Roots[0].RootCert, "should be the offline root") require.Contains(t, roots.Roots[0].RootCert, rootPEM) + require.Len(t, roots.Roots[0].IntermediateCerts, 1, "should just have the primary's intermediate") + + active := roots.Active() leafCert := getLeafCert(t, codec, roots.TrustDomain, "dc1") - verifyLeafCert(t, roots.Active(), leafCert) + verifyLeafCert(t, active, leafCert) + origLeaf = leafCert + primaryLeafSigningCert = serverDC1.caManager.getLeafSigningCertFromRoot(active) + }) + + secondaryVaultToken := ca.CreateVaultTokenWithAttrs(t, vault.Client(), &ca.VaultTokenAttributes{ + RootPath: "should-be-ignored", + IntermediatePath: "pki-secondary", + ConsulManaged: true, }) _, serverDC2 := testServerWithConfig(t, func(c *Config) { @@ -818,72 +924,91 @@ func TestCAManager_Initialize_Vault_WithExternalTrustedCA(t *testing.T) { Provider: "vault", Config: map[string]interface{}{ "Address": vault.Addr, - "Token": vault.RootToken, + "Token": secondaryVaultToken, "RootPKIPath": "should-be-ignored", "IntermediatePKIPath": "pki-secondary/", }, } }) + joinWAN(t, serverDC2, serverDC1) + testrpc.WaitForActiveCARoot(t, serverDC2.RPC, "dc2", nil) - var origLeafSecondary string + var ( + origLeafSecondary string + secondaryLeafSigningCert string + ) testutil.RunStep(t, "start secondary DC", func(t *testing.T) { - joinWAN(t, serverDC2, serverDC1) - testrpc.WaitForActiveCARoot(t, serverDC2.RPC, "dc2", nil) - codec := rpcClient(t, serverDC2) roots = structs.IndexedCARoots{} err := msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots) require.NoError(t, err) - require.Len(t, roots.Roots, 1) + + require.Len(t, roots.Roots, 1, "should have one because there's no provider rotation yet") + require.Equal(t, primaryCert, roots.Roots[0].RootCert, "should be the offline root") + require.Contains(t, roots.Roots[0].RootCert, rootPEM) + require.Len(t, roots.Roots[0].IntermediateCerts, 2, "should have the primary's intermediate and our own") + + active := roots.Active() leafPEM := getLeafCert(t, codec, roots.TrustDomain, "dc2") verifyLeafCert(t, roots.Roots[0], leafPEM) + origLeafSecondary = leafPEM + secondaryLeafSigningCert = serverDC2.caManager.getLeafSigningCertFromRoot(active) }) testutil.RunStep(t, "renew leaf signing CA in primary", func(t *testing.T) { - previous := serverDC1.caManager.getLeafSigningCertFromRoot(roots.Active()) - - renewLeafSigningCert(t, serverDC1.caManager, serverDC1.caManager.primaryRenewIntermediate) + require.NoError(t, serverDC1.caManager.renewIntermediateNow(context.Background())) codec := rpcClient(t, serverDC1) roots = structs.IndexedCARoots{} err := msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots) require.NoError(t, err) - require.Len(t, roots.Roots, 1) - require.Len(t, roots.Roots[0].IntermediateCerts, 2) + + require.Len(t, roots.Roots, 1, "should have one because there's no provider rotation yet") + require.Equal(t, primaryCert, roots.Roots[0].RootCert, "should be the offline root") + require.Contains(t, roots.Roots[0].RootCert, rootPEM) + require.Len(t, roots.Roots[0].IntermediateCerts, 2, "we renewed, so we have our old primary and our new primary intermediate") + + active := roots.Active() newCert := serverDC1.caManager.getLeafSigningCertFromRoot(roots.Active()) - require.NotEqual(t, previous, newCert) + require.NotEqual(t, primaryLeafSigningCert, newCert) + primaryLeafSigningCert = newCert leafPEM := getLeafCert(t, codec, roots.TrustDomain, "dc1") - verifyLeafCert(t, roots.Roots[0], leafPEM) + verifyLeafCert(t, active, leafPEM) // original certs from old signing cert should still verify - verifyLeafCert(t, roots.Roots[0], origLeaf) + verifyLeafCert(t, active, origLeaf) }) + var oldSecondaryData *structs.CARoot testutil.RunStep(t, "renew leaf signing CA in secondary", func(t *testing.T) { - previous := serverDC2.caManager.getLeafSigningCertFromRoot(roots.Active()) - - renewLeafSigningCert(t, serverDC2.caManager, serverDC2.caManager.secondaryRequestNewSigningCert) + require.NoError(t, serverDC2.caManager.renewIntermediateNow(context.Background())) codec := rpcClient(t, serverDC2) roots = structs.IndexedCARoots{} err := msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots) require.NoError(t, err) - require.Len(t, roots.Roots, 1) - // one intermediate from primary, two from secondary - require.Len(t, roots.Roots[0].IntermediateCerts, 3) - newCert := serverDC1.caManager.getLeafSigningCertFromRoot(roots.Active()) - require.NotEqual(t, previous, newCert) + require.Len(t, roots.Roots, 1, "should have one because there's no provider rotation yet") + require.Equal(t, primaryCert, roots.Roots[0].RootCert, "should be the offline root") + require.Contains(t, roots.Roots[0].RootCert, rootPEM) + require.Len(t, roots.Roots[0].IntermediateCerts, 3, "one intermediate from primary, two from secondary") + + active := roots.Active() + oldSecondaryData = active + + newCert := serverDC2.caManager.getLeafSigningCertFromRoot(active) + require.NotEqual(t, secondaryLeafSigningCert, newCert) + secondaryLeafSigningCert = newCert leafPEM := getLeafCert(t, codec, roots.TrustDomain, "dc2") - verifyLeafCert(t, roots.Roots[0], leafPEM) + verifyLeafCert(t, active, leafPEM) // original certs from old signing cert should still verify - verifyLeafCert(t, roots.Roots[0], origLeaf) + verifyLeafCert(t, active, origLeaf) }) testutil.RunStep(t, "rotate root by changing the provider", func(t *testing.T) { @@ -902,20 +1027,47 @@ func TestCAManager_Initialize_Vault_WithExternalTrustedCA(t *testing.T) { roots = structs.IndexedCARoots{} err = msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots) require.NoError(t, err) - require.Len(t, roots.Roots, 2) + + require.Len(t, roots.Roots, 2, "two because we rotated the provider") + active := roots.Active() - require.Len(t, active.IntermediateCerts, 1) + require.NotEqual(t, primaryCert, active.RootCert, "should NOT be the offline root, because we switched") + require.NotContains(t, active.RootCert, rootPEM) + require.Len(t, active.IntermediateCerts, 1, "only one new intermediate in the primary") leafPEM := getLeafCert(t, codec, roots.TrustDomain, "dc1") verifyLeafCert(t, roots.Active(), leafPEM) + // wait for secondary to witness it + codec2 := rpcClient(t, serverDC2) + retry.Run(t, func(r *retry.R) { + var reply structs.IndexedCARoots + err := msgpackrpc.CallWithCodec(codec2, "ConnectCA.Roots", &structs.DCSpecificRequest{ + Datacenter: "dc2", + }, &reply) + require.NoError(r, err) + + require.Len(r, reply.Roots, 2, "primary provider rotated, so secondary gets rekeyed") + + active := reply.Active() + require.NotNil(r, active) + + if oldSecondaryData.ID == reply.ActiveRootID { + r.Fatal("wait; did not witness primary root rotation yet") + } + + newCert := serverDC2.caManager.getLeafSigningCertFromRoot(roots.Active()) + require.NotEqual(r, secondaryLeafSigningCert, newCert) + secondaryLeafSigningCert = newCert + }) + // original certs from old root cert should still verify verifyLeafCertWithRoots(t, roots, origLeaf) // original certs from secondary should still verify rootsSecondary := structs.IndexedCARoots{} r := &structs.DCSpecificRequest{Datacenter: "dc2"} - err = msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", r, &rootsSecondary) + err = msgpackrpc.CallWithCodec(codec2, "ConnectCA.Roots", r, &rootsSecondary) require.NoError(t, err) verifyLeafCertWithRoots(t, rootsSecondary, origLeafSecondary) }) @@ -923,6 +1075,12 @@ func TestCAManager_Initialize_Vault_WithExternalTrustedCA(t *testing.T) { testutil.RunStep(t, "rotate to a different external root", func(t *testing.T) { setupPrimaryCA(t, vclient, "pki-primary-2/", rootPEM) + primaryVaultToken2 := ca.CreateVaultTokenWithAttrs(t, vault.Client(), &ca.VaultTokenAttributes{ + RootPath: "pki-primary-2", + IntermediatePath: "pki-intermediate-2", + ConsulManaged: true, + }) + codec := rpcClient(t, serverDC1) req := &structs.CARequest{ Op: structs.CAOpSetConfig, @@ -930,7 +1088,7 @@ func TestCAManager_Initialize_Vault_WithExternalTrustedCA(t *testing.T) { Provider: "vault", Config: map[string]interface{}{ "Address": vault.Addr, - "Token": vault.RootToken, + "Token": primaryVaultToken2, "RootPKIPath": "pki-primary-2/", "IntermediatePKIPath": "pki-intermediate-2/", }, @@ -963,28 +1121,6 @@ func TestCAManager_Initialize_Vault_WithExternalTrustedCA(t *testing.T) { }) } -// renewLeafSigningCert mimics RenewIntermediate. This is unfortunate, but -// necessary for now as there is no easy way to invoke that logic unconditionally. -// Currently, it requires patching values and polling for the operation to -// complete, which adds a lot of distractions to a test case. -// With this function we can instead unconditionally rotate the leaf signing cert -// synchronously. -func renewLeafSigningCert(t *testing.T, manager *CAManager, fn func(ca.Provider, *structs.CARoot) error) { - t.Helper() - provider, _ := manager.getCAProvider() - - store := manager.delegate.State() - _, root, err := store.CARootActive(nil) - require.NoError(t, err) - - activeRoot := root.Clone() - err = fn(provider, activeRoot) - require.NoError(t, err) - err = manager.persistNewRootAndConfig(provider, activeRoot, nil) - require.NoError(t, err) - manager.setCAProvider(provider, activeRoot) -} - func generateExternalRootCA(t *testing.T, client *vaultapi.Client) string { t.Helper() err := client.Sys().Mount("corp", &vaultapi.MountInput{ @@ -1033,14 +1169,20 @@ func setupPrimaryCA(t *testing.T, client *vaultapi.Client, path string, rootPEM }) require.NoError(t, err, "failed to sign intermediate") + cert := intermediate.Data["certificate"].(string) + var buf strings.Builder - buf.WriteString(lib.EnsureTrailingNewline(intermediate.Data["certificate"].(string))) - buf.WriteString(lib.EnsureTrailingNewline(rootPEM)) + buf.WriteString(lib.EnsureTrailingNewline(cert)) + if !strings.Contains(strings.TrimSpace(cert), strings.TrimSpace(rootPEM)) { + // Vault < v1.11 included the root in the output of sign-intermediate. + buf.WriteString(lib.EnsureTrailingNewline(rootPEM)) + } _, err = client.Logical().Write(path+"/intermediate/set-signed", map[string]interface{}{ "certificate": buf.String(), }) require.NoError(t, err, "failed to set signed intermediate") + // TODO: also fix issuers here? return lib.EnsureTrailingNewline(buf.String()) } diff --git a/agent/consul/leader_connect_test.go b/agent/consul/leader_connect_test.go index bf6fa9522104..f66406ee9151 100644 --- a/agent/consul/leader_connect_test.go +++ b/agent/consul/leader_connect_test.go @@ -329,13 +329,19 @@ func TestCAManager_RenewIntermediate_Vault_Primary(t *testing.T) { testVault := ca.NewTestVaultServer(t) + vaultToken := ca.CreateVaultTokenWithAttrs(t, testVault.Client(), &ca.VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + }) + _, s1 := testServerWithConfig(t, func(c *Config) { c.PrimaryDatacenter = "dc1" c.CAConfig = &structs.CAConfiguration{ Provider: "vault", Config: map[string]interface{}{ "Address": testVault.Addr, - "Token": testVault.RootToken, + "Token": vaultToken, "RootPKIPath": "pki-root/", "IntermediatePKIPath": "pki-intermediate/", "LeafCertTTL": "2s", @@ -701,7 +707,6 @@ func TestCAManager_Initialize_Vault_KeepOldRoots_Primary(t *testing.T) { t.Parallel() testVault := ca.NewTestVaultServer(t) - defer testVault.Stop() dir1pre, s1pre := testServer(t) defer os.RemoveAll(dir1pre) @@ -711,12 +716,18 @@ func TestCAManager_Initialize_Vault_KeepOldRoots_Primary(t *testing.T) { testrpc.WaitForLeader(t, s1pre.RPC, "dc1") + vaultToken := ca.CreateVaultTokenWithAttrs(t, testVault.Client(), &ca.VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + }) + // Update the CA config to use Vault - this should force the generation of a new root cert. vaultCAConf := &structs.CAConfiguration{ Provider: "vault", Config: map[string]interface{}{ "Address": testVault.Addr, - "Token": testVault.RootToken, + "Token": vaultToken, "RootPKIPath": "pki-root/", "IntermediatePKIPath": "pki-intermediate/", }, @@ -766,7 +777,12 @@ func TestCAManager_Initialize_Vault_FixesSigningKeyID_Primary(t *testing.T) { t.Parallel() testVault := ca.NewTestVaultServer(t) - defer testVault.Stop() + + vaultToken := ca.CreateVaultTokenWithAttrs(t, testVault.Client(), &ca.VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + }) dir1pre, s1pre := testServerWithConfig(t, func(c *Config) { c.Build = "1.6.0" @@ -775,7 +791,7 @@ func TestCAManager_Initialize_Vault_FixesSigningKeyID_Primary(t *testing.T) { Provider: "vault", Config: map[string]interface{}{ "Address": testVault.Addr, - "Token": testVault.RootToken, + "Token": vaultToken, "RootPKIPath": "pki-root/", "IntermediatePKIPath": "pki-intermediate/", }, @@ -1546,13 +1562,19 @@ func TestCAManager_Initialize_Vault_BadCAConfigDoesNotPreventLeaderEstablishment require.Empty(t, rootsList.Roots) require.Nil(t, activeRoot) + goodVaultToken := ca.CreateVaultTokenWithAttrs(t, testVault.Client(), &ca.VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + }) + // Now that the leader is up and we have verified that there are no roots / CA init failed, // verify that we can reconfigure away from the bad configuration. newConfig := &structs.CAConfiguration{ Provider: "vault", Config: map[string]interface{}{ "Address": testVault.Addr, - "Token": testVault.RootToken, + "Token": goodVaultToken, "RootPKIPath": "pki-root/", "IntermediatePKIPath": "pki-intermediate/", }, @@ -1676,7 +1698,13 @@ func TestConnectCA_ConfigurationSet_Vault_ForceWithoutCrossSigning(t *testing.T) ca.SkipIfVaultNotPresent(t) testVault := ca.NewTestVaultServer(t) - defer testVault.Stop() + + vaultToken1 := ca.CreateVaultTokenWithAttrs(t, testVault.Client(), &ca.VaultTokenAttributes{ + RootPath: "pki-root", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + WithSudo: true, + }) _, s1 := testServerWithConfig(t, func(c *Config) { c.Build = "1.9.1" @@ -1685,7 +1713,7 @@ func TestConnectCA_ConfigurationSet_Vault_ForceWithoutCrossSigning(t *testing.T) Provider: "vault", Config: map[string]interface{}{ "Address": testVault.Addr, - "Token": testVault.RootToken, + "Token": vaultToken1, "RootPKIPath": "pki-root/", "IntermediatePKIPath": "pki-intermediate/", }, @@ -1706,13 +1734,19 @@ func TestConnectCA_ConfigurationSet_Vault_ForceWithoutCrossSigning(t *testing.T) require.Len(t, rootList.Roots, 1) oldRoot := rootList.Roots[0] + vaultToken2 := ca.CreateVaultTokenWithAttrs(t, testVault.Client(), &ca.VaultTokenAttributes{ + RootPath: "pki-root-2", + IntermediatePath: "pki-intermediate", + ConsulManaged: true, + }) + // Update the provider config to use a new PKI path, which should // cause a rotation. newConfig := &structs.CAConfiguration{ Provider: "vault", Config: map[string]interface{}{ "Address": testVault.Addr, - "Token": testVault.RootToken, + "Token": vaultToken2, "RootPKIPath": "pki-root-2/", "IntermediatePKIPath": "pki-intermediate/", }, diff --git a/agent/consul/leader_intentions.go b/agent/consul/leader_intentions.go index 9adc26795deb..2894acd58460 100644 --- a/agent/consul/leader_intentions.go +++ b/agent/consul/leader_intentions.go @@ -22,7 +22,7 @@ func (s *Server) startIntentionConfigEntryMigration(ctx context.Context) error { // Check for the system metadata first, as that's the most trustworthy in // both the primary and secondaries. - intentionFormat, err := s.getSystemMetadata(structs.SystemMetadataIntentionFormatKey) + intentionFormat, err := s.GetSystemMetadata(structs.SystemMetadataIntentionFormatKey) if err != nil { return err } @@ -240,7 +240,7 @@ func (s *Server) legacyIntentionMigrationInSecondaryDC(ctx context.Context) erro // error. for { // Check for the system metadata first, as that's the most trustworthy. - intentionFormat, err := s.getSystemMetadata(structs.SystemMetadataIntentionFormatKey) + intentionFormat, err := s.GetSystemMetadata(structs.SystemMetadataIntentionFormatKey) if err != nil { return err } diff --git a/agent/consul/leader_intentions_oss.go b/agent/consul/leader_intentions_ce.go similarity index 96% rename from agent/consul/leader_intentions_oss.go rename to agent/consul/leader_intentions_ce.go index db9c742bd1d4..6913b6a90a3d 100644 --- a/agent/consul/leader_intentions_oss.go +++ b/agent/consul/leader_intentions_ce.go @@ -10,7 +10,7 @@ import ( ) func migrateIntentionsToConfigEntries(ixns structs.Intentions) []*structs.ServiceIntentionsConfigEntry { - // Remove any intention in OSS that happened to have used a non-default + // Remove any intention in CE that happened to have used a non-default // namespace. // // The one exception is that if we find wildcards namespaces we "upgrade" @@ -53,7 +53,7 @@ func migrateIntentionsToConfigEntries(ixns structs.Intentions) []*structs.Servic } retained[name] = struct{}{} output = append(output, ixn) - continue // a-ok for OSS + continue // a-ok for CE } // If anything is wildcarded, attempt to reify it as "default". diff --git a/agent/consul/leader_intentions_oss_test.go b/agent/consul/leader_intentions_ce_test.go similarity index 100% rename from agent/consul/leader_intentions_oss_test.go rename to agent/consul/leader_intentions_ce_test.go diff --git a/agent/consul/leader_intentions_test.go b/agent/consul/leader_intentions_test.go index b431567fc627..7713126da7dd 100644 --- a/agent/consul/leader_intentions_test.go +++ b/agent/consul/leader_intentions_test.go @@ -519,7 +519,7 @@ func TestLeader_LegacyIntentionMigration(t *testing.T) { // Wait until the migration routine is complete. retry.Run(t, func(r *retry.R) { - intentionFormat, err := s1.getSystemMetadata(structs.SystemMetadataIntentionFormatKey) + intentionFormat, err := s1.GetSystemMetadata(structs.SystemMetadataIntentionFormatKey) require.NoError(r, err) if intentionFormat != structs.SystemMetadataIntentionFormatConfigValue { r.Fatal("intention migration is not yet complete") diff --git a/agent/consul/leader_peering.go b/agent/consul/leader_peering.go index bfa24c6ce1f9..4e76c26d31dd 100644 --- a/agent/consul/leader_peering.go +++ b/agent/consul/leader_peering.go @@ -65,6 +65,8 @@ var ( maxFastConnRetries = uint(5) // maxFastRetryBackoff is the maximum amount of time we'll wait between retries following the fast path. maxFastRetryBackoff = 8192 * time.Millisecond + // maxRetryBackoffPeering is the maximum number of seconds we'll wait between retries when attempting to re-establish a peering connection. + maxRetryBackoffPeering = 64 ) func (s *Server) startPeeringStreamSync(ctx context.Context) { @@ -90,14 +92,14 @@ func (s *Server) runPeeringMetrics(ctx context.Context) error { metrics.SetGauge(leaderExportedServicesCountKey, float32(0)) return nil case <-ticker.C: - if err := s.emitPeeringMetricsOnce(logger, defaultMetrics()); err != nil { + if err := s.emitPeeringMetricsOnce(defaultMetrics()); err != nil { s.logger.Error("error emitting peering stream metrics", "error", err) } } } } -func (s *Server) emitPeeringMetricsOnce(logger hclog.Logger, metricsImpl *metrics.Metrics) error { +func (s *Server) emitPeeringMetricsOnce(metricsImpl *metrics.Metrics) error { _, peers, err := s.fsm.State().PeeringList(nil, *structs.NodeEnterpriseMetaInPartition(structs.WildcardSpecifier)) if err != nil { return err @@ -122,19 +124,14 @@ func (s *Server) emitPeeringMetricsOnce(logger hclog.Logger, metricsImpl *metric } // peering health metric - if status.NeverConnected { - metricsImpl.SetGaugeWithLabels(leaderHealthyPeeringKeyDeprecated, float32(math.NaN()), labels) - metricsImpl.SetGaugeWithLabels(leaderHealthyPeeringKey, float32(math.NaN()), labels) - } else { - healthy := s.peerStreamServer.Tracker.IsHealthy(status) - healthyInt := 0 - if healthy { - healthyInt = 1 - } - - metricsImpl.SetGaugeWithLabels(leaderHealthyPeeringKeyDeprecated, float32(healthyInt), labels) - metricsImpl.SetGaugeWithLabels(leaderHealthyPeeringKey, float32(healthyInt), labels) + healthy := 0 + switch { + case status.NeverConnected: + case s.peerStreamServer.Tracker.IsHealthy(status): + healthy = 1 } + metricsImpl.SetGaugeWithLabels(leaderHealthyPeeringKeyDeprecated, float32(healthy), labels) + metricsImpl.SetGaugeWithLabels(leaderHealthyPeeringKey, float32(healthy), labels) } return nil @@ -363,7 +360,7 @@ func (s *Server) establishStream(ctx context.Context, // send keepalive pings even if there is no active streams PermitWithoutStream: true, }), - grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(50 * 1024 * 1024)), + grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(8*1024*1024), grpc.MaxCallRecvMsgSize(8*1024*1024)), } logger.Trace("dialing peer", "addr", addr) @@ -718,10 +715,10 @@ func peeringRetryTimeout(failedAttempts uint, loopErr error) time.Duration { } // Else we go with the default backoff from retryLoopBackoff. - if (1 << failedAttempts) < maxRetryBackoff { + if (1 << failedAttempts) < maxRetryBackoffPeering { return (1 << failedAttempts) * time.Second } - return time.Duration(maxRetryBackoff) * time.Second + return time.Duration(maxRetryBackoffPeering) * time.Second } // isErrCode returns true if err is a gRPC error with given error code. diff --git a/agent/consul/leader_peering_test.go b/agent/consul/leader_peering_test.go index 4183a9f301bb..a61bd3afef1f 100644 --- a/agent/consul/leader_peering_test.go +++ b/agent/consul/leader_peering_test.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "io/ioutil" - "math" "net" "testing" "time" @@ -64,6 +63,7 @@ func TestLeader_PeeringSync_Lifecycle_ClientDeletion(t *testing.T) { conn, err := grpc.DialContext(ctx, acceptor.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(acceptor.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -102,6 +102,7 @@ func TestLeader_PeeringSync_Lifecycle_ClientDeletion(t *testing.T) { conn, err = grpc.DialContext(ctx, dialer.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(dialer.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -188,6 +189,7 @@ func TestLeader_PeeringSync_Lifecycle_UnexportWhileDown(t *testing.T) { conn, err := grpc.DialContext(ctx, acceptor.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(acceptor.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -222,6 +224,7 @@ func TestLeader_PeeringSync_Lifecycle_UnexportWhileDown(t *testing.T) { conn, err = grpc.DialContext(ctx, dialer.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(dialer.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -376,6 +379,7 @@ func TestLeader_PeeringSync_Lifecycle_ServerDeletion(t *testing.T) { conn, err := grpc.DialContext(ctx, acceptor.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(acceptor.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -409,6 +413,7 @@ func TestLeader_PeeringSync_Lifecycle_ServerDeletion(t *testing.T) { conn, err = grpc.DialContext(ctx, dialer.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(dialer.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -462,6 +467,30 @@ func TestLeader_PeeringSync_Lifecycle_ServerDeletion(t *testing.T) { require.NoError(r, err) require.Equal(r, pbpeering.PeeringState_TERMINATED, peering.State) }) + + // Re-establishing a peering terminated by the acceptor should be possible + // without needing to delete the terminated peering first. + ctx, cancel = context.WithTimeout(context.Background(), 3*time.Second) + t.Cleanup(cancel) + + req = pbpeering.GenerateTokenRequest{ + PeerName: "my-peer-dialer", + } + resp, err = peeringClient.GenerateToken(ctx, &req) + require.NoError(t, err) + + tokenJSON, err = base64.StdEncoding.DecodeString(resp.PeeringToken) + require.NoError(t, err) + + token = structs.PeeringToken{} + require.NoError(t, json.Unmarshal(tokenJSON, &token)) + + establishReq = pbpeering.EstablishRequest{ + PeerName: "my-peer-acceptor", + PeeringToken: resp.PeeringToken, + } + _, err = dialerClient.Establish(ctx, &establishReq) + require.NoError(t, err) } func TestLeader_PeeringSync_FailsForTLSError(t *testing.T) { @@ -472,7 +501,7 @@ func TestLeader_PeeringSync_FailsForTLSError(t *testing.T) { t.Run("server-name-validation", func(t *testing.T) { testLeader_PeeringSync_failsForTLSError(t, func(token *structs.PeeringToken) { token.ServerName = "wrong.name" - }, `transport: authentication handshake failed: x509: certificate is valid for server.dc1.peering.11111111-2222-3333-4444-555555555555.consul, not wrong.name`) + }, `transport: authentication handshake failed: tls: failed to verify certificate: x509: certificate is valid for server.dc1.peering.11111111-2222-3333-4444-555555555555.consul, not wrong.name`) }) t.Run("bad-ca-roots", func(t *testing.T) { wrongRoot, err := ioutil.ReadFile("../../test/client_certs/rootca.crt") @@ -480,7 +509,7 @@ func TestLeader_PeeringSync_FailsForTLSError(t *testing.T) { testLeader_PeeringSync_failsForTLSError(t, func(token *structs.PeeringToken) { token.CA = []string{string(wrongRoot)} - }, `transport: authentication handshake failed: x509: certificate signed by unknown authority`) + }, `transport: authentication handshake failed: tls: failed to verify certificate: x509: certificate signed by unknown authority`) }) } @@ -510,6 +539,7 @@ func testLeader_PeeringSync_failsForTLSError(t *testing.T, tokenMutateFn func(to conn, err := grpc.DialContext(ctx, s1.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(s1.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -552,6 +582,7 @@ func testLeader_PeeringSync_failsForTLSError(t *testing.T, tokenMutateFn func(to conn, err = grpc.DialContext(ctx, s2.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(s2.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -677,6 +708,7 @@ func TestLeader_Peering_RemoteInfo(t *testing.T) { conn, err := grpc.DialContext(ctx, acceptingServer.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(acceptingServer.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -712,6 +744,7 @@ func TestLeader_Peering_RemoteInfo(t *testing.T) { conn, err = grpc.DialContext(ctx, dialingServer.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(dialingServer.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -786,6 +819,7 @@ func TestLeader_Peering_DialerReestablishesConnectionOnError(t *testing.T) { conn, err := grpc.DialContext(ctx, acceptingServer.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(acceptingServer.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -821,6 +855,7 @@ func TestLeader_Peering_DialerReestablishesConnectionOnError(t *testing.T) { conn, err = grpc.DialContext(ctx, dialingServer.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(dialingServer.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -1006,6 +1041,7 @@ func TestLeader_Peering_ImportedExportedServicesCount(t *testing.T) { // Create a peering by generating a token conn, err := grpc.DialContext(ctx, s1.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(s1.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -1035,6 +1071,7 @@ func TestLeader_Peering_ImportedExportedServicesCount(t *testing.T) { conn, err = grpc.DialContext(ctx, s2.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(s2.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -1231,6 +1268,7 @@ func TestLeader_Peering_ImportedExportedServicesCount(t *testing.T) { conn2, err := grpc.DialContext(ctx, s2.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(s2.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -1312,6 +1350,7 @@ func TestLeader_PeeringMetrics_emitPeeringMetrics(t *testing.T) { conn, err := grpc.DialContext(ctx, s1.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(s1.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -1414,7 +1453,7 @@ func TestLeader_PeeringMetrics_emitPeeringMetrics(t *testing.T) { met, err := metrics.New(cfg, sink) require.NoError(t, err) - errM := s2.emitPeeringMetricsOnce(s2.logger, met) + errM := s2.emitPeeringMetricsOnce(met) require.NoError(t, errM) retry.Run(t, func(r *retry.R) { @@ -1445,7 +1484,7 @@ func TestLeader_PeeringMetrics_emitPeeringMetrics(t *testing.T) { healthyMetric3, ok := intv.Gauges[keyHealthyMetric3] require.True(r, ok, fmt.Sprintf("did not find the key %q", keyHealthyMetric3)) - require.True(r, math.IsNaN(float64(healthyMetric3.Value))) + require.Equal(r, float32(0), healthyMetric3.Value) }) } @@ -1587,10 +1626,12 @@ func TestLeader_Peering_peeringRetryTimeout_regularErrors(t *testing.T) { {1, 2 * time.Second}, {2, 4 * time.Second}, {3, 8 * time.Second}, + {4, 16 * time.Second}, + {5, 32 * time.Second}, // Until max. - {8, 256 * time.Second}, - {9, 256 * time.Second}, - {10, 256 * time.Second}, + {6, 64 * time.Second}, + {10, 64 * time.Second}, + {20, 64 * time.Second}, } for _, c := range cases { @@ -1753,6 +1794,7 @@ func Test_Leader_PeeringSync_ServerAddressUpdates(t *testing.T) { conn, err := grpc.DialContext(ctx, acceptor.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(acceptor.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -1780,6 +1822,7 @@ func Test_Leader_PeeringSync_ServerAddressUpdates(t *testing.T) { conn, err = grpc.DialContext(ctx, dialer.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(dialer.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -1893,6 +1936,7 @@ func Test_Leader_PeeringSync_PeerThroughMeshGateways_ServerFallBack(t *testing.T conn, err := grpc.DialContext(ctx, acceptor.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(acceptor.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -1936,11 +1980,13 @@ func Test_Leader_PeeringSync_PeerThroughMeshGateways_ServerFallBack(t *testing.T })) // Create a peering at dialer by establishing a peering with acceptor's token - ctx, cancel = context.WithTimeout(context.Background(), 3*time.Second) + // 7 second = 1 second wait + 3 second gw retry + 3 second token addr retry + ctx, cancel = context.WithTimeout(context.Background(), 7*time.Second) t.Cleanup(cancel) conn, err = grpc.DialContext(ctx, dialer.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(dialer.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -1994,6 +2040,7 @@ func Test_Leader_PeeringSync_PeerThroughMeshGateways_Success(t *testing.T) { conn, err := grpc.DialContext(ctx, acceptor.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(acceptor.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -2061,6 +2108,7 @@ func Test_Leader_PeeringSync_PeerThroughMeshGateways_Success(t *testing.T) { conn, err = grpc.DialContext(ctx, dialer.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(dialer.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) diff --git a/agent/consul/leader_test.go b/agent/consul/leader_test.go index 35bc924b7a39..c9f2327ea45b 100644 --- a/agent/consul/leader_test.go +++ b/agent/consul/leader_test.go @@ -1256,49 +1256,82 @@ func TestLeader_ACL_Initialization(t *testing.T) { tests := []struct { name string - build string initialManagement string - bootstrap bool + hcpManagement string + + // canBootstrap tracks whether the ACL system can be bootstrapped + // after the leader initializes ACLs. Bootstrapping is the act + // of persisting a token with the Global Management policy. + canBootstrap bool }{ - {"old version, no initial management", "0.8.0", "", true}, - {"old version, initial management", "0.8.0", "root", false}, - {"new version, no initial management", "0.9.1", "", true}, - {"new version, initial management", "0.9.1", "root", false}, + { + name: "bootstrap from initial management", + initialManagement: "c9ad785a-420d-470d-9b4d-6d9f084bfa87", + hcpManagement: "", + canBootstrap: false, + }, + { + name: "bootstrap from hcp management", + initialManagement: "", + hcpManagement: "924bc0e1-a41b-4f3a-b5e8-0899502fc50e", + canBootstrap: false, + }, + { + name: "bootstrap with both", + initialManagement: "c9ad785a-420d-470d-9b4d-6d9f084bfa87", + hcpManagement: "924bc0e1-a41b-4f3a-b5e8-0899502fc50e", + canBootstrap: false, + }, + { + name: "did not bootstrap", + initialManagement: "", + hcpManagement: "", + canBootstrap: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { conf := func(c *Config) { - c.Build = tt.build c.Bootstrap = true c.Datacenter = "dc1" c.PrimaryDatacenter = "dc1" c.ACLsEnabled = true c.ACLInitialManagementToken = tt.initialManagement + c.Cloud.ManagementToken = tt.hcpManagement } - dir1, s1 := testServerWithConfig(t, conf) - defer os.RemoveAll(dir1) - defer s1.Shutdown() + _, s1 := testServerWithConfig(t, conf) testrpc.WaitForTestAgent(t, s1.RPC, "dc1") + // check that the builtin policies were created + for _, builtinPolicy := range structs.ACLBuiltinPolicies { + _, policy, err := s1.fsm.State().ACLPolicyGetByID(nil, builtinPolicy.ID, nil) + require.NoError(t, err) + require.NotNil(t, policy) + } + if tt.initialManagement != "" { _, initialManagement, err := s1.fsm.State().ACLTokenGetBySecret(nil, tt.initialManagement, nil) require.NoError(t, err) require.NotNil(t, initialManagement) + require.Equal(t, tt.initialManagement, initialManagement.SecretID) } - _, anon, err := s1.fsm.State().ACLTokenGetBySecret(nil, anonymousToken, nil) - require.NoError(t, err) - require.NotNil(t, anon) + if tt.hcpManagement != "" { + _, hcpManagement, err := s1.fsm.State().ACLTokenGetBySecret(nil, tt.hcpManagement, nil) + require.NoError(t, err) + require.NotNil(t, hcpManagement) + require.Equal(t, tt.hcpManagement, hcpManagement.SecretID) + } canBootstrap, _, err := s1.fsm.State().CanBootstrapACLToken() require.NoError(t, err) - require.Equal(t, tt.bootstrap, canBootstrap) + require.Equal(t, tt.canBootstrap, canBootstrap) - _, policy, err := s1.fsm.State().ACLPolicyGetByID(nil, structs.ACLPolicyGlobalManagementID, nil) + _, anon, err := s1.fsm.State().ACLTokenGetBySecret(nil, anonymousToken, nil) require.NoError(t, err) - require.NotNil(t, policy) + require.NotNil(t, anon) - serverToken, err := s1.getSystemMetadata(structs.ServerManagementTokenAccessorID) + serverToken, err := s1.GetSystemMetadata(structs.ServerManagementTokenAccessorID) require.NoError(t, err) require.NotEmpty(t, serverToken) @@ -1308,6 +1341,51 @@ func TestLeader_ACL_Initialization(t *testing.T) { } } +func TestLeader_ACL_Initialization_SecondaryDC(t *testing.T) { + if testing.Short() { + t.Skip("too slow for testing.Short") + } + + t.Parallel() + + dir1, s1 := testServerWithConfig(t, func(c *Config) { + c.Bootstrap = true + c.Datacenter = "dc1" + c.PrimaryDatacenter = "dc1" + c.ACLsEnabled = true + }) + defer os.RemoveAll(dir1) + defer s1.Shutdown() + testrpc.WaitForTestAgent(t, s1.RPC, "dc1") + + dir2, s2 := testServerWithConfig(t, func(c *Config) { + c.Bootstrap = true + c.Datacenter = "dc2" + c.PrimaryDatacenter = "dc1" + c.ACLsEnabled = true + }) + defer os.RemoveAll(dir2) + defer s2.Shutdown() + testrpc.WaitForTestAgent(t, s2.RPC, "dc2") + + // Check dc1's management token + serverToken1, err := s1.GetSystemMetadata(structs.ServerManagementTokenAccessorID) + require.NoError(t, err) + require.NotEmpty(t, serverToken1) + _, err = uuid.ParseUUID(serverToken1) + require.NoError(t, err) + + // Check dc2's management token + serverToken2, err := s2.GetSystemMetadata(structs.ServerManagementTokenAccessorID) + require.NoError(t, err) + require.NotEmpty(t, serverToken2) + _, err = uuid.ParseUUID(serverToken2) + require.NoError(t, err) + + // Ensure the tokens were not replicated between clusters. + require.NotEqual(t, serverToken1, serverToken2) +} + func TestLeader_ACLUpgrade_IsStickyEvenIfSerfTagsRegress(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short") @@ -1359,15 +1437,17 @@ func TestLeader_ACLUpgrade_IsStickyEvenIfSerfTagsRegress(t *testing.T) { waitForLeaderEstablishment(t, s2) waitForNewACLReplication(t, s2, structs.ACLReplicatePolicies, 1, 0, 0) - // Everybody has the management policy. + // Everybody has the builtin policies. retry.Run(t, func(r *retry.R) { - _, policy1, err := s1.fsm.State().ACLPolicyGetByID(nil, structs.ACLPolicyGlobalManagementID, structs.DefaultEnterpriseMetaInDefaultPartition()) - require.NoError(r, err) - require.NotNil(r, policy1) + for _, builtinPolicy := range structs.ACLBuiltinPolicies { + _, policy1, err := s1.fsm.State().ACLPolicyGetByID(nil, builtinPolicy.ID, structs.DefaultEnterpriseMetaInDefaultPartition()) + require.NoError(r, err) + require.NotNil(r, policy1) - _, policy2, err := s2.fsm.State().ACLPolicyGetByID(nil, structs.ACLPolicyGlobalManagementID, structs.DefaultEnterpriseMetaInDefaultPartition()) - require.NoError(r, err) - require.NotNil(r, policy2) + _, policy2, err := s2.fsm.State().ACLPolicyGetByID(nil, builtinPolicy.ID, structs.DefaultEnterpriseMetaInDefaultPartition()) + require.NoError(r, err) + require.NotNil(r, policy2) + } }) // Shutdown s1 and s2. diff --git a/agent/consul/merge_oss.go b/agent/consul/merge_ce.go similarity index 100% rename from agent/consul/merge_oss.go rename to agent/consul/merge_ce.go diff --git a/agent/consul/merge_oss_test.go b/agent/consul/merge_ce_test.go similarity index 97% rename from agent/consul/merge_oss_test.go rename to agent/consul/merge_ce_test.go index 99333c7dd842..f046300de672 100644 --- a/agent/consul/merge_oss_test.go +++ b/agent/consul/merge_ce_test.go @@ -13,7 +13,7 @@ import ( "github.com/hashicorp/consul/types" ) -func TestMerge_OSS_LAN(t *testing.T) { +func TestMerge_CE_LAN(t *testing.T) { type testcase struct { segment string server bool diff --git a/agent/consul/operator_raft_endpoint.go b/agent/consul/operator_raft_endpoint.go index 328f8ff964e0..f5678fffdde5 100644 --- a/agent/consul/operator_raft_endpoint.go +++ b/agent/consul/operator_raft_endpoint.go @@ -45,6 +45,12 @@ func (op *Operator) RaftGetConfiguration(args *structs.DCSpecificRequest, reply serverMap[raft.ServerAddress(addr)] = member } + serverIDLastIndexMap := make(map[raft.ServerID]uint64) + + for _, serverState := range op.srv.autopilot.GetState().Servers { + serverIDLastIndexMap[serverState.Server.ID] = serverState.Stats.LastIndex + } + // Fill out the reply. leader := op.srv.raft.Leader() reply.Index = future.Index() @@ -63,6 +69,7 @@ func (op *Operator) RaftGetConfiguration(args *structs.DCSpecificRequest, reply Leader: server.Address == leader, Voter: server.Suffrage == raft.Voter, ProtocolVersion: raftProtocolVersion, + LastIndex: serverIDLastIndexMap[server.ID], } reply.Servers = append(reply.Servers, entry) } diff --git a/agent/consul/operator_raft_endpoint_test.go b/agent/consul/operator_raft_endpoint_test.go index be60ec66a317..e4f322130a75 100644 --- a/agent/consul/operator_raft_endpoint_test.go +++ b/agent/consul/operator_raft_endpoint_test.go @@ -47,6 +47,13 @@ func TestOperator_RaftGetConfiguration(t *testing.T) { if len(future.Configuration().Servers) != 1 { t.Fatalf("bad: %v", future.Configuration().Servers) } + + serverIDLastIndexMap := make(map[raft.ServerID]uint64) + + for _, serverState := range s1.autopilot.GetState().Servers { + serverIDLastIndexMap[serverState.Server.ID] = serverState.Stats.LastIndex + } + me := future.Configuration().Servers[0] expected := structs.RaftConfigurationResponse{ Servers: []*structs.RaftServer{ @@ -57,6 +64,7 @@ func TestOperator_RaftGetConfiguration(t *testing.T) { Leader: true, Voter: true, ProtocolVersion: "3", + LastIndex: serverIDLastIndexMap[me.ID], }, }, Index: future.Index(), @@ -110,6 +118,10 @@ func TestOperator_RaftGetConfiguration_ACLDeny(t *testing.T) { if len(future.Configuration().Servers) != 1 { t.Fatalf("bad: %v", future.Configuration().Servers) } + serverIDLastIndexMap := make(map[raft.ServerID]uint64) + for _, serverState := range s1.autopilot.GetState().Servers { + serverIDLastIndexMap[serverState.Server.ID] = serverState.Stats.LastIndex + } me := future.Configuration().Servers[0] expected := structs.RaftConfigurationResponse{ Servers: []*structs.RaftServer{ @@ -120,6 +132,7 @@ func TestOperator_RaftGetConfiguration_ACLDeny(t *testing.T) { Leader: true, Voter: true, ProtocolVersion: "3", + LastIndex: serverIDLastIndexMap[me.ID], }, }, Index: future.Index(), diff --git a/agent/consul/options_oss.go b/agent/consul/options_ce.go similarity index 100% rename from agent/consul/options_oss.go rename to agent/consul/options_ce.go diff --git a/agent/consul/peering_backend.go b/agent/consul/peering_backend.go index ba3c387ad53f..aa18cfd04aee 100644 --- a/agent/consul/peering_backend.go +++ b/agent/consul/peering_backend.go @@ -106,27 +106,38 @@ func (b *PeeringBackend) GetLocalServerAddresses() ([]string, error) { } // GetDialAddresses returns: the addresses to cycle through when dialing a peer's servers, -// a boolean indicating whether mesh gateways are present, and an optional error. +// an optional buffer of just gateway addresses, and an optional error. // The resulting ring buffer is front-loaded with the local mesh gateway addresses if they are present. -func (b *PeeringBackend) GetDialAddresses(logger hclog.Logger, ws memdb.WatchSet, peerID string) (*ring.Ring, bool, error) { +func (b *PeeringBackend) GetDialAddresses(logger hclog.Logger, ws memdb.WatchSet, peerID string) (*ring.Ring, *ring.Ring, error) { newRing, err := b.fetchPeerServerAddresses(ws, peerID) if err != nil { - return nil, false, fmt.Errorf("failed to refresh peer server addresses, will continue to use initial addresses: %w", err) + return nil, nil, fmt.Errorf("failed to refresh peer server addresses, will continue to use initial addresses: %w", err) } gatewayRing, err := b.maybeFetchGatewayAddresses(ws) if err != nil { // If we couldn't fetch the mesh gateway addresses we fall back to dialing the remote server addresses. - logger.Warn("failed to refresh local gateway addresses, will attempt to dial peer directly: %w", "error", err) - return newRing, false, nil + logger.Warn("failed to refresh local gateway addresses, will attempt to dial peer directly", "error", err) + return newRing, nil, nil } if gatewayRing != nil { // The ordering is important here. We always want to start with the mesh gateway // addresses and fallback to the remote addresses, so we append the server addresses - // in newRing to gatewayRing. - newRing = gatewayRing.Link(newRing) + // in newRing to gatewayRing. We also need a new ring to prevent mixing up pointers + // with the gateway-only buffer + compositeRing := ring.New(gatewayRing.Len() + newRing.Len()) + gatewayRing.Do(func(s any) { + compositeRing.Value = s.(string) + compositeRing = compositeRing.Next() + }) + + newRing.Do(func(s any) { + compositeRing.Value = s.(string) + compositeRing = compositeRing.Next() + }) + newRing = compositeRing } - return newRing, gatewayRing != nil, nil + return newRing, gatewayRing, nil } // fetchPeerServerAddresses will return a ring buffer with the latest peer server addresses. @@ -136,10 +147,13 @@ func (b *PeeringBackend) fetchPeerServerAddresses(ws memdb.WatchSet, peerID stri if err != nil { return nil, fmt.Errorf("failed to fetch peer %q: %w", peerID, err) } - if !peering.IsActive() { - return nil, fmt.Errorf("there is no active peering for %q", peerID) + if peering == nil { + return nil, fmt.Errorf("unknown peering %q", peerID) } - return bufferFromAddresses(peering.PeerServerAddresses) + if peering.DeletedAt != nil && !structs.IsZeroProtoTime(peering.DeletedAt) { + return nil, fmt.Errorf("peering %q was deleted", peerID) + } + return bufferFromAddresses(peering.GetAddressesToDial()) } // maybeFetchGatewayAddresses will return a ring buffer with the latest gateway addresses if the diff --git a/agent/consul/peering_backend_oss.go b/agent/consul/peering_backend_ce.go similarity index 100% rename from agent/consul/peering_backend_oss.go rename to agent/consul/peering_backend_ce.go diff --git a/agent/consul/peering_backend_oss_test.go b/agent/consul/peering_backend_ce_test.go similarity index 98% rename from agent/consul/peering_backend_oss_test.go rename to agent/consul/peering_backend_ce_test.go index 11466581b3e4..a9305de5ffa5 100644 --- a/agent/consul/peering_backend_oss_test.go +++ b/agent/consul/peering_backend_ce_test.go @@ -46,6 +46,7 @@ func TestPeeringBackend_RejectsPartition(t *testing.T) { conn, err := gogrpc.DialContext(ctx, s1.config.RPCAddr.String(), gogrpc.WithContextDialer(newServerDialer(s1.config.RPCAddr.String())), + //nolint:staticcheck gogrpc.WithInsecure(), gogrpc.WithBlock()) require.NoError(t, err) @@ -88,6 +89,7 @@ func TestPeeringBackend_IgnoresDefaultPartition(t *testing.T) { conn, err := gogrpc.DialContext(ctx, s1.config.RPCAddr.String(), gogrpc.WithContextDialer(newServerDialer(s1.config.RPCAddr.String())), + //nolint:staticcheck gogrpc.WithInsecure(), gogrpc.WithBlock()) require.NoError(t, err) diff --git a/agent/consul/peering_backend_test.go b/agent/consul/peering_backend_test.go index e8218bc43176..1e859049dea9 100644 --- a/agent/consul/peering_backend_test.go +++ b/agent/consul/peering_backend_test.go @@ -9,6 +9,8 @@ import ( gogrpc "google.golang.org/grpc" + "github.com/stretchr/testify/require" + "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/consul/state" @@ -20,7 +22,6 @@ import ( "github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/testrpc" "github.com/hashicorp/consul/types" - "github.com/stretchr/testify/require" ) func TestPeeringBackend_ForwardToLeader(t *testing.T) { @@ -58,6 +59,7 @@ func TestPeeringBackend_ForwardToLeader(t *testing.T) { // Dial server2 directly conn, err := gogrpc.DialContext(ctx, server2.config.RPCAddr.String(), gogrpc.WithContextDialer(newServerDialer(server2.config.RPCAddr.String())), + //nolint:staticcheck gogrpc.WithInsecure(), gogrpc.WithBlock()) require.NoError(t, err) @@ -196,7 +198,7 @@ func TestPeeringBackend_GetDialAddresses(t *testing.T) { type expectation struct { addrs []string - haveGateways bool + gatewayAddrs []string err string } @@ -212,14 +214,25 @@ func TestPeeringBackend_GetDialAddresses(t *testing.T) { tc.setup(srv.fsm.State()) } - ring, haveGateways, err := backend.GetDialAddresses(testutil.Logger(t), nil, tc.peerID) + ring, gatewayRing, err := backend.GetDialAddresses(testutil.Logger(t), nil, tc.peerID) if tc.expect.err != "" { testutil.RequireErrorContains(t, err, tc.expect.err) return } - require.Equal(t, tc.expect.haveGateways, haveGateways) + require.Equal(t, len(tc.expect.gatewayAddrs) > 0, gatewayRing != nil) require.NotNil(t, ring) + if len(tc.expect.gatewayAddrs) > 0 { + var addrs []string + gatewayRing.Do(func(value any) { + addr, ok := value.(string) + + require.True(t, ok) + addrs = append(addrs, addr) + }) + require.Equal(t, tc.expect.gatewayAddrs, addrs) + } + var addrs []string ring.Do(func(value any) { addr, ok := value.(string) @@ -239,7 +252,7 @@ func TestPeeringBackend_GetDialAddresses(t *testing.T) { }, peerID: acceptorPeerID, expect: expectation{ - err: fmt.Sprintf(`there is no active peering for %q`, acceptorPeerID), + err: fmt.Sprintf(`unknown peering %q`, acceptorPeerID), }, }, { @@ -258,6 +271,24 @@ func TestPeeringBackend_GetDialAddresses(t *testing.T) { err: "no known addresses", }, }, + { + name: "manual server addrs are returned when defined", + setup: func(store *state.Store) { + require.NoError(t, store.PeeringWrite(2, &pbpeering.PeeringWriteRequest{ + Peering: &pbpeering.Peering{ + Name: "dialer", + ID: dialerPeerID, + ManualServerAddresses: []string{"5.6.7.8:8502"}, + PeerServerAddresses: []string{"1.2.3.4:8502", "2.3.4.5:8503"}, + }, + })) + // Mesh config entry does not exist + }, + peerID: dialerPeerID, + expect: expectation{ + addrs: []string{"5.6.7.8:8502"}, + }, + }, { name: "only server addrs are returned when mesh config does not exist", setup: func(store *state.Store) { @@ -273,8 +304,7 @@ func TestPeeringBackend_GetDialAddresses(t *testing.T) { }, peerID: dialerPeerID, expect: expectation{ - haveGateways: false, - addrs: []string{"1.2.3.4:8502", "2.3.4.5:8503"}, + addrs: []string{"1.2.3.4:8502", "2.3.4.5:8503"}, }, }, { @@ -288,8 +318,7 @@ func TestPeeringBackend_GetDialAddresses(t *testing.T) { }, peerID: dialerPeerID, expect: expectation{ - haveGateways: false, - addrs: []string{"1.2.3.4:8502", "2.3.4.5:8503"}, + addrs: []string{"1.2.3.4:8502", "2.3.4.5:8503"}, }, }, { @@ -305,8 +334,6 @@ func TestPeeringBackend_GetDialAddresses(t *testing.T) { }, peerID: dialerPeerID, expect: expectation{ - haveGateways: false, - // Fall back to remote server addresses addrs: []string{"1.2.3.4:8502", "2.3.4.5:8503"}, }, @@ -351,10 +378,28 @@ func TestPeeringBackend_GetDialAddresses(t *testing.T) { }, peerID: dialerPeerID, expect: expectation{ - haveGateways: true, - // Gateways come first, and we use their LAN addresses since this is for outbound communication. - addrs: []string{"6.7.8.9:8443", "5.6.7.8:8443", "1.2.3.4:8502", "2.3.4.5:8503"}, + addrs: []string{"5.6.7.8:8443", "6.7.8.9:8443", "1.2.3.4:8502", "2.3.4.5:8503"}, + gatewayAddrs: []string{"5.6.7.8:8443", "6.7.8.9:8443"}, + }, + }, + { + name: "addresses are returned if the peering is marked as terminated", + setup: func(store *state.Store) { + require.NoError(t, store.PeeringWrite(5, &pbpeering.PeeringWriteRequest{ + Peering: &pbpeering.Peering{ + Name: "dialer", + ID: dialerPeerID, + PeerServerAddresses: []string{"1.2.3.4:8502", "2.3.4.5:8503"}, + State: pbpeering.PeeringState_TERMINATED, + }, + })) + }, + peerID: dialerPeerID, + expect: expectation{ + // Gateways come first, and we use their LAN addresses since this is for outbound communication. + addrs: []string{"5.6.7.8:8443", "6.7.8.9:8443", "1.2.3.4:8502", "2.3.4.5:8503"}, + gatewayAddrs: []string{"5.6.7.8:8443", "6.7.8.9:8443"}, }, }, { @@ -374,7 +419,7 @@ func TestPeeringBackend_GetDialAddresses(t *testing.T) { }, peerID: dialerPeerID, expect: expectation{ - err: fmt.Sprintf(`there is no active peering for %q`, dialerPeerID), + err: fmt.Sprintf(`peering %q was deleted`, dialerPeerID), }, }, } @@ -459,6 +504,7 @@ func TestPeerStreamService_ForwardToLeader(t *testing.T) { // We will dial server2 which should forward to server1 conn, err := gogrpc.DialContext(ctx, server2.config.RPCAddr.String(), gogrpc.WithContextDialer(newServerDialer(server2.config.RPCAddr.String())), + //nolint:staticcheck gogrpc.WithInsecure(), gogrpc.WithBlock()) require.NoError(t, err) diff --git a/agent/consul/prepared_query/walk_oss_test.go b/agent/consul/prepared_query/walk_ce_test.go similarity index 100% rename from agent/consul/prepared_query/walk_oss_test.go rename to agent/consul/prepared_query/walk_ce_test.go diff --git a/agent/consul/prepared_query_endpoint.go b/agent/consul/prepared_query_endpoint.go index ffa4b5e50915..2d6384c39d22 100644 --- a/agent/consul/prepared_query_endpoint.go +++ b/agent/consul/prepared_query_endpoint.go @@ -305,9 +305,9 @@ func (p *PreparedQuery) Explain(args *structs.PreparedQueryExecuteRequest, defer metrics.MeasureSince([]string{"prepared-query", "explain"}, time.Now()) // We have to do this ourselves since we are not doing a blocking RPC. - p.srv.setQueryMeta(&reply.QueryMeta, args.Token) + p.srv.SetQueryMeta(&reply.QueryMeta, args.Token) if args.RequireConsistent { - if err := p.srv.consistentRead(); err != nil { + if err := p.srv.ConsistentRead(); err != nil { return err } } @@ -353,7 +353,7 @@ func (p *PreparedQuery) Execute(args *structs.PreparedQueryExecuteRequest, // We have to do this ourselves since we are not doing a blocking RPC. if args.RequireConsistent { - if err := p.srv.consistentRead(); err != nil { + if err := p.srv.ConsistentRead(); err != nil { return err } } @@ -389,7 +389,7 @@ func (p *PreparedQuery) Execute(args *structs.PreparedQueryExecuteRequest, // though, since this is essentially a misconfiguration. // We have to do this ourselves since we are not doing a blocking RPC. - p.srv.setQueryMeta(&reply.QueryMeta, token) + p.srv.SetQueryMeta(&reply.QueryMeta, token) // Shuffle the results in case coordinates are not available if they // requested an RTT sort. @@ -468,7 +468,7 @@ func (p *PreparedQuery) Execute(args *structs.PreparedQueryExecuteRequest, // by the query setup. if len(reply.Nodes) == 0 { wrapper := &queryServerWrapper{srv: p.srv, executeRemote: p.ExecuteRemote} - if err := queryFailover(wrapper, query, args, reply); err != nil { + if err := queryFailover(wrapper, *query, args, reply); err != nil { return err } } @@ -490,7 +490,7 @@ func (p *PreparedQuery) ExecuteRemote(args *structs.PreparedQueryExecuteRemoteRe // We have to do this ourselves since we are not doing a blocking RPC. if args.RequireConsistent { - if err := p.srv.consistentRead(); err != nil { + if err := p.srv.ConsistentRead(); err != nil { return err } } @@ -511,7 +511,7 @@ func (p *PreparedQuery) ExecuteRemote(args *structs.PreparedQueryExecuteRemoteRe } // We have to do this ourselves since we are not doing a blocking RPC. - p.srv.setQueryMeta(&reply.QueryMeta, token) + p.srv.SetQueryMeta(&reply.QueryMeta, token) // We don't bother trying to do an RTT sort here since we are by // definition in another DC. We just shuffle to make sure that we @@ -707,7 +707,7 @@ func (q *queryServerWrapper) GetOtherDatacentersByDistance() ([]string, error) { // queryFailover runs an algorithm to determine which DCs to try and then calls // them to try to locate alternative services. -func queryFailover(q queryServer, query *structs.PreparedQuery, +func queryFailover(q queryServer, query structs.PreparedQuery, args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExecuteResponse) error { @@ -789,7 +789,7 @@ func queryFailover(q queryServer, query *structs.PreparedQuery, // the remote query as well. remote := &structs.PreparedQueryExecuteRemoteRequest{ Datacenter: dc, - Query: *query, + Query: query, Limit: args.Limit, QueryOptions: args.QueryOptions, Connect: args.Connect, diff --git a/agent/consul/prepared_query_endpoint_test.go b/agent/consul/prepared_query_endpoint_test.go index 108a56849877..5e20d6976bfb 100644 --- a/agent/consul/prepared_query_endpoint_test.go +++ b/agent/consul/prepared_query_endpoint_test.go @@ -19,7 +19,6 @@ import ( msgpackrpc "github.com/hashicorp/consul-net-rpc/net-rpc-msgpackrpc" "github.com/hashicorp/consul-net-rpc/net/rpc" - "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/connect" grpcexternal "github.com/hashicorp/consul/agent/grpc-external" @@ -1517,6 +1516,7 @@ func TestPreparedQuery_Execute(t *testing.T) { conn, err := grpc.DialContext(ctx, s3.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(s3.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -1531,6 +1531,7 @@ func TestPreparedQuery_Execute(t *testing.T) { conn, err = grpc.DialContext(ctx, s1.config.RPCAddr.String(), grpc.WithContextDialer(newServerDialer(s1.config.RPCAddr.String())), + //nolint:staticcheck grpc.WithInsecure(), grpc.WithBlock()) require.NoError(t, err) @@ -1576,7 +1577,7 @@ func TestPreparedQuery_Execute(t *testing.T) { execNoNodesToken := createTokenWithPolicyName(t, codec1, "no-nodes", `service_prefix "foo" { policy = "read" }`, "root") rules := ` - service_prefix "foo" { policy = "read" } + service_prefix "" { policy = "read" } node_prefix "" { policy = "read" } ` execToken := createTokenWithPolicyName(t, codec1, "with-read", rules, "root") @@ -1674,8 +1675,7 @@ func TestPreparedQuery_Execute(t *testing.T) { assert.Len(t, reply.Nodes, 0) }) - expectNodes := func(t *testing.T, query *structs.PreparedQueryRequest, reply *structs.PreparedQueryExecuteResponse, n int) { - t.Helper() + expectNodes := func(t require.TestingT, query *structs.PreparedQueryRequest, reply *structs.PreparedQueryExecuteResponse, n int) { assert.Len(t, reply.Nodes, n) assert.Equal(t, "dc1", reply.Datacenter) assert.Equal(t, 0, reply.Failovers) @@ -1683,8 +1683,7 @@ func TestPreparedQuery_Execute(t *testing.T) { assert.Equal(t, query.Query.DNS, reply.DNS) assert.True(t, reply.QueryMeta.KnownLeader) } - expectFailoverNodes := func(t *testing.T, query *structs.PreparedQueryRequest, reply *structs.PreparedQueryExecuteResponse, n int) { - t.Helper() + expectFailoverNodes := func(t require.TestingT, query *structs.PreparedQueryRequest, reply *structs.PreparedQueryExecuteResponse, n int) { assert.Len(t, reply.Nodes, n) assert.Equal(t, "dc2", reply.Datacenter) assert.Equal(t, 1, reply.Failovers) @@ -1693,8 +1692,7 @@ func TestPreparedQuery_Execute(t *testing.T) { assert.True(t, reply.QueryMeta.KnownLeader) } - expectFailoverPeerNodes := func(t *testing.T, query *structs.PreparedQueryRequest, reply *structs.PreparedQueryExecuteResponse, n int) { - t.Helper() + expectFailoverPeerNodes := func(t require.TestingT, query *structs.PreparedQueryRequest, reply *structs.PreparedQueryExecuteResponse, n int) { assert.Len(t, reply.Nodes, n) assert.Equal(t, "", reply.Datacenter) assert.Equal(t, acceptingPeerName, reply.PeerName) @@ -2090,16 +2088,16 @@ func TestPreparedQuery_Execute(t *testing.T) { require.NoError(t, msgpackrpc.CallWithCodec(codec1, "PreparedQuery.Apply", &query, &query.Query.ID)) // Update the health of a node to mark it critical. - setHealth := func(t *testing.T, codec rpc.ClientCodec, dc string, node string, health string) { + setHealth := func(t *testing.T, codec rpc.ClientCodec, dc string, i int, health string) { t.Helper() req := structs.RegisterRequest{ Datacenter: dc, - Node: node, + Node: fmt.Sprintf("node%d", i), Address: "127.0.0.1", Service: &structs.NodeService{ Service: "foo", Port: 8000, - Tags: []string{"dc1", "tag1"}, + Tags: []string{dc, fmt.Sprintf("tag%d", i)}, }, Check: &structs.HealthCheck{ Name: "failing", @@ -2111,7 +2109,7 @@ func TestPreparedQuery_Execute(t *testing.T) { var reply struct{} require.NoError(t, msgpackrpc.CallWithCodec(codec, "Catalog.Register", &req, &reply)) } - setHealth(t, codec1, "dc1", "node1", api.HealthCritical) + setHealth(t, codec1, "dc1", 1, api.HealthCritical) // The failing node should be filtered. t.Run("failing node filtered", func(t *testing.T) { @@ -2131,7 +2129,7 @@ func TestPreparedQuery_Execute(t *testing.T) { }) // Upgrade it to a warning and re-query, should be 10 nodes again. - setHealth(t, codec1, "dc1", "node1", api.HealthWarning) + setHealth(t, codec1, "dc1", 1, api.HealthWarning) t.Run("warning nodes are included", func(t *testing.T) { req := structs.PreparedQueryExecuteRequest{ Datacenter: "dc1", @@ -2301,7 +2299,7 @@ func TestPreparedQuery_Execute(t *testing.T) { // Now fail everything in dc1 and we should get an empty list back. for i := 0; i < 10; i++ { - setHealth(t, codec1, "dc1", fmt.Sprintf("node%d", i+1), api.HealthCritical) + setHealth(t, codec1, "dc1", i+1, api.HealthCritical) } t.Run("everything is failing so should get empty list", func(t *testing.T) { req := structs.PreparedQueryExecuteRequest{ @@ -2472,7 +2470,7 @@ func TestPreparedQuery_Execute(t *testing.T) { // Set all checks in dc2 as critical for i := 0; i < 10; i++ { - setHealth(t, codec2, "dc2", fmt.Sprintf("node%d", i+1), api.HealthCritical) + setHealth(t, codec2, "dc2", i+1, api.HealthCritical) } // Now we should see 9 nodes from dc3 (we have the tag filter still) @@ -2491,6 +2489,31 @@ func TestPreparedQuery_Execute(t *testing.T) { } expectFailoverPeerNodes(t, &query, &reply, 9) }) + + // Set all checks in dc1 as passing + for i := 0; i < 10; i++ { + setHealth(t, codec1, "dc1", i+1, api.HealthPassing) + } + + // Nothing is healthy so nothing is returned + t.Run("un-failing over", func(t *testing.T) { + retry.Run(t, func(r *retry.R) { + req := structs.PreparedQueryExecuteRequest{ + Datacenter: "dc1", + QueryIDOrName: query.Query.ID, + QueryOptions: structs.QueryOptions{Token: execToken}, + } + + var reply structs.PreparedQueryExecuteResponse + require.NoError(r, msgpackrpc.CallWithCodec(codec1, "PreparedQuery.Execute", &req, &reply)) + + for _, node := range reply.Nodes { + assert.NotEqual(r, "node3", node.Node.Node) + } + + expectNodes(r, &query, &reply, 9) + }) + }) } func TestPreparedQuery_Execute_ForwardLeader(t *testing.T) { @@ -2980,7 +3003,7 @@ func (m *mockQueryServer) ExecuteRemote(args *structs.PreparedQueryExecuteRemote func TestPreparedQuery_queryFailover(t *testing.T) { t.Parallel() - query := &structs.PreparedQuery{ + query := structs.PreparedQuery{ Name: "test", Service: structs.ServiceQuery{ Failover: structs.QueryFailoverOptions{ diff --git a/agent/consul/reporting/reporting.go b/agent/consul/reporting/reporting.go new file mode 100644 index 000000000000..94f780ec0602 --- /dev/null +++ b/agent/consul/reporting/reporting.go @@ -0,0 +1,52 @@ +package reporting + +import ( + "sync" + "time" + + "github.com/hashicorp/consul/agent/consul/state" + "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-memdb" +) + +type ReportingManager struct { + logger hclog.Logger + server ServerDelegate + stateProvider StateDelegate + tickerInterval time.Duration + EntDeps + sync.RWMutex +} + +const ( + SystemMetadataReportingProcessID = "reporting-process-id" + ReportingInterval = 1 * time.Hour +) + +//go:generate mockery --name ServerDelegate --inpackage +type ServerDelegate interface { + GetSystemMetadata(key string) (string, error) + SetSystemMetadataKey(key, val string) error + IsLeader() bool +} + +type StateDelegate interface { + NodeUsage() (uint64, state.NodeUsage, error) + ServiceUsage(ws memdb.WatchSet) (uint64, structs.ServiceUsage, error) +} + +func NewReportingManager(logger hclog.Logger, deps EntDeps, server ServerDelegate, stateProvider StateDelegate) *ReportingManager { + rm := &ReportingManager{ + logger: logger.Named("reporting"), + server: server, + stateProvider: stateProvider, + tickerInterval: ReportingInterval, + } + err := rm.initEnterpriseReporting(deps) + if err != nil { + rm.logger.Error("Error initializing reporting manager", "error", err) + return nil + } + return rm +} diff --git a/agent/consul/reporting/reporting_ce.go b/agent/consul/reporting/reporting_ce.go new file mode 100644 index 000000000000..240500d6d509 --- /dev/null +++ b/agent/consul/reporting/reporting_ce.go @@ -0,0 +1,29 @@ +//go:build !consulent +// +build !consulent + +package reporting + +import ( + "context" +) + +type EntDeps struct{} + +func (rm *ReportingManager) initEnterpriseReporting(entDeps EntDeps) error { + // no op + return nil +} + +func (rm *ReportingManager) StartReportingAgent() error { + // no op + return nil +} + +func (rm *ReportingManager) StopReportingAgent() error { + // no op + return nil +} + +func (m *ReportingManager) Run(ctx context.Context) { + // no op +} diff --git a/agent/consul/rpc.go b/agent/consul/rpc.go index d6fa9fae4925..76f2181fe3d6 100644 --- a/agent/consul/rpc.go +++ b/agent/consul/rpc.go @@ -1,7 +1,6 @@ package consul import ( - "context" "crypto/tls" "encoding/binary" "errors" @@ -9,14 +8,13 @@ import ( "io" "net" "strings" - "sync/atomic" "time" "github.com/armon/go-metrics" "github.com/armon/go-metrics/prometheus" - connlimit "github.com/hashicorp/go-connlimit" + "github.com/hashicorp/go-connlimit" "github.com/hashicorp/go-hclog" - memdb "github.com/hashicorp/go-memdb" + "github.com/hashicorp/go-memdb" "github.com/hashicorp/go-raftchunking" "github.com/hashicorp/memberlist" "github.com/hashicorp/raft" @@ -26,6 +24,7 @@ import ( msgpackrpc "github.com/hashicorp/consul-net-rpc/net-rpc-msgpackrpc" "github.com/hashicorp/consul/acl" + "github.com/hashicorp/consul/agent/blockingquery" "github.com/hashicorp/consul/agent/consul/state" "github.com/hashicorp/consul/agent/consul/wanfed" "github.com/hashicorp/consul/agent/metadata" @@ -954,167 +953,26 @@ type blockingQueryResponseMeta interface { SetResultsFilteredByACLs(bool) } -// blockingQuery performs a blocking query if opts.GetMinQueryIndex is -// greater than 0, otherwise performs a non-blocking query. Blocking queries will -// block until responseMeta.Index is greater than opts.GetMinQueryIndex, -// or opts.GetMaxQueryTime is reached. Non-blocking queries return immediately -// after performing the query. -// -// If opts.GetRequireConsistent is true, blockingQuery will first verify it is -// still the cluster leader before performing the query. -// -// The query function is expected to be a closure that has access to responseMeta -// so that it can set the Index. The actual result of the query is opaque to blockingQuery. -// -// The query function can return errNotFound, which is a sentinel error. Returning -// errNotFound indicates that the query found no results, which allows -// blockingQuery to keep blocking until the query returns a non-nil error. -// The query function must take care to set the actual result of the query to -// nil in these cases, otherwise when blockingQuery times out it may return -// a previous result. errNotFound will never be returned to the caller, it is -// converted to nil before returning. -// -// The query function can return errNotChanged, which is a sentinel error. This -// can only be returned on calls AFTER the first call, as it would not be -// possible to detect the absence of a change on the first call. Returning -// errNotChanged indicates that the query results are identical to the prior -// results which allows blockingQuery to keep blocking until the query returns -// a real changed result. -// -// The query function must take care to ensure the actual result of the query -// is either left unmodified or explicitly left in a good state before -// returning, otherwise when blockingQuery times out it may return an -// incomplete or unexpected result. errNotChanged will never be returned to the -// caller, it is converted to nil before returning. -// -// If query function returns any other error, the error is returned to the caller -// immediately. -// -// The query function must follow these rules: -// -// 1. to access data it must use the passed in state.Store. -// 2. it must set the responseMeta.Index to an index greater than -// opts.GetMinQueryIndex if the results return by the query have changed. -// 3. any channels added to the memdb.WatchSet must unblock when the results -// returned by the query have changed. -// -// To ensure optimal performance of the query, the query function should make a -// best-effort attempt to follow these guidelines: -// -// 1. only set responseMeta.Index to an index greater than -// opts.GetMinQueryIndex when the results returned by the query have changed. -// 2. any channels added to the memdb.WatchSet should only unblock when the -// results returned by the query have changed. +// blockingQuery is a passthrough to blockingquery.Query that keeps API +// compatibility with Server. That has RPC and FSM machinery mixed in the same consul +// package. func (s *Server) blockingQuery( - opts blockingQueryOptions, - responseMeta blockingQueryResponseMeta, - query queryFn, + requestOpts blockingquery.RequestOptions, + responseMeta blockingquery.ResponseMeta, + query blockingquery.QueryFn, ) error { - var ctx context.Context = &lib.StopChannelContext{StopCh: s.shutdownCh} - - metrics.IncrCounter([]string{"rpc", "query"}, 1) - - minQueryIndex := opts.GetMinQueryIndex() - // Perform a non-blocking query - if minQueryIndex == 0 { - if opts.GetRequireConsistent() { - if err := s.consistentRead(); err != nil { - return err - } - } - - var ws memdb.WatchSet - err := query(ws, s.fsm.State()) - s.setQueryMeta(responseMeta, opts.GetToken()) - if errors.Is(err, errNotFound) || errors.Is(err, errNotChanged) { - return nil - } - return err - } - - maxQueryTimeout, err := opts.GetMaxQueryTime() - if err != nil { - return err - } - timeout := s.rpcQueryTimeout(maxQueryTimeout) - ctx, cancel := context.WithTimeout(ctx, timeout) - defer cancel() - - count := atomic.AddUint64(&s.queriesBlocking, 1) - metrics.SetGauge([]string{"rpc", "queries_blocking"}, float32(count)) - // decrement the count when the function returns. - defer atomic.AddUint64(&s.queriesBlocking, ^uint64(0)) - - var ( - notFound bool - ranOnce bool - ) - - for { - if opts.GetRequireConsistent() { - if err := s.consistentRead(); err != nil { - return err - } - } - - // Operate on a consistent set of state. This makes sure that the - // abandon channel goes with the state that the caller is using to - // build watches. - state := s.fsm.State() - - ws := memdb.NewWatchSet() - // This channel will be closed if a snapshot is restored and the - // whole state store is abandoned. - ws.Add(state.AbandonCh()) - - err := query(ws, state) - s.setQueryMeta(responseMeta, opts.GetToken()) - - switch { - case errors.Is(err, errNotFound): - if notFound { - // query result has not changed - minQueryIndex = responseMeta.GetIndex() - } - notFound = true - case errors.Is(err, errNotChanged): - if ranOnce { - // query result has not changed - minQueryIndex = responseMeta.GetIndex() - } - case err != nil: - return err - } - ranOnce = true - - if responseMeta.GetIndex() > minQueryIndex { - return nil - } - - // block until something changes, or the timeout - if err := ws.WatchCtx(ctx); err != nil { - // exit if we've reached the timeout, or other cancellation - return nil - } - - // exit if the state store has been abandoned - select { - case <-state.AbandonCh(): - return nil - default: - } - } + return blockingquery.Query(s, requestOpts, responseMeta, query) } var ( - errNotFound = fmt.Errorf("no data found for query") - errNotChanged = fmt.Errorf("data did not change for query") + errNotFound = blockingquery.ErrNotFound + errNotChanged = blockingquery.ErrNotChanged ) -// setQueryMeta is used to populate the QueryMeta data for an RPC call +// SetQueryMeta is used to populate the QueryMeta data for an RPC call // // Note: This method must be called *after* filtering query results with ACLs. -func (s *Server) setQueryMeta(m blockingQueryResponseMeta, token string) { +func (s *Server) SetQueryMeta(m blockingquery.ResponseMeta, token string) { if s.IsLeader() { m.SetLastContact(0) m.SetKnownLeader(true) @@ -1138,11 +996,11 @@ func (s *Server) setQueryMeta(m blockingQueryResponseMeta, token string) { // consistentRead is used to ensure we do not perform a stale // read. This is done by verifying leadership before the read. -func (s *Server) consistentRead() error { +func (s *Server) ConsistentRead() error { defer metrics.MeasureSince([]string{"rpc", "consistentRead"}, time.Now()) future := s.raft.VerifyLeader() if err := future.Error(); err != nil { - return err //fail fast if leader verification fails + return err // fail fast if leader verification fails } // poll consistent read readiness, wait for up to RPCHoldTimeout milliseconds if s.isReadyForConsistentReads() { @@ -1169,10 +1027,10 @@ func (s *Server) consistentRead() error { return structs.ErrNotReadyForConsistentReads } -// rpcQueryTimeout calculates the timeout for the query, ensures it is +// RPCQueryTimeout calculates the timeout for the query, ensures it is // constrained to the configured limit, and adds jitter to prevent multiple // blocking queries from all timing out at the same time. -func (s *Server) rpcQueryTimeout(queryTimeout time.Duration) time.Duration { +func (s *Server) RPCQueryTimeout(queryTimeout time.Duration) time.Duration { // Restrict the max query time, and ensure there is always one. if queryTimeout > s.config.MaxQueryTime { queryTimeout = s.config.MaxQueryTime @@ -1197,16 +1055,16 @@ func (s *Server) rpcQueryTimeout(queryTimeout time.Duration) time.Duration { // // Notes: // -// * The definition of "unauthenticated" here is incomplete, as it doesn't -// account for the fact that operators can modify the anonymous token with -// custom policies, or set namespace default policies. As these scenarios -// are less common and this flag is a best-effort UX improvement, we think -// the trade-off for reduced complexity is acceptable. +// - The definition of "unauthenticated" here is incomplete, as it doesn't +// account for the fact that operators can modify the anonymous token with +// custom policies, or set namespace default policies. As these scenarios +// are less common and this flag is a best-effort UX improvement, we think +// the trade-off for reduced complexity is acceptable. // -// * This method assumes that the given token has already been validated (and -// will only check whether it is blank or not). It's a safe assumption because -// ResultsFilteredByACLs is only set to try when applying the already-resolved -// token's policies. +// - This method assumes that the given token has already been validated (and +// will only check whether it is blank or not). It's a safe assumption because +// ResultsFilteredByACLs is only set to try when applying the already-resolved +// token's policies. func maskResultsFilteredByACLs(token string, meta blockingQueryResponseMeta) { if token == "" { meta.SetResultsFilteredByACLs(false) diff --git a/agent/consul/rpc_test.go b/agent/consul/rpc_test.go index ff586157083f..46694292c2a7 100644 --- a/agent/consul/rpc_test.go +++ b/agent/consul/rpc_test.go @@ -498,7 +498,7 @@ func TestRPC_ReadyForConsistentReads(t *testing.T) { } s.resetConsistentReadReady() - err := s.consistentRead() + err := s.ConsistentRead() if err.Error() != "Not ready to serve consistent reads" { t.Fatal("Server should NOT be ready for consistent reads") } @@ -509,7 +509,7 @@ func TestRPC_ReadyForConsistentReads(t *testing.T) { }() retry.Run(t, func(r *retry.R) { - if err := s.consistentRead(); err != nil { + if err := s.ConsistentRead(); err != nil { r.Fatalf("Expected server to be ready for consistent reads, got error %v", err) } }) diff --git a/agent/consul/rtt_test.go b/agent/consul/rtt_test.go index d9a0fe113305..9a488a372495 100644 --- a/agent/consul/rtt_test.go +++ b/agent/consul/rtt_test.go @@ -73,10 +73,9 @@ func verifyCheckServiceNodeSort(t *testing.T, nodes structs.CheckServiceNodes, e // // Here's the layout of the nodes: // -// node3 node2 node5 node4 node1 -// | | | | | | | | | | | -// 0 1 2 3 4 5 6 7 8 9 10 (ms) -// +// node3 node2 node5 node4 node1 +// | | | | | | | | | | | +// 0 1 2 3 4 5 6 7 8 9 10 (ms) func seedCoordinates(t *testing.T, codec rpc.ClientCodec, server *Server) { // Register some nodes. for i := 0; i < 5; i++ { diff --git a/agent/consul/segment_oss.go b/agent/consul/segment_ce.go similarity index 88% rename from agent/consul/segment_oss.go rename to agent/consul/segment_ce.go index 034e79c54ef1..44b8a14b2e7e 100644 --- a/agent/consul/segment_oss.go +++ b/agent/consul/segment_ce.go @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/consul/agent/structs" ) -var SegmentOSSSummaries = []prometheus.SummaryDefinition{ +var SegmentCESummaries = []prometheus.SummaryDefinition{ { Name: []string{"leader", "reconcile"}, Help: "Measures the time spent updating the raft store from the serf member information.", @@ -23,7 +23,7 @@ func (s *Server) LANSegmentAddr(name string) string { return "" } -// setupSegmentRPC returns an error if any segments are defined since the OSS +// setupSegmentRPC returns an error if any segments are defined since the CE // version of Consul doesn't support them. func (s *Server) setupSegmentRPC() (map[string]net.Listener, error) { if len(s.config.Segments) > 0 { @@ -33,7 +33,7 @@ func (s *Server) setupSegmentRPC() (map[string]net.Listener, error) { return nil, nil } -// setupSegments returns an error if any segments are defined since the OSS +// setupSegments returns an error if any segments are defined since the CE // version of Consul doesn't support them. func (s *Server) setupSegments(config *Config, rpcListeners map[string]net.Listener) error { if len(config.Segments) > 0 { @@ -43,6 +43,6 @@ func (s *Server) setupSegments(config *Config, rpcListeners map[string]net.Liste return nil } -// floodSegments is a NOP in the OSS version of Consul. +// floodSegments is a NOP in the CE version of Consul. func (s *Server) floodSegments(config *Config) { } diff --git a/agent/consul/server.go b/agent/consul/server.go index 9a1363c7abe1..805772a86cc6 100644 --- a/agent/consul/server.go +++ b/agent/consul/server.go @@ -32,9 +32,11 @@ import ( "google.golang.org/grpc" "github.com/hashicorp/consul/acl" + "github.com/hashicorp/consul/agent/blockingquery" "github.com/hashicorp/consul/agent/consul/authmethod" "github.com/hashicorp/consul/agent/consul/authmethod/ssoauth" "github.com/hashicorp/consul/agent/consul/fsm" + "github.com/hashicorp/consul/agent/consul/reporting" "github.com/hashicorp/consul/agent/consul/state" "github.com/hashicorp/consul/agent/consul/stream" "github.com/hashicorp/consul/agent/consul/usagemetrics" @@ -142,6 +144,8 @@ const ( PoolKindSegment = "segment" ) +var _ blockingquery.FSMServer = (*Server)(nil) + // Server is Consul server which manages the service discovery, // health checking, DC forwarding, Raft, and multiple Serf pools. type Server struct { @@ -386,7 +390,23 @@ type Server struct { // embedded struct to hold all the enterprise specific data EnterpriseServer + + // handles metrics reporting to HashiCorp + reportingManager *reporting.ReportingManager +} + +func (s *Server) DecrementBlockingQueries() uint64 { + return atomic.AddUint64(&s.queriesBlocking, ^uint64(0)) +} + +func (s *Server) GetShutdownChannel() chan struct{} { + return s.shutdownCh +} + +func (s *Server) IncrementBlockingQueries() uint64 { + return atomic.AddUint64(&s.queriesBlocking, 1) } + type connHandler interface { Run() error Handle(conn net.Conn) @@ -694,6 +714,9 @@ func NewServer(config *Config, flat Deps, externalGRPCServer *grpc.Server) (*Ser s.overviewManager = NewOverviewManager(s.logger, s.fsm, s.config.MetricsReportingInterval) go s.overviewManager.Run(&lib.StopChannelContext{StopCh: s.shutdownCh}) + s.reportingManager = reporting.NewReportingManager(s.logger, getEnterpriseReportingDeps(flat), s, s.fsm.State()) + go s.reportingManager.Run(&lib.StopChannelContext{StopCh: s.shutdownCh}) + // Initialize external gRPC server - register services on external gRPC server. s.externalACLServer = aclgrpc.NewServer(aclgrpc.Config{ ACLsEnabled: s.config.ACLsEnabled, @@ -825,6 +848,7 @@ func newGRPCHandlerFromConfig(deps Deps, config *Config, s *Server) connHandler Datacenter: config.Datacenter, ConnectEnabled: config.ConnectEnabled, PeeringEnabled: config.PeeringEnabled, + FSMServer: s, }) s.peeringServer = p @@ -950,7 +974,7 @@ func (s *Server) setupRaft() error { log = cacheStore // Create the snapshot store. - snapshots, err := raft.NewFileSnapshotStoreWithLogger(path, snapshotsRetained, s.logger.Named("snapshot")) + snapshots, err := raft.NewFileSnapshotStoreWithLogger(path, snapshotsRetained, s.logger.Named("raft.snapshot")) if err != nil { return err } @@ -1564,6 +1588,13 @@ func (s *Server) FSM() *fsm.FSM { return s.fsm } +func (s *Server) GetState() *state.Store { + if s == nil || s.FSM() == nil { + return nil + } + return s.FSM().State() +} + // Stats is used to return statistics for debugging and insight // for various sub-systems func (s *Server) Stats() map[string]map[string]string { @@ -1641,6 +1672,8 @@ func (s *Server) ReloadConfig(config ReloadableConfig) error { return err } + s.updateReportingConfig(config) + s.rpcLimiter.Store(rate.NewLimiter(config.RPCRateLimit, config.RPCMaxBurst)) s.rpcConnLimiter.SetConfig(connlimit.Config{ MaxConnsPerClientIP: config.RPCMaxConnsPerClient, @@ -1747,6 +1780,7 @@ func (s *Server) hcpServerStatus(deps Deps) hcp.StatusCallback { status.LanAddress = s.config.RPCAdvertise.IP.String() status.GossipPort = s.config.SerfLANConfig.MemberlistConfig.AdvertisePort status.RPCPort = s.config.RPCAddr.Port + status.Datacenter = s.config.Datacenter tlsCert := s.tlsConfigurator.Cert() if tlsCert != nil { @@ -1788,6 +1822,8 @@ func (s *Server) hcpServerStatus(deps Deps) hcp.StatusCallback { status.ScadaStatus = deps.HCP.Provider.SessionStatus() } + status.ACL.Enabled = s.config.ACLsEnabled + return status, nil } } diff --git a/agent/consul/server_oss.go b/agent/consul/server_ce.go similarity index 94% rename from agent/consul/server_oss.go rename to agent/consul/server_ce.go index 4ae524b65c04..63de1bfe852d 100644 --- a/agent/consul/server_oss.go +++ b/agent/consul/server_ce.go @@ -15,6 +15,7 @@ import ( "google.golang.org/grpc" "github.com/hashicorp/consul/acl" + "github.com/hashicorp/consul/agent/consul/reporting" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/lib" ) @@ -78,7 +79,7 @@ func (s *Server) removeFailedNode( } // lanPoolAllMembers only returns our own segment or partition's members, because -// OSS servers can't be in multiple segments or partitions. +// CE servers can't be in multiple segments or partitions. func (s *Server) lanPoolAllMembers() ([]serf.Member, error) { return s.LANMembersInAgentPartition(), nil } @@ -174,3 +175,12 @@ func addSerfMetricsLabels(conf *serf.Config, wan bool, segment string, partition conf.MetricLabels = append(conf.MetricLabels, networkMetric) } + +func (s *Server) updateReportingConfig(config ReloadableConfig) { + // no-op +} + +func getEnterpriseReportingDeps(deps Deps) reporting.EntDeps { + // no-op + return reporting.EntDeps{} +} diff --git a/agent/consul/server_ce_test.go b/agent/consul/server_ce_test.go new file mode 100644 index 000000000000..d5a2aff08208 --- /dev/null +++ b/agent/consul/server_ce_test.go @@ -0,0 +1,43 @@ +//go:build !consulent +// +build !consulent + +package consul + +import ( + "os" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/hashicorp/consul/testrpc" +) + +func TestAgent_ReloadConfig_Reporting(t *testing.T) { + if testing.Short() { + t.Skip("too slow for testing.Short") + } + t.Parallel() + + dir1, s := testServerWithConfig(t, func(c *Config) { + c.Reporting.License.Enabled = false + }) + defer os.RemoveAll(dir1) + defer s.Shutdown() + + testrpc.WaitForTestAgent(t, s.RPC, "dc1") + + require.Equal(t, false, s.config.Reporting.License.Enabled) + + rc := ReloadableConfig{ + Reporting: Reporting{ + License: License{ + Enabled: true, + }, + }, + } + + require.NoError(t, s.ReloadConfig(rc)) + + // Check config reload is no-op + require.Equal(t, false, s.config.Reporting.License.Enabled) +} diff --git a/agent/consul/server_serf.go b/agent/consul/server_serf.go index a515589303f0..8c4c7600ab77 100644 --- a/agent/consul/server_serf.go +++ b/agent/consul/server_serf.go @@ -20,6 +20,7 @@ import ( "github.com/hashicorp/consul/lib" libserf "github.com/hashicorp/consul/lib/serf" "github.com/hashicorp/consul/logging" + "github.com/hashicorp/consul/types" ) const ( @@ -356,6 +357,7 @@ func (s *Server) lanNodeJoin(me serf.MemberEvent) { // Update server lookup s.serverLookup.AddServer(serverMeta) + s.router.AddServer(types.AreaLAN, serverMeta) // If we're still expecting to bootstrap, may need to handle this. if s.config.BootstrapExpect != 0 { @@ -377,6 +379,7 @@ func (s *Server) lanNodeUpdate(me serf.MemberEvent) { // Update server lookup s.serverLookup.AddServer(serverMeta) + s.router.AddServer(types.AreaLAN, serverMeta) } } @@ -515,5 +518,6 @@ func (s *Server) lanNodeFailed(me serf.MemberEvent) { // Update id to address map s.serverLookup.RemoveServer(serverMeta) + s.router.RemoveServer(types.AreaLAN, serverMeta) } } diff --git a/agent/consul/server_test.go b/agent/consul/server_test.go index faf13307052e..299b2cc158b3 100644 --- a/agent/consul/server_test.go +++ b/agent/consul/server_test.go @@ -2,7 +2,6 @@ package consul import ( "context" - "crypto/tls" "crypto/x509" "fmt" "net" @@ -31,6 +30,7 @@ import ( "github.com/hashicorp/consul/agent/connect" external "github.com/hashicorp/consul/agent/grpc-external" + grpcmiddleware "github.com/hashicorp/consul/agent/grpc-middleware" "github.com/hashicorp/consul/agent/metadata" "github.com/hashicorp/consul/agent/rpc/middleware" "github.com/hashicorp/consul/agent/structs" @@ -258,7 +258,9 @@ func testServerWithConfig(t *testing.T, configOpts ...func(*Config)) (string, *S ln, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", grpcPort)) require.NoError(t, err) + protocol := grpcmiddleware.ProtocolPlaintext if grpcPort == srv.config.GRPCTLSPort || deps.TLSConfigurator.GRPCServerUseTLS() { + protocol = grpcmiddleware.ProtocolTLS // Set the internally managed server certificate. The cert manager is hooked to the Agent, so we need to bypass that here. if srv.config.PeeringEnabled && srv.config.ConnectEnabled { key, _ := srv.config.CAConfig.Config["PrivateKey"].(string) @@ -273,9 +275,8 @@ func testServerWithConfig(t *testing.T, configOpts ...func(*Config)) (string, *S } } - // Wrap the listener with TLS. - ln = tls.NewListener(ln, deps.TLSConfigurator.IncomingGRPCConfig()) } + ln = grpcmiddleware.LabelledListener{Listener: ln, Protocol: protocol} go func() { _ = srv.externalGRPCServer.Serve(ln) @@ -307,6 +308,7 @@ func testGRPCIntegrationServer(t *testing.T, cb func(*Config)) (*Server, *grpc.C _, srv, codec := testACLServerWithConfig(t, cb, false) grpcAddr := fmt.Sprintf("127.0.0.1:%d", srv.config.GRPCPort) + //nolint:staticcheck conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure()) require.NoError(t, err) @@ -329,7 +331,7 @@ func newServerWithDeps(t *testing.T, c *Config, deps Deps) (*Server, error) { oldNotify() } } - grpcServer := external.NewServer(deps.Logger.Named("grpc.external"), nil) + grpcServer := external.NewServer(deps.Logger.Named("grpc.external"), nil, deps.TLSConfigurator) srv, err := NewServer(c, deps, grpcServer) if err != nil { return nil, err diff --git a/agent/consul/snapshot_endpoint.go b/agent/consul/snapshot_endpoint.go index 80e255bd9e14..74223e85d6b3 100644 --- a/agent/consul/snapshot_endpoint.go +++ b/agent/consul/snapshot_endpoint.go @@ -69,14 +69,14 @@ func (s *Server) dispatchSnapshotRequest(args *structs.SnapshotRequest, in io.Re switch args.Op { case structs.SnapshotSave: if !args.AllowStale { - if err := s.consistentRead(); err != nil { + if err := s.ConsistentRead(); err != nil { return nil, err } } // Set the metadata here before we do anything; this should always be // pessimistic if we get more data while the snapshot is being taken. - s.setQueryMeta(&reply.QueryMeta, args.Token) + s.SetQueryMeta(&reply.QueryMeta, args.Token) // Take the snapshot and capture the index. snap, err := snapshot.New(s.logger, s.raft) diff --git a/agent/consul/state/acl.go b/agent/consul/state/acl.go index 61fa3337fbcb..1281e2bb258c 100644 --- a/agent/consul/state/acl.go +++ b/agent/consul/state/acl.go @@ -640,8 +640,35 @@ func aclTokenGetTxn(tx ReadTxn, ws memdb.WatchSet, value, index string, entMeta return nil, nil } +type ACLTokenListParameters struct { + Local bool + Global bool + Policy string + Role string + ServiceName string + MethodName string + MethodMeta *acl.EnterpriseMeta + EnterpriseMeta *acl.EnterpriseMeta +} + // ACLTokenList return a list of ACL Tokens that match the policy, role, and method. +// This function should be treated as deprecated, and ACLTokenListWithParameters should be preferred. +// +// Deprecated: use ACLTokenListWithParameters func (s *Store) ACLTokenList(ws memdb.WatchSet, local, global bool, policy, role, methodName string, methodMeta, entMeta *acl.EnterpriseMeta) (uint64, structs.ACLTokens, error) { + return s.ACLTokenListWithParameters(ws, ACLTokenListParameters{ + Local: local, + Global: global, + Policy: policy, + Role: role, + MethodName: methodName, + MethodMeta: methodMeta, + EnterpriseMeta: entMeta, + }) +} + +// ACLTokenListWithParameters returns a list of ACL Tokens that match the provided parameters. +func (s *Store) ACLTokenListWithParameters(ws memdb.WatchSet, params ACLTokenListParameters) (uint64, structs.ACLTokens, error) { tx := s.db.Txn(false) defer tx.Abort() @@ -654,43 +681,51 @@ func (s *Store) ACLTokenList(ws memdb.WatchSet, local, global bool, policy, role needLocalityFilter := false - if policy == "" && role == "" && methodName == "" { - if global == local { - iter, err = aclTokenListAll(tx, entMeta) + if params.Policy == "" && params.Role == "" && params.MethodName == "" && params.ServiceName == "" { + if params.Global == params.Local { + iter, err = aclTokenListAll(tx, params.EnterpriseMeta) } else { - iter, err = aclTokenList(tx, entMeta, local) + iter, err = aclTokenList(tx, params.EnterpriseMeta, params.Local) } - } else if policy != "" && role == "" && methodName == "" { - iter, err = aclTokenListByPolicy(tx, policy, entMeta) + } else if params.Policy != "" && params.Role == "" && params.MethodName == "" && params.ServiceName == "" { + // Find by policy + iter, err = aclTokenListByPolicy(tx, params.Policy, params.EnterpriseMeta) + needLocalityFilter = true + + } else if params.Policy == "" && params.Role != "" && params.MethodName == "" && params.ServiceName == "" { + // Find by role + iter, err = aclTokenListByRole(tx, params.Role, params.EnterpriseMeta) needLocalityFilter = true - } else if policy == "" && role != "" && methodName == "" { - iter, err = aclTokenListByRole(tx, role, entMeta) + } else if params.Policy == "" && params.Role == "" && params.MethodName != "" && params.ServiceName == "" { + // Find by methodName + iter, err = aclTokenListByAuthMethod(tx, params.MethodName, params.MethodMeta, params.EnterpriseMeta) needLocalityFilter = true - } else if policy == "" && role == "" && methodName != "" { - iter, err = aclTokenListByAuthMethod(tx, methodName, methodMeta, entMeta) + } else if params.Policy == "" && params.Role == "" && params.MethodName == "" && params.ServiceName != "" { + // Find by the service identity's serviceName + iter, err = aclTokenListByServiceName(tx, params.ServiceName, params.EnterpriseMeta) needLocalityFilter = true } else { - return 0, nil, fmt.Errorf("can only filter by one of policy, role, or methodName at a time") + return 0, nil, fmt.Errorf("can only filter by one of policy, role, serviceName, or methodName at a time") } if err != nil { return 0, nil, fmt.Errorf("failed acl token lookup: %v", err) } - if needLocalityFilter && global != local { + if needLocalityFilter && params.Global != params.Local { iter = memdb.NewFilterIterator(iter, func(raw interface{}) bool { token, ok := raw.(*structs.ACLToken) if !ok { return true } - if global && !token.Local { + if params.Global && !token.Local { return false - } else if local && token.Local { + } else if params.Local && token.Local { return false } @@ -715,7 +750,7 @@ func (s *Store) ACLTokenList(ws memdb.WatchSet, local, global bool, policy, role } // Get the table index. - idx := aclTokenMaxIndex(tx, nil, entMeta) + idx := aclTokenMaxIndex(tx, nil, params.EnterpriseMeta) return idx, result, nil } @@ -924,18 +959,18 @@ func aclPolicySetTxn(tx WriteTxn, idx uint64, policy *structs.ACLPolicy) error { } if existing != nil { - if policy.ID == structs.ACLPolicyGlobalManagementID { + if builtinPolicy, ok := structs.ACLBuiltinPolicies[policy.ID]; ok { // Only the name and description are modifiable - // Here we specifically check that the rules on the global management policy + // Here we specifically check that the rules on the builtin policy // are identical to the correct policy rules within the binary. This is opposed // to checking against the current rules to allow us to update the rules during // upgrades. - if policy.Rules != structs.ACLPolicyGlobalManagement { - return fmt.Errorf("Changing the Rules for the builtin global-management policy is not permitted") + if policy.Rules != builtinPolicy.Rules { + return fmt.Errorf("Changing the Rules for the builtin %s policy is not permitted", builtinPolicy.Name) } if policy.Datacenters != nil && len(policy.Datacenters) != 0 { - return fmt.Errorf("Changing the Datacenters of the builtin global-management policy is not permitted") + return fmt.Errorf("Changing the Datacenters of the builtin %s policy is not permitted", builtinPolicy.Name) } } } @@ -1102,8 +1137,8 @@ func aclPolicyDeleteTxn(tx WriteTxn, idx uint64, value string, fn aclPolicyGetFn policy := rawPolicy.(*structs.ACLPolicy) - if policy.ID == structs.ACLPolicyGlobalManagementID { - return fmt.Errorf("Deletion of the builtin global-management policy is not permitted") + if builtinPolicy, ok := structs.ACLBuiltinPolicies[policy.ID]; ok { + return fmt.Errorf("Deletion of the builtin %s policy is not permitted", builtinPolicy.Name) } return aclPolicyDeleteWithPolicy(tx, policy, idx) diff --git a/agent/consul/state/acl_oss.go b/agent/consul/state/acl_ce.go similarity index 97% rename from agent/consul/state/acl_oss.go rename to agent/consul/state/acl_ce.go index 68671307132f..d1a176c0adef 100644 --- a/agent/consul/state/acl_oss.go +++ b/agent/consul/state/acl_ce.go @@ -73,6 +73,10 @@ func aclTokenListByAuthMethod(tx ReadTxn, authMethod string, _, _ *acl.Enterpris return tx.Get(tableACLTokens, indexAuthMethod, AuthMethodQuery{Value: authMethod}) } +func aclTokenListByServiceName(tx ReadTxn, serviceName string, entMeta *acl.EnterpriseMeta) (memdb.ResultIterator, error) { + return tx.Get(tableACLTokens, indexServiceName, Query{Value: serviceName}) +} + func aclTokenDeleteWithToken(tx WriteTxn, token *structs.ACLToken, idx uint64) error { // remove the token if err := tx.Delete(tableACLTokens, token); err != nil { diff --git a/agent/consul/state/acl_oss_test.go b/agent/consul/state/acl_ce_test.go similarity index 100% rename from agent/consul/state/acl_oss_test.go rename to agent/consul/state/acl_ce_test.go diff --git a/agent/consul/state/acl_schema.go b/agent/consul/state/acl_schema.go index 485b5b92d977..8d24d4e390dd 100644 --- a/agent/consul/state/acl_schema.go +++ b/agent/consul/state/acl_schema.go @@ -19,6 +19,7 @@ const ( indexAccessor = "accessor" indexPolicies = "policies" indexRoles = "roles" + indexServiceName = "service-name" indexAuthMethod = "authmethod" indexLocality = "locality" indexName = "name" @@ -104,7 +105,6 @@ func tokensTableSchema() *memdb.TableSchema { writeIndex: indexExpiresLocalFromACLToken, }, }, - // DEPRECATED (ACL-Legacy-Compat) - This index is only needed while we support upgrading v1 to v2 acls // This table indexes all the ACL tokens that do not have an AccessorID // TODO(ACL-Legacy-Compat): remove in phase 2 @@ -121,6 +121,15 @@ func tokensTableSchema() *memdb.TableSchema { }, }, }, + indexServiceName: { + Name: indexServiceName, + AllowMissing: true, + Unique: false, + Indexer: indexerMulti[Query, *structs.ACLToken]{ + readIndex: indexFromQuery, + writeIndexMulti: indexServiceNameFromACLToken, + }, + }, }, } } @@ -413,6 +422,21 @@ func indexExpiresFromACLToken(t *structs.ACLToken, local bool) ([]byte, error) { return b.Bytes(), nil } +func indexServiceNameFromACLToken(token *structs.ACLToken) ([][]byte, error) { + vals := make([][]byte, 0, len(token.ServiceIdentities)) + for _, id := range token.ServiceIdentities { + if id != nil && id.ServiceName != "" { + var b indexBuilder + b.String(strings.ToLower(id.ServiceName)) + vals = append(vals, b.Bytes()) + } + } + if len(vals) == 0 { + return nil, errMissingValueForIndex + } + return vals, nil +} + func authMethodsTableSchema() *memdb.TableSchema { return &memdb.TableSchema{ Name: tableACLAuthMethods, diff --git a/agent/consul/state/acl_test.go b/agent/consul/state/acl_test.go index 9634bf52f105..1e66639e74cd 100644 --- a/agent/consul/state/acl_test.go +++ b/agent/consul/state/acl_test.go @@ -13,7 +13,6 @@ import ( "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/structs" - "github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/proto/pbacl" ) @@ -28,17 +27,17 @@ const ( ) func setupGlobalManagement(t *testing.T, s *Store) { - policy := structs.ACLPolicy{ - ID: structs.ACLPolicyGlobalManagementID, - Name: "global-management", - Description: "Builtin Policy that grants unlimited access", - Rules: structs.ACLPolicyGlobalManagement, - Syntax: acl.SyntaxCurrent, - } + policy := structs.ACLBuiltinPolicies[structs.ACLPolicyGlobalManagementID] policy.SetHash(true) require.NoError(t, s.ACLPolicySet(1, &policy)) } +func setupBuiltinGlobalReadOnly(t *testing.T, s *Store) { + policy := structs.ACLBuiltinPolicies[structs.ACLPolicyGlobalReadOnlyID] + policy.SetHash(true) + require.NoError(t, s.ACLPolicySet(2, &policy)) +} + func setupAnonymous(t *testing.T, s *Store) { token := structs.ACLToken{ AccessorID: structs.ACLTokenAnonymousID, @@ -52,6 +51,7 @@ func setupAnonymous(t *testing.T, s *Store) { func testACLStateStore(t *testing.T) *Store { s := testStateStore(t) setupGlobalManagement(t, s) + setupBuiltinGlobalReadOnly(t, s) setupAnonymous(t, s) return s } @@ -188,6 +188,7 @@ func TestStateStore_ACLBootstrap(t *testing.T) { s := testStateStore(t) setupGlobalManagement(t, s) + setupBuiltinGlobalReadOnly(t, s) canBootstrap, index, err := s.CanBootstrapACLToken() require.NoError(t, err) @@ -215,6 +216,7 @@ func TestStateStore_ACLBootstrap(t *testing.T) { require.Equal(t, uint64(3), index) // Make sure the ACLs are in an expected state. + // nolint:staticcheck _, tokens, err := s.ACLTokenList(nil, true, true, "", "", "", nil, nil) require.NoError(t, err) require.Len(t, tokens, 1) @@ -229,6 +231,7 @@ func TestStateStore_ACLBootstrap(t *testing.T) { err = s.ACLBootstrap(32, index, token2.Clone()) require.NoError(t, err) + // nolint:staticcheck _, tokens, err = s.ACLTokenList(nil, true, true, "", "", "", nil, nil) require.NoError(t, err) require.Len(t, tokens, 2) @@ -956,18 +959,36 @@ func TestStateStore_ACLToken_List(t *testing.T) { AuthMethod: "test", Local: true, }, + // the serviceName specific token + &structs.ACLToken{ + AccessorID: "80c900e1-2fc5-4685-ae29-1b2d17fc30e4", + SecretID: "9d229cfd-ec4b-4d31-a6fd-ecbcb2a41d41", + ServiceIdentities: []*structs.ACLServiceIdentity{ + {ServiceName: "sn1"}, + }, + }, + // the serviceName specific token and local + &structs.ACLToken{ + AccessorID: "a14fa45e-0afe-4b44-961d-a430030ccfe2", + SecretID: "17f696b9-448a-4bd3-936b-08c92c66530f", + ServiceIdentities: []*structs.ACLServiceIdentity{ + {ServiceName: "sn1"}, + }, + Local: true, + }, } require.NoError(t, s.ACLTokenBatchSet(2, tokens, ACLTokenSetOptions{})) type testCase struct { - name string - local bool - global bool - policy string - role string - methodName string - accessors []string + name string + local bool + global bool + policy string + role string + methodName string + serviceName string + accessors []string } cases := []testCase{ @@ -983,6 +1004,7 @@ func TestStateStore_ACLToken_List(t *testing.T) { "47eea4da-bda1-48a6-901c-3e36d2d9262f", // policy + global "54866514-3cf2-4fec-8a8a-710583831834", // mgmt + global "74277ae1-6a9b-4035-b444-2370fe6a2cb5", // authMethod + global + "80c900e1-2fc5-4685-ae29-1b2d17fc30e4", // serviceName + global "a7715fde-8954-4c92-afbc-d84c6ecdc582", // role + global }, }, @@ -996,6 +1018,7 @@ func TestStateStore_ACLToken_List(t *testing.T) { accessors: []string{ "211f0360-ef53-41d3-9d4d-db84396eb6c0", // authMethod + local "4915fc9d-3726-4171-b588-6c271f45eecd", // policy + local + "a14fa45e-0afe-4b44-961d-a430030ccfe2", // serviceName + local "cadb4f13-f62a-49ab-ab3f-5a7e01b925d9", // role + local "f1093997-b6c7-496d-bfb8-6b1b1895641b", // mgmt + local }, @@ -1090,6 +1113,30 @@ func TestStateStore_ACLToken_List(t *testing.T) { "74277ae1-6a9b-4035-b444-2370fe6a2cb5", // authMethod + global }, }, + { + name: "ServiceName - Local", + local: true, + global: false, + policy: "", + role: "", + methodName: "", + serviceName: "sn1", + accessors: []string{ + "a14fa45e-0afe-4b44-961d-a430030ccfe2", // serviceName + local + }, + }, + { + name: "ServiceName - Global", + local: false, + global: true, + policy: "", + role: "", + methodName: "", + serviceName: "sn1", + accessors: []string{ + "80c900e1-2fc5-4685-ae29-1b2d17fc30e4", // serviceName + global + }, + }, { name: "All", local: true, @@ -1104,6 +1151,8 @@ func TestStateStore_ACLToken_List(t *testing.T) { "4915fc9d-3726-4171-b588-6c271f45eecd", // policy + local "54866514-3cf2-4fec-8a8a-710583831834", // mgmt + global "74277ae1-6a9b-4035-b444-2370fe6a2cb5", // authMethod + global + "80c900e1-2fc5-4685-ae29-1b2d17fc30e4", // serviceName + global + "a14fa45e-0afe-4b44-961d-a430030ccfe2", // serviceName + local "a7715fde-8954-4c92-afbc-d84c6ecdc582", // role + global "cadb4f13-f62a-49ab-ab3f-5a7e01b925d9", // role + local "f1093997-b6c7-496d-bfb8-6b1b1895641b", // mgmt + local @@ -1111,14 +1160,27 @@ func TestStateStore_ACLToken_List(t *testing.T) { }, } - for _, tc := range []struct{ policy, role, methodName string }{ - {testPolicyID_A, testRoleID_A, "test"}, - {"", testRoleID_A, "test"}, - {testPolicyID_A, "", "test"}, - {testPolicyID_A, testRoleID_A, ""}, + for _, tc := range []struct{ policy, role, methodName, serviceName string }{ + {testPolicyID_A, testRoleID_A, "test", ""}, + {"", testRoleID_A, "test", ""}, + {testPolicyID_A, "", "test", ""}, + {testPolicyID_A, testRoleID_A, "", ""}, + {testPolicyID_A, "", "", "test"}, } { - t.Run(fmt.Sprintf("can't filter on more than one: %s/%s/%s", tc.policy, tc.role, tc.methodName), func(t *testing.T) { - _, _, err := s.ACLTokenList(nil, false, false, tc.policy, tc.role, tc.methodName, nil, nil) + t.Run(fmt.Sprintf("can't filter on more than one: %s/%s/%s/%s", tc.policy, tc.role, tc.methodName, tc.serviceName), func(t *testing.T) { + var err error + if tc.serviceName == "" { + // The legacy call can only be tested when the serviceName is not specified + // nolint:staticcheck + _, _, err = s.ACLTokenList(nil, false, false, tc.policy, tc.role, tc.methodName, nil, nil) + require.Error(t, err) + } + _, _, err = s.ACLTokenListWithParameters(nil, ACLTokenListParameters{ + Policy: tc.policy, + Role: tc.role, + MethodName: tc.methodName, + ServiceName: tc.serviceName, + }) require.Error(t, err) }) } @@ -1127,12 +1189,33 @@ func TestStateStore_ACLToken_List(t *testing.T) { tc := tc // capture range variable t.Run(tc.name, func(t *testing.T) { t.Parallel() - _, tokens, err := s.ACLTokenList(nil, tc.local, tc.global, tc.policy, tc.role, tc.methodName, nil, nil) - require.NoError(t, err) - require.Len(t, tokens, len(tc.accessors)) - tokens.Sort() - for i, token := range tokens { - require.Equal(t, tc.accessors[i], token.AccessorID) + // Test old function + if tc.serviceName == "" { + // nolint:staticcheck + _, tokens, err := s.ACLTokenList(nil, tc.local, tc.global, tc.policy, tc.role, tc.methodName, nil, nil) + require.NoError(t, err) + require.Len(t, tokens, len(tc.accessors)) + tokens.Sort() + for i, token := range tokens { + require.Equal(t, tc.accessors[i], token.AccessorID) + } + } + // Test new function + { + _, tokens, err := s.ACLTokenListWithParameters(nil, ACLTokenListParameters{ + Local: tc.local, + Global: tc.global, + Policy: tc.policy, + Role: tc.role, + ServiceName: tc.serviceName, + MethodName: tc.methodName, + }) + require.NoError(t, err) + require.Len(t, tokens, len(tc.accessors)) + tokens.Sort() + for i, token := range tokens { + require.Equal(t, tc.accessors[i], token.AccessorID) + } } }) } @@ -1188,6 +1271,7 @@ func TestStateStore_ACLToken_FixupPolicyLinks(t *testing.T) { require.Equal(t, "node-read-renamed", retrieved.Policies[0].Name) // list tokens without stale links + // nolint:staticcheck _, tokens, err := s.ACLTokenList(nil, true, true, "", "", "", nil, nil) require.NoError(t, err) @@ -1232,6 +1316,7 @@ func TestStateStore_ACLToken_FixupPolicyLinks(t *testing.T) { require.Len(t, retrieved.Policies, 0) // list tokens without stale links + // nolint:staticcheck _, tokens, err = s.ACLTokenList(nil, true, true, "", "", "", nil, nil) require.NoError(t, err) @@ -1317,6 +1402,7 @@ func TestStateStore_ACLToken_FixupRoleLinks(t *testing.T) { require.Equal(t, "node-read-role-renamed", retrieved.Roles[0].Name) // list tokens without stale links + // nolint:staticcheck _, tokens, err := s.ACLTokenList(nil, true, true, "", "", "", nil, nil) require.NoError(t, err) @@ -1361,6 +1447,7 @@ func TestStateStore_ACLToken_FixupRoleLinks(t *testing.T) { require.Len(t, retrieved.Roles, 0) // list tokens without stale links + // nolint:staticcheck _, tokens, err = s.ACLTokenList(nil, true, true, "", "", "", nil, nil) require.NoError(t, err) @@ -1541,7 +1628,7 @@ func TestStateStore_ACLPolicy_SetGet(t *testing.T) { ID: structs.ACLPolicyGlobalManagementID, Name: "global-management", Description: "Global Management", - Rules: structs.ACLPolicyGlobalManagement, + Rules: structs.ACLPolicyGlobalManagementRules, Datacenters: []string{"dc1"}, } @@ -1555,7 +1642,7 @@ func TestStateStore_ACLPolicy_SetGet(t *testing.T) { ID: structs.ACLPolicyGlobalManagementID, Name: "management", Description: "Modified", - Rules: structs.ACLPolicyGlobalManagement, + Rules: structs.ACLPolicyGlobalManagementRules, } require.NoError(t, s.ACLPolicySet(3, &policy)) @@ -1606,8 +1693,8 @@ func TestStateStore_ACLPolicy_SetGet(t *testing.T) { require.NoError(t, err) require.NotNil(t, rpolicy) require.Equal(t, "global-management", rpolicy.Name) - require.Equal(t, "Builtin Policy that grants unlimited access", rpolicy.Description) - require.Equal(t, structs.ACLPolicyGlobalManagement, rpolicy.Rules) + require.Equal(t, structs.ACLPolicyGlobalManagementDesc, rpolicy.Description) + require.Equal(t, structs.ACLPolicyGlobalManagementRules, rpolicy.Rules) require.Equal(t, acl.SyntaxCurrent, rpolicy.Syntax) require.Len(t, rpolicy.Datacenters, 0) require.Equal(t, uint64(1), rpolicy.CreateIndex) @@ -1779,31 +1866,39 @@ func TestStateStore_ACLPolicy_List(t *testing.T) { _, policies, err := s.ACLPolicyList(nil, nil) require.NoError(t, err) - require.Len(t, policies, 3) + require.Len(t, policies, 4) policies.Sort() require.Equal(t, structs.ACLPolicyGlobalManagementID, policies[0].ID) - require.Equal(t, "global-management", policies[0].Name) - require.Equal(t, "Builtin Policy that grants unlimited access", policies[0].Description) + require.Equal(t, structs.ACLPolicyGlobalManagementName, policies[0].Name) + require.Equal(t, structs.ACLPolicyGlobalManagementDesc, policies[0].Description) require.Empty(t, policies[0].Datacenters) require.NotEqual(t, []byte{}, policies[0].Hash) require.Equal(t, uint64(1), policies[0].CreateIndex) require.Equal(t, uint64(1), policies[0].ModifyIndex) - require.Equal(t, "a2719052-40b3-4a4b-baeb-f3df1831a217", policies[1].ID) - require.Equal(t, "acl-write-dc3", policies[1].Name) - require.Equal(t, "Can manage ACLs in dc3", policies[1].Description) - require.ElementsMatch(t, []string{"dc3"}, policies[1].Datacenters) - require.Nil(t, policies[1].Hash) + require.Equal(t, structs.ACLPolicyGlobalReadOnlyID, policies[1].ID) + require.Equal(t, structs.ACLPolicyGlobalReadOnlyName, policies[1].Name) + require.Equal(t, structs.ACLPolicyGlobalReadOnlyDesc, policies[1].Description) + require.Empty(t, policies[1].Datacenters) + require.NotEqual(t, []byte{}, policies[1].Hash) require.Equal(t, uint64(2), policies[1].CreateIndex) require.Equal(t, uint64(2), policies[1].ModifyIndex) - require.Equal(t, "a4f68bd6-3af5-4f56-b764-3c6f20247879", policies[2].ID) - require.Equal(t, "service-read", policies[2].Name) - require.Equal(t, "", policies[2].Description) - require.Empty(t, policies[2].Datacenters) + require.Equal(t, "a2719052-40b3-4a4b-baeb-f3df1831a217", policies[2].ID) + require.Equal(t, "acl-write-dc3", policies[2].Name) + require.Equal(t, "Can manage ACLs in dc3", policies[2].Description) + require.ElementsMatch(t, []string{"dc3"}, policies[2].Datacenters) require.Nil(t, policies[2].Hash) require.Equal(t, uint64(2), policies[2].CreateIndex) require.Equal(t, uint64(2), policies[2].ModifyIndex) + + require.Equal(t, "a4f68bd6-3af5-4f56-b764-3c6f20247879", policies[3].ID) + require.Equal(t, "service-read", policies[3].Name) + require.Equal(t, "", policies[3].Description) + require.Empty(t, policies[3].Datacenters) + require.Nil(t, policies[3].Hash) + require.Equal(t, uint64(2), policies[3].CreateIndex) + require.Equal(t, uint64(2), policies[3].ModifyIndex) } func TestStateStore_ACLPolicy_Delete(t *testing.T) { @@ -2793,16 +2888,19 @@ func TestStateStore_ACLAuthMethod_GlobalNameShadowing_TokenTest(t *testing.T) { } require.True(t, t.Run("list local only", func(t *testing.T) { + // nolint:staticcheck _, got, err := s.ACLTokenList(nil, true, false, "", "", "test", defaultEntMeta, defaultEntMeta) require.NoError(t, err) require.ElementsMatch(t, []string{methodDC2_tok1, methodDC2_tok2}, toList(got)) })) require.True(t, t.Run("list global only", func(t *testing.T) { + // nolint:staticcheck _, got, err := s.ACLTokenList(nil, false, true, "", "", "test", defaultEntMeta, defaultEntMeta) require.NoError(t, err) require.ElementsMatch(t, []string{methodDC1_tok1, methodDC1_tok2}, toList(got)) })) require.True(t, t.Run("list both", func(t *testing.T) { + // nolint:staticcheck _, got, err := s.ACLTokenList(nil, true, true, "", "", "test", defaultEntMeta, defaultEntMeta) require.NoError(t, err) require.ElementsMatch(t, []string{methodDC1_tok1, methodDC1_tok2, methodDC2_tok1, methodDC2_tok2}, toList(got)) @@ -2814,16 +2912,19 @@ func TestStateStore_ACLAuthMethod_GlobalNameShadowing_TokenTest(t *testing.T) { })) require.True(t, t.Run("list local only (after dc2 delete)", func(t *testing.T) { + // nolint:staticcheck _, got, err := s.ACLTokenList(nil, true, false, "", "", "test", defaultEntMeta, defaultEntMeta) require.NoError(t, err) require.Empty(t, got) })) require.True(t, t.Run("list global only (after dc2 delete)", func(t *testing.T) { + // nolint:staticcheck _, got, err := s.ACLTokenList(nil, false, true, "", "", "test", defaultEntMeta, defaultEntMeta) require.NoError(t, err) require.ElementsMatch(t, []string{methodDC1_tok1, methodDC1_tok2}, toList(got)) })) require.True(t, t.Run("list both (after dc2 delete)", func(t *testing.T) { + // nolint:staticcheck _, got, err := s.ACLTokenList(nil, true, true, "", "", "test", defaultEntMeta, defaultEntMeta) require.NoError(t, err) require.ElementsMatch(t, []string{methodDC1_tok1, methodDC1_tok2}, toList(got)) @@ -3616,6 +3717,7 @@ func TestStateStore_ACLTokens_Snapshot_Restore(t *testing.T) { require.NoError(t, s.ACLRoleBatchSet(2, roles, false)) // Read the restored ACLs back out and verify that they match. + // nolint:staticcheck idx, res, err := s.ACLTokenList(nil, true, true, "", "", "", nil, nil) require.NoError(t, err) require.Equal(t, uint64(4), idx) @@ -3690,7 +3792,6 @@ func TestStateStore_ACLPolicies_Snapshot_Restore(t *testing.T) { } func TestTokenPoliciesIndex(t *testing.T) { - lib.SeedMathRand() idIndex := &memdb.IndexSchema{ Name: "id", diff --git a/agent/consul/state/catalog.go b/agent/consul/state/catalog.go index 7dad6e36fd41..003bf409f4e7 100644 --- a/agent/consul/state/catalog.go +++ b/agent/consul/state/catalog.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/hashicorp/go-memdb" - "github.com/mitchellh/copystructure" "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/configentry" @@ -900,12 +899,17 @@ func ensureServiceTxn(tx WriteTxn, idx uint64, node string, preserveIndexes bool return fmt.Errorf("failed updating gateway mapping: %s", err) } + if svc.PeerName == "" && sn.Name != "" { + if err := upsertKindServiceName(tx, idx, structs.ServiceKindConnectEnabled, sn); err != nil { + return fmt.Errorf("failed to persist service name as connect-enabled: %v", err) + } + } + + // Update the virtual IP for the service supported, err := virtualIPsSupported(tx, nil) if err != nil { return err } - - // Update the virtual IP for the service if supported { psn := structs.PeeredServiceName{Peer: svc.PeerName, ServiceName: sn} vip, err := assignServiceVirtualIP(tx, idx, psn) @@ -1181,7 +1185,7 @@ func serviceListTxn(tx ReadTxn, ws memdb.WatchSet, entMeta *acl.EnterpriseMeta, unique := make(map[structs.ServiceName]struct{}) for service := services.Next(); service != nil; service = services.Next() { svc := service.(*structs.ServiceNode) - unique[svc.CompoundServiceName()] = struct{}{} + unique[svc.CompoundServiceName().ServiceName] = struct{}{} } results := make(structs.ServiceList, 0, len(unique)) @@ -1267,8 +1271,8 @@ func (s *Store) ServicesByNodeMeta(ws memdb.WatchSet, filters map[string]string, // The service_last_extinction is set to the last raft index when a service // was unregistered (or 0 if no services were ever unregistered). This // allows blocking queries to -// * return when the last instance of a service is removed -// * block until an instance for this service is available, or another +// - return when the last instance of a service is removed +// - block until an instance for this service is available, or another // service is unregistered. func maxIndexForService(tx ReadTxn, serviceName string, serviceExists, checks bool, entMeta *acl.EnterpriseMeta, peerName string) uint64 { idx, _ := maxIndexAndWatchChForService(tx, serviceName, serviceExists, checks, entMeta, peerName) @@ -1280,8 +1284,8 @@ func maxIndexForService(tx ReadTxn, serviceName string, serviceExists, checks bo // index. The service_last_extinction is set to the last raft index when a // service was unregistered (or 0 if no services were ever unregistered). This // allows blocking queries to -// * return when the last instance of a service is removed -// * block until an instance for this service is available, or another +// - return when the last instance of a service is removed +// - block until an instance for this service is available, or another // service is unregistered. // // It also _may_ return a watch chan to add to a WatchSet. It will only return @@ -1915,17 +1919,17 @@ func (s *Store) deleteServiceTxn(tx WriteTxn, idx uint64, nodeName, serviceID st return fmt.Errorf("failed updating service-kind indexes: %w", err) } // Update the node indexes as the service information is included in node catalog queries. - if err := catalogUpdateNodesIndexes(tx, idx, entMeta, peerName); err != nil { + if err := catalogUpdateNodesIndexes(tx, idx, entMeta, svc.PeerName); err != nil { return fmt.Errorf("failed updating nodes indexes: %w", err) } - if err := catalogUpdateNodeIndexes(tx, idx, nodeName, entMeta, peerName); err != nil { + if err := catalogUpdateNodeIndexes(tx, idx, nodeName, entMeta, svc.PeerName); err != nil { return fmt.Errorf("failed updating node indexes: %w", err) } - name := svc.CompoundServiceName() + psn := svc.CompoundServiceName() if err := cleanupMeshTopology(tx, idx, svc); err != nil { - return fmt.Errorf("failed to clean up mesh-topology associations for %q: %v", name.String(), err) + return fmt.Errorf("failed to clean up mesh-topology associations for %q: %v", psn.String(), err) } q := Query{ @@ -1952,22 +1956,42 @@ func (s *Store) deleteServiceTxn(tx WriteTxn, idx uint64, nodeName, serviceID st if err := catalogUpdateServiceExtinctionIndex(tx, idx, entMeta, svc.PeerName); err != nil { return err } - psn := structs.PeeredServiceName{Peer: svc.PeerName, ServiceName: name} if err := freeServiceVirtualIP(tx, idx, psn, nil); err != nil { - return fmt.Errorf("failed to clean up virtual IP for %q: %v", name.String(), err) + return fmt.Errorf("failed to clean up virtual IP for %q: %v", psn.String(), err) } - if err := cleanupKindServiceName(tx, idx, svc.CompoundServiceName(), svc.ServiceKind); err != nil { - return fmt.Errorf("failed to persist service name: %v", err) + + if svc.PeerName == "" { + if err := cleanupKindServiceName(tx, idx, psn.ServiceName, svc.ServiceKind); err != nil { + return fmt.Errorf("failed to persist service name: %v", err) + } } } } else { return fmt.Errorf("Could not find any service %s: %s", svc.ServiceName, err) } + // Cleanup ConnectEnabled for this service if none exist. + if svc.PeerName == "" && (svc.ServiceKind == structs.ServiceKindConnectProxy || svc.ServiceConnect.Native) { + service := svc.ServiceName + if svc.ServiceKind == structs.ServiceKindConnectProxy { + service = svc.ServiceProxy.DestinationServiceName + } + sn := structs.ServiceName{Name: service, EnterpriseMeta: svc.EnterpriseMeta} + connectEnabled, err := serviceHasConnectEnabledInstances(tx, sn.Name, &sn.EnterpriseMeta) + if err != nil { + return fmt.Errorf("failed to search for connect instances for service %q: %w", sn.Name, err) + } + if !connectEnabled { + if err := cleanupKindServiceName(tx, idx, sn, structs.ServiceKindConnectEnabled); err != nil { + return fmt.Errorf("failed to cleanup connect-enabled service name: %v", err) + } + } + } + if svc.PeerName == "" { sn := structs.ServiceName{Name: svc.ServiceName, EnterpriseMeta: svc.EnterpriseMeta} if err := cleanupGatewayWildcards(tx, idx, sn, false); err != nil { - return fmt.Errorf("failed to clean up gateway-service associations for %q: %v", name.String(), err) + return fmt.Errorf("failed to clean up gateway-service associations for %q: %v", psn.String(), err) } } @@ -2672,7 +2696,7 @@ func (s *Store) CheckIngressServiceNodes(ws memdb.WatchSet, serviceName string, // De-dup services to lookup names := make(map[structs.ServiceName]struct{}) for _, n := range nodes { - names[n.CompoundServiceName()] = struct{}{} + names[n.CompoundServiceName().ServiceName] = struct{}{} } var results structs.CheckServiceNodes @@ -3634,7 +3658,7 @@ func updateGatewayNamespace(tx WriteTxn, idx uint64, service *structs.GatewaySer continue } - existing, err := tx.First(tableGatewayServices, indexID, service.Gateway, sn.CompoundServiceName(), service.Port) + existing, err := tx.First(tableGatewayServices, indexID, service.Gateway, sn.CompoundServiceName().ServiceName, service.Port) if err != nil { return fmt.Errorf("gateway service lookup failed: %s", err) } @@ -3731,6 +3755,27 @@ func serviceHasConnectInstances(tx WriteTxn, serviceName string, entMeta *acl.En return hasConnectInstance, hasNonConnectInstance, nil } +// serviceHasConnectEnabledInstances returns whether the given service name +// has a corresponding connect-proxy or connect-native instance. +// This function is mostly a clone of `serviceHasConnectInstances`, but it has +// an early return to improve performance and returns true if at least one +// connect-native instance exists. +func serviceHasConnectEnabledInstances(tx WriteTxn, serviceName string, entMeta *acl.EnterpriseMeta) (bool, error) { + query := Query{ + Value: serviceName, + EnterpriseMeta: *entMeta, + } + + svc, err := tx.First(tableServices, indexConnect, query) + if err != nil { + return false, fmt.Errorf("failed service lookup: %w", err) + } + if svc != nil { + return true, nil + } + return false, nil +} + // updateGatewayService associates services with gateways after an eligible event // ie. Registering a service in a namespace targeted by a gateway func updateGatewayService(tx WriteTxn, idx uint64, mapping *structs.GatewayService) error { @@ -4518,14 +4563,7 @@ func updateMeshTopology(tx WriteTxn, idx uint64, node string, svc *structs.NodeS var mapping *upstreamDownstream if existing, ok := obj.(*upstreamDownstream); ok { - rawCopy, err := copystructure.Copy(existing) - if err != nil { - return fmt.Errorf("failed to copy existing topology mapping: %v", err) - } - mapping, ok = rawCopy.(*upstreamDownstream) - if !ok { - return fmt.Errorf("unexpected topology type %T", rawCopy) - } + mapping := existing.DeepCopy() mapping.Refs[uid] = struct{}{} mapping.ModifyIndex = idx @@ -4567,7 +4605,10 @@ func updateMeshTopology(tx WriteTxn, idx uint64, node string, svc *structs.NodeS // cleanupMeshTopology removes a service from the mesh topology table // This is only safe to call when there are no more known instances of this proxy func cleanupMeshTopology(tx WriteTxn, idx uint64, service *structs.ServiceNode) error { - // TODO(peering): make this peering aware? + if service.PeerName != "" { + return nil + } + if service.ServiceKind != structs.ServiceKindConnectProxy { return nil } @@ -4588,14 +4629,7 @@ func cleanupMeshTopology(tx WriteTxn, idx uint64, service *structs.ServiceNode) // Do the updates in a separate loop so we don't trash the iterator. for _, m := range mappings { - rawCopy, err := copystructure.Copy(m) - if err != nil { - return fmt.Errorf("failed to copy existing topology mapping: %v", err) - } - copy, ok := rawCopy.(*upstreamDownstream) - if !ok { - return fmt.Errorf("unexpected topology type %T", rawCopy) - } + copy := m.DeepCopy() // Bail early if there's no reference to the proxy ID we're deleting if _, ok := copy.Refs[uid]; !ok { diff --git a/agent/consul/state/catalog_oss.go b/agent/consul/state/catalog_ce.go similarity index 98% rename from agent/consul/state/catalog_oss.go rename to agent/consul/state/catalog_ce.go index b7632f295bf2..ee599402d600 100644 --- a/agent/consul/state/catalog_oss.go +++ b/agent/consul/state/catalog_ce.go @@ -54,8 +54,8 @@ func catalogUpdateNodeIndexes(tx WriteTxn, idx uint64, nodeName string, _ *acl.E // catalogUpdateServicesIndexes upserts the max index for the entire services table with varying levels // of granularity (no-op if `idx` is lower than what exists for that index key): -// - all services -// - all services in a specified peer (including internal) +// - all services +// - all services in a specified peer (including internal) func catalogUpdateServicesIndexes(tx WriteTxn, idx uint64, _ *acl.EnterpriseMeta, peerName string) error { // overall services index for snapshot if err := indexUpdateMaxTxn(tx, idx, tableServices); err != nil { @@ -72,8 +72,8 @@ func catalogUpdateServicesIndexes(tx WriteTxn, idx uint64, _ *acl.EnterpriseMeta // catalogUpdateServiceKindIndexes upserts the max index for the ServiceKind with varying levels // of granularity (no-op if `idx` is lower than what exists for that index key): -// - all services of ServiceKind -// - all services of ServiceKind in a specified peer (including internal) +// - all services of ServiceKind +// - all services of ServiceKind in a specified peer (including internal) func catalogUpdateServiceKindIndexes(tx WriteTxn, idx uint64, kind structs.ServiceKind, _ *acl.EnterpriseMeta, peerName string) error { base := "service_kind." + kind.Normalized() // service-kind index @@ -112,7 +112,7 @@ func catalogUpdateNodeExtinctionIndex(tx WriteTxn, idx uint64, _ *acl.Enterprise } func catalogInsertNode(tx WriteTxn, node *structs.Node) error { - // ensure that the Partition is always clear within the state store in OSS + // ensure that the Partition is always clear within the state store in CE node.Partition = "" // Insert the node and update the index. diff --git a/agent/consul/state/catalog_oss_test.go b/agent/consul/state/catalog_ce_test.go similarity index 100% rename from agent/consul/state/catalog_oss_test.go rename to agent/consul/state/catalog_ce_test.go diff --git a/agent/consul/state/catalog_events.go b/agent/consul/state/catalog_events.go index 06d6414af53d..5fa03023e635 100644 --- a/agent/consul/state/catalog_events.go +++ b/agent/consul/state/catalog_events.go @@ -44,7 +44,6 @@ type EventPayloadCheckServiceNode struct { } func (e EventPayloadCheckServiceNode) HasReadPermission(authz acl.Authorizer) bool { - // TODO(peering): figure out how authz works for peered data return e.Value.CanRead(authz) == acl.Allow } diff --git a/agent/consul/state/catalog_events_oss.go b/agent/consul/state/catalog_events_ce.go similarity index 100% rename from agent/consul/state/catalog_events_oss.go rename to agent/consul/state/catalog_events_ce.go diff --git a/agent/consul/state/catalog_events_oss_test.go b/agent/consul/state/catalog_events_ce_test.go similarity index 92% rename from agent/consul/state/catalog_events_oss_test.go rename to agent/consul/state/catalog_events_ce_test.go index ace7cfe71202..8c29c692983b 100644 --- a/agent/consul/state/catalog_events_oss_test.go +++ b/agent/consul/state/catalog_events_ce_test.go @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/consul/agent/structs" ) -func TestEventPayloadCheckServiceNode_Subject_OSS(t *testing.T) { +func TestEventPayloadCheckServiceNode_Subject_CE(t *testing.T) { for desc, tc := range map[string]struct { evt EventPayloadCheckServiceNode sub string diff --git a/agent/consul/state/catalog_schema.deepcopy.go b/agent/consul/state/catalog_schema.deepcopy.go new file mode 100644 index 000000000000..406a7fdce796 --- /dev/null +++ b/agent/consul/state/catalog_schema.deepcopy.go @@ -0,0 +1,15 @@ +// generated by deep-copy -pointer-receiver -o ./catalog_schema.deepcopy.go -type upstreamDownstream ./; DO NOT EDIT. + +package state + +// DeepCopy generates a deep copy of *upstreamDownstream +func (o *upstreamDownstream) DeepCopy() *upstreamDownstream { + var cp upstreamDownstream = *o + if o.Refs != nil { + cp.Refs = make(map[string]struct{}, len(o.Refs)) + for k2, v2 := range o.Refs { + cp.Refs[k2] = v2 + } + } + return &cp +} diff --git a/agent/consul/state/catalog_schema.go b/agent/consul/state/catalog_schema.go index 5d0fe438cd0d..cad35bf4368b 100644 --- a/agent/consul/state/catalog_schema.go +++ b/agent/consul/state/catalog_schema.go @@ -418,7 +418,7 @@ func indexServiceNameFromHealthCheck(hc *structs.HealthCheck) ([]byte, error) { return b.Bytes(), nil } -// gatewayServicesTableSchema returns a new table schema used to store information +// gatewayServicesTableSchema returns a new table schema used to store information // about services associated with terminating gateways. func gatewayServicesTableSchema() *memdb.TableSchema { return &memdb.TableSchema{ diff --git a/agent/consul/state/catalog_test.go b/agent/consul/state/catalog_test.go index d354b9b094e3..b5976bbd2b00 100644 --- a/agent/consul/state/catalog_test.go +++ b/agent/consul/state/catalog_test.go @@ -2577,20 +2577,49 @@ func TestStateStore_DeleteService(t *testing.T) { testRegisterService(t, s, 2, "node1", "service1") testRegisterCheck(t, s, 3, "node1", "service1", "check1", api.HealthPassing) - // Delete the service. + // register a node with a service on a cluster peer. + testRegisterNodeOpts(t, s, 4, "node1", func(n *structs.Node) error { + n.PeerName = "cluster-01" + return nil + }) + testRegisterServiceOpts(t, s, 5, "node1", "service1", func(service *structs.NodeService) { + service.PeerName = "cluster-01" + }) + + wsPeer := memdb.NewWatchSet() + _, ns, err := s.NodeServices(wsPeer, "node1", nil, "cluster-01") + require.Len(t, ns.Services, 1) + require.NoError(t, err) + ws := memdb.NewWatchSet() - _, _, err := s.NodeServices(ws, "node1", nil, "") + _, ns, err = s.NodeServices(ws, "node1", nil, "") + require.Len(t, ns.Services, 1) require.NoError(t, err) - if err := s.DeleteService(4, "node1", "service1", nil, ""); err != nil { - t.Fatalf("err: %s", err) + + { + // Delete the peered service. + err = s.DeleteService(6, "node1", "service1", nil, "cluster-01") + require.NoError(t, err) + require.True(t, watchFired(wsPeer)) + _, kindServiceNames, err := s.ServiceNamesOfKind(nil, structs.ServiceKindTypical) + require.NoError(t, err) + require.Len(t, kindServiceNames, 1) + require.Equal(t, "service1", kindServiceNames[0].Service.Name) } - if !watchFired(ws) { - t.Fatalf("bad") + + { + // Delete the service. + err = s.DeleteService(6, "node1", "service1", nil, "") + require.NoError(t, err) + require.True(t, watchFired(ws)) + _, kindServiceNames, err := s.ServiceNamesOfKind(nil, structs.ServiceKindTypical) + require.NoError(t, err) + require.Len(t, kindServiceNames, 0) } // Service doesn't exist. ws = memdb.NewWatchSet() - _, ns, err := s.NodeServices(ws, "node1", nil, "") + _, ns, err = s.NodeServices(ws, "node1", nil, "") if err != nil || ns == nil || len(ns.Services) != 0 { t.Fatalf("bad: %#v (err: %#v)", ns, err) } @@ -2605,15 +2634,15 @@ func TestStateStore_DeleteService(t *testing.T) { } // Index tables were updated. - assert.Equal(t, uint64(4), catalogChecksMaxIndex(tx, nil, "")) - assert.Equal(t, uint64(4), catalogServicesMaxIndex(tx, nil, "")) + assert.Equal(t, uint64(6), catalogChecksMaxIndex(tx, nil, "")) + assert.Equal(t, uint64(6), catalogServicesMaxIndex(tx, nil, "")) // Deleting a nonexistent service should be idempotent and not return an // error, nor fire a watch. - if err := s.DeleteService(5, "node1", "service1", nil, ""); err != nil { + if err := s.DeleteService(6, "node1", "service1", nil, ""); err != nil { t.Fatalf("err: %s", err) } - assert.Equal(t, uint64(4), catalogServicesMaxIndex(tx, nil, "")) + assert.Equal(t, uint64(6), catalogServicesMaxIndex(tx, nil, "")) if watchFired(ws) { t.Fatalf("bad") } @@ -8664,7 +8693,7 @@ func TestStateStore_EnsureService_ServiceNames(t *testing.T) { }, } - var idx uint64 + var idx, connectEnabledIdx uint64 testRegisterNode(t, s, idx, "node1") for _, svc := range services { @@ -8678,8 +8707,29 @@ func TestStateStore_EnsureService_ServiceNames(t *testing.T) { require.Len(t, gotNames, 1) require.Equal(t, svc.CompoundServiceName(), gotNames[0].Service) require.Equal(t, svc.Kind, gotNames[0].Kind) + if svc.Kind == structs.ServiceKindConnectProxy { + connectEnabledIdx = idx + } } + // A ConnectEnabled service should exist if a corresponding ConnectProxy or ConnectNative service exists. + verifyConnectEnabled := func(expectIdx uint64) { + gotIdx, gotNames, err := s.ServiceNamesOfKind(nil, structs.ServiceKindConnectEnabled) + require.NoError(t, err) + require.Equal(t, expectIdx, gotIdx) + require.Equal(t, []*KindServiceName{ + { + Kind: structs.ServiceKindConnectEnabled, + Service: structs.NewServiceName("foo", entMeta), + RaftIndex: structs.RaftIndex{ + CreateIndex: connectEnabledIdx, + ModifyIndex: connectEnabledIdx, + }, + }, + }, gotNames) + } + verifyConnectEnabled(connectEnabledIdx) + // Register another ingress gateway and there should be two names under the kind index newIngress := structs.NodeService{ Kind: structs.ServiceKindIngressGateway, @@ -8749,6 +8799,38 @@ func TestStateStore_EnsureService_ServiceNames(t *testing.T) { require.NoError(t, err) require.Equal(t, idx, gotIdx) require.Empty(t, got) + + // A ConnectEnabled entry should not be removed until all corresponding services are removed. + { + verifyConnectEnabled(connectEnabledIdx) + // Add a connect-native service. + idx++ + require.NoError(t, s.EnsureService(idx, "node1", &structs.NodeService{ + Kind: structs.ServiceKindTypical, + ID: "foo", + Service: "foo", + Address: "5.5.5.5", + Port: 5555, + EnterpriseMeta: *entMeta, + Connect: structs.ServiceConnect{ + Native: true, + }, + })) + verifyConnectEnabled(connectEnabledIdx) + + // Delete the proxy. This should not clean up the entry, because we still have a + // connect-native service registered. + idx++ + require.NoError(t, s.DeleteService(idx, "node1", "connect-proxy", entMeta, "")) + verifyConnectEnabled(connectEnabledIdx) + + // Remove the connect-native service to clear out the connect-enabled entry. + require.NoError(t, s.DeleteService(idx, "node1", "foo", entMeta, "")) + gotIdx, gotNames, err := s.ServiceNamesOfKind(nil, structs.ServiceKindConnectEnabled) + require.NoError(t, err) + require.Equal(t, idx, gotIdx) + require.Empty(t, gotNames) + } } func assertMaxIndexes(t *testing.T, tx ReadTxn, expect map[string]uint64, skip ...string) { diff --git a/agent/consul/state/config_entry_oss.go b/agent/consul/state/config_entry_ce.go similarity index 93% rename from agent/consul/state/config_entry_oss.go rename to agent/consul/state/config_entry_ce.go index 56fff98e8704..07e7167b3832 100644 --- a/agent/consul/state/config_entry_oss.go +++ b/agent/consul/state/config_entry_ce.go @@ -7,7 +7,7 @@ import ( "fmt" "strings" - memdb "github.com/hashicorp/go-memdb" + "github.com/hashicorp/go-memdb" "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/configentry" @@ -62,9 +62,10 @@ func configIntentionsConvertToList(iter memdb.ResultIterator, _ *acl.EnterpriseM } // getExportedServicesMatchServicesNames returns a list of service names that are considered matches when -// found in a list of exported-services config entries. For OSS, namespace is not considered, so a match is one of: +// found in a list of exported-services config entries. For CE, namespace is not considered, so a match is one of: // - the service name matches // - the service name is a wildcard +// // This value can be used to filter exported-services config entries for a given service name. func getExportedServicesMatchServiceNames(serviceName string, entMeta *acl.EnterpriseMeta) []structs.ServiceName { return []structs.ServiceName{ diff --git a/agent/consul/state/config_entry_oss_test.go b/agent/consul/state/config_entry_ce_test.go similarity index 100% rename from agent/consul/state/config_entry_oss_test.go rename to agent/consul/state/config_entry_ce_test.go diff --git a/agent/consul/state/config_entry_events.go b/agent/consul/state/config_entry_events.go index 2792ff6d8262..5fc71f0275c9 100644 --- a/agent/consul/state/config_entry_events.go +++ b/agent/consul/state/config_entry_events.go @@ -16,6 +16,7 @@ var configEntryKindToTopic = map[string]stream.Topic{ structs.ServiceResolver: EventTopicServiceResolver, structs.IngressGateway: EventTopicIngressGateway, structs.ServiceIntentions: EventTopicServiceIntentions, + structs.ServiceDefaults: EventTopicServiceDefaults, } // EventSubjectConfigEntry is a stream.Subject used to route and receive events @@ -110,6 +111,12 @@ func (s *Store) ServiceIntentionsSnapshot(req stream.SubscribeRequest, buf strea return s.configEntrySnapshot(structs.ServiceIntentions, req, buf) } +// ServiceDefaultsSnapshot is a stream.SnapshotFunc that returns a snapshot of +// service-defaults config entries. +func (s *Store) ServiceDefaultsSnapshot(req stream.SubscribeRequest, buf stream.SnapshotAppender) (uint64, error) { + return s.configEntrySnapshot(structs.ServiceDefaults, req, buf) +} + func (s *Store) configEntrySnapshot(kind string, req stream.SubscribeRequest, buf stream.SnapshotAppender) (uint64, error) { var ( idx uint64 diff --git a/agent/consul/state/config_entry_events_test.go b/agent/consul/state/config_entry_events_test.go index c00450401006..2e50b677bda2 100644 --- a/agent/consul/state/config_entry_events_test.go +++ b/agent/consul/state/config_entry_events_test.go @@ -178,6 +178,47 @@ func TestConfigEntryEventsFromChanges(t *testing.T) { }, }, }, + "upsert service defaults": { + mutate: func(tx *txn) error { + return ensureConfigEntryTxn(tx, 0, &structs.ServiceConfigEntry{ + Name: "web", + }) + }, + events: []stream.Event{ + { + Topic: EventTopicServiceDefaults, + Index: changeIndex, + Payload: EventPayloadConfigEntry{ + Op: pbsubscribe.ConfigEntryUpdate_Upsert, + Value: &structs.ServiceConfigEntry{ + Name: "web", + }, + }, + }, + }, + }, + "delete service defaults": { + setup: func(tx *txn) error { + return ensureConfigEntryTxn(tx, 0, &structs.ServiceConfigEntry{ + Name: "web", + }) + }, + mutate: func(tx *txn) error { + return deleteConfigEntryTxn(tx, 0, structs.ServiceDefaults, "web", nil) + }, + events: []stream.Event{ + { + Topic: EventTopicServiceDefaults, + Index: changeIndex, + Payload: EventPayloadConfigEntry{ + Op: pbsubscribe.ConfigEntryUpdate_Delete, + Value: &structs.ServiceConfigEntry{ + Name: "web", + }, + }, + }, + }, + }, } for desc, tc := range testCases { t.Run(desc, func(t *testing.T) { @@ -376,11 +417,11 @@ func TestServiceIntentionsSnapshot(t *testing.T) { ixn1 := &structs.ServiceIntentionsConfigEntry{ Kind: structs.ServiceIntentions, - Name: "gw1", + Name: "svc1", } ixn2 := &structs.ServiceIntentionsConfigEntry{ Kind: structs.ServiceIntentions, - Name: "gw2", + Name: "svc2", } store := testStateStore(t) @@ -438,3 +479,71 @@ func TestServiceIntentionsSnapshot(t *testing.T) { }) } } + +func TestServiceDefaultsSnapshot(t *testing.T) { + const index uint64 = 123 + + ixn1 := &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "svc1", + } + ixn2 := &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "svc2", + } + + store := testStateStore(t) + require.NoError(t, store.EnsureConfigEntry(index, ixn1)) + require.NoError(t, store.EnsureConfigEntry(index, ixn2)) + + testCases := map[string]struct { + subject stream.Subject + events []stream.Event + }{ + "named entry": { + subject: EventSubjectConfigEntry{Name: ixn1.Name}, + events: []stream.Event{ + { + Topic: EventTopicServiceDefaults, + Index: index, + Payload: EventPayloadConfigEntry{ + Op: pbsubscribe.ConfigEntryUpdate_Upsert, + Value: ixn1, + }, + }, + }, + }, + "wildcard": { + subject: stream.SubjectWildcard, + events: []stream.Event{ + { + Topic: EventTopicServiceDefaults, + Index: index, + Payload: EventPayloadConfigEntry{ + Op: pbsubscribe.ConfigEntryUpdate_Upsert, + Value: ixn1, + }, + }, + { + Topic: EventTopicServiceDefaults, + Index: index, + Payload: EventPayloadConfigEntry{ + Op: pbsubscribe.ConfigEntryUpdate_Upsert, + Value: ixn2, + }, + }, + }, + }, + } + for desc, tc := range testCases { + t.Run(desc, func(t *testing.T) { + buf := &snapshotAppender{} + + idx, err := store.ServiceDefaultsSnapshot(stream.SubscribeRequest{Subject: tc.subject}, buf) + require.NoError(t, err) + require.Equal(t, index, idx) + require.Len(t, buf.events, 1) + require.ElementsMatch(t, tc.events, buf.events[0]) + }) + } +} diff --git a/agent/consul/state/config_entry_intention.go b/agent/consul/state/config_entry_intention.go index 17183e7ceece..76b5a487af0d 100644 --- a/agent/consul/state/config_entry_intention.go +++ b/agent/consul/state/config_entry_intention.go @@ -80,7 +80,7 @@ type ServiceIntentionSourceIndex struct { } // Compile-time assert that these interfaces hold to ensure that the -// methods correctly exist across the oss/ent split. +// methods correctly exist across the ce/ent split. var _ memdb.Indexer = (*ServiceIntentionSourceIndex)(nil) var _ memdb.MultiIndexer = (*ServiceIntentionSourceIndex)(nil) diff --git a/agent/consul/state/config_entry_intention_oss.go b/agent/consul/state/config_entry_intention_ce.go similarity index 100% rename from agent/consul/state/config_entry_intention_oss.go rename to agent/consul/state/config_entry_intention_ce.go diff --git a/agent/consul/state/config_entry_test.go b/agent/consul/state/config_entry_test.go index e32b1853435e..5253a20278e1 100644 --- a/agent/consul/state/config_entry_test.go +++ b/agent/consul/state/config_entry_test.go @@ -910,7 +910,7 @@ func TestStore_ConfigEntry_GraphValidation(t *testing.T) { if err := entry.Validate(); err != nil { return err } - return s.EnsureConfigEntry(0, entry) + return s.EnsureConfigEntry(idx, entry) } type tcase struct { diff --git a/agent/consul/state/coordinate_oss.go b/agent/consul/state/coordinate_ce.go similarity index 100% rename from agent/consul/state/coordinate_oss.go rename to agent/consul/state/coordinate_ce.go diff --git a/agent/consul/state/coordinate_oss_test.go b/agent/consul/state/coordinate_ce_test.go similarity index 100% rename from agent/consul/state/coordinate_oss_test.go rename to agent/consul/state/coordinate_ce_test.go diff --git a/agent/consul/state/deep-copy.sh b/agent/consul/state/deep-copy.sh new file mode 100755 index 000000000000..d976d921f3c8 --- /dev/null +++ b/agent/consul/state/deep-copy.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +readonly PACKAGE_DIR="$(dirname "${BASH_SOURCE[0]}")" +cd $PACKAGE_DIR + +# Uses: https://github.com/globusdigital/deep-copy +deep-copy \ + -pointer-receiver \ + -o ./catalog_schema.deepcopy.go \ + -type upstreamDownstream \ + ./ diff --git a/agent/consul/state/delay_oss.go b/agent/consul/state/delay_ce.go similarity index 100% rename from agent/consul/state/delay_oss.go rename to agent/consul/state/delay_ce.go diff --git a/agent/consul/state/events.go b/agent/consul/state/events.go index 2e74c44c946f..93a4558f271d 100644 --- a/agent/consul/state/events.go +++ b/agent/consul/state/events.go @@ -38,7 +38,7 @@ func PBToStreamSubscribeRequest(req *pbsubscribe.SubscribeRequest, entMeta acl.E EnterpriseMeta: entMeta, PeerName: named.PeerName, } - case EventTopicMeshConfig, EventTopicServiceResolver, EventTopicIngressGateway, EventTopicServiceIntentions: + case EventTopicMeshConfig, EventTopicServiceResolver, EventTopicIngressGateway, EventTopicServiceIntentions, EventTopicServiceDefaults: subject = EventSubjectConfigEntry{ Name: named.Key, EnterpriseMeta: &entMeta, diff --git a/agent/consul/state/graveyard_oss.go b/agent/consul/state/graveyard_ce.go similarity index 100% rename from agent/consul/state/graveyard_oss.go rename to agent/consul/state/graveyard_ce.go diff --git a/agent/consul/state/intention_oss.go b/agent/consul/state/intention_ce.go similarity index 100% rename from agent/consul/state/intention_oss.go rename to agent/consul/state/intention_ce.go diff --git a/agent/consul/state/kvs_oss.go b/agent/consul/state/kvs_ce.go similarity index 100% rename from agent/consul/state/kvs_oss.go rename to agent/consul/state/kvs_ce.go diff --git a/agent/consul/state/kvs_oss_test.go b/agent/consul/state/kvs_ce_test.go similarity index 100% rename from agent/consul/state/kvs_oss_test.go rename to agent/consul/state/kvs_ce_test.go diff --git a/agent/consul/state/memdb.go b/agent/consul/state/memdb.go index 751622977013..395325ee61f3 100644 --- a/agent/consul/state/memdb.go +++ b/agent/consul/state/memdb.go @@ -184,6 +184,7 @@ var ( EventTopicServiceResolver = pbsubscribe.Topic_ServiceResolver EventTopicIngressGateway = pbsubscribe.Topic_IngressGateway EventTopicServiceIntentions = pbsubscribe.Topic_ServiceIntentions + EventTopicServiceDefaults = pbsubscribe.Topic_ServiceDefaults EventTopicServiceList = pbsubscribe.Topic_ServiceList ) diff --git a/agent/consul/state/operations_oss.go b/agent/consul/state/operations_ce.go similarity index 100% rename from agent/consul/state/operations_oss.go rename to agent/consul/state/operations_ce.go diff --git a/agent/consul/state/peering.go b/agent/consul/state/peering.go index be2aa1c73a48..3ecd19994653 100644 --- a/agent/consul/state/peering.go +++ b/agent/consul/state/peering.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/configentry" "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/lib/maps" "github.com/hashicorp/consul/proto/pbpeering" ) @@ -769,88 +770,181 @@ func exportedServicesForPeerTxn( maxIdx := peering.ModifyIndex entMeta := structs.NodeEnterpriseMetaInPartition(peering.Partition) - idx, conf, err := getExportedServicesConfigEntryTxn(tx, ws, nil, entMeta) + idx, exportConf, err := getExportedServicesConfigEntryTxn(tx, ws, nil, entMeta) if err != nil { return 0, nil, fmt.Errorf("failed to fetch exported-services config entry: %w", err) } if idx > maxIdx { maxIdx = idx } - if conf == nil { + if exportConf == nil { return maxIdx, &structs.ExportedServiceList{}, nil } var ( - normalSet = make(map[structs.ServiceName]struct{}) - discoSet = make(map[structs.ServiceName]struct{}) + // exportedServices will contain the listing of all service names that are being exported + // and will need to be queried for connect / discovery chain information. + exportedServices = make(map[structs.ServiceName]struct{}) + + // exportedConnectServices will contain the listing of all connect service names that are being exported. + exportedConnectServices = make(map[structs.ServiceName]struct{}) + + // namespaceConnectServices provides a listing of all connect service names for a particular partition+namespace pair. + namespaceConnectServices = make(map[acl.EnterpriseMeta]map[string]struct{}) + + // namespaceDiscoChains provides a listing of all disco chain names for a particular partition+namespace pair. + namespaceDiscoChains = make(map[acl.EnterpriseMeta]map[string]struct{}) ) - // At least one of the following should be true for a name for it to - // replicate: - // - // - are a discovery chain by definition (service-router, service-splitter, service-resolver) - // - have an explicit sidecar kind=connect-proxy - // - use connect native mode + // Helper function for inserting data and auto-creating maps. + insertEntry := func(m map[acl.EnterpriseMeta]map[string]struct{}, entMeta acl.EnterpriseMeta, name string) { + names, ok := m[entMeta] + if !ok { + names = make(map[string]struct{}) + m[entMeta] = names + } + names[name] = struct{}{} + } - for _, svc := range conf.Services { + // Build the set of all services that will be exported. + // Any possible namespace wildcards or "consul" services should be removed by this step. + for _, svc := range exportConf.Services { // Prevent exporting the "consul" service. if svc.Name == structs.ConsulServiceName { continue } - svcMeta := acl.NewEnterpriseMetaWithPartition(entMeta.PartitionOrDefault(), svc.Namespace) + svcEntMeta := acl.NewEnterpriseMetaWithPartition(entMeta.PartitionOrDefault(), svc.Namespace) + svcName := structs.NewServiceName(svc.Name, &svcEntMeta) - sawPeer := false + peerFound := false for _, consumer := range svc.Consumers { - name := structs.NewServiceName(svc.Name, &svcMeta) - - if _, ok := normalSet[name]; ok { - // Service was covered by a wildcard that was already accounted for - continue + if consumer.Peer == peering.Name { + peerFound = true + break } - if consumer.Peer != peering.Name { - continue + } + // Only look for more information if the matching peer was found. + if !peerFound { + continue + } + + // If this isn't a wildcard, we can simply add it to the list of services to watch and move to the next entry. + if svc.Name != structs.WildcardSpecifier { + exportedServices[svcName] = struct{}{} + continue + } + + // If all services in the namespace are exported by the wildcard, query those service names. + idx, typicalServices, err := serviceNamesOfKindTxn(tx, ws, structs.ServiceKindTypical, svcEntMeta) + if err != nil { + return 0, nil, fmt.Errorf("failed to get typical service names: %w", err) + } + if idx > maxIdx { + maxIdx = idx + } + for _, sn := range typicalServices { + // Prevent exporting the "consul" service. + if sn.Service.Name != structs.ConsulServiceName { + exportedServices[sn.Service] = struct{}{} } - sawPeer = true + } - if svc.Name != structs.WildcardSpecifier { - normalSet[name] = struct{}{} + // List all config entries of kind service-resolver, service-router, service-splitter, because they + // will be exported as connect services. + idx, discoChains, err := listDiscoveryChainNamesTxn(tx, ws, nil, svcEntMeta) + if err != nil { + return 0, nil, fmt.Errorf("failed to get discovery chain names: %w", err) + } + if idx > maxIdx { + maxIdx = idx + } + for _, sn := range discoChains { + // Prevent exporting the "consul" service. + if sn.Name != structs.ConsulServiceName { + exportedConnectServices[sn] = struct{}{} + insertEntry(namespaceDiscoChains, svcEntMeta, sn.Name) } } + } - // If the target peer is a consumer, and all services in the namespace are exported, query those service names. - if sawPeer && svc.Name == structs.WildcardSpecifier { - idx, typicalServices, err := serviceNamesOfKindTxn(tx, ws, structs.ServiceKindTypical, svcMeta) + // At least one of the following should be true for a name to replicate it as a *connect* service: + // - are a discovery chain by definition (service-router, service-splitter, service-resolver) + // - have an explicit sidecar kind=connect-proxy + // - use connect native mode + // - are registered with a terminating gateway + populateConnectService := func(sn structs.ServiceName) error { + // Load all disco-chains in this namespace if we haven't already. + if _, ok := namespaceDiscoChains[sn.EnterpriseMeta]; !ok { + // Check to see if we have a discovery chain with the same name. + idx, chains, err := listDiscoveryChainNamesTxn(tx, ws, nil, sn.EnterpriseMeta) if err != nil { - return 0, nil, fmt.Errorf("failed to get typical service names: %w", err) + return fmt.Errorf("failed to get connect services: %w", err) } if idx > maxIdx { maxIdx = idx } - for _, s := range typicalServices { - // Prevent exporting the "consul" service. - if s.Service.Name == structs.ConsulServiceName { - continue - } - normalSet[s.Service] = struct{}{} + for _, sn := range chains { + insertEntry(namespaceDiscoChains, sn.EnterpriseMeta, sn.Name) } + } + // Check to see if we have the connect service. + if _, ok := namespaceDiscoChains[sn.EnterpriseMeta][sn.Name]; ok { + exportedConnectServices[sn] = struct{}{} + // Do not early return because we have multiple watches that should be established. + } - // list all config entries of kind service-resolver, service-router, service-splitter? - idx, discoChains, err := listDiscoveryChainNamesTxn(tx, ws, nil, svcMeta) + // Load all services in this namespace if we haven't already. + if _, ok := namespaceConnectServices[sn.EnterpriseMeta]; !ok { + // This is more efficient than querying the service instance table. + idx, connectServices, err := serviceNamesOfKindTxn(tx, ws, structs.ServiceKindConnectEnabled, sn.EnterpriseMeta) if err != nil { - return 0, nil, fmt.Errorf("failed to get discovery chain names: %w", err) + return fmt.Errorf("failed to get connect services: %w", err) } if idx > maxIdx { maxIdx = idx } - for _, sn := range discoChains { - discoSet[sn] = struct{}{} + for _, ksn := range connectServices { + insertEntry(namespaceConnectServices, sn.EnterpriseMeta, ksn.Service.Name) } } + // Check to see if we have the connect service. + if _, ok := namespaceConnectServices[sn.EnterpriseMeta][sn.Name]; ok { + exportedConnectServices[sn] = struct{}{} + // Do not early return because we have multiple watches that should be established. + } + + // Check if the service is exposed via terminating gateways. + svcGateways, err := tx.Get(tableGatewayServices, indexService, sn) + if err != nil { + return fmt.Errorf("failed gateway lookup for %q: %w", sn.Name, err) + } + ws.Add(svcGateways.WatchCh()) + for svc := svcGateways.Next(); svc != nil; svc = svcGateways.Next() { + gs, ok := svc.(*structs.GatewayService) + if !ok { + return fmt.Errorf("failed converting to GatewayService for %q", sn.Name) + } + if gs.GatewayKind == structs.ServiceKindTerminatingGateway { + exportedConnectServices[sn] = struct{}{} + break + } + } + + return nil } - normal := maps.SliceOfKeys(normalSet) - disco := maps.SliceOfKeys(discoSet) + // Perform queries and check if each service is connect-enabled. + for sn := range exportedServices { + // Do not query for data if we already know it's a connect service. + if _, ok := exportedConnectServices[sn]; ok { + continue + } + if err := populateConnectService(sn); err != nil { + return 0, nil, err + } + } + // Fetch the protocol / targets for connect services. chainInfo := make(map[structs.ServiceName]structs.ExportedDiscoveryChainInfo) populateChainInfo := func(svc structs.ServiceName) error { if _, ok := chainInfo[svc]; ok { @@ -898,21 +992,17 @@ func exportedServicesForPeerTxn( return nil } - for _, svc := range normal { - if err := populateChainInfo(svc); err != nil { - return 0, nil, err - } - } - for _, svc := range disco { + for svc := range exportedConnectServices { if err := populateChainInfo(svc); err != nil { return 0, nil, err } } - structs.ServiceList(normal).Sort() + sortedServices := maps.SliceOfKeys(exportedServices) + structs.ServiceList(sortedServices).Sort() list := &structs.ExportedServiceList{ - Services: normal, + Services: sortedServices, DiscoChains: chainInfo, } @@ -946,6 +1036,7 @@ func listAllExportedServices( return idx, found, nil } +//nolint:unparam func listServicesExportedToAnyPeerByConfigEntry( ws memdb.WatchSet, tx ReadTxn, @@ -1143,12 +1234,56 @@ func peeringTrustBundleReadTxn(tx ReadTxn, ws memdb.WatchSet, q Query) (uint64, return ptb.ModifyIndex, ptb, nil } -// PeeringTrustBundleWrite writes ptb to the state store. If there is an existing trust bundle with the given peer name, -// it will be overwritten. +// PeeringTrustBundleWrite writes ptb to the state store. +// It also updates the corresponding peering object with the new certs. +// If there is an existing trust bundle with the given peer name, it will be overwritten. +// If there is no corresponding peering, then an error is returned. func (s *Store) PeeringTrustBundleWrite(idx uint64, ptb *pbpeering.PeeringTrustBundle) error { tx := s.db.WriteTxn(idx) defer tx.Abort() + if ptb.PeerName == "" { + return errors.New("missing peer name") + } + + // Check for the existence of the peering object + _, existingPeering, err := peeringReadTxn(tx, nil, Query{ + Value: ptb.PeerName, + EnterpriseMeta: *structs.NodeEnterpriseMetaInPartition(ptb.Partition), + }) + if err != nil { + return err + } + if existingPeering == nil { + return fmt.Errorf("cannot write peering trust bundle for unknown peering %s", ptb.PeerName) + } + // Prevent modifications to Peering marked for deletion. + // This blocks generating new peering tokens or re-establishing the peering until the peering is done deleting. + if existingPeering.State == pbpeering.PeeringState_DELETING { + return fmt.Errorf("cannot write to peering that is marked for deletion") + } + c := proto.Clone(existingPeering) + clone, ok := c.(*pbpeering.Peering) + if !ok { + return fmt.Errorf("invalid type %T, expected *pbpeering.Peering", clone) + } + + // Update the certs on the peering + rootPEMs := make([]string, 0, len(ptb.RootPEMs)) + for _, c := range ptb.RootPEMs { + rootPEMs = append(rootPEMs, lib.EnsureTrailingNewline(c)) + } + clone.PeerCAPems = rootPEMs + clone.ModifyIndex = idx + + if err := tx.Insert(tablePeering, clone); err != nil { + return fmt.Errorf("failed inserting peering: %w", err) + } + if err := updatePeeringTableIndexes(tx, idx, clone.PartitionOrDefault()); err != nil { + return err + } + + // Check for the existing trust bundle and update q := Query{ Value: ptb.PeerName, EnterpriseMeta: *structs.NodeEnterpriseMetaInPartition(ptb.Partition), @@ -1158,13 +1293,13 @@ func (s *Store) PeeringTrustBundleWrite(idx uint64, ptb *pbpeering.PeeringTrustB return fmt.Errorf("failed peering trust bundle lookup: %w", err) } - existing, ok := existingRaw.(*pbpeering.PeeringTrustBundle) + existingPTB, ok := existingRaw.(*pbpeering.PeeringTrustBundle) if existingRaw != nil && !ok { return fmt.Errorf("invalid type %T", existingRaw) } - if existing != nil { - ptb.CreateIndex = existing.CreateIndex + if existingPTB != nil { + ptb.CreateIndex = existingPTB.CreateIndex } else { ptb.CreateIndex = idx @@ -1293,7 +1428,7 @@ func peersForServiceTxn( ) // Ensure the metadata is defaulted since we make assertions against potentially empty values below. - // In OSS this is a no-op. + // In CE this is a no-op. if entMeta == nil { entMeta = acl.DefaultEnterpriseMeta() } diff --git a/agent/consul/state/peering_oss.go b/agent/consul/state/peering_ce.go similarity index 100% rename from agent/consul/state/peering_oss.go rename to agent/consul/state/peering_ce.go diff --git a/agent/consul/state/peering_oss_test.go b/agent/consul/state/peering_ce_test.go similarity index 100% rename from agent/consul/state/peering_oss_test.go rename to agent/consul/state/peering_ce_test.go diff --git a/agent/consul/state/peering_test.go b/agent/consul/state/peering_test.go index 8e35bdb857e1..08b982352921 100644 --- a/agent/consul/state/peering_test.go +++ b/agent/consul/state/peering_test.go @@ -95,13 +95,42 @@ func insertTestPeeringTrustBundles(t *testing.T, s *Store) { tx := s.db.WriteTxn(0) defer tx.Abort() - err := tx.Insert(tablePeeringTrustBundles, &pbpeering.PeeringTrustBundle{ + // Insert peerings since it is assumed they exist before the trust bundle is created + err := tx.Insert(tablePeering, &pbpeering.Peering{ + Name: "foo", + ID: "89b8209d-0b64-45e2-8692-6c60181edbe7", + Partition: structs.NodeEnterpriseMetaInDefaultPartition().PartitionOrEmpty(), + PeerCAPems: []string{}, + PeerServerName: "foo.com", + CreateIndex: 1, + ModifyIndex: 1, + }) + require.NoError(t, err) + + err = tx.Insert(tablePeering, &pbpeering.Peering{ + Name: "baz", + ID: "d8230482-ae98-4b82-903f-e1ada3000ad4", + Partition: structs.NodeEnterpriseMetaInDefaultPartition().PartitionOrEmpty(), + PeerCAPems: []string{"old baz certificate bundle"}, + PeerServerName: "baz.com", + CreateIndex: 2, + ModifyIndex: 2, + }) + require.NoError(t, err) + + err = tx.Insert(tableIndex, &IndexEntry{ + Key: tablePeering, + Value: 2, + }) + require.NoError(t, err) + + err = tx.Insert(tablePeeringTrustBundles, &pbpeering.PeeringTrustBundle{ TrustDomain: "foo.com", PeerName: "foo", Partition: structs.NodeEnterpriseMetaInDefaultPartition().PartitionOrEmpty(), RootPEMs: []string{"foo certificate bundle"}, - CreateIndex: 1, - ModifyIndex: 1, + CreateIndex: 3, + ModifyIndex: 3, }) require.NoError(t, err) @@ -110,14 +139,14 @@ func insertTestPeeringTrustBundles(t *testing.T, s *Store) { PeerName: "bar", Partition: structs.NodeEnterpriseMetaInDefaultPartition().PartitionOrEmpty(), RootPEMs: []string{"bar certificate bundle"}, - CreateIndex: 2, - ModifyIndex: 2, + CreateIndex: 4, + ModifyIndex: 4, }) require.NoError(t, err) err = tx.Insert(tableIndex, &IndexEntry{ Key: tablePeeringTrustBundles, - Value: 2, + Value: 4, }) require.NoError(t, err) require.NoError(t, tx.Commit()) @@ -1549,16 +1578,16 @@ func TestStateStore_PeeringTrustBundleList(t *testing.T) { PeerName: "bar", Partition: entMeta.PartitionOrEmpty(), RootPEMs: []string{"bar certificate bundle"}, - CreateIndex: 2, - ModifyIndex: 2, + CreateIndex: 4, + ModifyIndex: 4, }, { TrustDomain: "foo.com", PeerName: "foo", Partition: entMeta.PartitionOrEmpty(), RootPEMs: []string{"foo certificate bundle"}, - CreateIndex: 1, - ModifyIndex: 1, + CreateIndex: 3, + ModifyIndex: 3, }, } @@ -1596,8 +1625,8 @@ func TestStateStore_PeeringTrustBundleRead(t *testing.T) { PeerName: "foo", Partition: entMeta.PartitionOrEmpty(), RootPEMs: []string{"foo certificate bundle"}, - CreateIndex: 1, - ModifyIndex: 1, + CreateIndex: 3, + ModifyIndex: 3, }, }, { @@ -1619,11 +1648,14 @@ func TestStore_PeeringTrustBundleWrite(t *testing.T) { s := NewStateStore(nil) insertTestPeeringTrustBundles(t, s) type testcase struct { - name string - input *pbpeering.PeeringTrustBundle + name string + input *pbpeering.PeeringTrustBundle + expectErr string } - run := func(t *testing.T, tc testcase) { - require.NoError(t, s.PeeringTrustBundleWrite(10, tc.input)) + run := func(t *testing.T, tc testcase) error { + if err := s.PeeringTrustBundleWrite(10, tc.input); err != nil { + return err + } q := Query{ Value: tc.input.PeerName, @@ -1634,6 +1666,16 @@ func TestStore_PeeringTrustBundleWrite(t *testing.T) { require.NotNil(t, ptb) require.Equal(t, tc.input.TrustDomain, ptb.TrustDomain) require.Equal(t, tc.input.PeerName, ptb.PeerName) + + // Validate peering object has certs updated + _, peering, err := s.PeeringRead(nil, Query{ + Value: tc.input.PeerName, + }) + require.NoError(t, err) + require.NotNil(t, peering) + + require.Equal(t, tc.input.RootPEMs, peering.PeerCAPems) + return nil } tcs := []testcase{ { @@ -1641,6 +1683,7 @@ func TestStore_PeeringTrustBundleWrite(t *testing.T) { input: &pbpeering.PeeringTrustBundle{ TrustDomain: "baz.com", PeerName: "baz", + RootPEMs: []string{"FAKE PEM HERE\n", "FAKE PEM HERE\n"}, Partition: structs.NodeEnterpriseMetaInDefaultPartition().PartitionOrEmpty(), }, }, @@ -1648,14 +1691,37 @@ func TestStore_PeeringTrustBundleWrite(t *testing.T) { name: "update foo", input: &pbpeering.PeeringTrustBundle{ TrustDomain: "foo-updated.com", + RootPEMs: []string{"FAKE PEM HERE\n"}, PeerName: "foo", Partition: structs.NodeEnterpriseMetaInDefaultPartition().PartitionOrEmpty(), }, }, + { + name: "create bar without existing peering", + input: &pbpeering.PeeringTrustBundle{ + TrustDomain: "bar.com", + PeerName: "bar", + Partition: structs.NodeEnterpriseMetaInDefaultPartition().PartitionOrEmpty(), + }, + expectErr: "cannot write peering trust bundle for unknown peering", + }, + { + name: "create without a peer name", + input: &pbpeering.PeeringTrustBundle{ + TrustDomain: "bar.com", + Partition: structs.NodeEnterpriseMetaInDefaultPartition().PartitionOrEmpty(), + }, + expectErr: "missing peer name", + }, } for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { - run(t, tc) + err := run(t, tc) + if err != nil && tc.expectErr != "" { + require.Contains(t, err.Error(), tc.expectErr) + return + } + require.NoError(t, err, "received unexpected test case error") }) } } @@ -1668,7 +1734,7 @@ func TestStore_PeeringTrustBundleDelete(t *testing.T) { require.NoError(t, s.PeeringTrustBundleDelete(10, q)) - _, ptb, err := s.PeeringRead(nil, q) + _, ptb, err := s.PeeringTrustBundleRead(nil, q) require.NoError(t, err) require.Nil(t, ptb) } @@ -1841,18 +1907,28 @@ func TestStateStore_ExportedServicesForPeer(t *testing.T) { }, }, { + // Should be exported as both a normal and disco chain (resolver). Name: "mysql", Consumers: []structs.ServiceConsumer{ {Peer: "my-peering"}, }, }, { + // Should be exported as both a normal and disco chain (connect-proxy). Name: "redis", Consumers: []structs.ServiceConsumer{ {Peer: "my-peering"}, }, }, { + // Should only be exported as a normal service. + Name: "prometheus", + Consumers: []structs.ServiceConsumer{ + {Peer: "my-peering"}, + }, + }, + { + // Should not be exported (different peer consumer) Name: "mongo", Consumers: []structs.ServiceConsumer{ {Peer: "my-other-peering"}, @@ -1865,12 +1941,37 @@ func TestStateStore_ExportedServicesForPeer(t *testing.T) { require.True(t, watchFired(ws)) ws = memdb.NewWatchSet() + // Register extra things so that disco chain entries appear. + lastIdx++ + require.NoError(t, s.EnsureNode(lastIdx, &structs.Node{ + Node: "node1", Address: "10.0.0.1", + })) + lastIdx++ + require.NoError(t, s.EnsureService(lastIdx, "node1", &structs.NodeService{ + Kind: structs.ServiceKindConnectProxy, + ID: "redis-sidecar-proxy", + Service: "redis-sidecar-proxy", + Port: 5005, + Proxy: structs.ConnectProxyConfig{ + DestinationServiceName: "redis", + }, + })) + ensureConfigEntry(t, &structs.ServiceResolverConfigEntry{ + Kind: structs.ServiceResolver, + Name: "mysql", + EnterpriseMeta: *defaultEntMeta, + }) + expect := &structs.ExportedServiceList{ Services: []structs.ServiceName{ { Name: "mysql", EnterpriseMeta: *defaultEntMeta, }, + { + Name: "prometheus", + EnterpriseMeta: *defaultEntMeta, + }, { Name: "redis", EnterpriseMeta: *defaultEntMeta, @@ -1931,17 +2032,21 @@ func TestStateStore_ExportedServicesForPeer(t *testing.T) { ws = memdb.NewWatchSet() expect := &structs.ExportedServiceList{ + // Only "billing" shows up, because there are no other service instances running, + // and "consul" is never exported. Services: []structs.ServiceName{ { Name: "billing", EnterpriseMeta: *defaultEntMeta, }, }, + // Only "mysql" appears because there it has a service resolver. + // "redis" does not appear, because it's a sidecar proxy without a corresponding service, so the wildcard doesn't find it. DiscoChains: map[structs.ServiceName]structs.ExportedDiscoveryChainInfo{ - newSN("billing"): { + newSN("mysql"): { Protocol: "tcp", TCPTargets: []*structs.DiscoveryTarget{ - newTarget("billing", "", "dc1"), + newTarget("mysql", "", "dc1"), }, }, }, @@ -1958,13 +2063,17 @@ func TestStateStore_ExportedServicesForPeer(t *testing.T) { ID: "payments", Service: "payments", Port: 5000, })) - // The proxy will be ignored. + // The proxy will cause "payments" to be output in the disco chains. It will NOT be output + // in the normal services list. lastIdx++ require.NoError(t, s.EnsureService(lastIdx, "foo", &structs.NodeService{ Kind: structs.ServiceKindConnectProxy, ID: "payments-proxy", Service: "payments-proxy", Port: 5000, + Proxy: structs.ConnectProxyConfig{ + DestinationServiceName: "payments", + }, })) lastIdx++ // The consul service should never be exported. @@ -2032,10 +2141,11 @@ func TestStateStore_ExportedServicesForPeer(t *testing.T) { }, DiscoChains: map[structs.ServiceName]structs.ExportedDiscoveryChainInfo{ // NOTE: no consul-redirect here - newSN("billing"): { + // NOTE: no billing here, because it does not have a proxy. + newSN("payments"): { Protocol: "http", }, - newSN("payments"): { + newSN("mysql"): { Protocol: "http", }, newSN("resolver"): { @@ -2062,6 +2172,9 @@ func TestStateStore_ExportedServicesForPeer(t *testing.T) { lastIdx++ require.NoError(t, s.DeleteConfigEntry(lastIdx, structs.ServiceSplitter, "splitter", nil)) + lastIdx++ + require.NoError(t, s.DeleteConfigEntry(lastIdx, structs.ServiceResolver, "mysql", nil)) + require.True(t, watchFired(ws)) ws = memdb.NewWatchSet() @@ -2093,6 +2206,51 @@ func TestStateStore_ExportedServicesForPeer(t *testing.T) { require.Equal(t, expect, got) }) + testutil.RunStep(t, "terminating gateway services are exported", func(t *testing.T) { + lastIdx++ + require.NoError(t, s.EnsureService(lastIdx, "foo", &structs.NodeService{ + ID: "term-svc", Service: "term-svc", Port: 6000, + })) + lastIdx++ + require.NoError(t, s.EnsureService(lastIdx, "foo", &structs.NodeService{ + Kind: structs.ServiceKindTerminatingGateway, + Service: "some-terminating-gateway", + ID: "some-terminating-gateway", + Port: 9000, + })) + lastIdx++ + require.NoError(t, s.EnsureConfigEntry(lastIdx, &structs.TerminatingGatewayConfigEntry{ + Kind: structs.TerminatingGateway, + Name: "some-terminating-gateway", + Services: []structs.LinkedService{{Name: "term-svc"}}, + })) + + expect := &structs.ExportedServiceList{ + Services: []structs.ServiceName{ + newSN("payments"), + newSN("term-svc"), + }, + DiscoChains: map[structs.ServiceName]structs.ExportedDiscoveryChainInfo{ + newSN("payments"): { + Protocol: "http", + }, + newSN("resolver"): { + Protocol: "http", + }, + newSN("router"): { + Protocol: "http", + }, + newSN("term-svc"): { + Protocol: "http", + }, + }, + } + idx, got, err := s.ExportedServicesForPeer(ws, id, "dc1") + require.NoError(t, err) + require.Equal(t, lastIdx, idx) + require.Equal(t, expect, got) + }) + testutil.RunStep(t, "deleting the config entry clears exported services", func(t *testing.T) { expect := &structs.ExportedServiceList{} @@ -2675,12 +2833,12 @@ func TestStateStore_Peering_Snapshot_Restore(t *testing.T) { expectedPeering := &pbpeering.Peering{ ID: "1fabcd52-1d46-49b0-b1d8-71559aee47f5", - Name: "baz", + Name: "example", } expectedTrustBundle := &pbpeering.PeeringTrustBundle{ TrustDomain: "example.com", PeerName: "example", - RootPEMs: []string{"example certificate bundle"}, + RootPEMs: []string{"example certificate bundle\n"}, } expectedSecret := &pbpeering.PeeringSecrets{ PeerID: expectedPeering.ID, @@ -2728,7 +2886,10 @@ func TestStateStore_Peering_Snapshot_Restore(t *testing.T) { for entry := iter.Next(); entry != nil; entry = iter.Next() { peeringDump = append(peeringDump, entry.(*pbpeering.Peering)) } - require.Equal(t, []*pbpeering.Peering{expectedPeering}, peeringDump) + expectedPeering.ModifyIndex = expectedTrustBundle.ModifyIndex + expectedPeering.PeerCAPems = expectedTrustBundle.RootPEMs + require.Len(t, peeringDump, 1) + prototest.AssertDeepEqual(t, expectedPeering, peeringDump[0]) } // Verify trust bundles { @@ -2771,7 +2932,8 @@ func TestStateStore_Peering_Snapshot_Restore(t *testing.T) { { idx, foundPeerings, err := s.PeeringList(nil, *acl.DefaultEnterpriseMeta()) require.NoError(t, err) - require.Equal(t, uint64(1001), idx) + // This is 1002 because the trust bundle write updates the underlying peering + require.Equal(t, uint64(1002), idx) require.Equal(t, []*pbpeering.Peering{expectedPeering}, foundPeerings) } // Verify trust Bundles diff --git a/agent/consul/state/query_oss.go b/agent/consul/state/query_ce.go similarity index 100% rename from agent/consul/state/query_oss.go rename to agent/consul/state/query_ce.go diff --git a/agent/consul/state/schema_oss.go b/agent/consul/state/schema_ce.go similarity index 100% rename from agent/consul/state/schema_oss.go rename to agent/consul/state/schema_ce.go diff --git a/agent/consul/state/schema_oss_test.go b/agent/consul/state/schema_ce_test.go similarity index 100% rename from agent/consul/state/schema_oss_test.go rename to agent/consul/state/schema_ce_test.go diff --git a/agent/consul/state/session_oss.go b/agent/consul/state/session_ce.go similarity index 100% rename from agent/consul/state/session_oss.go rename to agent/consul/state/session_ce.go diff --git a/agent/consul/state/state_store_oss_test.go b/agent/consul/state/state_store_ce_test.go similarity index 100% rename from agent/consul/state/state_store_oss_test.go rename to agent/consul/state/state_store_ce_test.go diff --git a/agent/consul/state/tombstone_gc.go b/agent/consul/state/tombstone_gc.go index 3b141c2bdfc1..c20fd34004d2 100644 --- a/agent/consul/state/tombstone_gc.go +++ b/agent/consul/state/tombstone_gc.go @@ -16,7 +16,6 @@ import ( // data is deleted from the KV store, the "latest" row can go backwards if the // newest row is removed. The tombstones provide a way to ensure time doesn't // move backwards within some interval. -// type TombstoneGC struct { // ttl sets the TTL for tombstones. ttl time.Duration diff --git a/agent/consul/state/usage.go b/agent/consul/state/usage.go index cfb38232a951..9db30e5b2d16 100644 --- a/agent/consul/state/usage.go +++ b/agent/consul/state/usage.go @@ -52,14 +52,6 @@ type UsageEntry struct { Count int } -// ServiceUsage contains all of the usage data related to services -type ServiceUsage struct { - Services int - ServiceInstances int - ConnectServiceInstances map[string]int - EnterpriseServiceUsage -} - // NodeUsage contains all of the usage data related to nodes type NodeUsage struct { Nodes int @@ -128,15 +120,17 @@ func updateUsage(tx WriteTxn, changes Changes) error { addEnterpriseServiceInstanceUsage(usageDeltas, change) connectDeltas(change, usageDeltas, delta) + billableServiceInstancesDeltas(change, usageDeltas, delta) + // Construct a mapping of all of the various service names that were // changed, in order to compare it with the finished memdb state. // Make sure to account for the fact that services can change their names. if serviceNameChanged(change) { - serviceNameChanges[svc.CompoundServiceName()] += 1 + serviceNameChanges[svc.CompoundServiceName().ServiceName] += 1 before := change.Before.(*structs.ServiceNode) - serviceNameChanges[before.CompoundServiceName()] -= 1 + serviceNameChanges[before.CompoundServiceName().ServiceName] -= 1 } else { - serviceNameChanges[svc.CompoundServiceName()] += delta + serviceNameChanges[svc.CompoundServiceName().ServiceName] += delta } case "kvs": @@ -271,6 +265,53 @@ func connectDeltas(change memdb.Change, usageDeltas map[string]int, delta int) { } } +// billableServiceInstancesDeltas calculates deltas for the billable services. Billable services +// are of "typical" service kind (i.e. non-connect or connect-native), excluding the "consul" service. +func billableServiceInstancesDeltas(change memdb.Change, usageDeltas map[string]int, delta int) { + // Billable service instances = # of typical service instances (i.e. non-connect) + connect-native service instances. + // Specifically, it should exclude "consul" service instances from the count. + // + // If the service has been updated, then we check + // 1. If the service name changed to or from "consul" and update deltas such that we exclude consul server service instances. + // This case is a bit contrived because we don't expect consul service to change once it's registered (beyond changing its instance count). + // a) If changed to "consul" -> decrement deltas by one + // b) If changed from "consul" and it's not a "connect" service -> increase deltas by one + // 2. If the service kind changed to or from "typical", we need to we need to update deltas so that we only account + // for non-connect or connect-native instances. + if change.Updated() { + // When there's an update, the delta arg passed to this function is 0, and so we need to explicitly increment + // or decrement by 1 depending on the situation. + before := change.Before.(*structs.ServiceNode) + after := change.After.(*structs.ServiceNode) + // Service name changed away from "consul" means we now need to account for this service instances unless it's a "connect" service. + if before.ServiceName == structs.ConsulServiceName && after.ServiceName != structs.ConsulServiceName { + if after.ServiceKind == structs.ServiceKindTypical { + usageDeltas[billableServiceInstancesTableName()] += 1 + addEnterpriseBillableServiceInstanceUsage(usageDeltas, after, 1) + } + } + if before.ServiceName != structs.ConsulServiceName && after.ServiceName == structs.ConsulServiceName { + usageDeltas[billableServiceInstancesTableName()] -= 1 + addEnterpriseBillableServiceInstanceUsage(usageDeltas, before, -1) + } + + if before.ServiceKind != structs.ServiceKindTypical && after.ServiceKind == structs.ServiceKindTypical { + usageDeltas[billableServiceInstancesTableName()] += 1 + addEnterpriseBillableServiceInstanceUsage(usageDeltas, after, 1) + } else if before.ServiceKind == structs.ServiceKindTypical && after.ServiceKind != structs.ServiceKindTypical { + usageDeltas[billableServiceInstancesTableName()] -= 1 + addEnterpriseBillableServiceInstanceUsage(usageDeltas, before, -1) + } + } else { + svc := changeObject(change).(*structs.ServiceNode) + // If it's not an update, only update delta if it's a typical service and not the "consul" service. + if svc.ServiceKind == structs.ServiceKindTypical && svc.ServiceName != structs.ConsulServiceName { + usageDeltas[billableServiceInstancesTableName()] += delta + addEnterpriseBillableServiceInstanceUsage(usageDeltas, svc, delta) + } + } +} + // writeUsageDeltas will take in a map of IDs to deltas and update each // entry accordingly, checking for integer underflow. The index that is // passed in will be recorded on the entry as well. @@ -289,7 +330,7 @@ func writeUsageDeltas(tx WriteTxn, idx uint64, usageDeltas map[string]int) error // large numbers. delta = 0 } - err := tx.Insert(tableUsage, &UsageEntry{ + err = tx.Insert(tableUsage, &UsageEntry{ ID: id, Count: delta, Index: idx, @@ -365,37 +406,43 @@ func (s *Store) PeeringUsage() (uint64, PeeringUsage, error) { // ServiceUsage returns the latest seen Raft index, a compiled set of service // usage data, and any errors. -func (s *Store) ServiceUsage(ws memdb.WatchSet) (uint64, ServiceUsage, error) { +func (s *Store) ServiceUsage(ws memdb.WatchSet) (uint64, structs.ServiceUsage, error) { tx := s.db.ReadTxn() defer tx.Abort() serviceInstances, err := firstUsageEntry(ws, tx, tableServices) if err != nil { - return 0, ServiceUsage{}, fmt.Errorf("failed services lookup: %s", err) + return 0, structs.ServiceUsage{}, fmt.Errorf("failed services lookup: %s", err) } services, err := firstUsageEntry(ws, tx, serviceNamesUsageTable) if err != nil { - return 0, ServiceUsage{}, fmt.Errorf("failed services lookup: %s", err) + return 0, structs.ServiceUsage{}, fmt.Errorf("failed services lookup: %s", err) } serviceKindInstances := make(map[string]int) for _, kind := range allConnectKind { usage, err := firstUsageEntry(ws, tx, connectUsageTableName(kind)) if err != nil { - return 0, ServiceUsage{}, fmt.Errorf("failed services lookup: %s", err) + return 0, structs.ServiceUsage{}, fmt.Errorf("failed services lookup: %s", err) } serviceKindInstances[kind] = usage.Count } - usage := ServiceUsage{ - ServiceInstances: serviceInstances.Count, - Services: services.Count, - ConnectServiceInstances: serviceKindInstances, + billableServiceInstances, err := firstUsageEntry(ws, tx, billableServiceInstancesTableName()) + if err != nil { + return 0, structs.ServiceUsage{}, fmt.Errorf("failed billable services lookup: %s", err) + } + + usage := structs.ServiceUsage{ + ServiceInstances: serviceInstances.Count, + Services: services.Count, + ConnectServiceInstances: serviceKindInstances, + BillableServiceInstances: billableServiceInstances.Count, } results, err := compileEnterpriseServiceUsage(ws, tx, usage) if err != nil { - return 0, ServiceUsage{}, fmt.Errorf("failed services lookup: %s", err) + return 0, structs.ServiceUsage{}, fmt.Errorf("failed services lookup: %s", err) } return serviceInstances.Index, results, nil @@ -469,3 +516,7 @@ func firstUsageEntry(ws memdb.WatchSet, tx ReadTxn, id string) (*UsageEntry, err return realUsage, nil } + +func billableServiceInstancesTableName() string { + return fmt.Sprintf("billable-%s", tableServices) +} diff --git a/agent/consul/state/usage_oss.go b/agent/consul/state/usage_ce.go similarity index 89% rename from agent/consul/state/usage_oss.go rename to agent/consul/state/usage_ce.go index a9b4d1c2fe3a..6279c10970d4 100644 --- a/agent/consul/state/usage_oss.go +++ b/agent/consul/state/usage_ce.go @@ -25,11 +25,13 @@ func addEnterpriseServiceUsage(map[string]int, map[structs.ServiceName]uniqueSer func addEnterpriseConnectServiceInstanceUsage(map[string]int, *structs.ServiceNode, int) {} +func addEnterpriseBillableServiceInstanceUsage(map[string]int, *structs.ServiceNode, int) {} + func addEnterpriseKVUsage(map[string]int, memdb.Change) {} func addEnterpriseConfigEntryUsage(map[string]int, memdb.Change) {} -func compileEnterpriseServiceUsage(ws memdb.WatchSet, tx ReadTxn, usage ServiceUsage) (ServiceUsage, error) { +func compileEnterpriseServiceUsage(ws memdb.WatchSet, tx ReadTxn, usage structs.ServiceUsage) (structs.ServiceUsage, error) { return usage, nil } diff --git a/agent/consul/state/usage_test.go b/agent/consul/state/usage_test.go index 5c69cc2d5592..b54e3dcfa0a1 100644 --- a/agent/consul/state/usage_test.go +++ b/agent/consul/state/usage_test.go @@ -160,6 +160,7 @@ func TestStateStore_Usage_ServiceUsageEmpty(t *testing.T) { for k := range usage.ConnectServiceInstances { require.Equal(t, 0, usage.ConnectServiceInstances[k]) } + require.Equal(t, 0, usage.BillableServiceInstances) } func TestStateStore_Usage_ServiceUsage(t *testing.T) { @@ -184,6 +185,7 @@ func TestStateStore_Usage_ServiceUsage(t *testing.T) { require.Equal(t, 8, usage.ServiceInstances) require.Equal(t, 2, usage.ConnectServiceInstances[string(structs.ServiceKindConnectProxy)]) require.Equal(t, 3, usage.ConnectServiceInstances[connectNativeInstancesTable]) + require.Equal(t, 6, usage.BillableServiceInstances) testRegisterSidecarProxy(t, s, 16, "node2", "service2") @@ -225,6 +227,7 @@ func TestStateStore_Usage_ServiceUsage_DeleteNode(t *testing.T) { require.Equal(t, 4, usage.ServiceInstances) require.Equal(t, 1, usage.ConnectServiceInstances[string(structs.ServiceKindConnectProxy)]) require.Equal(t, 1, usage.ConnectServiceInstances[connectNativeInstancesTable]) + require.Equal(t, 3, usage.BillableServiceInstances) require.NoError(t, s.DeleteNode(4, "node1", nil, "")) @@ -236,6 +239,7 @@ func TestStateStore_Usage_ServiceUsage_DeleteNode(t *testing.T) { for k := range usage.ConnectServiceInstances { require.Equal(t, 0, usage.ConnectServiceInstances[k]) } + require.Equal(t, 0, usage.BillableServiceInstances) } // Test that services from remote peers aren't counted in writes or deletes. @@ -263,6 +267,7 @@ func TestStateStore_Usage_ServiceUsagePeering(t *testing.T) { require.Equal(t, 3, usage.ServiceInstances) require.Equal(t, 1, usage.ConnectServiceInstances[string(structs.ServiceKindConnectProxy)]) require.Equal(t, 1, usage.ConnectServiceInstances[connectNativeInstancesTable]) + require.Equal(t, 2, usage.BillableServiceInstances) }) testutil.RunStep(t, "deletes", func(t *testing.T) { @@ -275,6 +280,7 @@ func TestStateStore_Usage_ServiceUsagePeering(t *testing.T) { require.Equal(t, 0, usage.ServiceInstances) require.Equal(t, 0, usage.ConnectServiceInstances[string(structs.ServiceKindConnectProxy)]) require.Equal(t, 0, usage.ConnectServiceInstances[connectNativeInstancesTable]) + require.Equal(t, 0, usage.BillableServiceInstances) }) } @@ -311,6 +317,7 @@ func TestStateStore_Usage_Restore(t *testing.T) { require.Equal(t, idx, uint64(9)) require.Equal(t, usage.Services, 1) require.Equal(t, usage.ServiceInstances, 2) + require.Equal(t, usage.BillableServiceInstances, 2) } func TestStateStore_Usage_updateUsage_Underflow(t *testing.T) { @@ -411,6 +418,7 @@ func TestStateStore_Usage_ServiceUsage_updatingService(t *testing.T) { require.Equal(t, idx, uint64(2)) require.Equal(t, usage.Services, 1) require.Equal(t, usage.ServiceInstances, 1) + require.Equal(t, usage.BillableServiceInstances, 1) }) t.Run("update service to be connect native", func(t *testing.T) { @@ -432,6 +440,7 @@ func TestStateStore_Usage_ServiceUsage_updatingService(t *testing.T) { require.Equal(t, usage.Services, 1) require.Equal(t, usage.ServiceInstances, 1) require.Equal(t, 1, usage.ConnectServiceInstances[connectNativeInstancesTable]) + require.Equal(t, 1, usage.BillableServiceInstances) }) t.Run("update service to not be connect native", func(t *testing.T) { @@ -453,6 +462,7 @@ func TestStateStore_Usage_ServiceUsage_updatingService(t *testing.T) { require.Equal(t, usage.Services, 1) require.Equal(t, usage.ServiceInstances, 1) require.Equal(t, 0, usage.ConnectServiceInstances[connectNativeInstancesTable]) + require.Equal(t, 1, usage.BillableServiceInstances) }) t.Run("rename service with a multiple instances", func(t *testing.T) { @@ -484,6 +494,7 @@ func TestStateStore_Usage_ServiceUsage_updatingService(t *testing.T) { require.Equal(t, usage.Services, 2) require.Equal(t, usage.ServiceInstances, 3) require.Equal(t, 2, usage.ConnectServiceInstances[connectNativeInstancesTable]) + require.Equal(t, 3, usage.BillableServiceInstances) update := &structs.NodeService{ ID: "service2", @@ -502,6 +513,7 @@ func TestStateStore_Usage_ServiceUsage_updatingService(t *testing.T) { require.Equal(t, usage.Services, 3) require.Equal(t, usage.ServiceInstances, 3) require.Equal(t, 2, usage.ConnectServiceInstances[connectNativeInstancesTable]) + require.Equal(t, 3, usage.BillableServiceInstances) }) } @@ -528,6 +540,7 @@ func TestStateStore_Usage_ServiceUsage_updatingConnectProxy(t *testing.T) { require.Equal(t, usage.Services, 1) require.Equal(t, usage.ServiceInstances, 1) require.Equal(t, 1, usage.ConnectServiceInstances[string(structs.ServiceKindConnectProxy)]) + require.Equal(t, 0, usage.BillableServiceInstances) }) t.Run("rename service with a multiple instances", func(t *testing.T) { @@ -554,6 +567,7 @@ func TestStateStore_Usage_ServiceUsage_updatingConnectProxy(t *testing.T) { require.Equal(t, usage.Services, 2) require.Equal(t, usage.ServiceInstances, 3) require.Equal(t, 2, usage.ConnectServiceInstances[string(structs.ServiceKindConnectProxy)]) + require.Equal(t, 1, usage.BillableServiceInstances) update := &structs.NodeService{ ID: "service3", @@ -569,6 +583,7 @@ func TestStateStore_Usage_ServiceUsage_updatingConnectProxy(t *testing.T) { require.Equal(t, usage.Services, 3) require.Equal(t, usage.ServiceInstances, 3) require.Equal(t, 1, usage.ConnectServiceInstances[string(structs.ServiceKindConnectProxy)]) + require.Equal(t, 2, usage.BillableServiceInstances) }) } diff --git a/agent/consul/subscribe_backend_test.go b/agent/consul/subscribe_backend_test.go index b7ea7e2d3b42..72e054d3960b 100644 --- a/agent/consul/subscribe_backend_test.go +++ b/agent/consul/subscribe_backend_test.go @@ -377,7 +377,10 @@ func newClientWithGRPCResolver(t *testing.T, ops ...func(*Config)) (*Client, *re } builder := resolver.NewServerResolverBuilder(newTestResolverConfig(t, - "client."+config.Datacenter+"."+string(config.NodeID))) + "client."+config.Datacenter+"."+string(config.NodeID), + config.Datacenter, + "client", + )) resolver.Register(builder) t.Cleanup(func() { @@ -444,13 +447,17 @@ func verifyMonotonicStreamUpdates(ctx context.Context, logger testLogger, client if err != nil { return err } - if expectPort != svc.Port { + switch svc.Port { + case expectPort: + atomic.AddUint64(updateCount, 1) + logger.Logf("subscriber %05d: got event with correct port=%d at index %d", i, expectPort, event.Index) + expectPort++ + case expectPort - 1: + logger.Logf("subscriber %05d: got event with repeated prior port=%d at index %d", i, expectPort-1, event.Index) + default: return fmt.Errorf("subscriber %05d: at index %d: expected port %d, got %d", i, event.Index, expectPort, svc.Port) } - atomic.AddUint64(updateCount, 1) - logger.Logf("subscriber %05d: got event with correct port=%d at index %d", i, expectPort, event.Index) - expectPort++ default: // snapshot events svc, err := svcOrErr(event) diff --git a/agent/consul/system_metadata.go b/agent/consul/system_metadata.go index f1603225738f..5ceb5fc5e717 100644 --- a/agent/consul/system_metadata.go +++ b/agent/consul/system_metadata.go @@ -4,7 +4,7 @@ import ( "github.com/hashicorp/consul/agent/structs" ) -func (s *Server) getSystemMetadata(key string) (string, error) { +func (s *Server) GetSystemMetadata(key string) (string, error) { _, entry, err := s.fsm.State().SystemMetadataGet(nil, key) if err != nil { return "", err @@ -16,7 +16,7 @@ func (s *Server) getSystemMetadata(key string) (string, error) { return entry.Value, nil } -func (s *Server) setSystemMetadataKey(key, val string) error { +func (s *Server) SetSystemMetadataKey(key, val string) error { args := &structs.SystemMetadataRequest{ Op: structs.SystemMetadataUpsert, Entry: &structs.SystemMetadataEntry{Key: key, Value: val}, diff --git a/agent/consul/system_metadata_test.go b/agent/consul/system_metadata_test.go index 633aa6bc4078..b17790d22469 100644 --- a/agent/consul/system_metadata_test.go +++ b/agent/consul/system_metadata_test.go @@ -39,9 +39,9 @@ func TestLeader_SystemMetadata_CRUD(t *testing.T) { require.Len(t, entries, 0) // Create 3 - require.NoError(t, srv.setSystemMetadataKey("key1", "val1")) - require.NoError(t, srv.setSystemMetadataKey("key2", "val2")) - require.NoError(t, srv.setSystemMetadataKey("key3", "")) + require.NoError(t, srv.SetSystemMetadataKey("key1", "val1")) + require.NoError(t, srv.SetSystemMetadataKey("key2", "val2")) + require.NoError(t, srv.SetSystemMetadataKey("key3", "")) mapify := func(entries []*structs.SystemMetadataEntry) map[string]string { m := make(map[string]string) @@ -62,7 +62,7 @@ func TestLeader_SystemMetadata_CRUD(t *testing.T) { }, mapify(entries)) // Update one and delete one. - require.NoError(t, srv.setSystemMetadataKey("key3", "val3")) + require.NoError(t, srv.SetSystemMetadataKey("key3", "val3")) require.NoError(t, srv.deleteSystemMetadataKey("key1")) _, entries, err = state.SystemMetadataList(nil) diff --git a/agent/consul/txn_endpoint.go b/agent/consul/txn_endpoint.go index a1977b91966b..e528ea725335 100644 --- a/agent/consul/txn_endpoint.go +++ b/agent/consul/txn_endpoint.go @@ -185,7 +185,7 @@ func (t *Txn) Read(args *structs.TxnReadRequest, reply *structs.TxnReadResponse) // We have to do this ourselves since we are not doing a blocking RPC. if args.RequireConsistent { - if err := t.srv.consistentRead(); err != nil { + if err := t.srv.ConsistentRead(); err != nil { return err } } @@ -217,7 +217,7 @@ func (t *Txn) Read(args *structs.TxnReadRequest, reply *structs.TxnReadResponse) reply.QueryMeta.ResultsFilteredByACLs = total != len(reply.Results) // We have to do this ourselves since we are not doing a blocking RPC. - t.srv.setQueryMeta(&reply.QueryMeta, args.Token) + t.srv.SetQueryMeta(&reply.QueryMeta, args.Token) return nil } diff --git a/agent/consul/usagemetrics/usagemetrics.go b/agent/consul/usagemetrics/usagemetrics.go index de15f497b38b..e968b9918dfe 100644 --- a/agent/consul/usagemetrics/usagemetrics.go +++ b/agent/consul/usagemetrics/usagemetrics.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/consul/agent/consul/state" "github.com/hashicorp/consul/logging" + "github.com/hashicorp/consul/version" ) var Gauges = []prometheus.GaugeDefinition{ @@ -88,6 +89,14 @@ var Gauges = []prometheus.GaugeDefinition{ Name: []string{"state", "config_entries"}, Help: "Measures the current number of unique configuration entries registered with Consul, labeled by Kind. It is only emitted by Consul servers. Added in v1.10.4.", }, + { + Name: []string{"state", "billable_service_instances"}, + Help: "Total number of billable service instances in the local datacenter.", + }, + { + Name: []string{"version"}, + Help: "Represents the Consul version.", + }, } type getMembersFunc func() []serf.Member @@ -237,6 +246,7 @@ func (u *UsageMetricsReporter) runOnce() { } u.emitConfigEntryUsage(configUsage) + u.emitVersion() } func (u *UsageMetricsReporter) memberUsage() []serf.Member { @@ -259,3 +269,26 @@ func (u *UsageMetricsReporter) memberUsage() []serf.Member { return out } + +func (u *UsageMetricsReporter) emitVersion() { + // consul version metric with labels + metrics.SetGaugeWithLabels( + []string{"version"}, + 1, + []metrics.Label{ + {Name: "version", Value: versionWithMetadata()}, + {Name: "pre_release", Value: version.VersionPrerelease}, + }, + ) +} + +func versionWithMetadata() string { + vsn := version.Version + metadata := version.VersionMetadata + + if metadata != "" { + vsn += "+" + metadata + } + + return vsn +} diff --git a/agent/consul/usagemetrics/usagemetrics_oss.go b/agent/consul/usagemetrics/usagemetrics_ce.go similarity index 91% rename from agent/consul/usagemetrics/usagemetrics_oss.go rename to agent/consul/usagemetrics/usagemetrics_ce.go index 6330707c12d0..884363b2aa46 100644 --- a/agent/consul/usagemetrics/usagemetrics_oss.go +++ b/agent/consul/usagemetrics/usagemetrics_ce.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/serf/serf" "github.com/hashicorp/consul/agent/consul/state" + "github.com/hashicorp/consul/agent/structs" ) func (u *UsageMetricsReporter) emitNodeUsage(nodeUsage state.NodeUsage) { @@ -74,7 +75,7 @@ func (u *UsageMetricsReporter) emitMemberUsage(members []serf.Member) { ) } -func (u *UsageMetricsReporter) emitServiceUsage(serviceUsage state.ServiceUsage) { +func (u *UsageMetricsReporter) emitServiceUsage(serviceUsage structs.ServiceUsage) { metrics.SetGaugeWithLabels( []string{"consul", "state", "services"}, float32(serviceUsage.Services), @@ -96,6 +97,11 @@ func (u *UsageMetricsReporter) emitServiceUsage(serviceUsage state.ServiceUsage) float32(serviceUsage.ServiceInstances), u.metricLabels, ) + metrics.SetGaugeWithLabels( + []string{"state", "billable_service_instances"}, + float32(serviceUsage.BillableServiceInstances), + u.metricLabels, + ) for k, i := range serviceUsage.ConnectServiceInstances { metrics.SetGaugeWithLabels( diff --git a/agent/consul/usagemetrics/usagemetrics_oss_test.go b/agent/consul/usagemetrics/usagemetrics_ce_test.go similarity index 96% rename from agent/consul/usagemetrics/usagemetrics_oss_test.go rename to agent/consul/usagemetrics/usagemetrics_ce_test.go index add26bca692f..50e53ba7a22f 100644 --- a/agent/consul/usagemetrics/usagemetrics_oss_test.go +++ b/agent/consul/usagemetrics/usagemetrics_ce_test.go @@ -4,6 +4,7 @@ package usagemetrics import ( + "fmt" "testing" "time" @@ -18,6 +19,7 @@ import ( "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/proto/pbpeering" "github.com/hashicorp/consul/sdk/testutil" + "github.com/hashicorp/consul/version" ) func newStateStore() (*state.Store, error) { @@ -178,6 +180,13 @@ var baseCases = map[string]testCase{ {Name: "kind", Value: "connect-native"}, }, }, + "consul.usage.test.state.billable_service_instances;datacenter=dc1": { + Name: "consul.usage.test.state.billable_service_instances", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + }, + }, // --- kv --- "consul.usage.test.consul.state.kv_entries;datacenter=dc1": { // Legacy Name: "consul.usage.test.consul.state.kv_entries", @@ -350,6 +359,15 @@ var baseCases = map[string]testCase{ {Name: "kind", Value: "exported-services"}, }, }, + // --- version --- + fmt.Sprintf("consul.usage.test.version;version=%s;pre_release=%s", versionWithMetadata(), version.VersionPrerelease): { + Name: "consul.usage.test.version", + Value: 1, + Labels: []metrics.Label{ + {Name: "version", Value: versionWithMetadata()}, + {Name: "pre_release", Value: version.VersionPrerelease}, + }, + }, }, getMembersFunc: func() []serf.Member { return []serf.Member{} }, }, @@ -518,6 +536,13 @@ var baseCases = map[string]testCase{ {Name: "kind", Value: "connect-native"}, }, }, + "consul.usage.test.state.billable_service_instances;datacenter=dc1": { + Name: "consul.usage.test.state.billable_service_instances", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + }, + }, // --- kv --- "consul.usage.test.consul.state.kv_entries;datacenter=dc1": { // Legacy Name: "consul.usage.test.consul.state.kv_entries", @@ -690,11 +715,20 @@ var baseCases = map[string]testCase{ {Name: "kind", Value: "exported-services"}, }, }, + // --- version --- + fmt.Sprintf("consul.usage.test.version;version=%s;pre_release=%s", versionWithMetadata(), version.VersionPrerelease): { + Name: "consul.usage.test.version", + Value: 1, + Labels: []metrics.Label{ + {Name: "version", Value: versionWithMetadata()}, + {Name: "pre_release", Value: version.VersionPrerelease}, + }, + }, }, }, } -func TestUsageReporter_emitNodeUsage_OSS(t *testing.T) { +func TestUsageReporter_emitNodeUsage_CE(t *testing.T) { cases := baseCases for name, tcase := range cases { @@ -733,7 +767,7 @@ func TestUsageReporter_emitNodeUsage_OSS(t *testing.T) { } } -func TestUsageReporter_emitPeeringUsage_OSS(t *testing.T) { +func TestUsageReporter_emitPeeringUsage_CE(t *testing.T) { cases := make(map[string]testCase) for k, v := range baseCases { eg := make(map[string]metrics.GaugeValue) @@ -837,7 +871,7 @@ func TestUsageReporter_emitPeeringUsage_OSS(t *testing.T) { } } -func TestUsageReporter_emitServiceUsage_OSS(t *testing.T) { +func TestUsageReporter_emitServiceUsage_CE(t *testing.T) { cases := make(map[string]testCase) for k, v := range baseCases { eg := make(map[string]metrics.GaugeValue) @@ -1016,6 +1050,13 @@ func TestUsageReporter_emitServiceUsage_OSS(t *testing.T) { {Name: "kind", Value: "connect-native"}, }, } + nodesAndSvcsCase.expectedGauges["consul.usage.test.state.billable_service_instances;datacenter=dc1"] = metrics.GaugeValue{ + Name: "consul.usage.test.state.billable_service_instances", + Value: 3, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + }, + } nodesAndSvcsCase.expectedGauges["consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=ingress-gateway"] = metrics.GaugeValue{ // Legacy Name: "consul.usage.test.consul.state.config_entries", Value: 3, @@ -1070,7 +1111,7 @@ func TestUsageReporter_emitServiceUsage_OSS(t *testing.T) { } } -func TestUsageReporter_emitKVUsage_OSS(t *testing.T) { +func TestUsageReporter_emitKVUsage_CE(t *testing.T) { cases := make(map[string]testCase) for k, v := range baseCases { eg := make(map[string]metrics.GaugeValue) diff --git a/agent/consul/usagemetrics/usagemetrics_test.go b/agent/consul/usagemetrics/usagemetrics_test.go index cf0cd01e01af..04aea1205115 100644 --- a/agent/consul/usagemetrics/usagemetrics_test.go +++ b/agent/consul/usagemetrics/usagemetrics_test.go @@ -24,7 +24,7 @@ func assertEqualGaugeMaps(t *testing.T, expectedMap, foundMap map[string]metrics for key := range foundMap { if _, ok := expectedMap[key]; !ok { - t.Errorf("found unexpected gauge key: %s", key) + t.Errorf("found unexpected gauge key: %s with value: %v", key, foundMap[key]) } } diff --git a/agent/consul/watch/mock_StateStore_test.go b/agent/consul/watch/mock_StateStore_test.go index 08d58e2f04c1..37cc383669cb 100644 --- a/agent/consul/watch/mock_StateStore_test.go +++ b/agent/consul/watch/mock_StateStore_test.go @@ -1,12 +1,8 @@ -// Code generated by mockery v2.12.2. DO NOT EDIT. +// Code generated by mockery v2.15.0. DO NOT EDIT. package watch -import ( - testing "testing" - - mock "github.com/stretchr/testify/mock" -) +import mock "github.com/stretchr/testify/mock" // MockStateStore is an autogenerated mock type for the StateStore type type MockStateStore struct { @@ -29,8 +25,13 @@ func (_m *MockStateStore) AbandonCh() <-chan struct{} { return r0 } -// NewMockStateStore creates a new instance of MockStateStore. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockStateStore(t testing.TB) *MockStateStore { +type mockConstructorTestingTNewMockStateStore interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockStateStore creates a new instance of MockStateStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockStateStore(t mockConstructorTestingTNewMockStateStore) *MockStateStore { mock := &MockStateStore{} mock.Mock.Test(t) diff --git a/agent/consul/watch/server_local.go b/agent/consul/watch/server_local.go index 4ad23ee38640..e9a45c82ce32 100644 --- a/agent/consul/watch/server_local.go +++ b/agent/consul/watch/server_local.go @@ -54,33 +54,33 @@ func noopDone() {} // ServerLocalBlockingQuery performs a blocking query similar to the pre-existing blockingQuery // method on the agent/consul.Server type. There are a few key differences. // -// 1. This function makes use of Go 1.18 generics. The function is parameterized with two -// types. The first is the ResultType which can be anything. Having this be parameterized -// instead of using interface{} allows us to simplify the call sites so that no type -// coercion from interface{} to the real type is necessary. The second parameterized type -// is something that VERY loosely resembles a agent/consul/state.Store type. The StateStore -// interface in this package has a single method to get the stores abandon channel so we -// know when a snapshot restore is occurring and can act accordingly. We could have not -// parameterized this type and used a real *state.Store instead but then we would have -// concrete dependencies on the state package and it would make it a little harder to -// test this function. +// 1. This function makes use of Go 1.18 generics. The function is parameterized with two +// types. The first is the ResultType which can be anything. Having this be parameterized +// instead of using interface{} allows us to simplify the call sites so that no type +// coercion from interface{} to the real type is necessary. The second parameterized type +// is something that VERY loosely resembles a agent/consul/state.Store type. The StateStore +// interface in this package has a single method to get the stores abandon channel so we +// know when a snapshot restore is occurring and can act accordingly. We could have not +// parameterized this type and used a real *state.Store instead but then we would have +// concrete dependencies on the state package and it would make it a little harder to +// test this function. // -// We could have also avoided the need to use a ResultType parameter by taking the route -// the original blockingQuery method did and to just assume all callers close around -// a pointer to their results and can modify it as necessary. That way of doing things -// feels a little gross so I have taken this one a different direction. The old way -// also gets especially gross with how we have to push concerns of spurious wakeup -// suppression down into every call site. +// We could have also avoided the need to use a ResultType parameter by taking the route +// the original blockingQuery method did and to just assume all callers close around +// a pointer to their results and can modify it as necessary. That way of doing things +// feels a little gross so I have taken this one a different direction. The old way +// also gets especially gross with how we have to push concerns of spurious wakeup +// suppression down into every call site. // -// 2. This method has no internal timeout and can potentially run forever until a state -// change is observed. If there is a desire to have a timeout, that should be built into -// the context.Context passed as the first argument. +// 2. This method has no internal timeout and can potentially run forever until a state +// change is observed. If there is a desire to have a timeout, that should be built into +// the context.Context passed as the first argument. // -// 3. This method bakes in some newer functionality around hashing of results to prevent sending -// back data when nothing has actually changed. With the old blockingQuery method this has to -// be done within the closure passed to the method which means the same bit of code is duplicated -// in many places. As this functionality isn't necessary in many scenarios whether to opt-in to -// that behavior is a argument to this function. +// 3. This method bakes in some newer functionality around hashing of results to prevent sending +// back data when nothing has actually changed. With the old blockingQuery method this has to +// be done within the closure passed to the method which means the same bit of code is duplicated +// in many places. As this functionality isn't necessary in many scenarios whether to opt-in to +// that behavior is a argument to this function. // // Similar to the older method: // @@ -88,21 +88,20 @@ func noopDone() {} // // The query function must follow these rules: // -// 1. To access data it must use the passed in StoreType (which will be a state.Store when -// everything gets stiched together outside of unit tests). -// 2. It must return an index greater than the minIndex if the results returned by the query -// have changed. -// 3. Any channels added to the memdb.WatchSet must unblock when the results -// returned by the query have changed. +// 1. To access data it must use the passed in StoreType (which will be a state.Store when +// everything gets stiched together outside of unit tests). +// 2. It must return an index greater than the minIndex if the results returned by the query +// have changed. +// 3. Any channels added to the memdb.WatchSet must unblock when the results +// returned by the query have changed. // // To ensure optimal performance of the query, the query function should make a // best-effort attempt to follow these guidelines: // -// 1. Only return an index greater than the minIndex. -// 2. Any channels added to the memdb.WatchSet should only unblock when the -// results returned by the query have changed. This might be difficult -// to do when blocking on non-existent data. -// +// 1. Only return an index greater than the minIndex. +// 2. Any channels added to the memdb.WatchSet should only unblock when the +// results returned by the query have changed. This might be difficult +// to do when blocking on non-existent data. func ServerLocalBlockingQuery[ResultType any, StoreType StateStore]( ctx context.Context, getStore func() StoreType, diff --git a/agent/consul/xdscapacity/capacity.go b/agent/consul/xdscapacity/capacity.go index f1974b96418e..31fb53ea92b9 100644 --- a/agent/consul/xdscapacity/capacity.go +++ b/agent/consul/xdscapacity/capacity.go @@ -7,12 +7,12 @@ import ( "github.com/armon/go-metrics" "github.com/armon/go-metrics/prometheus" - "github.com/hashicorp/consul/agent/consul/state" - "github.com/hashicorp/consul/agent/structs" - "github.com/hashicorp/consul/lib/retry" "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-memdb" "golang.org/x/time/rate" + + "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/lib/retry" ) var StatsGauges = []prometheus.GaugeDefinition{ @@ -132,7 +132,6 @@ func (c *Controller) updateDrainRateLimit(numProxies uint32) { // 0-512 proxies: drain 1 per second // 513-2815 proxies: linearly scaled by 1/s for every additional 256 proxies // 2816+ proxies: drain 10 per second -// func calcRateLimit(numProxies uint32) rate.Limit { perSecond := math.Floor((float64(numProxies) - 256) / 256) @@ -206,5 +205,5 @@ func (c *Controller) countProxies(ctx context.Context) (<-chan error, uint32, er type Store interface { AbandonCh() <-chan struct{} - ServiceUsage(ws memdb.WatchSet) (uint64, state.ServiceUsage, error) + ServiceUsage(ws memdb.WatchSet) (uint64, structs.ServiceUsage, error) } diff --git a/agent/coordinate_endpoint_test.go b/agent/coordinate_endpoint_test.go index 331451641f3a..bef55e50c61d 100644 --- a/agent/coordinate_endpoint_test.go +++ b/agent/coordinate_endpoint_test.go @@ -39,9 +39,9 @@ func TestCoordinate_Disabled_Response(t *testing.T) { req, _ := http.NewRequest("PUT", "/should/not/care", nil) resp := httptest.NewRecorder() obj, err := tt(resp, req) - if err, ok := err.(HTTPError); ok { - if err.StatusCode != 401 { - t.Fatalf("expected status 401 but got %d", err.StatusCode) + if httpErr, ok := err.(HTTPError); ok { + if httpErr.StatusCode != 401 { + t.Fatalf("expected status 401 but got %d", httpErr.StatusCode) } } else { t.Fatalf("expected HTTP error but got %v", err) diff --git a/agent/dns.go b/agent/dns.go index d458928e803b..9ad005bf498a 100644 --- a/agent/dns.go +++ b/agent/dns.go @@ -105,6 +105,7 @@ type dnsConfig struct { } type serviceLookup struct { + PeerName string Datacenter string Service string Tag string @@ -116,6 +117,7 @@ type serviceLookup struct { type nodeLookup struct { Datacenter string + PeerName string Node string Tag string MaxRecursionLevel int @@ -421,11 +423,18 @@ func (d *DNSServer) handlePtr(resp dns.ResponseWriter, req *dns.Msg) { // server side to avoid transferring the entire node list. if err := d.agent.RPC("Catalog.ListNodes", &args, &out); err == nil { for _, n := range out.Nodes { + lookup := serviceLookup{ + // Peering PTR lookups are currently not supported, so we don't + // need to populate that field for creating the node FQDN. + // PeerName: n.PeerName, + Datacenter: n.Datacenter, + EnterpriseMeta: *n.GetEnterpriseMeta(), + } arpa, _ := dns.ReverseAddr(n.Address) if arpa == qName { ptr := &dns.PTR{ Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: 0}, - Ptr: fmt.Sprintf("%s.node.%s.%s", n.Node, datacenter, d.domain), + Ptr: nodeCanonicalDNSName(lookup, n.Node, d.domain), } m.Answer = append(m.Answer, ptr) break @@ -685,8 +694,16 @@ type queryLocality struct { // Example query: .virtual..ns..ap..dc.consul datacenter string - // peerOrDatacenter is parsed from DNS queries where the datacenter and peer name are specified in the same query part. + // peer is the peer name parsed from a label that has explicit parts. + // Example query: .virtual..ns..peer..ap.consul + peer string + + // peerOrDatacenter is parsed from DNS queries where the datacenter and peer name are + // specified in the same query part. // Example query: .virtual..consul + // + // Note that this field should only be a "peer" for virtual queries, since virtual IPs should + // not be shared between datacenters. In all other cases, it should be considered a DC. peerOrDatacenter string acl.EnterpriseMeta @@ -763,11 +780,17 @@ func (d *DNSServer) dispatch(remoteAddr net.Addr, req, resp *dns.Msg, maxRecursi lookup := serviceLookup{ Datacenter: locality.effectiveDatacenter(d.agent.config.Datacenter), + PeerName: locality.peer, Connect: false, Ingress: false, MaxRecursionLevel: maxRecursionLevel, EnterpriseMeta: locality.EnterpriseMeta, } + // Only one of dc or peer can be used. + if lookup.PeerName != "" { + lookup.Datacenter = "" + } + // Support RFC 2782 style syntax if n == 2 && strings.HasPrefix(queryParts[1], "_") && strings.HasPrefix(queryParts[0], "_") { @@ -808,6 +831,9 @@ func (d *DNSServer) dispatch(remoteAddr net.Addr, req, resp *dns.Msg, maxRecursi return invalid() } + // Peering is not currently supported for connect queries. + // Exposing this likely would not provide much value, since users would + // need to be very familiar with our TLS / SNI / mesh gateways to leverage it. lookup := serviceLookup{ Datacenter: locality.effectiveDatacenter(d.agent.config.Datacenter), Service: queryParts[len(queryParts)-1], @@ -833,13 +859,18 @@ func (d *DNSServer) dispatch(remoteAddr net.Addr, req, resp *dns.Msg, maxRecursi // The datacenter of the request is not specified because cross-datacenter virtual IP // queries are not supported. This guard rail is in place because virtual IPs are allocated // within a DC, therefore their uniqueness is not guaranteed globally. - PeerName: locality.peerOrDatacenter, + PeerName: locality.peer, ServiceName: queryParts[len(queryParts)-1], EnterpriseMeta: locality.EnterpriseMeta, QueryOptions: structs.QueryOptions{ Token: d.agent.tokens.UserToken(), }, } + if args.PeerName == "" { + // If the peer name was not explicitly defined, fall back to the ambiguously-parsed version. + args.PeerName = locality.peerOrDatacenter + } + var out string if err := d.agent.RPC("Catalog.VirtualIPForService", &args, &out); err != nil { return err @@ -868,6 +899,8 @@ func (d *DNSServer) dispatch(remoteAddr net.Addr, req, resp *dns.Msg, maxRecursi return invalid() } + // Peering is not currently supported for ingress queries. + // We probably should not be encouraging chained calls from ingress to peers anyway. lookup := serviceLookup{ Datacenter: locality.effectiveDatacenter(d.agent.config.Datacenter), Service: queryParts[len(queryParts)-1], @@ -900,10 +933,15 @@ func (d *DNSServer) dispatch(remoteAddr net.Addr, req, resp *dns.Msg, maxRecursi lookup := nodeLookup{ Datacenter: locality.effectiveDatacenter(d.agent.config.Datacenter), + PeerName: locality.peer, Node: node, MaxRecursionLevel: maxRecursionLevel, EnterpriseMeta: locality.EnterpriseMeta, } + // Only one of dc or peer can be used. + if lookup.PeerName != "" { + lookup.Datacenter = "" + } return d.nodeLookup(cfg, lookup, req, resp) @@ -989,7 +1027,7 @@ func (d *DNSServer) trimDomain(query string) string { longer, shorter = shorter, longer } - if strings.HasSuffix(query, longer) { + if strings.HasSuffix(query, "."+strings.TrimLeft(longer, ".")) { return strings.TrimSuffix(query, longer) } return strings.TrimSuffix(query, shorter) @@ -1024,6 +1062,7 @@ func (d *DNSServer) nodeLookup(cfg *dnsConfig, lookup nodeLookup, req, resp *dns // Make an RPC request args := &structs.NodeSpecificRequest{ Datacenter: lookup.Datacenter, + PeerName: lookup.PeerName, Node: lookup.Node, QueryOptions: structs.QueryOptions{ Token: d.agent.tokens.UserToken(), @@ -1350,6 +1389,7 @@ func (d *DNSServer) lookupServiceNodes(cfg *dnsConfig, lookup serviceLookup) (st serviceTags = []string{lookup.Tag} } args := structs.ServiceSpecificRequest{ + PeerName: lookup.PeerName, Connect: lookup.Connect, Ingress: lookup.Ingress, Datacenter: lookup.Datacenter, @@ -1400,9 +1440,9 @@ func (d *DNSServer) serviceLookup(cfg *dnsConfig, lookup serviceLookup, req, res // Add various responses depending on the request qType := req.Question[0].Qtype if qType == dns.TypeSRV { - d.serviceSRVRecords(cfg, lookup.Datacenter, out.Nodes, req, resp, ttl, lookup.MaxRecursionLevel) + d.serviceSRVRecords(cfg, lookup, out.Nodes, req, resp, ttl, lookup.MaxRecursionLevel) } else { - d.serviceNodeRecords(cfg, lookup.Datacenter, out.Nodes, req, resp, ttl, lookup.MaxRecursionLevel) + d.serviceNodeRecords(cfg, lookup, out.Nodes, req, resp, ttl, lookup.MaxRecursionLevel) } if len(resp.Answer) == 0 { @@ -1505,10 +1545,14 @@ func (d *DNSServer) preparedQueryLookup(cfg *dnsConfig, datacenter, query string // Add various responses depending on the request. qType := req.Question[0].Qtype + + // This serviceLookup only needs the datacenter field populated, + // because peering is not supported with prepared queries. + lookup := serviceLookup{Datacenter: out.Datacenter} if qType == dns.TypeSRV { - d.serviceSRVRecords(cfg, out.Datacenter, out.Nodes, req, resp, ttl, maxRecursionLevel) + d.serviceSRVRecords(cfg, lookup, out.Nodes, req, resp, ttl, maxRecursionLevel) } else { - d.serviceNodeRecords(cfg, out.Datacenter, out.Nodes, req, resp, ttl, maxRecursionLevel) + d.serviceNodeRecords(cfg, lookup, out.Nodes, req, resp, ttl, maxRecursionLevel) } if len(resp.Answer) == 0 { @@ -1559,7 +1603,7 @@ RPC: } // serviceNodeRecords is used to add the node records for a service lookup -func (d *DNSServer) serviceNodeRecords(cfg *dnsConfig, dc string, nodes structs.CheckServiceNodes, req, resp *dns.Msg, ttl time.Duration, maxRecursionLevel int) { +func (d *DNSServer) serviceNodeRecords(cfg *dnsConfig, lookup serviceLookup, nodes structs.CheckServiceNodes, req, resp *dns.Msg, ttl time.Duration, maxRecursionLevel int) { handled := make(map[string]struct{}) var answerCNAME []dns.RR = nil @@ -1567,7 +1611,7 @@ func (d *DNSServer) serviceNodeRecords(cfg *dnsConfig, dc string, nodes structs. for _, node := range nodes { // Add the node record had_answer := false - records, _ := d.nodeServiceRecords(dc, node, req, ttl, cfg, maxRecursionLevel) + records, _ := d.nodeServiceRecords(lookup, node, req, ttl, cfg, maxRecursionLevel) if len(records) == 0 { continue } @@ -1650,15 +1694,20 @@ func findWeight(node structs.CheckServiceNode) int { } } -func (d *DNSServer) encodeIPAsFqdn(questionName string, dc string, ip net.IP) string { +func (d *DNSServer) encodeIPAsFqdn(questionName string, lookup serviceLookup, ip net.IP) string { ipv4 := ip.To4() respDomain := d.getResponseDomain(questionName) + ipStr := hex.EncodeToString(ip) if ipv4 != nil { - ipStr := hex.EncodeToString(ip) - return fmt.Sprintf("%s.addr.%s.%s", ipStr[len(ipStr)-(net.IPv4len*2):], dc, respDomain) - } else { - return fmt.Sprintf("%s.addr.%s.%s", hex.EncodeToString(ip), dc, respDomain) + ipStr = ipStr[len(ipStr)-(net.IPv4len*2):] + } + if lookup.PeerName != "" { + // Exclude the datacenter from the FQDN on the addr for peers. + // This technically makes no difference, since the addr endpoint ignores the DC + // component of the request, but do it anyway for a less confusing experience. + return fmt.Sprintf("%s.addr.%s", ipStr, respDomain) } + return fmt.Sprintf("%s.addr.%s.%s", ipStr, lookup.Datacenter, respDomain) } func makeARecord(qType uint16, ip net.IP, ttl time.Duration) dns.RR { @@ -1737,16 +1786,16 @@ func (d *DNSServer) makeRecordFromNode(node *structs.Node, qType uint16, qName s // Craft dns records for a service // In case of an SRV query the answer will be a IN SRV and additional data will store an IN A to the node IP // Otherwise it will return a IN A record -func (d *DNSServer) makeRecordFromServiceNode(dc string, serviceNode structs.CheckServiceNode, addr net.IP, req *dns.Msg, ttl time.Duration) ([]dns.RR, []dns.RR) { +func (d *DNSServer) makeRecordFromServiceNode(lookup serviceLookup, serviceNode structs.CheckServiceNode, addr net.IP, req *dns.Msg, ttl time.Duration) ([]dns.RR, []dns.RR) { q := req.Question[0] - respDomain := d.getResponseDomain(q.Name) - ipRecord := makeARecord(q.Qtype, addr, ttl) if ipRecord == nil { return nil, nil } + if q.Qtype == dns.TypeSRV { - nodeFQDN := fmt.Sprintf("%s.node.%s.%s", serviceNode.Node.Node, dc, respDomain) + respDomain := d.getResponseDomain(q.Name) + nodeFQDN := nodeCanonicalDNSName(lookup, serviceNode.Node.Node, respDomain) answers := []dns.RR{ &dns.SRV{ Hdr: dns.RR_Header{ @@ -1757,7 +1806,7 @@ func (d *DNSServer) makeRecordFromServiceNode(dc string, serviceNode structs.Che }, Priority: 1, Weight: uint16(findWeight(serviceNode)), - Port: uint16(d.agent.TranslateServicePort(dc, serviceNode.Service.Port, serviceNode.Service.TaggedAddresses)), + Port: uint16(d.agent.TranslateServicePort(lookup.Datacenter, serviceNode.Service.Port, serviceNode.Service.TaggedAddresses)), Target: nodeFQDN, }, } @@ -1773,7 +1822,7 @@ func (d *DNSServer) makeRecordFromServiceNode(dc string, serviceNode structs.Che // Craft dns records for an IP // In case of an SRV query the answer will be a IN SRV and additional data will store an IN A to the IP // Otherwise it will return a IN A record -func (d *DNSServer) makeRecordFromIP(dc string, addr net.IP, serviceNode structs.CheckServiceNode, req *dns.Msg, ttl time.Duration) ([]dns.RR, []dns.RR) { +func (d *DNSServer) makeRecordFromIP(lookup serviceLookup, addr net.IP, serviceNode structs.CheckServiceNode, req *dns.Msg, ttl time.Duration) ([]dns.RR, []dns.RR) { q := req.Question[0] ipRecord := makeARecord(q.Qtype, addr, ttl) if ipRecord == nil { @@ -1781,7 +1830,7 @@ func (d *DNSServer) makeRecordFromIP(dc string, addr net.IP, serviceNode structs } if q.Qtype == dns.TypeSRV { - ipFQDN := d.encodeIPAsFqdn(q.Name, dc, addr) + ipFQDN := d.encodeIPAsFqdn(q.Name, lookup, addr) answers := []dns.RR{ &dns.SRV{ Hdr: dns.RR_Header{ @@ -1792,7 +1841,7 @@ func (d *DNSServer) makeRecordFromIP(dc string, addr net.IP, serviceNode structs }, Priority: 1, Weight: uint16(findWeight(serviceNode)), - Port: uint16(d.agent.TranslateServicePort(dc, serviceNode.Service.Port, serviceNode.Service.TaggedAddresses)), + Port: uint16(d.agent.TranslateServicePort(lookup.Datacenter, serviceNode.Service.Port, serviceNode.Service.TaggedAddresses)), Target: ipFQDN, }, } @@ -1808,7 +1857,7 @@ func (d *DNSServer) makeRecordFromIP(dc string, addr net.IP, serviceNode structs // Craft dns records for an FQDN // In case of an SRV query the answer will be a IN SRV and additional data will store an IN A to the IP // Otherwise it will return a CNAME and a IN A record -func (d *DNSServer) makeRecordFromFQDN(dc string, fqdn string, serviceNode structs.CheckServiceNode, req *dns.Msg, ttl time.Duration, cfg *dnsConfig, maxRecursionLevel int) ([]dns.RR, []dns.RR) { +func (d *DNSServer) makeRecordFromFQDN(lookup serviceLookup, fqdn string, serviceNode structs.CheckServiceNode, req *dns.Msg, ttl time.Duration, cfg *dnsConfig, maxRecursionLevel int) ([]dns.RR, []dns.RR) { edns := req.IsEdns0() != nil q := req.Question[0] @@ -1841,7 +1890,7 @@ MORE_REC: }, Priority: 1, Weight: uint16(findWeight(serviceNode)), - Port: uint16(d.agent.TranslateServicePort(dc, serviceNode.Service.Port, serviceNode.Service.TaggedAddresses)), + Port: uint16(d.agent.TranslateServicePort(lookup.Datacenter, serviceNode.Service.Port, serviceNode.Service.TaggedAddresses)), Target: dns.Fqdn(fqdn), }, } @@ -1863,7 +1912,7 @@ MORE_REC: return answers, nil } -func (d *DNSServer) nodeServiceRecords(dc string, node structs.CheckServiceNode, req *dns.Msg, ttl time.Duration, cfg *dnsConfig, maxRecursionLevel int) ([]dns.RR, []dns.RR) { +func (d *DNSServer) nodeServiceRecords(lookup serviceLookup, node structs.CheckServiceNode, req *dns.Msg, ttl time.Duration, cfg *dnsConfig, maxRecursionLevel int) ([]dns.RR, []dns.RR) { addrTranslate := TranslateAddressAcceptDomain if req.Question[0].Qtype == dns.TypeA { addrTranslate |= TranslateAddressAcceptIPv4 @@ -1873,7 +1922,9 @@ func (d *DNSServer) nodeServiceRecords(dc string, node structs.CheckServiceNode, addrTranslate |= TranslateAddressAcceptAny } - serviceAddr := d.agent.TranslateServiceAddress(dc, node.Service.Address, node.Service.TaggedAddresses, addrTranslate) + // The datacenter should be empty during translation if it is a peering lookup. + // This should be fine because we should always prefer the WAN address. + serviceAddr := d.agent.TranslateServiceAddress(lookup.Datacenter, node.Service.Address, node.Service.TaggedAddresses, addrTranslate) nodeAddr := d.agent.TranslateAddress(node.Node.Datacenter, node.Node.Address, node.Node.TaggedAddresses, addrTranslate) if serviceAddr == "" && nodeAddr == "" { return nil, nil @@ -1886,30 +1937,30 @@ func (d *DNSServer) nodeServiceRecords(dc string, node structs.CheckServiceNode, if serviceAddr == "" && nodeIPAddr != nil { if node.Node.Address != nodeAddr { // Do not CNAME node address in case of WAN address - return d.makeRecordFromIP(dc, nodeIPAddr, node, req, ttl) + return d.makeRecordFromIP(lookup, nodeIPAddr, node, req, ttl) } - return d.makeRecordFromServiceNode(dc, node, nodeIPAddr, req, ttl) + return d.makeRecordFromServiceNode(lookup, node, nodeIPAddr, req, ttl) } // There is no service address and the node address is a FQDN (external service) if serviceAddr == "" { - return d.makeRecordFromFQDN(dc, nodeAddr, node, req, ttl, cfg, maxRecursionLevel) + return d.makeRecordFromFQDN(lookup, nodeAddr, node, req, ttl, cfg, maxRecursionLevel) } // The service address is an IP if serviceIPAddr != nil { - return d.makeRecordFromIP(dc, serviceIPAddr, node, req, ttl) + return d.makeRecordFromIP(lookup, serviceIPAddr, node, req, ttl) } // If the service address is a CNAME for the service we are looking // for then use the node address. if dns.Fqdn(serviceAddr) == req.Question[0].Name && nodeIPAddr != nil { - return d.makeRecordFromServiceNode(dc, node, nodeIPAddr, req, ttl) + return d.makeRecordFromServiceNode(lookup, node, nodeIPAddr, req, ttl) } // The service address is a FQDN (external service) - return d.makeRecordFromFQDN(dc, serviceAddr, node, req, ttl, cfg, maxRecursionLevel) + return d.makeRecordFromFQDN(lookup, serviceAddr, node, req, ttl, cfg, maxRecursionLevel) } func (d *DNSServer) generateMeta(qName string, node *structs.Node, ttl time.Duration) []dns.RR { @@ -1934,28 +1985,31 @@ func (d *DNSServer) generateMeta(qName string, node *structs.Node, ttl time.Dura } // serviceARecords is used to add the SRV records for a service lookup -func (d *DNSServer) serviceSRVRecords(cfg *dnsConfig, dc string, nodes structs.CheckServiceNodes, req, resp *dns.Msg, ttl time.Duration, maxRecursionLevel int) { +func (d *DNSServer) serviceSRVRecords(cfg *dnsConfig, lookup serviceLookup, nodes structs.CheckServiceNodes, req, resp *dns.Msg, ttl time.Duration, maxRecursionLevel int) { handled := make(map[string]struct{}) for _, node := range nodes { // Avoid duplicate entries, possible if a node has // the same service the same port, etc. - serviceAddress := d.agent.TranslateServiceAddress(dc, node.Service.Address, node.Service.TaggedAddresses, TranslateAddressAcceptAny) - servicePort := d.agent.TranslateServicePort(dc, node.Service.Port, node.Service.TaggedAddresses) + + // The datacenter should be empty during translation if it is a peering lookup. + // This should be fine because we should always prefer the WAN address. + serviceAddress := d.agent.TranslateServiceAddress(lookup.Datacenter, node.Service.Address, node.Service.TaggedAddresses, TranslateAddressAcceptAny) + servicePort := d.agent.TranslateServicePort(lookup.Datacenter, node.Service.Port, node.Service.TaggedAddresses) tuple := fmt.Sprintf("%s:%s:%d", node.Node.Node, serviceAddress, servicePort) if _, ok := handled[tuple]; ok { continue } handled[tuple] = struct{}{} - answers, extra := d.nodeServiceRecords(dc, node, req, ttl, cfg, maxRecursionLevel) + answers, extra := d.nodeServiceRecords(lookup, node, req, ttl, cfg, maxRecursionLevel) respDomain := d.getResponseDomain(req.Question[0].Name) resp.Answer = append(resp.Answer, answers...) resp.Extra = append(resp.Extra, extra...) if cfg.NodeMetaTXT { - resp.Extra = append(resp.Extra, d.generateMeta(fmt.Sprintf("%s.node.%s.%s", node.Node.Node, dc, respDomain), node.Node, ttl)...) + resp.Extra = append(resp.Extra, d.generateMeta(nodeCanonicalDNSName(lookup, node.Node.Node, respDomain), node.Node, ttl)...) } } } diff --git a/agent/dns_ce.go b/agent/dns_ce.go new file mode 100644 index 000000000000..6ccbe2f8dfb2 --- /dev/null +++ b/agent/dns_ce.go @@ -0,0 +1,72 @@ +//go:build !consulent +// +build !consulent + +package agent + +import ( + "fmt" + + "github.com/hashicorp/consul/acl" + "github.com/hashicorp/consul/agent/config" +) + +type enterpriseDNSConfig struct{} + +func getEnterpriseDNSConfig(conf *config.RuntimeConfig) enterpriseDNSConfig { + return enterpriseDNSConfig{} +} + +// parseLocality can parse peer name or datacenter from a DNS query's labels. +// Peer name is parsed from the same query part that datacenter is, so given this ambiguity +// we parse a "peerOrDatacenter". The caller or RPC handler are responsible for disambiguating. +func (d *DNSServer) parseLocality(labels []string, cfg *dnsConfig) (queryLocality, bool) { + locality := queryLocality{ + EnterpriseMeta: d.defaultEnterpriseMeta, + } + + switch len(labels) { + case 2, 4: + // Support the following formats: + // - [..dc] + // - [..peer] + for i := 0; i < len(labels); i += 2 { + switch labels[i+1] { + case "dc": + locality.datacenter = labels[i] + case "peer": + locality.peer = labels[i] + default: + return queryLocality{}, false + } + } + // Return error when both datacenter and peer are specified. + if locality.datacenter != "" && locality.peer != "" { + return queryLocality{}, false + } + return locality, true + case 1: + return queryLocality{peerOrDatacenter: labels[0]}, true + + case 0: + return queryLocality{}, true + } + + return queryLocality{}, false +} + +func serviceCanonicalDNSName(name, kind, datacenter, domain string, _ *acl.EnterpriseMeta) string { + return fmt.Sprintf("%s.%s.%s.%s", name, kind, datacenter, domain) +} + +func nodeCanonicalDNSName(lookup serviceLookup, nodeName, respDomain string) string { + if lookup.PeerName != "" { + // We must return a more-specific DNS name for peering so + // that there is no ambiguity with lookups. + return fmt.Sprintf("%s.node.%s.peer.%s", + nodeName, + lookup.PeerName, + respDomain) + } + // Return a simpler format for non-peering nodes. + return fmt.Sprintf("%s.node.%s.%s", nodeName, lookup.Datacenter, respDomain) +} diff --git a/agent/dns_ce_test.go b/agent/dns_ce_test.go new file mode 100644 index 000000000000..774fdf601999 --- /dev/null +++ b/agent/dns_ce_test.go @@ -0,0 +1,127 @@ +//go:build !consulent +// +build !consulent + +package agent + +import ( + "testing" + + "github.com/hashicorp/consul/acl" + "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/testrpc" + "github.com/miekg/dns" + "github.com/stretchr/testify/require" +) + +func TestDNS_CE_PeeredServices(t *testing.T) { + if testing.Short() { + t.Skip("too slow for testing.Short") + } + + a := StartTestAgent(t, TestAgent{HCL: ``, Overrides: `peering = { test_allow_peer_registrations = true }`}) + defer a.Shutdown() + testrpc.WaitForTestAgent(t, a.RPC, "dc1") + + makeReq := func() *structs.RegisterRequest { + return &structs.RegisterRequest{ + PeerName: "peer1", + Datacenter: "dc1", + Node: "peernode1", + Address: "198.18.1.1", + Service: &structs.NodeService{ + PeerName: "peer1", + Kind: structs.ServiceKindConnectProxy, + Service: "web-proxy", + Address: "199.0.0.1", + Port: 12345, + Proxy: structs.ConnectProxyConfig{ + DestinationServiceName: "peer-web", + }, + EnterpriseMeta: *acl.DefaultEnterpriseMeta(), + }, + EnterpriseMeta: *acl.DefaultEnterpriseMeta(), + } + } + + dnsQuery := func(t *testing.T, question string, typ uint16) *dns.Msg { + m := new(dns.Msg) + m.SetQuestion(question, typ) + + c := new(dns.Client) + reply, _, err := c.Exchange(m, a.DNSAddr()) + require.NoError(t, err) + require.Len(t, reply.Answer, 1, "zero valid records found for %q", question) + return reply + } + + assertARec := func(t *testing.T, rec dns.RR, expectName, expectIP string) { + aRec, ok := rec.(*dns.A) + require.True(t, ok, "Extra is not an A record: %T", rec) + require.Equal(t, expectName, aRec.Hdr.Name) + require.Equal(t, expectIP, aRec.A.String()) + } + + assertSRVRec := func(t *testing.T, rec dns.RR, expectName string, expectPort uint16) { + srvRec, ok := rec.(*dns.SRV) + require.True(t, ok, "Answer is not a SRV record: %T", rec) + require.Equal(t, expectName, srvRec.Target) + require.Equal(t, expectPort, srvRec.Port) + } + + t.Run("srv-with-addr-reply", func(t *testing.T) { + require.NoError(t, a.RPC("Catalog.Register", makeReq(), &struct{}{})) + q := dnsQuery(t, "web-proxy.service.peer1.peer.consul.", dns.TypeSRV) + require.Len(t, q.Answer, 1) + require.Len(t, q.Extra, 1) + + addr := "c7000001.addr.consul." + assertSRVRec(t, q.Answer[0], addr, 12345) + assertARec(t, q.Extra[0], addr, "199.0.0.1") + + // Query the addr to make sure it's also valid. + q = dnsQuery(t, addr, dns.TypeA) + require.Len(t, q.Answer, 1) + require.Len(t, q.Extra, 0) + assertARec(t, q.Answer[0], addr, "199.0.0.1") + }) + + t.Run("srv-with-node-reply", func(t *testing.T) { + req := makeReq() + // Clear service address to trigger node response + req.Service.Address = "" + require.NoError(t, a.RPC("Catalog.Register", req, &struct{}{})) + q := dnsQuery(t, "web-proxy.service.peer1.peer.consul.", dns.TypeSRV) + require.Len(t, q.Answer, 1) + require.Len(t, q.Extra, 1) + + nodeName := "peernode1.node.peer1.peer.consul." + assertSRVRec(t, q.Answer[0], nodeName, 12345) + assertARec(t, q.Extra[0], nodeName, "198.18.1.1") + + // Query the node to make sure it's also valid. + q = dnsQuery(t, nodeName, dns.TypeA) + require.Len(t, q.Answer, 1) + require.Len(t, q.Extra, 0) + assertARec(t, q.Answer[0], nodeName, "198.18.1.1") + }) + + t.Run("srv-with-fqdn-reply", func(t *testing.T) { + req := makeReq() + // Set non-ip address to trigger external response + req.Address = "localhost" + req.Service.Address = "" + require.NoError(t, a.RPC("Catalog.Register", req, &struct{}{})) + q := dnsQuery(t, "web-proxy.service.peer1.peer.consul.", dns.TypeSRV) + require.Len(t, q.Answer, 1) + require.Len(t, q.Extra, 0) + assertSRVRec(t, q.Answer[0], "localhost.", 12345) + }) + + t.Run("a-reply", func(t *testing.T) { + require.NoError(t, a.RPC("Catalog.Register", makeReq(), &struct{}{})) + q := dnsQuery(t, "web-proxy.service.peer1.peer.consul.", dns.TypeA) + require.Len(t, q.Answer, 1) + require.Len(t, q.Extra, 0) + assertARec(t, q.Answer[0], "web-proxy.service.peer1.peer.consul.", "199.0.0.1") + }) +} diff --git a/agent/dns_oss.go b/agent/dns_oss.go deleted file mode 100644 index de257aa4cce3..000000000000 --- a/agent/dns_oss.go +++ /dev/null @@ -1,36 +0,0 @@ -//go:build !consulent -// +build !consulent - -package agent - -import ( - "fmt" - - "github.com/hashicorp/consul/acl" - "github.com/hashicorp/consul/agent/config" -) - -type enterpriseDNSConfig struct{} - -func getEnterpriseDNSConfig(conf *config.RuntimeConfig) enterpriseDNSConfig { - return enterpriseDNSConfig{} -} - -// parseLocality can parse peer name or datacenter from a DNS query's labels. -// Peer name is parsed from the same query part that datacenter is, so given this ambiguity -// we parse a "peerOrDatacenter". The caller or RPC handler are responsible for disambiguating. -func (d *DNSServer) parseLocality(labels []string, cfg *dnsConfig) (queryLocality, bool) { - switch len(labels) { - case 1: - return queryLocality{peerOrDatacenter: labels[0]}, true - - case 0: - return queryLocality{}, true - } - - return queryLocality{}, false -} - -func serviceCanonicalDNSName(name, kind, datacenter, domain string, _ *acl.EnterpriseMeta) string { - return fmt.Sprintf("%s.%s.%s.%s", name, kind, datacenter, domain) -} diff --git a/agent/dns_test.go b/agent/dns_test.go index 2f2499a2efcb..01d08d67df6b 100644 --- a/agent/dns_test.go +++ b/agent/dns_test.go @@ -12,12 +12,12 @@ import ( "testing" "time" - "github.com/hashicorp/consul/agent/consul" "github.com/hashicorp/serf/coordinate" "github.com/miekg/dns" "github.com/stretchr/testify/require" "github.com/hashicorp/consul/agent/config" + "github.com/hashicorp/consul/agent/consul" agentdns "github.com/hashicorp/consul/agent/dns" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/api" @@ -479,6 +479,7 @@ func TestDNSCycleRecursorCheck(t *testing.T) { } require.Equal(t, wantAnswer, in.Answer) } + func TestDNSCycleRecursorCheckAllFail(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short") @@ -512,6 +513,7 @@ func TestDNSCycleRecursorCheckAllFail(t *testing.T) { // Verify if we hit SERVFAIL from Consul require.Equal(t, dns.RcodeServerFailure, in.Rcode) } + func TestDNS_NodeLookup_CNAME(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short") @@ -3178,7 +3180,7 @@ func TestDNS_ServiceLookup_WanTranslation(t *testing.T) { } var out struct{} - require.NoError(t, a2.RPC("Catalog.Register", args, &out)) + require.NoError(r, a2.RPC("Catalog.Register", args, &out)) }) // Look up the SRV record via service and prepared query. @@ -3506,11 +3508,11 @@ func TestDNS_CaseInsensitiveServiceLookup(t *testing.T) { retry.Run(t, func(r *retry.R) { in, _, err := c.Exchange(m, a.DNSAddr()) if err != nil { - t.Fatalf("err: %v", err) + r.Fatalf("err: %v", err) } if len(in.Answer) != 1 { - t.Fatalf("question %v, empty lookup: %#v", question, in) + r.Fatalf("question %v, empty lookup: %#v", question, in) } }) } @@ -5162,9 +5164,10 @@ func testDNSServiceLookupResponseLimits(t *testing.T, answerLimit int, qType uin defer a.Shutdown() testrpc.WaitForTestAgent(t, a.RPC, "dc1") + choices := perfectlyRandomChoices(generateNumNodes, pctNodesWithIPv6) for i := 0; i < generateNumNodes; i++ { nodeAddress := fmt.Sprintf("127.0.0.%d", i+1) - if rand.Float64() < pctNodesWithIPv6 { + if choices[i] { nodeAddress = fmt.Sprintf("fe80::%d", i+1) } args := &structs.RegisterRequest{ @@ -5240,8 +5243,14 @@ func testDNSServiceLookupResponseLimits(t *testing.T, answerLimit int, qType uin return true, nil } -func checkDNSService(t *testing.T, generateNumNodes int, aRecordLimit int, qType uint16, - expectedResultsCount int, udpSize uint16) error { +func checkDNSService( + t *testing.T, + generateNumNodes int, + aRecordLimit int, + qType uint16, + expectedResultsCount int, + udpSize uint16, +) { a := NewTestAgent(t, ` node_name = "test-node" dns_config { @@ -5249,12 +5258,12 @@ func checkDNSService(t *testing.T, generateNumNodes int, aRecordLimit int, qType udp_answer_limit = `+fmt.Sprintf("%d", aRecordLimit)+` } `) - defer a.Shutdown() testrpc.WaitForTestAgent(t, a.RPC, "dc1") + choices := perfectlyRandomChoices(generateNumNodes, pctNodesWithIPv6) for i := 0; i < generateNumNodes; i++ { nodeAddress := fmt.Sprintf("127.0.0.%d", i+1) - if rand.Float64() < pctNodesWithIPv6 { + if choices[i] { nodeAddress = fmt.Sprintf("fe80::%d", i+1) } args := &structs.RegisterRequest{ @@ -5268,9 +5277,7 @@ func checkDNSService(t *testing.T, generateNumNodes int, aRecordLimit int, qType } var out struct{} - if err := a.RPC("Catalog.Register", args, &out); err != nil { - return fmt.Errorf("err: %v", err) - } + require.NoError(t, a.RPC("Catalog.Register", args, &out)) } var id string { @@ -5285,9 +5292,7 @@ func checkDNSService(t *testing.T, generateNumNodes int, aRecordLimit int, qType }, } - if err := a.RPC("PreparedQuery.Apply", args, &id); err != nil { - return fmt.Errorf("err: %v", err) - } + require.NoError(t, a.RPC("PreparedQuery.Apply", args, &id)) } // Look up the service directly and via prepared query. @@ -5297,28 +5302,29 @@ func checkDNSService(t *testing.T, generateNumNodes int, aRecordLimit int, qType id + ".query.consul.", } for _, question := range questions { - m := new(dns.Msg) + question := question + t.Run("question: "+question, func(t *testing.T) { - m.SetQuestion(question, qType) - protocol := "tcp" - if udpSize > 0 { - protocol = "udp" - } - if udpSize > 512 { - m.SetEdns0(udpSize, true) - } - c := &dns.Client{Net: protocol, UDPSize: 8192} - in, _, err := c.Exchange(m, a.DNSAddr()) - t.Logf("DNS Response for %+v - %+v", m, in) - if err != nil { - return fmt.Errorf("err: %v", err) - } - if len(in.Answer) != expectedResultsCount { - return fmt.Errorf("%d/%d answers received for type %v for %s (%s)", len(in.Answer), expectedResultsCount, qType, question, protocol) - } - } + m := new(dns.Msg) + + m.SetQuestion(question, qType) + protocol := "tcp" + if udpSize > 0 { + protocol = "udp" + } + if udpSize > 512 { + m.SetEdns0(udpSize, true) + } + c := &dns.Client{Net: protocol, UDPSize: 8192} + in, _, err := c.Exchange(m, a.DNSAddr()) + require.NoError(t, err) - return nil + t.Logf("DNS Response for %+v - %+v", m, in) + + require.Equal(t, expectedResultsCount, len(in.Answer), + "%d/%d answers received for type %v for %s (%s)", len(in.Answer), expectedResultsCount, qType, question, protocol) + }) + } } func TestDNS_ServiceLookup_ARecordLimits(t *testing.T) { @@ -5328,77 +5334,81 @@ func TestDNS_ServiceLookup_ARecordLimits(t *testing.T) { t.Parallel() tests := []struct { - name string - aRecordLimit int - expectedAResults int - expectedAAAAResults int - expectedSRVResults int - numNodesTotal int - udpSize uint16 - udpAnswerLimit int + name string + aRecordLimit int + expectedAResults int + expectedAAAAResults int + expectedANYResults int + expectedSRVResults int + numNodesTotal int + udpSize uint16 + _unused_udpAnswerLimit int // NOTE: this field is not used }{ // UDP + EDNS - {"udp-edns-1", 1, 1, 1, 30, 30, 8192, 3}, - {"udp-edns-2", 2, 2, 1, 30, 30, 8192, 3}, - {"udp-edns-3", 3, 3, 1, 30, 30, 8192, 3}, - {"udp-edns-4", 4, 4, 1, 30, 30, 8192, 3}, - {"udp-edns-5", 5, 5, 1, 30, 30, 8192, 3}, - {"udp-edns-6", 6, 6, 1, 30, 30, 8192, 3}, - {"udp-edns-max", 6, 3, 3, 3, 3, 8192, 3}, + {"udp-edns-1", 1, 1, 1, 1, 30, 30, 8192, 3}, + {"udp-edns-2", 2, 2, 2, 2, 30, 30, 8192, 3}, + {"udp-edns-3", 3, 3, 3, 3, 30, 30, 8192, 3}, + {"udp-edns-4", 4, 4, 4, 4, 30, 30, 8192, 3}, + {"udp-edns-5", 5, 5, 5, 5, 30, 30, 8192, 3}, + {"udp-edns-6", 6, 6, 6, 6, 30, 30, 8192, 3}, + {"udp-edns-max", 6, 2, 1, 3, 3, 3, 8192, 3}, // All UDP without EDNS have a limit of 2 answers due to udpAnswerLimit // Even SRV records are limit to 2 records - {"udp-limit-1", 1, 1, 1, 1, 1, 512, 2}, - {"udp-limit-2", 2, 2, 2, 2, 2, 512, 2}, + {"udp-limit-1", 1, 1, 0, 1, 1, 1, 512, 2}, + {"udp-limit-2", 2, 1, 1, 2, 2, 2, 512, 2}, // AAAA results limited by size of payload - {"udp-limit-3", 3, 2, 2, 2, 2, 512, 2}, - {"udp-limit-4", 4, 2, 2, 2, 2, 512, 2}, - {"udp-limit-5", 5, 2, 2, 2, 2, 512, 2}, - {"udp-limit-6", 6, 2, 2, 2, 2, 512, 2}, - {"udp-limit-max", 6, 2, 2, 2, 2, 512, 2}, + {"udp-limit-3", 3, 1, 1, 2, 2, 2, 512, 2}, + {"udp-limit-4", 4, 1, 1, 2, 2, 2, 512, 2}, + {"udp-limit-5", 5, 1, 1, 2, 2, 2, 512, 2}, + {"udp-limit-6", 6, 1, 1, 2, 2, 2, 512, 2}, + {"udp-limit-max", 6, 1, 1, 2, 2, 2, 512, 2}, // All UDP without EDNS and no udpAnswerLimit // Size of records is limited by UDP payload - {"udp-1", 1, 1, 1, 1, 1, 512, 0}, - {"udp-2", 2, 2, 2, 2, 2, 512, 0}, - {"udp-3", 3, 2, 2, 2, 2, 512, 0}, - {"udp-4", 4, 2, 2, 2, 2, 512, 0}, - {"udp-5", 5, 2, 2, 2, 2, 512, 0}, - {"udp-6", 6, 2, 2, 2, 2, 512, 0}, + {"udp-1", 1, 1, 0, 1, 1, 1, 512, 0}, + {"udp-2", 2, 1, 1, 2, 2, 2, 512, 0}, + {"udp-3", 3, 1, 1, 2, 2, 2, 512, 0}, + {"udp-4", 4, 1, 1, 2, 2, 2, 512, 0}, + {"udp-5", 5, 1, 1, 2, 2, 2, 512, 0}, + {"udp-6", 6, 1, 1, 2, 2, 2, 512, 0}, // Only 3 A and 3 SRV records on 512 bytes - {"udp-max", 6, 2, 2, 2, 2, 512, 0}, + {"udp-max", 6, 1, 1, 2, 2, 2, 512, 0}, - {"tcp-1", 1, 1, 1, 30, 30, 0, 0}, - {"tcp-2", 2, 2, 2, 30, 30, 0, 0}, - {"tcp-3", 3, 3, 3, 30, 30, 0, 0}, - {"tcp-4", 4, 4, 4, 30, 30, 0, 0}, - {"tcp-5", 5, 5, 5, 30, 30, 0, 0}, - {"tcp-6", 6, 6, 5, 30, 30, 0, 0}, - {"tcp-max", 6, 2, 2, 2, 2, 0, 0}, + {"tcp-1", 1, 1, 1, 1, 30, 30, 0, 0}, + {"tcp-2", 2, 2, 2, 2, 30, 30, 0, 0}, + {"tcp-3", 3, 3, 3, 3, 30, 30, 0, 0}, + {"tcp-4", 4, 4, 4, 4, 30, 30, 0, 0}, + {"tcp-5", 5, 5, 5, 5, 30, 30, 0, 0}, + {"tcp-6", 6, 6, 6, 6, 30, 30, 0, 0}, + {"tcp-max", 6, 1, 1, 2, 2, 2, 0, 0}, } for _, test := range tests { test := test // capture loop var - queriesLimited := []uint16{ - dns.TypeA, - dns.TypeAAAA, - dns.TypeANY, - } - // All those queries should have at max queriesLimited elements - for idx, qType := range queriesLimited { - t.Run(fmt.Sprintf("ARecordLimit %d qType: %d", idx, qType), func(t *testing.T) { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + // All those queries should have at max queriesLimited elements + + t.Run("A", func(t *testing.T) { t.Parallel() - err := checkDNSService(t, test.numNodesTotal, test.aRecordLimit, qType, test.expectedAResults, test.udpSize) - if err != nil { - t.Fatalf("Expected lookup %s to pass: %v", test.name, err) - } + checkDNSService(t, test.numNodesTotal, test.aRecordLimit, dns.TypeA, test.expectedAResults, test.udpSize) + }) + + t.Run("AAAA", func(t *testing.T) { + t.Parallel() + checkDNSService(t, test.numNodesTotal, test.aRecordLimit, dns.TypeAAAA, test.expectedAAAAResults, test.udpSize) + }) + + t.Run("ANY", func(t *testing.T) { + t.Parallel() + checkDNSService(t, test.numNodesTotal, test.aRecordLimit, dns.TypeANY, test.expectedANYResults, test.udpSize) + }) + + // No limits but the size of records for SRV records, since not subject to randomization issues + t.Run("SRV", func(t *testing.T) { + t.Parallel() + checkDNSService(t, test.expectedSRVResults, test.aRecordLimit, dns.TypeSRV, test.numNodesTotal, test.udpSize) }) - } - // No limits but the size of records for SRV records, since not subject to randomization issues - t.Run("SRV lookup limitARecord", func(t *testing.T) { - t.Parallel() - err := checkDNSService(t, test.expectedSRVResults, test.aRecordLimit, dns.TypeSRV, test.numNodesTotal, test.udpSize) - if err != nil { - t.Fatalf("Expected service SRV lookup %s to pass: %v", test.name, err) - } }) } } @@ -6349,6 +6359,7 @@ func TestDNS_ServiceLookup_FilterACL(t *testing.T) { }) } } + func TestDNS_ServiceLookup_MetaTXT(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short") @@ -7047,6 +7058,45 @@ func TestDNS_AltDomains_Overlap(t *testing.T) { } } +func TestDNS_AltDomain_DCName_Overlap(t *testing.T) { + if testing.Short() { + t.Skip("too slow for testing.Short") + } + + // this tests the DC name overlap with the consul domain/alt-domain + // we should get response when DC suffix is a prefix of consul alt-domain + t.Parallel() + a := NewTestAgent(t, ` + datacenter = "dc-test" + node_name = "test-node" + alt_domain = "test.consul." + `) + defer a.Shutdown() + testrpc.WaitForLeader(t, a.RPC, "dc-test") + + questions := []string{ + "test-node.node.dc-test.consul.", + "test-node.node.dc-test.test.consul.", + } + + for _, question := range questions { + m := new(dns.Msg) + m.SetQuestion(question, dns.TypeA) + + c := new(dns.Client) + in, _, err := c.Exchange(m, a.DNSAddr()) + if err != nil { + t.Fatalf("err: %v", err) + } + + require.Len(t, in.Answer, 1) + + aRec, ok := in.Answer[0].(*dns.A) + require.True(t, ok) + require.Equal(t, aRec.A.To4().String(), "127.0.0.1") + } +} + func TestDNS_PreparedQuery_AllowStale(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short") @@ -8271,3 +8321,72 @@ func TestECSNotGlobalError(t *testing.T) { require.Equal(t, errNameNotFound, errors.Unwrap(e)) }) } + +// perfectlyRandomChoices assigns exactly the provided fraction of size items a +// true value, and then presents a random permutation of those boolean values. +func perfectlyRandomChoices(size int, frac float64) []bool { + out := make([]bool, size) + + max := int(float64(size) * frac) + for i := 0; i < max; i++ { + out[i] = true + } + + rand.Shuffle(size, func(i, j int) { + out[i], out[j] = out[j], out[i] + }) + return out +} + +func TestPerfectlyRandomChoices(t *testing.T) { + count := func(got []bool) int { + var x int + for _, v := range got { + if v { + x++ + } + } + return x + } + + type testcase struct { + size int + frac float64 + expect int + } + + run := func(t *testing.T, tc testcase) { + got := perfectlyRandomChoices(tc.size, tc.frac) + require.Equal(t, tc.expect, count(got)) + } + + cases := []testcase{ + // 100% + {0, 1, 0}, + {1, 1, 1}, + {2, 1, 2}, + {3, 1, 3}, + {5, 1, 5}, + // 50% + {0, 0.5, 0}, + {1, 0.5, 0}, + {2, 0.5, 1}, + {3, 0.5, 1}, + {5, 0.5, 2}, + // 10% + {0, 0.1, 0}, + {1, 0.1, 0}, + {2, 0.1, 0}, + {3, 0.1, 0}, + {5, 0.1, 0}, + {10, 0.1, 1}, + {11, 0.1, 1}, + {15, 0.1, 1}, + } + + for _, tc := range cases { + t.Run(fmt.Sprintf("size=%d frac=%g", tc.size, tc.frac), func(t *testing.T) { + run(t, tc) + }) + } +} diff --git a/agent/enterprise_delegate_oss.go b/agent/enterprise_delegate_ce.go similarity index 67% rename from agent/enterprise_delegate_oss.go rename to agent/enterprise_delegate_ce.go index 876c8837afea..399848982576 100644 --- a/agent/enterprise_delegate_oss.go +++ b/agent/enterprise_delegate_ce.go @@ -3,5 +3,5 @@ package agent -// enterpriseDelegate has no functions in OSS +// enterpriseDelegate has no functions in CE type enterpriseDelegate interface{} diff --git a/agent/grpc-external/limiter/limiter.go b/agent/grpc-external/limiter/limiter.go index 26e013b161f8..9c0fcf795bad 100644 --- a/agent/grpc-external/limiter/limiter.go +++ b/agent/grpc-external/limiter/limiter.go @@ -28,9 +28,9 @@ var ErrCapacityReached = errors.New("active session limit reached") // // It is the session-holder's responsibility to: // -// 1. Call End on the session when finished. -// 2. Receive on the session's Terminated channel and exit (e.g. close the gRPC -// stream) when it is closed. +// 1. Call End on the session when finished. +// 2. Receive on the session's Terminated channel and exit (e.g. close the gRPC +// stream) when it is closed. // // The maximum number of concurrent sessions is controlled with SetMaxSessions. // If there are more than the given maximum sessions already in-flight, @@ -114,9 +114,9 @@ func (l *SessionLimiter) SetDrainRateLimit(limit rate.Limit) { // // It is the session-holder's responsibility to: // -// 1. Call End on the session when finished. -// 2. Receive on the session's Terminated channel and exit (e.g. close the gRPC -// stream) when it is closed. +// 1. Call End on the session when finished. +// 2. Receive on the session's Terminated channel and exit (e.g. close the gRPC +// stream) when it is closed. func (l *SessionLimiter) BeginSession() (Session, error) { if !l.hasCapacity() { return nil, ErrCapacityReached @@ -129,8 +129,8 @@ func (l *SessionLimiter) BeginSession() (Session, error) { // Note: hasCapacity is *best effort*. As we do not hold l.mu it's possible that: // -// - max has changed by the time we compare it to inFlight. -// - inFlight < max now, but increases before we create a new session. +// - max has changed by the time we compare it to inFlight. +// - inFlight < max now, but increases before we create a new session. // // This is acceptable for our uses, especially because excess sessions will // eventually be drained. @@ -146,8 +146,8 @@ func (l *SessionLimiter) hasCapacity() bool { // Note: overCapacity is *best effort*. As we do not hold l.mu it's possible that: // -// - max has changed by the time we compare it to inFlight. -// - inFlight > max now, but decreases before we terminate a session. +// - max has changed by the time we compare it to inFlight. +// - inFlight > max now, but decreases before we terminate a session. func (l *SessionLimiter) overCapacity() bool { max := atomic.LoadUint32(&l.max) if max == Unlimited { @@ -213,6 +213,10 @@ func (l *SessionLimiter) deleteSessionWithID(id uint64) { l.deleteSessionLocked(idx, id) } +// SessionTerminatedChan is a channel that will be closed to notify session- +// holders that a session has been terminated. +type SessionTerminatedChan <-chan struct{} + // Session allows its holder to perform an operation (e.g. serve a gRPC stream) // concurrenly with other session-holders. Sessions may be terminated abruptly // by the SessionLimiter, so it is the responsibility of the holder to receive @@ -228,7 +232,7 @@ type Session interface { // // The session-holder MUST receive on it and exit (e.g. close the gRPC stream) // when it is closed. - Terminated() <-chan struct{} + Terminated() SessionTerminatedChan } type session struct { @@ -240,6 +244,6 @@ type session struct { func (s *session) End() { s.l.deleteSessionWithID(s.id) } -func (s *session) Terminated() <-chan struct{} { return s.termCh } +func (s *session) Terminated() SessionTerminatedChan { return s.termCh } func (s *session) terminate() { close(s.termCh) } diff --git a/agent/grpc-external/limiter/limiter_test.go b/agent/grpc-external/limiter/limiter_test.go index cef6a4d41719..7f5b9654a0aa 100644 --- a/agent/grpc-external/limiter/limiter_test.go +++ b/agent/grpc-external/limiter/limiter_test.go @@ -8,12 +8,8 @@ import ( "time" "github.com/stretchr/testify/require" - - "github.com/hashicorp/consul/lib" ) -func init() { lib.SeedMathRand() } - func TestSessionLimiter(t *testing.T) { lim := NewSessionLimiter() diff --git a/agent/grpc-external/querymeta.go b/agent/grpc-external/querymeta.go new file mode 100644 index 000000000000..55b960255fff --- /dev/null +++ b/agent/grpc-external/querymeta.go @@ -0,0 +1,77 @@ +package external + +import ( + "fmt" + "reflect" + + "github.com/mitchellh/mapstructure" + "google.golang.org/grpc/metadata" + + "github.com/hashicorp/consul/agent/structs" +) + +func StringToQueryBackendDecodeHookFunc(f reflect.Type, t reflect.Type, data any) (any, error) { + if f.Kind() != reflect.String { + return data, nil + } + if t != reflect.TypeOf(structs.QueryBackend(0)) { + return data, nil + } + + name, ok := data.(string) + if !ok { + return data, fmt.Errorf("could not parse query backend as string") + } + + return structs.QueryBackendFromString(name), nil +} + +// QueryMetaFromGRPCMeta returns a structs.QueryMeta struct parsed from the metadata.MD, +// such as from a gRPC header or trailer. +func QueryMetaFromGRPCMeta(md metadata.MD) (structs.QueryMeta, error) { + var queryMeta structs.QueryMeta + + m := map[string]string{} + for k, v := range md { + m[k] = v[0] + } + + decodeHooks := mapstructure.ComposeDecodeHookFunc( + mapstructure.StringToTimeDurationHookFunc(), + StringToQueryBackendDecodeHookFunc, + ) + + config := &mapstructure.DecoderConfig{ + Metadata: nil, + Result: &queryMeta, + WeaklyTypedInput: true, + DecodeHook: decodeHooks, + } + + decoder, err := mapstructure.NewDecoder(config) + if err != nil { + return queryMeta, err + } + + err = decoder.Decode(m) + if err != nil { + return queryMeta, err + } + + return queryMeta, nil +} + +// GRPCMetadataFromQueryMeta returns a metadata struct with fields from the structs.QueryMeta attached. +// The return value is suitable for attaching to a gRPC header/trailer. +func GRPCMetadataFromQueryMeta(queryMeta structs.QueryMeta) (metadata.MD, error) { + md := metadata.MD{} + m := map[string]any{} + err := mapstructure.Decode(queryMeta, &m) + if err != nil { + return nil, err + } + for k, v := range m { + md.Set(k, fmt.Sprintf("%v", v)) + } + return md, nil +} diff --git a/agent/grpc-external/querymeta_test.go b/agent/grpc-external/querymeta_test.go new file mode 100644 index 000000000000..66c7136a3dd4 --- /dev/null +++ b/agent/grpc-external/querymeta_test.go @@ -0,0 +1,35 @@ +package external + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/hashicorp/consul/agent/structs" +) + +func TestQueryMetaFromGRPCMetaRoundTrip(t *testing.T) { + lastContact, err := time.ParseDuration("1s") + require.NoError(t, err) + + expected := structs.QueryMeta{ + Index: 42, + LastContact: lastContact, + KnownLeader: true, + ConsistencyLevel: "stale", + NotModified: true, + Backend: structs.QueryBackend(0), + ResultsFilteredByACLs: true, + } + + md, err := GRPCMetadataFromQueryMeta(expected) + require.NoError(t, err) + + actual, err := QueryMetaFromGRPCMeta(md) + if err != nil { + t.Fatal(err) + } + + require.Equal(t, expected, actual) +} diff --git a/agent/grpc-external/server.go b/agent/grpc-external/server.go index 59ca0dde2f93..dd0186d480f3 100644 --- a/agent/grpc-external/server.go +++ b/agent/grpc-external/server.go @@ -7,9 +7,11 @@ import ( middleware "github.com/grpc-ecosystem/go-grpc-middleware" recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" "google.golang.org/grpc" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/keepalive" agentmiddleware "github.com/hashicorp/consul/agent/grpc-middleware" + "github.com/hashicorp/consul/tlsutil" ) var ( @@ -21,25 +23,34 @@ var ( // NewServer constructs a gRPC server for the external gRPC port, to which // handlers can be registered. -func NewServer(logger agentmiddleware.Logger, metricsObj *metrics.Metrics) *grpc.Server { +func NewServer(logger agentmiddleware.Logger, metricsObj *metrics.Metrics, tls *tlsutil.Configurator) *grpc.Server { if metricsObj == nil { metricsObj = metrics.Default() } recoveryOpts := agentmiddleware.PanicHandlerMiddlewareOpts(logger) + unaryInterceptors := []grpc.UnaryServerInterceptor{ + // Add middlware interceptors to recover in case of panics. + recovery.UnaryServerInterceptor(recoveryOpts...), + } + streamInterceptors := []grpc.StreamServerInterceptor{ + // Add middlware interceptors to recover in case of panics. + recovery.StreamServerInterceptor(recoveryOpts...), + agentmiddleware.NewActiveStreamCounter(metricsObj, metricsLabels).Intercept, + } + + if tls != nil { + // Attach TLS middleware if TLS is provided. + authInterceptor := agentmiddleware.AuthInterceptor{TLS: tls, Logger: logger} + unaryInterceptors = append(unaryInterceptors, authInterceptor.InterceptUnary) + streamInterceptors = append(streamInterceptors, authInterceptor.InterceptStream) + } opts := []grpc.ServerOption{ grpc.MaxConcurrentStreams(2048), grpc.MaxRecvMsgSize(50 * 1024 * 1024), grpc.StatsHandler(agentmiddleware.NewStatsHandler(metricsObj, metricsLabels)), - middleware.WithUnaryServerChain( - // Add middlware interceptors to recover in case of panics. - recovery.UnaryServerInterceptor(recoveryOpts...), - ), - middleware.WithStreamServerChain( - // Add middlware interceptors to recover in case of panics. - recovery.StreamServerInterceptor(recoveryOpts...), - agentmiddleware.NewActiveStreamCounter(metricsObj, metricsLabels).Intercept, - ), + middleware.WithUnaryServerChain(unaryInterceptors...), + middleware.WithStreamServerChain(streamInterceptors...), grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{ // This must be less than the keealive.ClientParameters Time setting, otherwise // the server will disconnect the client for sending too many keepalive pings. @@ -47,5 +58,13 @@ func NewServer(logger agentmiddleware.Logger, metricsObj *metrics.Metrics) *grpc MinTime: 15 * time.Second, }), } + + if tls != nil { + // Attach TLS credentials, if provided. + tlsCreds := agentmiddleware.NewOptionalTransportCredentials( + credentials.NewTLS(tls.IncomingGRPCConfig()), + logger) + opts = append(opts, grpc.Creds(tlsCreds)) + } return grpc.NewServer(opts...) } diff --git a/agent/grpc-external/services/acl/login_test.go b/agent/grpc-external/services/acl/login_test.go index 3c681945f644..9b05842d4850 100644 --- a/agent/grpc-external/services/acl/login_test.go +++ b/agent/grpc-external/services/acl/login_test.go @@ -6,7 +6,7 @@ import ( "fmt" "testing" - mock "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/codes" @@ -17,7 +17,7 @@ import ( "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/consul/authmethod" "github.com/hashicorp/consul/agent/grpc-external/testutils" - structs "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/proto-public/pbacl" ) @@ -232,6 +232,7 @@ func TestServer_Login_RPCForwarding(t *testing.T) { NewLogin: func() Login { return login }, }) + //nolint:staticcheck leaderConn, err := grpc.Dial(testutils.RunTestServer(t, dc2).String(), grpc.WithInsecure()) require.NoError(t, err) diff --git a/agent/grpc-external/services/acl/logout_test.go b/agent/grpc-external/services/acl/logout_test.go index dfe998f319f6..276d26652c55 100644 --- a/agent/grpc-external/services/acl/logout_test.go +++ b/agent/grpc-external/services/acl/logout_test.go @@ -139,6 +139,7 @@ func TestServer_Logout_RPCForwarding(t *testing.T) { dc1Conn, err := grpc.Dial( testutils.RunTestServer(t, dc1).String(), + //nolint:staticcheck grpc.WithInsecure(), ) require.NoError(t, err) @@ -187,6 +188,7 @@ func TestServer_Logout_GlobalWritesForwardedToPrimaryDC(t *testing.T) { primaryConn, err := grpc.Dial( testutils.RunTestServer(t, primary).String(), + //nolint:staticcheck grpc.WithInsecure(), ) require.NoError(t, err) diff --git a/agent/grpc-external/services/acl/mock_Login.go b/agent/grpc-external/services/acl/mock_Login.go index 3c33169a86d2..d20d676d407a 100644 --- a/agent/grpc-external/services/acl/mock_Login.go +++ b/agent/grpc-external/services/acl/mock_Login.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.12.0. DO NOT EDIT. +// Code generated by mockery v2.15.0. DO NOT EDIT. package acl @@ -7,8 +7,6 @@ import ( mock "github.com/stretchr/testify/mock" structs "github.com/hashicorp/consul/agent/structs" - - testing "testing" ) // MockLogin is an autogenerated mock type for the Login type @@ -39,8 +37,13 @@ func (_m *MockLogin) TokenForVerifiedIdentity(identity *authmethod.Identity, aut return r0, r1 } -// NewMockLogin creates a new instance of MockLogin. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockLogin(t testing.TB) *MockLogin { +type mockConstructorTestingTNewMockLogin interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockLogin creates a new instance of MockLogin. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockLogin(t mockConstructorTestingTNewMockLogin) *MockLogin { mock := &MockLogin{} mock.Mock.Test(t) diff --git a/agent/grpc-external/services/acl/mock_TokenWriter.go b/agent/grpc-external/services/acl/mock_TokenWriter.go index 19408afc8895..a0a31b948c01 100644 --- a/agent/grpc-external/services/acl/mock_TokenWriter.go +++ b/agent/grpc-external/services/acl/mock_TokenWriter.go @@ -1,12 +1,8 @@ -// Code generated by mockery v2.12.0. DO NOT EDIT. +// Code generated by mockery v2.15.0. DO NOT EDIT. package acl -import ( - testing "testing" - - mock "github.com/stretchr/testify/mock" -) +import mock "github.com/stretchr/testify/mock" // MockTokenWriter is an autogenerated mock type for the TokenWriter type type MockTokenWriter struct { @@ -27,8 +23,13 @@ func (_m *MockTokenWriter) Delete(secretID string, fromLogout bool) error { return r0 } -// NewMockTokenWriter creates a new instance of MockTokenWriter. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockTokenWriter(t testing.TB) *MockTokenWriter { +type mockConstructorTestingTNewMockTokenWriter interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockTokenWriter creates a new instance of MockTokenWriter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockTokenWriter(t mockConstructorTestingTNewMockTokenWriter) *MockTokenWriter { mock := &MockTokenWriter{} mock.Mock.Test(t) diff --git a/agent/grpc-external/services/acl/mock_Validator.go b/agent/grpc-external/services/acl/mock_Validator.go index 3c27ec38baf9..3436762d2486 100644 --- a/agent/grpc-external/services/acl/mock_Validator.go +++ b/agent/grpc-external/services/acl/mock_Validator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.12.0. DO NOT EDIT. +// Code generated by mockery v2.15.0. DO NOT EDIT. package acl @@ -8,8 +8,6 @@ import ( authmethod "github.com/hashicorp/consul/agent/consul/authmethod" mock "github.com/stretchr/testify/mock" - - testing "testing" ) // MockValidator is an autogenerated mock type for the Validator type @@ -40,8 +38,13 @@ func (_m *MockValidator) ValidateLogin(ctx context.Context, loginToken string) ( return r0, r1 } -// NewMockValidator creates a new instance of MockValidator. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockValidator(t testing.TB) *MockValidator { +type mockConstructorTestingTNewMockValidator interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockValidator creates a new instance of MockValidator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockValidator(t mockConstructorTestingTNewMockValidator) *MockValidator { mock := &MockValidator{} mock.Mock.Test(t) diff --git a/agent/grpc-external/services/connectca/mock_ACLResolver.go b/agent/grpc-external/services/connectca/mock_ACLResolver.go index 24fb26a22590..9c2f2cac2c9d 100644 --- a/agent/grpc-external/services/connectca/mock_ACLResolver.go +++ b/agent/grpc-external/services/connectca/mock_ACLResolver.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.12.0. DO NOT EDIT. +// Code generated by mockery v2.15.0. DO NOT EDIT. package connectca @@ -7,8 +7,6 @@ import ( mock "github.com/stretchr/testify/mock" resolver "github.com/hashicorp/consul/acl/resolver" - - testing "testing" ) // MockACLResolver is an autogenerated mock type for the ACLResolver type @@ -37,8 +35,13 @@ func (_m *MockACLResolver) ResolveTokenAndDefaultMeta(token string, entMeta *acl return r0, r1 } -// NewMockACLResolver creates a new instance of MockACLResolver. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockACLResolver(t testing.TB) *MockACLResolver { +type mockConstructorTestingTNewMockACLResolver interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockACLResolver creates a new instance of MockACLResolver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockACLResolver(t mockConstructorTestingTNewMockACLResolver) *MockACLResolver { mock := &MockACLResolver{} mock.Mock.Test(t) diff --git a/agent/grpc-external/services/connectca/mock_CAManager.go b/agent/grpc-external/services/connectca/mock_CAManager.go index 2667692c3303..296186bbe5ad 100644 --- a/agent/grpc-external/services/connectca/mock_CAManager.go +++ b/agent/grpc-external/services/connectca/mock_CAManager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.12.0. DO NOT EDIT. +// Code generated by mockery v2.15.0. DO NOT EDIT. package connectca @@ -8,8 +8,6 @@ import ( structs "github.com/hashicorp/consul/agent/structs" - testing "testing" - x509 "crypto/x509" ) @@ -41,8 +39,13 @@ func (_m *MockCAManager) AuthorizeAndSignCertificate(csr *x509.CertificateReques return r0, r1 } -// NewMockCAManager creates a new instance of MockCAManager. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockCAManager(t testing.TB) *MockCAManager { +type mockConstructorTestingTNewMockCAManager interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockCAManager creates a new instance of MockCAManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockCAManager(t mockConstructorTestingTNewMockCAManager) *MockCAManager { mock := &MockCAManager{} mock.Mock.Test(t) diff --git a/agent/grpc-external/services/connectca/server_test.go b/agent/grpc-external/services/connectca/server_test.go index 824883fbd621..1026860ae342 100644 --- a/agent/grpc-external/services/connectca/server_test.go +++ b/agent/grpc-external/services/connectca/server_test.go @@ -10,7 +10,7 @@ import ( "github.com/hashicorp/consul/agent/consul/state" "github.com/hashicorp/consul/agent/consul/stream" "github.com/hashicorp/consul/agent/grpc-external/testutils" - structs "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/proto-public/pbconnectca" ) @@ -39,6 +39,7 @@ func testClient(t *testing.T, server *Server) pbconnectca.ConnectCAServiceClient addr := testutils.RunTestServer(t, server) + //nolint:staticcheck conn, err := grpc.DialContext(context.Background(), addr.String(), grpc.WithInsecure()) require.NoError(t, err) t.Cleanup(func() { diff --git a/agent/grpc-external/services/connectca/sign_test.go b/agent/grpc-external/services/connectca/sign_test.go index 6bba0c197e5c..5aa1f114b389 100644 --- a/agent/grpc-external/services/connectca/sign_test.go +++ b/agent/grpc-external/services/connectca/sign_test.go @@ -13,8 +13,8 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - acl "github.com/hashicorp/consul/acl" - resolver "github.com/hashicorp/consul/acl/resolver" + "github.com/hashicorp/consul/acl" + "github.com/hashicorp/consul/acl/resolver" "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/grpc-external/testutils" "github.com/hashicorp/consul/agent/structs" @@ -33,7 +33,7 @@ func TestSign_ConnectDisabled(t *testing.T) { func TestSign_Validation(t *testing.T) { aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", mock.Anything, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerAllowAll(t), nil) + Return(testutils.ACLsDisabled(t), nil) server := NewServer(Config{ Logger: hclog.NewNullLogger(), @@ -90,7 +90,7 @@ func TestSign_Unauthenticated(t *testing.T) { func TestSign_PermissionDenied(t *testing.T) { aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", mock.Anything, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerAllowAll(t), nil) + Return(testutils.ACLsDisabled(t), nil) caManager := &MockCAManager{} caManager.On("AuthorizeAndSignCertificate", mock.Anything, mock.Anything). @@ -116,7 +116,7 @@ func TestSign_PermissionDenied(t *testing.T) { func TestSign_InvalidCSR(t *testing.T) { aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", mock.Anything, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerAllowAll(t), nil) + Return(testutils.ACLsDisabled(t), nil) caManager := &MockCAManager{} caManager.On("AuthorizeAndSignCertificate", mock.Anything, mock.Anything). @@ -142,7 +142,7 @@ func TestSign_InvalidCSR(t *testing.T) { func TestSign_RateLimited(t *testing.T) { aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", mock.Anything, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerAllowAll(t), nil) + Return(testutils.ACLsDisabled(t), nil) caManager := &MockCAManager{} caManager.On("AuthorizeAndSignCertificate", mock.Anything, mock.Anything). @@ -168,7 +168,7 @@ func TestSign_RateLimited(t *testing.T) { func TestSign_InternalError(t *testing.T) { aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", mock.Anything, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerAllowAll(t), nil) + Return(testutils.ACLsDisabled(t), nil) caManager := &MockCAManager{} caManager.On("AuthorizeAndSignCertificate", mock.Anything, mock.Anything). @@ -194,7 +194,7 @@ func TestSign_InternalError(t *testing.T) { func TestSign_Success(t *testing.T) { aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", mock.Anything, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerAllowAll(t), nil) + Return(testutils.ACLsDisabled(t), nil) caManager := &MockCAManager{} caManager.On("AuthorizeAndSignCertificate", mock.Anything, mock.Anything). @@ -220,7 +220,7 @@ func TestSign_Success(t *testing.T) { func TestSign_RPCForwarding(t *testing.T) { aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", mock.Anything, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerAllowAll(t), nil) + Return(testutils.ACLsDisabled(t), nil) caManager := &MockCAManager{} caManager.On("AuthorizeAndSignCertificate", mock.Anything, mock.Anything). @@ -233,6 +233,7 @@ func TestSign_RPCForwarding(t *testing.T) { ForwardRPC: noopForwardRPC, ConnectEnabled: true, }) + //nolint:staticcheck leaderConn, err := grpc.Dial(testutils.RunTestServer(t, leader).String(), grpc.WithInsecure()) require.NoError(t, err) diff --git a/agent/grpc-external/services/connectca/watch_roots.go b/agent/grpc-external/services/connectca/watch_roots.go index b2ee9f4914fc..09dfd95720c8 100644 --- a/agent/grpc-external/services/connectca/watch_roots.go +++ b/agent/grpc-external/services/connectca/watch_roots.go @@ -58,7 +58,7 @@ func (s *Server) serveRoots( serverStream pbconnectca.ConnectCAService_WatchRootsServer, logger hclog.Logger, ) (uint64, error) { - if err := s.authorize(token); err != nil { + if err := external.RequireAnyValidACLToken(s.ACLResolver, token); err != nil { return 0, err } diff --git a/agent/grpc-external/services/connectca/watch_roots_test.go b/agent/grpc-external/services/connectca/watch_roots_test.go index f5c65a6201f0..1f7b8e89683c 100644 --- a/agent/grpc-external/services/connectca/watch_roots_test.go +++ b/agent/grpc-external/services/connectca/watch_roots_test.go @@ -54,7 +54,7 @@ func TestWatchRoots_Success(t *testing.T) { // Mock the ACL Resolver to return an authorizer with `service:write`. aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", testACLToken, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerServiceWriteAny(t), nil) + Return(testutils.ACLNoPermissions(t), nil) options := structs.QueryOptions{Token: testACLToken} ctx, err := external.ContextWithQueryOptions(context.Background(), options) @@ -144,7 +144,7 @@ func TestWatchRoots_ACLTokenInvalidated(t *testing.T) { // first two times it is called (initial connect and first re-auth). aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", testACLToken, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerServiceWriteAny(t), nil).Twice() + Return(testutils.ACLNoPermissions(t), nil).Twice() options := structs.QueryOptions{Token: testACLToken} ctx, err := external.ContextWithQueryOptions(context.Background(), options) @@ -184,9 +184,9 @@ func TestWatchRoots_ACLTokenInvalidated(t *testing.T) { // Expect the stream to remain open and to receive the new roots. mustGetRoots(t, rspCh) - // Simulate removing the `service:write` permission. + // Simulate deleting the ACL token. aclResolver.On("ResolveTokenAndDefaultMeta", testACLToken, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerDenyAll(t), nil) + Return(resolver.Result{}, acl.ErrNotFound) // Update the ACL token to cause the subscription to be force-closed. err = fsm.GetStore().ACLTokenSet(1, &structs.ACLToken{ @@ -197,7 +197,7 @@ func TestWatchRoots_ACLTokenInvalidated(t *testing.T) { // Expect the stream to be terminated. err = mustGetError(t, rspCh) - require.Equal(t, codes.PermissionDenied.String(), status.Code(err).String()) + require.Equal(t, codes.Unauthenticated.String(), status.Code(err).String()) } func TestWatchRoots_StateStoreAbandoned(t *testing.T) { @@ -214,7 +214,7 @@ func TestWatchRoots_StateStoreAbandoned(t *testing.T) { // Mock the ACL Resolver to return an authorizer with `service:write`. aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", testACLToken, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerServiceWriteAny(t), nil) + Return(testutils.ACLNoPermissions(t), nil) options := structs.QueryOptions{Token: testACLToken} ctx, err := external.ContextWithQueryOptions(context.Background(), options) diff --git a/agent/grpc-external/services/dataplane/get_envoy_bootstrap_params_test.go b/agent/grpc-external/services/dataplane/get_envoy_bootstrap_params_test.go index 55aeca0e3875..a96ef9254ab4 100644 --- a/agent/grpc-external/services/dataplane/get_envoy_bootstrap_params_test.go +++ b/agent/grpc-external/services/dataplane/get_envoy_bootstrap_params_test.go @@ -126,7 +126,7 @@ func TestGetEnvoyBootstrapParams_Success(t *testing.T) { aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", testToken, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerServiceRead(t, tc.registerReq.Service.ID), nil) + Return(testutils.ACLServiceRead(t, tc.registerReq.Service.ID), nil) options := structs.QueryOptions{Token: testToken} ctx, err := external.ContextWithQueryOptions(context.Background(), options) @@ -233,7 +233,7 @@ func TestGetEnvoyBootstrapParams_Error(t *testing.T) { aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", testToken, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerServiceRead(t, proxyServiceID), nil) + Return(testutils.ACLServiceRead(t, proxyServiceID), nil) options := structs.QueryOptions{Token: testToken} ctx, err := external.ContextWithQueryOptions(context.Background(), options) @@ -329,7 +329,7 @@ func TestGetEnvoyBootstrapParams_PermissionDenied(t *testing.T) { // Mock the ACL resolver to return a deny all authorizer aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", testToken, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerDenyAll(t), nil) + Return(testutils.ACLNoPermissions(t), nil) options := structs.QueryOptions{Token: testToken} ctx, err := external.ContextWithQueryOptions(context.Background(), options) diff --git a/agent/grpc-external/services/dataplane/get_supported_features.go b/agent/grpc-external/services/dataplane/get_supported_features.go index 4d3abc0eddf2..a37d381b2ce8 100644 --- a/agent/grpc-external/services/dataplane/get_supported_features.go +++ b/agent/grpc-external/services/dataplane/get_supported_features.go @@ -6,9 +6,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - acl "github.com/hashicorp/consul/acl" external "github.com/hashicorp/consul/agent/grpc-external" - structs "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/proto-public/pbdataplane" ) @@ -18,20 +16,12 @@ func (s *Server) GetSupportedDataplaneFeatures(ctx context.Context, req *pbdatap logger.Trace("Started processing request") defer logger.Trace("Finished processing request") - // Require the given ACL token to have `service:write` on any service options, err := external.QueryOptionsFromContext(ctx) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } - - var authzContext acl.AuthorizerContext - entMeta := structs.WildcardEnterpriseMetaInPartition(structs.WildcardSpecifier) - authz, err := s.ACLResolver.ResolveTokenAndDefaultMeta(options.Token, entMeta, &authzContext) - if err != nil { - return nil, status.Error(codes.Unauthenticated, err.Error()) - } - if err := authz.ToAllowAuthorizer().ServiceWriteAnyAllowed(&authzContext); err != nil { - return nil, status.Error(codes.PermissionDenied, err.Error()) + if err := external.RequireAnyValidACLToken(s.ACLResolver, options.Token); err != nil { + return nil, err } supportedFeatures := []*pbdataplane.DataplaneFeatureSupport{ diff --git a/agent/grpc-external/services/dataplane/get_supported_features_test.go b/agent/grpc-external/services/dataplane/get_supported_features_test.go index 52ff3f30a593..86fcdb0c8892 100644 --- a/agent/grpc-external/services/dataplane/get_supported_features_test.go +++ b/agent/grpc-external/services/dataplane/get_supported_features_test.go @@ -24,7 +24,7 @@ func TestSupportedDataplaneFeatures_Success(t *testing.T) { // Mock the ACL Resolver to return an authorizer with `service:write`. aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", testACLToken, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerServiceWriteAny(t), nil) + Return(testutils.ACLServiceWriteAny(t), nil) options := structs.QueryOptions{Token: testACLToken} ctx, err := external.ContextWithQueryOptions(context.Background(), options) @@ -53,7 +53,26 @@ func TestSupportedDataplaneFeatures_Success(t *testing.T) { } } -func TestSupportedDataplaneFeatures_Unauthenticated(t *testing.T) { +func TestSupportedDataplaneFeatures_ACLsDisabled(t *testing.T) { + aclResolver := &MockACLResolver{} + aclResolver.On("ResolveTokenAndDefaultMeta", "", mock.Anything, mock.Anything). + Return(testutils.ACLsDisabled(t), nil) + + options := structs.QueryOptions{Token: ""} + ctx, err := external.ContextWithQueryOptions(context.Background(), options) + require.NoError(t, err) + + server := NewServer(Config{ + Logger: hclog.NewNullLogger(), + ACLResolver: aclResolver, + }) + client := testClient(t, server) + resp, err := client.GetSupportedDataplaneFeatures(ctx, &pbdataplane.GetSupportedDataplaneFeaturesRequest{}) + require.NoError(t, err) + require.Equal(t, 3, len(resp.SupportedDataplaneFeatures)) +} + +func TestSupportedDataplaneFeatures_InvalidACLToken(t *testing.T) { // Mock the ACL resolver to return ErrNotFound. aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", mock.Anything, mock.Anything, mock.Anything). @@ -74,11 +93,11 @@ func TestSupportedDataplaneFeatures_Unauthenticated(t *testing.T) { require.Nil(t, resp) } -func TestSupportedDataplaneFeatures_PermissionDenied(t *testing.T) { - // Mock the ACL resolver to return a deny all authorizer +func TestSupportedDataplaneFeatures_AnonymousACLToken(t *testing.T) { + // Mock the ACL resolver to return ErrNotFound. aclResolver := &MockACLResolver{} - aclResolver.On("ResolveTokenAndDefaultMeta", testACLToken, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerDenyAll(t), nil) + aclResolver.On("ResolveTokenAndDefaultMeta", mock.Anything, mock.Anything, mock.Anything). + Return(testutils.ACLAnonymous(t), nil) options := structs.QueryOptions{Token: testACLToken} ctx, err := external.ContextWithQueryOptions(context.Background(), options) @@ -91,6 +110,25 @@ func TestSupportedDataplaneFeatures_PermissionDenied(t *testing.T) { client := testClient(t, server) resp, err := client.GetSupportedDataplaneFeatures(ctx, &pbdataplane.GetSupportedDataplaneFeaturesRequest{}) require.Error(t, err) - require.Equal(t, codes.PermissionDenied.String(), status.Code(err).String()) + require.Equal(t, codes.Unauthenticated.String(), status.Code(err).String()) require.Nil(t, resp) } + +func TestSupportedDataplaneFeatures_NoPermissions(t *testing.T) { + // Mock the ACL resolver to return a deny all authorizer + aclResolver := &MockACLResolver{} + aclResolver.On("ResolveTokenAndDefaultMeta", testACLToken, mock.Anything, mock.Anything). + Return(testutils.ACLNoPermissions(t), nil) + + options := structs.QueryOptions{Token: testACLToken} + ctx, err := external.ContextWithQueryOptions(context.Background(), options) + require.NoError(t, err) + + server := NewServer(Config{ + Logger: hclog.NewNullLogger(), + ACLResolver: aclResolver, + }) + client := testClient(t, server) + _, err = client.GetSupportedDataplaneFeatures(ctx, &pbdataplane.GetSupportedDataplaneFeaturesRequest{}) + require.NoError(t, err) +} diff --git a/agent/grpc-external/services/dataplane/mock_ACLResolver.go b/agent/grpc-external/services/dataplane/mock_ACLResolver.go index 0408d3a50c4e..781811624058 100644 --- a/agent/grpc-external/services/dataplane/mock_ACLResolver.go +++ b/agent/grpc-external/services/dataplane/mock_ACLResolver.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.12.0. DO NOT EDIT. +// Code generated by mockery v2.15.0. DO NOT EDIT. package dataplane @@ -7,8 +7,6 @@ import ( mock "github.com/stretchr/testify/mock" resolver "github.com/hashicorp/consul/acl/resolver" - - testing "testing" ) // MockACLResolver is an autogenerated mock type for the ACLResolver type @@ -37,8 +35,13 @@ func (_m *MockACLResolver) ResolveTokenAndDefaultMeta(_a0 string, _a1 *acl.Enter return r0, r1 } -// NewMockACLResolver creates a new instance of MockACLResolver. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockACLResolver(t testing.TB) *MockACLResolver { +type mockConstructorTestingTNewMockACLResolver interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockACLResolver creates a new instance of MockACLResolver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockACLResolver(t mockConstructorTestingTNewMockACLResolver) *MockACLResolver { mock := &MockACLResolver{} mock.Mock.Test(t) diff --git a/agent/grpc-external/services/dataplane/server_test.go b/agent/grpc-external/services/dataplane/server_test.go index 5ca346a6e18e..ece296afd62f 100644 --- a/agent/grpc-external/services/dataplane/server_test.go +++ b/agent/grpc-external/services/dataplane/server_test.go @@ -4,10 +4,11 @@ import ( "context" "testing" - "github.com/hashicorp/consul/agent/grpc-external/testutils" - "github.com/hashicorp/consul/proto-public/pbdataplane" "github.com/stretchr/testify/require" "google.golang.org/grpc" + + "github.com/hashicorp/consul/agent/grpc-external/testutils" + "github.com/hashicorp/consul/proto-public/pbdataplane" ) func testClient(t *testing.T, server *Server) pbdataplane.DataplaneServiceClient { @@ -15,6 +16,7 @@ func testClient(t *testing.T, server *Server) pbdataplane.DataplaneServiceClient addr := testutils.RunTestServer(t, server) + //nolint:staticcheck conn, err := grpc.DialContext(context.Background(), addr.String(), grpc.WithInsecure()) require.NoError(t, err) t.Cleanup(func() { diff --git a/agent/grpc-external/services/dns/server_test.go b/agent/grpc-external/services/dns/server_test.go index b477fed49861..dd27097097ff 100644 --- a/agent/grpc-external/services/dns/server_test.go +++ b/agent/grpc-external/services/dns/server_test.go @@ -35,6 +35,7 @@ func testClient(t *testing.T, server *Server) pbdns.DNSServiceClient { addr := testutils.RunTestServer(t, server) + //nolint:staticcheck conn, err := grpc.DialContext(context.Background(), addr.String(), grpc.WithInsecure()) require.NoError(t, err) t.Cleanup(func() { diff --git a/agent/grpc-external/services/peerstream/mock_ACLResolver.go b/agent/grpc-external/services/peerstream/mock_ACLResolver.go index d0e6720887c5..e4027a5da504 100644 --- a/agent/grpc-external/services/peerstream/mock_ACLResolver.go +++ b/agent/grpc-external/services/peerstream/mock_ACLResolver.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.12.2. DO NOT EDIT. +// Code generated by mockery v2.15.0. DO NOT EDIT. package peerstream @@ -7,8 +7,6 @@ import ( mock "github.com/stretchr/testify/mock" resolver "github.com/hashicorp/consul/acl/resolver" - - testing "testing" ) // MockACLResolver is an autogenerated mock type for the ACLResolver type @@ -37,8 +35,13 @@ func (_m *MockACLResolver) ResolveTokenAndDefaultMeta(_a0 string, _a1 *acl.Enter return r0, r1 } -// NewMockACLResolver creates a new instance of MockACLResolver. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockACLResolver(t testing.TB) *MockACLResolver { +type mockConstructorTestingTNewMockACLResolver interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockACLResolver creates a new instance of MockACLResolver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockACLResolver(t mockConstructorTestingTNewMockACLResolver) *MockACLResolver { mock := &MockACLResolver{} mock.Mock.Test(t) diff --git a/agent/grpc-external/services/peerstream/replication.go b/agent/grpc-external/services/peerstream/replication.go index 2a62f74a6efc..d5a0084e2cf2 100644 --- a/agent/grpc-external/services/peerstream/replication.go +++ b/agent/grpc-external/services/peerstream/replication.go @@ -10,6 +10,7 @@ import ( newproto "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" + "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/cache" "github.com/hashicorp/consul/agent/consul/state" "github.com/hashicorp/consul/agent/structs" @@ -63,10 +64,7 @@ func makeExportedServiceListResponse( // makeServiceResponse handles preparing exported service instance updates to the peer cluster. // Each cache.UpdateEvent will contain all instances for a service name. // If there are no instances in the event, we consider that to be a de-registration. -func makeServiceResponse( - mst *MutableStatus, - update cache.UpdateEvent, -) (*pbpeerstream.ReplicationMessage_Response, error) { +func makeServiceResponse(update cache.UpdateEvent) (*pbpeerstream.ReplicationMessage_Response, error) { serviceName := strings.TrimPrefix(update.CorrelationID, subExportedService) csn, ok := update.Result.(*pbservice.IndexedCheckServiceNodes) if !ok { @@ -284,13 +282,14 @@ func (s *Server) handleUpsertExportedServiceList( exportedServices[snSidecarProxy] = struct{}{} serviceNames = append(serviceNames, sn) } - entMeta := structs.NodeEnterpriseMetaInPartition(partition) - _, serviceList, err := s.GetStore().ServiceList(nil, entMeta, peerName) + // Ensure we query services from all namespaces in this partition when we perform + // this query or else we may not propagate updates / deletes correctly. + entMeta := acl.NewEnterpriseMetaWithPartition(partition, acl.WildcardName) + _, serviceList, err := s.GetStore().ServiceList(nil, &entMeta, peerName) if err != nil { return err } - for _, sn := range serviceList { if _, ok := exportedServices[sn]; !ok { err := s.handleUpdateService(peerName, partition, sn, nil) @@ -327,9 +326,12 @@ func (s *Server) handleUpdateService( return fmt.Errorf("failed to read imported services: %w", err) } - structsNodes, err := export.CheckServiceNodesToStruct() - if err != nil { - return fmt.Errorf("failed to convert protobuf instances to structs: %w", err) + structsNodes := []structs.CheckServiceNode{} + if export != nil { + structsNodes, err = export.CheckServiceNodesToStruct() + if err != nil { + return fmt.Errorf("failed to convert protobuf instances to structs: %w", err) + } } // Normalize the data into a convenient form for operation. @@ -339,7 +341,7 @@ func (s *Server) handleUpdateService( for _, nodeSnap := range snap.Nodes { // First register the node - skip the unchanged ones changed := true - if storedNode, ok := storedNodesMap[nodeSnap.Node.ID]; ok { + if storedNode, ok := storedNodesMap[nodeSnap.Node.Node]; ok { if storedNode.IsSame(nodeSnap.Node) { changed = false } @@ -355,7 +357,7 @@ func (s *Server) handleUpdateService( // Then register all services on that node - skip the unchanged ones for _, svcSnap := range nodeSnap.Services { changed = true - if storedSvcInst, ok := storedSvcInstMap[makeNodeSvcInstID(nodeSnap.Node.ID, svcSnap.Service.ID)]; ok { + if storedSvcInst, ok := storedSvcInstMap[makeNodeSvcInstID(nodeSnap.Node.Node, svcSnap.Service.ID)]; ok { if storedSvcInst.IsSame(svcSnap.Service) { changed = false } @@ -375,7 +377,7 @@ func (s *Server) handleUpdateService( for _, svcSnap := range nodeSnap.Services { for _, c := range svcSnap.Checks { changed := true - if chk, ok := storedChecksMap[makeNodeCheckID(nodeSnap.Node.ID, svcSnap.Service.ID, c.CheckID)]; ok { + if chk, ok := storedChecksMap[makeNodeCheckID(nodeSnap.Node.Node, svcSnap.Service.ID, c.CheckID)]; ok { if chk.IsSame(c) { changed = false } @@ -513,8 +515,10 @@ func (s *Server) handleUpdateService( // Delete any nodes that do not have any other services registered on them. for node := range unusedNodes { - nodeMeta := structs.NodeEnterpriseMetaInPartition(sn.PartitionOrDefault()) - _, ns, err := s.GetStore().NodeServices(nil, node, nodeMeta, peerName) + // The wildcard is used here so that all services, regardless of namespace are returned + // by the following query. Without this, the node might accidentally be cleaned up early. + wildcardNSMeta := acl.NewEnterpriseMetaWithPartition(sn.PartitionOrDefault(), acl.WildcardName) + _, ns, err := s.GetStore().NodeServiceList(nil, node, &wildcardNSMeta, peerName) if err != nil { return fmt.Errorf("failed to query services on node: %w", err) } @@ -527,10 +531,10 @@ func (s *Server) handleUpdateService( err = s.Backend.CatalogDeregister(&structs.DeregisterRequest{ Node: node, PeerName: peerName, - EnterpriseMeta: *nodeMeta, + EnterpriseMeta: *structs.NodeEnterpriseMetaInPartition(sn.PartitionOrDefault()), }) if err != nil { - ident := fmt.Sprintf("partition:%s/peer:%s/node:%s", nodeMeta.PartitionOrDefault(), peerName, node) + ident := fmt.Sprintf("partition:%s/peer:%s/node:%s", sn.PartitionOrDefault(), peerName, node) return fmt.Errorf("failed to deregister node %q: %w", ident, err) } } @@ -633,31 +637,35 @@ type nodeCheckIdentity struct { checkID string } -func makeNodeSvcInstID(nodeID types.NodeID, serviceID string) nodeSvcInstIdentity { +func makeNodeSvcInstID(node string, serviceID string) nodeSvcInstIdentity { return nodeSvcInstIdentity{ - nodeID: string(nodeID), + nodeID: node, serviceID: serviceID, } } -func makeNodeCheckID(nodeID types.NodeID, serviceID string, checkID types.CheckID) nodeCheckIdentity { +func makeNodeCheckID(node string, serviceID string, checkID types.CheckID) nodeCheckIdentity { return nodeCheckIdentity{ serviceID: serviceID, checkID: string(checkID), - nodeID: string(nodeID), + nodeID: node, } } -func buildStoredMap(storedInstances structs.CheckServiceNodes) (map[types.NodeID]*structs.Node, map[nodeSvcInstIdentity]*structs.NodeService, map[nodeCheckIdentity]*structs.HealthCheck) { - nodesMap := map[types.NodeID]*structs.Node{} +func buildStoredMap(storedInstances structs.CheckServiceNodes) ( + map[string]*structs.Node, + map[nodeSvcInstIdentity]*structs.NodeService, + map[nodeCheckIdentity]*structs.HealthCheck, +) { + nodesMap := map[string]*structs.Node{} svcInstMap := map[nodeSvcInstIdentity]*structs.NodeService{} checksMap := map[nodeCheckIdentity]*structs.HealthCheck{} for _, csn := range storedInstances { - nodesMap[csn.Node.ID] = csn.Node - svcInstMap[makeNodeSvcInstID(csn.Node.ID, csn.Service.ID)] = csn.Service + nodesMap[csn.Node.Node] = csn.Node + svcInstMap[makeNodeSvcInstID(csn.Node.Node, csn.Service.ID)] = csn.Service for _, chk := range csn.Checks { - checksMap[makeNodeCheckID(csn.Node.ID, csn.Service.ID, chk.CheckID)] = chk + checksMap[makeNodeCheckID(csn.Node.Node, csn.Service.ID, chk.CheckID)] = chk } } return nodesMap, svcInstMap, checksMap diff --git a/agent/grpc-external/services/peerstream/server.go b/agent/grpc-external/services/peerstream/server.go index 8a5e33e93c5e..a67da563a039 100644 --- a/agent/grpc-external/services/peerstream/server.go +++ b/agent/grpc-external/services/peerstream/server.go @@ -119,7 +119,7 @@ type StateStore interface { ExportedServicesForPeer(ws memdb.WatchSet, peerID, dc string) (uint64, *structs.ExportedServiceList, error) ServiceDump(ws memdb.WatchSet, kind structs.ServiceKind, useKind bool, entMeta *acl.EnterpriseMeta, peerName string) (uint64, structs.CheckServiceNodes, error) CheckServiceNodes(ws memdb.WatchSet, serviceName string, entMeta *acl.EnterpriseMeta, peerName string) (uint64, structs.CheckServiceNodes, error) - NodeServices(ws memdb.WatchSet, nodeNameOrID string, entMeta *acl.EnterpriseMeta, peerName string) (uint64, *structs.NodeServices, error) + NodeServiceList(ws memdb.WatchSet, nodeNameOrID string, entMeta *acl.EnterpriseMeta, peerName string) (uint64, *structs.NodeServiceList, error) CAConfig(ws memdb.WatchSet) (uint64, *structs.CAConfiguration, error) TrustBundleListByService(ws memdb.WatchSet, service, dc string, entMeta acl.EnterpriseMeta) (uint64, []*pbpeering.PeeringTrustBundle, error) ServiceList(ws memdb.WatchSet, entMeta *acl.EnterpriseMeta, peerName string) (uint64, structs.ServiceList, error) diff --git a/agent/grpc-external/services/peerstream/stream_resources.go b/agent/grpc-external/services/peerstream/stream_resources.go index bf9d1b791a8d..d0f7c7470d56 100644 --- a/agent/grpc-external/services/peerstream/stream_resources.go +++ b/agent/grpc-external/services/peerstream/stream_resources.go @@ -277,7 +277,7 @@ type HandleStreamRequest struct { Stream BidirectionalStream } -func (r HandleStreamRequest) WasDialed() bool { +func (r HandleStreamRequest) IsAcceptor() bool { return r.RemoteID == "" } @@ -316,7 +316,7 @@ func (s *Server) realHandleStream(streamReq HandleStreamRequest) error { logger := s.Logger.Named("stream"). With("peer_name", streamReq.PeerName). With("peer_id", streamReq.LocalID). - With("dialed", streamReq.WasDialed()) + With("dailer", !streamReq.IsAcceptor()) logger.Trace("handling stream for peer") // handleStreamCtx is local to this function. @@ -380,13 +380,18 @@ func (s *Server) realHandleStream(streamReq HandleStreamRequest) error { return err } - // Subscribe to all relevant resource types. - for _, resourceURL := range []string{ + resources := []string{ pbpeerstream.TypeURLExportedService, pbpeerstream.TypeURLExportedServiceList, pbpeerstream.TypeURLPeeringTrustBundle, - pbpeerstream.TypeURLPeeringServerAddresses, - } { + } + // Acceptors should not subscribe to server address updates, because they should always have an empty list. + if !streamReq.IsAcceptor() { + resources = append(resources, pbpeerstream.TypeURLPeeringServerAddresses) + } + + // Subscribe to all relevant resource types. + for _, resourceURL := range resources { sub := makeReplicationRequest(&pbpeerstream.ReplicationMessage_Request{ ResourceURL: resourceURL, PeerID: streamReq.RemoteID, @@ -558,7 +563,7 @@ func (s *Server) realHandleStream(streamReq HandleStreamRequest) error { // This must be a new subscription request to add a new // resource type, vet it like a new request. - if !streamReq.WasDialed() { + if !streamReq.IsAcceptor() { if req.PeerID != "" && req.PeerID != streamReq.RemoteID { // Not necessary after the first request from the dialer, // but if provided must match. @@ -658,7 +663,7 @@ func (s *Server) realHandleStream(streamReq HandleStreamRequest) error { continue } case strings.HasPrefix(update.CorrelationID, subExportedService): - resp, err = makeServiceResponse(status, update) + resp, err = makeServiceResponse(update) if err != nil { // Log the error and skip this response to avoid locking up peering due to a bad update event. logger.Error("failed to create service response", "error", err) diff --git a/agent/grpc-external/services/peerstream/stream_test.go b/agent/grpc-external/services/peerstream/stream_test.go index 4674e34b37f4..3927fb19b50e 100644 --- a/agent/grpc-external/services/peerstream/stream_test.go +++ b/agent/grpc-external/services/peerstream/stream_test.go @@ -125,7 +125,7 @@ func TestStreamResources_Server_LeaderBecomesFollower(t *testing.T) { // Receive a subscription from a peer. This message arrives while the // server is a leader and should work. - testutil.RunStep(t, "send subscription request to leader and consume its four requests", func(t *testing.T) { + testutil.RunStep(t, "send subscription request to leader and consume its three requests", func(t *testing.T) { sub := &pbpeerstream.ReplicationMessage{ Payload: &pbpeerstream.ReplicationMessage_Open_{ Open: &pbpeerstream.ReplicationMessage_Open{ @@ -148,10 +148,6 @@ func TestStreamResources_Server_LeaderBecomesFollower(t *testing.T) { msg3, err := client.Recv() require.NoError(t, err) require.NotEmpty(t, msg3) - - msg4, err := client.Recv() - require.NoError(t, err) - require.NotEmpty(t, msg4) }) // The ACK will be a new request but at this point the server is not the @@ -551,6 +547,7 @@ func TestStreamResources_Server_StreamTracker(t *testing.T) { it := incrementalTime{ base: time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC), } + waitUntil := it.FutureNow(7) srv, store := newTestServer(t, nil) srv.Tracker.setClock(it.Now) @@ -576,6 +573,11 @@ func TestStreamResources_Server_StreamTracker(t *testing.T) { client.DrainStream(t) + // Wait for async workflows to complete. + retry.Run(t, func(r *retry.R) { + require.Equal(r, waitUntil, it.FutureNow(1)) + }) + // Manually grab the last success time from sending the trust bundle or exported services list. status, ok := srv.StreamStatus(testPeerID) require.True(t, ok) @@ -605,7 +607,6 @@ func TestStreamResources_Server_StreamTracker(t *testing.T) { LastAck: lastSendAck, ExportedServices: []string{}, } - retry.Run(t, func(r *retry.R) { rStatus, ok := srv.StreamStatus(testPeerID) require.True(r, ok) @@ -843,6 +844,13 @@ func TestStreamResources_Server_ServiceUpdates(t *testing.T) { Node: &structs.Node{Node: "foo", Address: "10.0.0.1"}, Service: &structs.NodeService{ID: "mysql-1", Service: "mysql", Port: 5000}, } + mysqlSidecar := &structs.NodeService{ + Kind: structs.ServiceKindConnectProxy, + Service: "mysql-sidecar-proxy", + Proxy: structs.ConnectProxyConfig{ + DestinationServiceName: "mysql", + }, + } lastIdx++ require.NoError(t, store.EnsureNode(lastIdx, mysql.Node)) @@ -850,6 +858,9 @@ func TestStreamResources_Server_ServiceUpdates(t *testing.T) { lastIdx++ require.NoError(t, store.EnsureService(lastIdx, "foo", mysql.Service)) + lastIdx++ + require.NoError(t, store.EnsureService(lastIdx, "foo", mysqlSidecar)) + mongoSvcDefaults := &structs.ServiceConfigEntry{ Kind: structs.ServiceDefaults, Name: "mongo", @@ -869,6 +880,24 @@ func TestStreamResources_Server_ServiceUpdates(t *testing.T) { mysqlProxySN = structs.NewServiceName("mysql-sidecar-proxy", nil).String() ) + testutil.RunStep(t, "initial stream data is received", func(t *testing.T) { + expectReplEvents(t, client, + func(t *testing.T, msg *pbpeerstream.ReplicationMessage) { + require.Equal(t, pbpeerstream.TypeURLPeeringTrustBundle, msg.GetResponse().ResourceURL) + // Roots tested in TestStreamResources_Server_CARootUpdates + }, + func(t *testing.T, msg *pbpeerstream.ReplicationMessage) { + require.Equal(t, pbpeerstream.TypeURLExportedServiceList, msg.GetResponse().ResourceURL) + require.Equal(t, subExportedServiceList, msg.GetResponse().ResourceID) + require.Equal(t, pbpeerstream.Operation_OPERATION_UPSERT, msg.GetResponse().Operation) + + var exportedServices pbpeerstream.ExportedServiceList + require.NoError(t, msg.GetResponse().Resource.UnmarshalTo(&exportedServices)) + require.ElementsMatch(t, []string{}, exportedServices.Services) + }, + ) + }) + testutil.RunStep(t, "exporting mysql leads to an UPSERT event", func(t *testing.T) { entry := &structs.ExportedServicesConfigEntry{ Name: "default", @@ -894,13 +923,6 @@ func TestStreamResources_Server_ServiceUpdates(t *testing.T) { require.NoError(t, store.EnsureConfigEntry(lastIdx, entry)) expectReplEvents(t, client, - func(t *testing.T, msg *pbpeerstream.ReplicationMessage) { - require.Equal(t, pbpeerstream.TypeURLPeeringServerAddresses, msg.GetRequest().ResourceURL) - }, - func(t *testing.T, msg *pbpeerstream.ReplicationMessage) { - require.Equal(t, pbpeerstream.TypeURLPeeringTrustBundle, msg.GetResponse().ResourceURL) - // Roots tested in TestStreamResources_Server_CARootUpdates - }, func(t *testing.T, msg *pbpeerstream.ReplicationMessage) { // no mongo instances exist require.Equal(t, pbpeerstream.TypeURLExportedService, msg.GetResponse().ResourceURL) @@ -911,16 +933,6 @@ func TestStreamResources_Server_ServiceUpdates(t *testing.T) { require.NoError(t, msg.GetResponse().Resource.UnmarshalTo(&nodes)) require.Len(t, nodes.Nodes, 0) }, - func(t *testing.T, msg *pbpeerstream.ReplicationMessage) { - // proxies can't export because no mesh gateway exists yet - require.Equal(t, pbpeerstream.TypeURLExportedService, msg.GetResponse().ResourceURL) - require.Equal(t, mongoProxySN, msg.GetResponse().ResourceID) - require.Equal(t, pbpeerstream.Operation_OPERATION_UPSERT, msg.GetResponse().Operation) - - var nodes pbpeerstream.ExportedService - require.NoError(t, msg.GetResponse().Resource.UnmarshalTo(&nodes)) - require.Len(t, nodes.Nodes, 0) - }, func(t *testing.T, msg *pbpeerstream.ReplicationMessage) { require.Equal(t, pbpeerstream.TypeURLExportedService, msg.GetResponse().ResourceURL) require.Equal(t, mysqlSN, msg.GetResponse().ResourceID) @@ -940,17 +952,6 @@ func TestStreamResources_Server_ServiceUpdates(t *testing.T) { require.NoError(t, msg.GetResponse().Resource.UnmarshalTo(&nodes)) require.Len(t, nodes.Nodes, 0) }, - // This event happens because this is the first test case and there are - // no exported services when replication is initially set up. - func(t *testing.T, msg *pbpeerstream.ReplicationMessage) { - require.Equal(t, pbpeerstream.TypeURLExportedServiceList, msg.GetResponse().ResourceURL) - require.Equal(t, subExportedServiceList, msg.GetResponse().ResourceID) - require.Equal(t, pbpeerstream.Operation_OPERATION_UPSERT, msg.GetResponse().Operation) - - var exportedServices pbpeerstream.ExportedServiceList - require.NoError(t, msg.GetResponse().Resource.UnmarshalTo(&exportedServices)) - require.ElementsMatch(t, []string{}, exportedServices.Services) - }, func(t *testing.T, msg *pbpeerstream.ReplicationMessage) { require.Equal(t, pbpeerstream.TypeURLExportedServiceList, msg.GetResponse().ResourceURL) require.Equal(t, subExportedServiceList, msg.GetResponse().ResourceID) @@ -980,7 +981,7 @@ func TestStreamResources_Server_ServiceUpdates(t *testing.T) { expectReplEvents(t, client, func(t *testing.T, msg *pbpeerstream.ReplicationMessage) { require.Equal(t, pbpeerstream.TypeURLExportedService, msg.GetResponse().ResourceURL) - require.Equal(t, mongoProxySN, msg.GetResponse().ResourceID) + require.Equal(t, mysqlProxySN, msg.GetResponse().ResourceID) require.Equal(t, pbpeerstream.Operation_OPERATION_UPSERT, msg.GetResponse().Operation) var nodes pbpeerstream.ExportedService @@ -988,16 +989,26 @@ func TestStreamResources_Server_ServiceUpdates(t *testing.T) { require.Len(t, nodes.Nodes, 1) pm := nodes.Nodes[0].Service.Connect.PeerMeta - require.Equal(t, "grpc", pm.Protocol) + require.Equal(t, "tcp", pm.Protocol) spiffeIDs := []string{ - "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/mongo", + "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/mysql", "spiffe://11111111-2222-3333-4444-555555555555.consul/gateway/mesh/dc/dc1", } require.Equal(t, spiffeIDs, pm.SpiffeID) }, + ) + }) + + testutil.RunStep(t, "register service resolver to send proxy updates", func(t *testing.T) { + lastIdx++ + require.NoError(t, store.EnsureConfigEntry(lastIdx, &structs.ServiceResolverConfigEntry{ + Kind: structs.ServiceResolver, + Name: "mongo", + })) + expectReplEvents(t, client, func(t *testing.T, msg *pbpeerstream.ReplicationMessage) { require.Equal(t, pbpeerstream.TypeURLExportedService, msg.GetResponse().ResourceURL) - require.Equal(t, mysqlProxySN, msg.GetResponse().ResourceID) + require.Equal(t, mongoProxySN, msg.GetResponse().ResourceID) require.Equal(t, pbpeerstream.Operation_OPERATION_UPSERT, msg.GetResponse().Operation) var nodes pbpeerstream.ExportedService @@ -1005,9 +1016,9 @@ func TestStreamResources_Server_ServiceUpdates(t *testing.T) { require.Len(t, nodes.Nodes, 1) pm := nodes.Nodes[0].Service.Connect.PeerMeta - require.Equal(t, "tcp", pm.Protocol) + require.Equal(t, "grpc", pm.Protocol) spiffeIDs := []string{ - "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/mysql", + "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/mongo", "spiffe://11111111-2222-3333-4444-555555555555.consul/gateway/mesh/dc/dc1", } require.Equal(t, spiffeIDs, pm.SpiffeID) @@ -1034,7 +1045,7 @@ func TestStreamResources_Server_ServiceUpdates(t *testing.T) { require.Equal(r, mongo.Service.CompoundServiceName().String(), msg.GetResponse().ResourceID) var nodes pbpeerstream.ExportedService - require.NoError(t, msg.GetResponse().Resource.UnmarshalTo(&nodes)) + require.NoError(r, msg.GetResponse().Resource.UnmarshalTo(&nodes)) require.Len(r, nodes.Nodes, 1) }) }) @@ -1063,12 +1074,12 @@ func TestStreamResources_Server_ServiceUpdates(t *testing.T) { msg, err := client.RecvWithTimeout(100 * time.Millisecond) require.NoError(r, err) require.Equal(r, pbpeerstream.TypeURLExportedServiceList, msg.GetResponse().ResourceURL) - require.Equal(t, subExportedServiceList, msg.GetResponse().ResourceID) - require.Equal(t, pbpeerstream.Operation_OPERATION_UPSERT, msg.GetResponse().Operation) + require.Equal(r, subExportedServiceList, msg.GetResponse().ResourceID) + require.Equal(r, pbpeerstream.Operation_OPERATION_UPSERT, msg.GetResponse().Operation) var exportedServices pbpeerstream.ExportedServiceList - require.NoError(t, msg.GetResponse().Resource.UnmarshalTo(&exportedServices)) - require.Equal(t, []string{structs.ServiceName{Name: "mongo"}.String()}, exportedServices.Services) + require.NoError(r, msg.GetResponse().Resource.UnmarshalTo(&exportedServices)) + require.Equal(r, []string{structs.ServiceName{Name: "mongo"}.String()}, exportedServices.Services) }) }) @@ -1080,12 +1091,12 @@ func TestStreamResources_Server_ServiceUpdates(t *testing.T) { msg, err := client.RecvWithTimeout(100 * time.Millisecond) require.NoError(r, err) require.Equal(r, pbpeerstream.TypeURLExportedServiceList, msg.GetResponse().ResourceURL) - require.Equal(t, subExportedServiceList, msg.GetResponse().ResourceID) - require.Equal(t, pbpeerstream.Operation_OPERATION_UPSERT, msg.GetResponse().Operation) + require.Equal(r, subExportedServiceList, msg.GetResponse().ResourceID) + require.Equal(r, pbpeerstream.Operation_OPERATION_UPSERT, msg.GetResponse().Operation) var exportedServices pbpeerstream.ExportedServiceList - require.NoError(t, msg.GetResponse().Resource.UnmarshalTo(&exportedServices)) - require.Len(t, exportedServices.Services, 0) + require.NoError(r, msg.GetResponse().Resource.UnmarshalTo(&exportedServices)) + require.Len(r, exportedServices.Services, 0) }) }) } @@ -1105,9 +1116,6 @@ func TestStreamResources_Server_CARootUpdates(t *testing.T) { testutil.RunStep(t, "initial CA Roots replication", func(t *testing.T) { expectReplEvents(t, client, - func(t *testing.T, msg *pbpeerstream.ReplicationMessage) { - require.Equal(t, pbpeerstream.TypeURLPeeringServerAddresses, msg.GetRequest().ResourceURL) - }, func(t *testing.T, msg *pbpeerstream.ReplicationMessage) { require.Equal(t, pbpeerstream.TypeURLPeeringTrustBundle, msg.GetResponse().ResourceURL) require.Equal(t, "roots", msg.GetResponse().ResourceID) @@ -1164,7 +1172,7 @@ func TestStreamResources_Server_CARootUpdates(t *testing.T) { func TestStreamResources_Server_AckNackNonce(t *testing.T) { srv, store := newTestServer(t, func(c *Config) { - c.incomingHeartbeatTimeout = 50 * time.Millisecond + c.incomingHeartbeatTimeout = 10 * time.Millisecond }) p := writePeeringToBeDialed(t, store, 1, "my-peer") @@ -1209,6 +1217,9 @@ func TestStreamResources_Server_AckNackNonce(t *testing.T) { require.NoError(t, err) require.Equal(t, "5678", msg.GetRequest().ResponseNonce) }) + // Add in a sleep to prevent the test from flaking. + // The mock client expects certain calls to be made. + time.Sleep(50 * time.Millisecond) } // Test that when the client doesn't send a heartbeat in time, the stream is disconnected. @@ -1241,8 +1252,8 @@ func TestStreamResources_Server_DisconnectsOnHeartbeatTimeout(t *testing.T) { }) testutil.RunStep(t, "stream is disconnected due to heartbeat timeout", func(t *testing.T) { - disconnectTime := it.FutureNow(1) retry.Run(t, func(r *retry.R) { + disconnectTime := it.StaticNow() status, ok := srv.StreamStatus(testPeerID) require.True(r, ok) require.False(r, status.Connected) @@ -1310,7 +1321,7 @@ func TestStreamResources_Server_KeepsConnectionOpenWithHeartbeat(t *testing.T) { it := incrementalTime{ base: time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC), } - incomingHeartbeatTimeout := 10 * time.Millisecond + incomingHeartbeatTimeout := 50 * time.Millisecond srv, store := newTestServer(t, func(c *Config) { c.incomingHeartbeatTimeout = incomingHeartbeatTimeout @@ -1359,7 +1370,7 @@ func TestStreamResources_Server_KeepsConnectionOpenWithHeartbeat(t *testing.T) { return } select { - case <-time.After(incomingHeartbeatTimeout / 2): + case <-time.After(incomingHeartbeatTimeout / 10): // Going any slower here triggers flakes when running case <-ctx.Done(): close(errCh) return @@ -1428,7 +1439,9 @@ func makeClient(t *testing.T, srv *testServer, peerID string) *MockClient { // Note that server address may not come as an initial message for _, resourceURL := range []string{ pbpeerstream.TypeURLExportedService, + pbpeerstream.TypeURLExportedServiceList, pbpeerstream.TypeURLPeeringTrustBundle, + // only dialers request, which is why this is absent below pbpeerstream.TypeURLPeeringServerAddresses, } { init := &pbpeerstream.ReplicationMessage{ @@ -1457,7 +1470,7 @@ func makeClient(t *testing.T, srv *testServer, peerID string) *MockClient { { Payload: &pbpeerstream.ReplicationMessage_Request_{ Request: &pbpeerstream.ReplicationMessage_Request{ - ResourceURL: pbpeerstream.TypeURLPeeringTrustBundle, + ResourceURL: pbpeerstream.TypeURLExportedServiceList, // The PeerID field is only set for the messages coming FROM // the establishing side and are going to be empty from the // other side. @@ -1468,7 +1481,7 @@ func makeClient(t *testing.T, srv *testServer, peerID string) *MockClient { { Payload: &pbpeerstream.ReplicationMessage_Request_{ Request: &pbpeerstream.ReplicationMessage_Request{ - ResourceURL: pbpeerstream.TypeURLPeeringServerAddresses, + ResourceURL: pbpeerstream.TypeURLPeeringTrustBundle, // The PeerID field is only set for the messages coming FROM // the establishing side and are going to be empty from the // other side. @@ -1580,7 +1593,11 @@ func Test_ExportedServicesCount(t *testing.T) { mst, err := srv.Tracker.Connected(peerID) require.NoError(t, err) - services := []string{"web", "api", "mongo"} + services := []string{ + structs.NewServiceName("web", nil).String(), + structs.NewServiceName("api", nil).String(), + structs.NewServiceName("mongo", nil).String(), + } update := cache.UpdateEvent{ CorrelationID: subExportedServiceList, Result: &pbpeerstream.ExportedServiceList{ @@ -1598,17 +1615,20 @@ func Test_processResponse_Validation(t *testing.T) { peerID := "1fabcd52-1d46-49b0-b1d8-71559aee47f5" type testCase struct { - name string - in *pbpeerstream.ReplicationMessage_Response - expect *pbpeerstream.ReplicationMessage - wantErr bool + name string + in *pbpeerstream.ReplicationMessage_Response + expect *pbpeerstream.ReplicationMessage + extraTests func(t *testing.T, s *state.Store) + wantErr bool } srv, store := newTestServer(t, nil) require.NoError(t, store.PeeringWrite(31, &pbpeering.PeeringWriteRequest{ Peering: &pbpeering.Peering{ - ID: peerID, - Name: peerName, + Name: peerName, + ID: peerID, + ManualServerAddresses: []string{"manual"}, + PeerServerAddresses: []string{"one", "two"}, }, })) @@ -1624,6 +1644,9 @@ func Test_processResponse_Validation(t *testing.T) { require.NoError(t, err) } require.Equal(t, tc.expect, reply) + if tc.extraTests != nil { + tc.extraTests(t, store) + } } tt := []testCase{ @@ -1731,6 +1754,32 @@ func Test_processResponse_Validation(t *testing.T) { }, wantErr: true, }, + { + name: "manual server addresses are not overwritten", + in: &pbpeerstream.ReplicationMessage_Response{ + ResourceURL: pbpeerstream.TypeURLPeeringServerAddresses, + Nonce: "1", + Operation: pbpeerstream.Operation_OPERATION_UPSERT, + Resource: makeAnyPB(t, &pbpeering.PeeringServerAddresses{ + Addresses: []string{"three"}, + }), + }, + expect: &pbpeerstream.ReplicationMessage{ + Payload: &pbpeerstream.ReplicationMessage_Request_{ + Request: &pbpeerstream.ReplicationMessage_Request{ + ResourceURL: pbpeerstream.TypeURLPeeringServerAddresses, + ResponseNonce: "1", + }, + }, + }, + extraTests: func(t *testing.T, s *state.Store) { + _, peer, err := s.PeeringReadByID(nil, peerID) + require.NoError(t, err) + require.Equal(t, []string{"manual"}, peer.ManualServerAddresses) + require.Equal(t, []string{"three"}, peer.PeerServerAddresses) + }, + wantErr: false, + }, } for _, tc := range tt { t.Run(tc.name, func(t *testing.T) { @@ -1892,36 +1941,30 @@ func expectReplEvents(t *testing.T, client *MockClient, checkFns ...func(t *test } } -func Test_processResponse_ExportedServiceUpdates(t *testing.T) { - srv, store := newTestServer(t, func(c *Config) { - backend := c.Backend.(*testStreamBackend) - backend.leader = func() bool { - return false - } - }) - - type testCase struct { - name string - seed []*structs.RegisterRequest - input *pbpeerstream.ExportedService - expect map[string]structs.CheckServiceNodes - exportedServices []string - } - - peerName := "billing" - peerID := "1fabcd52-1d46-49b0-b1d8-71559aee47f5" - remoteMeta := pbcommon.NewEnterpriseMetaFromStructs(*structs.DefaultEnterpriseMetaInPartition("billing-ap")) - - // "api" service is imported from the billing-ap partition, corresponding to the billing peer. - // Locally it is stored to the default partition. - defaultMeta := *acl.DefaultEnterpriseMeta() - apiSN := structs.NewServiceName("api", &defaultMeta) +type PeeringProcessResponse_testCase struct { + name string + seed []*structs.RegisterRequest + inputServiceName structs.ServiceName + input *pbpeerstream.ExportedService + expect map[structs.ServiceName]structs.CheckServiceNodes + exportedServices []string +} +func processResponse_ExportedServiceUpdates( + t *testing.T, + srv *testServer, + store *state.Store, + localEntMeta acl.EnterpriseMeta, + peerName string, + tests []PeeringProcessResponse_testCase, +) *MutableStatus { // create a peering in the state store + peerID := "1fabcd52-1d46-49b0-b1d8-71559aee47f5" require.NoError(t, store.PeeringWrite(31, &pbpeering.PeeringWriteRequest{ Peering: &pbpeering.Peering{ - ID: peerID, - Name: peerName, + ID: peerID, + Name: peerName, + Partition: localEntMeta.PartitionOrDefault(), }, })) @@ -1929,7 +1972,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { mst, err := srv.Tracker.Connected(peerID) require.NoError(t, err) - run := func(t *testing.T, tc testCase) { + run := func(t *testing.T, tc PeeringProcessResponse_testCase) { // Seed the local catalog with some data to reconcile against. // and increment the tracker's imported services count var serviceNames []structs.ServiceName @@ -1943,14 +1986,14 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { in := &pbpeerstream.ReplicationMessage_Response{ ResourceURL: pbpeerstream.TypeURLExportedService, - ResourceID: apiSN.String(), + ResourceID: tc.inputServiceName.String(), Nonce: "1", Operation: pbpeerstream.Operation_OPERATION_UPSERT, Resource: makeAnyPB(t, tc.input), } // Simulate an update arriving for billing/api. - _, err = srv.processResponse(peerName, acl.DefaultPartitionName, mst, in) + _, err = srv.processResponse(peerName, localEntMeta.PartitionOrDefault(), mst, in) require.NoError(t, err) if len(tc.exportedServices) > 0 { @@ -1963,63 +2006,82 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { } // Simulate an update arriving for billing/api. - _, err = srv.processResponse(peerName, acl.DefaultPartitionName, mst, resp) + _, err = srv.processResponse(peerName, localEntMeta.PartitionOrDefault(), mst, resp) require.NoError(t, err) // Test the count and contents separately to ensure the count code path is hit. require.Equal(t, mst.GetImportedServicesCount(), len(tc.exportedServices)) require.ElementsMatch(t, mst.ImportedServices, tc.exportedServices) } - _, allServices, err := srv.GetStore().ServiceList(nil, &defaultMeta, peerName) + wildcardNS := acl.NewEnterpriseMetaWithPartition(localEntMeta.PartitionOrDefault(), acl.WildcardName) + _, allServices, err := srv.GetStore().ServiceList(nil, &wildcardNS, peerName) require.NoError(t, err) // This ensures that only services specified under tc.expect are stored. It includes // all exported services plus their sidecar proxies. for _, svc := range allServices { - _, ok := tc.expect[svc.Name] + _, ok := tc.expect[svc] require.True(t, ok) } for svc, expect := range tc.expect { - t.Run(svc, func(t *testing.T) { - _, got, err := srv.GetStore().CheckServiceNodes(nil, svc, &defaultMeta, peerName) + t.Run(svc.String(), func(t *testing.T) { + _, got, err := srv.GetStore().CheckServiceNodes(nil, svc.Name, &svc.EnterpriseMeta, peerName) require.NoError(t, err) requireEqualInstances(t, expect, got) }) } } - tt := []testCase{ + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + run(t, tc) + }) + } + return mst +} + +func Test_processResponse_ExportedServiceUpdates(t *testing.T) { + peerName := "billing" + localEntMeta := *acl.DefaultEnterpriseMeta() + + remoteMeta := *structs.DefaultEnterpriseMetaInPartition("billing-ap") + pbRemoteMeta := pbcommon.NewEnterpriseMetaFromStructs(remoteMeta) + + apiLocalSN := structs.NewServiceName("api", &localEntMeta) + redisLocalSN := structs.NewServiceName("redis", &localEntMeta) + tests := []PeeringProcessResponse_testCase{ { name: "upsert two service instances to the same node", - exportedServices: []string{"api"}, + exportedServices: []string{apiLocalSN.String()}, + inputServiceName: structs.NewServiceName("api", &remoteMeta), input: &pbpeerstream.ExportedService{ Nodes: []*pbservice.CheckServiceNode{ { Node: &pbservice.Node{ ID: "af913374-68ea-41e5-82e8-6ffd3dffc461", Node: "node-foo", - Partition: remoteMeta.Partition, + Partition: pbRemoteMeta.Partition, PeerName: peerName, }, Service: &pbservice.NodeService{ ID: "api-1", Service: "api", - EnterpriseMeta: remoteMeta, + EnterpriseMeta: pbRemoteMeta, PeerName: peerName, }, Checks: []*pbservice.HealthCheck{ { CheckID: "node-foo-check", Node: "node-foo", - EnterpriseMeta: remoteMeta, + EnterpriseMeta: pbRemoteMeta, PeerName: peerName, }, { CheckID: "api-1-check", ServiceID: "api-1", Node: "node-foo", - EnterpriseMeta: remoteMeta, + EnterpriseMeta: pbRemoteMeta, PeerName: peerName, }, }, @@ -2028,42 +2090,42 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Node: &pbservice.Node{ ID: "af913374-68ea-41e5-82e8-6ffd3dffc461", Node: "node-foo", - Partition: remoteMeta.Partition, + Partition: pbRemoteMeta.Partition, PeerName: peerName, }, Service: &pbservice.NodeService{ ID: "api-2", Service: "api", - EnterpriseMeta: remoteMeta, + EnterpriseMeta: pbRemoteMeta, PeerName: peerName, }, Checks: []*pbservice.HealthCheck{ { CheckID: "node-foo-check", Node: "node-foo", - EnterpriseMeta: remoteMeta, + EnterpriseMeta: pbRemoteMeta, PeerName: peerName, }, { CheckID: "api-2-check", ServiceID: "api-2", Node: "node-foo", - EnterpriseMeta: remoteMeta, + EnterpriseMeta: pbRemoteMeta, PeerName: peerName, }, }, }, }, }, - expect: map[string]structs.CheckServiceNodes{ - "api": { + expect: map[structs.ServiceName]structs.CheckServiceNodes{ + structs.NewServiceName("api", &localEntMeta): { { Node: &structs.Node{ ID: "af913374-68ea-41e5-82e8-6ffd3dffc461", Node: "node-foo", // The remote billing-ap partition is overwritten for all resources with the local default. - Partition: defaultMeta.PartitionOrEmpty(), + Partition: localEntMeta.PartitionOrEmpty(), // The name of the peer "billing" is attached as well. PeerName: peerName, @@ -2071,21 +2133,21 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Service: &structs.NodeService{ ID: "api-1", Service: "api", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: []*structs.HealthCheck{ { CheckID: "node-foo-check", Node: "node-foo", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, { CheckID: "api-1-check", ServiceID: "api-1", Node: "node-foo", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, }, @@ -2094,27 +2156,27 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Node: &structs.Node{ ID: "af913374-68ea-41e5-82e8-6ffd3dffc461", Node: "node-foo", - Partition: defaultMeta.PartitionOrEmpty(), + Partition: localEntMeta.PartitionOrEmpty(), PeerName: peerName, }, Service: &structs.NodeService{ ID: "api-2", Service: "api", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: []*structs.HealthCheck{ { CheckID: "node-foo-check", Node: "node-foo", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, { CheckID: "api-2-check", ServiceID: "api-2", Node: "node-foo", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, }, @@ -2124,7 +2186,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { }, { name: "deleting a service with an empty exported service event", - exportedServices: []string{"api"}, + exportedServices: []string{apiLocalSN.String()}, seed: []*structs.RegisterRequest{ { ID: types.NodeID("af913374-68ea-41e5-82e8-6ffd3dffc461"), @@ -2133,7 +2195,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Service: &structs.NodeService{ ID: "api-2", Service: "api", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: structs.HealthChecks{ @@ -2151,41 +2213,43 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { }, }, }, - input: &pbpeerstream.ExportedService{}, - expect: map[string]structs.CheckServiceNodes{ - "api": {}, + inputServiceName: structs.NewServiceName("api", &remoteMeta), + input: &pbpeerstream.ExportedService{}, + expect: map[structs.ServiceName]structs.CheckServiceNodes{ + structs.NewServiceName("api", &localEntMeta): {}, }, }, { name: "upsert two service instances to different nodes", - exportedServices: []string{"api"}, + exportedServices: []string{apiLocalSN.String()}, + inputServiceName: structs.NewServiceName("api", &remoteMeta), input: &pbpeerstream.ExportedService{ Nodes: []*pbservice.CheckServiceNode{ { Node: &pbservice.Node{ ID: "af913374-68ea-41e5-82e8-6ffd3dffc461", Node: "node-foo", - Partition: remoteMeta.Partition, + Partition: pbRemoteMeta.Partition, PeerName: peerName, }, Service: &pbservice.NodeService{ ID: "api-1", Service: "api", - EnterpriseMeta: remoteMeta, + EnterpriseMeta: pbRemoteMeta, PeerName: peerName, }, Checks: []*pbservice.HealthCheck{ { CheckID: "node-foo-check", Node: "node-foo", - EnterpriseMeta: remoteMeta, + EnterpriseMeta: pbRemoteMeta, PeerName: peerName, }, { CheckID: "api-1-check", ServiceID: "api-1", Node: "node-foo", - EnterpriseMeta: remoteMeta, + EnterpriseMeta: pbRemoteMeta, PeerName: peerName, }, }, @@ -2194,60 +2258,60 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Node: &pbservice.Node{ ID: "c0f97de9-4e1b-4e80-a1c6-cd8725835ab2", Node: "node-bar", - Partition: remoteMeta.Partition, + Partition: pbRemoteMeta.Partition, PeerName: peerName, }, Service: &pbservice.NodeService{ ID: "api-2", Service: "api", - EnterpriseMeta: remoteMeta, + EnterpriseMeta: pbRemoteMeta, PeerName: peerName, }, Checks: []*pbservice.HealthCheck{ { CheckID: "node-bar-check", Node: "node-bar", - EnterpriseMeta: remoteMeta, + EnterpriseMeta: pbRemoteMeta, PeerName: peerName, }, { CheckID: "api-2-check", ServiceID: "api-2", Node: "node-bar", - EnterpriseMeta: remoteMeta, + EnterpriseMeta: pbRemoteMeta, PeerName: peerName, }, }, }, }, }, - expect: map[string]structs.CheckServiceNodes{ - "api": { + expect: map[structs.ServiceName]structs.CheckServiceNodes{ + structs.NewServiceName("api", &localEntMeta): { { Node: &structs.Node{ ID: "c0f97de9-4e1b-4e80-a1c6-cd8725835ab2", Node: "node-bar", - Partition: defaultMeta.PartitionOrEmpty(), + Partition: localEntMeta.PartitionOrEmpty(), PeerName: peerName, }, Service: &structs.NodeService{ ID: "api-2", Service: "api", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: []*structs.HealthCheck{ { CheckID: "node-bar-check", Node: "node-bar", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, { CheckID: "api-2-check", ServiceID: "api-2", Node: "node-bar", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, }, @@ -2258,7 +2322,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Node: "node-foo", // The remote billing-ap partition is overwritten for all resources with the local default. - Partition: defaultMeta.PartitionOrEmpty(), + Partition: localEntMeta.PartitionOrEmpty(), // The name of the peer "billing" is attached as well. PeerName: peerName, @@ -2266,21 +2330,21 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Service: &structs.NodeService{ ID: "api-1", Service: "api", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: []*structs.HealthCheck{ { CheckID: "node-foo-check", Node: "node-foo", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, { CheckID: "api-1-check", ServiceID: "api-1", Node: "node-foo", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, }, @@ -2290,7 +2354,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { }, { name: "deleting one service name from a node does not delete other service names", - exportedServices: []string{"api", "redis"}, + exportedServices: []string{apiLocalSN.String(), redisLocalSN.String()}, seed: []*structs.RegisterRequest{ { ID: types.NodeID("af913374-68ea-41e5-82e8-6ffd3dffc461"), @@ -2299,7 +2363,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Service: &structs.NodeService{ ID: "redis-2", Service: "redis", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: structs.HealthChecks{ @@ -2323,7 +2387,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Service: &structs.NodeService{ ID: "api-1", Service: "api", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: structs.HealthChecks{ @@ -2341,37 +2405,38 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { }, }, }, + inputServiceName: structs.NewServiceName("api", &remoteMeta), // Nil input is for the "api" service. input: &pbpeerstream.ExportedService{}, - expect: map[string]structs.CheckServiceNodes{ - "api": {}, + expect: map[structs.ServiceName]structs.CheckServiceNodes{ + structs.NewServiceName("api", &localEntMeta): {}, // Existing redis service was not affected by deletion. - "redis": { + structs.NewServiceName("redis", &localEntMeta): { { Node: &structs.Node{ ID: "af913374-68ea-41e5-82e8-6ffd3dffc461", Node: "node-foo", - Partition: defaultMeta.PartitionOrEmpty(), + Partition: localEntMeta.PartitionOrEmpty(), PeerName: peerName, }, Service: &structs.NodeService{ ID: "redis-2", Service: "redis", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: []*structs.HealthCheck{ { CheckID: "node-foo-check", Node: "node-foo", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, { CheckID: "redis-2-check", ServiceID: "redis-2", Node: "node-foo", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, }, @@ -2389,7 +2454,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Service: &structs.NodeService{ ID: "redis-2", Service: "redis", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: structs.HealthChecks{ @@ -2413,7 +2478,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Service: &structs.NodeService{ ID: "redis-2-sidecar-proxy", Service: "redis-sidecar-proxy", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: structs.HealthChecks{ @@ -2437,7 +2502,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Service: &structs.NodeService{ ID: "api-1", Service: "api", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: structs.HealthChecks{ @@ -2461,7 +2526,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Service: &structs.NodeService{ ID: "api-1-sidecar-proxy", Service: "api-sidecar-proxy", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: structs.HealthChecks{ @@ -2480,68 +2545,69 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { }, }, }, + inputServiceName: structs.NewServiceName("api", &remoteMeta), // Nil input is for the "api" service. input: &pbpeerstream.ExportedService{}, - exportedServices: []string{"redis"}, - expect: map[string]structs.CheckServiceNodes{ + exportedServices: []string{redisLocalSN.String()}, + expect: map[structs.ServiceName]structs.CheckServiceNodes{ // Existing redis service was not affected by deletion. - "redis": { + structs.NewServiceName("redis", &localEntMeta): { { Node: &structs.Node{ ID: "af913374-68ea-41e5-82e8-6ffd3dffc461", Node: "node-foo", - Partition: defaultMeta.PartitionOrEmpty(), + Partition: localEntMeta.PartitionOrEmpty(), PeerName: peerName, }, Service: &structs.NodeService{ ID: "redis-2", Service: "redis", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: []*structs.HealthCheck{ { CheckID: "node-foo-check", Node: "node-foo", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, { CheckID: "redis-2-check", ServiceID: "redis-2", Node: "node-foo", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, }, }, }, - "redis-sidecar-proxy": { + structs.NewServiceName("redis-sidecar-proxy", &localEntMeta): { { Node: &structs.Node{ ID: "af913374-68ea-41e5-82e8-6ffd3dffc461", Node: "node-foo", - Partition: defaultMeta.PartitionOrEmpty(), + Partition: localEntMeta.PartitionOrEmpty(), PeerName: peerName, }, Service: &structs.NodeService{ ID: "redis-2-sidecar-proxy", Service: "redis-sidecar-proxy", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: []*structs.HealthCheck{ { CheckID: "node-foo-check", Node: "node-foo", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, { CheckID: "redis-2-sidecar-proxy-check", ServiceID: "redis-2-sidecar-proxy", Node: "node-foo", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, }, @@ -2551,7 +2617,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { }, { name: "service checks are cleaned up when not present in a response", - exportedServices: []string{"api"}, + exportedServices: []string{apiLocalSN.String()}, seed: []*structs.RegisterRequest{ { ID: types.NodeID("af913374-68ea-41e5-82e8-6ffd3dffc461"), @@ -2560,7 +2626,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Service: &structs.NodeService{ ID: "api-1", Service: "api", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: structs.HealthChecks{ @@ -2578,19 +2644,20 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { }, }, }, + inputServiceName: structs.NewServiceName("api", &remoteMeta), input: &pbpeerstream.ExportedService{ Nodes: []*pbservice.CheckServiceNode{ { Node: &pbservice.Node{ ID: "af913374-68ea-41e5-82e8-6ffd3dffc461", Node: "node-foo", - Partition: remoteMeta.Partition, + Partition: pbRemoteMeta.Partition, PeerName: peerName, }, Service: &pbservice.NodeService{ ID: "api-1", Service: "api", - EnterpriseMeta: remoteMeta, + EnterpriseMeta: pbRemoteMeta, PeerName: peerName, }, Checks: []*pbservice.HealthCheck{ @@ -2599,20 +2666,20 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { }, }, }, - expect: map[string]structs.CheckServiceNodes{ + expect: map[structs.ServiceName]structs.CheckServiceNodes{ // Service check should be gone - "api": { + structs.NewServiceName("api", &localEntMeta): { { Node: &structs.Node{ ID: "af913374-68ea-41e5-82e8-6ffd3dffc461", Node: "node-foo", - Partition: defaultMeta.PartitionOrEmpty(), + Partition: localEntMeta.PartitionOrEmpty(), PeerName: peerName, }, Service: &structs.NodeService{ ID: "api-1", Service: "api", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: []*structs.HealthCheck{}, @@ -2622,7 +2689,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { }, { name: "node checks are cleaned up when not present in a response", - exportedServices: []string{"api", "redis"}, + exportedServices: []string{apiLocalSN.String(), redisLocalSN.String()}, seed: []*structs.RegisterRequest{ { ID: types.NodeID("af913374-68ea-41e5-82e8-6ffd3dffc461"), @@ -2631,7 +2698,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Service: &structs.NodeService{ ID: "redis-2", Service: "redis", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: structs.HealthChecks{ @@ -2655,7 +2722,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Service: &structs.NodeService{ ID: "api-1", Service: "api", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: structs.HealthChecks{ @@ -2673,19 +2740,20 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { }, }, }, + inputServiceName: structs.NewServiceName("api", &remoteMeta), input: &pbpeerstream.ExportedService{ Nodes: []*pbservice.CheckServiceNode{ { Node: &pbservice.Node{ ID: "af913374-68ea-41e5-82e8-6ffd3dffc461", Node: "node-foo", - Partition: remoteMeta.Partition, + Partition: pbRemoteMeta.Partition, PeerName: peerName, }, Service: &pbservice.NodeService{ ID: "api-1", Service: "api", - EnterpriseMeta: remoteMeta, + EnterpriseMeta: pbRemoteMeta, PeerName: peerName, }, Checks: []*pbservice.HealthCheck{ @@ -2694,27 +2762,27 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { CheckID: "api-1-check", ServiceID: "api-1", Node: "node-foo", - EnterpriseMeta: remoteMeta, + EnterpriseMeta: pbRemoteMeta, PeerName: peerName, }, }, }, }, }, - expect: map[string]structs.CheckServiceNodes{ + expect: map[structs.ServiceName]structs.CheckServiceNodes{ // Node check should be gone - "api": { + structs.NewServiceName("api", &localEntMeta): { { Node: &structs.Node{ ID: "af913374-68ea-41e5-82e8-6ffd3dffc461", Node: "node-foo", - Partition: defaultMeta.PartitionOrEmpty(), + Partition: localEntMeta.PartitionOrEmpty(), PeerName: peerName, }, Service: &structs.NodeService{ ID: "api-1", Service: "api", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: []*structs.HealthCheck{ @@ -2722,24 +2790,24 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { CheckID: "api-1-check", ServiceID: "api-1", Node: "node-foo", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, }, }, }, - "redis": { + structs.NewServiceName("redis", &localEntMeta): { { Node: &structs.Node{ ID: "af913374-68ea-41e5-82e8-6ffd3dffc461", Node: "node-foo", - Partition: defaultMeta.PartitionOrEmpty(), + Partition: localEntMeta.PartitionOrEmpty(), PeerName: peerName, }, Service: &structs.NodeService{ ID: "redis-2", Service: "redis", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: []*structs.HealthCheck{ @@ -2747,7 +2815,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { CheckID: "redis-2-check", ServiceID: "redis-2", Node: "node-foo", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, }, @@ -2757,7 +2825,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { }, { name: "replacing a service instance on a node cleans up the old instance", - exportedServices: []string{"api", "redis"}, + exportedServices: []string{apiLocalSN.String(), redisLocalSN.String()}, seed: []*structs.RegisterRequest{ { ID: types.NodeID("af913374-68ea-41e5-82e8-6ffd3dffc461"), @@ -2766,7 +2834,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Service: &structs.NodeService{ ID: "redis-2", Service: "redis", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: structs.HealthChecks{ @@ -2790,7 +2858,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { Service: &structs.NodeService{ ID: "api-1", Service: "api", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: structs.HealthChecks{ @@ -2808,20 +2876,21 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { }, }, }, + inputServiceName: structs.NewServiceName("api", &remoteMeta), input: &pbpeerstream.ExportedService{ Nodes: []*pbservice.CheckServiceNode{ { Node: &pbservice.Node{ ID: "af913374-68ea-41e5-82e8-6ffd3dffc461", Node: "node-foo", - Partition: remoteMeta.Partition, + Partition: pbRemoteMeta.Partition, PeerName: peerName, }, // New service ID and checks for the api service. Service: &pbservice.NodeService{ ID: "new-api-v2", Service: "api", - EnterpriseMeta: remoteMeta, + EnterpriseMeta: pbRemoteMeta, PeerName: peerName, }, Checks: []*pbservice.HealthCheck{ @@ -2840,19 +2909,19 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { }, }, }, - expect: map[string]structs.CheckServiceNodes{ - "api": { + expect: map[structs.ServiceName]structs.CheckServiceNodes{ + structs.NewServiceName("api", &localEntMeta): { { Node: &structs.Node{ ID: "af913374-68ea-41e5-82e8-6ffd3dffc461", Node: "node-foo", - Partition: defaultMeta.PartitionOrEmpty(), + Partition: localEntMeta.PartitionOrEmpty(), PeerName: peerName, }, Service: &structs.NodeService{ ID: "new-api-v2", Service: "api", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: []*structs.HealthCheck{ @@ -2865,24 +2934,24 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { CheckID: "new-api-v2-check", ServiceID: "new-api-v2", Node: "node-foo", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, }, }, }, - "redis": { + structs.NewServiceName("redis", &localEntMeta): { { Node: &structs.Node{ ID: "af913374-68ea-41e5-82e8-6ffd3dffc461", Node: "node-foo", - Partition: defaultMeta.PartitionOrEmpty(), + Partition: localEntMeta.PartitionOrEmpty(), PeerName: peerName, }, Service: &structs.NodeService{ ID: "redis-2", Service: "redis", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, Checks: []*structs.HealthCheck{ @@ -2895,7 +2964,7 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { CheckID: "redis-2-check", ServiceID: "redis-2", Node: "node-foo", - EnterpriseMeta: defaultMeta, + EnterpriseMeta: localEntMeta, PeerName: peerName, }, }, @@ -2904,12 +2973,13 @@ func Test_processResponse_ExportedServiceUpdates(t *testing.T) { }, }, } - - for _, tc := range tt { - t.Run(tc.name, func(t *testing.T) { - run(t, tc) - }) - } + srv, store := newTestServer(t, func(c *Config) { + backend := c.Backend.(*testStreamBackend) + backend.leader = func() bool { + return false + } + }) + processResponse_ExportedServiceUpdates(t, srv, store, localEntMeta, peerName, tests) } // TestLogTraceProto tests that all PB trace log helpers redact the diff --git a/agent/grpc-external/services/peerstream/stream_tracker.go b/agent/grpc-external/services/peerstream/stream_tracker.go index daf891d38adf..c2d358543939 100644 --- a/agent/grpc-external/services/peerstream/stream_tracker.go +++ b/agent/grpc-external/services/peerstream/stream_tracker.go @@ -359,9 +359,8 @@ func (s *MutableStatus) SetImportedServices(serviceNames []structs.ServiceName) defer s.mu.Unlock() s.ImportedServices = make([]string, len(serviceNames)) - for i, sn := range serviceNames { - s.ImportedServices[i] = sn.Name + s.ImportedServices[i] = sn.String() } } @@ -379,7 +378,7 @@ func (s *MutableStatus) SetExportedServices(serviceNames []structs.ServiceName) s.ExportedServices = make([]string, len(serviceNames)) for i, sn := range serviceNames { - s.ExportedServices[i] = sn.Name + s.ExportedServices[i] = sn.String() } } diff --git a/agent/grpc-external/services/peerstream/subscription_manager.go b/agent/grpc-external/services/peerstream/subscription_manager.go index ef31f850bfef..007b51bb4512 100644 --- a/agent/grpc-external/services/peerstream/subscription_manager.go +++ b/agent/grpc-external/services/peerstream/subscription_manager.go @@ -9,11 +9,12 @@ import ( "time" "github.com/golang/protobuf/proto" - "github.com/hashicorp/consul/ipaddr" - "github.com/hashicorp/consul/lib/retry" "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-memdb" + "github.com/hashicorp/consul/ipaddr" + "github.com/hashicorp/consul/lib/retry" + "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/cache" "github.com/hashicorp/consul/agent/connect" @@ -142,7 +143,7 @@ func (m *subscriptionManager) handleEvent(ctx context.Context, state *subscripti pending := &pendingPayload{} m.syncNormalServices(ctx, state, evt.Services) if m.config.ConnectEnabled { - m.syncDiscoveryChains(ctx, state, pending, evt.ListAllDiscoveryChains()) + m.syncDiscoveryChains(state, pending, evt.DiscoChains) } err := pending.Add( @@ -254,7 +255,7 @@ func (m *subscriptionManager) handleEvent(ctx context.Context, state *subscripti if state.exportList != nil { // Trigger public events for all synthetic discovery chain replies. for chainName, info := range state.connectServices { - m.collectPendingEventForDiscoveryChain(ctx, state, pending, chainName, info) + m.collectPendingEventForDiscoveryChain(state, pending, chainName, info) } } @@ -475,7 +476,6 @@ func (m *subscriptionManager) syncNormalServices( } func (m *subscriptionManager) syncDiscoveryChains( - ctx context.Context, state *subscriptionState, pending *pendingPayload, chainsByName map[structs.ServiceName]structs.ExportedDiscoveryChainInfo, @@ -488,7 +488,7 @@ func (m *subscriptionManager) syncDiscoveryChains( state.connectServices[chainName] = info - m.collectPendingEventForDiscoveryChain(ctx, state, pending, chainName, info) + m.collectPendingEventForDiscoveryChain(state, pending, chainName, info) } // if it was dropped, try to emit an DELETE event @@ -516,7 +516,6 @@ func (m *subscriptionManager) syncDiscoveryChains( } func (m *subscriptionManager) collectPendingEventForDiscoveryChain( - ctx context.Context, state *subscriptionState, pending *pendingPayload, chainName structs.ServiceName, @@ -665,6 +664,21 @@ func createDiscoChainHealth( } } +var statusScores = map[string]int{ + // 0 is reserved for unknown + api.HealthMaint: 1, + api.HealthCritical: 2, + api.HealthWarning: 3, + api.HealthPassing: 4, +} + +func getMostImportantStatus(a, b string) string { + if statusScores[a] < statusScores[b] { + return a + } + return b +} + func flattenChecks( nodeName string, serviceID string, @@ -676,10 +690,16 @@ func flattenChecks( return nil } + // Similar logic to (api.HealthChecks).AggregatedStatus() healthStatus := api.HealthPassing - for _, chk := range checks { - if chk.Status != api.HealthPassing { - healthStatus = chk.Status + if len(checks) > 0 { + for _, chk := range checks { + id := chk.CheckID + if id == api.NodeMaint || strings.HasPrefix(id, api.ServiceMaintPrefix) { + healthStatus = api.HealthMaint + break // always wins + } + healthStatus = getMostImportantStatus(healthStatus, chk.Status) } } @@ -724,7 +744,7 @@ func (m *subscriptionManager) NotifyStandardService( // // This name was chosen to match existing "sidecar service" generation logic // and similar logic in the Service Identity synthetic ACL policies. -const syntheticProxyNameSuffix = "-sidecar-proxy" +const syntheticProxyNameSuffix = structs.SidecarProxySuffix func generateProxyNameForDiscoveryChain(sn structs.ServiceName) structs.ServiceName { return structs.NewServiceName(sn.Name+syntheticProxyNameSuffix, &sn.EnterpriseMeta) @@ -786,7 +806,7 @@ func (m *subscriptionManager) notifyMeshConfigUpdates(ctx context.Context) <-cha const meshConfigWatch = "mesh-config-entry" notifyCh := make(chan cache.UpdateEvent, 1) - go m.syncViaBlockingQuery(ctx, meshConfigWatch, func(ctx_ context.Context, store StateStore, ws memdb.WatchSet) (interface{}, error) { + go m.syncViaBlockingQuery(ctx, meshConfigWatch, func(_ context.Context, store StateStore, ws memdb.WatchSet) (interface{}, error) { _, rawEntry, err := store.ConfigEntry(ws, structs.MeshConfig, structs.MeshConfigMesh, acl.DefaultEnterpriseMeta()) if err != nil { return nil, fmt.Errorf("failed to get mesh config entry: %w", err) @@ -909,7 +929,13 @@ func (m *subscriptionManager) subscribeServerAddrs( if srv.ExtGRPCPort == 0 { continue } - grpcAddr := srv.Address + ":" + strconv.Itoa(srv.ExtGRPCPort) + addr := srv.Address + + // wan address is preferred + if v, ok := srv.TaggedAddresses[structs.TaggedAddressWAN]; ok && v != "" { + addr = v + } + grpcAddr := addr + ":" + strconv.Itoa(srv.ExtGRPCPort) serverAddrs = append(serverAddrs, grpcAddr) } if len(serverAddrs) == 0 { diff --git a/agent/grpc-external/services/peerstream/subscription_manager_test.go b/agent/grpc-external/services/peerstream/subscription_manager_test.go index 615d72030e61..c7b77edec961 100644 --- a/agent/grpc-external/services/peerstream/subscription_manager_test.go +++ b/agent/grpc-external/services/peerstream/subscription_manager_test.go @@ -7,7 +7,6 @@ import ( "testing" "time" - "github.com/hashicorp/consul/types" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -18,12 +17,14 @@ import ( "github.com/hashicorp/consul/agent/consul/state" "github.com/hashicorp/consul/agent/consul/stream" "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/proto/pbcommon" "github.com/hashicorp/consul/proto/pbpeering" "github.com/hashicorp/consul/proto/pbpeerstream" "github.com/hashicorp/consul/proto/pbservice" "github.com/hashicorp/consul/proto/prototest" "github.com/hashicorp/consul/sdk/testutil" + "github.com/hashicorp/consul/types" ) func TestSubscriptionManager_RegisterDeregister(t *testing.T) { @@ -471,15 +472,40 @@ func TestSubscriptionManager_InitialSnapshot(t *testing.T) { Node: &structs.Node{Node: "foo", Address: "10.0.0.1"}, Service: &structs.NodeService{ID: "mysql-1", Service: "mysql", Port: 5000}, } + mysqlSidecar := structs.NodeService{ + Kind: structs.ServiceKindConnectProxy, + Service: "mysql-sidecar-proxy", + Proxy: structs.ConnectProxyConfig{ + DestinationServiceName: "mysql", + }, + } backend.ensureNode(t, mysql.Node) backend.ensureService(t, "foo", mysql.Service) + backend.ensureService(t, "foo", &mysqlSidecar) mongo := &structs.CheckServiceNode{ - Node: &structs.Node{Node: "zip", Address: "10.0.0.3"}, - Service: &structs.NodeService{ID: "mongo-1", Service: "mongo", Port: 5000}, + Node: &structs.Node{Node: "zip", Address: "10.0.0.3"}, + Service: &structs.NodeService{ + ID: "mongo-1", + Service: "mongo", + Port: 5000, + }, + } + mongoSidecar := structs.NodeService{ + Kind: structs.ServiceKindConnectProxy, + Service: "mongo-sidecar-proxy", + Proxy: structs.ConnectProxyConfig{ + DestinationServiceName: "mongo", + }, } backend.ensureNode(t, mongo.Node) backend.ensureService(t, "zip", mongo.Service) + backend.ensureService(t, "zip", &mongoSidecar) + + backend.ensureConfigEntry(t, &structs.ServiceResolverConfigEntry{ + Kind: structs.ServiceResolver, + Name: "chain", + }) var ( mysqlCorrID = subExportedService + structs.NewServiceName("mysql", nil).String() @@ -710,6 +736,35 @@ func TestSubscriptionManager_ServerAddrs(t *testing.T) { ) }) + testutil.RunStep(t, "added server with WAN address", func(t *testing.T) { + payload = append(payload, autopilotevents.ReadyServerInfo{ + ID: "eec8721f-c42b-48da-a5a5-07565158015e", + Address: "198.18.0.3", + Version: "1.13.1", + ExtGRPCPort: 9502, + TaggedAddresses: map[string]string{ + structs.TaggedAddressWAN: "198.18.0.103", + }, + }) + backend.Publish([]stream.Event{ + { + Topic: autopilotevents.EventTopicReadyServers, + Index: 3, + Payload: payload, + }, + }) + + expectEvents(t, subCh, + func(t *testing.T, got cache.UpdateEvent) { + require.Equal(t, subServerAddrs, got.CorrelationID) + addrs, ok := got.Result.(*pbpeering.PeeringServerAddresses) + require.True(t, ok) + + require.Equal(t, []string{"198.18.0.1:8502", "198.18.0.2:9502", "198.18.0.103:9502"}, addrs.GetAddresses()) + }, + ) + }) + testutil.RunStep(t, "flipped to peering through mesh gateways", func(t *testing.T) { require.NoError(t, backend.store.EnsureConfigEntry(1, &structs.MeshConfigEntry{ Peering: &structs.PeeringMeshConfig{ @@ -807,6 +862,154 @@ func TestSubscriptionManager_ServerAddrs(t *testing.T) { }) } +func TestFlattenChecks(t *testing.T) { + type testcase struct { + checks []*pbservice.HealthCheck + expect string + expectNoResult bool + } + + run := func(t *testing.T, tc testcase) { + t.Helper() + got := flattenChecks( + "node-name", "service-id", "service-name", nil, tc.checks, + ) + if tc.expectNoResult { + require.Empty(t, got) + } else { + require.Len(t, got, 1) + require.Equal(t, tc.expect, got[0].Status) + } + } + + cases := map[string]testcase{ + "empty": { + checks: nil, + expectNoResult: true, + }, + "passing": { + checks: []*pbservice.HealthCheck{ + { + CheckID: "check-id", + Status: api.HealthPassing, + }, + }, + expect: api.HealthPassing, + }, + "warning": { + checks: []*pbservice.HealthCheck{ + { + CheckID: "check-id", + Status: api.HealthWarning, + }, + }, + expect: api.HealthWarning, + }, + "critical": { + checks: []*pbservice.HealthCheck{ + { + CheckID: "check-id", + Status: api.HealthCritical, + }, + }, + expect: api.HealthCritical, + }, + "node_maintenance": { + checks: []*pbservice.HealthCheck{ + { + CheckID: api.NodeMaint, + Status: api.HealthPassing, + }, + }, + expect: api.HealthMaint, + }, + "service_maintenance": { + checks: []*pbservice.HealthCheck{ + { + CheckID: api.ServiceMaintPrefix + "service", + Status: api.HealthPassing, + }, + }, + expect: api.HealthMaint, + }, + "unknown": { + checks: []*pbservice.HealthCheck{ + { + CheckID: "check-id", + Status: "nope-nope-noper", + }, + }, + expect: "nope-nope-noper", + }, + "maintenance_over_critical": { + checks: []*pbservice.HealthCheck{ + { + CheckID: api.NodeMaint, + Status: api.HealthPassing, + }, + { + CheckID: "check-id", + Status: api.HealthCritical, + }, + }, + expect: api.HealthMaint, + }, + "critical_over_warning": { + checks: []*pbservice.HealthCheck{ + { + CheckID: "check-id", + Status: api.HealthCritical, + }, + { + CheckID: "check-id", + Status: api.HealthWarning, + }, + }, + expect: api.HealthCritical, + }, + "warning_over_passing": { + checks: []*pbservice.HealthCheck{ + { + CheckID: "check-id", + Status: api.HealthWarning, + }, + { + CheckID: "check-id", + Status: api.HealthPassing, + }, + }, + expect: api.HealthWarning, + }, + "lots": { + checks: []*pbservice.HealthCheck{ + { + CheckID: "check-id", + Status: api.HealthPassing, + }, + { + CheckID: "check-id", + Status: api.HealthPassing, + }, + { + CheckID: "check-id", + Status: api.HealthPassing, + }, + { + CheckID: "check-id", + Status: api.HealthWarning, + }, + }, + expect: api.HealthWarning, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + run(t, tc) + }) + } +} + type testSubscriptionBackend struct { state.EventPublisher store *state.Store @@ -843,11 +1046,13 @@ func newTestSubscriptionBackend(t *testing.T) *testSubscriptionBackend { return backend } +//nolint:unparam func (b *testSubscriptionBackend) ensurePeering(t *testing.T, name string) (uint64, string) { b.lastIdx++ return b.lastIdx, setupTestPeering(t, b.store, name, b.lastIdx) } +//nolint:unparam func (b *testSubscriptionBackend) ensureConfigEntry(t *testing.T, entry structs.ConfigEntry) uint64 { require.NoError(t, entry.Normalize()) require.NoError(t, entry.Validate()) @@ -863,24 +1068,28 @@ func (b *testSubscriptionBackend) deleteConfigEntry(t *testing.T, kind, name str return b.lastIdx } +//nolint:unparam func (b *testSubscriptionBackend) ensureNode(t *testing.T, node *structs.Node) uint64 { b.lastIdx++ require.NoError(t, b.store.EnsureNode(b.lastIdx, node)) return b.lastIdx } +//nolint:unparam func (b *testSubscriptionBackend) ensureService(t *testing.T, node string, svc *structs.NodeService) uint64 { b.lastIdx++ require.NoError(t, b.store.EnsureService(b.lastIdx, node, svc)) return b.lastIdx } +//nolint:unparam func (b *testSubscriptionBackend) ensureCheck(t *testing.T, hc *structs.HealthCheck) uint64 { b.lastIdx++ require.NoError(t, b.store.EnsureCheck(b.lastIdx, hc)) return b.lastIdx } +//nolint:unparam func (b *testSubscriptionBackend) deleteService(t *testing.T, nodeName, serviceID string) uint64 { b.lastIdx++ require.NoError(t, b.store.DeleteService(b.lastIdx, nodeName, serviceID, nil, "")) diff --git a/agent/grpc-external/services/peerstream/testing.go b/agent/grpc-external/services/peerstream/testing.go index 4f0297a6c522..5eb575c06aa9 100644 --- a/agent/grpc-external/services/peerstream/testing.go +++ b/agent/grpc-external/services/peerstream/testing.go @@ -150,6 +150,16 @@ func (t *incrementalTime) Now() time.Time { return t.base.Add(dur) } +// StaticNow returns the current internal clock without advancing it. +func (t *incrementalTime) StaticNow() time.Time { + t.mu.Lock() + defer t.mu.Unlock() + + dur := time.Duration(t.next) * time.Second + + return t.base.Add(dur) +} + // FutureNow will return a given future value of the Now() function. // The numerical argument indicates which future Now value you wanted. The // value must be > 0. diff --git a/agent/grpc-external/services/serverdiscovery/mock_ACLResolver.go b/agent/grpc-external/services/serverdiscovery/mock_ACLResolver.go index 850ec8bb9505..4192be1ab974 100644 --- a/agent/grpc-external/services/serverdiscovery/mock_ACLResolver.go +++ b/agent/grpc-external/services/serverdiscovery/mock_ACLResolver.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.12.0. DO NOT EDIT. +// Code generated by mockery v2.15.0. DO NOT EDIT. package serverdiscovery @@ -7,8 +7,6 @@ import ( mock "github.com/stretchr/testify/mock" resolver "github.com/hashicorp/consul/acl/resolver" - - testing "testing" ) // MockACLResolver is an autogenerated mock type for the ACLResolver type @@ -37,8 +35,13 @@ func (_m *MockACLResolver) ResolveTokenAndDefaultMeta(_a0 string, _a1 *acl.Enter return r0, r1 } -// NewMockACLResolver creates a new instance of MockACLResolver. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockACLResolver(t testing.TB) *MockACLResolver { +type mockConstructorTestingTNewMockACLResolver interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockACLResolver creates a new instance of MockACLResolver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockACLResolver(t mockConstructorTestingTNewMockACLResolver) *MockACLResolver { mock := &MockACLResolver{} mock.Mock.Test(t) diff --git a/agent/grpc-external/services/serverdiscovery/server_test.go b/agent/grpc-external/services/serverdiscovery/server_test.go index c946adaa8c03..35146f554ff4 100644 --- a/agent/grpc-external/services/serverdiscovery/server_test.go +++ b/agent/grpc-external/services/serverdiscovery/server_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - mock "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "google.golang.org/grpc" @@ -79,6 +79,7 @@ func testClient(t *testing.T, server *Server) pbserverdiscovery.ServerDiscoveryS addr := testutils.RunTestServer(t, server) + //nolint:staticcheck conn, err := grpc.DialContext(context.Background(), addr.String(), grpc.WithInsecure()) require.NoError(t, err) t.Cleanup(func() { diff --git a/agent/grpc-external/services/serverdiscovery/watch_servers.go b/agent/grpc-external/services/serverdiscovery/watch_servers.go index de3977be80f0..a672560b9ce9 100644 --- a/agent/grpc-external/services/serverdiscovery/watch_servers.go +++ b/agent/grpc-external/services/serverdiscovery/watch_servers.go @@ -8,7 +8,6 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/consul/autopilotevents" "github.com/hashicorp/consul/agent/consul/stream" external "github.com/hashicorp/consul/agent/grpc-external" @@ -46,7 +45,7 @@ func (s *Server) WatchServers(req *pbserverdiscovery.WatchServersRequest, server } func (s *Server) serveReadyServers(token string, index uint64, req *pbserverdiscovery.WatchServersRequest, serverStream pbserverdiscovery.ServerDiscoveryService_WatchServersServer, logger hclog.Logger) (uint64, error) { - if err := s.authorize(token); err != nil { + if err := external.RequireAnyValidACLToken(s.ACLResolver, token); err != nil { return 0, err } @@ -105,21 +104,6 @@ func (s *Server) serveReadyServers(token string, index uint64, req *pbserverdisc } } -func (s *Server) authorize(token string) error { - // Require the given ACL token to have `service:write` on any service (in any - // partition and namespace). - var authzContext acl.AuthorizerContext - entMeta := structs.WildcardEnterpriseMetaInPartition(structs.WildcardSpecifier) - authz, err := s.ACLResolver.ResolveTokenAndDefaultMeta(token, entMeta, &authzContext) - if err != nil { - return status.Error(codes.Unauthenticated, err.Error()) - } - if err := authz.ToAllowAuthorizer().ServiceWriteAnyAllowed(&authzContext); err != nil { - return status.Error(codes.PermissionDenied, err.Error()) - } - return nil -} - func eventToResponse(req *pbserverdiscovery.WatchServersRequest, event stream.Event) (*pbserverdiscovery.WatchServersResponse, error) { readyServers, err := autopilotevents.ExtractEventPayload(event) if err != nil { diff --git a/agent/grpc-external/services/serverdiscovery/watch_servers_test.go b/agent/grpc-external/services/serverdiscovery/watch_servers_test.go index a57c0f985586..91570e395417 100644 --- a/agent/grpc-external/services/serverdiscovery/watch_servers_test.go +++ b/agent/grpc-external/services/serverdiscovery/watch_servers_test.go @@ -123,7 +123,7 @@ func TestWatchServers_StreamLifeCycle(t *testing.T) { // 2 times authorization should succeed and the third should fail. resolver := newMockACLResolver(t) resolver.On("ResolveTokenAndDefaultMeta", testACLToken, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerServiceWriteAny(t), nil).Twice() + Return(testutils.ACLNoPermissions(t), nil).Twice() // add the token to the requests context options := structs.QueryOptions{Token: testACLToken} @@ -192,13 +192,13 @@ func TestWatchServers_StreamLifeCycle(t *testing.T) { prototest.AssertDeepEqual(t, threeServerResponse, rsp) } -func TestWatchServers_ACLToken_PermissionDenied(t *testing.T) { +func TestWatchServers_ACLToken_AnonymousToken(t *testing.T) { // setup the event publisher and snapshot handler _, publisher := setupPublisher(t) resolver := newMockACLResolver(t) resolver.On("ResolveTokenAndDefaultMeta", testACLToken, mock.Anything, mock.Anything). - Return(testutils.TestAuthorizerDenyAll(t), nil).Once() + Return(testutils.ACLAnonymous(t), nil).Once() // add the token to the requests context options := structs.QueryOptions{Token: testACLToken} @@ -222,7 +222,7 @@ func TestWatchServers_ACLToken_PermissionDenied(t *testing.T) { // Expect to get an Unauthenticated error immediately. err = mustGetError(t, rspCh) - require.Equal(t, codes.PermissionDenied.String(), status.Code(err).String()) + require.Equal(t, codes.Unauthenticated.String(), status.Code(err).String()) } func TestWatchServers_ACLToken_Unauthenticated(t *testing.T) { diff --git a/agent/grpc-external/stats_test.go b/agent/grpc-external/stats_test.go index 8f5dffb67ab9..c231a922d121 100644 --- a/agent/grpc-external/stats_test.go +++ b/agent/grpc-external/stats_test.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/go-hclog" + grpcmiddleware "github.com/hashicorp/consul/agent/grpc-middleware" "github.com/hashicorp/consul/agent/grpc-middleware/testutil" "github.com/hashicorp/consul/agent/grpc-middleware/testutil/testservice" "github.com/hashicorp/consul/proto/prototest" @@ -22,12 +23,13 @@ import ( func TestServer_EmitsStats(t *testing.T) { sink, metricsObj := testutil.NewFakeSink(t) - srv := NewServer(hclog.Default(), metricsObj) + srv := NewServer(hclog.Default(), metricsObj, nil) testservice.RegisterSimpleServer(srv, &testservice.Simple{}) lis, err := net.Listen("tcp", "127.0.0.1:0") require.NoError(t, err) + lis = grpcmiddleware.LabelledListener{Listener: lis, Protocol: grpcmiddleware.ProtocolPlaintext} ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) @@ -43,6 +45,7 @@ func TestServer_EmitsStats(t *testing.T) { } }) + //nolint:staticcheck conn, err := grpc.DialContext(ctx, lis.Addr().String(), grpc.WithInsecure()) require.NoError(t, err) t.Cleanup(func() { conn.Close() }) diff --git a/agent/grpc-external/testutils/acl.go b/agent/grpc-external/testutils/acl.go index fab3646e73d4..ccb2e6a30e90 100644 --- a/agent/grpc-external/testutils/acl.go +++ b/agent/grpc-external/testutils/acl.go @@ -5,23 +5,42 @@ import ( "github.com/stretchr/testify/require" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/acl/resolver" + "github.com/hashicorp/consul/agent/structs" ) -func TestAuthorizerAllowAll(t *testing.T) resolver.Result { +func ACLAnonymous(t *testing.T) resolver.Result { t.Helper() - return resolver.Result{Authorizer: acl.AllowAll()} + return resolver.Result{ + Authorizer: acl.DenyAll(), + ACLIdentity: &structs.ACLToken{ + AccessorID: structs.ACLTokenAnonymousID, + }, + } } -func TestAuthorizerDenyAll(t *testing.T) resolver.Result { +func ACLsDisabled(t *testing.T) resolver.Result { t.Helper() - return resolver.Result{Authorizer: acl.DenyAll()} + return resolver.Result{ + Authorizer: acl.ManageAll(), + } } -func TestAuthorizerServiceWriteAny(t *testing.T) resolver.Result { +func ACLNoPermissions(t *testing.T) resolver.Result { + t.Helper() + + return resolver.Result{ + Authorizer: acl.DenyAll(), + ACLIdentity: randomACLIdentity(t), + } +} + +func ACLServiceWriteAny(t *testing.T) resolver.Result { t.Helper() policy, err := acl.NewPolicyFromSource(` @@ -34,10 +53,13 @@ func TestAuthorizerServiceWriteAny(t *testing.T) resolver.Result { authz, err := acl.NewPolicyAuthorizerWithDefaults(acl.DenyAll(), []*acl.Policy{policy}, nil) require.NoError(t, err) - return resolver.Result{Authorizer: authz} + return resolver.Result{ + Authorizer: authz, + ACLIdentity: randomACLIdentity(t), + } } -func TestAuthorizerServiceRead(t *testing.T, serviceName string) resolver.Result { +func ACLServiceRead(t *testing.T, serviceName string) resolver.Result { t.Helper() aclRule := &acl.Policy{ @@ -53,5 +75,15 @@ func TestAuthorizerServiceRead(t *testing.T, serviceName string) resolver.Result authz, err := acl.NewPolicyAuthorizerWithDefaults(acl.DenyAll(), []*acl.Policy{aclRule}, nil) require.NoError(t, err) - return resolver.Result{Authorizer: authz} + return resolver.Result{ + Authorizer: authz, + ACLIdentity: randomACLIdentity(t), + } +} + +func randomACLIdentity(t *testing.T) structs.ACLIdentity { + id, err := uuid.GenerateUUID() + require.NoError(t, err) + + return &structs.ACLToken{AccessorID: id} } diff --git a/agent/grpc-external/utils.go b/agent/grpc-external/utils.go index c2c77ace6477..4d6e9189245d 100644 --- a/agent/grpc-external/utils.go +++ b/agent/grpc-external/utils.go @@ -1,6 +1,14 @@ package external -import "github.com/hashicorp/go-uuid" +import ( + "github.com/hashicorp/go-uuid" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/hashicorp/consul/acl" + "github.com/hashicorp/consul/acl/resolver" + "github.com/hashicorp/consul/agent/structs" +) // We tag logs with a unique identifier to ease debugging. In the future this // should probably be a real Open Telemetry trace ID. @@ -11,3 +19,26 @@ func TraceID() string { } return id } + +type ACLResolver interface { + ResolveTokenAndDefaultMeta(string, *acl.EnterpriseMeta, *acl.AuthorizerContext) (resolver.Result, error) +} + +// RequireAnyValidACLToken checks that the caller provided a valid ACL token +// without requiring any specific permissions. This is useful for endpoints +// that are used by all/most consumers of our API, such as those called by the +// consul-server-connection-manager library when establishing a new connection. +// +// Note: no token is required if ACLs are disabled. +func RequireAnyValidACLToken(resolver ACLResolver, token string) error { + authz, err := resolver.ResolveTokenAndDefaultMeta(token, nil, nil) + if err != nil { + return status.Error(codes.Unauthenticated, err.Error()) + } + + if id := authz.ACLIdentity; id != nil && id.ID() == structs.ACLTokenAnonymousID { + return status.Error(codes.Unauthenticated, "An ACL token must be provided (via the `x-consul-token` metadata field) to call this endpoint") + } + + return nil +} diff --git a/agent/grpc-internal/balancer/custombalancer.go b/agent/grpc-internal/balancer/custombalancer.go new file mode 100644 index 000000000000..c3c5409d39dd --- /dev/null +++ b/agent/grpc-internal/balancer/custombalancer.go @@ -0,0 +1,87 @@ +package balancer + +import ( + "google.golang.org/grpc/balancer" + "google.golang.org/grpc/connectivity" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/resolver" +) + +func init() { + balancer.Register(newCustomPickfirstBuilder()) +} + +// logger is referenced in pickfirst.go. +// The gRPC library uses the same component name. +var logger = grpclog.Component("balancer") + +func newCustomPickfirstBuilder() balancer.Builder { + return &customPickfirstBuilder{} +} + +type customPickfirstBuilder struct{} + +func (*customPickfirstBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer { + return &customPickfirstBalancer{ + pickfirstBalancer: pickfirstBalancer{cc: cc}, + } +} + +func (*customPickfirstBuilder) Name() string { + return "pick_first_custom" +} + +// customPickfirstBalancer overrides UpdateClientConnState of pickfirstBalancer. +type customPickfirstBalancer struct { + pickfirstBalancer + + activeAddr resolver.Address +} + +func (b *customPickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState) error { + for _, a := range state.ResolverState.Addresses { + // This hack preserves an existing behavior in our client-side + // load balancing where if the first address in a shuffled list + // of addresses matched the currently connected address, it would + // be an effective no-op. + if a.Equal(b.activeAddr) { + break + } + + // Attempt to make a new SubConn with a single address so we can + // track a successful connection explicitly. If we were to pass + // a list of addresses, we cannot assume the first address was + // successful and there is no way to extract the connected address. + sc, err := b.cc.NewSubConn([]resolver.Address{a}, balancer.NewSubConnOptions{}) + if err != nil { + logger.Warningf("balancer.customPickfirstBalancer: failed to create new SubConn: %v", err) + continue + } + + if b.subConn != nil { + b.cc.RemoveSubConn(b.subConn) + } + + // Copy-pasted from pickfirstBalancer.UpdateClientConnState. + { + b.subConn = sc + b.state = connectivity.Idle + b.cc.UpdateState(balancer.State{ + ConnectivityState: connectivity.Idle, + Picker: &picker{result: balancer.PickResult{SubConn: b.subConn}}, + }) + b.subConn.Connect() + } + + b.activeAddr = a + + // We now have a new subConn with one address. + // Break the loop and call UpdateClientConnState + // with the full set of addresses. + break + } + + // This will load the full set of addresses but leave the + // newly created subConn alone. + return b.pickfirstBalancer.UpdateClientConnState(state) +} diff --git a/agent/grpc-internal/balancer/pickfirst.go b/agent/grpc-internal/balancer/pickfirst.go new file mode 100644 index 000000000000..45edcddce2b1 --- /dev/null +++ b/agent/grpc-internal/balancer/pickfirst.go @@ -0,0 +1,189 @@ +// NOTICE: This file is a copy of grpc's pick_first implementation [1]. +// It is preserved as-is with the init() removed for easier updating. +// +// [1]: https://github.com/grpc/grpc-go/blob/v1.49.x/pickfirst.go + +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package balancer + +import ( + "errors" + "fmt" + + "google.golang.org/grpc/balancer" + "google.golang.org/grpc/connectivity" +) + +// PickFirstBalancerName is the name of the pick_first balancer. +const PickFirstBalancerName = "pick_first_original" + +func newPickfirstBuilder() balancer.Builder { + return &pickfirstBuilder{} +} + +type pickfirstBuilder struct{} + +func (*pickfirstBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer { + return &pickfirstBalancer{cc: cc} +} + +func (*pickfirstBuilder) Name() string { + return PickFirstBalancerName +} + +type pickfirstBalancer struct { + state connectivity.State + cc balancer.ClientConn + subConn balancer.SubConn +} + +func (b *pickfirstBalancer) ResolverError(err error) { + if logger.V(2) { + logger.Infof("pickfirstBalancer: ResolverError called with error %v", err) + } + if b.subConn == nil { + b.state = connectivity.TransientFailure + } + + if b.state != connectivity.TransientFailure { + // The picker will not change since the balancer does not currently + // report an error. + return + } + b.cc.UpdateState(balancer.State{ + ConnectivityState: connectivity.TransientFailure, + Picker: &picker{err: fmt.Errorf("name resolver error: %v", err)}, + }) +} + +func (b *pickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState) error { + if len(state.ResolverState.Addresses) == 0 { + // The resolver reported an empty address list. Treat it like an error by + // calling b.ResolverError. + if b.subConn != nil { + // Remove the old subConn. All addresses were removed, so it is no longer + // valid. + b.cc.RemoveSubConn(b.subConn) + b.subConn = nil + } + b.ResolverError(errors.New("produced zero addresses")) + return balancer.ErrBadResolverState + } + + if b.subConn != nil { + b.cc.UpdateAddresses(b.subConn, state.ResolverState.Addresses) + return nil + } + + subConn, err := b.cc.NewSubConn(state.ResolverState.Addresses, balancer.NewSubConnOptions{}) + if err != nil { + if logger.V(2) { + logger.Errorf("pickfirstBalancer: failed to NewSubConn: %v", err) + } + b.state = connectivity.TransientFailure + b.cc.UpdateState(balancer.State{ + ConnectivityState: connectivity.TransientFailure, + Picker: &picker{err: fmt.Errorf("error creating connection: %v", err)}, + }) + return balancer.ErrBadResolverState + } + b.subConn = subConn + b.state = connectivity.Idle + b.cc.UpdateState(balancer.State{ + ConnectivityState: connectivity.Idle, + Picker: &picker{result: balancer.PickResult{SubConn: b.subConn}}, + }) + b.subConn.Connect() + return nil +} + +func (b *pickfirstBalancer) UpdateSubConnState(subConn balancer.SubConn, state balancer.SubConnState) { + if logger.V(2) { + logger.Infof("pickfirstBalancer: UpdateSubConnState: %p, %v", subConn, state) + } + if b.subConn != subConn { + if logger.V(2) { + logger.Infof("pickfirstBalancer: ignored state change because subConn is not recognized") + } + return + } + b.state = state.ConnectivityState + if state.ConnectivityState == connectivity.Shutdown { + b.subConn = nil + return + } + + switch state.ConnectivityState { + case connectivity.Ready: + b.cc.UpdateState(balancer.State{ + ConnectivityState: state.ConnectivityState, + Picker: &picker{result: balancer.PickResult{SubConn: subConn}}, + }) + case connectivity.Connecting: + b.cc.UpdateState(balancer.State{ + ConnectivityState: state.ConnectivityState, + Picker: &picker{err: balancer.ErrNoSubConnAvailable}, + }) + case connectivity.Idle: + b.cc.UpdateState(balancer.State{ + ConnectivityState: state.ConnectivityState, + Picker: &idlePicker{subConn: subConn}, + }) + case connectivity.TransientFailure: + b.cc.UpdateState(balancer.State{ + ConnectivityState: state.ConnectivityState, + Picker: &picker{err: state.ConnectionError}, + }) + } +} + +func (b *pickfirstBalancer) Close() { +} + +func (b *pickfirstBalancer) ExitIdle() { + if b.subConn != nil && b.state == connectivity.Idle { + b.subConn.Connect() + } +} + +type picker struct { + result balancer.PickResult + err error +} + +func (p *picker) Pick(balancer.PickInfo) (balancer.PickResult, error) { + return p.result, p.err +} + +// idlePicker is used when the SubConn is IDLE and kicks the SubConn into +// CONNECTING when Pick is called. +type idlePicker struct { + subConn balancer.SubConn +} + +func (i *idlePicker) Pick(balancer.PickInfo) (balancer.PickResult, error) { + i.subConn.Connect() + return balancer.PickResult{}, balancer.ErrNoSubConnAvailable +} + +// Intentionally removed +// func init() { +// balancer.Register(newPickfirstBuilder()) +// } diff --git a/agent/grpc-internal/client.go b/agent/grpc-internal/client.go index 7113105384e8..9a1e8402a767 100644 --- a/agent/grpc-internal/client.go +++ b/agent/grpc-internal/client.go @@ -8,9 +8,13 @@ import ( "time" "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/keepalive" "github.com/armon/go-metrics" + + _ "github.com/hashicorp/consul/agent/grpc-internal/balancer" + agentmiddleware "github.com/hashicorp/consul/agent/grpc-middleware" "github.com/hashicorp/consul/agent/metadata" "github.com/hashicorp/consul/agent/pool" @@ -128,12 +132,11 @@ func (c *ClientConnPool) dial(datacenter string, serverType string) (*grpc.Clien target, // use WithInsecure mode here because we handle the TLS wrapping in the // custom dialer based on logic around whether the server has TLS enabled. - grpc.WithInsecure(), + grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithContextDialer(c.dialer), grpc.WithDisableRetry(), grpc.WithStatsHandler(agentmiddleware.NewStatsHandler(metrics.Default(), metricsLabels)), - // nolint:staticcheck // there is no other supported alternative to WithBalancerName - grpc.WithBalancerName("pick_first"), + grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"pick_first_custom"}`), // Keep alive parameters are based on the same default ones we used for // Yamux. These are somewhat arbitrary but we did observe in scale testing // that the gRPC defaults (servers send keepalives only every 2 hours, @@ -148,7 +151,9 @@ func (c *ClientConnPool) dial(datacenter string, serverType string) (*grpc.Clien grpc.WithKeepaliveParams(keepalive.ClientParameters{ Time: 30 * time.Second, Timeout: 10 * time.Second, - })) + }), + grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(8*1024*1024), grpc.MaxCallRecvMsgSize(8*1024*1024)), + ) if err != nil { return nil, err } diff --git a/agent/grpc-internal/client_test.go b/agent/grpc-internal/client_test.go index d9d264d80303..ce4b6b41a51c 100644 --- a/agent/grpc-internal/client_test.go +++ b/agent/grpc-internal/client_test.go @@ -33,8 +33,8 @@ func TestNewDialer_WithTLSWrapper(t *testing.T) { require.NoError(t, err) t.Cleanup(logError(t, lis.Close)) - builder := resolver.NewServerResolverBuilder(newConfig(t)) - builder.AddServer(types.AreaWAN, &metadata.Server{ + builder := resolver.NewServerResolverBuilder(newConfig(t, "dc1", "server")) + builder.AddServer(types.AreaLAN, &metadata.Server{ Name: "server-1", ID: "ID1", Datacenter: "dc1", @@ -84,7 +84,7 @@ func TestNewDialer_WithALPNWrapper(t *testing.T) { p.Wait() }() - builder := resolver.NewServerResolverBuilder(newConfig(t)) + builder := resolver.NewServerResolverBuilder(newConfig(t, "dc1", "server")) builder.AddServer(types.AreaWAN, &metadata.Server{ Name: "server-1", ID: "ID1", @@ -92,6 +92,13 @@ func TestNewDialer_WithALPNWrapper(t *testing.T) { Addr: lis1.Addr(), UseTLS: true, }) + builder.AddServer(types.AreaLAN, &metadata.Server{ + Name: "server-1", + ID: "ID1", + Datacenter: "dc1", + Addr: lis1.Addr(), + UseTLS: true, + }) builder.AddServer(types.AreaWAN, &metadata.Server{ Name: "server-2", ID: "ID2", @@ -139,7 +146,7 @@ func TestNewDialer_WithALPNWrapper(t *testing.T) { func TestNewDialer_IntegrationWithTLSEnabledHandler(t *testing.T) { // if this test is failing because of expired certificates // use the procedure in test/CA-GENERATION.md - res := resolver.NewServerResolverBuilder(newConfig(t)) + res := resolver.NewServerResolverBuilder(newConfig(t, "dc1", "server")) registerWithGRPC(t, res) tlsConf, err := tlsutil.NewConfigurator(tlsutil.Config{ @@ -156,9 +163,17 @@ func TestNewDialer_IntegrationWithTLSEnabledHandler(t *testing.T) { srv := newSimpleTestServer(t, "server-1", "dc1", tlsConf) md := srv.Metadata() - res.AddServer(types.AreaWAN, md) + res.AddServer(types.AreaLAN, md) t.Cleanup(srv.shutdown) + { + // Put a duplicate instance of this on the WAN that will + // fail if we accidentally use it. + srv := newPanicTestServer(t, hclog.Default(), "server-1", "dc1", nil) + res.AddServer(types.AreaWAN, srv.Metadata()) + t.Cleanup(srv.shutdown) + } + pool := NewClientConnPool(ClientConnPoolConfig{ Servers: res, TLSWrapper: TLSWrapper(tlsConf.OutgoingRPCWrapper()), @@ -186,7 +201,7 @@ func TestNewDialer_IntegrationWithTLSEnabledHandler_viaMeshGateway(t *testing.T) // use the procedure in test/CA-GENERATION.md gwAddr := ipaddr.FormatAddressPort("127.0.0.1", freeport.GetOne(t)) - res := resolver.NewServerResolverBuilder(newConfig(t)) + res := resolver.NewServerResolverBuilder(newConfig(t, "dc2", "server")) registerWithGRPC(t, res) tlsConf, err := tlsutil.NewConfigurator(tlsutil.Config{ @@ -261,7 +276,7 @@ func TestNewDialer_IntegrationWithTLSEnabledHandler_viaMeshGateway(t *testing.T) func TestClientConnPool_IntegrationWithGRPCResolver_Failover(t *testing.T) { count := 4 - res := resolver.NewServerResolverBuilder(newConfig(t)) + res := resolver.NewServerResolverBuilder(newConfig(t, "dc1", "server")) registerWithGRPC(t, res) pool := NewClientConnPool(ClientConnPoolConfig{ Servers: res, @@ -272,9 +287,18 @@ func TestClientConnPool_IntegrationWithGRPCResolver_Failover(t *testing.T) { for i := 0; i < count; i++ { name := fmt.Sprintf("server-%d", i) - srv := newSimpleTestServer(t, name, "dc1", nil) - res.AddServer(types.AreaWAN, srv.Metadata()) - t.Cleanup(srv.shutdown) + { + srv := newSimpleTestServer(t, name, "dc1", nil) + res.AddServer(types.AreaLAN, srv.Metadata()) + t.Cleanup(srv.shutdown) + } + { + // Put a duplicate instance of this on the WAN that will + // fail if we accidentally use it. + srv := newPanicTestServer(t, hclog.Default(), name, "dc1", nil) + res.AddServer(types.AreaWAN, srv.Metadata()) + t.Cleanup(srv.shutdown) + } } conn, err := pool.ClientConn("dc1") @@ -287,7 +311,7 @@ func TestClientConnPool_IntegrationWithGRPCResolver_Failover(t *testing.T) { first, err := client.Something(ctx, &testservice.Req{}) require.NoError(t, err) - res.RemoveServer(types.AreaWAN, &metadata.Server{ID: first.ServerName, Datacenter: "dc1"}) + res.RemoveServer(types.AreaLAN, &metadata.Server{ID: first.ServerName, Datacenter: "dc1"}) resp, err := client.Something(ctx, &testservice.Req{}) require.NoError(t, err) @@ -296,7 +320,7 @@ func TestClientConnPool_IntegrationWithGRPCResolver_Failover(t *testing.T) { func TestClientConnPool_ForwardToLeader_Failover(t *testing.T) { count := 3 - res := resolver.NewServerResolverBuilder(newConfig(t)) + res := resolver.NewServerResolverBuilder(newConfig(t, "dc1", "server")) registerWithGRPC(t, res) pool := NewClientConnPool(ClientConnPoolConfig{ Servers: res, @@ -308,10 +332,19 @@ func TestClientConnPool_ForwardToLeader_Failover(t *testing.T) { var servers []testServer for i := 0; i < count; i++ { name := fmt.Sprintf("server-%d", i) - srv := newSimpleTestServer(t, name, "dc1", nil) - res.AddServer(types.AreaWAN, srv.Metadata()) - servers = append(servers, srv) - t.Cleanup(srv.shutdown) + { + srv := newSimpleTestServer(t, name, "dc1", nil) + res.AddServer(types.AreaLAN, srv.Metadata()) + servers = append(servers, srv) + t.Cleanup(srv.shutdown) + } + { + // Put a duplicate instance of this on the WAN that will + // fail if we accidentally use it. + srv := newPanicTestServer(t, hclog.Default(), name, "dc1", nil) + res.AddServer(types.AreaWAN, srv.Metadata()) + t.Cleanup(srv.shutdown) + } } // Set the leader address to the first server. @@ -338,16 +371,20 @@ func TestClientConnPool_ForwardToLeader_Failover(t *testing.T) { require.Equal(t, resp.ServerName, servers[1].name) } -func newConfig(t *testing.T) resolver.Config { +func newConfig(t *testing.T, dc, agentType string) resolver.Config { n := t.Name() s := strings.Replace(n, "/", "", -1) s = strings.Replace(s, "_", "", -1) - return resolver.Config{Authority: strings.ToLower(s)} + return resolver.Config{ + Datacenter: dc, + AgentType: agentType, + Authority: strings.ToLower(s), + } } func TestClientConnPool_IntegrationWithGRPCResolver_Rebalance(t *testing.T) { count := 5 - res := resolver.NewServerResolverBuilder(newConfig(t)) + res := resolver.NewServerResolverBuilder(newConfig(t, "dc1", "server")) registerWithGRPC(t, res) pool := NewClientConnPool(ClientConnPoolConfig{ Servers: res, @@ -359,8 +396,13 @@ func TestClientConnPool_IntegrationWithGRPCResolver_Rebalance(t *testing.T) { for i := 0; i < count; i++ { name := fmt.Sprintf("server-%d", i) srv := newSimpleTestServer(t, name, "dc1", nil) - res.AddServer(types.AreaWAN, srv.Metadata()) + res.AddServer(types.AreaLAN, srv.Metadata()) t.Cleanup(srv.shutdown) + // Put a duplicate instance of this on the WAN that will + // fail if we accidentally use it. + srvBad := newPanicTestServer(t, hclog.Default(), name, "dc1", nil) + res.AddServer(types.AreaWAN, srvBad.Metadata()) + t.Cleanup(srvBad.shutdown) } conn, err := pool.ClientConn("dc1") @@ -401,7 +443,7 @@ func TestClientConnPool_IntegrationWithGRPCResolver_Rebalance(t *testing.T) { func TestClientConnPool_IntegrationWithGRPCResolver_MultiDC(t *testing.T) { dcs := []string{"dc1", "dc2", "dc3"} - res := resolver.NewServerResolverBuilder(newConfig(t)) + res := resolver.NewServerResolverBuilder(newConfig(t, "dc1", "server")) registerWithGRPC(t, res) pool := NewClientConnPool(ClientConnPoolConfig{ Servers: res, @@ -413,7 +455,16 @@ func TestClientConnPool_IntegrationWithGRPCResolver_MultiDC(t *testing.T) { for _, dc := range dcs { name := "server-0-" + dc srv := newSimpleTestServer(t, name, dc, nil) - res.AddServer(types.AreaWAN, srv.Metadata()) + if dc == "dc1" { + res.AddServer(types.AreaLAN, srv.Metadata()) + // Put a duplicate instance of this on the WAN that will + // fail if we accidentally use it. + srvBad := newPanicTestServer(t, hclog.Default(), name, dc, nil) + res.AddServer(types.AreaWAN, srvBad.Metadata()) + t.Cleanup(srvBad.shutdown) + } else { + res.AddServer(types.AreaWAN, srv.Metadata()) + } t.Cleanup(srv.shutdown) } diff --git a/agent/grpc-internal/handler_test.go b/agent/grpc-internal/handler_test.go index 4f093ac65ee1..109a2cc60082 100644 --- a/agent/grpc-internal/handler_test.go +++ b/agent/grpc-internal/handler_test.go @@ -26,11 +26,11 @@ func TestHandler_PanicRecoveryInterceptor(t *testing.T) { Output: &buf, }) - res := resolver.NewServerResolverBuilder(newConfig(t)) + res := resolver.NewServerResolverBuilder(newConfig(t, "dc1", "server")) registerWithGRPC(t, res) srv := newPanicTestServer(t, logger, "server-1", "dc1", nil) - res.AddServer(types.AreaWAN, srv.Metadata()) + res.AddServer(types.AreaLAN, srv.Metadata()) t.Cleanup(srv.shutdown) pool := NewClientConnPool(ClientConnPoolConfig{ diff --git a/agent/grpc-internal/resolver/registry.go b/agent/grpc-internal/resolver/registry.go index 14c93af2d147..582103b9eaee 100644 --- a/agent/grpc-internal/resolver/registry.go +++ b/agent/grpc-internal/resolver/registry.go @@ -19,8 +19,10 @@ type registry struct { func (r *registry) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) { r.lock.RLock() defer r.lock.RUnlock() + //nolint:staticcheck res, ok := r.byAuthority[target.Authority] if !ok { + //nolint:staticcheck return nil, fmt.Errorf("no resolver registered for %v", target.Authority) } return res.Build(target, cc, opts) diff --git a/agent/grpc-internal/resolver/resolver.go b/agent/grpc-internal/resolver/resolver.go index c0c3b8938abb..9e4f73ff67d5 100644 --- a/agent/grpc-internal/resolver/resolver.go +++ b/agent/grpc-internal/resolver/resolver.go @@ -17,25 +17,45 @@ import ( // ServerResolvers updated when changes occur. type ServerResolverBuilder struct { cfg Config + // leaderResolver is used to track the address of the leader in the local DC. leaderResolver leaderResolver + // servers is an index of Servers by area and Server.ID. The map contains server IDs // for all datacenters. servers map[types.AreaID]map[string]*metadata.Server + // resolvers is an index of connections to the serverResolver which manages // addresses of servers for that connection. + // + // this is only applicable for non-leader conn types resolvers map[resolver.ClientConn]*serverResolver + // lock for all stateful fields (excludes config which is immutable). lock sync.RWMutex } type Config struct { + // Datacenter is the datacenter of this agent. + Datacenter string + + // AgentType is either 'server' or 'client' and is required. + AgentType string + // Authority used to query the server. Defaults to "". Used to support // parallel testing because gRPC registers resolvers globally. Authority string } func NewServerResolverBuilder(cfg Config) *ServerResolverBuilder { + if cfg.Datacenter == "" { + panic("ServerResolverBuilder needs Config.Datacenter to be nonempty") + } + switch cfg.AgentType { + case "server", "client": + default: + panic("ServerResolverBuilder needs Config.AgentType to be either server or client") + } return &ServerResolverBuilder{ cfg: cfg, servers: make(map[types.AreaID]map[string]*metadata.Server), @@ -80,6 +100,7 @@ func (s *ServerResolverBuilder) ServerForGlobalAddr(globalAddr string) (*metadat } } } + return nil, fmt.Errorf("failed to find Consul server for global address %q", globalAddr) } @@ -91,13 +112,14 @@ func (s *ServerResolverBuilder) Build(target resolver.Target, cc resolver.Client // If there's already a resolver for this connection, return it. // TODO(streaming): how would this happen since we already cache connections in ClientConnPool? - if resolver, ok := s.resolvers[cc]; ok { - return resolver, nil - } if cc == s.leaderResolver.clientConn { return s.leaderResolver, nil } + if resolver, ok := s.resolvers[cc]; ok { + return resolver, nil + } + //nolint:staticcheck serverType, datacenter, err := parseEndpoint(target.Endpoint) if err != nil { return nil, err @@ -142,6 +164,10 @@ func (s *ServerResolverBuilder) Authority() string { // AddServer updates the resolvers' states to include the new server's address. func (s *ServerResolverBuilder) AddServer(areaID types.AreaID, server *metadata.Server) { + if s.shouldIgnoreServer(areaID, server) { + return + } + s.lock.Lock() defer s.lock.Unlock() @@ -178,6 +204,10 @@ func DCPrefix(datacenter, suffix string) string { // RemoveServer updates the resolvers' states with the given server removed. func (s *ServerResolverBuilder) RemoveServer(areaID types.AreaID, server *metadata.Server) { + if s.shouldIgnoreServer(areaID, server) { + return + } + s.lock.Lock() defer s.lock.Unlock() @@ -199,14 +229,48 @@ func (s *ServerResolverBuilder) RemoveServer(areaID types.AreaID, server *metada } } +// shouldIgnoreServer is used to contextually decide if a particular kind of +// server should be accepted into a given area. +// +// On client agents it's pretty easy: clients only participate in the standard +// LAN, so we only accept servers from the LAN. +// +// On server agents it's a little less obvious. This resolver is ultimately +// used to have servers dial other servers. If a server is going to cross +// between datacenters (using traditional federation) then we want to use the +// WAN addresses for them, but if a server is going to dial a sibling server in +// the same datacenter we want it to use the LAN addresses always. To achieve +// that here we simply never allow WAN servers for our current datacenter to be +// added into the resolver, letting only the LAN instances through. +func (s *ServerResolverBuilder) shouldIgnoreServer(areaID types.AreaID, server *metadata.Server) bool { + if s.cfg.AgentType == "client" && areaID != types.AreaLAN { + return true + } + + if s.cfg.AgentType == "server" && + server.Datacenter == s.cfg.Datacenter && + areaID != types.AreaLAN { + return true + } + + return false +} + // getDCAddrs returns a list of the server addresses for the given datacenter. // This method requires that lock is held for reads. func (s *ServerResolverBuilder) getDCAddrs(dc string) []resolver.Address { + lanRequest := (s.cfg.Datacenter == dc) + var ( addrs []resolver.Address keptServerIDs = make(map[string]struct{}) ) - for _, areaServers := range s.servers { + for areaID, areaServers := range s.servers { + if (areaID == types.AreaLAN) != lanRequest { + // LAN requests only look at LAN data. WAN requests only look at + // WAN data. + continue + } for _, server := range areaServers { if server.Datacenter != dc { continue @@ -270,21 +334,7 @@ func (r *serverResolver) updateAddrs(addrs []resolver.Address) { // updateAddrsLocked updates this serverResolver's ClientConn to use the given // set of addrs. addrLock must be held by caller. func (r *serverResolver) updateAddrsLocked(addrs []resolver.Address) { - // Only pass the first address initially, which will cause the - // balancer to spin down the connection for its previous first address - // if it is different. If we don't do this, it will keep using the old - // first address as long as it is still in the list, making it impossible to - // rebalance until that address is removed. - var firstAddr []resolver.Address - if len(addrs) > 0 { - firstAddr = []resolver.Address{addrs[0]} - } - r.clientConn.UpdateState(resolver.State{Addresses: firstAddr}) - - // Call UpdateState again with the entire list of addrs in case we need them - // for failover. r.clientConn.UpdateState(resolver.State{Addresses: addrs}) - r.addrs = addrs } diff --git a/agent/grpc-internal/resolver/resolver_test.go b/agent/grpc-internal/resolver/resolver_test.go new file mode 100644 index 000000000000..ab6e403d7dee --- /dev/null +++ b/agent/grpc-internal/resolver/resolver_test.go @@ -0,0 +1,195 @@ +package resolver + +import ( + "fmt" + "net" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/resolver" + "google.golang.org/grpc/serviceconfig" + + "github.com/hashicorp/consul/agent/metadata" + "github.com/hashicorp/consul/types" +) + +func TestServerResolverBuilder(t *testing.T) { + const agentDC = "dc1" + + type testcase struct { + name string + agentType string // server/client + serverType string // server/leader + requestDC string + expectLAN bool + } + + run := func(t *testing.T, tc testcase) { + rs := NewServerResolverBuilder(newConfig(t, agentDC, tc.agentType)) + + endpoint := "" + if tc.serverType == "leader" { + endpoint = "leader.local" + } else { + endpoint = tc.serverType + "." + tc.requestDC + } + + cc := &fakeClientConn{} + _, err := rs.Build(resolver.Target{ + Scheme: "consul", + Authority: rs.Authority(), + Endpoint: endpoint, + }, cc, resolver.BuildOptions{}) + require.NoError(t, err) + + for i := 0; i < 3; i++ { + dc := fmt.Sprintf("dc%d", i+1) + for j := 0; j < 3; j++ { + wanIP := fmt.Sprintf("127.1.%d.%d", i+1, j+10) + name := fmt.Sprintf("%s-server-%d", dc, j+1) + wanMeta := newServerMeta(name, dc, wanIP, true) + + if tc.agentType == "server" { + rs.AddServer(types.AreaWAN, wanMeta) + } + + if dc == agentDC { + // register LAN/WAN pairs for the same instances + lanIP := fmt.Sprintf("127.0.%d.%d", i+1, j+10) + lanMeta := newServerMeta(name, dc, lanIP, false) + rs.AddServer(types.AreaLAN, lanMeta) + + if j == 0 { + rs.UpdateLeaderAddr(dc, lanIP) + } + } + } + } + + if tc.serverType == "leader" { + assert.Len(t, cc.state.Addresses, 1) + } else { + assert.Len(t, cc.state.Addresses, 3) + } + + for _, addr := range cc.state.Addresses { + addrPrefix := tc.requestDC + "-" + if tc.expectLAN { + addrPrefix += "127.0." + } else { + addrPrefix += "127.1." + } + assert.True(t, strings.HasPrefix(addr.Addr, addrPrefix), + "%q does not start with %q (returned WAN for LAN request)", addr.Addr, addrPrefix) + + if tc.expectLAN { + assert.False(t, strings.Contains(addr.ServerName, ".dc"), + "%q ends with datacenter suffix (returned WAN for LAN request)", addr.ServerName) + } else { + assert.True(t, strings.HasSuffix(addr.ServerName, "."+tc.requestDC), + "%q does not end with %q", addr.ServerName, "."+tc.requestDC) + } + } + } + + cases := []testcase{ + { + name: "server requesting local servers", + agentType: "server", + serverType: "server", + requestDC: agentDC, + expectLAN: true, + }, + { + name: "server requesting remote servers in dc2", + agentType: "server", + serverType: "server", + requestDC: "dc2", + expectLAN: false, + }, + { + name: "server requesting remote servers in dc3", + agentType: "server", + serverType: "server", + requestDC: "dc3", + expectLAN: false, + }, + // --------------- + { + name: "server requesting local leader", + agentType: "server", + serverType: "leader", + requestDC: agentDC, + expectLAN: true, + }, + // --------------- + { + name: "client requesting local server", + agentType: "client", + serverType: "server", + requestDC: agentDC, + expectLAN: true, + }, + { + name: "client requesting local leader", + agentType: "client", + serverType: "leader", + requestDC: agentDC, + expectLAN: true, + }, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + run(t, tc) + }) + } +} + +func newServerMeta(name, dc, ip string, wan bool) *metadata.Server { + fullname := name + if wan { + fullname = name + "." + dc + } + return &metadata.Server{ + ID: name, + Name: fullname, + ShortName: name, + Datacenter: dc, + Addr: &net.IPAddr{IP: net.ParseIP(ip)}, + UseTLS: false, + } +} + +func newConfig(t *testing.T, dc, agentType string) Config { + n := t.Name() + s := strings.Replace(n, "/", "", -1) + s = strings.Replace(s, "_", "", -1) + return Config{ + Datacenter: dc, + AgentType: agentType, + Authority: strings.ToLower(s), + } +} + +// fakeClientConn implements resolver.ClientConn for tests +type fakeClientConn struct { + state resolver.State +} + +var _ resolver.ClientConn = (*fakeClientConn)(nil) + +func (f *fakeClientConn) UpdateState(state resolver.State) error { + f.state = state + return nil +} + +func (*fakeClientConn) ReportError(error) {} +func (*fakeClientConn) NewAddress(addresses []resolver.Address) {} +func (*fakeClientConn) NewServiceConfig(serviceConfig string) {} +func (*fakeClientConn) ParseServiceConfig(serviceConfigJSON string) *serviceconfig.ParseResult { + return nil +} diff --git a/agent/grpc-internal/services/subscribe/subscribe_test.go b/agent/grpc-internal/services/subscribe/subscribe_test.go index c737b4d4a297..065b7354076d 100644 --- a/agent/grpc-internal/services/subscribe/subscribe_test.go +++ b/agent/grpc-internal/services/subscribe/subscribe_test.go @@ -40,6 +40,7 @@ func TestServer_Subscribe_SubjectIsRequired(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) t.Cleanup(cancel) + //nolint:staticcheck conn, err := gogrpc.DialContext(ctx, addr.String(), gogrpc.WithInsecure()) require.NoError(t, err) t.Cleanup(logError(t, conn.Close)) @@ -109,6 +110,7 @@ func TestServer_Subscribe_IntegrationWithBackend(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) t.Cleanup(cancel) + //nolint:staticcheck conn, err := gogrpc.DialContext(ctx, addr.String(), gogrpc.WithInsecure()) require.NoError(t, err) t.Cleanup(logError(t, conn.Close)) @@ -441,6 +443,7 @@ func TestServer_Subscribe_IntegrationWithBackend_ForwardToDC(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) t.Cleanup(cancel) + //nolint:staticcheck connRemoteDC, err := gogrpc.DialContext(ctx, addrRemoteDC.String(), gogrpc.WithInsecure()) require.NoError(t, err) t.Cleanup(logError(t, connRemoteDC.Close)) @@ -488,6 +491,7 @@ func TestServer_Subscribe_IntegrationWithBackend_ForwardToDC(t *testing.T) { require.NoError(t, backendRemoteDC.store.EnsureRegistration(ids.Next("reg3"), req)) }) + //nolint:staticcheck connLocal, err := gogrpc.DialContext(ctx, addrLocal.String(), gogrpc.WithInsecure()) require.NoError(t, err) t.Cleanup(logError(t, connLocal.Close)) @@ -749,6 +753,7 @@ node "node1" { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) t.Cleanup(cancel) + //nolint:staticcheck conn, err := gogrpc.DialContext(ctx, addr.String(), gogrpc.WithInsecure()) require.NoError(t, err) t.Cleanup(logError(t, conn.Close)) @@ -901,6 +906,7 @@ node "node1" { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) t.Cleanup(cancel) + //nolint:staticcheck conn, err := gogrpc.DialContext(ctx, addr.String(), gogrpc.WithInsecure()) require.NoError(t, err) t.Cleanup(logError(t, conn.Close)) diff --git a/agent/grpc-internal/stats_test.go b/agent/grpc-internal/stats_test.go index 8ded41dd8f13..a304de870e79 100644 --- a/agent/grpc-internal/stats_test.go +++ b/agent/grpc-internal/stats_test.go @@ -48,6 +48,7 @@ func TestHandler_EmitsStats(t *testing.T) { } }) + //nolint:staticcheck conn, err := grpc.DialContext(ctx, lis.Addr().String(), grpc.WithInsecure()) require.NoError(t, err) t.Cleanup(func() { conn.Close() }) diff --git a/agent/grpc-middleware/auth_interceptor.go b/agent/grpc-middleware/auth_interceptor.go new file mode 100644 index 000000000000..bc9082c75e1f --- /dev/null +++ b/agent/grpc-middleware/auth_interceptor.go @@ -0,0 +1,90 @@ +package middleware + +import ( + "context" + "fmt" + "strings" + + "github.com/hashicorp/consul/tlsutil" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/peer" + "google.golang.org/grpc/status" +) + +const AllowedPeerEndpointPrefix = "/hashicorp.consul.internal.peerstream.PeerStreamService/" + +// AuthInterceptor provides gRPC interceptors for restricting endpoint access based +// on SNI. If the connection is plaintext, this filter will not activate, and the +// connection will be allowed to proceed. +type AuthInterceptor struct { + TLS *tlsutil.Configurator + Logger Logger +} + +// InterceptUnary prevents non-streaming gRPC calls from calling certain endpoints, +// based on the SNI information. +func (a *AuthInterceptor) InterceptUnary( + ctx context.Context, + req interface{}, + info *grpc.UnaryServerInfo, + handler grpc.UnaryHandler, +) (interface{}, error) { + p, ok := peer.FromContext(ctx) + if !ok { + return nil, fmt.Errorf("unable to fetch peer info from grpc context") + } + err := restrictPeeringEndpoints(p.AuthInfo, a.TLS.PeeringServerName(), info.FullMethod) + if err != nil { + return nil, err + } + return handler(ctx, req) +} + +// InterceptUnary prevents streaming gRPC calls from calling certain endpoints, +// based on the SNI information. +func (a *AuthInterceptor) InterceptStream( + srv interface{}, + ss grpc.ServerStream, + info *grpc.StreamServerInfo, + handler grpc.StreamHandler, +) error { + p, ok := peer.FromContext(ss.Context()) + if !ok { + return fmt.Errorf("unable to fetch peer info from grpc context") + } + err := restrictPeeringEndpoints(p.AuthInfo, a.TLS.PeeringServerName(), info.FullMethod) + if err != nil { + return err + } + return handler(srv, ss) +} + +// restrictPeeringEndpoints will return an error if a peering TLS connection attempts to call +// a non-peering endpoint. This is necessary, because the peer streaming workflow does not +// present a mutual TLS certificate, and is allowed to bypass the `tls.grpc.verify_incoming` +// check as a special case. See the `tlsutil.Configurator` for this bypass. +func restrictPeeringEndpoints(authInfo credentials.AuthInfo, peeringSNI string, endpoint string) error { + // No peering connection has been configured + if peeringSNI == "" { + return nil + } + // This indicates a plaintext connection. + if authInfo == nil { + return nil + } + // Otherwise attempt to check the AuthInfo for TLS credentials. + tlsAuth, ok := authInfo.(credentials.TLSInfo) + if !ok { + return status.Error(codes.Unauthenticated, "invalid transport credentials") + } + + if tlsAuth.State.ServerName == peeringSNI { + // Prevent any calls, except those in the PeerStreamService + if !strings.HasPrefix(endpoint, AllowedPeerEndpointPrefix) { + return status.Error(codes.PermissionDenied, "invalid permissions to the specified endpoint") + } + } + return nil +} diff --git a/agent/grpc-middleware/auth_interceptor_test.go b/agent/grpc-middleware/auth_interceptor_test.go new file mode 100644 index 000000000000..512d5ed5501f --- /dev/null +++ b/agent/grpc-middleware/auth_interceptor_test.go @@ -0,0 +1,87 @@ +package middleware + +import ( + "crypto/tls" + "testing" + + "github.com/stretchr/testify/require" + "google.golang.org/grpc/credentials" +) + +type invalidAuthInfo struct{} + +func (i invalidAuthInfo) AuthType() string { + return "invalid." +} + +func TestGRPCMiddleware_restrictPeeringEndpoints(t *testing.T) { + + tests := []struct { + name string + authInfo credentials.AuthInfo + peeringSNI string + endpoint string + expectErr string + }{ + { + name: "plaintext_always_allowed", + authInfo: nil, + peeringSNI: "expected-server-sni", + endpoint: "/hashicorp.consul.internal.peerstream.PeerStreamService/SomeEndpoint", + }, + { + name: "peering_not_enabled", + authInfo: nil, + peeringSNI: "", + endpoint: "/hashicorp.consul.internal.peerstream.PeerStreamService/SomeEndpoint", + }, + { + name: "deny_invalid_credentials", + authInfo: invalidAuthInfo{}, + peeringSNI: "expected-server-sni", + expectErr: "invalid transport credentials", + }, + { + name: "peering_sni_with_invalid_endpoint", + authInfo: credentials.TLSInfo{ + State: tls.ConnectionState{ + ServerName: "peering-sni", + }, + }, + peeringSNI: "peering-sni", + endpoint: "/some-invalid-endpoint", + expectErr: "invalid permissions to the specified endpoint", + }, + { + name: "peering_sni_with_valid_endpoint", + authInfo: credentials.TLSInfo{ + State: tls.ConnectionState{ + ServerName: "peering-sni", + }, + }, + peeringSNI: "peering-sni", + endpoint: "/hashicorp.consul.internal.peerstream.PeerStreamService/SomeEndpoint", + }, + { + name: "non_peering_sni_always_allowed", + authInfo: credentials.TLSInfo{ + State: tls.ConnectionState{ + ServerName: "non-peering-sni", + }, + }, + peeringSNI: "peering-sni", + endpoint: "/some-non-peering-endpoint", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + err := restrictPeeringEndpoints(tc.authInfo, tc.peeringSNI, tc.endpoint) + if tc.expectErr == "" { + require.NoError(t, err) + } else { + require.NotNil(t, err) + require.Contains(t, err.Error(), tc.expectErr) + } + }) + } +} diff --git a/agent/grpc-middleware/handshake.go b/agent/grpc-middleware/handshake.go new file mode 100644 index 000000000000..8fe4c2739ed8 --- /dev/null +++ b/agent/grpc-middleware/handshake.go @@ -0,0 +1,78 @@ +package middleware + +import ( + "fmt" + "net" + + "google.golang.org/grpc/credentials" +) + +var _ net.Listener = (*LabelledListener)(nil) +var _ net.Conn = (*LabelledConn)(nil) + +type Protocol int + +var ( + ProtocolPlaintext Protocol = 0 + ProtocolTLS Protocol = 1 +) + +// LabelledListener wraps a listener and attaches pre-specified +// fields to each spawned connection. +type LabelledListener struct { + net.Listener + Protocol Protocol +} + +func (l LabelledListener) Accept() (net.Conn, error) { + conn, err := l.Listener.Accept() + if conn != nil { + conn = LabelledConn{conn, l.Protocol} + } + return conn, err +} + +// LabelledConn wraps a connection and provides extra metadata fields. +type LabelledConn struct { + net.Conn + protocol Protocol +} + +var _ credentials.TransportCredentials = (*optionalTransportCredentials)(nil) + +// optionalTransportCredentials provides a way to selectively perform a TLS handshake +// based on metadata extracted from the underlying connection object. +type optionalTransportCredentials struct { + credentials.TransportCredentials + logger Logger +} + +func NewOptionalTransportCredentials(creds credentials.TransportCredentials, logger Logger) credentials.TransportCredentials { + return &optionalTransportCredentials{creds, logger} +} + +// ServerHandshake will attempt to detect the underlying connection protocol (TLS or Plaintext) +// based on metadata attached to the underlying connection. If TLS is detected, then a handshake +// will be performed, and the corresponding AuthInfo will be attached to the gRPC context. +// For plaintext connections, this is effectively a no-op, since there is no TLS info to attach. +// If the underlying connection is not a LabelledConn with a valid protocol, then this method will +// panic and prevent the gRPC connection from successfully progressing further. +func (tc *optionalTransportCredentials) ServerHandshake(conn net.Conn) (net.Conn, credentials.AuthInfo, error) { + // This should always be a LabelledConn, so no check is necessary. + nc := conn.(LabelledConn) + switch nc.protocol { + case ProtocolPlaintext: + // This originated from a plaintext listener, so do not use TLS auth. + return nc, nil, nil + case ProtocolTLS: + // This originated from a TLS listener, so it should have a full handshake performed. + c, ai, err := tc.TransportCredentials.ServerHandshake(conn) + if err == nil && ai == nil { + // This should not be possible, but ensure that it's non-nil for safety. + return nil, nil, fmt.Errorf("missing auth info after handshake") + } + return c, ai, err + default: + return nil, nil, fmt.Errorf("invalid protocol for grpc connection") + } +} diff --git a/agent/grpc-middleware/handshake_test.go b/agent/grpc-middleware/handshake_test.go new file mode 100644 index 000000000000..78f4f4f87a70 --- /dev/null +++ b/agent/grpc-middleware/handshake_test.go @@ -0,0 +1,84 @@ +package middleware + +import ( + "net" + "testing" + + "github.com/stretchr/testify/require" + "google.golang.org/grpc/credentials" +) + +type fakeTransportCredentials struct { + credentials.TransportCredentials + callback func(conn net.Conn) (net.Conn, credentials.AuthInfo, error) +} + +func (f fakeTransportCredentials) ServerHandshake(conn net.Conn) (net.Conn, credentials.AuthInfo, error) { + return f.callback(conn) +} + +func TestGRPCMiddleware_optionalTransportCredentials_ServerHandshake(t *testing.T) { + + plainConn := LabelledConn{protocol: ProtocolPlaintext} + tlsConn := LabelledConn{protocol: ProtocolTLS} + tests := []struct { + name string + conn net.Conn + callback func(conn net.Conn) (net.Conn, credentials.AuthInfo, error) + expectConn net.Conn + expectAuthInfo credentials.AuthInfo + expectErr string + }{ + { + name: "plaintext_noop", + conn: plainConn, + expectConn: plainConn, + expectAuthInfo: nil, + }, + { + name: "tls_with_missing_auth", + conn: tlsConn, + callback: func(conn net.Conn) (net.Conn, credentials.AuthInfo, error) { + return conn, nil, nil + }, + expectConn: nil, + expectAuthInfo: nil, + expectErr: "missing auth info after handshake", + }, + { + name: "tls_success", + conn: tlsConn, + callback: func(conn net.Conn) (net.Conn, credentials.AuthInfo, error) { + return conn, credentials.TLSInfo{}, nil + }, + expectConn: tlsConn, + expectAuthInfo: credentials.TLSInfo{}, + expectErr: "", + }, + { + name: "invalid_protocol", + conn: LabelledConn{protocol: -1}, + expectConn: nil, + expectAuthInfo: nil, + expectErr: "invalid protocol for grpc connection", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + creds := optionalTransportCredentials{ + TransportCredentials: fakeTransportCredentials{ + callback: tc.callback, + }, + } + conn, authInfo, err := creds.ServerHandshake(tc.conn) + require.Equal(t, tc.expectConn, conn) + require.Equal(t, tc.expectAuthInfo, authInfo) + if tc.expectErr == "" { + require.NoError(t, err) + } else { + require.Error(t, err) + require.Contains(t, err.Error(), tc.expectErr) + } + }) + } +} diff --git a/agent/hcp/bootstrap/bootstrap.go b/agent/hcp/bootstrap/bootstrap.go index 3de7de435032..e09146926d92 100644 --- a/agent/hcp/bootstrap/bootstrap.go +++ b/agent/hcp/bootstrap/bootstrap.go @@ -7,27 +7,34 @@ package bootstrap import ( "bufio" "context" + "crypto/tls" + "crypto/x509" "encoding/json" + "encoding/pem" "errors" "fmt" - "io/ioutil" "os" "path/filepath" "strings" "time" "github.com/hashicorp/consul/agent/config" + "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/hcp" "github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/lib/retry" + "github.com/hashicorp/go-uuid" ) const ( - caFileName = "server-tls-cas.pem" - certFileName = "server-tls-cert.pem" - keyFileName = "server-tls-key.pem" - configFileName = "server-config.json" - subDir = "hcp-config" + subDir = "hcp-config" + + caFileName = "server-tls-cas.pem" + certFileName = "server-tls-cert.pem" + configFileName = "server-config.json" + keyFileName = "server-tls-key.pem" + tokenFileName = "hcp-management-token" + successFileName = "successful-bootstrap" ) type ConfigLoader func(source config.Source) (config.LoadResult, error) @@ -44,44 +51,80 @@ type UI interface { Error(string) } -// MaybeBootstrap will use the passed ConfigLoader to read the existing -// configuration, and if required attempt to bootstrap from HCP. It will retry -// until successful or a terminal error condition is found (e.g. permission -// denied). It must be passed a (CLI) UI implementation so it can deliver progress -// updates to the user, for example if it is waiting to retry for a long period. -func MaybeBootstrap(ctx context.Context, loader ConfigLoader, ui UI) (bool, ConfigLoader, error) { - loader = wrapConfigLoader(loader) - res, err := loader(nil) - if err != nil { - return false, nil, err - } - - // Check to see if this is a server and HCP is configured - - if !res.RuntimeConfig.IsCloudEnabled() { - // Not a server, let agent continue unmodified - return false, loader, nil - } +// RawBootstrapConfig contains the Consul config as a raw JSON string and the management token +// which either was retrieved from persisted files or from the bootstrap endpoint +type RawBootstrapConfig struct { + ConfigJSON string + ManagementToken string +} - ui.Output("Bootstrapping configuration from HCP") +// LoadConfig will attempt to load previously-fetched config from disk and fall back to +// fetch from HCP servers if the local data is incomplete. +// It must be passed a (CLI) UI implementation so it can deliver progress +// updates to the user, for example if it is waiting to retry for a long period. +func LoadConfig(ctx context.Context, client hcp.Client, dataDir string, loader ConfigLoader, ui UI) (ConfigLoader, error) { + ui.Output("Loading configuration from HCP") // See if we have existing config on disk - cfgJSON, ok := loadPersistedBootstrapConfig(res.RuntimeConfig, ui) - + // + // OPTIMIZE: We could probably be more intelligent about config loading. + // The currently implemented approach is: + // 1. Attempt to load data from disk + // 2. If that fails or the data is incomplete, block indefinitely fetching remote config. + // + // What if instead we had the following flow: + // 1. Attempt to fetch config from HCP. + // 2. If that fails, fall back to data on disk from last fetch. + // 3. If that fails, go into blocking loop to fetch remote config. + // + // This should allow us to more gracefully transition cases like when + // an existing cluster is linked, but then wants to receive TLS materials + // at a later time. Currently, if we observe the existing-cluster marker we + // don't attempt to fetch any additional configuration from HCP. + + cfg, ok := loadPersistedBootstrapConfig(dataDir, ui) if !ok { - // Fetch from HCP - ui.Info("Fetching configuration from HCP") - cfgJSON, err = doHCPBootstrap(ctx, res.RuntimeConfig, ui) + ui.Info("Fetching configuration from HCP servers") + + var err error + cfg, err = fetchBootstrapConfig(ctx, client, dataDir, ui) if err != nil { - return false, nil, fmt.Errorf("failed to bootstrap from HCP: %w", err) + return nil, fmt.Errorf("failed to bootstrap from HCP: %w", err) } ui.Info("Configuration fetched from HCP and saved on local disk") + } else { - ui.Info("Loaded configuration from local disk") + ui.Info("Loaded HCP configuration from local disk") + } // Create a new loader func to return - newLoader := func(source config.Source) (config.LoadResult, error) { + newLoader := bootstrapConfigLoader(loader, cfg) + return newLoader, nil +} + +// bootstrapConfigLoader is a ConfigLoader for passing bootstrap JSON config received from HCP +// to the config.builder. ConfigLoaders are functions used to build an agent's RuntimeConfig +// from various sources like files and flags. This config is contained in the config.LoadResult. +// +// The flow to include bootstrap config from HCP as a loader's data source is as follows: +// +// 1. A base ConfigLoader function (baseLoader) is created on agent start, and it sets the input +// source argument as the DefaultConfig. +// +// 2. When a server agent can be configured by HCP that baseLoader is wrapped in this bootstrapConfigLoader. +// +// 3. The bootstrapConfigLoader calls that base loader with the bootstrap JSON config as the +// default source. This data will be merged with other valid sources in the config.builder. +// +// 4. The result of the call to baseLoader() below contains the resulting RuntimeConfig, and we do some +// additional modifications to attach data that doesn't get populated during the build in the config pkg. +// +// Note that since the ConfigJSON is stored as the baseLoader's DefaultConfig, its data is the first +// to be merged by the config.builder and could be overwritten by user-provided values in config files or +// CLI flags. However, values set to RuntimeConfig after the baseLoader call are final. +func bootstrapConfigLoader(baseLoader ConfigLoader, cfg *RawBootstrapConfig) ConfigLoader { + return func(source config.Source) (config.LoadResult, error) { // Don't allow any further attempts to provide a DefaultSource. This should // only ever be needed later in client agent AutoConfig code but that should // be mutually exclusive from this bootstrapping mechanism since this is @@ -92,34 +135,50 @@ func MaybeBootstrap(ctx context.Context, loader ConfigLoader, ui UI) (bool, Conf return config.LoadResult{}, fmt.Errorf("non-nil config source provided to a loader after HCP bootstrap already provided a DefaultSource") } + // Otherwise, just call to the loader we were passed with our own additional // JSON as the source. - s := config.FileSource{ + // + // OPTIMIZE: We could check/log whether any fields set by the remote config were overwritten by a user-provided flag. + res, err := baseLoader(config.FileSource{ Name: "HCP Bootstrap", Format: "json", - Data: cfgJSON, + Data: cfg.ConfigJSON, + }) + if err != nil { + return res, fmt.Errorf("failed to load HCP Bootstrap config: %w", err) } - return loader(s) - } - return true, newLoader, nil + finalizeRuntimeConfig(res.RuntimeConfig, cfg) + return res, nil + } } -func wrapConfigLoader(loader ConfigLoader) ConfigLoader { - return func(source config.Source) (config.LoadResult, error) { - res, err := loader(source) - if err != nil { - return res, err - } +const ( + accessControlHeaderName = "Access-Control-Expose-Headers" + accessControlHeaderValue = "x-consul-default-acl-policy" +) - if res.RuntimeConfig.Cloud.ResourceID == "" { - res.RuntimeConfig.Cloud.ResourceID = os.Getenv("HCP_RESOURCE_ID") - } - return res, nil +// finalizeRuntimeConfig will set additional HCP-specific values that are not +// handled by the config.builder. +func finalizeRuntimeConfig(rc *config.RuntimeConfig, cfg *RawBootstrapConfig) { + rc.Cloud.ManagementToken = cfg.ManagementToken + + // HTTP response headers are modified for the HCP UI to work. + if rc.HTTPResponseHeaders == nil { + rc.HTTPResponseHeaders = make(map[string]string) + } + prevValue, ok := rc.HTTPResponseHeaders[accessControlHeaderName] + if !ok { + rc.HTTPResponseHeaders[accessControlHeaderName] = accessControlHeaderValue + } else { + rc.HTTPResponseHeaders[accessControlHeaderName] = prevValue + "," + accessControlHeaderValue } } -func doHCPBootstrap(ctx context.Context, rc *config.RuntimeConfig, ui UI) (string, error) { +// fetchBootstrapConfig will fetch boostrap configuration from remote servers and persist it to disk. +// It will retry until successful or a terminal error condition is found (e.g. permission denied). +func fetchBootstrapConfig(ctx context.Context, client hcp.Client, dataDir string, ui UI) (*RawBootstrapConfig, error) { w := retry.Waiter{ MinWait: 1 * time.Second, MaxWait: 5 * time.Minute, @@ -127,12 +186,6 @@ func doHCPBootstrap(ctx context.Context, rc *config.RuntimeConfig, ui UI) (strin } var bsCfg *hcp.BootstrapConfig - - client, err := hcp.NewClient(rc.Cloud) - if err != nil { - return "", err - } - for { // Note we don't want to shadow `ctx` here since we need that for the Wait // below. @@ -141,10 +194,10 @@ func doHCPBootstrap(ctx context.Context, rc *config.RuntimeConfig, ui UI) (strin resp, err := client.FetchBootstrap(reqCtx) if err != nil { - ui.Error(fmt.Sprintf("failed to fetch bootstrap config from HCP, will retry in %s: %s", + ui.Error(fmt.Sprintf("Error: failed to fetch bootstrap config from HCP, will retry in %s: %s", w.NextWait().Round(time.Second), err)) if err := w.Wait(ctx); err != nil { - return "", err + return nil, err } // Finished waiting, restart loop continue @@ -153,9 +206,24 @@ func doHCPBootstrap(ctx context.Context, rc *config.RuntimeConfig, ui UI) (strin break } - dataDir := rc.DataDir - shouldPersist := true - if dataDir == "" { + devMode := dataDir == "" + + cfgJSON, err := persistAndProcessConfig(dataDir, devMode, bsCfg) + if err != nil { + return nil, fmt.Errorf("failed to persist config for existing cluster: %w", err) + } + + return &RawBootstrapConfig{ + ConfigJSON: cfgJSON, + ManagementToken: bsCfg.ManagementToken, + }, nil +} + +// persistAndProcessConfig is called when we receive data from CCM. +// We validate and persist everything that was received, then also update +// the JSON config as needed. +func persistAndProcessConfig(dataDir string, devMode bool, bsCfg *hcp.BootstrapConfig) (string, error) { + if devMode { // Agent in dev mode, we still need somewhere to persist the certs // temporarily though to be able to start up at all since we don't support // inline certs right now. Use temp dir @@ -164,41 +232,96 @@ func doHCPBootstrap(ctx context.Context, rc *config.RuntimeConfig, ui UI) (strin return "", fmt.Errorf("failed to create temp dir for certificates: %w", err) } dataDir = tmp - shouldPersist = false } - // Persist the TLS cert files from the response since we need to refer to them - // as disk files either way. - if err := persistTLSCerts(dataDir, bsCfg); err != nil { - return "", fmt.Errorf("failed to persist TLS certificates to dir %q: %w", dataDir, err) + // Create subdir if it's not already there. + dir := filepath.Join(dataDir, subDir) + if err := lib.EnsurePath(dir, true); err != nil { + return "", fmt.Errorf("failed to ensure directory %q: %w", dir, err) } - // Update the config JSON to include those TLS cert files - cfgJSON, err := injectTLSCerts(dataDir, bsCfg.ConsulConfig) - if err != nil { - return "", fmt.Errorf("failed to inject TLS Certs into bootstrap config: %w", err) + + // Parse just to a map for now as we only have to inject to a specific place + // and parsing whole Config struct is complicated... + var cfg map[string]any + + if err := json.Unmarshal([]byte(bsCfg.ConsulConfig), &cfg); err != nil { + return "", fmt.Errorf("failed to unmarshal bootstrap config: %w", err) + } + + // Avoid ever setting an initial_management token from HCP now that we can + // separately bootstrap an HCP management token with a distinct accessor ID. + // + // CCM will continue to return an initial_management token because previous versions of Consul + // cannot bootstrap an HCP management token distinct from the initial management token. + // This block can be deleted once CCM supports tailoring bootstrap config responses + // based on the version of Consul that requested it. + acls, aclsOK := cfg["acl"].(map[string]any) + if aclsOK { + tokens, tokensOK := acls["tokens"].(map[string]interface{}) + if tokensOK { + delete(tokens, "initial_management") + } } - // Persist the final config we need to add for restarts. Assuming this wasn't - // a tmp dir to start with. - if shouldPersist { - if err := persistBootstrapConfig(dataDir, cfgJSON); err != nil { - return "", fmt.Errorf("failed to persist bootstrap config to dir %q: %w", dataDir, err) + var cfgJSON string + if bsCfg.TLSCert != "" { + if err := validateTLSCerts(bsCfg.TLSCert, bsCfg.TLSCertKey, bsCfg.TLSCAs); err != nil { + return "", fmt.Errorf("invalid certificates: %w", err) + } + + // Persist the TLS cert files from the response since we need to refer to them + // as disk files either way. + if err := persistTLSCerts(dir, bsCfg.TLSCert, bsCfg.TLSCertKey, bsCfg.TLSCAs); err != nil { + return "", fmt.Errorf("failed to persist TLS certificates to dir %q: %w", dataDir, err) + } + + // Store paths to the persisted TLS cert files. + cfg["ca_file"] = filepath.Join(dir, caFileName) + cfg["cert_file"] = filepath.Join(dir, certFileName) + cfg["key_file"] = filepath.Join(dir, keyFileName) + + // Convert the bootstrap config map back into a string + cfgJSONBytes, err := json.Marshal(cfg) + if err != nil { + return "", err } + cfgJSON = string(cfgJSONBytes) } + if !devMode { + // Persist the final config we need to add so that it is available locally after a restart. + // Assuming the configured data dir wasn't a tmp dir to start with. + if err := persistBootstrapConfig(dir, cfgJSON); err != nil { + return "", fmt.Errorf("failed to persist bootstrap config: %w", err) + } + + // HCP only returns the management token if it requires Consul to + // initialize it + if bsCfg.ManagementToken != "" { + if err := validateManagementToken(bsCfg.ManagementToken); err != nil { + return "", fmt.Errorf("invalid management token: %w", err) + } + if err := persistManagementToken(dir, bsCfg.ManagementToken); err != nil { + return "", fmt.Errorf("failed to persist HCP management token: %w", err) + } + } + + if err := persistSuccessMarker(dir); err != nil { + return "", fmt.Errorf("failed to persist success marker: %w", err) + } + } return cfgJSON, nil } -func persistTLSCerts(dataDir string, bsCfg *hcp.BootstrapConfig) error { - dir := filepath.Join(dataDir, subDir) +func persistSuccessMarker(dir string) error { + name := filepath.Join(dir, successFileName) + return os.WriteFile(name, []byte(""), 0600) - if bsCfg.TLSCert == "" || bsCfg.TLSCertKey == "" { - return fmt.Errorf("unexpected bootstrap response from HCP: missing TLS information") - } +} - // Create a subdir if it's not already there - if err := lib.EnsurePath(dir, true); err != nil { - return err +func persistTLSCerts(dir string, serverCert, serverKey string, caCerts []string) error { + if serverCert == "" || serverKey == "" { + return fmt.Errorf("unexpected bootstrap response from HCP: missing TLS information") } // Write out CA cert(s). We write them all to one file because Go's x509 @@ -209,7 +332,7 @@ func persistTLSCerts(dataDir string, bsCfg *hcp.BootstrapConfig) error { return err } bf := bufio.NewWriter(f) - for _, caPEM := range bsCfg.TLSCAs { + for _, caPEM := range caCerts { bf.WriteString(caPEM + "\n") } if err := bf.Flush(); err != nil { @@ -219,87 +342,240 @@ func persistTLSCerts(dataDir string, bsCfg *hcp.BootstrapConfig) error { return err } - if err := ioutil.WriteFile(filepath.Join(dir, certFileName), []byte(bsCfg.TLSCert), 0600); err != nil { + if err := os.WriteFile(filepath.Join(dir, certFileName), []byte(serverCert), 0600); err != nil { return err } - if err := ioutil.WriteFile(filepath.Join(dir, keyFileName), []byte(bsCfg.TLSCertKey), 0600); err != nil { + if err := os.WriteFile(filepath.Join(dir, keyFileName), []byte(serverKey), 0600); err != nil { return err } return nil } -func injectTLSCerts(dataDir string, bootstrapJSON string) (string, error) { - // Parse just to a map for now as we only have to inject to a specific place - // and parsing whole Config struct is complicated... - var cfg map[string]interface{} +// Basic validation to ensure a UUID was loaded and assumes the token is non-empty +func validateManagementToken(token string) error { + // note: we assume that the token is not an empty string + if _, err := uuid.ParseUUID(token); err != nil { + return errors.New("management token is not a valid UUID") + } + return nil +} + +func persistManagementToken(dir, token string) error { + name := filepath.Join(dir, tokenFileName) + return os.WriteFile(name, []byte(token), 0600) +} + +func persistBootstrapConfig(dir, cfgJSON string) error { + // Persist the important bits we got from bootstrapping. The TLS certs are + // already persisted, just need to persist the config we are going to add. + name := filepath.Join(dir, configFileName) + return os.WriteFile(name, []byte(cfgJSON), 0600) +} + +func loadPersistedBootstrapConfig(dataDir string, ui UI) (*RawBootstrapConfig, bool) { + if dataDir == "" { + // There's no files to load when in dev mode. + return nil, false + } + + dir := filepath.Join(dataDir, subDir) - if err := json.Unmarshal([]byte(bootstrapJSON), &cfg); err != nil { - return "", err + _, err := os.Stat(filepath.Join(dir, successFileName)) + if os.IsNotExist(err) { + // Haven't bootstrapped from HCP. + return nil, false + } + if err != nil { + ui.Warn("failed to check for config on disk, re-fetching from HCP: " + err.Error()) + return nil, false } - // Inject TLS cert files - cfg["ca_file"] = filepath.Join(dataDir, subDir, caFileName) - cfg["cert_file"] = filepath.Join(dataDir, subDir, certFileName) - cfg["key_file"] = filepath.Join(dataDir, subDir, keyFileName) + if err := checkCerts(dir); err != nil { + ui.Warn("failed to validate certs on disk, re-fetching from HCP: " + err.Error()) + return nil, false + } + + configJSON, err := loadBootstrapConfigJSON(dataDir) + if err != nil { + ui.Warn("failed to load bootstrap config from disk, re-fetching from HCP: " + err.Error()) + return nil, false + } - jsonBs, err := json.Marshal(cfg) + mgmtToken, err := loadManagementToken(dir) if err != nil { - return "", err + ui.Warn("failed to load HCP management token from disk, re-fetching from HCP: " + err.Error()) + return nil, false } - return string(jsonBs), nil + return &RawBootstrapConfig{ + ConfigJSON: configJSON, + ManagementToken: mgmtToken, + }, true } -func persistBootstrapConfig(dataDir, cfgJSON string) error { - // Persist the important bits we got from bootstrapping. The TLS certs are - // already persisted, just need to persist the config we are going to add. - name := filepath.Join(dataDir, subDir, configFileName) - return ioutil.WriteFile(name, []byte(cfgJSON), 0600) +func loadBootstrapConfigJSON(dataDir string) (string, error) { + filename := filepath.Join(dataDir, subDir, configFileName) + + _, err := os.Stat(filename) + if os.IsNotExist(err) { + return "", nil + } + if err != nil { + return "", fmt.Errorf("failed to check for bootstrap config: %w", err) + } + + // Attempt to load persisted config to check for errors and basic validity. + // Errors here will raise issues like referencing unsupported config fields. + _, err = config.Load(config.LoadOpts{ + ConfigFiles: []string{filename}, + HCL: []string{ + "server = true", + `bind_addr = "127.0.0.1"`, + fmt.Sprintf("data_dir = %q", dataDir), + }, + ConfigFormat: "json", + }) + if err != nil { + return "", fmt.Errorf("failed to parse local bootstrap config: %w", err) + } + + jsonBs, err := os.ReadFile(filename) + if err != nil { + return "", fmt.Errorf(fmt.Sprintf("failed to read local bootstrap config file: %s", err)) + } + return strings.TrimSpace(string(jsonBs)), nil +} + +func loadManagementToken(dir string) (string, error) { + name := filepath.Join(dir, tokenFileName) + bytes, err := os.ReadFile(name) + if os.IsNotExist(err) { + return "", errors.New("configuration files on disk are incomplete, missing: " + name) + } + if err != nil { + return "", fmt.Errorf("failed to read: %w", err) + } + + token := string(bytes) + if err := validateManagementToken(token); err != nil { + return "", fmt.Errorf("invalid management token: %w", err) + } + + return token, nil } -func loadPersistedBootstrapConfig(rc *config.RuntimeConfig, ui UI) (string, bool) { - // Check if the files all exist +func checkCerts(dir string) error { files := []string{ - filepath.Join(rc.DataDir, subDir, configFileName), - filepath.Join(rc.DataDir, subDir, caFileName), - filepath.Join(rc.DataDir, subDir, certFileName), - filepath.Join(rc.DataDir, subDir, keyFileName), - } - hasSome := false - for _, name := range files { - if _, err := os.Stat(name); errors.Is(err, os.ErrNotExist) { - // At least one required file doesn't exist, failed loading. This is not - // an error though - if hasSome { - ui.Warn("ignoring incomplete local bootstrap config files") - } - return "", false + filepath.Join(dir, caFileName), + filepath.Join(dir, certFileName), + filepath.Join(dir, keyFileName), + } + + missing := make([]string, 0) + for _, file := range files { + _, err := os.Stat(file) + if os.IsNotExist(err) { + missing = append(missing, file) + continue } - hasSome = true + if err != nil { + return err + } + } + + // If all the TLS files are missing, assume this is intentional. + // Existing clusters do not receive any TLS certs. + if len(missing) == len(files) { + return nil + } + + // If only some of the files are missing, something went wrong. + if len(missing) > 0 { + return fmt.Errorf("configuration files on disk are incomplete, missing: %v", missing) + } + + cert, key, caCerts, err := loadCerts(dir) + if err != nil { + return fmt.Errorf("failed to load certs from disk: %w", err) + } + + if err = validateTLSCerts(cert, key, caCerts); err != nil { + return fmt.Errorf("invalid certs on disk: %w", err) } + return nil +} - name := filepath.Join(rc.DataDir, subDir, configFileName) - jsonBs, err := ioutil.ReadFile(name) +func loadCerts(dir string) (cert, key string, caCerts []string, err error) { + certPEMBlock, err := os.ReadFile(filepath.Join(dir, certFileName)) + if err != nil { + return "", "", nil, err + } + keyPEMBlock, err := os.ReadFile(filepath.Join(dir, keyFileName)) if err != nil { - ui.Warn(fmt.Sprintf("failed to read local bootstrap config file, ignoring local files: %s", err)) - return "", false + return "", "", nil, err } - // Check this looks non-empty at least - jsonStr := strings.TrimSpace(string(jsonBs)) - // 50 is arbitrary but config containing the right secrets would always be - // bigger than this in JSON format so it is a reasonable test that this wasn't - // empty or just an empty JSON object or something. - if len(jsonStr) < 50 { - ui.Warn("ignoring incomplete local bootstrap config files") - return "", false + caPEMs, err := os.ReadFile(filepath.Join(dir, caFileName)) + if err != nil { + return "", "", nil, err + } + caCerts, err = splitCACerts(caPEMs) + if err != nil { + return "", "", nil, fmt.Errorf("failed to parse CA certs: %w", err) } - // TODO we could parse the certificates and check they are still valid here - // and force a reload if not. We could also attempt to parse config and check - // it's all valid just in case the local config was really old and has - // deprecated fields or something? - return jsonStr, true + return string(certPEMBlock), string(keyPEMBlock), caCerts, nil +} + +// splitCACerts takes a list of concatenated PEM blocks and splits +// them back up into strings. This is used because CACerts are written +// into a single file, but validated individually. +func splitCACerts(caPEMs []byte) ([]string, error) { + var out []string + + for { + nextBlock, remaining := pem.Decode(caPEMs) + if nextBlock == nil { + break + } + if nextBlock.Type != "CERTIFICATE" { + return nil, fmt.Errorf("PEM-block should be CERTIFICATE type") + } + + // Collect up to the start of the remaining bytes. + // We don't grab nextBlock.Bytes because it's not PEM encoded. + out = append(out, string(caPEMs[:len(caPEMs)-len(remaining)])) + caPEMs = remaining + } + + if len(out) == 0 { + return nil, errors.New("invalid CA certificate") + } + return out, nil +} + +// validateTLSCerts checks that the CA cert, server cert, and key on disk are structurally valid. +// +// OPTIMIZE: This could be improved by returning an error if certs are expired or close to expiration. +// However, that requires issuing new certs on bootstrap requests, since returning an error +// would trigger a re-fetch from HCP. +func validateTLSCerts(cert, key string, caCerts []string) error { + leaf, err := tls.X509KeyPair([]byte(cert), []byte(key)) + if err != nil { + return errors.New("invalid server certificate or key") + } + _, err = x509.ParseCertificate(leaf.Certificate[0]) + if err != nil { + return errors.New("invalid server certificate") + } + + for _, caCert := range caCerts { + _, err = connect.ParseCert(caCert) + if err != nil { + return errors.New("invalid CA certificate") + } + } + return nil } diff --git a/agent/hcp/bootstrap/bootstrap_test.go b/agent/hcp/bootstrap/bootstrap_test.go new file mode 100644 index 000000000000..e10d4618a572 --- /dev/null +++ b/agent/hcp/bootstrap/bootstrap_test.go @@ -0,0 +1,472 @@ +package bootstrap + +import ( + "context" + "crypto/tls" + "crypto/x509" + "fmt" + "net/http/httptest" + "os" + "path/filepath" + "testing" + + "github.com/hashicorp/consul/agent/config" + "github.com/hashicorp/consul/agent/hcp" + "github.com/hashicorp/consul/lib" + "github.com/hashicorp/consul/tlsutil" + "github.com/hashicorp/go-uuid" + "github.com/mitchellh/cli" + "github.com/stretchr/testify/require" +) + +func TestBootstrapConfigLoader(t *testing.T) { + baseLoader := func(source config.Source) (config.LoadResult, error) { + return config.Load(config.LoadOpts{ + DefaultConfig: source, + HCL: []string{ + `server = true`, + `bind_addr = "127.0.0.1"`, + `data_dir = "/tmp/consul-data"`, + }, + }) + } + + bootstrapLoader := func(source config.Source) (config.LoadResult, error) { + return bootstrapConfigLoader(baseLoader, &RawBootstrapConfig{ + ConfigJSON: `{"bootstrap_expect": 8}`, + ManagementToken: "test-token", + })(source) + } + + result, err := bootstrapLoader(nil) + require.NoError(t, err) + + // bootstrap_expect and management token are injected from bootstrap config received from HCP. + require.Equal(t, 8, result.RuntimeConfig.BootstrapExpect) + require.Equal(t, "test-token", result.RuntimeConfig.Cloud.ManagementToken) + + // Response header is always injected from a constant. + require.Equal(t, "x-consul-default-acl-policy", result.RuntimeConfig.HTTPResponseHeaders[accessControlHeaderName]) +} + +func Test_finalizeRuntimeConfig(t *testing.T) { + type testCase struct { + rc *config.RuntimeConfig + cfg *RawBootstrapConfig + verifyFn func(t *testing.T, rc *config.RuntimeConfig) + } + run := func(t *testing.T, tc testCase) { + finalizeRuntimeConfig(tc.rc, tc.cfg) + tc.verifyFn(t, tc.rc) + } + + tt := map[string]testCase{ + "set header if not present": { + rc: &config.RuntimeConfig{}, + cfg: &RawBootstrapConfig{ + ManagementToken: "test-token", + }, + verifyFn: func(t *testing.T, rc *config.RuntimeConfig) { + require.Equal(t, "test-token", rc.Cloud.ManagementToken) + require.Equal(t, "x-consul-default-acl-policy", rc.HTTPResponseHeaders[accessControlHeaderName]) + }, + }, + "append to header if present": { + rc: &config.RuntimeConfig{ + HTTPResponseHeaders: map[string]string{ + accessControlHeaderName: "Content-Encoding", + }, + }, + cfg: &RawBootstrapConfig{ + ManagementToken: "test-token", + }, + verifyFn: func(t *testing.T, rc *config.RuntimeConfig) { + require.Equal(t, "test-token", rc.Cloud.ManagementToken) + require.Equal(t, "Content-Encoding,x-consul-default-acl-policy", rc.HTTPResponseHeaders[accessControlHeaderName]) + }, + }, + } + + for name, tc := range tt { + t.Run(name, func(t *testing.T) { + run(t, tc) + }) + } +} + +func boolPtr(value bool) *bool { + return &value +} + +func TestLoadConfig_Persistence(t *testing.T) { + type testCase struct { + // resourceID is the HCP resource ID. If set, a server is considered to be cloud-enabled. + resourceID string + + // devMode indicates whether the loader should not have a data directory. + devMode bool + + // verifyFn issues case-specific assertions. + verifyFn func(t *testing.T, rc *config.RuntimeConfig) + } + + run := func(t *testing.T, tc testCase) { + dir, err := os.MkdirTemp(os.TempDir(), "bootstrap-test-") + require.NoError(t, err) + t.Cleanup(func() { os.RemoveAll(dir) }) + + s := hcp.NewMockHCPServer() + s.AddEndpoint(TestEndpoint()) + + // Use an HTTPS server since that's what the HCP SDK expects for auth. + srv := httptest.NewTLSServer(s) + defer srv.Close() + + caCert, err := x509.ParseCertificate(srv.TLS.Certificates[0].Certificate[0]) + require.NoError(t, err) + + pool := x509.NewCertPool() + pool.AddCert(caCert) + clientTLS := &tls.Config{RootCAs: pool} + + baseOpts := config.LoadOpts{ + HCL: []string{ + `server = true`, + `bind_addr = "127.0.0.1"`, + fmt.Sprintf(`http_config = { response_headers = { %s = "Content-Encoding" } }`, accessControlHeaderName), + fmt.Sprintf(`cloud { client_id="test" client_secret="test" hostname=%q auth_url=%q resource_id=%q }`, + srv.Listener.Addr().String(), srv.URL, tc.resourceID), + }, + } + if tc.devMode { + baseOpts.DevMode = boolPtr(true) + } else { + baseOpts.HCL = append(baseOpts.HCL, fmt.Sprintf(`data_dir = %q`, dir)) + } + + baseLoader := func(source config.Source) (config.LoadResult, error) { + baseOpts.DefaultConfig = source + return config.Load(baseOpts) + } + + ui := cli.NewMockUi() + + // Load initial config to check whether bootstrapping from HCP is enabled. + initial, err := baseLoader(nil) + require.NoError(t, err) + + // Override the client TLS config so that the test server can be trusted. + initial.RuntimeConfig.Cloud.WithTLSConfig(clientTLS) + client, err := hcp.NewClient(initial.RuntimeConfig.Cloud) + require.NoError(t, err) + + loader, err := LoadConfig(context.Background(), client, initial.RuntimeConfig.DataDir, baseLoader, ui) + require.NoError(t, err) + + // Load the agent config with the potentially wrapped loader. + fromRemote, err := loader(nil) + require.NoError(t, err) + + // HCP-enabled cases should fetch from HCP on the first run of LoadConfig. + require.Contains(t, ui.OutputWriter.String(), "Fetching configuration from HCP") + + // Run case-specific verification. + tc.verifyFn(t, fromRemote.RuntimeConfig) + + require.Empty(t, fromRemote.RuntimeConfig.ACLInitialManagementToken, + "initial_management token should have been sanitized") + + if tc.devMode { + // Re-running the bootstrap func below isn't relevant to dev mode + // since they don't have a data directory to load data from. + return + } + + // Run LoadConfig again to exercise the logic of loading config from disk. + loader, err = LoadConfig(context.Background(), client, initial.RuntimeConfig.DataDir, baseLoader, ui) + require.NoError(t, err) + + fromDisk, err := loader(nil) + require.NoError(t, err) + + // HCP-enabled cases should fetch from disk on the second run. + require.Contains(t, ui.OutputWriter.String(), "Loaded HCP configuration from local disk") + + // Config loaded from disk should be the same as the one that was initially fetched from the HCP servers. + require.Equal(t, fromRemote.RuntimeConfig, fromDisk.RuntimeConfig) + } + + tt := map[string]testCase{ + "dev mode": { + devMode: true, + + resourceID: "organization/0b9de9a3-8403-4ca6-aba8-fca752f42100/" + + "project/0b9de9a3-8403-4ca6-aba8-fca752f42100/" + + "consul.cluster/new-cluster-id", + + verifyFn: func(t *testing.T, rc *config.RuntimeConfig) { + require.Empty(t, rc.DataDir) + + // Dev mode should have persisted certs since they can't be inlined. + require.NotEmpty(t, rc.TLS.HTTPS.CertFile) + require.NotEmpty(t, rc.TLS.HTTPS.KeyFile) + require.NotEmpty(t, rc.TLS.HTTPS.CAFile) + + // Find the temporary directory they got stored in. + dir := filepath.Dir(rc.TLS.HTTPS.CertFile) + + // Ensure we only stored the TLS materials. + entries, err := os.ReadDir(dir) + require.NoError(t, err) + require.Len(t, entries, 3) + + haveFiles := make([]string, 3) + for i, entry := range entries { + haveFiles[i] = entry.Name() + } + + wantFiles := []string{caFileName, certFileName, keyFileName} + require.ElementsMatch(t, wantFiles, haveFiles) + }, + }, + "new cluster": { + resourceID: "organization/0b9de9a3-8403-4ca6-aba8-fca752f42100/" + + "project/0b9de9a3-8403-4ca6-aba8-fca752f42100/" + + "consul.cluster/new-cluster-id", + + // New clusters should have received and persisted the whole suite of config. + verifyFn: func(t *testing.T, rc *config.RuntimeConfig) { + dir := filepath.Join(rc.DataDir, subDir) + + entries, err := os.ReadDir(dir) + require.NoError(t, err) + require.Len(t, entries, 6) + + files := []string{ + filepath.Join(dir, configFileName), + filepath.Join(dir, caFileName), + filepath.Join(dir, certFileName), + filepath.Join(dir, keyFileName), + filepath.Join(dir, tokenFileName), + filepath.Join(dir, successFileName), + } + for _, name := range files { + _, err := os.Stat(name) + require.NoError(t, err) + } + + require.Equal(t, filepath.Join(dir, certFileName), rc.TLS.HTTPS.CertFile) + require.Equal(t, filepath.Join(dir, keyFileName), rc.TLS.HTTPS.KeyFile) + require.Equal(t, filepath.Join(dir, caFileName), rc.TLS.HTTPS.CAFile) + + cert, key, caCerts, err := loadCerts(dir) + require.NoError(t, err) + + require.NoError(t, validateTLSCerts(cert, key, caCerts)) + }, + }, + "existing cluster": { + resourceID: "organization/0b9de9a3-8403-4ca6-aba8-fca752f42100/" + + "project/0b9de9a3-8403-4ca6-aba8-fca752f42100/" + + "consul.cluster/" + TestExistingClusterID, + + // Existing clusters should have only received and persisted the management token. + verifyFn: func(t *testing.T, rc *config.RuntimeConfig) { + dir := filepath.Join(rc.DataDir, subDir) + + entries, err := os.ReadDir(dir) + require.NoError(t, err) + require.Len(t, entries, 3) + + files := []string{ + filepath.Join(dir, tokenFileName), + filepath.Join(dir, successFileName), + filepath.Join(dir, configFileName), + } + for _, name := range files { + _, err := os.Stat(name) + require.NoError(t, err) + } + }, + }, + } + + for name, tc := range tt { + t.Run(name, func(t *testing.T) { + run(t, tc) + }) + } +} + +func Test_loadPersistedBootstrapConfig(t *testing.T) { + type expect struct { + loaded bool + warning string + } + type testCase struct { + existingCluster bool + disableManagementToken bool + mutateFn func(t *testing.T, dir string) + expect expect + } + + run := func(t *testing.T, tc testCase) { + dataDir, err := os.MkdirTemp(os.TempDir(), "load-bootstrap-test-") + require.NoError(t, err) + t.Cleanup(func() { os.RemoveAll(dataDir) }) + + dir := filepath.Join(dataDir, subDir) + + // Do some common setup as if we received config from HCP and persisted it to disk. + require.NoError(t, lib.EnsurePath(dir, true)) + require.NoError(t, persistSuccessMarker(dir)) + + if !tc.existingCluster { + caCert, caKey, err := tlsutil.GenerateCA(tlsutil.CAOpts{}) + require.NoError(t, err) + + serverCert, serverKey, err := testLeaf(caCert, caKey) + require.NoError(t, err) + require.NoError(t, persistTLSCerts(dir, serverCert, serverKey, []string{caCert})) + + cfgJSON := `{"bootstrap_expect": 8}` + require.NoError(t, persistBootstrapConfig(dir, cfgJSON)) + } + + var token string + if !tc.disableManagementToken { + token, err = uuid.GenerateUUID() + require.NoError(t, err) + require.NoError(t, persistManagementToken(dir, token)) + } + + // Optionally mutate the persisted data to trigger errors while loading. + if tc.mutateFn != nil { + tc.mutateFn(t, dir) + } + + ui := cli.NewMockUi() + cfg, loaded := loadPersistedBootstrapConfig(dataDir, ui) + require.Equal(t, tc.expect.loaded, loaded, ui.ErrorWriter.String()) + if loaded { + require.Equal(t, token, cfg.ManagementToken) + require.Empty(t, ui.ErrorWriter.String()) + } else { + require.Nil(t, cfg) + require.Contains(t, ui.ErrorWriter.String(), tc.expect.warning) + } + } + + tt := map[string]testCase{ + "existing cluster with valid files": { + existingCluster: true, + // Don't mutate, files from setup are valid. + mutateFn: nil, + expect: expect{ + loaded: true, + warning: "", + }, + }, + "existing cluster no token": { + existingCluster: true, + disableManagementToken: true, + expect: expect{ + loaded: false, + }, + }, + "existing cluster no files": { + existingCluster: true, + mutateFn: func(t *testing.T, dir string) { + // Remove all files + require.NoError(t, os.RemoveAll(dir)) + }, + expect: expect{ + loaded: false, + // No warnings since we assume we need to fetch config from HCP for the first time. + warning: "", + }, + }, + "new cluster with valid files": { + // Don't mutate, files from setup are valid. + mutateFn: nil, + expect: expect{ + loaded: true, + warning: "", + }, + }, + "new cluster with no token": { + disableManagementToken: true, + expect: expect{ + loaded: false, + }, + }, + "new cluster some files": { + mutateFn: func(t *testing.T, dir string) { + // Remove one of the required files + require.NoError(t, os.Remove(filepath.Join(dir, certFileName))) + }, + expect: expect{ + loaded: false, + warning: "configuration files on disk are incomplete", + }, + }, + "new cluster no files": { + mutateFn: func(t *testing.T, dir string) { + // Remove all files + require.NoError(t, os.RemoveAll(dir)) + }, + expect: expect{ + loaded: false, + // No warnings since we assume we need to fetch config from HCP for the first time. + warning: "", + }, + }, + "new cluster invalid cert": { + mutateFn: func(t *testing.T, dir string) { + name := filepath.Join(dir, certFileName) + require.NoError(t, os.WriteFile(name, []byte("not-a-cert"), 0600)) + }, + expect: expect{ + loaded: false, + warning: "invalid server certificate", + }, + }, + "new cluster invalid CA": { + mutateFn: func(t *testing.T, dir string) { + name := filepath.Join(dir, caFileName) + require.NoError(t, os.WriteFile(name, []byte("not-a-ca-cert"), 0600)) + }, + expect: expect{ + loaded: false, + warning: "invalid CA certificate", + }, + }, + "new cluster invalid config flag": { + mutateFn: func(t *testing.T, dir string) { + name := filepath.Join(dir, configFileName) + require.NoError(t, os.WriteFile(name, []byte(`{"not_a_consul_agent_config_field" = "zap"}`), 0600)) + }, + expect: expect{ + loaded: false, + warning: "failed to parse local bootstrap config", + }, + }, + "existing cluster invalid token": { + existingCluster: true, + mutateFn: func(t *testing.T, dir string) { + name := filepath.Join(dir, tokenFileName) + require.NoError(t, os.WriteFile(name, []byte("not-a-uuid"), 0600)) + }, + expect: expect{ + loaded: false, + warning: "is not a valid UUID", + }, + }, + } + + for name, tc := range tt { + t.Run(name, func(t *testing.T) { + run(t, tc) + }) + } +} diff --git a/agent/hcp/bootstrap/testing.go b/agent/hcp/bootstrap/testing.go index b1a05a7e50be..d06c2d747c4f 100644 --- a/agent/hcp/bootstrap/testing.go +++ b/agent/hcp/bootstrap/testing.go @@ -10,12 +10,11 @@ import ( "net/http" "strings" - gnmmod "github.com/hashicorp/hcp-sdk-go/clients/cloud-global-network-manager-service/preview/2022-02-15/models" - "github.com/hashicorp/hcp-sdk-go/resource" - "github.com/hashicorp/consul/agent/hcp" "github.com/hashicorp/consul/tlsutil" "github.com/hashicorp/go-uuid" + gnmmod "github.com/hashicorp/hcp-sdk-go/clients/cloud-global-network-manager-service/preview/2022-02-15/models" + "github.com/hashicorp/hcp-sdk-go/resource" ) // TestEndpoint returns an hcp.TestEndpoint to be used in an hcp.MockHCPServer. @@ -46,6 +45,29 @@ func handleBootstrap(data map[string]gnmmod.HashicorpCloudGlobalNetworkManager20 return resp, nil } +const TestExistingClusterID = "133114e7-9745-41ce-b1c9-9644a20d2952" + +func testLeaf(caCert, caKey string) (serverCert, serverKey string, err error) { + signer, err := tlsutil.ParseSigner(caKey) + if err != nil { + return "", "", err + } + + serverCert, serverKey, err = tlsutil.GenerateCert(tlsutil.CertOpts{ + Signer: signer, + CA: caCert, + Name: "server.dc1.consul", + Days: 30, + DNSNames: []string{"server.dc1.consul", "localhost"}, + IPAddresses: append([]net.IP{}, net.ParseIP("127.0.0.1")), + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, + }) + if err != nil { + return "", "", err + } + return serverCert, serverKey, nil +} + func generateClusterData(cluster resource.Resource) (gnmmod.HashicorpCloudGlobalNetworkManager20220215AgentBootstrapResponse, error) { resp := gnmmod.HashicorpCloudGlobalNetworkManager20220215AgentBootstrapResponse{ Cluster: &gnmmod.HashicorpCloudGlobalNetworkManager20220215Cluster{}, @@ -53,32 +75,28 @@ func generateClusterData(cluster resource.Resource) (gnmmod.HashicorpCloudGlobal ServerTLS: &gnmmod.HashicorpCloudGlobalNetworkManager20220215ServerTLS{}, }, } - - CACert, CAKey, err := tlsutil.GenerateCA(tlsutil.CAOpts{}) - if err != nil { - return resp, err + if cluster.ID == TestExistingClusterID { + token, err := uuid.GenerateUUID() + if err != nil { + return resp, err + } + resp.Bootstrap.ConsulConfig = "{}" + resp.Bootstrap.ManagementToken = token + return resp, nil } - resp.Bootstrap.ServerTLS.CertificateAuthorities = append(resp.Bootstrap.ServerTLS.CertificateAuthorities, CACert) - signer, err := tlsutil.ParseSigner(CAKey) + caCert, caKey, err := tlsutil.GenerateCA(tlsutil.CAOpts{}) if err != nil { return resp, err } - - cert, priv, err := tlsutil.GenerateCert(tlsutil.CertOpts{ - Signer: signer, - CA: CACert, - Name: "server.dc1.consul", - Days: 30, - DNSNames: []string{"server.dc1.consul", "localhost"}, - IPAddresses: append([]net.IP{}, net.ParseIP("127.0.0.1")), - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, - }) + serverCert, serverKey, err := testLeaf(caCert, caKey) if err != nil { return resp, err } - resp.Bootstrap.ServerTLS.Cert = cert - resp.Bootstrap.ServerTLS.PrivateKey = priv + + resp.Bootstrap.ServerTLS.CertificateAuthorities = append(resp.Bootstrap.ServerTLS.CertificateAuthorities, caCert) + resp.Bootstrap.ServerTLS.Cert = serverCert + resp.Bootstrap.ServerTLS.PrivateKey = serverKey // Generate Config. We don't use the read config.Config struct because it // doesn't have `omitempty` which makes the output gross. We only want a tiny @@ -113,8 +131,9 @@ func generateClusterData(cluster resource.Resource) (gnmmod.HashicorpCloudGlobal // Enable HTTPS port, disable HTTP "ports": map[string]interface{}{ - "https": 8501, - "http": -1, + "https": 8501, + "http": -1, + "grpc_tls": 8503, }, // RAFT Peers @@ -125,16 +144,18 @@ func generateClusterData(cluster resource.Resource) (gnmmod.HashicorpCloudGlobal } // ACLs - management, err := uuid.GenerateUUID() + token, err := uuid.GenerateUUID() if err != nil { return resp, err } + resp.Bootstrap.ManagementToken = token + cfg["acl"] = map[string]interface{}{ "tokens": map[string]interface{}{ - "initial_management": management, - // Also setup the server's own agent token to be the same so it has + // Also setup the server's own agent token to be the management token so it has // permission to register itself. - "agent": management, + "agent": token, + "initial_management": token, }, "default_policy": "deny", "enabled": true, diff --git a/agent/hcp/client.go b/agent/hcp/client.go index 070814024a46..d394b38da96d 100644 --- a/agent/hcp/client.go +++ b/agent/hcp/client.go @@ -18,6 +18,7 @@ import ( ) // Client interface exposes HCP operations that can be invoked by Consul +// //go:generate mockery --name Client --with-expecter --inpackage type Client interface { FetchBootstrap(ctx context.Context) (*BootstrapConfig, error) @@ -33,6 +34,7 @@ type BootstrapConfig struct { TLSCertKey string TLSCAs []string ConsulConfig string + ManagementToken string } type hcpClient struct { @@ -75,10 +77,12 @@ func httpClient(c config.CloudConfig) (*httptransport.Runtime, error) { } func (c *hcpClient) FetchBootstrap(ctx context.Context) (*BootstrapConfig, error) { + version := version.GetHumanVersion() params := hcpgnm.NewAgentBootstrapConfigParamsWithContext(ctx). WithID(c.resource.ID). WithLocationOrganizationID(c.resource.Organization). - WithLocationProjectID(c.resource.Project) + WithLocationProjectID(c.resource.Project). + WithConsulVersion(&version) resp, err := c.gnm.AgentBootstrapConfig(params, nil) if err != nil { @@ -102,6 +106,7 @@ func bootstrapConfigFromHCP(res *gnmmod.HashicorpCloudGlobalNetworkManager202202 TLSCertKey: serverTLS.PrivateKey, TLSCAs: serverTLS.CertificateAuthorities, ConsulConfig: res.Bootstrap.ConsulConfig, + ManagementToken: res.Bootstrap.ManagementToken, } } @@ -111,7 +116,7 @@ func (c *hcpClient) PushServerStatus(ctx context.Context, s *ServerStatus) error WithLocationOrganizationID(c.resource.Organization). WithLocationProjectID(c.resource.Project) - params.SetBody(&gnmmod.HashicorpCloudGlobalNetworkManager20220215AgentPushServerStateRequest{ + params.SetBody(hcpgnm.AgentPushServerStateBody{ ServerState: serverStatusToHCP(s), }) @@ -126,10 +131,12 @@ type ServerStatus struct { LanAddress string GossipPort int RPCPort int + Datacenter string Autopilot ServerAutopilot Raft ServerRaft TLS ServerTLSInfo + ACL ServerACLInfo ScadaStatus string } @@ -149,6 +156,10 @@ type ServerRaft struct { TimeSinceLastContact time.Duration } +type ServerACLInfo struct { + Enabled bool +} + type ServerTLSInfo struct { Enabled bool CertExpiry time.Time @@ -193,6 +204,10 @@ func serverStatusToHCP(s *ServerStatus) *gnmmod.HashicorpCloudGlobalNetworkManag }, Version: s.Version, ScadaStatus: s.ScadaStatus, + ACL: &gnmmod.HashicorpCloudGlobalNetworkManager20220215ACLInfo{ + Enabled: s.ACL.Enabled, + }, + Datacenter: s.Datacenter, } } diff --git a/agent/hcp/config/config.go b/agent/hcp/config/config.go index 98135710463f..9abf43ffccea 100644 --- a/agent/hcp/config/config.go +++ b/agent/hcp/config/config.go @@ -14,20 +14,34 @@ type CloudConfig struct { Hostname string AuthURL string ScadaAddress string + + // Management token used by HCP management plane. + // Cannot be set via config files. + ManagementToken string + + // TlsConfig for testing. + TLSConfig *tls.Config +} + +func (c *CloudConfig) WithTLSConfig(cfg *tls.Config) { + c.TLSConfig = cfg } func (c *CloudConfig) HCPConfig(opts ...hcpcfg.HCPConfigOption) (hcpcfg.HCPConfig, error) { + if c.TLSConfig == nil { + c.TLSConfig = &tls.Config{} + } if c.ClientID != "" && c.ClientSecret != "" { opts = append(opts, hcpcfg.WithClientCredentials(c.ClientID, c.ClientSecret)) } if c.AuthURL != "" { - opts = append(opts, hcpcfg.WithAuth(c.AuthURL, &tls.Config{})) + opts = append(opts, hcpcfg.WithAuth(c.AuthURL, c.TLSConfig)) } if c.Hostname != "" { - opts = append(opts, hcpcfg.WithAPI(c.Hostname, &tls.Config{})) + opts = append(opts, hcpcfg.WithAPI(c.Hostname, c.TLSConfig)) } if c.ScadaAddress != "" { - opts = append(opts, hcpcfg.WithSCADA(c.ScadaAddress, &tls.Config{})) + opts = append(opts, hcpcfg.WithSCADA(c.ScadaAddress, c.TLSConfig)) } opts = append(opts, hcpcfg.FromEnv()) return hcpcfg.NewHCPConfig(opts...) diff --git a/agent/hcp/manager_test.go b/agent/hcp/manager_test.go index 68a4505e995b..09e2fe1628ac 100644 --- a/agent/hcp/manager_test.go +++ b/agent/hcp/manager_test.go @@ -36,7 +36,6 @@ func TestManager_Run(t *testing.T) { // Make sure after manager has stopped no more statuses are pushed. cancel() - mgr.SendUpdate() client.AssertExpectations(t) } diff --git a/agent/hcp/mock_Client.go b/agent/hcp/mock_Client.go index ec6129f98056..29bd27cbf1bc 100644 --- a/agent/hcp/mock_Client.go +++ b/agent/hcp/mock_Client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.13.1. DO NOT EDIT. +// Code generated by mockery v2.15.0. DO NOT EDIT. package hcp @@ -50,7 +50,7 @@ type MockClient_DiscoverServers_Call struct { } // DiscoverServers is a helper method to define mock.On call -// - ctx context.Context +// - ctx context.Context func (_e *MockClient_Expecter) DiscoverServers(ctx interface{}) *MockClient_DiscoverServers_Call { return &MockClient_DiscoverServers_Call{Call: _e.mock.On("DiscoverServers", ctx)} } @@ -96,7 +96,7 @@ type MockClient_FetchBootstrap_Call struct { } // FetchBootstrap is a helper method to define mock.On call -// - ctx context.Context +// - ctx context.Context func (_e *MockClient_Expecter) FetchBootstrap(ctx interface{}) *MockClient_FetchBootstrap_Call { return &MockClient_FetchBootstrap_Call{Call: _e.mock.On("FetchBootstrap", ctx)} } @@ -133,8 +133,8 @@ type MockClient_PushServerStatus_Call struct { } // PushServerStatus is a helper method to define mock.On call -// - ctx context.Context -// - status *ServerStatus +// - ctx context.Context +// - status *ServerStatus func (_e *MockClient_Expecter) PushServerStatus(ctx interface{}, status interface{}) *MockClient_PushServerStatus_Call { return &MockClient_PushServerStatus_Call{Call: _e.mock.On("PushServerStatus", ctx, status)} } diff --git a/agent/hcp/scada/mock_Provider.go b/agent/hcp/scada/mock_Provider.go index 744f54e68e08..b9a0fd2d4967 100644 --- a/agent/hcp/scada/mock_Provider.go +++ b/agent/hcp/scada/mock_Provider.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.14.0. DO NOT EDIT. +// Code generated by mockery v2.20.0. DO NOT EDIT. package scada @@ -7,6 +7,8 @@ import ( mock "github.com/stretchr/testify/mock" + provider "github.com/hashicorp/hcp-scada-provider" + time "time" ) @@ -23,6 +25,98 @@ func (_m *MockProvider) EXPECT() *MockProvider_Expecter { return &MockProvider_Expecter{mock: &_m.Mock} } +// AddMeta provides a mock function with given fields: _a0 +func (_m *MockProvider) AddMeta(_a0 ...provider.Meta) { + _va := make([]interface{}, len(_a0)) + for _i := range _a0 { + _va[_i] = _a0[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + _m.Called(_ca...) +} + +// MockProvider_AddMeta_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddMeta' +type MockProvider_AddMeta_Call struct { + *mock.Call +} + +// AddMeta is a helper method to define mock.On call +// - _a0 ...provider.Meta +func (_e *MockProvider_Expecter) AddMeta(_a0 ...interface{}) *MockProvider_AddMeta_Call { + return &MockProvider_AddMeta_Call{Call: _e.mock.On("AddMeta", + append([]interface{}{}, _a0...)...)} +} + +func (_c *MockProvider_AddMeta_Call) Run(run func(_a0 ...provider.Meta)) *MockProvider_AddMeta_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]provider.Meta, len(args)-0) + for i, a := range args[0:] { + if a != nil { + variadicArgs[i] = a.(provider.Meta) + } + } + run(variadicArgs...) + }) + return _c +} + +func (_c *MockProvider_AddMeta_Call) Return() *MockProvider_AddMeta_Call { + _c.Call.Return() + return _c +} + +func (_c *MockProvider_AddMeta_Call) RunAndReturn(run func(...provider.Meta)) *MockProvider_AddMeta_Call { + _c.Call.Return(run) + return _c +} + +// DeleteMeta provides a mock function with given fields: _a0 +func (_m *MockProvider) DeleteMeta(_a0 ...string) { + _va := make([]interface{}, len(_a0)) + for _i := range _a0 { + _va[_i] = _a0[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + _m.Called(_ca...) +} + +// MockProvider_DeleteMeta_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteMeta' +type MockProvider_DeleteMeta_Call struct { + *mock.Call +} + +// DeleteMeta is a helper method to define mock.On call +// - _a0 ...string +func (_e *MockProvider_Expecter) DeleteMeta(_a0 ...interface{}) *MockProvider_DeleteMeta_Call { + return &MockProvider_DeleteMeta_Call{Call: _e.mock.On("DeleteMeta", + append([]interface{}{}, _a0...)...)} +} + +func (_c *MockProvider_DeleteMeta_Call) Run(run func(_a0 ...string)) *MockProvider_DeleteMeta_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]string, len(args)-0) + for i, a := range args[0:] { + if a != nil { + variadicArgs[i] = a.(string) + } + } + run(variadicArgs...) + }) + return _c +} + +func (_c *MockProvider_DeleteMeta_Call) Return() *MockProvider_DeleteMeta_Call { + _c.Call.Return() + return _c +} + +func (_c *MockProvider_DeleteMeta_Call) RunAndReturn(run func(...string)) *MockProvider_DeleteMeta_Call { + _c.Call.Return(run) + return _c +} + // GetMeta provides a mock function with given fields: func (_m *MockProvider) GetMeta() map[string]string { ret := _m.Called() @@ -61,18 +155,26 @@ func (_c *MockProvider_GetMeta_Call) Return(_a0 map[string]string) *MockProvider return _c } +func (_c *MockProvider_GetMeta_Call) RunAndReturn(run func() map[string]string) *MockProvider_GetMeta_Call { + _c.Call.Return(run) + return _c +} + // LastError provides a mock function with given fields: func (_m *MockProvider) LastError() (time.Time, error) { ret := _m.Called() var r0 time.Time + var r1 error + if rf, ok := ret.Get(0).(func() (time.Time, error)); ok { + return rf() + } if rf, ok := ret.Get(0).(func() time.Time); ok { r0 = rf() } else { r0 = ret.Get(0).(time.Time) } - var r1 error if rf, ok := ret.Get(1).(func() error); ok { r1 = rf() } else { @@ -104,11 +206,20 @@ func (_c *MockProvider_LastError_Call) Return(_a0 time.Time, _a1 error) *MockPro return _c } +func (_c *MockProvider_LastError_Call) RunAndReturn(run func() (time.Time, error)) *MockProvider_LastError_Call { + _c.Call.Return(run) + return _c +} + // Listen provides a mock function with given fields: capability func (_m *MockProvider) Listen(capability string) (net.Listener, error) { ret := _m.Called(capability) var r0 net.Listener + var r1 error + if rf, ok := ret.Get(0).(func(string) (net.Listener, error)); ok { + return rf(capability) + } if rf, ok := ret.Get(0).(func(string) net.Listener); ok { r0 = rf(capability) } else { @@ -117,7 +228,6 @@ func (_m *MockProvider) Listen(capability string) (net.Listener, error) { } } - var r1 error if rf, ok := ret.Get(1).(func(string) error); ok { r1 = rf(capability) } else { @@ -133,7 +243,7 @@ type MockProvider_Listen_Call struct { } // Listen is a helper method to define mock.On call -// - capability string +// - capability string func (_e *MockProvider_Expecter) Listen(capability interface{}) *MockProvider_Listen_Call { return &MockProvider_Listen_Call{Call: _e.mock.On("Listen", capability)} } @@ -150,6 +260,11 @@ func (_c *MockProvider_Listen_Call) Return(_a0 net.Listener, _a1 error) *MockPro return _c } +func (_c *MockProvider_Listen_Call) RunAndReturn(run func(string) (net.Listener, error)) *MockProvider_Listen_Call { + _c.Call.Return(run) + return _c +} + // SessionStatus provides a mock function with given fields: func (_m *MockProvider) SessionStatus() string { ret := _m.Called() @@ -186,6 +301,11 @@ func (_c *MockProvider_SessionStatus_Call) Return(_a0 string) *MockProvider_Sess return _c } +func (_c *MockProvider_SessionStatus_Call) RunAndReturn(run func() string) *MockProvider_SessionStatus_Call { + _c.Call.Return(run) + return _c +} + // Start provides a mock function with given fields: func (_m *MockProvider) Start() error { ret := _m.Called() @@ -222,6 +342,11 @@ func (_c *MockProvider_Start_Call) Return(_a0 error) *MockProvider_Start_Call { return _c } +func (_c *MockProvider_Start_Call) RunAndReturn(run func() error) *MockProvider_Start_Call { + _c.Call.Return(run) + return _c +} + // Stop provides a mock function with given fields: func (_m *MockProvider) Stop() error { ret := _m.Called() @@ -258,6 +383,11 @@ func (_c *MockProvider_Stop_Call) Return(_a0 error) *MockProvider_Stop_Call { return _c } +func (_c *MockProvider_Stop_Call) RunAndReturn(run func() error) *MockProvider_Stop_Call { + _c.Call.Return(run) + return _c +} + // UpdateMeta provides a mock function with given fields: _a0 func (_m *MockProvider) UpdateMeta(_a0 map[string]string) { _m.Called(_a0) @@ -269,7 +399,7 @@ type MockProvider_UpdateMeta_Call struct { } // UpdateMeta is a helper method to define mock.On call -// - _a0 map[string]string +// - _a0 map[string]string func (_e *MockProvider_Expecter) UpdateMeta(_a0 interface{}) *MockProvider_UpdateMeta_Call { return &MockProvider_UpdateMeta_Call{Call: _e.mock.On("UpdateMeta", _a0)} } @@ -286,6 +416,11 @@ func (_c *MockProvider_UpdateMeta_Call) Return() *MockProvider_UpdateMeta_Call { return _c } +func (_c *MockProvider_UpdateMeta_Call) RunAndReturn(run func(map[string]string)) *MockProvider_UpdateMeta_Call { + _c.Call.Return(run) + return _c +} + type mockConstructorTestingTNewMockProvider interface { mock.TestingT Cleanup(func()) diff --git a/agent/hcp/testing.go b/agent/hcp/testing.go index e32602777da0..10e6a1114a68 100644 --- a/agent/hcp/testing.go +++ b/agent/hcp/testing.go @@ -10,6 +10,7 @@ import ( "sync" "time" + hcpgnm "github.com/hashicorp/hcp-sdk-go/clients/cloud-global-network-manager-service/preview/2022-02-15/client/global_network_manager_service" gnmmod "github.com/hashicorp/hcp-sdk-go/clients/cloud-global-network-manager-service/preview/2022-02-15/models" "github.com/hashicorp/hcp-sdk-go/resource" ) @@ -60,7 +61,7 @@ func (s *MockHCPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { s.mu.Lock() defer s.mu.Unlock() - if r.URL.Path == "/oauth/token" { + if r.URL.Path == "/oauth2/token" { mockTokenResponse(w) return } @@ -133,30 +134,31 @@ func enforceMethod(w http.ResponseWriter, r *http.Request, methods []string) boo } func mockTokenResponse(w http.ResponseWriter) { + w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - w.Write([]byte(`{access_token: "token", token_type: "Bearer"}`)) + + w.Write([]byte(`{"access_token": "token", "token_type": "Bearer"}`)) } func (s *MockHCPServer) handleStatus(r *http.Request, cluster resource.Resource) (interface{}, error) { - var req gnmmod.HashicorpCloudGlobalNetworkManager20220215AgentPushServerStateRequest + var req hcpgnm.AgentPushServerStateBody if err := json.NewDecoder(r.Body).Decode(&req); err != nil { return nil, err } - status := req.ServerState log.Printf("STATUS UPDATE: server=%s version=%s leader=%v hasLeader=%v healthy=%v tlsCertExpiryDays=%1.0f", - status.Name, - status.Version, - status.Raft.IsLeader, - status.Raft.KnownLeader, - status.Autopilot.Healthy, - time.Until(time.Time(status.TLS.CertExpiry)).Hours()/24, + req.ServerState.Name, + req.ServerState.Version, + req.ServerState.Raft.IsLeader, + req.ServerState.Raft.KnownLeader, + req.ServerState.Autopilot.Healthy, + time.Until(time.Time(req.ServerState.TLS.CertExpiry)).Hours()/24, ) - s.servers[status.Name] = &gnmmod.HashicorpCloudGlobalNetworkManager20220215Server{ - GossipPort: status.GossipPort, - ID: status.ID, - LanAddress: status.LanAddress, - Name: status.Name, - RPCPort: status.RPCPort, + s.servers[req.ServerState.Name] = &gnmmod.HashicorpCloudGlobalNetworkManager20220215Server{ + GossipPort: req.ServerState.GossipPort, + ID: req.ServerState.ID, + LanAddress: req.ServerState.LanAddress, + Name: req.ServerState.Name, + RPCPort: req.ServerState.RPCPort, } return "{}", nil } diff --git a/agent/health_endpoint_test.go b/agent/health_endpoint_test.go index bfe187ea7b47..b822bdde8217 100644 --- a/agent/health_endpoint_test.go +++ b/agent/health_endpoint_test.go @@ -1128,76 +1128,84 @@ func TestHealthServiceNodes_NodeMetaFilter(t *testing.T) { } for _, tst := range tests { t.Run(tst.name, func(t *testing.T) { - a := NewTestAgent(t, tst.config) - defer a.Shutdown() testrpc.WaitForLeader(t, a.RPC, "dc1") + testrpc.WaitForTestAgent(t, a.RPC, "dc1") + waitForStreamingToBeReady(t, a) - req, _ := http.NewRequest("GET", "/v1/health/service/consul?dc=dc1&node-meta=somekey:somevalue", nil) - resp := httptest.NewRecorder() - obj, err := a.srv.HealthServiceNodes(resp, req) - if err != nil { - t.Fatalf("err: %v", err) - } + encodedMeta := url.QueryEscape("somekey:somevalue") - assertIndex(t, resp) + var lastIndex uint64 + testutil.RunStep(t, "do initial read", func(t *testing.T) { + u := fmt.Sprintf("/v1/health/service/test?dc=dc1&node-meta=%s", encodedMeta) - cIndex, err := strconv.ParseUint(resp.Header().Get("X-Consul-Index"), 10, 64) - require.NoError(t, err) + req, err := http.NewRequest("GET", u, nil) + require.NoError(t, err) + resp := httptest.NewRecorder() + obj, err := a.srv.HealthServiceNodes(resp, req) + require.NoError(t, err) - // Should be a non-nil empty list - nodes := obj.(structs.CheckServiceNodes) - if nodes == nil || len(nodes) != 0 { - t.Fatalf("bad: %v", obj) - } + lastIndex = getIndex(t, resp) + require.True(t, lastIndex > 0) - args := &structs.RegisterRequest{ - Datacenter: "dc1", - Node: "bar", - Address: "127.0.0.1", - NodeMeta: map[string]string{"somekey": "somevalue"}, - Service: &structs.NodeService{ - ID: "test", - Service: "test", - }, - } + // Should be a non-nil empty list + nodes := obj.(structs.CheckServiceNodes) + require.NotNil(t, nodes) + require.Empty(t, nodes) + }) - var out struct{} - if err := a.RPC("Catalog.Register", args, &out); err != nil { - t.Fatalf("err: %v", err) - } + require.True(t, lastIndex > 0, "lastindex = %d", lastIndex) - args = &structs.RegisterRequest{ - Datacenter: "dc1", - Node: "bar2", - Address: "127.0.0.1", - NodeMeta: map[string]string{"somekey": "othervalue"}, - Service: &structs.NodeService{ - ID: "test2", - Service: "test", - }, - } + testutil.RunStep(t, "register item 1", func(t *testing.T) { + args := &structs.RegisterRequest{ + Datacenter: "dc1", + Node: "bar", + Address: "127.0.0.1", + NodeMeta: map[string]string{"somekey": "somevalue"}, + Service: &structs.NodeService{ + ID: "test", + Service: "test", + }, + } - if err := a.RPC("Catalog.Register", args, &out); err != nil { - t.Fatalf("err: %v", err) - } + var ignored struct{} + require.NoError(t, a.RPC("Catalog.Register", args, &ignored)) + }) - req, _ = http.NewRequest("GET", fmt.Sprintf("/v1/health/service/test?dc=dc1&node-meta=somekey:somevalue&index=%d&wait=10ms", cIndex), nil) - resp = httptest.NewRecorder() - obj, err = a.srv.HealthServiceNodes(resp, req) - if err != nil { - t.Fatalf("err: %v", err) - } + testutil.RunStep(t, "register item 2", func(t *testing.T) { + args := &structs.RegisterRequest{ + Datacenter: "dc1", + Node: "bar2", + Address: "127.0.0.1", + NodeMeta: map[string]string{"somekey": "othervalue"}, + Service: &structs.NodeService{ + ID: "test2", + Service: "test", + }, + } + var ignored struct{} + require.NoError(t, a.RPC("Catalog.Register", args, &ignored)) + }) - assertIndex(t, resp) + testutil.RunStep(t, "do blocking read", func(t *testing.T) { + u := fmt.Sprintf("/v1/health/service/test?dc=dc1&node-meta=%s&index=%d&wait=100ms&cached", encodedMeta, lastIndex) - // Should be a non-nil empty list for checks - nodes = obj.(structs.CheckServiceNodes) - if len(nodes) != 1 || nodes[0].Checks == nil || len(nodes[0].Checks) != 0 { - t.Fatalf("bad: %v", obj) - } + req, err := http.NewRequest("GET", u, nil) + require.NoError(t, err) + resp := httptest.NewRecorder() + obj, err := a.srv.HealthServiceNodes(resp, req) + require.NoError(t, err) + + assertIndex(t, resp) + + // Should be a non-nil empty list for checks + nodes := obj.(structs.CheckServiceNodes) + require.Len(t, nodes, 1) + require.NotNil(t, nodes[0].Checks) + require.Empty(t, nodes[0].Checks) - require.Equal(t, tst.queryBackend, resp.Header().Get("X-Consul-Query-Backend")) + require.Equal(t, tst.queryBackend, resp.Header().Get("X-Consul-Query-Backend")) + }) }) } } @@ -1637,6 +1645,7 @@ func testHealthIngressServiceNodes(t *testing.T, agentHCL string) { a := NewTestAgent(t, agentHCL) defer a.Shutdown() testrpc.WaitForLeader(t, a.RPC, "dc1") + waitForStreamingToBeReady(t, a) // Register gateway gatewayArgs := structs.TestRegisterIngressGateway(t) @@ -2038,3 +2047,9 @@ func peerQuerySuffix(peerName string) string { } return "&peer=" + peerName } + +func waitForStreamingToBeReady(t *testing.T, a *TestAgent) { + retry.Run(t, func(r *retry.R) { + require.True(r, a.rpcClientHealth.IsReadyForStreaming()) + }) +} diff --git a/agent/http.go b/agent/http.go index 24f0ed0bb838..32a4166a67cf 100644 --- a/agent/http.go +++ b/agent/http.go @@ -162,7 +162,7 @@ func (s *HTTPHandlers) ReloadConfig(newCfg *config.RuntimeConfig) error { // // The first call must not be concurrent with any other call. Subsequent calls // may be concurrent with HTTP requests since no state is modified. -func (s *HTTPHandlers) handler(enableDebug bool) http.Handler { +func (s *HTTPHandlers) handler() http.Handler { // Memoize multiple calls. if s.h != nil { return s.h @@ -205,17 +205,18 @@ func (s *HTTPHandlers) handler(enableDebug bool) http.Handler { // handlePProf takes the given pattern and pprof handler // and wraps it to add authorization and metrics handlePProf := func(pattern string, handler http.HandlerFunc) { + wrapper := func(resp http.ResponseWriter, req *http.Request) { - var token string - s.parseToken(req, &token) - // If enableDebug is not set, and ACLs are disabled, write - // an unauthorized response - if !enableDebug && s.checkACLDisabled() { - resp.WriteHeader(http.StatusUnauthorized) + // If enableDebug register wrapped pprof handlers + if !s.agent.enableDebug.Load() && s.checkACLDisabled() { + resp.WriteHeader(http.StatusNotFound) return } + var token string + s.parseToken(req, &token) + authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, nil, nil) if err != nil { resp.WriteHeader(http.StatusForbidden) @@ -247,7 +248,6 @@ func (s *HTTPHandlers) handler(enableDebug bool) http.Handler { handleFuncMetrics(pattern, s.wrap(bound, methods)) } - // Register wrapped pprof handlers handlePProf("/debug/pprof/", pprof.Index) handlePProf("/debug/pprof/cmdline", pprof.Cmdline) handlePProf("/debug/pprof/profile", pprof.Profile) @@ -320,8 +320,8 @@ func (s *HTTPHandlers) nodeName() string { // this regular expression is applied, so the regular expression substitution // results in: // -// /v1/acl/clone/foo?token=bar -> /v1/acl/clone/?token=bar -// ^---- $1 ----^^- $2 -^^-- $3 --^ +// /v1/acl/clone/foo?token=bar -> /v1/acl/clone/?token=bar +// ^---- $1 ----^^- $2 -^^-- $3 --^ // // And then the loop that looks for parameters called "token" does the last // step to get to the final redacted form. diff --git a/agent/http_oss.go b/agent/http_ce.go similarity index 99% rename from agent/http_oss.go rename to agent/http_ce.go index 94eb575c36e2..04c14b7f3204 100644 --- a/agent/http_oss.go +++ b/agent/http_ce.go @@ -36,7 +36,7 @@ func (s *HTTPHandlers) validateEnterpriseIntentionPartition(logName, partition s return nil } - // No special handling for wildcard namespaces as they are pointless in OSS. + // No special handling for wildcard namespaces as they are pointless in CE. return HTTPError{ StatusCode: http.StatusBadRequest, @@ -51,7 +51,7 @@ func (s *HTTPHandlers) validateEnterpriseIntentionNamespace(logName, ns string, return nil } - // No special handling for wildcard namespaces as they are pointless in OSS. + // No special handling for wildcard namespaces as they are pointless in CE. return HTTPError{ StatusCode: http.StatusBadRequest, diff --git a/agent/http_oss_test.go b/agent/http_ce_test.go similarity index 94% rename from agent/http_oss_test.go rename to agent/http_ce_test.go index 4bb392f61859..34b2ad9cdf4c 100644 --- a/agent/http_oss_test.go +++ b/agent/http_ce_test.go @@ -59,7 +59,7 @@ func newHttpClient(timeout time.Duration) *http.Client { } } -func TestHTTPAPI_MethodNotAllowed_OSS(t *testing.T) { +func TestHTTPAPI_MethodNotAllowed_CE(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short") } @@ -127,7 +127,7 @@ func TestHTTPAPI_MethodNotAllowed_OSS(t *testing.T) { } } -func TestHTTPAPI_OptionMethod_OSS(t *testing.T) { +func TestHTTPAPI_OptionMethod_CE(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short") } @@ -141,7 +141,8 @@ func TestHTTPAPI_OptionMethod_OSS(t *testing.T) { uri := fmt.Sprintf("http://%s%s", a.HTTPAddr(), path) req, _ := http.NewRequest("OPTIONS", uri, nil) resp := httptest.NewRecorder() - a.srv.handler(true).ServeHTTP(resp, req) + a.enableDebug.Store(true) + a.srv.handler().ServeHTTP(resp, req) allMethods := append([]string{"OPTIONS"}, methods...) if resp.Code != http.StatusOK { @@ -167,7 +168,7 @@ func TestHTTPAPI_OptionMethod_OSS(t *testing.T) { } } -func TestHTTPAPI_AllowedNets_OSS(t *testing.T) { +func TestHTTPAPI_AllowedNets_CE(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short") } @@ -187,7 +188,10 @@ func TestHTTPAPI_AllowedNets_OSS(t *testing.T) { req, _ := http.NewRequest(method, uri, nil) req.RemoteAddr = "192.168.1.2:5555" resp := httptest.NewRecorder() - a.srv.handler(true).ServeHTTP(resp, req) + + a.enableDebug.Store(true) + + a.srv.handler().ServeHTTP(resp, req) require.Equal(t, http.StatusForbidden, resp.Code, "%s %s", method, path) }) diff --git a/agent/http_decode_test.go b/agent/http_decode_test.go index 50347f6e1ea4..a11f4ce83116 100644 --- a/agent/http_decode_test.go +++ b/agent/http_decode_test.go @@ -33,7 +33,6 @@ package agent import ( "bytes" "fmt" - "strings" "testing" "time" @@ -791,21 +790,7 @@ var translateServiceIDTCs = []translateKeyTestCase{ }, } -// ACLPolicySetRequest: -// Policy structs.ACLPolicy -// ID string -// Name string -// Description string -// Rules string -// Syntax acl.SyntaxVersion -// Datacenters []string -// Hash []uint8 -// RaftIndex structs.RaftIndex -// CreateIndex uint64 -// ModifyIndex uint64 -// Datacenter string -// WriteRequest structs.WriteRequest -// Token string +// structs.ACLPolicySetRequest func TestDecodeACLPolicyWrite(t *testing.T) { for _, tc := range hashTestCases { @@ -833,35 +818,7 @@ func TestDecodeACLPolicyWrite(t *testing.T) { } } -// ACLTokenSetRequest: -// ACLToken structs.ACLToken -// AccessorID string -// SecretID string -// Description string -// Policies []structs.ACLTokenPolicyLink -// ID string -// Name string -// Roles []structs.ACLTokenRoleLink -// ID string -// Name string -// ServiceIdentities []*structs.ACLServiceIdentity -// ServiceName string -// Datacenters []string -// Type string -// Rules string -// Local bool -// AuthMethod string -// ExpirationTime *time.Time -// ExpirationTTL time.Duration -// CreateTime time.Time -// Hash []uint8 -// RaftIndex structs.RaftIndex -// CreateIndex uint64 -// ModifyIndex uint64 -// Create bool -// Datacenter string -// WriteRequest structs.WriteRequest -// Token string +// structs.ACLTokenSetRequest func TestDecodeACLToken(t *testing.T) { for _, tc := range translateValueTestCases { t.Run(tc.desc, func(t *testing.T) { @@ -1079,76 +1036,7 @@ func TestDecodeAgentRegisterCheck(t *testing.T) { } -// ServiceDefinition: -// Kind structs.ServiceKind -// ID string -// Name string -// Tags []string -// Address string -// TaggedAddresses map[string]structs.ServiceAddress -// Address string -// Port int -// Meta map[string]string -// Port int -// Check structs.CheckType -// CheckID types.CheckID -// Name string -// Status string -// Notes string -// ScriptArgs []string -// HTTP string -// Header map[string][]string -// Method string -// TCP string -// Interval time.Duration -// AliasNode string -// AliasService string -// DockerContainerID string -// Shell string -// GRPC string -// GRPCUseTLS bool -// TLSServerName string -// TLSSkipVerify bool -// Timeout time.Duration -// TTL time.Duration -// ProxyHTTP string -// ProxyGRPC string -// DeregisterCriticalServiceAfter time.Duration -// OutputMaxSize int -// Checks structs.CheckTypes -// Weights *structs.Weights -// Passing int -// Warning int -// Token string -// EnableTagOverride bool -// Proxy *structs.ConnectProxyConfig -// DestinationServiceName string -// DestinationServiceID string -// LocalServiceAddress string -// LocalServicePort int -// Config map[string]interface {} -// Upstreams structs.Upstreams -// DestinationType string -// DestinationNamespace string -// DestinationName string -// Datacenter string -// LocalBindAddress string -// LocalBindPort int -// Config map[string]interface {} -// MeshGateway structs.MeshGatewayConfig -// Mode structs.MeshGatewayMode -// MeshGateway structs.MeshGatewayConfig -// Expose structs.ExposeConfig -// Checks bool -// Paths []structs.ExposePath -// ListenerPort int -// Path string -// LocalPathPort int -// Protocol string -// ParsedFromCheck bool -// Connect *structs.ServiceConnect -// Native bool -// SidecarService *structs.ServiceDefinition +// structs.ServiceDefinition func TestDecodeAgentRegisterService(t *testing.T) { // key translation tests: // decodeCB fields: @@ -1969,133 +1857,7 @@ func TestDecodeAgentRegisterService(t *testing.T) { } -// RegisterRequest: -// Datacenter string -// ID types.NodeID -// Node string -// Address string -// TaggedAddresses map[string]string -// NodeMeta map[string]string -// Service *structs.NodeService -// Kind structs.ServiceKind -// ID string -// Service string -// Tags []string -// Address string -// TaggedAddresses map[string]structs.ServiceAddress -// Address string -// Port int -// Meta map[string]string -// Port int -// Weights *structs.Weights -// Passing int -// Warning int -// EnableTagOverride bool -// Proxy structs.ConnectProxyConfig -// DestinationServiceName string -// DestinationServiceID string -// LocalServiceAddress string -// LocalServicePort int -// Config map[string]interface {} -// Upstreams structs.Upstreams -// DestinationType string -// DestinationNamespace string -// DestinationName string -// Datacenter string -// LocalBindAddress string -// LocalBindPort int -// Config map[string]interface {} -// MeshGateway structs.MeshGatewayConfig -// Mode structs.MeshGatewayMode -// MeshGateway structs.MeshGatewayConfig -// Expose structs.ExposeConfig -// Checks bool -// Paths []structs.ExposePath -// ListenerPort int -// Path string -// LocalPathPort int -// Protocol string -// ParsedFromCheck bool -// Connect structs.ServiceConnect -// Native bool -// SidecarService *structs.ServiceDefinition -// Kind structs.ServiceKind -// ID string -// Name string -// Tags []string -// Address string -// TaggedAddresses map[string]structs.ServiceAddress -// Meta map[string]string -// Port int -// Check structs.CheckType -// CheckID types.CheckID -// Name string -// Status string -// Notes string -// ScriptArgs []string -// HTTP string -// Header map[string][]string -// Method string -// TCP string -// Interval time.Duration -// AliasNode string -// AliasService string -// DockerContainerID string -// Shell string -// GRPC string -// GRPCUseTLS bool -// TLSServerName string -// TLSSkipVerify bool -// Timeout time.Duration -// TTL time.Duration -// ProxyHTTP string -// ProxyGRPC string -// DeregisterCriticalServiceAfter time.Duration -// OutputMaxSize int -// Checks structs.CheckTypes -// Weights *structs.Weights -// Token string -// EnableTagOverride bool -// Proxy *structs.ConnectProxyConfig -// Connect *structs.ServiceConnect -// LocallyRegisteredAsSidecar bool -// RaftIndex structs.RaftIndex -// CreateIndex uint64 -// ModifyIndex uint64 -// Check *structs.HealthCheck -// Node string -// CheckID types.CheckID -// Name string -// Status string -// Notes string -// Output string -// ServiceID string -// ServiceName string -// ServiceTags []string -// Definition structs.HealthCheckDefinition -// HTTP string -// TLSServerName string -// TLSSkipVerify bool -// Header map[string][]string -// Method string -// TCP string -// Interval time.Duration -// OutputMaxSize uint -// Timeout time.Duration -// DeregisterCriticalServiceAfter time.Duration -// ScriptArgs []string -// DockerContainerID string -// Shell string -// GRPC string -// GRPCUseTLS bool -// AliasNode string -// AliasService string -// TTL time.Duration -// RaftIndex structs.RaftIndex -// Checks structs.HealthChecks -// SkipNodeUpdate bool -// WriteRequest structs.WriteRequest -// Token string +// structs.RegisterRequest func TestDecodeCatalogRegister(t *testing.T) { for _, tc := range durationTestCases { t.Run(tc.desc, func(t *testing.T) { @@ -2164,28 +1926,7 @@ func TestDecodeCatalogRegister(t *testing.T) { } } -// IntentionRequest: -// Datacenter string -// Op structs.IntentionOp -// Intention *structs.Intention -// ID string -// Description string -// SourceNS string -// SourceName string -// DestinationNS string -// DestinationName string -// SourceType structs.IntentionSourceType -// Action structs.IntentionAction -// Meta map[string]string -// Precedence int -// CreatedAt time.Time mapstructure:'-' -// UpdatedAt time.Time mapstructure:'-' -// Hash []uint8 -// RaftIndex structs.RaftIndex -// CreateIndex uint64 -// ModifyIndex uint64 -// WriteRequest structs.WriteRequest -// Token string +// structs.IntentionRequest func TestDecodeIntentionCreate(t *testing.T) { for _, tc := range append(hashTestCases, timestampTestCases...) { t.Run(tc.desc, func(t *testing.T) { @@ -2300,22 +2041,7 @@ func TestDecodeOperatorAutopilotConfiguration(t *testing.T) { } } -// SessionRequest: -// Datacenter string -// Op structs.SessionOp -// Session structs.Session -// ID string -// Name string -// Node string -// Checks []types.CheckID -// LockDelay time.Duration -// Behavior structs.SessionBehavior -// TTL string -// RaftIndex structs.RaftIndex -// CreateIndex uint64 -// ModifyIndex uint64 -// WriteRequest structs.WriteRequest -// Token string +// structs.SessionRequest func TestDecodeSessionCreate(t *testing.T) { // outSession var is shared among test cases b/c of the // nature/signature of the FixupChecks callback. @@ -2454,137 +2180,7 @@ func TestDecodeSessionCreate(t *testing.T) { } } -// TxnOps: -// KV *api.KVTxnOp -// Verb api.KVOp -// Key string -// Value []uint8 -// Flags uint64 -// Index uint64 -// Session string -// Node *api.NodeTxnOp -// Verb api.NodeOp -// Node api.Node -// ID string -// Node string -// Address string -// Datacenter string -// TaggedAddresses map[string]string -// Meta map[string]string -// CreateIndex uint64 -// ModifyIndex uint64 -// Service *api.ServiceTxnOp -// Verb api.ServiceOp -// Node string -// Service api.AgentService -// Kind api.ServiceKind -// ID string -// Service string -// Tags []string -// Meta map[string]string -// Port int -// Address string -// TaggedAddresses map[string]api.ServiceAddress -// Address string -// Port int -// Weights api.AgentWeights -// Passing int -// Warning int -// EnableTagOverride bool -// CreateIndex uint64 -// ModifyIndex uint64 -// ContentHash string -// Proxy *api.AgentServiceConnectProxyConfig -// DestinationServiceName string -// DestinationServiceID string -// LocalServiceAddress string -// LocalServicePort int -// Config map[string]interface {} -// Upstreams []api.Upstream -// DestinationType api.UpstreamDestType -// DestinationNamespace string -// DestinationName string -// Datacenter string -// LocalBindAddress string -// LocalBindPort int -// Config map[string]interface {} -// MeshGateway api.MeshGatewayConfig -// Mode api.MeshGatewayMode -// MeshGateway api.MeshGatewayConfig -// Expose api.ExposeConfig -// Checks bool -// Paths []api.ExposePath -// ListenerPort int -// Path string -// LocalPathPort int -// Protocol string -// ParsedFromCheck bool -// Connect *api.AgentServiceConnect -// Native bool -// SidecarService *api.AgentServiceRegistration -// Kind api.ServiceKind -// ID string -// Name string -// Tags []string -// Port int -// Address string -// TaggedAddresses map[string]api.ServiceAddress -// EnableTagOverride bool -// Meta map[string]string -// Weights *api.AgentWeights -// Check *api.AgentServiceCheck -// CheckID string -// Name string -// Args []string -// DockerContainerID string -// Shell string -// Interval string -// Timeout string -// TTL string -// HTTP string -// Header map[string][]string -// Method string -// TCP string -// Status string -// Notes string -// TLSServerName string -// TLSSkipVerify bool -// GRPC string -// GRPCUseTLS bool -// AliasNode string -// AliasService string -// DeregisterCriticalServiceAfter string -// Checks api.AgentServiceChecks -// Proxy *api.AgentServiceConnectProxyConfig -// Connect *api.AgentServiceConnect -// Check *api.CheckTxnOp -// Verb api.CheckOp -// Check api.HealthCheck -// Node string -// CheckID string -// Name string -// Status string -// Notes string -// Output string -// ServiceID string -// ServiceName string -// ServiceTags []string -// Definition api.HealthCheckDefinition -// HTTP string -// Header map[string][]string -// Method string -// Body string -// TLSServerName string -// TLSSkipVerify bool -// TCP string -// IntervalDuration time.Duration -// TimeoutDuration time.Duration -// DeregisterCriticalServiceAfterDuration time.Duration -// Interval api.ReadableDuration -// Timeout api.ReadableDuration -// DeregisterCriticalServiceAfter api.ReadableDuration -// CreateIndex uint64 -// ModifyIndex uint64 +// structs.TxnOps func TestDecodeTxnConvertOps(t *testing.T) { for _, tc := range durationTestCases { t.Run(tc.desc, func(t *testing.T) { diff --git a/agent/http_test.go b/agent/http_test.go index 60b0bd97f7ee..d0cfaba3770f 100644 --- a/agent/http_test.go +++ b/agent/http_test.go @@ -20,7 +20,7 @@ import ( "time" "github.com/NYTimes/gziphandler" - cleanhttp "github.com/hashicorp/go-cleanhttp" + "github.com/hashicorp/go-cleanhttp" "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -190,7 +190,9 @@ func TestSetupHTTPServer_HTTP2(t *testing.T) { err = setupHTTPS(httpServer, noopConnState, time.Second) require.NoError(t, err) - srvHandler := a.srv.handler(true) + a.enableDebug.Store(true) + + srvHandler := a.srv.handler() mux, ok := srvHandler.(*wrappedMux) require.True(t, ok, "expected a *wrappedMux, got %T", handler) mux.mux.HandleFunc("/echo", handler) @@ -385,7 +387,10 @@ func TestHTTPAPI_Ban_Nonprintable_Characters(t *testing.T) { t.Fatal(err) } resp := httptest.NewRecorder() - a.srv.handler(true).ServeHTTP(resp, req) + + a.enableDebug.Store(true) + + a.srv.handler().ServeHTTP(resp, req) if got, want := resp.Code, http.StatusBadRequest; got != want { t.Fatalf("bad response code got %d want %d", got, want) } @@ -408,7 +413,10 @@ func TestHTTPAPI_Allow_Nonprintable_Characters_With_Flag(t *testing.T) { t.Fatal(err) } resp := httptest.NewRecorder() - a.srv.handler(true).ServeHTTP(resp, req) + + a.enableDebug.Store(true) + + a.srv.handler().ServeHTTP(resp, req) // Key doesn't actually exist so we should get 404 if got, want := resp.Code, http.StatusNotFound; got != want { t.Fatalf("bad response code got %d want %d", got, want) @@ -547,7 +555,10 @@ func requireHasHeadersSet(t *testing.T, a *TestAgent, path string) { resp := httptest.NewRecorder() req, _ := http.NewRequest("GET", path, nil) - a.srv.handler(true).ServeHTTP(resp, req) + + a.enableDebug.Store(true) + + a.srv.handler().ServeHTTP(resp, req) hdrs := resp.Header() require.Equal(t, "*", hdrs.Get("Access-Control-Allow-Origin"), @@ -608,14 +619,20 @@ func TestAcceptEncodingGzip(t *testing.T) { // negotiation, but since this call doesn't go through a real // transport, the header has to be set manually req.Header["Accept-Encoding"] = []string{"gzip"} - a.srv.handler(true).ServeHTTP(resp, req) + + a.enableDebug.Store(true) + + a.srv.handler().ServeHTTP(resp, req) require.Equal(t, 200, resp.Code) require.Equal(t, "", resp.Header().Get("Content-Encoding")) resp = httptest.NewRecorder() req, _ = http.NewRequest("GET", "/v1/kv/long", nil) req.Header["Accept-Encoding"] = []string{"gzip"} - a.srv.handler(true).ServeHTTP(resp, req) + + a.enableDebug.Store(true) + + a.srv.handler().ServeHTTP(resp, req) require.Equal(t, 200, resp.Code) require.Equal(t, "gzip", resp.Header().Get("Content-Encoding")) } @@ -961,8 +978,10 @@ func TestHTTPServer_PProfHandlers_EnableDebug(t *testing.T) { resp := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/debug/pprof/profile?seconds=1", nil) + a.enableDebug.Store(true) + httpServer := &HTTPHandlers{agent: a.Agent} - httpServer.handler(true).ServeHTTP(resp, req) + httpServer.handler().ServeHTTP(resp, req) require.Equal(t, http.StatusOK, resp.Code) } @@ -980,9 +999,9 @@ func TestHTTPServer_PProfHandlers_DisableDebugNoACLs(t *testing.T) { req, _ := http.NewRequest("GET", "/debug/pprof/profile", nil) httpServer := &HTTPHandlers{agent: a.Agent} - httpServer.handler(false).ServeHTTP(resp, req) + httpServer.handler().ServeHTTP(resp, req) - require.Equal(t, http.StatusUnauthorized, resp.Code) + require.Equal(t, http.StatusNotFound, resp.Code) } func TestHTTPServer_PProfHandlers_ACLs(t *testing.T) { @@ -1061,7 +1080,10 @@ func TestHTTPServer_PProfHandlers_ACLs(t *testing.T) { t.Run(fmt.Sprintf("case %d (%#v)", i, c), func(t *testing.T) { req, _ := http.NewRequest("GET", fmt.Sprintf("%s?token=%s", c.endpoint, c.token), nil) resp := httptest.NewRecorder() - a.srv.handler(true).ServeHTTP(resp, req) + + a.enableDebug.Store(true) + + a.srv.handler().ServeHTTP(resp, req) assert.Equal(t, c.code, resp.Code) }) } @@ -1371,7 +1393,10 @@ func TestEnableWebUI(t *testing.T) { req, _ := http.NewRequest("GET", "/ui/", nil) resp := httptest.NewRecorder() - a.srv.handler(true).ServeHTTP(resp, req) + + a.enableDebug.Store(true) + + a.srv.handler().ServeHTTP(resp, req) require.Equal(t, http.StatusOK, resp.Code) // Validate that it actually sent the index page we expect since an error @@ -1400,7 +1425,10 @@ func TestEnableWebUI(t *testing.T) { { req, _ := http.NewRequest("GET", "/ui/", nil) resp := httptest.NewRecorder() - a.srv.handler(true).ServeHTTP(resp, req) + + a.enableDebug.Store(true) + + a.srv.handler().ServeHTTP(resp, req) require.Equal(t, http.StatusOK, resp.Code) require.Contains(t, resp.Body.String(), ` dst1 <== Conn.CopyBytes ==> src2 <---> dst2 +// src1 <---> dst1 <== Conn.CopyBytes ==> src2 <---> dst2 // // The returned values are the src1 and dst2 which should be able to send and // receive to each other via the Conn, the Conn itself (not running), and a diff --git a/connect/resolver.go b/connect/resolver.go index 54ca27267467..68d56cc7b972 100644 --- a/connect/resolver.go +++ b/connect/resolver.go @@ -78,6 +78,9 @@ type ConsulResolver struct { // Datacenter to resolve in, empty indicates agent's local DC. Datacenter string + + // Specifies the expression used to filter the queries results prior to returning the data. + Filter string } // Resolve performs service discovery against the local Consul agent and returns @@ -173,6 +176,7 @@ func (cr *ConsulResolver) queryOptions(ctx context.Context) *api.QueryOptions { // For prepared queries Connect: true, + Filter: cr.Filter, } return q.WithContext(ctx) } diff --git a/connect/resolver_test.go b/connect/resolver_test.go index ba082c96bb2d..e84ea1f2b935 100644 --- a/connect/resolver_test.go +++ b/connect/resolver_test.go @@ -68,6 +68,9 @@ func TestConsulResolver_Resolve(t *testing.T) { Proxy: &api.AgentServiceConnectProxyConfig{ DestinationServiceName: "web", }, + Meta: map[string]string{ + "MetaKey": "MetaValue", + }, } err = client.Agent().ServiceRegister(regProxy) require.Nil(t, err) @@ -75,6 +78,7 @@ func TestConsulResolver_Resolve(t *testing.T) { // And another proxy so we can test handling with multiple endpoints returned regProxy.Port = 9091 regProxy.ID = "web-proxy-2" + regProxy.Meta = map[string]string{} err = client.Agent().ServiceRegister(regProxy) require.Nil(t, err) @@ -110,6 +114,7 @@ func TestConsulResolver_Resolve(t *testing.T) { Name string Type int Datacenter string + Filter string } tests := []struct { name string @@ -145,6 +150,32 @@ func TestConsulResolver_Resolve(t *testing.T) { wantCertURI: connect.TestSpiffeIDServiceWithHost(t, "db", ""), wantErr: false, }, + { + name: "service discovery with filter", + fields: fields{ + Namespace: "default", + Name: "web", + Type: ConsulResolverTypeService, + Filter: "Service.Meta[`MetaKey`] == `MetaValue`", + }, + // Want empty host since we don't enforce trust domain outside of TLS and + // don't need to load the current one this way. + wantCertURI: connect.TestSpiffeIDServiceWithHost(t, "web", ""), + wantErr: false, + addrs: []string{ + agent.Config.AdvertiseAddrLAN.String() + ":9090", + }, + }, + { + name: "service discovery with filter", + fields: fields{ + Namespace: "default", + Name: "web", + Type: ConsulResolverTypeService, + Filter: "`AnotherMetaValue` in Service.Meta.MetaKey", + }, + wantErr: true, + }, { name: "Bad Type errors", fields: fields{ @@ -206,6 +237,7 @@ func TestConsulResolver_Resolve(t *testing.T) { Name: tt.fields.Name, Type: tt.fields.Type, Datacenter: tt.fields.Datacenter, + Filter: tt.fields.Filter, } // WithCancel just to have a cancel func in scope to assign in the if // clause. diff --git a/docs/README.md b/docs/README.md index 0c24ff8f9920..da3c361ee91f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -47,7 +47,7 @@ contain other important source related to Consul. * [ui] contains the source code for the Consul UI. * [website] contains the source for [consul.io](https://www.consul.io/). A pull requests can update the source code and Consul's documentation at the same time. -* [.circleci] and [.github] contain the source for our CI and GitHub repository +* [.github] contains the source for our CI and GitHub repository automation. * [.changelog] contains markdown files that are used by [hashicorp/go-changelog] to produce the [CHANGELOG.md]. @@ -58,7 +58,6 @@ contain other important source related to Consul. [ui]: https://github.com/hashicorp/consul/tree/main/ui [website]: https://github.com/hashicorp/consul/tree/main/website -[.circleci]: https://github.com/hashicorp/consul/tree/main/.circleci [.github]: https://github.com/hashicorp/consul/tree/main/.github [.changelog]: https://github.com/hashicorp/consul/tree/main/.changelog [hashicorp/go-changelog]: https://github.com/hashicorp/go-changelog diff --git a/docs/config/checklist-adding-config-fields.md b/docs/config/checklist-adding-config-fields.md index 7a47eb84159f..f90fb448595f 100644 --- a/docs/config/checklist-adding-config-fields.md +++ b/docs/config/checklist-adding-config-fields.md @@ -11,7 +11,7 @@ through in your PR description**. Examples of special cases this doesn't cover are: - If the config needs special treatment like a different default in `-dev` mode - or differences between OSS and Enterprise. + or differences between CE and Enterprise. - If custom logic is needed to support backwards compatibility when changing syntax or semantics of anything diff --git a/docs/persistence/README.md b/docs/persistence/README.md index bb907d7d133d..a9388c714c94 100644 --- a/docs/persistence/README.md +++ b/docs/persistence/README.md @@ -58,11 +58,11 @@ There are two styles for defining table indexes. The original style uses generic implementations from [hashicorp/go-memdb] (ex: `StringFieldIndex`). These indexes use [reflect] to find values for an index. These generic indexers work well when the index value is a single value available directly from the struct field, and there are no -oss/enterprise differences. +ce/enterprise differences. The second style of indexers are custom indexers implemented using only functions and based on the types defined in [indexer.go]. This style of index works well when the index -value is a value derived from one or multiple fields, or when there are oss/enterprise +value is a value derived from one or multiple fields, or when there are ce/enterprise differences between the indexes. [reflect]: https://golang.org/pkg/reflect/ diff --git a/go.mod b/go.mod index fb06f28b1c0a..a7f83030cb85 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/hashicorp/consul -go 1.18 +go 1.20 replace github.com/hashicorp/consul/api => ./api @@ -15,30 +15,30 @@ require ( github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e github.com/armon/go-metrics v0.3.10 github.com/armon/go-radix v1.0.0 - github.com/aws/aws-sdk-go v1.42.34 - github.com/coredns/coredns v1.6.6 + github.com/aws/aws-sdk-go v1.44.289 + github.com/coredns/coredns v1.10.1 github.com/coreos/go-oidc v2.1.0+incompatible github.com/docker/go-connections v0.3.0 - github.com/envoyproxy/go-control-plane v0.10.1 + github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 github.com/fsnotify/fsnotify v1.5.1 - github.com/go-openapi/runtime v0.24.1 + github.com/go-openapi/runtime v0.25.0 github.com/go-openapi/strfmt v0.21.3 - github.com/golang/protobuf v1.5.0 - github.com/google/go-cmp v0.5.8 + github.com/golang/protobuf v1.5.2 + github.com/google/go-cmp v0.5.9 github.com/google/gofuzz v1.2.0 - github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22 + github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 github.com/google/tcpproxy v0.0.0-20180808230851-dfa16c61dad2 github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 github.com/hashicorp/consul-awsauth v0.0.0-20220713182709-05ac1c5c2706 github.com/hashicorp/consul-net-rpc v0.0.0-20220307172752-3602954411b4 - github.com/hashicorp/consul/api v1.15.3 - github.com/hashicorp/consul/proto-public v0.1.0 - github.com/hashicorp/consul/sdk v0.11.0 + github.com/hashicorp/consul/api v1.18.0 + github.com/hashicorp/consul/proto-public v0.2.1 + github.com/hashicorp/consul/sdk v0.13.0 github.com/hashicorp/go-bexpr v0.1.2 github.com/hashicorp/go-checkpoint v0.5.0 - github.com/hashicorp/go-cleanhttp v0.5.1 + github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-connlimit v0.3.0 - github.com/hashicorp/go-discover v0.0.0-20220411141802-20db45f7f0f9 + github.com/hashicorp/go-discover v0.0.0-20220714221025-1c234a67149a github.com/hashicorp/go-hclog v1.2.1 github.com/hashicorp/go-memdb v1.3.4 github.com/hashicorp/go-multierror v1.1.1 @@ -49,8 +49,8 @@ require ( github.com/hashicorp/go-version v1.2.1 github.com/hashicorp/golang-lru v0.5.4 github.com/hashicorp/hcl v1.0.0 - github.com/hashicorp/hcp-scada-provider v0.1.0 - github.com/hashicorp/hcp-sdk-go v0.23.1-0.20220921131124-49168300a7dc + github.com/hashicorp/hcp-scada-provider v0.2.3 + github.com/hashicorp/hcp-sdk-go v0.44.1-0.20230508124639-28da4c5b03f3 github.com/hashicorp/hil v0.0.0-20200423225030-a18a1cd20038 github.com/hashicorp/memberlist v0.5.0 github.com/hashicorp/raft v1.3.11 @@ -62,116 +62,122 @@ require ( github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 github.com/imdario/mergo v0.3.13 github.com/kr/text v0.2.0 - github.com/miekg/dns v1.1.41 + github.com/miekg/dns v1.1.50 github.com/mitchellh/cli v1.1.0 github.com/mitchellh/copystructure v1.0.0 github.com/mitchellh/go-testing-interface v1.14.0 github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452 github.com/mitchellh/hashstructure/v2 v2.0.2 - github.com/mitchellh/mapstructure v1.4.3 + github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/pointerstructure v1.2.1 github.com/mitchellh/reflectwalk v1.0.1 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.4.0 - github.com/rboyer/safeio v0.2.1 + github.com/prometheus/client_golang v1.14.0 + github.com/rboyer/safeio v0.2.3 github.com/ryanuber/columnize v2.1.2+incompatible github.com/shirou/gopsutil/v3 v3.22.8 - github.com/stretchr/testify v1.8.0 + github.com/stretchr/testify v1.8.3 go.etcd.io/bbolt v1.3.5 go.uber.org/goleak v1.1.10 - golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d - golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd - golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58 - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 - golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e - google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 - google.golang.org/grpc v1.37.1 - google.golang.org/protobuf v1.27.1 + golang.org/x/crypto v0.12.0 + golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 + golang.org/x/net v0.14.0 + golang.org/x/oauth2 v0.6.0 + golang.org/x/sync v0.3.0 + golang.org/x/sys v0.11.0 + golang.org/x/time v0.3.0 + google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef + google.golang.org/grpc v1.52.3 + google.golang.org/protobuf v1.28.1 gopkg.in/square/go-jose.v2 v2.5.1 gotest.tools/v3 v3.0.3 - k8s.io/api v0.18.2 - k8s.io/apimachinery v0.18.2 - k8s.io/client-go v0.18.2 + k8s.io/api v0.26.1 + k8s.io/apimachinery v0.26.1 + k8s.io/client-go v0.26.1 ) require ( - cloud.google.com/go v0.65.0 // indirect - github.com/Azure/azure-sdk-for-go v44.0.0+incompatible // indirect + cloud.google.com/go/compute v1.14.0 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect - github.com/Azure/go-autorest/autorest v0.11.18 // indirect - github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect - github.com/Azure/go-autorest/autorest/azure/auth v0.5.0 // indirect - github.com/Azure/go-autorest/autorest/azure/cli v0.4.0 // indirect + github.com/Azure/go-autorest/autorest v0.11.28 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect + github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 // indirect + github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect github.com/Azure/go-autorest/autorest/validation v0.3.0 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect - github.com/DataDog/datadog-go v3.2.0+incompatible // indirect - github.com/Microsoft/go-winio v0.4.3 // indirect - github.com/PuerkitoBio/purell v1.1.1 // indirect - github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/DataDog/datadog-go v4.8.2+incompatible // indirect + github.com/Microsoft/go-winio v0.5.1 // indirect github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect github.com/boltdb/bolt v1.3.1 // indirect github.com/census-instrumentation/opencensus-proto v0.2.1 // indirect - github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible // indirect github.com/circonus-labs/circonusllhist v0.1.3 // indirect - github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe // indirect + github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661 // indirect github.com/digitalocean/godo v1.10.0 // indirect - github.com/dimchansky/utfbom v1.1.0 // indirect + github.com/dimchansky/utfbom v1.1.1 // indirect + github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/envoyproxy/protoc-gen-validate v0.1.0 // indirect github.com/fatih/color v1.13.0 // indirect - github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect github.com/frankban/quicktest v1.11.0 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect - github.com/go-openapi/analysis v0.21.2 // indirect - github.com/go-openapi/errors v0.20.2 // indirect + github.com/go-openapi/analysis v0.21.4 // indirect + github.com/go-openapi/errors v0.20.3 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.19.6 // indirect - github.com/go-openapi/loads v0.21.1 // indirect - github.com/go-openapi/spec v0.20.4 // indirect - github.com/go-openapi/swag v0.21.1 // indirect - github.com/go-openapi/validate v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/loads v0.21.2 // indirect + github.com/go-openapi/spec v0.20.8 // indirect + github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-openapi/validate v0.22.1 // indirect github.com/go-ozzo/ozzo-validation v3.6.0+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect - github.com/golang/snappy v0.0.1 // indirect - github.com/google/btree v1.0.0 // indirect + github.com/golang-jwt/jwt/v4 v4.2.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/snappy v0.0.3 // indirect + github.com/google/btree v1.0.1 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-querystring v1.0.0 // indirect - github.com/googleapis/gax-go/v2 v2.0.5 // indirect - github.com/googleapis/gnostic v0.2.0 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.1 // indirect + github.com/googleapis/gax-go/v2 v2.7.0 // indirect github.com/gophercloud/gophercloud v0.3.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.0 // indirect - github.com/hashicorp/go-msgpack v1.1.5 // indirect + github.com/hashicorp/go-msgpack v0.5.5 // indirect + github.com/hashicorp/go-msgpack/v2 v2.0.0 // indirect github.com/hashicorp/go-retryablehttp v0.6.7 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/mdns v1.0.4 // indirect - github.com/hashicorp/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69 // indirect + github.com/hashicorp/net-rpc-msgpackrpc/v2 v2.0.0 // indirect github.com/hashicorp/raft-boltdb v0.0.0-20211202195631-7d34b9fb3f42 // indirect github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f // indirect - github.com/json-iterator/go v1.1.9 // indirect - github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/linode/linodego v0.10.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect @@ -181,38 +187,43 @@ require ( github.com/posener/complete v1.2.3 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect - github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.9.1 // indirect - github.com/prometheus/procfs v0.0.8 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.39.0 // indirect + github.com/prometheus/procfs v0.8.0 // indirect github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect - github.com/sirupsen/logrus v1.4.2 // indirect + github.com/sirupsen/logrus v1.7.0 // indirect github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.4.0 // indirect + github.com/stretchr/objx v0.5.0 // indirect github.com/tencentcloud/tencentcloud-sdk-go v1.0.162 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/numcpus v0.4.0 // indirect github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 // indirect github.com/vmware/govmomi v0.18.0 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect - go.mongodb.org/mongo-driver v1.10.0 // indirect - go.opencensus.io v0.22.4 // indirect + go.mongodb.org/mongo-driver v1.11.0 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/otel v1.11.1 // indirect + go.opentelemetry.io/otel/trace v1.11.1 // indirect go.opentelemetry.io/proto/otlp v0.7.0 // indirect - golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect - golang.org/x/text v0.3.7 // indirect - golang.org/x/tools v0.1.0 // indirect - google.golang.org/api v0.30.0 // indirect - google.golang.org/appengine v1.6.6 // indirect + golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/term v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect + golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect + google.golang.org/api v0.109.0 // indirect + google.golang.org/appengine v1.6.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/resty.v1 v1.12.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/klog v1.0.0 // indirect - k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 // indirect - sigs.k8s.io/structured-merge-diff/v3 v3.0.0 // indirect - sigs.k8s.io/yaml v1.2.0 // indirect + k8s.io/klog/v2 v2.90.0 // indirect + k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect + k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 36fa68acc852..edbd49dcda6e 100644 --- a/go.sum +++ b/go.sum @@ -1,128 +1,76 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v32.6.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v44.0.0+incompatible h1:e82Yv2HNpS0kuyeCrV29OPKvEiqfs2/uJHic3/3iKdg= +cloud.google.com/go v0.105.0 h1:DNtEKRBAAzeS4KyIory52wWHuClNaXJ5x1F7xa4q+5Y= +cloud.google.com/go/compute v1.14.0 h1:hfm2+FfxVmnRlh6LpB7cg1ZNU+5edAHmW679JePztk0= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs= github.com/Azure/azure-sdk-for-go v44.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg= -github.com/Azure/go-autorest/autorest v0.5.0/go.mod h1:9HLKlQjVBH6U3oDfsXOeVc56THsLPw1L03yban4xThw= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.9.2/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= -github.com/Azure/go-autorest/autorest v0.11.18 h1:90Y4srNYrwOtAgVo3ndrQkTYn6kf1Eg/AjTFJ8Is2aM= github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= -github.com/Azure/go-autorest/autorest/adal v0.1.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E= -github.com/Azure/go-autorest/autorest/adal v0.2.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E= +github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc= +github.com/Azure/go-autorest/autorest v0.11.28 h1:ndAExarwr5Y+GaHE6VCaY1kyS/HwwGGyuimVhWsHOEM= +github.com/Azure/go-autorest/autorest v0.11.28/go.mod h1:MrkzG3Y3AH668QyF9KRk5neJnGgmhQ6krbhR8Q5eMvA= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= -github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= -github.com/Azure/go-autorest/autorest/azure/auth v0.1.0/go.mod h1:Gf7/i2FUpyb/sGBLIFxTBzrNzBo7aPXXE3ZVeDRwdpM= -github.com/Azure/go-autorest/autorest/azure/auth v0.4.1/go.mod h1:5TgH20II424SXIV9YDBsO4rBCKsh39Vbx9DvhJZZ8rU= -github.com/Azure/go-autorest/autorest/azure/auth v0.5.0 h1:nSMjYIe24eBYasAIxt859TxyXef/IqoH+8/g4+LmcVs= +github.com/Azure/go-autorest/autorest/adal v0.9.18 h1:kLnPsRjzZZUF3K5REu/Kc+qMQrvuza2bwSnNdhmzLfQ= +github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= github.com/Azure/go-autorest/autorest/azure/auth v0.5.0/go.mod h1:QRTvSZQpxqm8mSErhnbI+tANIBAKP7B+UIE2z4ypUO0= -github.com/Azure/go-autorest/autorest/azure/cli v0.1.0/go.mod h1:Dk8CUAt/b/PzkfeRsWzVG9Yj3ps8mS8ECztu43rdU8U= -github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw= -github.com/Azure/go-autorest/autorest/azure/cli v0.4.0 h1:Ml+UCrnlKD+cJmSzrZ/RDcDw86NjkRUpnFh7V5JUhzU= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 h1:wkAZRgT/pn8HhFyzfe9UnqOjJYqlembgCTi72Bm/xKk= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.12/go.mod h1:84w/uV8E37feW2NCJ08uT9VBfjfUHpgLVnG2InYD6cg= github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 h1:0W/yGmFdTIT77fvdlGZ0LMISoLHFJ7Tx4U0yeB+uFs4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.5/go.mod h1:ADQAXrkgm7acgWVUNamOgh8YNrv4p27l3Wc55oVfpzg= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= +github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= -github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= github.com/Azure/go-autorest/autorest/validation v0.3.0 h1:3I9AAI63HfcLtphd9g39ruUwRI+Ca+z/f36KHPFRUss= github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/DataDog/zstd v1.3.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/Microsoft/go-winio v0.4.3 h1:M3NHMuPgMSUPdE5epwNUHlRPSVzHs8HpRTrVXhR0myo= -github.com/Microsoft/go-winio v0.4.3/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/DataDog/datadog-go v4.8.2+incompatible h1:qbcKSx29aBLD+5QLvlQZlGmRMF/FfGqFLFev/1TDzRo= +github.com/DataDog/datadog-go v4.8.2+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= +github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.0.1 h1:iLrQrdwjDd52kHDA5op2UBJFjmOb9g+7scBan4RN8F0= github.com/NYTimes/gziphandler v1.0.1/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/sarama v1.21.0/go.mod h1:yuqtN/pe8cXRWG5zPaO7hCfNJp5MwmkoJEoLjkm5tCQ= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af h1:DBNMBMuMiWYu0b+8KMJuWmfCkcxl09JwdlqwDZZ6U14= github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw= -github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.0/go.mod h1:zpDJeKyp9ScW4NNrbdr+Eyxvry3ilGPewKoXw3XGN1k= -github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75/go.mod h1:uAXEEpARkRhCZfEvy/y0Jcc888f9tHCc1W7/UeEtreE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190808125512-07798873deee/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ= -github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= @@ -138,13 +86,10 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.25.41/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.42.34 h1:fqGAiKmCSRY1rEa4G9VqgkKKbNmLKYq5dKmLtQkvYi8= -github.com/aws/aws-sdk-go v1.42.34/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc= -github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= +github.com/aws/aws-sdk-go v1.44.289 h1:5CVEjiHFvdiVlKPBzv0rjG4zH/21W/onT18R5AH/qx0= +github.com/aws/aws-sdk-go v1.44.289/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -153,16 +98,12 @@ github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= -github.com/caddyserver/caddy v1.0.4/go.mod h1:uruyfVsyMcDb3IOzSKsi1x0wOjy1my/PxOSTcD+24jM= -github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= -github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -171,84 +112,63 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYutcJ5PCekLxXn56w6SY= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe h1:QJDJubh0OEcpeGjC7/8uF9tt4e39U/Ya1uyK+itnNPQ= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1 h1:zH8ljVhhq7yC0MIeUL/IviMtY8hx2mK8cN9wEYb8ggw= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/coredns/coredns v1.6.6 h1:GFJXHHBiN2YGp4vS1tltNR0AhI1+TXhb79WT1VAS47I= -github.com/coredns/coredns v1.6.6/go.mod h1:Bdcnka9HmKGYj12ZIDF3lpQSfDHSsMc85Wj9xEyZUts= -github.com/coredns/federation v0.0.0-20190818181423-e032b096babe/go.mod h1:MoqTEFX8GlnKkyq8eBCF94VzkNAOgjdlCJ+Pz/oCLPk= +github.com/coredns/coredns v1.10.1 h1:6OyL7tcvYxeNHONj5iQlVM2GXBzAOq57L3/LUKP1DbA= +github.com/coredns/coredns v1.10.1/go.mod h1:oGgoY6cRrdJzKgNrsT30Hztu7/MutSHCYwqGDWngXCc= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190212144455-93d5ec2c7f76/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMElOWxok= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/decker502/dnspod-go v0.2.0/go.mod h1:qsurYu1FgxcDwfSwXJdLt4kRsBLZeosEb9uq4Sy+08g= github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661 h1:lrWnAyy/F72MbxIxFUzKmcMCdt9Oi8RzpAxzTNQHD7o= github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= -github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/digitalocean/godo v1.7.5/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= github.com/digitalocean/godo v1.10.0 h1:uW1/FcvZE/hoixnJcnlmIUvTVNdZCLjRLzmDtRi1xXY= github.com/digitalocean/godo v1.10.0/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= -github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= +github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/dnsimple/dnsimple-go v0.30.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg= -github.com/dnstap/golang-dnstap v0.0.0-20170829151710-2cf77a2b5e11/go.mod h1:s1PfVYYVmTMgCSPtho4LKBDecEHJWtiVDPNv78Z985U= github.com/docker/go-connections v0.3.0 h1:3lOnM9cSzgGwx8VfK/NGOW5fLQ0GjIlCkaktF+n1M6o= github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.10.1 h1:cgDRLG7bs59Zd+apAWuzLQL95obVYAymNJek76W3mgw= -github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 h1:xvqufLtNVwAhN8NMyWklVgxnWohi+wtMGQMhtxexlm0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/exoscale/egoscale v0.18.1/go.mod h1:Z7OOdzzTOz1Q1PjQXumlz9Wn/CddH0zSYdCF3rnBKXE= -github.com/farsightsec/golang-framestream v0.0.0-20181102145529-8a0cb8ba8710/go.mod h1:eNde4IQyEiA5br02AouhEHCu3p3UzrCdFR4LuQHklMI= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.11.0 h1:Yyrghcw93e1jKo4DTZkRFTTFvBsVhzbblBUPNU1vW6Q= github.com/frankban/quicktest v1.11.0/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s= @@ -257,59 +177,62 @@ github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWp github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-acme/lego/v3 v3.1.0/go.mod h1:074uqt+JS6plx+c9Xaiz6+L+GBb+7itGtzfcDM2AhEE= -github.com/go-acme/lego/v3 v3.2.0/go.mod h1:074uqt+JS6plx+c9Xaiz6+L+GBb+7itGtzfcDM2AhEE= github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-ini/ini v1.44.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-ldap/ldap/v3 v3.1.3/go.mod h1:3rbOH3jRS2u6jg2rJnKAMLE/xQyCKIveG2Sa/Cohzb8= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-openapi/analysis v0.21.2 h1:hXFrOYFHUAMQdu6zwAiKKJHJQ8kqZs1ux/ru1P1wLJU= github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= +github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= +github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.2 h1:dxy7PGTqEh94zj2E3h1cUmQQWiM1+aeCROfAr02EmK8= github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc= +github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= -github.com/go-openapi/loads v0.21.1 h1:Wb3nVZpdEzDTcly8S4HMkey6fjARRzb7iEaySimlDW0= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= -github.com/go-openapi/runtime v0.24.1 h1:Sml5cgQKGYQHF+M7yYSHaH1eOjvTykrddTE/KtQVjqo= -github.com/go-openapi/runtime v0.24.1/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk= +github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= +github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= +github.com/go-openapi/runtime v0.25.0 h1:7yQTCdRbWhX8vnIjdzU8S00tBYf7Sg71EBeorlPHvhc= +github.com/go-openapi/runtime v0.25.0/go.mod h1:Ux6fikcHXyyob6LNWxtE96hWwjBPYF0DXgVFuMTneOs= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/spec v0.20.8 h1:ubHmXNY3FCIOinT8RNrrPfGc9t7I1qhPtdOGoG2AxRU= +github.com/go-openapi/spec v0.20.8/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= -github.com/go-openapi/strfmt v0.21.2/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o= github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU= github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/validate v0.21.0 h1:+Wqk39yKOhfpLqNLEC0/eViCkzM5FVXVqrvt526+wcI= -github.com/go-openapi/validate v0.21.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= +github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= github.com/go-ozzo/ozzo-validation v3.6.0+incompatible h1:msy24VGS42fKO9K1vLz82/GeYW1cILu7Nuuj1N3BBkE= github.com/go-ozzo/ozzo-validation v3.6.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= @@ -337,36 +260,27 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= -github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -376,83 +290,66 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20160524151835-7d79101e329e/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22 h1:ub2sxhs2A0HRa2dWHavvmWxiVGXNfE9wI+gcTMwED8A= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/tcpproxy v0.0.0-20180808230851-dfa16c61dad2 h1:AtvtonGEH/fZK0XPNNBdB6swgy7Iudfx88wzyIpwqJ8= github.com/google/tcpproxy v0.0.0-20180808230851-dfa16c61dad2/go.mod h1:DavVbd41y+b7ukKDmlnPR4nGYmkWXR6vHUkjQNiHPBs= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.2.1 h1:RY7tHKZcRlk788d5WSo/e83gOyyy742E8GSs771ySpg= +github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g= github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gophercloud/gophercloud v0.3.0 h1:6sjpKIpVwRIIwmcEGp+WwNovNsem+c+2vm6oxshRpL8= github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= -github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/hashicorp/consul-awsauth v0.0.0-20220713182709-05ac1c5c2706 h1:1ZEjnveDe20yFa6lSkfdQZm5BR/b271n0MsB5R2L3us= github.com/hashicorp/consul-awsauth v0.0.0-20220713182709-05ac1c5c2706/go.mod h1:1Cs8FlmD1BfSQXJGcFLSV5FuIx1AbJP+EJGdxosoS2g= github.com/hashicorp/consul-net-rpc v0.0.0-20220307172752-3602954411b4 h1:Com/5n/omNSBusX11zdyIYtidiqewLIanchbm//McZA= @@ -464,12 +361,13 @@ github.com/hashicorp/go-bexpr v0.1.2/go.mod h1:ANbpTX1oAql27TZkKVeW8p1w8NTdnyzPe github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-connlimit v0.3.0 h1:oAojHGjFxUTTTA8c5XXnDqWJ2HLuWbDiBPTpWvNzvqM= github.com/hashicorp/go-connlimit v0.3.0/go.mod h1:OUj9FGL1tPIhl/2RCfzYHrIiWj+VVPGNyVPnUX8AqS0= -github.com/hashicorp/go-discover v0.0.0-20220411141802-20db45f7f0f9 h1:2GsEkBZf1q4LKZjtd4cO+V0xd85xGCMolX3ebC2+xd4= -github.com/hashicorp/go-discover v0.0.0-20220411141802-20db45f7f0f9/go.mod h1:1xfdKvc3pe5WKxfUUHHOGaKMk7NLGhHY1jkyhKo6098= +github.com/hashicorp/go-discover v0.0.0-20220714221025-1c234a67149a h1:xeDSq/xo0CfnSZnPUkNH/00Qy8Q8ySJW0Ij2u/pH680= +github.com/hashicorp/go-discover v0.0.0-20220714221025-1c234a67149a/go.mod h1:1xfdKvc3pe5WKxfUUHHOGaKMk7NLGhHY1jkyhKo6098= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= @@ -484,9 +382,10 @@ github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jU github.com/hashicorp/go-memdb v1.3.4 h1:XSL3NR682X/cVk2IeV0d70N4DZ9ljI885xAEU8IoK3c= github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6KvJWs= -github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4= +github.com/hashicorp/go-msgpack/v2 v2.0.0 h1:c1fiLq1LNghmLOry1ipGhvLDi+/zEoaEP2JrE1oFJ9s= +github.com/hashicorp/go-msgpack/v2 v2.0.0/go.mod h1:JIxYkkFJRDDRSoWQBSh7s9QAVThq+82iWmUpmE4jKak= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= @@ -514,15 +413,14 @@ github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pB github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/hcp-scada-provider v0.1.0 h1:FSjTw7EBl6GJFv5533harm1vw15OaEYodNGHde908MI= -github.com/hashicorp/hcp-scada-provider v0.1.0/go.mod h1:8Pp3pBLzZ9DL56OHSbf55qhh+TpvmXBuR5cJx9jcdcA= -github.com/hashicorp/hcp-sdk-go v0.23.1-0.20220921131124-49168300a7dc h1:on26TCKYnX7JzZCtwkR/LWHSqMu40PoZ6h/0e6Pq8ug= -github.com/hashicorp/hcp-sdk-go v0.23.1-0.20220921131124-49168300a7dc/go.mod h1:/9UoDY2FYYA8lFaKBb2HmM/jKYZGANmf65q9QRc/cVw= +github.com/hashicorp/hcp-scada-provider v0.2.3 h1:AarYR+/Pcv+cMvPdAlb92uOBmZfEH6ny4+DT+4NY2VQ= +github.com/hashicorp/hcp-scada-provider v0.2.3/go.mod h1:ZFTgGwkzNv99PLQjTsulzaCplCzOTBh0IUQsPKzrQFo= +github.com/hashicorp/hcp-sdk-go v0.44.1-0.20230508124639-28da4c5b03f3 h1:9QstZdsLIS6iPyYxQoyymRz8nBw9jMdEbGy29gtgzVQ= +github.com/hashicorp/hcp-sdk-go v0.44.1-0.20230508124639-28da4c5b03f3/go.mod h1:hZqky4HEzsKwvLOt4QJlZUrjeQmb4UCZUhDP2HyQFfc= github.com/hashicorp/hil v0.0.0-20200423225030-a18a1cd20038 h1:n9J0rwVWXDpNd5iZnwY7w4WZyq53/rROeI7OVvLW8Ok= github.com/hashicorp/hil v0.0.0-20200423225030-a18a1cd20038/go.mod h1:n2TSygSNwsLJ76m8qFXTSc7beTb+auJxYdqrnoqwZWE= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -531,8 +429,8 @@ github.com/hashicorp/mdns v1.0.4 h1:sY0CMhFmjIPDMlTB+HfymFHCaYLhgifZ0QhjaYKD/UQ= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM= github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= -github.com/hashicorp/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69 h1:lc3c72qGlIMDqQpQH82Y4vaglRMMFdJbziYWriR4UcE= -github.com/hashicorp/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69/go.mod h1:/z+jUGRBlwVpUZfjute9jWaF6/HuhjuFQuL1YXzVD1Q= +github.com/hashicorp/net-rpc-msgpackrpc/v2 v2.0.0 h1:kBpVVl1sl3MaSrs97e0+pDQhSrqJv9gVbSUrPpVfl1w= +github.com/hashicorp/net-rpc-msgpackrpc/v2 v2.0.0/go.mod h1:6pdNz0vo0mF0GvhwDG56O3N18qBrAz/XRIcfINfTbwo= github.com/hashicorp/raft v1.1.0/go.mod h1:4Ak7FSPnuvmb0GV6vgIAJ4vYT4bek9bb6Q+7HVbyzqM= github.com/hashicorp/raft v1.1.1/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8= github.com/hashicorp/raft v1.2.0/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8= @@ -558,21 +456,16 @@ github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKe github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/infobloxopen/go-trees v0.0.0-20190313150506-2af4e13f9062/go.mod h1:PcNJqIlcX/dj3DTG/+QQnRvSgTMG6CLpRMjWcv4+J6w= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da h1:FjHUJJ7oBW4G/9j1KzlHaXL09LyMVM9rupS39lncbXk= github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= -github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= @@ -585,16 +478,12 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA= github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f h1:ENpDacvnr8faw5ugQmEF1QYk+f/Y9lXFvuYmRxykago= github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f/go.mod h1:KDSfL7qe5ZfQqvlDMkVjCztbmcpp/c8M77vhQP8ZPvk= -github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= @@ -603,10 +492,7 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -617,15 +503,10 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= -github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA= -github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/linode/linodego v0.7.1/go.mod h1:ga11n3ivecUrPCHN0rANxKmfWBJVkOXfLMZinAbj2sY= github.com/linode/linodego v0.10.0 h1:AMdb82HVgY8o3mjBXJcUv9B+fnJjfDMn2rNRGbX+jvM= github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA= -github.com/liquidweb/liquidweb-go v1.6.0/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVLEIG/i5J9cyixzQ= -github.com/lucas-clemente/quic-go v0.13.1/go.mod h1:Vn3/Fb0/77b02SGhQk36KzOUmXgVpFfizUfW5WMaqyU= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -637,9 +518,6 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= -github.com/marten-seemann/chacha20 v0.2.0/go.mod h1:HSdjFau7GzYRj+ahFNwsO3ouVJr1HFkWoEwNDb4TMtE= -github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI= -github.com/marten-seemann/qtls v0.4.1/go.mod h1:pxVXcHHw1pNIt8Qo0pwSYQEoZ8yYOOPXTCZLQQunvRc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -647,26 +525,21 @@ github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mholt/certmagic v0.8.3/go.mod h1:91uJzK5K8IWtYQqTi5R2tsxV1pCde+wdGfaRaOZi6aQ= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= +github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0 h1:tEElEatulEHDeedTxwckzyYMA5c86fbmNIUL1hBIiTg= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= @@ -680,7 +553,6 @@ github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go. github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.14.0 h1:/x0XQ6h+3U3nAyk1yx+bHPURrKa9sVVvYbuqZ7pIAtI= github.com/mitchellh/go-testing-interface v1.14.0/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= -github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452 h1:hOY53G+kBFhbYFpRVxHl5eS7laP6B1+Cq+Z9Dry1iMU= github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= @@ -691,8 +563,8 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= -github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw= github.com/mitchellh/pointerstructure v1.2.1/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= @@ -702,45 +574,32 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8= -github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= -github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= -github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 h1:BQ1HW7hr4IVovMwWg0E0PYcyW8CzqDcVmaew9cujU4s= github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2/go.mod h1:TLb2Sg7HQcgGdloNxkrmtgDNR9uVYF3lfdFIN4Ro6Sk= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nrdcg/auroradns v1.0.0/go.mod h1:6JPXKzIRzZzMqtTDgueIhTi6rFf1QvYE/HzqidhOhjw= -github.com/nrdcg/goinwx v0.6.1/go.mod h1:XPiut7enlbEdntAqalBIqcYcTEVhpv/dKWgDCX2SwKQ= -github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.0-20180130162743-b8a9be070da4/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/openzipkin-contrib/zipkin-go-opentracing v0.3.5/go.mod h1:uVHyebswE1cCXr2A73cRM2frx5ld1RJUCJkFNZ90ZiI= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= -github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ= github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c h1:vwpFWvAO8DeIZfFeqASzZfsxuWPno9ncAebBEP0N3uE= github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c/go.mod h1:otzZQXgoO96RTzDB/Hycg0qZcXZsWJGJRSXbmEIJ+4M= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -751,7 +610,6 @@ github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTK github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI= github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -770,42 +628,34 @@ github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAm github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= -github.com/prometheus/client_golang v1.4.0 h1:YVIb/fVcOTMSqtqZWSKnHpSLBxu8DKgxq8z6RuBZwqI= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= -github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= +github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA= -github.com/rboyer/safeio v0.2.1 h1:05xhhdRNAdS3apYm7JRjOqngf4xruaW959jmRxGDuSU= -github.com/rboyer/safeio v0.2.1/go.mod h1:Cq/cEPK+YXFn622lsQ0K4KsPZSPtaptHHEldsy7Fmig= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rboyer/safeio v0.2.3 h1:gUybicx1kp8nuM4vO0GA5xTBX58/OBd8MQuErBfDxP8= +github.com/rboyer/safeio v0.2.3/go.mod h1:d7RMmt7utQBJZ4B7f0H/cU/EdZibQAU1Y8NWepK2dS8= github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 h1:Wdi9nwnhFNAlseAOekn6B5G/+GMtks9UKbvRU/CMM/o= github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03/go.mod h1:gRAiPF5C5Nd0eyyRdqIu9qTiFSoZzpTq727b5B8fkkU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -814,16 +664,13 @@ github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/zerolog v1.4.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= -github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.2+incompatible h1:C89EOx/XBWwIXl8wm8OPJBd7kPF25UfsK2X7Ph/zCAk= github.com/ryanuber/columnize v2.1.2+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/conswriter v0.0.0-20180208195008-f5ae3917a627/go.mod h1:7zjs06qF79/FKAJpBvFx3P8Ww4UTIMAe+lpNXDHziac= github.com/sean-/pager v0.0.0-20180208200047-666be9bf53b5/go.mod h1:BeybITEsBEg6qbIiqJ6/Bqeq25bCLbL7YFmpaFfJDuM= @@ -832,18 +679,15 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg github.com/shirou/gopsutil/v3 v3.22.8 h1:a4s3hXogo5mE2PfdfJIonDbstO/P+9JszdfhAHSzD9Y= github.com/shirou/gopsutil/v3 v3.22.8/go.mod h1:s648gW4IywYzUfE/KjXxUsqrqx/T2xO5VqOXxONeRfI= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d h1:bVQRCxQvfjNUeRqaY/uT0tFuvuFY0ulgnczuR684Xic= github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d/go.mod h1:Cw4GTlQccdRGSEf6KiMju767x0NEHE0YIVPJSaXjlsw= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -856,16 +700,17 @@ github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -874,131 +719,99 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tencentcloud/tencentcloud-sdk-go v1.0.162 h1:8fDzz4GuVg4skjY2B0nMN7h6uN61EDVkuLyI2+qGHhI= github.com/tencentcloud/tencentcloud-sdk-go v1.0.162/go.mod h1:asUz5BPXxgoPGaRgZaVm1iGcUAuHyYUo1nXqKa83cvI= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY= -github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o= github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/transip/gotransip v0.0.0-20190812104329-6d8d9179b66f/go.mod h1:i0f4R4o2HM0m3DZYQWsj6/MEowD57VzoH0v3d7igeFY= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vmware/govmomi v0.18.0 h1:f7QxSmP7meCtoAmiKZogvVbLInT+CZx6Px6K5rYsJZo= github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= -github.com/vultr/govultr v0.1.4/go.mod h1:9H008Uxr/C4vFNGLqKx232C206GL0PBHzOP0809bGNA= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/etcd v0.5.0-alpha.5.0.20190917205325-a14579fbfb1a/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= -go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= -go.mongodb.org/mongo-driver v1.10.0 h1:UtV6N5k14upNp4LTduX0QCufG124fSu25Wz9tu94GLg= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.mongodb.org/mongo-driver v1.11.0 h1:FZKhBSTydeuffHj9CBjXlR8vQLee1cQyTWYPA6/tqiE= +go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4= +go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= +go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZpKxs= +go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= +go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= go.opentelemetry.io/proto/otlp v0.7.0 h1:rwOQPCuKAKmwGKq2aVNnYIibI6wnV7EvzgfTCzcdGg8= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1009,55 +822,36 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58 h1:Mj83v+wSRNEar42a/MQgxk9X42TdEmrOl9i+y8WbxLo= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1065,13 +859,12 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1079,237 +872,130 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= +golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0 h1:yfrXXP61wVuLb0vBcG6qaOoIoqYEzOQS8jum51jkv2w= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.109.0 h1:sW9hgHyX497PP5//NUM7nqfV8D0iDfBApqq7sOh1XR8= +google.golang.org/api v0.109.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190626174449-989357319d63/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 h1:PDIOdWxZ8eRizhKa1AAvY53xsvLB1cWorMjslvY3VA8= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef h1:uQ2vjV/sHTsWSqdKeLqmwitzgvjMl7o4IdtHwUDXSJY= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.1 h1:ARnQJNWxGyYJpdf/JXscNlQr/uv607ZPU9Z7ogHi+iI= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.52.3 h1:pf7sOysg4LdgBqduXveGKrcEwbStiK2rtfghdzlUYDQ= +google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1321,33 +1007,25 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/DataDog/dd-trace-go.v1 v1.19.0/go.mod h1:DVp8HmDh8PuTu2Z0fVVlBsyWaC++fzwVCaGWylTe3tg= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= -gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= -gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/ns1/ns1-go.v2 v2.0.0-20190730140822-b51389932cbc/go.mod h1:VV+3haRsgDiVLxyifmMBrBIuCWFBPYKbRssXB9z67Hw= gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc= gopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= @@ -1369,43 +1047,37 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.0.0-20190620084959-7cf5895f2711/go.mod h1:TBhBqb1AWbBQbW3XRusr7n7E4v2+5ZY8r8sAMnyFC5A= -k8s.io/api v0.18.2 h1:wG5g5ZmSVgm5B+eHMIbI9EGATS2L8Z72rda19RIEgY8= k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= -k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA= -k8s.io/apimachinery v0.18.2 h1:44CmtbmkzVDAhCpRVSiP2R5PPrC2RtlIv/MoB8xpdRA= +k8s.io/api v0.26.1 h1:f+SWYiPd/GsiWwVRz+NbFyCgvv75Pk9NK6dlkZgpCRQ= +k8s.io/api v0.26.1/go.mod h1:xd/GBNgR0f707+ATNyPmQ1oyKSgndzXij81FzWGsejg= k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= -k8s.io/client-go v0.0.0-20190620085101-78d2af792bab/go.mod h1:E95RaSlHr79aHaX0aGSwcPNfygDiPKOVXdmivCIZT0k= -k8s.io/client-go v0.18.2 h1:aLB0iaD4nmwh7arT2wIn+lMnAq7OswjaejkQ8p9bBYE= +k8s.io/apimachinery v0.26.1 h1:8EZ/eGJL+hY/MYCNwhmDzVqq2lPl3N3Bo8rvweJwXUQ= +k8s.io/apimachinery v0.26.1/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74= k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= +k8s.io/client-go v0.26.1 h1:87CXzYJnAMGaa/IDDfRdhTzxk/wzGZ+/HUQpqgVSZXU= +k8s.io/client-go v0.26.1/go.mod h1:IWNSglg+rQ3OcvDkhY6+QLeasV4OYHDjdqeWkDQZwGE= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= -k8s.io/kube-openapi v0.0.0-20190306001800-15615b16d372/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= +k8s.io/klog/v2 v2.90.0 h1:VkTxIV/FjRXn1fgNNcKGM8cfmL1Z33ZjXRTVxKCoF5M= +k8s.io/klog/v2 v2.90.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= -k8s.io/utils v0.0.0-20190529001817-6999998975a7/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/internal/go-sso/oidcauth/oidcjwt.go b/internal/go-sso/oidcauth/oidcjwt.go index a2942ca7ed5e..b2df662cd51d 100644 --- a/internal/go-sso/oidcauth/oidcjwt.go +++ b/internal/go-sso/oidcauth/oidcjwt.go @@ -11,11 +11,12 @@ import ( "strconv" "strings" - "github.com/hashicorp/consul/internal/go-sso/oidcauth/internal/strutil" "github.com/hashicorp/go-cleanhttp" "github.com/hashicorp/go-hclog" "github.com/mitchellh/pointerstructure" "golang.org/x/oauth2" + + "github.com/hashicorp/consul/internal/go-sso/oidcauth/internal/strutil" ) func contextWithHttpClient(ctx context.Context, client *http.Client) context.Context { @@ -63,11 +64,11 @@ func (a *Authenticator) extractClaims(allClaims map[string]interface{}) (*Claims // claims and claims mappings. The referenced claims must be strings and the // claims mappings must be of the structure: // -// { -// "/some/claim/pointer": "metadata_key1", -// "another_claim": "metadata_key2", -// ... -// } +// { +// "/some/claim/pointer": "metadata_key1", +// "another_claim": "metadata_key2", +// ... +// } func extractStringMetadata(logger hclog.Logger, allClaims map[string]interface{}, claimMappings map[string]string) (map[string]string, error) { metadata := make(map[string]string) for source, target := range claimMappings { @@ -90,11 +91,11 @@ func extractStringMetadata(logger hclog.Logger, allClaims map[string]interface{} // of claims and claims mappings. The referenced claims must be strings and // the claims mappings must be of the structure: // -// { -// "/some/claim/pointer": "metadata_key1", -// "another_claim": "metadata_key2", -// ... -// } +// { +// "/some/claim/pointer": "metadata_key1", +// "another_claim": "metadata_key2", +// ... +// } func extractListMetadata(logger hclog.Logger, allClaims map[string]interface{}, listClaimMappings map[string]string) (map[string][]string, error) { out := make(map[string][]string) for source, target := range listClaimMappings { diff --git a/internal/tools/proto-gen-rpc-glue/e2e/source.pb.go b/internal/tools/proto-gen-rpc-glue/e2e/source.pb.go index f90deb2067d7..a75728bb57e4 100644 --- a/internal/tools/proto-gen-rpc-glue/e2e/source.pb.go +++ b/internal/tools/proto-gen-rpc-glue/e2e/source.pb.go @@ -38,21 +38,6 @@ type ExampleDatacenter struct { Datacenter string } -// @consul-rpc-glue: ReadTODO -type ExampleReadTODO struct { - Value string -} - -// @consul-rpc-glue: LeaderReadTODO -type ExampleLeaderReadTODO struct { - Value string -} - -// @consul-rpc-glue: WriteTODO -type ExampleWriteTODO struct { - Value string -} - // @consul-rpc-glue: WriteRequest=AltWriteRequest type AltExampleWriteRequest struct { Value int diff --git a/internal/tools/proto-gen-rpc-glue/e2e/source.rpcglue.pb.go.golden b/internal/tools/proto-gen-rpc-glue/e2e/source.rpcglue.pb.go.golden index 4c7b1c3610b5..4e0360060a37 100644 --- a/internal/tools/proto-gen-rpc-glue/e2e/source.rpcglue.pb.go.golden +++ b/internal/tools/proto-gen-rpc-glue/e2e/source.rpcglue.pb.go.golden @@ -28,14 +28,6 @@ func (msg *ExampleWriteRequest) HasTimedOut(start time.Time, rpcHoldTimeout time return msg.WriteRequest.HasTimedOut(start, rpcHoldTimeout, a, b) } -// Timeout implements structs.RPCInfo -func (msg *ExampleWriteRequest) Timeout(rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) time.Duration { - if msg == nil || msg.WriteRequest == nil { - return 0 - } - return msg.WriteRequest.Timeout(rpcHoldTimeout, a, b) -} - // IsRead implements structs.RPCInfo func (msg *ExampleWriteRequest) IsRead() bool { return false @@ -90,14 +82,6 @@ func (msg *ExampleReadRequest) HasTimedOut(start time.Time, rpcHoldTimeout time. return msg.ReadRequest.HasTimedOut(start, rpcHoldTimeout, a, b) } -// Timeout implements structs.RPCInfo -func (msg *ExampleReadRequest) Timeout(rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) time.Duration { - if msg == nil || msg.ReadRequest == nil { - return 0 - } - return msg.ReadRequest.Timeout(rpcHoldTimeout, a, b) -} - // SetTokenSecret implements structs.RPCInfo func (msg *ExampleReadRequest) SetTokenSecret(s string) { // TODO: initialize if nil @@ -146,6 +130,16 @@ func (msg *ExampleQueryOptions) AllowStaleRead() bool { return msg.QueryOptions.AllowStaleRead() } +// BlockingTimeout implements pool.BlockableQuery +func (msg *ExampleQueryOptions) BlockingTimeout(maxQueryTime, defaultQueryTime time.Duration) time.Duration { + maxTime := structs.DurationFromProto(msg.QueryOptions.GetMaxQueryTime()) + o := structs.QueryOptions{ + MaxQueryTime: maxTime, + MinQueryIndex: msg.QueryOptions.GetMinQueryIndex(), + } + return o.BlockingTimeout(maxQueryTime, defaultQueryTime) +} + // HasTimedOut implements structs.RPCInfo func (msg *ExampleQueryOptions) HasTimedOut(start time.Time, rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) (bool, error) { if msg == nil || msg.QueryOptions == nil { @@ -154,14 +148,6 @@ func (msg *ExampleQueryOptions) HasTimedOut(start time.Time, rpcHoldTimeout time return msg.QueryOptions.HasTimedOut(start, rpcHoldTimeout, a, b) } -// Timeout implements structs.RPCInfo -func (msg *ExampleQueryOptions) Timeout(rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) time.Duration { - if msg == nil || msg.QueryOptions == nil { - return 0 - } - return msg.QueryOptions.Timeout(rpcHoldTimeout, a, b) -} - // SetTokenSecret implements structs.RPCInfo func (msg *ExampleQueryOptions) SetTokenSecret(s string) { // TODO: initialize if nil @@ -267,126 +253,6 @@ func (msg *ExampleDatacenter) RequestDatacenter() string { return msg.Datacenter } -// IsRead implements structs.RPCInfo -func (msg *ExampleReadTODO) IsRead() bool { - // TODO(peering): figure out read semantics here - return true -} - -// AllowStaleRead implements structs.RPCInfo -func (msg *ExampleReadTODO) AllowStaleRead() bool { - // TODO(peering): figure out read semantics here - return false -} - -// HasTimedOut implements structs.RPCInfo -func (msg *ExampleReadTODO) HasTimedOut(start time.Time, rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) (bool, error) { - // TODO(peering): figure out read semantics here - return time.Since(start) > rpcHoldTimeout, nil -} - -// Timeout implements structs.RPCInfo -func (msg *ExampleReadTODO) Timeout(rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) time.Duration { - // TODO(peering): figure out read semantics here - return rpcHoldTimeout -} - -// SetTokenSecret implements structs.RPCInfo -func (msg *ExampleReadTODO) SetTokenSecret(s string) { - // TODO(peering): figure out read semantics here -} - -// TokenSecret implements structs.RPCInfo -func (msg *ExampleReadTODO) TokenSecret() string { - // TODO(peering): figure out read semantics here - return "" -} - -// Token implements structs.RPCInfo -func (msg *ExampleReadTODO) Token() string { - // TODO(peering): figure out read semantics here - return "" -} - -// IsRead implements structs.RPCInfo -func (msg *ExampleLeaderReadTODO) IsRead() bool { - // TODO(peering): figure out read semantics here - return true -} - -// AllowStaleRead implements structs.RPCInfo -func (msg *ExampleLeaderReadTODO) AllowStaleRead() bool { - // TODO(peering): figure out read semantics here - // TODO(peering): this needs to stay false for calls to head to the leader until we sync stream tracker information - // like ImportedServicesCount, ExportedServicesCount, as well as general Status fields thru raft to make available - // to followers as well - return false -} - -// HasTimedOut implements structs.RPCInfo -func (msg *ExampleLeaderReadTODO) HasTimedOut(start time.Time, rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) (bool, error) { - // TODO(peering): figure out read semantics here - return time.Since(start) > rpcHoldTimeout, nil -} - -// Timeout implements structs.RPCInfo -func (msg *ExampleLeaderReadTODO) Timeout(rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) time.Duration { - // TODO(peering): figure out read semantics here - return rpcHoldTimeout -} - -// SetTokenSecret implements structs.RPCInfo -func (msg *ExampleLeaderReadTODO) SetTokenSecret(s string) { - // TODO(peering): figure out read semantics here -} - -// TokenSecret implements structs.RPCInfo -func (msg *ExampleLeaderReadTODO) TokenSecret() string { - // TODO(peering): figure out read semantics here - return "" -} - -// Token implements structs.RPCInfo -func (msg *ExampleLeaderReadTODO) Token() string { - // TODO(peering): figure out read semantics here - return "" -} - -// IsRead implements structs.RPCInfo -func (msg *ExampleWriteTODO) IsRead() bool { - // TODO(peering): figure out write semantics here - return false -} - -// AllowStaleRead implements structs.RPCInfo -func (msg *ExampleWriteTODO) AllowStaleRead() bool { - // TODO(peering): figure out write semantics here - return false -} - -// HasTimedOut implements structs.RPCInfo -func (msg *ExampleWriteTODO) HasTimedOut(start time.Time, rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) (bool, error) { - // TODO(peering): figure out write semantics here - return time.Since(start) > rpcHoldTimeout, nil -} - -// Timeout implements structs.RPCInfo -func (msg *ExampleWriteTODO) Timeout(rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) time.Duration { - // TODO(peering): figure out write semantics here - return rpcHoldTimeout -} - -// SetTokenSecret implements structs.RPCInfo -func (msg *ExampleWriteTODO) SetTokenSecret(s string) { - // TODO(peering): figure out write semantics here -} - -// TokenSecret implements structs.RPCInfo -func (msg *ExampleWriteTODO) TokenSecret() string { - // TODO(peering): figure out write semantics here - return "" -} - // AllowStaleRead implements structs.RPCInfo func (msg *AltExampleWriteRequest) AllowStaleRead() bool { return false @@ -400,14 +266,6 @@ func (msg *AltExampleWriteRequest) HasTimedOut(start time.Time, rpcHoldTimeout t return msg.AltWriteRequest.HasTimedOut(start, rpcHoldTimeout, a, b) } -// Timeout implements structs.RPCInfo -func (msg *AltExampleWriteRequest) Timeout(rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) time.Duration { - if msg == nil || msg.AltWriteRequest == nil { - return 0 - } - return msg.AltWriteRequest.Timeout(rpcHoldTimeout, a, b) -} - // IsRead implements structs.RPCInfo func (msg *AltExampleWriteRequest) IsRead() bool { return false @@ -454,14 +312,6 @@ func (msg *AltExampleReadRequest) HasTimedOut(start time.Time, rpcHoldTimeout ti return msg.AltReadRequest.HasTimedOut(start, rpcHoldTimeout, a, b) } -// Timeout implements structs.RPCInfo -func (msg *AltExampleReadRequest) Timeout(rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) time.Duration { - if msg == nil || msg.AltReadRequest == nil { - return 0 - } - return msg.AltReadRequest.Timeout(rpcHoldTimeout, a, b) -} - // SetTokenSecret implements structs.RPCInfo func (msg *AltExampleReadRequest) SetTokenSecret(s string) { // TODO: initialize if nil @@ -494,6 +344,16 @@ func (msg *AltExampleQueryOptions) AllowStaleRead() bool { return msg.AltQueryOptions.AllowStaleRead() } +// BlockingTimeout implements pool.BlockableQuery +func (msg *AltExampleQueryOptions) BlockingTimeout(maxQueryTime, defaultQueryTime time.Duration) time.Duration { + maxTime := structs.DurationFromProto(msg.AltQueryOptions.GetMaxQueryTime()) + o := structs.QueryOptions{ + MaxQueryTime: maxTime, + MinQueryIndex: msg.AltQueryOptions.GetMinQueryIndex(), + } + return o.BlockingTimeout(maxQueryTime, defaultQueryTime) +} + // HasTimedOut implements structs.RPCInfo func (msg *AltExampleQueryOptions) HasTimedOut(start time.Time, rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) (bool, error) { if msg == nil || msg.AltQueryOptions == nil { @@ -502,14 +362,6 @@ func (msg *AltExampleQueryOptions) HasTimedOut(start time.Time, rpcHoldTimeout t return msg.AltQueryOptions.HasTimedOut(start, rpcHoldTimeout, a, b) } -// Timeout implements structs.RPCInfo -func (msg *AltExampleQueryOptions) Timeout(rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) time.Duration { - if msg == nil || msg.AltQueryOptions == nil { - return 0 - } - return msg.AltQueryOptions.Timeout(rpcHoldTimeout, a, b) -} - // SetTokenSecret implements structs.RPCInfo func (msg *AltExampleQueryOptions) SetTokenSecret(s string) { // TODO: initialize if nil diff --git a/internal/tools/proto-gen-rpc-glue/main.go b/internal/tools/proto-gen-rpc-glue/main.go index f66118cfc605..38ef20eb2fa3 100644 --- a/internal/tools/proto-gen-rpc-glue/main.go +++ b/internal/tools/proto-gen-rpc-glue/main.go @@ -105,15 +105,6 @@ func processFile(path string) error { if ann.Datacenter != "" { log.Printf(" Datacenter from %s", ann.Datacenter) } - if ann.ReadTODO != "" { - log.Printf(" ReadTODO from %s", ann.ReadTODO) - } - if ann.LeaderReadTODO != "" { - log.Printf(" LeaderReadTODO from %s", ann.LeaderReadTODO) - } - if ann.WriteTODO != "" { - log.Printf(" WriteTODO from %s", ann.WriteTODO) - } } } @@ -160,15 +151,6 @@ var _ time.Month if typ.Annotation.Datacenter != "" { buf.WriteString(fmt.Sprintf(tmplDatacenter, typ.Name, typ.Annotation.Datacenter)) } - if typ.Annotation.LeaderReadTODO != "" { - buf.WriteString(fmt.Sprintf(tmplLeaderOnlyReadTODO, typ.Name, typ.Annotation.LeaderReadTODO)) - } - if typ.Annotation.ReadTODO != "" { - buf.WriteString(fmt.Sprintf(tmplReadTODO, typ.Name, typ.Annotation.ReadTODO)) - } - if typ.Annotation.WriteTODO != "" { - buf.WriteString(fmt.Sprintf(tmplWriteTODO, typ.Name, typ.Annotation.WriteTODO)) - } } // write to disk @@ -322,13 +304,6 @@ func getAnnotation(doc []*ast.Comment) (Annotation, error) { case strings.HasPrefix(part, "Datacenter="): ann.Datacenter = strings.TrimPrefix(part, "Datacenter=") - case part == "ReadTODO": - ann.ReadTODO = "ReadTODO" - case part == "WriteTODO": - ann.WriteTODO = "WriteTODO" - case part == "LeaderReadTODO": - ann.LeaderReadTODO = "LeaderReadTODO" - default: return Annotation{}, fmt.Errorf("unexpected annotation part: %s", part) } @@ -456,114 +431,6 @@ func (msg *%[1]s) Token() string { } ` -const tmplLeaderOnlyReadTODO = ` -// IsRead implements structs.RPCInfo -func (msg *%[1]s) IsRead() bool { - // TODO(peering): figure out read semantics here - return true -} - -// AllowStaleRead implements structs.RPCInfo -func (msg *%[1]s) AllowStaleRead() bool { - // TODO(peering): figure out read semantics here - // TODO(peering): this needs to stay false for calls to head to the leader until we sync stream tracker information - // like ImportedServicesCount, ExportedServicesCount, as well as general Status fields thru raft to make available - // to followers as well - return false -} - -// HasTimedOut implements structs.RPCInfo -func (msg *%[1]s) HasTimedOut(start time.Time, rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) (bool, error) { - // TODO(peering): figure out read semantics here - return time.Since(start) > rpcHoldTimeout, nil -} - -// SetTokenSecret implements structs.RPCInfo -func (msg *%[1]s) SetTokenSecret(s string) { - // TODO(peering): figure out read semantics here -} - -// TokenSecret implements structs.RPCInfo -func (msg *%[1]s) TokenSecret() string { - // TODO(peering): figure out read semantics here - return "" -} - -// Token implements structs.RPCInfo -func (msg *%[1]s) Token() string { - // TODO(peering): figure out read semantics here - return "" -} -` - -const tmplReadTODO = ` -// IsRead implements structs.RPCInfo -func (msg *%[1]s) IsRead() bool { - // TODO(peering): figure out read semantics here - return true -} - -// AllowStaleRead implements structs.RPCInfo -func (msg *%[1]s) AllowStaleRead() bool { - // TODO(peering): figure out read semantics here - return false -} - -// HasTimedOut implements structs.RPCInfo -func (msg *%[1]s) HasTimedOut(start time.Time, rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) (bool, error) { - // TODO(peering): figure out read semantics here - return time.Since(start) > rpcHoldTimeout, nil -} - -// SetTokenSecret implements structs.RPCInfo -func (msg *%[1]s) SetTokenSecret(s string) { - // TODO(peering): figure out read semantics here -} - -// TokenSecret implements structs.RPCInfo -func (msg *%[1]s) TokenSecret() string { - // TODO(peering): figure out read semantics here - return "" -} - -// Token implements structs.RPCInfo -func (msg *%[1]s) Token() string { - // TODO(peering): figure out read semantics here - return "" -} -` - -const tmplWriteTODO = ` -// IsRead implements structs.RPCInfo -func (msg *%[1]s) IsRead() bool { - // TODO(peering): figure out write semantics here - return false -} - -// AllowStaleRead implements structs.RPCInfo -func (msg *%[1]s) AllowStaleRead() bool { - // TODO(peering): figure out write semantics here - return false -} - -// HasTimedOut implements structs.RPCInfo -func (msg *%[1]s) HasTimedOut(start time.Time, rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) (bool, error) { - // TODO(peering): figure out write semantics here - return time.Since(start) > rpcHoldTimeout, nil -} - -// SetTokenSecret implements structs.RPCInfo -func (msg *%[1]s) SetTokenSecret(s string) { - // TODO(peering): figure out write semantics here -} - -// TokenSecret implements structs.RPCInfo -func (msg *%[1]s) TokenSecret() string { - // TODO(peering): figure out write semantics here - return "" -} -` - const tmplTargetDatacenter = ` // RequestDatacenter implements structs.RPCInfo func (msg *%[1]s) RequestDatacenter() string { @@ -595,6 +462,16 @@ func (msg *%[1]s) AllowStaleRead() bool { return msg.%[2]s.AllowStaleRead() } +// BlockingTimeout implements pool.BlockableQuery +func (msg *%[1]s) BlockingTimeout(maxQueryTime, defaultQueryTime time.Duration) time.Duration { + maxTime := structs.DurationFromProto(msg.%[2]s.GetMaxQueryTime()) + o := structs.QueryOptions{ + MaxQueryTime: maxTime, + MinQueryIndex: msg.%[2]s.GetMinQueryIndex(), + } + return o.BlockingTimeout(maxQueryTime, defaultQueryTime) +} + // HasTimedOut implements structs.RPCInfo func (msg *%[1]s) HasTimedOut(start time.Time, rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) (bool, error) { if msg == nil || msg.%[2]s == nil { diff --git a/lib/decode/decode.go b/lib/decode/decode.go index 0461962c3c14..f47b5a4bc368 100644 --- a/lib/decode/decode.go +++ b/lib/decode/decode.go @@ -19,7 +19,8 @@ import ( // Aliases must be lowercase, as keys are compared case-insensitive. // // Example alias tag: -// MyField []string `alias:"old_field_name,otherfieldname"` +// +// MyField []string `alias:"old_field_name,otherfieldname"` // // This hook should ONLY be used to maintain backwards compatibility with // deprecated keys. For new structures use mapstructure struct tags to set the @@ -143,7 +144,7 @@ type mapstructureFieldTags struct { // the target is a slice. This is necessary because this hook would have converted // the initial slices into single values on the first pass. // -// Background +// # Background // // HCL allows for repeated blocks which forces it to store structures // as []map[string]interface{} instead of map[string]interface{}. This is an diff --git a/lib/map_walker.go b/lib/map_walker.go index ca103806d46f..b3779311be8b 100644 --- a/lib/map_walker.go +++ b/lib/map_walker.go @@ -47,12 +47,11 @@ var typByteSlice = reflect.TypeOf([]byte{}) // // In particular we're looking to replace two cases the msgpack codec causes: // -// 1.) String values get turned into byte slices. JSON will base64-encode -// this and we don't want that, so we convert them back to strings. -// -// 2.) Nested maps turn into map[interface{}]interface{}. JSON cannot -// encode this, so we need to turn it back into map[string]interface{}. +// 1.) String values get turned into byte slices. JSON will base64-encode +// this and we don't want that, so we convert them back to strings. // +// 2.) Nested maps turn into map[interface{}]interface{}. JSON cannot +// encode this, so we need to turn it back into map[string]interface{}. type mapWalker struct { lastValue reflect.Value // lastValue of map, required for replacement loc, lastLoc reflectwalk.Location // locations @@ -111,7 +110,7 @@ func (w *mapWalker) MapElem(m, k, v reflect.Value) error { return nil } - if inner := v.Elem(); inner.Type() == typMapIfaceIface { + if inner := v.Elem(); inner.IsValid() && inner.Type() == typMapIfaceIface { // map[interface{}]interface{}, attempt to weakly decode into string keys var target map[string]interface{} if err := mapstructure.WeakDecode(v.Interface(), &target); err != nil { diff --git a/lib/map_walker_test.go b/lib/map_walker_test.go index 2642802f9ddb..068add7590a3 100644 --- a/lib/map_walker_test.go +++ b/lib/map_walker_test.go @@ -38,6 +38,16 @@ func TestMapWalk(t *testing.T) { }, unexpected: true, }, + // ensure we don't panic from trying to call reflect.Value.Type + // on a nil pointer + "nil pointer": { + input: map[string]interface{}{ + "foo": nil, + }, + expected: map[string]interface{}{ + "foo": nil, + }, + }, // ensure nested maps get processed correctly "nested": { input: map[string]interface{}{ diff --git a/lib/rand.go b/lib/rand.go deleted file mode 100644 index 22aa4f3544bb..000000000000 --- a/lib/rand.go +++ /dev/null @@ -1,34 +0,0 @@ -package lib - -import ( - crand "crypto/rand" - "math" - "math/big" - "math/rand" - "sync" - "time" -) - -var ( - once sync.Once - - // SeededSecurely is set to true if a cryptographically secure seed - // was used to initialize rand. When false, the start time is used - // as a seed. - SeededSecurely bool -) - -// SeedMathRand provides weak, but guaranteed seeding, which is better than -// running with Go's default seed of 1. A call to SeedMathRand() is expected -// to be called via init(), but never a second time. -func SeedMathRand() { - once.Do(func() { - n, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64)) - if err != nil { - rand.Seed(time.Now().UTC().UnixNano()) - return - } - rand.Seed(n.Int64()) - SeededSecurely = true - }) -} diff --git a/lib/routine/routine.go b/lib/routine/routine.go index cf1ab1c0d918..4b7277ff996e 100644 --- a/lib/routine/routine.go +++ b/lib/routine/routine.go @@ -12,7 +12,7 @@ type Routine func(ctx context.Context) error // cancelCh is the ctx.Done() // When cancel() is called, if the routine is running a blocking call (e.g. some ACL replication RPCs), -// stoppedCh won't be closed till the blocking call returns, while cancelCh will be closed immediately. +// stoppedCh won't be closed till the blocking call returns, while cancelCh will be closed immediately. // cancelCh is used to properly detect routine running status between cancel() and close(stoppedCh) type routineTracker struct { cancel context.CancelFunc @@ -110,9 +110,9 @@ func (m *Manager) execute(ctx context.Context, name string, routine Routine, don } // Caveat: The returned stoppedCh indicates that the routine is completed -// It's possible that ctx is canceled, but stoppedCh not yet closed -// Use mgr.IsRunning(name) than this stoppedCh to tell whether the -// instance is still running (not cancelled or completed). +// It's possible that ctx is canceled, but stoppedCh not yet closed +// Use mgr.IsRunning(name) than this stoppedCh to tell whether the +// instance is still running (not cancelled or completed). func (m *Manager) Stop(name string) <-chan struct{} { instance := m.stopInstance(name) if instance == nil { diff --git a/lib/translate.go b/lib/translate.go index 815dd73a439d..3404039a6e5a 100644 --- a/lib/translate.go +++ b/lib/translate.go @@ -12,7 +12,7 @@ import ( // // Example: // -// m = TranslateKeys(m, map[string]string{"snake_case": "CamelCase"}) +// m = TranslateKeys(m, map[string]string{"snake_case": "CamelCase"}) // // If the canonical string provided is the empty string, the effect is to stop // recursing into any key matching the left hand side. In this case the left @@ -27,13 +27,14 @@ import ( // where the clash with key names in other parts of the definition :sob: // // Example: -// m - TranslateKeys(m, map[string]string{ -// "foo_bar": "FooBar", -// "widget.config": "", -// // Assume widgets is an array, this will prevent recursing into any -// // item's config field -// "widgets.config": "", -// }) +// +// m - TranslateKeys(m, map[string]string{ +// "foo_bar": "FooBar", +// "widget.config": "", +// // Assume widgets is an array, this will prevent recursing into any +// // item's config field +// "widgets.config": "", +// }) // // Deprecated: Use lib/decode.HookTranslateKeys instead. func TranslateKeys(v map[string]interface{}, dict map[string]string) { diff --git a/lib/useragent.go b/lib/useragent.go index 84e76d4dfb87..f083fe3f1903 100644 --- a/lib/useragent.go +++ b/lib/useragent.go @@ -16,7 +16,7 @@ var ( // versionFunc is the func that returns the current version. This is a // function to take into account the different build processes and distinguish - // between enterprise and oss builds. + // between enterprise and CE builds. versionFunc = func() string { return version.GetHumanVersion() } diff --git a/logging/logfile.go b/logging/logfile.go index 153473482ff3..bb0c71269735 100644 --- a/logging/logfile.go +++ b/logging/logfile.go @@ -15,7 +15,7 @@ var ( now = time.Now ) -//LogFile is used to setup a file based logger that also performs log rotation +// LogFile is used to setup a file based logger that also performs log rotation type LogFile struct { //Name of the log file fileName string @@ -57,31 +57,50 @@ func (l *LogFile) fileNamePattern() string { } func (l *LogFile) openNew() error { - fileNamePattern := l.fileNamePattern() - - createTime := now() - newfileName := fmt.Sprintf(fileNamePattern, strconv.FormatInt(createTime.UnixNano(), 10)) + newfileName := l.fileName newfilePath := filepath.Join(l.logPath, newfileName) - // Try creating a file. We truncate the file because we are the only authority to write the logs - filePointer, err := os.OpenFile(newfilePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0640) + // Try creating or opening the active log file. Since the active log file + // always has the same name, append log entries to prevent overwriting + // previous log data. + filePointer, err := os.OpenFile(newfilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0640) if err != nil { return err } l.FileInfo = filePointer + stat, err := filePointer.Stat() + if err != nil { + return err + } // New file, new bytes tracker, new creation time :) - l.LastCreated = createTime + l.LastCreated = l.createTime(stat) l.BytesWritten = 0 return nil } +func (l *LogFile) renameCurrentFile() error { + fileNamePattern := l.fileNamePattern() + + createTime := now() + // Current file is consul.log always + currentFilePath := filepath.Join(l.logPath, l.fileName) + + oldFileName := fmt.Sprintf(fileNamePattern, strconv.FormatInt(createTime.UnixNano(), 10)) + oldFilePath := filepath.Join(l.logPath, oldFileName) + + return os.Rename(currentFilePath, oldFilePath) +} + func (l *LogFile) rotate() error { // Get the time from the last point of contact timeElapsed := time.Since(l.LastCreated) // Rotate if we hit the byte file limit or the time limit if (l.BytesWritten >= int64(l.MaxBytes) && (l.MaxBytes > 0)) || timeElapsed >= l.duration { l.FileInfo.Close() + if err := l.renameCurrentFile(); err != nil { + return err + } if err := l.pruneFiles(); err != nil { return err } diff --git a/logging/logfile_bsd.go b/logging/logfile_bsd.go new file mode 100644 index 000000000000..d81d065be1ce --- /dev/null +++ b/logging/logfile_bsd.go @@ -0,0 +1,16 @@ +//go:build darwin || freebsd || netbsd || openbsd +// +build darwin freebsd netbsd openbsd + +package logging + +import ( + "os" + "syscall" + "time" +) + +func (l *LogFile) createTime(stat os.FileInfo) time.Time { + stat_t := stat.Sys().(*syscall.Stat_t) + createTime := stat_t.Ctimespec + return time.Unix(int64(createTime.Sec), int64(createTime.Nsec)) +} diff --git a/logging/logfile_linux.go b/logging/logfile_linux.go new file mode 100644 index 000000000000..6cdacfe80e22 --- /dev/null +++ b/logging/logfile_linux.go @@ -0,0 +1,17 @@ +//go:build dragonfly || linux +// +build dragonfly linux + +package logging + +import ( + "os" + "syscall" + "time" +) + +func (l *LogFile) createTime(stat os.FileInfo) time.Time { + stat_t := stat.Sys().(*syscall.Stat_t) + createTime := stat_t.Ctim + // Sec and Nsec are int32 in 32-bit architectures. + return time.Unix(int64(createTime.Sec), int64(createTime.Nsec)) //nolint:unconvert +} diff --git a/logging/logfile_solaris.go b/logging/logfile_solaris.go new file mode 100644 index 000000000000..b64610cc38fc --- /dev/null +++ b/logging/logfile_solaris.go @@ -0,0 +1,17 @@ +//go:build solaris +// +build solaris + +package logging + +import ( + "os" + "syscall" + "time" +) + +func (l *LogFile) createTime(stat os.FileInfo) time.Time { + stat_t := stat.Sys().(*syscall.Stat_t) + createTime := stat_t.Ctim + // Sec and Nsec are int32 in 32-bit architectures. + return time.Unix(int64(createTime.Sec), int64(createTime.Nsec)) //nolint:unconvert +} diff --git a/logging/logfile_test.go b/logging/logfile_test.go index 96fc0e169644..73c81a37f11b 100644 --- a/logging/logfile_test.go +++ b/logging/logfile_test.go @@ -49,6 +49,22 @@ func TestLogFile_openNew(t *testing.T) { require.Contains(t, string(content), msg) } +func TestLogFile_renameCurrentFile(t *testing.T) { + logFile := LogFile{ + fileName: "consul.log", + logPath: testutil.TempDir(t, ""), + duration: defaultRotateDuration, + } + err := logFile.openNew() + require.NoError(t, err) + + err = logFile.renameCurrentFile() + require.NoError(t, err) + + _, err = os.ReadFile(logFile.FileInfo.Name()) + require.Contains(t, err.Error(), "no such file or directory") +} + func TestLogFile_Rotation_MaxBytes(t *testing.T) { tempDir := testutil.TempDir(t, "LogWriterBytes") logFile := LogFile{ diff --git a/logging/logfile_windows.go b/logging/logfile_windows.go new file mode 100644 index 000000000000..688a8351cdbe --- /dev/null +++ b/logging/logfile_windows.go @@ -0,0 +1,14 @@ +package logging + +import ( + "os" + "time" +) + +func (l *LogFile) createTime(stat os.FileInfo) time.Time { + // Use `ModTime` as an approximation if the exact create time is not + // available. + // On Windows, the file create time is not updated after the active log + // rotates, so use `ModTime` as an approximation as well. + return stat.ModTime() +} diff --git a/main.go b/main.go index e7b04e241fb5..35bb04281d6d 100644 --- a/main.go +++ b/main.go @@ -11,14 +11,9 @@ import ( "github.com/hashicorp/consul/command" "github.com/hashicorp/consul/command/cli" "github.com/hashicorp/consul/command/version" - "github.com/hashicorp/consul/lib" _ "github.com/hashicorp/consul/service_os" ) -func init() { - lib.SeedMathRand() -} - func main() { os.Exit(realMain()) } diff --git a/proto-public/go.mod b/proto-public/go.mod index 9870dccfb5e8..7179ce8f1ccc 100644 --- a/proto-public/go.mod +++ b/proto-public/go.mod @@ -4,13 +4,18 @@ go 1.19 require ( github.com/golang/protobuf v1.5.0 + github.com/stretchr/testify v1.5.1 google.golang.org/grpc v1.37.1 google.golang.org/protobuf v1.27.1 ) require ( - golang.org/x/net v0.0.0-20190311183353-d8887717615a // indirect - golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a // indirect - golang.org/x/text v0.3.0 // indirect + github.com/davecgh/go-spew v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/objx v0.1.0 // indirect + golang.org/x/net v0.13.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect + gopkg.in/yaml.v2 v2.2.2 // indirect ) diff --git a/proto-public/go.sum b/proto-public/go.sum index 59e6e6727b78..74915e0d847c 100644 --- a/proto-public/go.sum +++ b/proto-public/go.sum @@ -3,6 +3,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -29,9 +30,12 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -41,17 +45,20 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY= +golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -82,7 +89,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/proto-public/pbacl/acl.pb.go b/proto-public/pbacl/acl.pb.go index 1a89a05c136a..40ee16831ecc 100644 --- a/proto-public/pbacl/acl.pb.go +++ b/proto-public/pbacl/acl.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto-public/pbacl/acl.proto diff --git a/proto-public/pbconnectca/ca.pb.go b/proto-public/pbconnectca/ca.pb.go index e690ae1c2fa0..1a76ab02b79a 100644 --- a/proto-public/pbconnectca/ca.pb.go +++ b/proto-public/pbconnectca/ca.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto-public/pbconnectca/ca.proto diff --git a/proto-public/pbdataplane/dataplane.pb.go b/proto-public/pbdataplane/dataplane.pb.go index 8e8a1000f253..21caa9e4d10a 100644 --- a/proto-public/pbdataplane/dataplane.pb.go +++ b/proto-public/pbdataplane/dataplane.pb.go @@ -2,7 +2,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto-public/pbdataplane/dataplane.proto @@ -296,6 +296,7 @@ type GetEnvoyBootstrapParamsRequest struct { unknownFields protoimpl.UnknownFields // Types that are assignable to NodeSpec: + // // *GetEnvoyBootstrapParamsRequest_NodeId // *GetEnvoyBootstrapParamsRequest_NodeName NodeSpec isGetEnvoyBootstrapParamsRequest_NodeSpec `protobuf_oneof:"node_spec"` diff --git a/proto-public/pbdns/dns.pb.go b/proto-public/pbdns/dns.pb.go index cf136c2bd332..90d080294fd5 100644 --- a/proto-public/pbdns/dns.pb.go +++ b/proto-public/pbdns/dns.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto-public/pbdns/dns.proto diff --git a/proto-public/pbdns/mock_DNSServiceClient.go b/proto-public/pbdns/mock_DNSServiceClient.go index a11f1e963e95..d9fffda65aef 100644 --- a/proto-public/pbdns/mock_DNSServiceClient.go +++ b/proto-public/pbdns/mock_DNSServiceClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.12.2. DO NOT EDIT. +// Code generated by mockery v2.20.0. DO NOT EDIT. package pbdns @@ -8,8 +8,6 @@ import ( grpc "google.golang.org/grpc" mock "github.com/stretchr/testify/mock" - - testing "testing" ) // MockDNSServiceClient is an autogenerated mock type for the DNSServiceClient type @@ -29,6 +27,10 @@ func (_m *MockDNSServiceClient) Query(ctx context.Context, in *QueryRequest, opt ret := _m.Called(_ca...) var r0 *QueryResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *QueryRequest, ...grpc.CallOption) (*QueryResponse, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *QueryRequest, ...grpc.CallOption) *QueryResponse); ok { r0 = rf(ctx, in, opts...) } else { @@ -37,7 +39,6 @@ func (_m *MockDNSServiceClient) Query(ctx context.Context, in *QueryRequest, opt } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *QueryRequest, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { @@ -47,8 +48,13 @@ func (_m *MockDNSServiceClient) Query(ctx context.Context, in *QueryRequest, opt return r0, r1 } -// NewMockDNSServiceClient creates a new instance of MockDNSServiceClient. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockDNSServiceClient(t testing.TB) *MockDNSServiceClient { +type mockConstructorTestingTNewMockDNSServiceClient interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockDNSServiceClient creates a new instance of MockDNSServiceClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockDNSServiceClient(t mockConstructorTestingTNewMockDNSServiceClient) *MockDNSServiceClient { mock := &MockDNSServiceClient{} mock.Mock.Test(t) diff --git a/proto-public/pbdns/mock_DNSServiceServer.go b/proto-public/pbdns/mock_DNSServiceServer.go index 97b98dddbd66..e78c7d4c304b 100644 --- a/proto-public/pbdns/mock_DNSServiceServer.go +++ b/proto-public/pbdns/mock_DNSServiceServer.go @@ -1,10 +1,9 @@ -// Code generated by mockery v2.12.2. DO NOT EDIT. +// Code generated by mockery v2.20.0. DO NOT EDIT. package pbdns import ( context "context" - testing "testing" mock "github.com/stretchr/testify/mock" ) @@ -19,6 +18,10 @@ func (_m *MockDNSServiceServer) Query(_a0 context.Context, _a1 *QueryRequest) (* ret := _m.Called(_a0, _a1) var r0 *QueryResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *QueryRequest) (*QueryResponse, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, *QueryRequest) *QueryResponse); ok { r0 = rf(_a0, _a1) } else { @@ -27,7 +30,6 @@ func (_m *MockDNSServiceServer) Query(_a0 context.Context, _a1 *QueryRequest) (* } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *QueryRequest) error); ok { r1 = rf(_a0, _a1) } else { @@ -37,8 +39,13 @@ func (_m *MockDNSServiceServer) Query(_a0 context.Context, _a1 *QueryRequest) (* return r0, r1 } -// NewMockDNSServiceServer creates a new instance of MockDNSServiceServer. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockDNSServiceServer(t testing.TB) *MockDNSServiceServer { +type mockConstructorTestingTNewMockDNSServiceServer interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockDNSServiceServer creates a new instance of MockDNSServiceServer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockDNSServiceServer(t mockConstructorTestingTNewMockDNSServiceServer) *MockDNSServiceServer { mock := &MockDNSServiceServer{} mock.Mock.Test(t) diff --git a/proto-public/pbdns/mock_UnsafeDNSServiceServer.go b/proto-public/pbdns/mock_UnsafeDNSServiceServer.go index a56e55bcb628..43a9e1e461ae 100644 --- a/proto-public/pbdns/mock_UnsafeDNSServiceServer.go +++ b/proto-public/pbdns/mock_UnsafeDNSServiceServer.go @@ -1,12 +1,8 @@ -// Code generated by mockery v2.12.2. DO NOT EDIT. +// Code generated by mockery v2.20.0. DO NOT EDIT. package pbdns -import ( - testing "testing" - - mock "github.com/stretchr/testify/mock" -) +import mock "github.com/stretchr/testify/mock" // MockUnsafeDNSServiceServer is an autogenerated mock type for the UnsafeDNSServiceServer type type MockUnsafeDNSServiceServer struct { @@ -18,8 +14,13 @@ func (_m *MockUnsafeDNSServiceServer) mustEmbedUnimplementedDNSServiceServer() { _m.Called() } -// NewMockUnsafeDNSServiceServer creates a new instance of MockUnsafeDNSServiceServer. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockUnsafeDNSServiceServer(t testing.TB) *MockUnsafeDNSServiceServer { +type mockConstructorTestingTNewMockUnsafeDNSServiceServer interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockUnsafeDNSServiceServer creates a new instance of MockUnsafeDNSServiceServer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockUnsafeDNSServiceServer(t mockConstructorTestingTNewMockUnsafeDNSServiceServer) *MockUnsafeDNSServiceServer { mock := &MockUnsafeDNSServiceServer{} mock.Mock.Test(t) diff --git a/proto-public/pbserverdiscovery/serverdiscovery.pb.go b/proto-public/pbserverdiscovery/serverdiscovery.pb.go index 050158d38672..d273d27601cf 100644 --- a/proto-public/pbserverdiscovery/serverdiscovery.pb.go +++ b/proto-public/pbserverdiscovery/serverdiscovery.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto-public/pbserverdiscovery/serverdiscovery.proto diff --git a/proto/pbacl/acl.pb.go b/proto/pbacl/acl.pb.go index ede3fc3ba41b..430666921345 100644 --- a/proto/pbacl/acl.pb.go +++ b/proto/pbacl/acl.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto/pbacl/acl.proto diff --git a/proto/pbautoconf/auto_config.pb.go b/proto/pbautoconf/auto_config.pb.go index f93a4263d62f..3af70821fb79 100644 --- a/proto/pbautoconf/auto_config.pb.go +++ b/proto/pbautoconf/auto_config.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto/pbautoconf/auto_config.proto diff --git a/proto/pbautoconf/auto_config_oss.go b/proto/pbautoconf/auto_config_ce.go similarity index 100% rename from proto/pbautoconf/auto_config_oss.go rename to proto/pbautoconf/auto_config_ce.go diff --git a/proto/pbcommon/common.pb.go b/proto/pbcommon/common.pb.go index 80010a7ab028..c43d58f2eacf 100644 --- a/proto/pbcommon/common.pb.go +++ b/proto/pbcommon/common.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto/pbcommon/common.proto diff --git a/proto/pbcommon/common_oss.go b/proto/pbcommon/common_ce.go similarity index 100% rename from proto/pbcommon/common_oss.go rename to proto/pbcommon/common_ce.go diff --git a/proto/pbconfig/config.pb.go b/proto/pbconfig/config.pb.go index 80953c882b26..589985d171e6 100644 --- a/proto/pbconfig/config.pb.go +++ b/proto/pbconfig/config.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto/pbconfig/config.proto diff --git a/proto/pbconfigentry/config_entry.gen.go b/proto/pbconfigentry/config_entry.gen.go index bfdce5e5c0e8..64641ac1d7bb 100644 --- a/proto/pbconfigentry/config_entry.gen.go +++ b/proto/pbconfigentry/config_entry.gen.go @@ -20,6 +20,70 @@ func CookieConfigFromStructs(t *structs.CookieConfig, s *CookieConfig) { s.TTL = structs.DurationToProto(t.TTL) s.Path = t.Path } +func DestinationConfigToStructs(s *DestinationConfig, t *structs.DestinationConfig) { + if s == nil { + return + } + t.Addresses = s.Addresses + t.Port = int(s.Port) +} +func DestinationConfigFromStructs(t *structs.DestinationConfig, s *DestinationConfig) { + if s == nil { + return + } + s.Addresses = t.Addresses + s.Port = int32(t.Port) +} +func ExposeConfigToStructs(s *ExposeConfig, t *structs.ExposeConfig) { + if s == nil { + return + } + t.Checks = s.Checks + { + t.Paths = make([]structs.ExposePath, len(s.Paths)) + for i := range s.Paths { + if s.Paths[i] != nil { + ExposePathToStructs(s.Paths[i], &t.Paths[i]) + } + } + } +} +func ExposeConfigFromStructs(t *structs.ExposeConfig, s *ExposeConfig) { + if s == nil { + return + } + s.Checks = t.Checks + { + s.Paths = make([]*ExposePath, len(t.Paths)) + for i := range t.Paths { + { + var x ExposePath + ExposePathFromStructs(&t.Paths[i], &x) + s.Paths[i] = &x + } + } + } +} +func ExposePathToStructs(s *ExposePath, t *structs.ExposePath) { + if s == nil { + return + } + t.ListenerPort = int(s.ListenerPort) + t.Path = s.Path + t.LocalPathPort = int(s.LocalPathPort) + t.Protocol = s.Protocol + t.ParsedFromCheck = s.ParsedFromCheck +} +func ExposePathFromStructs(t *structs.ExposePath, s *ExposePath) { + if s == nil { + return + } + s.ListenerPort = int32(t.ListenerPort) + s.Path = t.Path + s.LocalPathPort = int32(t.LocalPathPort) + s.Protocol = t.Protocol + s.ParsedFromCheck = t.ParsedFromCheck +} func GatewayServiceTLSConfigToStructs(s *GatewayServiceTLSConfig, t *structs.GatewayServiceTLSConfig) { if s == nil { return @@ -496,6 +560,18 @@ func MeshDirectionalTLSConfigFromStructs(t *structs.MeshDirectionalTLSConfig, s s.TLSMaxVersion = tlsVersionFromStructs(t.TLSMaxVersion) s.CipherSuites = cipherSuitesFromStructs(t.CipherSuites) } +func MeshGatewayConfigToStructs(s *MeshGatewayConfig, t *structs.MeshGatewayConfig) { + if s == nil { + return + } + t.Mode = meshGatewayModeToStructs(s.Mode) +} +func MeshGatewayConfigFromStructs(t *structs.MeshGatewayConfig, s *MeshGatewayConfig) { + if s == nil { + return + } + s.Mode = meshGatewayModeFromStructs(t.Mode) +} func MeshHTTPConfigToStructs(s *MeshHTTPConfig, t *structs.MeshHTTPConfig) { if s == nil { return @@ -538,6 +614,26 @@ func MeshTLSConfigFromStructs(t *structs.MeshTLSConfig, s *MeshTLSConfig) { s.Outgoing = &x } } +func PassiveHealthCheckToStructs(s *PassiveHealthCheck, t *structs.PassiveHealthCheck) { + if s == nil { + return + } + t.Interval = structs.DurationFromProto(s.Interval) + t.MaxFailures = s.MaxFailures + t.EnforcingConsecutive5xx = pointerToUint32FromUint32(s.EnforcingConsecutive5Xx) + t.MaxEjectionPercent = pointerToUint32FromUint32(s.MaxEjectionPercent) + t.BaseEjectionTime = structs.DurationPointerFromProto(s.BaseEjectionTime) +} +func PassiveHealthCheckFromStructs(t *structs.PassiveHealthCheck, s *PassiveHealthCheck) { + if s == nil { + return + } + s.Interval = structs.DurationToProto(t.Interval) + s.MaxFailures = t.MaxFailures + s.EnforcingConsecutive5Xx = uint32FromPointerToUint32(t.EnforcingConsecutive5xx) + s.MaxEjectionPercent = uint32FromPointerToUint32(t.MaxEjectionPercent) + s.BaseEjectionTime = structs.DurationPointerToProto(t.BaseEjectionTime) +} func PeeringMeshConfigToStructs(s *PeeringMeshConfig, t *structs.PeeringMeshConfig) { if s == nil { return @@ -564,6 +660,76 @@ func RingHashConfigFromStructs(t *structs.RingHashConfig, s *RingHashConfig) { s.MinimumRingSize = t.MinimumRingSize s.MaximumRingSize = t.MaximumRingSize } +func ServiceDefaultsToStructs(s *ServiceDefaults, t *structs.ServiceConfigEntry) { + if s == nil { + return + } + t.Protocol = s.Protocol + t.Mode = proxyModeToStructs(s.Mode) + if s.TransparentProxy != nil { + TransparentProxyConfigToStructs(s.TransparentProxy, &t.TransparentProxy) + } + if s.MeshGateway != nil { + MeshGatewayConfigToStructs(s.MeshGateway, &t.MeshGateway) + } + if s.Expose != nil { + ExposeConfigToStructs(s.Expose, &t.Expose) + } + t.ExternalSNI = s.ExternalSNI + if s.UpstreamConfig != nil { + var x structs.UpstreamConfiguration + UpstreamConfigurationToStructs(s.UpstreamConfig, &x) + t.UpstreamConfig = &x + } + if s.Destination != nil { + var x structs.DestinationConfig + DestinationConfigToStructs(s.Destination, &x) + t.Destination = &x + } + t.MaxInboundConnections = int(s.MaxInboundConnections) + t.LocalConnectTimeoutMs = int(s.LocalConnectTimeoutMs) + t.LocalRequestTimeoutMs = int(s.LocalRequestTimeoutMs) + t.BalanceInboundConnections = s.BalanceInboundConnections + t.Meta = s.Meta +} +func ServiceDefaultsFromStructs(t *structs.ServiceConfigEntry, s *ServiceDefaults) { + if s == nil { + return + } + s.Protocol = t.Protocol + s.Mode = proxyModeFromStructs(t.Mode) + { + var x TransparentProxyConfig + TransparentProxyConfigFromStructs(&t.TransparentProxy, &x) + s.TransparentProxy = &x + } + { + var x MeshGatewayConfig + MeshGatewayConfigFromStructs(&t.MeshGateway, &x) + s.MeshGateway = &x + } + { + var x ExposeConfig + ExposeConfigFromStructs(&t.Expose, &x) + s.Expose = &x + } + s.ExternalSNI = t.ExternalSNI + if t.UpstreamConfig != nil { + var x UpstreamConfiguration + UpstreamConfigurationFromStructs(t.UpstreamConfig, &x) + s.UpstreamConfig = &x + } + if t.Destination != nil { + var x DestinationConfig + DestinationConfigFromStructs(t.Destination, &x) + s.Destination = &x + } + s.MaxInboundConnections = int32(t.MaxInboundConnections) + s.LocalConnectTimeoutMs = int32(t.LocalConnectTimeoutMs) + s.LocalRequestTimeoutMs = int32(t.LocalRequestTimeoutMs) + s.BalanceInboundConnections = t.BalanceInboundConnections + s.Meta = t.Meta +} func ServiceIntentionsToStructs(s *ServiceIntentions, t *structs.ServiceIntentionsConfigEntry) { if s == nil { return @@ -627,6 +793,7 @@ func ServiceResolverToStructs(s *ServiceResolver, t *structs.ServiceResolverConf } } t.ConnectTimeout = structs.DurationFromProto(s.ConnectTimeout) + t.RequestTimeout = structs.DurationFromProto(s.RequestTimeout) if s.LoadBalancer != nil { var x structs.LoadBalancer LoadBalancerToStructs(s.LoadBalancer, &x) @@ -669,6 +836,7 @@ func ServiceResolverFromStructs(t *structs.ServiceResolverConfigEntry, s *Servic } } s.ConnectTimeout = structs.DurationToProto(t.ConnectTimeout) + s.RequestTimeout = structs.DurationToProto(t.RequestTimeout) if t.LoadBalancer != nil { var x LoadBalancer LoadBalancerFromStructs(t.LoadBalancer, &x) @@ -822,6 +990,20 @@ func SourceIntentionFromStructs(t *structs.SourceIntention, s *SourceIntention) s.EnterpriseMeta = enterpriseMetaFromStructs(t.EnterpriseMeta) s.Peer = t.Peer } +func TransparentProxyConfigToStructs(s *TransparentProxyConfig, t *structs.TransparentProxyConfig) { + if s == nil { + return + } + t.OutboundListenerPort = int(s.OutboundListenerPort) + t.DialedDirectly = s.DialedDirectly +} +func TransparentProxyConfigFromStructs(t *structs.TransparentProxyConfig, s *TransparentProxyConfig) { + if s == nil { + return + } + s.OutboundListenerPort = int32(t.OutboundListenerPort) + s.DialedDirectly = t.DialedDirectly +} func TransparentProxyMeshConfigToStructs(s *TransparentProxyMeshConfig, t *structs.TransparentProxyMeshConfig) { if s == nil { return @@ -834,3 +1016,111 @@ func TransparentProxyMeshConfigFromStructs(t *structs.TransparentProxyMeshConfig } s.MeshDestinationsOnly = t.MeshDestinationsOnly } +func UpstreamConfigToStructs(s *UpstreamConfig, t *structs.UpstreamConfig) { + if s == nil { + return + } + t.Name = s.Name + t.EnterpriseMeta = enterpriseMetaToStructs(s.EnterpriseMeta) + t.EnvoyListenerJSON = s.EnvoyListenerJSON + t.EnvoyClusterJSON = s.EnvoyClusterJSON + t.Protocol = s.Protocol + t.ConnectTimeoutMs = int(s.ConnectTimeoutMs) + if s.Limits != nil { + var x structs.UpstreamLimits + UpstreamLimitsToStructs(s.Limits, &x) + t.Limits = &x + } + if s.PassiveHealthCheck != nil { + var x structs.PassiveHealthCheck + PassiveHealthCheckToStructs(s.PassiveHealthCheck, &x) + t.PassiveHealthCheck = &x + } + if s.MeshGateway != nil { + MeshGatewayConfigToStructs(s.MeshGateway, &t.MeshGateway) + } + t.BalanceOutboundConnections = s.BalanceOutboundConnections +} +func UpstreamConfigFromStructs(t *structs.UpstreamConfig, s *UpstreamConfig) { + if s == nil { + return + } + s.Name = t.Name + s.EnterpriseMeta = enterpriseMetaFromStructs(t.EnterpriseMeta) + s.EnvoyListenerJSON = t.EnvoyListenerJSON + s.EnvoyClusterJSON = t.EnvoyClusterJSON + s.Protocol = t.Protocol + s.ConnectTimeoutMs = int32(t.ConnectTimeoutMs) + if t.Limits != nil { + var x UpstreamLimits + UpstreamLimitsFromStructs(t.Limits, &x) + s.Limits = &x + } + if t.PassiveHealthCheck != nil { + var x PassiveHealthCheck + PassiveHealthCheckFromStructs(t.PassiveHealthCheck, &x) + s.PassiveHealthCheck = &x + } + { + var x MeshGatewayConfig + MeshGatewayConfigFromStructs(&t.MeshGateway, &x) + s.MeshGateway = &x + } + s.BalanceOutboundConnections = t.BalanceOutboundConnections +} +func UpstreamConfigurationToStructs(s *UpstreamConfiguration, t *structs.UpstreamConfiguration) { + if s == nil { + return + } + { + t.Overrides = make([]*structs.UpstreamConfig, len(s.Overrides)) + for i := range s.Overrides { + if s.Overrides[i] != nil { + var x structs.UpstreamConfig + UpstreamConfigToStructs(s.Overrides[i], &x) + t.Overrides[i] = &x + } + } + } + if s.Defaults != nil { + var x structs.UpstreamConfig + UpstreamConfigToStructs(s.Defaults, &x) + t.Defaults = &x + } +} +func UpstreamConfigurationFromStructs(t *structs.UpstreamConfiguration, s *UpstreamConfiguration) { + if s == nil { + return + } + { + s.Overrides = make([]*UpstreamConfig, len(t.Overrides)) + for i := range t.Overrides { + if t.Overrides[i] != nil { + var x UpstreamConfig + UpstreamConfigFromStructs(t.Overrides[i], &x) + s.Overrides[i] = &x + } + } + } + if t.Defaults != nil { + var x UpstreamConfig + UpstreamConfigFromStructs(t.Defaults, &x) + s.Defaults = &x + } +} +func UpstreamLimitsToStructs(s *UpstreamLimits, t *structs.UpstreamLimits) { + if s == nil { + return + } + t.MaxConnections = pointerToIntFromInt32(s.MaxConnections) + t.MaxPendingRequests = pointerToIntFromInt32(s.MaxPendingRequests) + t.MaxConcurrentRequests = pointerToIntFromInt32(s.MaxConcurrentRequests) +} +func UpstreamLimitsFromStructs(t *structs.UpstreamLimits, s *UpstreamLimits) { + if s == nil { + return + } + s.MaxConnections = int32FromPointerToInt(t.MaxConnections) + s.MaxPendingRequests = int32FromPointerToInt(t.MaxPendingRequests) + s.MaxConcurrentRequests = int32FromPointerToInt(t.MaxConcurrentRequests) +} diff --git a/proto/pbconfigentry/config_entry.go b/proto/pbconfigentry/config_entry.go index 7553bd82fe7e..a864a3a3b68f 100644 --- a/proto/pbconfigentry/config_entry.go +++ b/proto/pbconfigentry/config_entry.go @@ -5,7 +5,7 @@ import ( "time" "github.com/golang/protobuf/ptypes/timestamp" - timestamppb "google.golang.org/protobuf/types/known/timestamppb" + "google.golang.org/protobuf/types/known/timestamppb" "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/structs" @@ -45,6 +45,14 @@ func ConfigEntryToStructs(s *ConfigEntry) structs.ConfigEntry { pbcommon.RaftIndexToStructs(s.RaftIndex, &target.RaftIndex) pbcommon.EnterpriseMetaToStructs(s.EnterpriseMeta, &target.EnterpriseMeta) return &target + case Kind_KindServiceDefaults: + var target structs.ServiceConfigEntry + target.Name = s.Name + + ServiceDefaultsToStructs(s.GetServiceDefaults(), &target) + pbcommon.RaftIndexToStructs(s.RaftIndex, &target.RaftIndex) + pbcommon.EnterpriseMetaToStructs(s.EnterpriseMeta, &target.EnterpriseMeta) + return &target default: panic(fmt.Sprintf("unable to convert ConfigEntry of kind %s to structs", s.Kind)) } @@ -93,6 +101,14 @@ func ConfigEntryFromStructs(s structs.ConfigEntry) *ConfigEntry { configEntry.Entry = &ConfigEntry_ServiceIntentions{ ServiceIntentions: &serviceIntentions, } + case *structs.ServiceConfigEntry: + var serviceDefaults ServiceDefaults + ServiceDefaultsFromStructs(v, &serviceDefaults) + + configEntry.Kind = Kind_KindServiceDefaults + configEntry.Entry = &ConfigEntry_ServiceDefaults{ + ServiceDefaults: &serviceDefaults, + } default: panic(fmt.Sprintf("unable to convert %T to proto", s)) } @@ -170,3 +186,83 @@ func intentionSourceTypeFromStructs(structs.IntentionSourceType) IntentionSource func intentionSourceTypeToStructs(IntentionSourceType) structs.IntentionSourceType { return structs.IntentionSourceConsul } + +func pointerToIntFromInt32(i32 int32) *int { + i := int(i32) + return &i +} + +func int32FromPointerToInt(i *int) int32 { + if i != nil { + return int32(*i) + } + return 0 +} + +func pointerToUint32FromUint32(ui32 uint32) *uint32 { + i := ui32 + return &i +} + +func uint32FromPointerToUint32(i *uint32) uint32 { + if i != nil { + return *i + } + return 0 +} + +func proxyModeFromStructs(a structs.ProxyMode) ProxyMode { + switch a { + case structs.ProxyModeDefault: + return ProxyMode_ProxyModeDefault + case structs.ProxyModeTransparent: + return ProxyMode_ProxyModeTransparent + case structs.ProxyModeDirect: + return ProxyMode_ProxyModeDirect + default: + return ProxyMode_ProxyModeDefault + } +} + +func proxyModeToStructs(a ProxyMode) structs.ProxyMode { + switch a { + case ProxyMode_ProxyModeDefault: + return structs.ProxyModeDefault + case ProxyMode_ProxyModeTransparent: + return structs.ProxyModeTransparent + case ProxyMode_ProxyModeDirect: + return structs.ProxyModeDirect + default: + return structs.ProxyModeDefault + } +} + +func meshGatewayModeFromStructs(a structs.MeshGatewayMode) MeshGatewayMode { + switch a { + case structs.MeshGatewayModeDefault: + return MeshGatewayMode_MeshGatewayModeDefault + case structs.MeshGatewayModeNone: + return MeshGatewayMode_MeshGatewayModeNone + case structs.MeshGatewayModeLocal: + return MeshGatewayMode_MeshGatewayModeLocal + case structs.MeshGatewayModeRemote: + return MeshGatewayMode_MeshGatewayModeRemote + default: + return MeshGatewayMode_MeshGatewayModeDefault + } +} + +func meshGatewayModeToStructs(a MeshGatewayMode) structs.MeshGatewayMode { + switch a { + case MeshGatewayMode_MeshGatewayModeDefault: + return structs.MeshGatewayModeDefault + case MeshGatewayMode_MeshGatewayModeNone: + return structs.MeshGatewayModeNone + case MeshGatewayMode_MeshGatewayModeLocal: + return structs.MeshGatewayModeLocal + case MeshGatewayMode_MeshGatewayModeRemote: + return structs.MeshGatewayModeRemote + default: + return structs.MeshGatewayModeDefault + } +} diff --git a/proto/pbconfigentry/config_entry.pb.binary.go b/proto/pbconfigentry/config_entry.pb.binary.go index af897e925bf6..5d69a6320fc3 100644 --- a/proto/pbconfigentry/config_entry.pb.binary.go +++ b/proto/pbconfigentry/config_entry.pb.binary.go @@ -306,3 +306,103 @@ func (msg *IntentionHTTPHeaderPermission) MarshalBinary() ([]byte, error) { func (msg *IntentionHTTPHeaderPermission) UnmarshalBinary(b []byte) error { return proto.Unmarshal(b, msg) } + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *ServiceDefaults) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *ServiceDefaults) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *TransparentProxyConfig) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *TransparentProxyConfig) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *MeshGatewayConfig) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *MeshGatewayConfig) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *ExposeConfig) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *ExposeConfig) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *ExposePath) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *ExposePath) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *UpstreamConfiguration) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *UpstreamConfiguration) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *UpstreamConfig) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *UpstreamConfig) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *UpstreamLimits) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *UpstreamLimits) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *PassiveHealthCheck) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *PassiveHealthCheck) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *DestinationConfig) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *DestinationConfig) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} diff --git a/proto/pbconfigentry/config_entry.pb.go b/proto/pbconfigentry/config_entry.pb.go index aaeb6ce9f25c..6b3372d0df5c 100644 --- a/proto/pbconfigentry/config_entry.pb.go +++ b/proto/pbconfigentry/config_entry.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto/pbconfigentry/config_entry.proto @@ -31,6 +31,7 @@ const ( Kind_KindServiceResolver Kind = 2 Kind_KindIngressGateway Kind = 3 Kind_KindServiceIntentions Kind = 4 + Kind_KindServiceDefaults Kind = 5 ) // Enum value maps for Kind. @@ -41,6 +42,7 @@ var ( 2: "KindServiceResolver", 3: "KindIngressGateway", 4: "KindServiceIntentions", + 5: "KindServiceDefaults", } Kind_value = map[string]int32{ "KindUnknown": 0, @@ -48,6 +50,7 @@ var ( "KindServiceResolver": 2, "KindIngressGateway": 3, "KindServiceIntentions": 4, + "KindServiceDefaults": 5, } ) @@ -167,6 +170,107 @@ func (IntentionSourceType) EnumDescriptor() ([]byte, []int) { return file_proto_pbconfigentry_config_entry_proto_rawDescGZIP(), []int{2} } +type ProxyMode int32 + +const ( + ProxyMode_ProxyModeDefault ProxyMode = 0 + ProxyMode_ProxyModeTransparent ProxyMode = 1 + ProxyMode_ProxyModeDirect ProxyMode = 2 +) + +// Enum value maps for ProxyMode. +var ( + ProxyMode_name = map[int32]string{ + 0: "ProxyModeDefault", + 1: "ProxyModeTransparent", + 2: "ProxyModeDirect", + } + ProxyMode_value = map[string]int32{ + "ProxyModeDefault": 0, + "ProxyModeTransparent": 1, + "ProxyModeDirect": 2, + } +) + +func (x ProxyMode) Enum() *ProxyMode { + p := new(ProxyMode) + *p = x + return p +} + +func (x ProxyMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ProxyMode) Descriptor() protoreflect.EnumDescriptor { + return file_proto_pbconfigentry_config_entry_proto_enumTypes[3].Descriptor() +} + +func (ProxyMode) Type() protoreflect.EnumType { + return &file_proto_pbconfigentry_config_entry_proto_enumTypes[3] +} + +func (x ProxyMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ProxyMode.Descriptor instead. +func (ProxyMode) EnumDescriptor() ([]byte, []int) { + return file_proto_pbconfigentry_config_entry_proto_rawDescGZIP(), []int{3} +} + +type MeshGatewayMode int32 + +const ( + MeshGatewayMode_MeshGatewayModeDefault MeshGatewayMode = 0 + MeshGatewayMode_MeshGatewayModeNone MeshGatewayMode = 1 + MeshGatewayMode_MeshGatewayModeLocal MeshGatewayMode = 2 + MeshGatewayMode_MeshGatewayModeRemote MeshGatewayMode = 3 +) + +// Enum value maps for MeshGatewayMode. +var ( + MeshGatewayMode_name = map[int32]string{ + 0: "MeshGatewayModeDefault", + 1: "MeshGatewayModeNone", + 2: "MeshGatewayModeLocal", + 3: "MeshGatewayModeRemote", + } + MeshGatewayMode_value = map[string]int32{ + "MeshGatewayModeDefault": 0, + "MeshGatewayModeNone": 1, + "MeshGatewayModeLocal": 2, + "MeshGatewayModeRemote": 3, + } +) + +func (x MeshGatewayMode) Enum() *MeshGatewayMode { + p := new(MeshGatewayMode) + *p = x + return p +} + +func (x MeshGatewayMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (MeshGatewayMode) Descriptor() protoreflect.EnumDescriptor { + return file_proto_pbconfigentry_config_entry_proto_enumTypes[4].Descriptor() +} + +func (MeshGatewayMode) Type() protoreflect.EnumType { + return &file_proto_pbconfigentry_config_entry_proto_enumTypes[4] +} + +func (x MeshGatewayMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use MeshGatewayMode.Descriptor instead. +func (MeshGatewayMode) EnumDescriptor() ([]byte, []int) { + return file_proto_pbconfigentry_config_entry_proto_rawDescGZIP(), []int{4} +} + type ConfigEntry struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -177,10 +281,12 @@ type ConfigEntry struct { EnterpriseMeta *pbcommon.EnterpriseMeta `protobuf:"bytes,3,opt,name=EnterpriseMeta,proto3" json:"EnterpriseMeta,omitempty"` RaftIndex *pbcommon.RaftIndex `protobuf:"bytes,4,opt,name=RaftIndex,proto3" json:"RaftIndex,omitempty"` // Types that are assignable to Entry: + // // *ConfigEntry_MeshConfig // *ConfigEntry_ServiceResolver // *ConfigEntry_IngressGateway // *ConfigEntry_ServiceIntentions + // *ConfigEntry_ServiceDefaults Entry isConfigEntry_Entry `protobuf_oneof:"Entry"` } @@ -279,6 +385,13 @@ func (x *ConfigEntry) GetServiceIntentions() *ServiceIntentions { return nil } +func (x *ConfigEntry) GetServiceDefaults() *ServiceDefaults { + if x, ok := x.GetEntry().(*ConfigEntry_ServiceDefaults); ok { + return x.ServiceDefaults + } + return nil +} + type isConfigEntry_Entry interface { isConfigEntry_Entry() } @@ -299,6 +412,10 @@ type ConfigEntry_ServiceIntentions struct { ServiceIntentions *ServiceIntentions `protobuf:"bytes,8,opt,name=ServiceIntentions,proto3,oneof"` } +type ConfigEntry_ServiceDefaults struct { + ServiceDefaults *ServiceDefaults `protobuf:"bytes,9,opt,name=ServiceDefaults,proto3,oneof"` +} + func (*ConfigEntry_MeshConfig) isConfigEntry_Entry() {} func (*ConfigEntry_ServiceResolver) isConfigEntry_Entry() {} @@ -307,6 +424,8 @@ func (*ConfigEntry_IngressGateway) isConfigEntry_Entry() {} func (*ConfigEntry_ServiceIntentions) isConfigEntry_Entry() {} +func (*ConfigEntry_ServiceDefaults) isConfigEntry_Entry() {} + // mog annotation: // // target=github.com/hashicorp/consul/agent/structs.MeshConfigEntry @@ -698,6 +817,8 @@ type ServiceResolver struct { ConnectTimeout *durationpb.Duration `protobuf:"bytes,5,opt,name=ConnectTimeout,proto3" json:"ConnectTimeout,omitempty"` LoadBalancer *LoadBalancer `protobuf:"bytes,6,opt,name=LoadBalancer,proto3" json:"LoadBalancer,omitempty"` Meta map[string]string `protobuf:"bytes,7,rep,name=Meta,proto3" json:"Meta,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto + RequestTimeout *durationpb.Duration `protobuf:"bytes,8,opt,name=RequestTimeout,proto3" json:"RequestTimeout,omitempty"` } func (x *ServiceResolver) Reset() { @@ -781,6 +902,13 @@ func (x *ServiceResolver) GetMeta() map[string]string { return nil } +func (x *ServiceResolver) GetRequestTimeout() *durationpb.Duration { + if x != nil { + return x.RequestTimeout + } + return nil +} + // mog annotation: // // target=github.com/hashicorp/consul/agent/structs.ServiceResolverSubset @@ -2516,692 +2644,1746 @@ func (x *IntentionHTTPHeaderPermission) GetInvert() bool { return false } -var File_proto_pbconfigentry_config_entry_proto protoreflect.FileDescriptor +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.ServiceConfigEntry +// output=config_entry.gen.go +// name=Structs +// ignore-fields=Kind,Name,RaftIndex,EnterpriseMeta +type ServiceDefaults struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -var file_proto_pbconfigentry_config_entry_proto_rawDesc = []byte{ - 0x0a, 0x26, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x65, 0x6e, 0x74, - 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x25, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, - 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x1a, - 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, - 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x1a, 0x1b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x94, 0x05, - 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x3f, 0x0a, - 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x68, 0x61, - 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, - 0x74, 0x72, 0x79, 0x2e, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x12, - 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x58, 0x0a, 0x0e, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, - 0x4d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x68, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6e, - 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x0e, 0x45, 0x6e, - 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x49, 0x0a, 0x09, - 0x52, 0x61, 0x66, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2b, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, - 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x52, 0x61, 0x66, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x09, 0x52, 0x61, - 0x66, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x53, 0x0a, 0x0a, 0x4d, 0x65, 0x73, 0x68, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x68, 0x61, - 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, - 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, - 0x52, 0x0a, 0x4d, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x62, 0x0a, 0x0f, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, - 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x48, 0x00, 0x52, - 0x0f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, - 0x12, 0x5f, 0x0a, 0x0e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x47, 0x61, 0x74, 0x65, 0x77, - 0x61, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, - 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, - 0x2e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x48, - 0x00, 0x52, 0x0e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x12, 0x68, 0x0a, 0x11, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x68, - 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, - 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x11, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x07, 0x0a, 0x05, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x22, 0xec, 0x03, 0x0a, 0x0a, 0x4d, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x12, 0x6d, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x41, 0x2e, - 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, - 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x52, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, - 0x78, 0x79, 0x12, 0x46, 0x0a, 0x03, 0x54, 0x4c, 0x53, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x34, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, - 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x65, 0x73, 0x68, 0x54, 0x4c, 0x53, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x03, 0x54, 0x4c, 0x53, 0x12, 0x49, 0x0a, 0x04, 0x48, 0x54, - 0x54, 0x50, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, - 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, - 0x2e, 0x4d, 0x65, 0x73, 0x68, 0x48, 0x54, 0x54, 0x50, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, - 0x04, 0x48, 0x54, 0x54, 0x50, 0x12, 0x4f, 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, - 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x65, 0x73, 0x68, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x52, 0x0a, 0x07, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, - 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, - 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, - 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x52, 0x07, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, - 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x22, 0x50, 0x0a, 0x1a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x32, 0x0a, 0x14, 0x4d, 0x65, 0x73, 0x68, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x14, 0x4d, 0x65, 0x73, 0x68, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0xc9, 0x01, 0x0a, 0x0d, 0x4d, 0x65, 0x73, 0x68, 0x54, 0x4c, - 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x5b, 0x0a, 0x08, 0x49, 0x6e, 0x63, 0x6f, 0x6d, - 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x68, 0x61, 0x73, 0x68, - 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, - 0x79, 0x2e, 0x4d, 0x65, 0x73, 0x68, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, - 0x6c, 0x54, 0x4c, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x49, 0x6e, 0x63, 0x6f, - 0x6d, 0x69, 0x6e, 0x67, 0x12, 0x5b, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, - 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4d, - 0x65, 0x73, 0x68, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x4c, - 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x4f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, - 0x67, 0x22, 0x8a, 0x01, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x68, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x4c, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x24, - 0x0a, 0x0d, 0x54, 0x4c, 0x53, 0x4d, 0x69, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x54, 0x4c, 0x53, 0x4d, 0x69, 0x6e, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x54, 0x4c, 0x53, 0x4d, 0x61, 0x78, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x54, 0x4c, 0x53, - 0x4d, 0x61, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x43, 0x69, - 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x0c, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73, 0x22, 0x54, - 0x0a, 0x0e, 0x4d, 0x65, 0x73, 0x68, 0x48, 0x54, 0x54, 0x50, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x12, 0x42, 0x0a, 0x1c, 0x53, 0x61, 0x6e, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x58, 0x46, 0x6f, 0x72, - 0x77, 0x61, 0x72, 0x64, 0x65, 0x64, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x65, 0x72, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x53, 0x61, 0x6e, 0x69, 0x74, 0x69, 0x7a, 0x65, - 0x58, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x64, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x43, 0x65, 0x72, 0x74, 0x22, 0x4d, 0x0a, 0x11, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x4d, - 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x38, 0x0a, 0x17, 0x50, 0x65, 0x65, - 0x72, 0x54, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x4d, 0x65, 0x73, 0x68, 0x47, 0x61, 0x74, 0x65, - 0x77, 0x61, 0x79, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x50, 0x65, 0x65, 0x72, - 0x54, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x4d, 0x65, 0x73, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, - 0x61, 0x79, 0x73, 0x22, 0xf6, 0x06, 0x0a, 0x0f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, - 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0d, 0x44, 0x65, 0x66, 0x61, 0x75, - 0x6c, 0x74, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, - 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x12, 0x5d, 0x0a, - 0x07, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, - 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, - 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, - 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x07, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x73, 0x12, 0x5a, 0x0a, 0x08, - 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3e, - 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, - 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, - 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x52, 0x08, - 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x12, 0x60, 0x0a, 0x08, 0x46, 0x61, 0x69, 0x6c, - 0x6f, 0x76, 0x65, 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x68, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, - 0x72, 0x79, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, - 0x65, 0x72, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x08, 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0e, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0e, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x57, 0x0a, - 0x0c, 0x4c, 0x6f, 0x61, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, - 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x6f, 0x61, 0x64, - 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x52, 0x0c, 0x4c, 0x6f, 0x61, 0x64, 0x42, 0x61, - 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x12, 0x54, 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x07, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, - 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, - 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, - 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x1a, 0x78, 0x0a, 0x0c, - 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x52, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, - 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, - 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, - 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x7b, 0x0a, 0x0d, 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, - 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x54, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, - 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, - 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, - 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x51, 0x0a, 0x15, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x53, - 0x75, 0x62, 0x73, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x20, 0x0a, - 0x0b, 0x4f, 0x6e, 0x6c, 0x79, 0x50, 0x61, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0b, 0x4f, 0x6e, 0x6c, 0x79, 0x50, 0x61, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x22, - 0xc9, 0x01, 0x0a, 0x17, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, - 0x76, 0x65, 0x72, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x4e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, - 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, - 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x63, - 0x65, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x44, 0x61, 0x74, - 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x50, 0x65, 0x65, 0x72, 0x22, 0xf9, 0x01, 0x0a, 0x17, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x46, - 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, - 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4e, 0x61, 0x6d, 0x65, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, - 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x44, 0x61, 0x74, 0x61, - 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x12, 0x5e, 0x0a, 0x07, 0x54, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, - 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, - 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, - 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x07, - 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x22, 0xcf, 0x01, 0x0a, 0x1d, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x46, 0x61, 0x69, 0x6c, 0x6f, - 0x76, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x75, - 0x62, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, - 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, - 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4e, 0x61, 0x6d, 0x65, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, - 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x63, - 0x65, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x50, 0x65, 0x65, 0x72, 0x22, 0xc7, 0x02, 0x0a, 0x0c, 0x4c, 0x6f, - 0x61, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x12, 0x5d, 0x0a, 0x0e, 0x52, 0x69, 0x6e, 0x67, 0x48, 0x61, 0x73, 0x68, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, - 0x72, 0x79, 0x2e, 0x52, 0x69, 0x6e, 0x67, 0x48, 0x61, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x52, 0x0e, 0x52, 0x69, 0x6e, 0x67, 0x48, 0x61, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x69, 0x0a, 0x12, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, - 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, - 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x12, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x55, 0x0a, 0x0c, - 0x48, 0x61, 0x73, 0x68, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, - 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0c, 0x48, 0x61, 0x73, 0x68, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x69, 0x65, 0x73, 0x22, 0x64, 0x0a, 0x0e, 0x52, 0x69, 0x6e, 0x67, 0x48, 0x61, 0x73, 0x68, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x28, 0x0a, 0x0f, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, - 0x52, 0x69, 0x6e, 0x67, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, - 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x52, 0x69, 0x6e, 0x67, 0x53, 0x69, 0x7a, 0x65, 0x12, - 0x28, 0x0a, 0x0f, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x52, 0x69, 0x6e, 0x67, 0x53, 0x69, - 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, - 0x6d, 0x52, 0x69, 0x6e, 0x67, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x36, 0x0a, 0x12, 0x4c, 0x65, 0x61, - 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, - 0x20, 0x0a, 0x0b, 0x43, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x43, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x75, 0x6e, - 0x74, 0x22, 0xd3, 0x01, 0x0a, 0x0a, 0x48, 0x61, 0x73, 0x68, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x12, 0x14, 0x0a, 0x05, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x46, 0x69, 0x65, 0x6c, - 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x43, 0x6f, 0x6f, 0x6b, 0x69, 0x65, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x68, - 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, - 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x52, 0x0c, 0x43, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, - 0x1a, 0x0a, 0x08, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x50, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x08, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x50, 0x12, 0x1a, 0x0a, 0x08, 0x54, - 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x54, - 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x22, 0x69, 0x0a, 0x0c, 0x43, 0x6f, 0x6f, 0x6b, 0x69, - 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x2b, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x54, 0x54, 0x4c, 0x12, 0x12, - 0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x50, 0x61, - 0x74, 0x68, 0x22, 0x98, 0x03, 0x0a, 0x0e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x47, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x49, 0x0a, 0x03, 0x54, 0x4c, 0x53, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, - 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, - 0x61, 0x79, 0x54, 0x4c, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x03, 0x54, 0x4c, 0x53, - 0x12, 0x54, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, - 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x67, 0x72, - 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x09, 0x4c, 0x69, 0x73, - 0x74, 0x65, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x53, 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, - 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, - 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x67, - 0x72, 0x65, 0x73, 0x73, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x4d, 0x65, 0x74, 0x61, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x57, 0x0a, 0x08, 0x44, - 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, - 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, - 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x44, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x73, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa4, 0x01, - 0x0a, 0x14, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x26, 0x0a, 0x0e, 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, - 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2e, - 0x0a, 0x12, 0x4d, 0x61, 0x78, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x4d, 0x61, 0x78, 0x50, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x34, - 0x0a, 0x15, 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x15, 0x4d, - 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x73, 0x22, 0xea, 0x01, 0x0a, 0x10, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x54, 0x4c, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x45, 0x6e, 0x61, - 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x45, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x64, 0x12, 0x4c, 0x0a, 0x03, 0x53, 0x44, 0x53, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x3a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, - 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x54, 0x4c, 0x53, 0x53, 0x44, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x03, 0x53, 0x44, - 0x53, 0x12, 0x24, 0x0a, 0x0d, 0x54, 0x4c, 0x53, 0x4d, 0x69, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x54, 0x4c, 0x53, 0x4d, 0x69, 0x6e, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x54, 0x4c, 0x53, 0x4d, 0x61, - 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, - 0x54, 0x4c, 0x53, 0x4d, 0x61, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, - 0x0c, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x0c, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, 0x65, - 0x73, 0x22, 0x5b, 0x0a, 0x13, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x54, 0x4c, 0x53, 0x53, - 0x44, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x43, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x43, - 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x43, 0x65, - 0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xdf, - 0x01, 0x0a, 0x0f, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, - 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, - 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, - 0x6f, 0x6c, 0x12, 0x51, 0x0a, 0x08, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, - 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, - 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x67, - 0x72, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x08, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x49, 0x0a, 0x03, 0x54, 0x4c, 0x53, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, - 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, - 0x61, 0x79, 0x54, 0x4c, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x03, 0x54, 0x4c, 0x53, - 0x22, 0xcc, 0x05, 0x0a, 0x0e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x50, 0x0a, - 0x03, 0x54, 0x4c, 0x53, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x68, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, - 0x72, 0x79, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x54, 0x4c, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x03, 0x54, 0x4c, 0x53, 0x12, - 0x62, 0x0a, 0x0e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, - 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, - 0x48, 0x54, 0x54, 0x50, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, - 0x65, 0x72, 0x73, 0x52, 0x0e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x73, 0x12, 0x64, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x68, - 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, - 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, - 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x53, 0x0a, 0x04, 0x4d, 0x65, 0x74, - 0x61, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, - 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, - 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4d, - 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x58, - 0x0a, 0x0e, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, - 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, - 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x0e, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, - 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x26, 0x0a, 0x0e, 0x4d, 0x61, 0x78, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x0e, 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x12, 0x2e, 0x0a, 0x12, 0x4d, 0x61, 0x78, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x4d, 0x61, - 0x78, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, - 0x12, 0x34, 0x0a, 0x15, 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x15, 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, - 0x67, 0x0a, 0x17, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x54, 0x4c, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4c, 0x0a, 0x03, 0x53, 0x44, - 0x53, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, - 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, - 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x54, 0x4c, 0x53, 0x53, 0x44, 0x53, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x52, 0x03, 0x53, 0x44, 0x53, 0x22, 0xcb, 0x02, 0x0a, 0x13, 0x48, 0x54, 0x54, - 0x50, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, - 0x12, 0x55, 0x0a, 0x03, 0x41, 0x64, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, - 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, - 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x03, 0x41, 0x64, 0x64, 0x12, 0x55, 0x0a, 0x03, 0x53, 0x65, 0x74, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, - 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, - 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x48, 0x54, 0x54, - 0x50, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, - 0x2e, 0x53, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x03, 0x53, 0x65, 0x74, 0x12, 0x16, - 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, - 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x1a, 0x36, 0x0a, 0x08, 0x41, 0x64, 0x64, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x36, - 0x0a, 0x08, 0x53, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xf6, 0x01, 0x0a, 0x11, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x50, 0x0a, 0x07, - 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, - 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, - 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x56, - 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x68, - 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, - 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, - 0xa6, 0x06, 0x0a, 0x0f, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x4e, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, - 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, - 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5c, 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x6d, 0x69, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x68, - 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, - 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x65, - 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, - 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x50, 0x72, 0x65, 0x63, 0x65, - 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x49, - 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x49, - 0x44, 0x12, 0x4e, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x3a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, - 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x0a, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x4d, 0x65, 0x74, - 0x61, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, - 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, - 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x0a, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x46, 0x0a, 0x10, 0x4c, - 0x65, 0x67, 0x61, 0x63, 0x79, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x52, 0x10, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, - 0x69, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x10, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x4c, 0x65, 0x67, 0x61, 0x63, - 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x58, 0x0a, 0x0e, 0x45, - 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x0b, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, - 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, - 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x0e, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, - 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x18, 0x0c, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x50, 0x65, 0x65, 0x72, 0x1a, 0x3d, 0x0a, 0x0f, 0x4c, 0x65, 0x67, - 0x61, 0x63, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xb9, 0x01, 0x0a, 0x13, 0x49, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x4e, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, - 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, - 0x6f, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x52, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3e, - 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, - 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, - 0x48, 0x54, 0x54, 0x50, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x04, - 0x48, 0x54, 0x54, 0x50, 0x22, 0xed, 0x01, 0x0a, 0x17, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, - 0x6f, 0x6e, 0x48, 0x54, 0x54, 0x50, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x74, 0x68, 0x45, 0x78, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x74, 0x68, 0x45, 0x78, 0x61, 0x63, 0x74, 0x12, 0x1e, - 0x0a, 0x0a, 0x50, 0x61, 0x74, 0x68, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x50, 0x61, 0x74, 0x68, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x1c, - 0x0a, 0x09, 0x50, 0x61, 0x74, 0x68, 0x52, 0x65, 0x67, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x50, 0x61, 0x74, 0x68, 0x52, 0x65, 0x67, 0x65, 0x78, 0x12, 0x5c, 0x0a, 0x06, - 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x68, - 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, - 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x54, - 0x54, 0x50, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x52, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x65, - 0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x4d, 0x65, 0x74, - 0x68, 0x6f, 0x64, 0x73, 0x22, 0xc1, 0x01, 0x0a, 0x1d, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, - 0x6f, 0x6e, 0x48, 0x54, 0x54, 0x50, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x50, 0x65, 0x72, 0x6d, - 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x72, - 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x50, 0x72, 0x65, - 0x73, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x45, 0x78, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x45, 0x78, 0x61, 0x63, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x72, - 0x65, 0x66, 0x69, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x50, 0x72, 0x65, 0x66, - 0x69, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x75, 0x66, 0x66, 0x69, 0x78, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x53, 0x75, 0x66, 0x66, 0x69, 0x78, 0x12, 0x14, 0x0a, 0x05, 0x52, 0x65, - 0x67, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, - 0x12, 0x16, 0x0a, 0x06, 0x49, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x06, 0x49, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x2a, 0x77, 0x0a, 0x04, 0x4b, 0x69, 0x6e, 0x64, - 0x12, 0x0f, 0x0a, 0x0b, 0x4b, 0x69, 0x6e, 0x64, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, - 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4b, 0x69, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x4b, 0x69, 0x6e, 0x64, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x10, 0x02, 0x12, 0x16, - 0x0a, 0x12, 0x4b, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x47, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x4b, 0x69, 0x6e, 0x64, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x10, - 0x04, 0x2a, 0x26, 0x0a, 0x0f, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x65, 0x6e, 0x79, 0x10, 0x00, 0x12, 0x09, - 0x0a, 0x05, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x10, 0x01, 0x2a, 0x21, 0x0a, 0x13, 0x49, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x10, 0x00, 0x42, 0xa6, 0x02, 0x0a, - 0x29, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, - 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x10, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2f, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, - 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x70, 0x62, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0xa2, - 0x02, 0x04, 0x48, 0x43, 0x49, 0x43, 0xaa, 0x02, 0x25, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, - 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0xca, 0x02, - 0x25, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, - 0x6c, 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5c, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0xe2, 0x02, 0x31, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, - 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x5c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5c, 0x47, - 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x28, 0x48, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, - 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x65, 0x6e, 0x74, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + Protocol string `protobuf:"bytes,1,opt,name=Protocol,proto3" json:"Protocol,omitempty"` + // mog: func-to=proxyModeToStructs func-from=proxyModeFromStructs + Mode ProxyMode `protobuf:"varint,2,opt,name=Mode,proto3,enum=hashicorp.consul.internal.configentry.ProxyMode" json:"Mode,omitempty"` + TransparentProxy *TransparentProxyConfig `protobuf:"bytes,3,opt,name=TransparentProxy,proto3" json:"TransparentProxy,omitempty"` + MeshGateway *MeshGatewayConfig `protobuf:"bytes,4,opt,name=MeshGateway,proto3" json:"MeshGateway,omitempty"` + Expose *ExposeConfig `protobuf:"bytes,5,opt,name=Expose,proto3" json:"Expose,omitempty"` + ExternalSNI string `protobuf:"bytes,6,opt,name=ExternalSNI,proto3" json:"ExternalSNI,omitempty"` + UpstreamConfig *UpstreamConfiguration `protobuf:"bytes,7,opt,name=UpstreamConfig,proto3" json:"UpstreamConfig,omitempty"` + Destination *DestinationConfig `protobuf:"bytes,8,opt,name=Destination,proto3" json:"Destination,omitempty"` + // mog: func-to=int func-from=int32 + MaxInboundConnections int32 `protobuf:"varint,9,opt,name=MaxInboundConnections,proto3" json:"MaxInboundConnections,omitempty"` + // mog: func-to=int func-from=int32 + LocalConnectTimeoutMs int32 `protobuf:"varint,10,opt,name=LocalConnectTimeoutMs,proto3" json:"LocalConnectTimeoutMs,omitempty"` + // mog: func-to=int func-from=int32 + LocalRequestTimeoutMs int32 `protobuf:"varint,11,opt,name=LocalRequestTimeoutMs,proto3" json:"LocalRequestTimeoutMs,omitempty"` + BalanceInboundConnections string `protobuf:"bytes,12,opt,name=BalanceInboundConnections,proto3" json:"BalanceInboundConnections,omitempty"` + Meta map[string]string `protobuf:"bytes,13,rep,name=Meta,proto3" json:"Meta,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } -var ( - file_proto_pbconfigentry_config_entry_proto_rawDescOnce sync.Once - file_proto_pbconfigentry_config_entry_proto_rawDescData = file_proto_pbconfigentry_config_entry_proto_rawDesc -) - -func file_proto_pbconfigentry_config_entry_proto_rawDescGZIP() []byte { - file_proto_pbconfigentry_config_entry_proto_rawDescOnce.Do(func() { - file_proto_pbconfigentry_config_entry_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_pbconfigentry_config_entry_proto_rawDescData) - }) - return file_proto_pbconfigentry_config_entry_proto_rawDescData +func (x *ServiceDefaults) Reset() { + *x = ServiceDefaults{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -var file_proto_pbconfigentry_config_entry_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_proto_pbconfigentry_config_entry_proto_msgTypes = make([]protoimpl.MessageInfo, 40) -var file_proto_pbconfigentry_config_entry_proto_goTypes = []interface{}{ - (Kind)(0), // 0: hashicorp.consul.internal.configentry.Kind - (IntentionAction)(0), // 1: hashicorp.consul.internal.configentry.IntentionAction - (IntentionSourceType)(0), // 2: hashicorp.consul.internal.configentry.IntentionSourceType - (*ConfigEntry)(nil), // 3: hashicorp.consul.internal.configentry.ConfigEntry - (*MeshConfig)(nil), // 4: hashicorp.consul.internal.configentry.MeshConfig - (*TransparentProxyMeshConfig)(nil), // 5: hashicorp.consul.internal.configentry.TransparentProxyMeshConfig - (*MeshTLSConfig)(nil), // 6: hashicorp.consul.internal.configentry.MeshTLSConfig - (*MeshDirectionalTLSConfig)(nil), // 7: hashicorp.consul.internal.configentry.MeshDirectionalTLSConfig - (*MeshHTTPConfig)(nil), // 8: hashicorp.consul.internal.configentry.MeshHTTPConfig - (*PeeringMeshConfig)(nil), // 9: hashicorp.consul.internal.configentry.PeeringMeshConfig - (*ServiceResolver)(nil), // 10: hashicorp.consul.internal.configentry.ServiceResolver - (*ServiceResolverSubset)(nil), // 11: hashicorp.consul.internal.configentry.ServiceResolverSubset - (*ServiceResolverRedirect)(nil), // 12: hashicorp.consul.internal.configentry.ServiceResolverRedirect - (*ServiceResolverFailover)(nil), // 13: hashicorp.consul.internal.configentry.ServiceResolverFailover - (*ServiceResolverFailoverTarget)(nil), // 14: hashicorp.consul.internal.configentry.ServiceResolverFailoverTarget - (*LoadBalancer)(nil), // 15: hashicorp.consul.internal.configentry.LoadBalancer - (*RingHashConfig)(nil), // 16: hashicorp.consul.internal.configentry.RingHashConfig - (*LeastRequestConfig)(nil), // 17: hashicorp.consul.internal.configentry.LeastRequestConfig - (*HashPolicy)(nil), // 18: hashicorp.consul.internal.configentry.HashPolicy - (*CookieConfig)(nil), // 19: hashicorp.consul.internal.configentry.CookieConfig - (*IngressGateway)(nil), // 20: hashicorp.consul.internal.configentry.IngressGateway - (*IngressServiceConfig)(nil), // 21: hashicorp.consul.internal.configentry.IngressServiceConfig - (*GatewayTLSConfig)(nil), // 22: hashicorp.consul.internal.configentry.GatewayTLSConfig - (*GatewayTLSSDSConfig)(nil), // 23: hashicorp.consul.internal.configentry.GatewayTLSSDSConfig - (*IngressListener)(nil), // 24: hashicorp.consul.internal.configentry.IngressListener - (*IngressService)(nil), // 25: hashicorp.consul.internal.configentry.IngressService - (*GatewayServiceTLSConfig)(nil), // 26: hashicorp.consul.internal.configentry.GatewayServiceTLSConfig - (*HTTPHeaderModifiers)(nil), // 27: hashicorp.consul.internal.configentry.HTTPHeaderModifiers - (*ServiceIntentions)(nil), // 28: hashicorp.consul.internal.configentry.ServiceIntentions - (*SourceIntention)(nil), // 29: hashicorp.consul.internal.configentry.SourceIntention - (*IntentionPermission)(nil), // 30: hashicorp.consul.internal.configentry.IntentionPermission - (*IntentionHTTPPermission)(nil), // 31: hashicorp.consul.internal.configentry.IntentionHTTPPermission - (*IntentionHTTPHeaderPermission)(nil), // 32: hashicorp.consul.internal.configentry.IntentionHTTPHeaderPermission - nil, // 33: hashicorp.consul.internal.configentry.MeshConfig.MetaEntry - nil, // 34: hashicorp.consul.internal.configentry.ServiceResolver.SubsetsEntry - nil, // 35: hashicorp.consul.internal.configentry.ServiceResolver.FailoverEntry - nil, // 36: hashicorp.consul.internal.configentry.ServiceResolver.MetaEntry - nil, // 37: hashicorp.consul.internal.configentry.IngressGateway.MetaEntry - nil, // 38: hashicorp.consul.internal.configentry.IngressService.MetaEntry - nil, // 39: hashicorp.consul.internal.configentry.HTTPHeaderModifiers.AddEntry - nil, // 40: hashicorp.consul.internal.configentry.HTTPHeaderModifiers.SetEntry - nil, // 41: hashicorp.consul.internal.configentry.ServiceIntentions.MetaEntry - nil, // 42: hashicorp.consul.internal.configentry.SourceIntention.LegacyMetaEntry - (*pbcommon.EnterpriseMeta)(nil), // 43: hashicorp.consul.internal.common.EnterpriseMeta - (*pbcommon.RaftIndex)(nil), // 44: hashicorp.consul.internal.common.RaftIndex - (*durationpb.Duration)(nil), // 45: google.protobuf.Duration - (*timestamppb.Timestamp)(nil), // 46: google.protobuf.Timestamp -} -var file_proto_pbconfigentry_config_entry_proto_depIdxs = []int32{ - 0, // 0: hashicorp.consul.internal.configentry.ConfigEntry.Kind:type_name -> hashicorp.consul.internal.configentry.Kind - 43, // 1: hashicorp.consul.internal.configentry.ConfigEntry.EnterpriseMeta:type_name -> hashicorp.consul.internal.common.EnterpriseMeta - 44, // 2: hashicorp.consul.internal.configentry.ConfigEntry.RaftIndex:type_name -> hashicorp.consul.internal.common.RaftIndex - 4, // 3: hashicorp.consul.internal.configentry.ConfigEntry.MeshConfig:type_name -> hashicorp.consul.internal.configentry.MeshConfig - 10, // 4: hashicorp.consul.internal.configentry.ConfigEntry.ServiceResolver:type_name -> hashicorp.consul.internal.configentry.ServiceResolver - 20, // 5: hashicorp.consul.internal.configentry.ConfigEntry.IngressGateway:type_name -> hashicorp.consul.internal.configentry.IngressGateway - 28, // 6: hashicorp.consul.internal.configentry.ConfigEntry.ServiceIntentions:type_name -> hashicorp.consul.internal.configentry.ServiceIntentions - 5, // 7: hashicorp.consul.internal.configentry.MeshConfig.TransparentProxy:type_name -> hashicorp.consul.internal.configentry.TransparentProxyMeshConfig - 6, // 8: hashicorp.consul.internal.configentry.MeshConfig.TLS:type_name -> hashicorp.consul.internal.configentry.MeshTLSConfig - 8, // 9: hashicorp.consul.internal.configentry.MeshConfig.HTTP:type_name -> hashicorp.consul.internal.configentry.MeshHTTPConfig - 33, // 10: hashicorp.consul.internal.configentry.MeshConfig.Meta:type_name -> hashicorp.consul.internal.configentry.MeshConfig.MetaEntry - 9, // 11: hashicorp.consul.internal.configentry.MeshConfig.Peering:type_name -> hashicorp.consul.internal.configentry.PeeringMeshConfig - 7, // 12: hashicorp.consul.internal.configentry.MeshTLSConfig.Incoming:type_name -> hashicorp.consul.internal.configentry.MeshDirectionalTLSConfig - 7, // 13: hashicorp.consul.internal.configentry.MeshTLSConfig.Outgoing:type_name -> hashicorp.consul.internal.configentry.MeshDirectionalTLSConfig - 34, // 14: hashicorp.consul.internal.configentry.ServiceResolver.Subsets:type_name -> hashicorp.consul.internal.configentry.ServiceResolver.SubsetsEntry - 12, // 15: hashicorp.consul.internal.configentry.ServiceResolver.Redirect:type_name -> hashicorp.consul.internal.configentry.ServiceResolverRedirect - 35, // 16: hashicorp.consul.internal.configentry.ServiceResolver.Failover:type_name -> hashicorp.consul.internal.configentry.ServiceResolver.FailoverEntry - 45, // 17: hashicorp.consul.internal.configentry.ServiceResolver.ConnectTimeout:type_name -> google.protobuf.Duration - 15, // 18: hashicorp.consul.internal.configentry.ServiceResolver.LoadBalancer:type_name -> hashicorp.consul.internal.configentry.LoadBalancer - 36, // 19: hashicorp.consul.internal.configentry.ServiceResolver.Meta:type_name -> hashicorp.consul.internal.configentry.ServiceResolver.MetaEntry - 14, // 20: hashicorp.consul.internal.configentry.ServiceResolverFailover.Targets:type_name -> hashicorp.consul.internal.configentry.ServiceResolverFailoverTarget - 16, // 21: hashicorp.consul.internal.configentry.LoadBalancer.RingHashConfig:type_name -> hashicorp.consul.internal.configentry.RingHashConfig - 17, // 22: hashicorp.consul.internal.configentry.LoadBalancer.LeastRequestConfig:type_name -> hashicorp.consul.internal.configentry.LeastRequestConfig - 18, // 23: hashicorp.consul.internal.configentry.LoadBalancer.HashPolicies:type_name -> hashicorp.consul.internal.configentry.HashPolicy - 19, // 24: hashicorp.consul.internal.configentry.HashPolicy.CookieConfig:type_name -> hashicorp.consul.internal.configentry.CookieConfig - 45, // 25: hashicorp.consul.internal.configentry.CookieConfig.TTL:type_name -> google.protobuf.Duration - 22, // 26: hashicorp.consul.internal.configentry.IngressGateway.TLS:type_name -> hashicorp.consul.internal.configentry.GatewayTLSConfig - 24, // 27: hashicorp.consul.internal.configentry.IngressGateway.Listeners:type_name -> hashicorp.consul.internal.configentry.IngressListener - 37, // 28: hashicorp.consul.internal.configentry.IngressGateway.Meta:type_name -> hashicorp.consul.internal.configentry.IngressGateway.MetaEntry - 21, // 29: hashicorp.consul.internal.configentry.IngressGateway.Defaults:type_name -> hashicorp.consul.internal.configentry.IngressServiceConfig - 23, // 30: hashicorp.consul.internal.configentry.GatewayTLSConfig.SDS:type_name -> hashicorp.consul.internal.configentry.GatewayTLSSDSConfig - 25, // 31: hashicorp.consul.internal.configentry.IngressListener.Services:type_name -> hashicorp.consul.internal.configentry.IngressService - 22, // 32: hashicorp.consul.internal.configentry.IngressListener.TLS:type_name -> hashicorp.consul.internal.configentry.GatewayTLSConfig - 26, // 33: hashicorp.consul.internal.configentry.IngressService.TLS:type_name -> hashicorp.consul.internal.configentry.GatewayServiceTLSConfig - 27, // 34: hashicorp.consul.internal.configentry.IngressService.RequestHeaders:type_name -> hashicorp.consul.internal.configentry.HTTPHeaderModifiers - 27, // 35: hashicorp.consul.internal.configentry.IngressService.ResponseHeaders:type_name -> hashicorp.consul.internal.configentry.HTTPHeaderModifiers - 38, // 36: hashicorp.consul.internal.configentry.IngressService.Meta:type_name -> hashicorp.consul.internal.configentry.IngressService.MetaEntry - 43, // 37: hashicorp.consul.internal.configentry.IngressService.EnterpriseMeta:type_name -> hashicorp.consul.internal.common.EnterpriseMeta - 23, // 38: hashicorp.consul.internal.configentry.GatewayServiceTLSConfig.SDS:type_name -> hashicorp.consul.internal.configentry.GatewayTLSSDSConfig - 39, // 39: hashicorp.consul.internal.configentry.HTTPHeaderModifiers.Add:type_name -> hashicorp.consul.internal.configentry.HTTPHeaderModifiers.AddEntry - 40, // 40: hashicorp.consul.internal.configentry.HTTPHeaderModifiers.Set:type_name -> hashicorp.consul.internal.configentry.HTTPHeaderModifiers.SetEntry - 29, // 41: hashicorp.consul.internal.configentry.ServiceIntentions.Sources:type_name -> hashicorp.consul.internal.configentry.SourceIntention - 41, // 42: hashicorp.consul.internal.configentry.ServiceIntentions.Meta:type_name -> hashicorp.consul.internal.configentry.ServiceIntentions.MetaEntry - 1, // 43: hashicorp.consul.internal.configentry.SourceIntention.Action:type_name -> hashicorp.consul.internal.configentry.IntentionAction - 30, // 44: hashicorp.consul.internal.configentry.SourceIntention.Permissions:type_name -> hashicorp.consul.internal.configentry.IntentionPermission - 2, // 45: hashicorp.consul.internal.configentry.SourceIntention.Type:type_name -> hashicorp.consul.internal.configentry.IntentionSourceType - 42, // 46: hashicorp.consul.internal.configentry.SourceIntention.LegacyMeta:type_name -> hashicorp.consul.internal.configentry.SourceIntention.LegacyMetaEntry - 46, // 47: hashicorp.consul.internal.configentry.SourceIntention.LegacyCreateTime:type_name -> google.protobuf.Timestamp - 46, // 48: hashicorp.consul.internal.configentry.SourceIntention.LegacyUpdateTime:type_name -> google.protobuf.Timestamp - 43, // 49: hashicorp.consul.internal.configentry.SourceIntention.EnterpriseMeta:type_name -> hashicorp.consul.internal.common.EnterpriseMeta - 1, // 50: hashicorp.consul.internal.configentry.IntentionPermission.Action:type_name -> hashicorp.consul.internal.configentry.IntentionAction - 31, // 51: hashicorp.consul.internal.configentry.IntentionPermission.HTTP:type_name -> hashicorp.consul.internal.configentry.IntentionHTTPPermission - 32, // 52: hashicorp.consul.internal.configentry.IntentionHTTPPermission.Header:type_name -> hashicorp.consul.internal.configentry.IntentionHTTPHeaderPermission - 11, // 53: hashicorp.consul.internal.configentry.ServiceResolver.SubsetsEntry.value:type_name -> hashicorp.consul.internal.configentry.ServiceResolverSubset - 13, // 54: hashicorp.consul.internal.configentry.ServiceResolver.FailoverEntry.value:type_name -> hashicorp.consul.internal.configentry.ServiceResolverFailover - 55, // [55:55] is the sub-list for method output_type - 55, // [55:55] is the sub-list for method input_type - 55, // [55:55] is the sub-list for extension type_name - 55, // [55:55] is the sub-list for extension extendee - 0, // [0:55] is the sub-list for field type_name +func (x *ServiceDefaults) String() string { + return protoimpl.X.MessageStringOf(x) } -func init() { file_proto_pbconfigentry_config_entry_proto_init() } -func file_proto_pbconfigentry_config_entry_proto_init() { +func (*ServiceDefaults) ProtoMessage() {} + +func (x *ServiceDefaults) ProtoReflect() protoreflect.Message { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServiceDefaults.ProtoReflect.Descriptor instead. +func (*ServiceDefaults) Descriptor() ([]byte, []int) { + return file_proto_pbconfigentry_config_entry_proto_rawDescGZIP(), []int{30} +} + +func (x *ServiceDefaults) GetProtocol() string { + if x != nil { + return x.Protocol + } + return "" +} + +func (x *ServiceDefaults) GetMode() ProxyMode { + if x != nil { + return x.Mode + } + return ProxyMode_ProxyModeDefault +} + +func (x *ServiceDefaults) GetTransparentProxy() *TransparentProxyConfig { + if x != nil { + return x.TransparentProxy + } + return nil +} + +func (x *ServiceDefaults) GetMeshGateway() *MeshGatewayConfig { + if x != nil { + return x.MeshGateway + } + return nil +} + +func (x *ServiceDefaults) GetExpose() *ExposeConfig { + if x != nil { + return x.Expose + } + return nil +} + +func (x *ServiceDefaults) GetExternalSNI() string { + if x != nil { + return x.ExternalSNI + } + return "" +} + +func (x *ServiceDefaults) GetUpstreamConfig() *UpstreamConfiguration { + if x != nil { + return x.UpstreamConfig + } + return nil +} + +func (x *ServiceDefaults) GetDestination() *DestinationConfig { + if x != nil { + return x.Destination + } + return nil +} + +func (x *ServiceDefaults) GetMaxInboundConnections() int32 { + if x != nil { + return x.MaxInboundConnections + } + return 0 +} + +func (x *ServiceDefaults) GetLocalConnectTimeoutMs() int32 { + if x != nil { + return x.LocalConnectTimeoutMs + } + return 0 +} + +func (x *ServiceDefaults) GetLocalRequestTimeoutMs() int32 { + if x != nil { + return x.LocalRequestTimeoutMs + } + return 0 +} + +func (x *ServiceDefaults) GetBalanceInboundConnections() string { + if x != nil { + return x.BalanceInboundConnections + } + return "" +} + +func (x *ServiceDefaults) GetMeta() map[string]string { + if x != nil { + return x.Meta + } + return nil +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.TransparentProxyConfig +// output=config_entry.gen.go +// name=Structs +type TransparentProxyConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // mog: func-to=int func-from=int32 + OutboundListenerPort int32 `protobuf:"varint,1,opt,name=OutboundListenerPort,proto3" json:"OutboundListenerPort,omitempty"` + DialedDirectly bool `protobuf:"varint,2,opt,name=DialedDirectly,proto3" json:"DialedDirectly,omitempty"` +} + +func (x *TransparentProxyConfig) Reset() { + *x = TransparentProxyConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TransparentProxyConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TransparentProxyConfig) ProtoMessage() {} + +func (x *TransparentProxyConfig) ProtoReflect() protoreflect.Message { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TransparentProxyConfig.ProtoReflect.Descriptor instead. +func (*TransparentProxyConfig) Descriptor() ([]byte, []int) { + return file_proto_pbconfigentry_config_entry_proto_rawDescGZIP(), []int{31} +} + +func (x *TransparentProxyConfig) GetOutboundListenerPort() int32 { + if x != nil { + return x.OutboundListenerPort + } + return 0 +} + +func (x *TransparentProxyConfig) GetDialedDirectly() bool { + if x != nil { + return x.DialedDirectly + } + return false +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.MeshGatewayConfig +// output=config_entry.gen.go +// name=Structs +type MeshGatewayConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // mog: func-to=meshGatewayModeToStructs func-from=meshGatewayModeFromStructs + Mode MeshGatewayMode `protobuf:"varint,1,opt,name=Mode,proto3,enum=hashicorp.consul.internal.configentry.MeshGatewayMode" json:"Mode,omitempty"` +} + +func (x *MeshGatewayConfig) Reset() { + *x = MeshGatewayConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MeshGatewayConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MeshGatewayConfig) ProtoMessage() {} + +func (x *MeshGatewayConfig) ProtoReflect() protoreflect.Message { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MeshGatewayConfig.ProtoReflect.Descriptor instead. +func (*MeshGatewayConfig) Descriptor() ([]byte, []int) { + return file_proto_pbconfigentry_config_entry_proto_rawDescGZIP(), []int{32} +} + +func (x *MeshGatewayConfig) GetMode() MeshGatewayMode { + if x != nil { + return x.Mode + } + return MeshGatewayMode_MeshGatewayModeDefault +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.ExposeConfig +// output=config_entry.gen.go +// name=Structs +type ExposeConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Checks bool `protobuf:"varint,1,opt,name=Checks,proto3" json:"Checks,omitempty"` + Paths []*ExposePath `protobuf:"bytes,2,rep,name=Paths,proto3" json:"Paths,omitempty"` +} + +func (x *ExposeConfig) Reset() { + *x = ExposeConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExposeConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExposeConfig) ProtoMessage() {} + +func (x *ExposeConfig) ProtoReflect() protoreflect.Message { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExposeConfig.ProtoReflect.Descriptor instead. +func (*ExposeConfig) Descriptor() ([]byte, []int) { + return file_proto_pbconfigentry_config_entry_proto_rawDescGZIP(), []int{33} +} + +func (x *ExposeConfig) GetChecks() bool { + if x != nil { + return x.Checks + } + return false +} + +func (x *ExposeConfig) GetPaths() []*ExposePath { + if x != nil { + return x.Paths + } + return nil +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.ExposePath +// output=config_entry.gen.go +// name=Structs +type ExposePath struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // mog: func-to=int func-from=int32 + ListenerPort int32 `protobuf:"varint,1,opt,name=ListenerPort,proto3" json:"ListenerPort,omitempty"` + Path string `protobuf:"bytes,2,opt,name=Path,proto3" json:"Path,omitempty"` + // mog: func-to=int func-from=int32 + LocalPathPort int32 `protobuf:"varint,3,opt,name=LocalPathPort,proto3" json:"LocalPathPort,omitempty"` + Protocol string `protobuf:"bytes,4,opt,name=Protocol,proto3" json:"Protocol,omitempty"` + ParsedFromCheck bool `protobuf:"varint,5,opt,name=ParsedFromCheck,proto3" json:"ParsedFromCheck,omitempty"` +} + +func (x *ExposePath) Reset() { + *x = ExposePath{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExposePath) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExposePath) ProtoMessage() {} + +func (x *ExposePath) ProtoReflect() protoreflect.Message { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[34] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExposePath.ProtoReflect.Descriptor instead. +func (*ExposePath) Descriptor() ([]byte, []int) { + return file_proto_pbconfigentry_config_entry_proto_rawDescGZIP(), []int{34} +} + +func (x *ExposePath) GetListenerPort() int32 { + if x != nil { + return x.ListenerPort + } + return 0 +} + +func (x *ExposePath) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +func (x *ExposePath) GetLocalPathPort() int32 { + if x != nil { + return x.LocalPathPort + } + return 0 +} + +func (x *ExposePath) GetProtocol() string { + if x != nil { + return x.Protocol + } + return "" +} + +func (x *ExposePath) GetParsedFromCheck() bool { + if x != nil { + return x.ParsedFromCheck + } + return false +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.UpstreamConfiguration +// output=config_entry.gen.go +// name=Structs +type UpstreamConfiguration struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Overrides []*UpstreamConfig `protobuf:"bytes,1,rep,name=Overrides,proto3" json:"Overrides,omitempty"` + Defaults *UpstreamConfig `protobuf:"bytes,2,opt,name=Defaults,proto3" json:"Defaults,omitempty"` +} + +func (x *UpstreamConfiguration) Reset() { + *x = UpstreamConfiguration{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpstreamConfiguration) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpstreamConfiguration) ProtoMessage() {} + +func (x *UpstreamConfiguration) ProtoReflect() protoreflect.Message { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[35] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpstreamConfiguration.ProtoReflect.Descriptor instead. +func (*UpstreamConfiguration) Descriptor() ([]byte, []int) { + return file_proto_pbconfigentry_config_entry_proto_rawDescGZIP(), []int{35} +} + +func (x *UpstreamConfiguration) GetOverrides() []*UpstreamConfig { + if x != nil { + return x.Overrides + } + return nil +} + +func (x *UpstreamConfiguration) GetDefaults() *UpstreamConfig { + if x != nil { + return x.Defaults + } + return nil +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.UpstreamConfig +// output=config_entry.gen.go +// name=Structs +type UpstreamConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` + // mog: func-to=enterpriseMetaToStructs func-from=enterpriseMetaFromStructs + EnterpriseMeta *pbcommon.EnterpriseMeta `protobuf:"bytes,2,opt,name=EnterpriseMeta,proto3" json:"EnterpriseMeta,omitempty"` + EnvoyListenerJSON string `protobuf:"bytes,3,opt,name=EnvoyListenerJSON,proto3" json:"EnvoyListenerJSON,omitempty"` + EnvoyClusterJSON string `protobuf:"bytes,4,opt,name=EnvoyClusterJSON,proto3" json:"EnvoyClusterJSON,omitempty"` + Protocol string `protobuf:"bytes,5,opt,name=Protocol,proto3" json:"Protocol,omitempty"` + // mog: func-to=int func-from=int32 + ConnectTimeoutMs int32 `protobuf:"varint,6,opt,name=ConnectTimeoutMs,proto3" json:"ConnectTimeoutMs,omitempty"` + Limits *UpstreamLimits `protobuf:"bytes,7,opt,name=Limits,proto3" json:"Limits,omitempty"` + PassiveHealthCheck *PassiveHealthCheck `protobuf:"bytes,8,opt,name=PassiveHealthCheck,proto3" json:"PassiveHealthCheck,omitempty"` + MeshGateway *MeshGatewayConfig `protobuf:"bytes,9,opt,name=MeshGateway,proto3" json:"MeshGateway,omitempty"` + BalanceOutboundConnections string `protobuf:"bytes,10,opt,name=BalanceOutboundConnections,proto3" json:"BalanceOutboundConnections,omitempty"` +} + +func (x *UpstreamConfig) Reset() { + *x = UpstreamConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpstreamConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpstreamConfig) ProtoMessage() {} + +func (x *UpstreamConfig) ProtoReflect() protoreflect.Message { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[36] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpstreamConfig.ProtoReflect.Descriptor instead. +func (*UpstreamConfig) Descriptor() ([]byte, []int) { + return file_proto_pbconfigentry_config_entry_proto_rawDescGZIP(), []int{36} +} + +func (x *UpstreamConfig) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *UpstreamConfig) GetEnterpriseMeta() *pbcommon.EnterpriseMeta { + if x != nil { + return x.EnterpriseMeta + } + return nil +} + +func (x *UpstreamConfig) GetEnvoyListenerJSON() string { + if x != nil { + return x.EnvoyListenerJSON + } + return "" +} + +func (x *UpstreamConfig) GetEnvoyClusterJSON() string { + if x != nil { + return x.EnvoyClusterJSON + } + return "" +} + +func (x *UpstreamConfig) GetProtocol() string { + if x != nil { + return x.Protocol + } + return "" +} + +func (x *UpstreamConfig) GetConnectTimeoutMs() int32 { + if x != nil { + return x.ConnectTimeoutMs + } + return 0 +} + +func (x *UpstreamConfig) GetLimits() *UpstreamLimits { + if x != nil { + return x.Limits + } + return nil +} + +func (x *UpstreamConfig) GetPassiveHealthCheck() *PassiveHealthCheck { + if x != nil { + return x.PassiveHealthCheck + } + return nil +} + +func (x *UpstreamConfig) GetMeshGateway() *MeshGatewayConfig { + if x != nil { + return x.MeshGateway + } + return nil +} + +func (x *UpstreamConfig) GetBalanceOutboundConnections() string { + if x != nil { + return x.BalanceOutboundConnections + } + return "" +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.UpstreamLimits +// output=config_entry.gen.go +// name=Structs +type UpstreamLimits struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // mog: func-to=pointerToIntFromInt32 func-from=int32FromPointerToInt + MaxConnections int32 `protobuf:"varint,1,opt,name=MaxConnections,proto3" json:"MaxConnections,omitempty"` + // mog: func-to=pointerToIntFromInt32 func-from=int32FromPointerToInt + MaxPendingRequests int32 `protobuf:"varint,2,opt,name=MaxPendingRequests,proto3" json:"MaxPendingRequests,omitempty"` + // mog: func-to=pointerToIntFromInt32 func-from=int32FromPointerToInt + MaxConcurrentRequests int32 `protobuf:"varint,3,opt,name=MaxConcurrentRequests,proto3" json:"MaxConcurrentRequests,omitempty"` +} + +func (x *UpstreamLimits) Reset() { + *x = UpstreamLimits{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpstreamLimits) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpstreamLimits) ProtoMessage() {} + +func (x *UpstreamLimits) ProtoReflect() protoreflect.Message { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[37] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpstreamLimits.ProtoReflect.Descriptor instead. +func (*UpstreamLimits) Descriptor() ([]byte, []int) { + return file_proto_pbconfigentry_config_entry_proto_rawDescGZIP(), []int{37} +} + +func (x *UpstreamLimits) GetMaxConnections() int32 { + if x != nil { + return x.MaxConnections + } + return 0 +} + +func (x *UpstreamLimits) GetMaxPendingRequests() int32 { + if x != nil { + return x.MaxPendingRequests + } + return 0 +} + +func (x *UpstreamLimits) GetMaxConcurrentRequests() int32 { + if x != nil { + return x.MaxConcurrentRequests + } + return 0 +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.PassiveHealthCheck +// output=config_entry.gen.go +// name=Structs +type PassiveHealthCheck struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto + Interval *durationpb.Duration `protobuf:"bytes,1,opt,name=Interval,proto3" json:"Interval,omitempty"` + MaxFailures uint32 `protobuf:"varint,2,opt,name=MaxFailures,proto3" json:"MaxFailures,omitempty"` + // mog: target=EnforcingConsecutive5xx func-to=pointerToUint32FromUint32 func-from=uint32FromPointerToUint32 + EnforcingConsecutive5Xx uint32 `protobuf:"varint,3,opt,name=EnforcingConsecutive5xx,proto3" json:"EnforcingConsecutive5xx,omitempty"` + // mog: func-to=pointerToUint32FromUint32 func-from=uint32FromPointerToUint32 + MaxEjectionPercent uint32 `protobuf:"varint,4,opt,name=MaxEjectionPercent,proto3" json:"MaxEjectionPercent,omitempty"` + // mog: func-to=structs.DurationPointerFromProto func-from=structs.DurationPointerToProto + BaseEjectionTime *durationpb.Duration `protobuf:"bytes,5,opt,name=BaseEjectionTime,proto3" json:"BaseEjectionTime,omitempty"` +} + +func (x *PassiveHealthCheck) Reset() { + *x = PassiveHealthCheck{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PassiveHealthCheck) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PassiveHealthCheck) ProtoMessage() {} + +func (x *PassiveHealthCheck) ProtoReflect() protoreflect.Message { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[38] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PassiveHealthCheck.ProtoReflect.Descriptor instead. +func (*PassiveHealthCheck) Descriptor() ([]byte, []int) { + return file_proto_pbconfigentry_config_entry_proto_rawDescGZIP(), []int{38} +} + +func (x *PassiveHealthCheck) GetInterval() *durationpb.Duration { + if x != nil { + return x.Interval + } + return nil +} + +func (x *PassiveHealthCheck) GetMaxFailures() uint32 { + if x != nil { + return x.MaxFailures + } + return 0 +} + +func (x *PassiveHealthCheck) GetEnforcingConsecutive5Xx() uint32 { + if x != nil { + return x.EnforcingConsecutive5Xx + } + return 0 +} + +func (x *PassiveHealthCheck) GetMaxEjectionPercent() uint32 { + if x != nil { + return x.MaxEjectionPercent + } + return 0 +} + +func (x *PassiveHealthCheck) GetBaseEjectionTime() *durationpb.Duration { + if x != nil { + return x.BaseEjectionTime + } + return nil +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.DestinationConfig +// output=config_entry.gen.go +// name=Structs +type DestinationConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Addresses []string `protobuf:"bytes,1,rep,name=Addresses,proto3" json:"Addresses,omitempty"` + // mog: func-to=int func-from=int32 + Port int32 `protobuf:"varint,2,opt,name=Port,proto3" json:"Port,omitempty"` +} + +func (x *DestinationConfig) Reset() { + *x = DestinationConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DestinationConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DestinationConfig) ProtoMessage() {} + +func (x *DestinationConfig) ProtoReflect() protoreflect.Message { + mi := &file_proto_pbconfigentry_config_entry_proto_msgTypes[39] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DestinationConfig.ProtoReflect.Descriptor instead. +func (*DestinationConfig) Descriptor() ([]byte, []int) { + return file_proto_pbconfigentry_config_entry_proto_rawDescGZIP(), []int{39} +} + +func (x *DestinationConfig) GetAddresses() []string { + if x != nil { + return x.Addresses + } + return nil +} + +func (x *DestinationConfig) GetPort() int32 { + if x != nil { + return x.Port + } + return 0 +} + +var File_proto_pbconfigentry_config_entry_proto protoreflect.FileDescriptor + +var file_proto_pbconfigentry_config_entry_proto_rawDesc = []byte{ + 0x0a, 0x26, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x25, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x1a, + 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x1a, 0x1b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf8, 0x05, + 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x3f, 0x0a, + 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x68, 0x61, + 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, + 0x74, 0x72, 0x79, 0x2e, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x58, 0x0a, 0x0e, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, + 0x4d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x68, 0x61, 0x73, + 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6e, + 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x0e, 0x45, 0x6e, + 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x49, 0x0a, 0x09, + 0x52, 0x61, 0x66, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2b, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, + 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x52, 0x61, 0x66, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x09, 0x52, 0x61, + 0x66, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x53, 0x0a, 0x0a, 0x4d, 0x65, 0x73, 0x68, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x68, 0x61, + 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, + 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, + 0x52, 0x0a, 0x4d, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x62, 0x0a, 0x0f, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, + 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x48, 0x00, 0x52, + 0x0f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, + 0x12, 0x5f, 0x0a, 0x0e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x47, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x2e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x48, + 0x00, 0x52, 0x0e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x12, 0x68, 0x0a, 0x11, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x68, + 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, + 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x11, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x62, 0x0a, 0x0f, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, + 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x48, 0x00, 0x52, 0x0f, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x42, + 0x07, 0x0a, 0x05, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xec, 0x03, 0x0a, 0x0a, 0x4d, 0x65, 0x73, + 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x6d, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x41, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, + 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, 0x65, 0x73, 0x68, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x12, 0x46, 0x0a, 0x03, 0x54, 0x4c, 0x53, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, + 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x65, 0x73, 0x68, + 0x54, 0x4c, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x03, 0x54, 0x4c, 0x53, 0x12, 0x49, + 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, + 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, + 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x65, 0x73, 0x68, 0x48, 0x54, 0x54, 0x50, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x52, 0x04, 0x48, 0x54, 0x54, 0x50, 0x12, 0x4f, 0x0a, 0x04, 0x4d, 0x65, 0x74, + 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, + 0x4d, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x52, 0x0a, 0x07, 0x50, 0x65, + 0x65, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x68, 0x61, + 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, + 0x74, 0x72, 0x79, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x68, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x1a, 0x37, + 0x0a, 0x09, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x50, 0x0a, 0x1a, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, 0x65, 0x73, 0x68, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x32, 0x0a, 0x14, 0x4d, 0x65, 0x73, 0x68, 0x44, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x14, 0x4d, 0x65, 0x73, 0x68, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0xc9, 0x01, 0x0a, 0x0d, 0x4d, 0x65, + 0x73, 0x68, 0x54, 0x4c, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x5b, 0x0a, 0x08, 0x49, + 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, + 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x65, 0x73, 0x68, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x4c, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, + 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x12, 0x5b, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x67, + 0x6f, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x68, 0x61, 0x73, + 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2e, 0x4d, 0x65, 0x73, 0x68, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x54, 0x4c, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x4f, 0x75, 0x74, + 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x22, 0x8a, 0x01, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x68, 0x44, 0x69, + 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x4c, 0x53, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x24, 0x0a, 0x0d, 0x54, 0x4c, 0x53, 0x4d, 0x69, 0x6e, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x54, 0x4c, 0x53, 0x4d, 0x69, + 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x54, 0x4c, 0x53, 0x4d, + 0x61, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0d, 0x54, 0x4c, 0x53, 0x4d, 0x61, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, + 0x0a, 0x0c, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, + 0x65, 0x73, 0x22, 0x54, 0x0a, 0x0e, 0x4d, 0x65, 0x73, 0x68, 0x48, 0x54, 0x54, 0x50, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x42, 0x0a, 0x1c, 0x53, 0x61, 0x6e, 0x69, 0x74, 0x69, 0x7a, 0x65, + 0x58, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x64, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x43, 0x65, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x53, 0x61, 0x6e, 0x69, + 0x74, 0x69, 0x7a, 0x65, 0x58, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x64, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x43, 0x65, 0x72, 0x74, 0x22, 0x4d, 0x0a, 0x11, 0x50, 0x65, 0x65, 0x72, + 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x38, 0x0a, + 0x17, 0x50, 0x65, 0x65, 0x72, 0x54, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x4d, 0x65, 0x73, 0x68, + 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, + 0x50, 0x65, 0x65, 0x72, 0x54, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x4d, 0x65, 0x73, 0x68, 0x47, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x22, 0xb9, 0x07, 0x0a, 0x0f, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0d, 0x44, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0d, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x75, 0x62, 0x73, 0x65, + 0x74, 0x12, 0x5d, 0x0a, 0x07, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, + 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x65, + 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x73, + 0x12, 0x5a, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, + 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, + 0x63, 0x74, 0x52, 0x08, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x12, 0x60, 0x0a, 0x08, + 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, + 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, + 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, + 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x41, + 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x0e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, + 0x74, 0x12, 0x57, 0x0a, 0x0c, 0x4c, 0x6f, 0x61, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, + 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, + 0x4c, 0x6f, 0x61, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x52, 0x0c, 0x4c, 0x6f, + 0x61, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x12, 0x54, 0x0a, 0x04, 0x4d, 0x65, + 0x74, 0x61, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, + 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, + 0x12, 0x41, 0x0a, 0x0e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, + 0x75, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x0e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x69, 0x6d, 0x65, + 0x6f, 0x75, 0x74, 0x1a, 0x78, 0x0a, 0x0c, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x52, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, + 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x53, 0x75, 0x62, 0x73, + 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x7b, 0x0a, + 0x0d, 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x54, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x3e, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, + 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, + 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, + 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x22, 0x51, 0x0a, 0x15, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, + 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, + 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x46, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x6e, 0x6c, 0x79, 0x50, 0x61, 0x73, 0x73, + 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x4f, 0x6e, 0x6c, 0x79, 0x50, + 0x61, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x22, 0xc9, 0x01, 0x0a, 0x17, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, + 0x63, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x24, 0x0a, 0x0d, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, + 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, + 0x0a, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x12, + 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x50, 0x65, + 0x65, 0x72, 0x22, 0xf9, 0x01, 0x0a, 0x17, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, + 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x18, + 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x12, 0x1c, + 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0b, + 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0b, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x12, 0x5e, + 0x0a, 0x07, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x44, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, + 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, + 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x54, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x07, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x22, 0xcf, + 0x01, 0x0a, 0x1d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, + 0x65, 0x72, 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x12, 0x18, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, + 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, + 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x0a, + 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, + 0x50, 0x65, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x50, 0x65, 0x65, 0x72, + 0x22, 0xc7, 0x02, 0x0a, 0x0c, 0x4c, 0x6f, 0x61, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, + 0x72, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x5d, 0x0a, 0x0e, 0x52, 0x69, 0x6e, + 0x67, 0x48, 0x61, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, + 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x52, 0x69, 0x6e, 0x67, 0x48, 0x61, + 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x52, 0x69, 0x6e, 0x67, 0x48, 0x61, + 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x69, 0x0a, 0x12, 0x4c, 0x65, 0x61, 0x73, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, + 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x65, 0x61, + 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x12, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x12, 0x55, 0x0a, 0x0c, 0x48, 0x61, 0x73, 0x68, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x68, 0x61, 0x73, 0x68, + 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0c, 0x48, 0x61, + 0x73, 0x68, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x22, 0x64, 0x0a, 0x0e, 0x52, 0x69, + 0x6e, 0x67, 0x48, 0x61, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x28, 0x0a, 0x0f, + 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x52, 0x69, 0x6e, 0x67, 0x53, 0x69, 0x7a, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x52, 0x69, + 0x6e, 0x67, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, + 0x6d, 0x52, 0x69, 0x6e, 0x67, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0f, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x52, 0x69, 0x6e, 0x67, 0x53, 0x69, 0x7a, 0x65, + 0x22, 0x36, 0x0a, 0x12, 0x4c, 0x65, 0x61, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x43, 0x68, 0x6f, 0x69, 0x63, 0x65, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x43, 0x68, 0x6f, + 0x69, 0x63, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xd3, 0x01, 0x0a, 0x0a, 0x48, 0x61, 0x73, + 0x68, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x46, 0x69, 0x65, 0x6c, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x1e, 0x0a, + 0x0a, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x57, 0x0a, + 0x0c, 0x43, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, + 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6f, 0x6b, + 0x69, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0c, 0x43, 0x6f, 0x6f, 0x6b, 0x69, 0x65, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x49, 0x50, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x49, 0x50, 0x12, 0x1a, 0x0a, 0x08, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x22, 0x69, + 0x0a, 0x0c, 0x43, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, + 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x03, 0x54, 0x54, 0x4c, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x50, 0x61, 0x74, 0x68, 0x22, 0x98, 0x03, 0x0a, 0x0e, 0x49, 0x6e, + 0x67, 0x72, 0x65, 0x73, 0x73, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x49, 0x0a, 0x03, + 0x54, 0x4c, 0x53, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, + 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x54, 0x4c, 0x53, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x03, 0x54, 0x4c, 0x53, 0x12, 0x54, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x65, + 0x6e, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x68, 0x61, 0x73, + 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, + 0x65, 0x72, 0x52, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x53, 0x0a, + 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x68, 0x61, + 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, + 0x74, 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x47, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x4d, 0x65, + 0x74, 0x61, 0x12, 0x57, 0x0a, 0x08, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, + 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x67, + 0x72, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x52, 0x08, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x1a, 0x37, 0x0a, 0x09, 0x4d, + 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa4, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x26, 0x0a, + 0x0e, 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x4d, 0x61, 0x78, 0x50, 0x65, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x12, 0x4d, 0x61, 0x78, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x34, 0x0a, 0x15, 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x15, 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x22, 0xea, 0x01, 0x0a, 0x10, + 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x54, 0x4c, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x12, 0x18, 0x0a, 0x07, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x07, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x4c, 0x0a, 0x03, 0x53, 0x44, + 0x53, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, + 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x54, 0x4c, 0x53, 0x53, 0x44, 0x53, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x52, 0x03, 0x53, 0x44, 0x53, 0x12, 0x24, 0x0a, 0x0d, 0x54, 0x4c, 0x53, 0x4d, + 0x69, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0d, 0x54, 0x4c, 0x53, 0x4d, 0x69, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, + 0x0a, 0x0d, 0x54, 0x4c, 0x53, 0x4d, 0x61, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x54, 0x4c, 0x53, 0x4d, 0x61, 0x78, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, + 0x69, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x43, 0x69, 0x70, 0x68, + 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73, 0x22, 0x5b, 0x0a, 0x13, 0x47, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x54, 0x4c, 0x53, 0x53, 0x44, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, + 0x20, 0x0a, 0x0b, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xdf, 0x01, 0x0a, 0x0f, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, + 0x73, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x6f, 0x72, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1a, 0x0a, + 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x51, 0x0a, 0x08, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, 0x61, + 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, + 0x74, 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x52, 0x08, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x49, 0x0a, 0x03, + 0x54, 0x4c, 0x53, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, + 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x54, 0x4c, 0x53, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x03, 0x54, 0x4c, 0x53, 0x22, 0xcc, 0x05, 0x0a, 0x0e, 0x49, 0x6e, 0x67, 0x72, + 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x48, + 0x6f, 0x73, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x03, 0x54, 0x4c, 0x53, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x3e, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, + 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x4c, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x52, 0x03, 0x54, 0x4c, 0x53, 0x12, 0x62, 0x0a, 0x0e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, + 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, + 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x64, 0x0a, 0x0f, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, + 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x48, 0x54, 0x54, 0x50, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, + 0x0f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, + 0x12, 0x53, 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, + 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, + 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x04, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x58, 0x0a, 0x0e, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, + 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, + 0x0e, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, + 0x26, 0x0a, 0x0e, 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x4d, 0x61, 0x78, 0x50, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x12, 0x4d, 0x61, 0x78, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x34, 0x0a, 0x15, 0x4d, 0x61, 0x78, 0x43, 0x6f, + 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x15, 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x63, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x1a, 0x37, 0x0a, + 0x09, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x67, 0x0a, 0x17, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x4c, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x12, 0x4c, 0x0a, 0x03, 0x53, 0x44, 0x53, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, + 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, + 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x54, 0x4c, + 0x53, 0x53, 0x44, 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x03, 0x53, 0x44, 0x53, 0x22, + 0xcb, 0x02, 0x0a, 0x13, 0x48, 0x54, 0x54, 0x50, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x6f, + 0x64, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x12, 0x55, 0x0a, 0x03, 0x41, 0x64, 0x64, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, + 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x48, 0x54, 0x54, + 0x50, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, + 0x2e, 0x41, 0x64, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x03, 0x41, 0x64, 0x64, 0x12, 0x55, + 0x0a, 0x03, 0x53, 0x65, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x68, 0x61, + 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, + 0x74, 0x72, 0x79, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x6f, + 0x64, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x2e, 0x53, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x03, 0x53, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x1a, 0x36, 0x0a, + 0x08, 0x41, 0x64, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x36, 0x0a, 0x08, 0x53, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xf6, 0x01, + 0x0a, 0x11, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x50, 0x0a, 0x07, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, + 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x56, 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, + 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4d, 0x65, + 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x1a, 0x37, 0x0a, + 0x09, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa6, 0x06, 0x0a, 0x0f, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x4e, + 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, + 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, + 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5c, + 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, + 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, + 0x0b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x0a, + 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x0a, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, + 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x49, 0x44, 0x12, 0x4e, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, + 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x49, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x44, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x0a, 0x4c, 0x65, + 0x67, 0x61, 0x63, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, + 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, + 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x4d, 0x65, 0x74, + 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x4d, 0x65, + 0x74, 0x61, 0x12, 0x46, 0x0a, 0x10, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x10, 0x4c, 0x65, + 0x67, 0x61, 0x63, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x10, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x58, 0x0a, 0x0e, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, + 0x4d, 0x65, 0x74, 0x61, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x68, 0x61, 0x73, + 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6e, + 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x0e, 0x45, 0x6e, + 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, + 0x50, 0x65, 0x65, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x50, 0x65, 0x65, 0x72, + 0x1a, 0x3d, 0x0a, 0x0f, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, + 0xb9, 0x01, 0x0a, 0x13, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x65, 0x72, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, + 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x52, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, + 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x49, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x54, 0x54, 0x50, 0x50, 0x65, 0x72, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x48, 0x54, 0x54, 0x50, 0x22, 0xed, 0x01, 0x0a, 0x17, + 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x54, 0x54, 0x50, 0x50, 0x65, 0x72, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x74, 0x68, 0x45, + 0x78, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x74, 0x68, + 0x45, 0x78, 0x61, 0x63, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x50, 0x61, 0x74, 0x68, 0x50, 0x72, 0x65, + 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x50, 0x61, 0x74, 0x68, 0x50, + 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x74, 0x68, 0x52, 0x65, 0x67, + 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x74, 0x68, 0x52, 0x65, + 0x67, 0x65, 0x78, 0x12, 0x5c, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, + 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x54, 0x54, 0x50, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x50, + 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x07, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x22, 0xc1, 0x01, 0x0a, 0x1d, + 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x54, 0x54, 0x50, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, + 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x07, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x45, + 0x78, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x45, 0x78, 0x61, 0x63, + 0x74, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x75, 0x66, + 0x66, 0x69, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x53, 0x75, 0x66, 0x66, 0x69, + 0x78, 0x12, 0x14, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x49, 0x6e, 0x76, 0x65, 0x72, + 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x49, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x22, + 0xda, 0x07, 0x0a, 0x0f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, + 0x44, 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, + 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x52, + 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x69, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x3d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, + 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, + 0x12, 0x5a, 0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, + 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x65, + 0x73, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x0b, 0x4d, 0x65, 0x73, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x4b, 0x0a, 0x06, + 0x45, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x68, + 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, + 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x52, 0x06, 0x45, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x45, 0x78, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x4e, 0x49, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x4e, 0x49, 0x12, 0x64, 0x0a, 0x0e, 0x55, + 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, + 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x55, 0x70, 0x73, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x0e, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x12, 0x5a, 0x0a, 0x0b, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, + 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x44, + 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x52, 0x0b, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, + 0x15, 0x4d, 0x61, 0x78, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x15, 0x4d, 0x61, + 0x78, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x34, 0x0a, 0x15, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4d, 0x73, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x15, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4d, 0x73, 0x12, 0x34, 0x0a, 0x15, 0x4c, 0x6f, 0x63, + 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, + 0x4d, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x15, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4d, 0x73, 0x12, + 0x3c, 0x0a, 0x19, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, + 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x19, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, + 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x54, 0x0a, + 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x68, 0x61, + 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, + 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x4d, + 0x65, 0x74, 0x61, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x74, 0x0a, 0x16, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x32, 0x0a, 0x14, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, + 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x14, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x4c, 0x69, + 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x44, 0x69, + 0x61, 0x6c, 0x65, 0x64, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0e, 0x44, 0x69, 0x61, 0x6c, 0x65, 0x64, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x6c, 0x79, 0x22, 0x5f, 0x0a, 0x11, 0x4d, 0x65, 0x73, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4a, 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, + 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x65, + 0x73, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x4d, + 0x6f, 0x64, 0x65, 0x22, 0x6f, 0x0a, 0x0c, 0x45, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x06, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x12, 0x47, 0x0a, 0x05, 0x50, + 0x61, 0x74, 0x68, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x68, 0x61, 0x73, + 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x50, 0x61, 0x74, 0x68, 0x52, 0x05, 0x50, + 0x61, 0x74, 0x68, 0x73, 0x22, 0xb0, 0x01, 0x0a, 0x0a, 0x45, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x50, + 0x61, 0x74, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x50, + 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x65, + 0x6e, 0x65, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x50, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0d, 0x4c, + 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x0d, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x50, 0x6f, 0x72, + 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x28, 0x0a, + 0x0f, 0x50, 0x61, 0x72, 0x73, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x50, 0x61, 0x72, 0x73, 0x65, 0x64, 0x46, 0x72, + 0x6f, 0x6d, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x22, 0xbf, 0x01, 0x0a, 0x15, 0x55, 0x70, 0x73, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x53, 0x0a, 0x09, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, + 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x55, 0x70, 0x73, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x4f, 0x76, 0x65, + 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x12, 0x51, 0x0a, 0x08, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x2e, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x08, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x22, 0xf6, 0x04, 0x0a, 0x0e, 0x55, 0x70, + 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, + 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x58, 0x0a, 0x0e, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, + 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6e, 0x74, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x0e, 0x45, 0x6e, 0x74, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x2c, 0x0a, 0x11, 0x45, 0x6e, + 0x76, 0x6f, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x4a, 0x53, 0x4f, 0x4e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x45, 0x6e, 0x76, 0x6f, 0x79, 0x4c, 0x69, 0x73, 0x74, + 0x65, 0x6e, 0x65, 0x72, 0x4a, 0x53, 0x4f, 0x4e, 0x12, 0x2a, 0x0a, 0x10, 0x45, 0x6e, 0x76, 0x6f, + 0x79, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4a, 0x53, 0x4f, 0x4e, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x10, 0x45, 0x6e, 0x76, 0x6f, 0x79, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x4a, 0x53, 0x4f, 0x4e, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x12, 0x2a, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, + 0x75, 0x74, 0x4d, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4d, 0x73, 0x12, 0x4d, 0x0a, 0x06, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, + 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, + 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x73, 0x52, 0x06, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x69, 0x0a, 0x12, 0x50, + 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, + 0x50, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x52, 0x12, 0x50, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, + 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x5a, 0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x68, 0x47, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x68, 0x61, + 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, + 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x65, 0x73, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0b, 0x4d, 0x65, 0x73, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x12, 0x3e, 0x0a, 0x1a, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x4f, 0x75, 0x74, + 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1a, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x4f, + 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x22, 0x9e, 0x01, 0x0a, 0x0e, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x4d, + 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2e, 0x0a, + 0x12, 0x4d, 0x61, 0x78, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x4d, 0x61, 0x78, 0x50, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x34, 0x0a, + 0x15, 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x15, 0x4d, 0x61, + 0x78, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x73, 0x22, 0x9e, 0x02, 0x0a, 0x12, 0x50, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x48, + 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x35, 0x0a, 0x08, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, + 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x4d, 0x61, 0x78, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x4d, 0x61, 0x78, 0x46, 0x61, 0x69, 0x6c, 0x75, + 0x72, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x17, 0x45, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x69, 0x6e, 0x67, + 0x43, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x74, 0x69, 0x76, 0x65, 0x35, 0x78, 0x78, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x17, 0x45, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x69, 0x6e, 0x67, 0x43, + 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x74, 0x69, 0x76, 0x65, 0x35, 0x78, 0x78, 0x12, 0x2e, 0x0a, + 0x12, 0x4d, 0x61, 0x78, 0x45, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x63, + 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x4d, 0x61, 0x78, 0x45, 0x6a, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x45, 0x0a, + 0x10, 0x42, 0x61, 0x73, 0x65, 0x45, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x10, 0x42, 0x61, 0x73, 0x65, 0x45, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x54, 0x69, 0x6d, 0x65, 0x22, 0x45, 0x0a, 0x11, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x2a, 0x90, 0x01, 0x0a, 0x04, + 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x0f, 0x0a, 0x0b, 0x4b, 0x69, 0x6e, 0x64, 0x55, 0x6e, 0x6b, 0x6e, + 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4b, 0x69, 0x6e, 0x64, 0x4d, 0x65, 0x73, + 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x4b, 0x69, 0x6e, + 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, + 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, 0x4b, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, + 0x73, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x4b, 0x69, + 0x6e, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x10, 0x04, 0x12, 0x17, 0x0a, 0x13, 0x4b, 0x69, 0x6e, 0x64, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x10, 0x05, 0x2a, 0x26, + 0x0a, 0x0f, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x65, 0x6e, 0x79, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x41, + 0x6c, 0x6c, 0x6f, 0x77, 0x10, 0x01, 0x2a, 0x21, 0x0a, 0x13, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, + 0x06, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x10, 0x00, 0x2a, 0x50, 0x0a, 0x09, 0x50, 0x72, 0x6f, + 0x78, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, + 0x6f, 0x64, 0x65, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, + 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, + 0x6f, 0x64, 0x65, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x10, 0x02, 0x2a, 0x7b, 0x0a, 0x0f, 0x4d, + 0x65, 0x73, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1a, + 0x0a, 0x16, 0x4d, 0x65, 0x73, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4d, 0x6f, 0x64, + 0x65, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x4d, 0x65, + 0x73, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x4e, 0x6f, 0x6e, + 0x65, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x4d, 0x65, 0x73, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x10, 0x02, 0x12, 0x19, 0x0a, + 0x15, 0x4d, 0x65, 0x73, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4d, 0x6f, 0x64, 0x65, + 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x10, 0x03, 0x42, 0xa6, 0x02, 0x0a, 0x29, 0x63, 0x6f, 0x6d, + 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, + 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x10, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, + 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0xa2, 0x02, 0x04, 0x48, 0x43, + 0x49, 0x43, 0xaa, 0x02, 0x25, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, + 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0xca, 0x02, 0x25, 0x48, 0x61, 0x73, + 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0xe2, 0x02, 0x31, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, + 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5c, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x28, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, + 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x49, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_proto_pbconfigentry_config_entry_proto_rawDescOnce sync.Once + file_proto_pbconfigentry_config_entry_proto_rawDescData = file_proto_pbconfigentry_config_entry_proto_rawDesc +) + +func file_proto_pbconfigentry_config_entry_proto_rawDescGZIP() []byte { + file_proto_pbconfigentry_config_entry_proto_rawDescOnce.Do(func() { + file_proto_pbconfigentry_config_entry_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_pbconfigentry_config_entry_proto_rawDescData) + }) + return file_proto_pbconfigentry_config_entry_proto_rawDescData +} + +var file_proto_pbconfigentry_config_entry_proto_enumTypes = make([]protoimpl.EnumInfo, 5) +var file_proto_pbconfigentry_config_entry_proto_msgTypes = make([]protoimpl.MessageInfo, 51) +var file_proto_pbconfigentry_config_entry_proto_goTypes = []interface{}{ + (Kind)(0), // 0: hashicorp.consul.internal.configentry.Kind + (IntentionAction)(0), // 1: hashicorp.consul.internal.configentry.IntentionAction + (IntentionSourceType)(0), // 2: hashicorp.consul.internal.configentry.IntentionSourceType + (ProxyMode)(0), // 3: hashicorp.consul.internal.configentry.ProxyMode + (MeshGatewayMode)(0), // 4: hashicorp.consul.internal.configentry.MeshGatewayMode + (*ConfigEntry)(nil), // 5: hashicorp.consul.internal.configentry.ConfigEntry + (*MeshConfig)(nil), // 6: hashicorp.consul.internal.configentry.MeshConfig + (*TransparentProxyMeshConfig)(nil), // 7: hashicorp.consul.internal.configentry.TransparentProxyMeshConfig + (*MeshTLSConfig)(nil), // 8: hashicorp.consul.internal.configentry.MeshTLSConfig + (*MeshDirectionalTLSConfig)(nil), // 9: hashicorp.consul.internal.configentry.MeshDirectionalTLSConfig + (*MeshHTTPConfig)(nil), // 10: hashicorp.consul.internal.configentry.MeshHTTPConfig + (*PeeringMeshConfig)(nil), // 11: hashicorp.consul.internal.configentry.PeeringMeshConfig + (*ServiceResolver)(nil), // 12: hashicorp.consul.internal.configentry.ServiceResolver + (*ServiceResolverSubset)(nil), // 13: hashicorp.consul.internal.configentry.ServiceResolverSubset + (*ServiceResolverRedirect)(nil), // 14: hashicorp.consul.internal.configentry.ServiceResolverRedirect + (*ServiceResolverFailover)(nil), // 15: hashicorp.consul.internal.configentry.ServiceResolverFailover + (*ServiceResolverFailoverTarget)(nil), // 16: hashicorp.consul.internal.configentry.ServiceResolverFailoverTarget + (*LoadBalancer)(nil), // 17: hashicorp.consul.internal.configentry.LoadBalancer + (*RingHashConfig)(nil), // 18: hashicorp.consul.internal.configentry.RingHashConfig + (*LeastRequestConfig)(nil), // 19: hashicorp.consul.internal.configentry.LeastRequestConfig + (*HashPolicy)(nil), // 20: hashicorp.consul.internal.configentry.HashPolicy + (*CookieConfig)(nil), // 21: hashicorp.consul.internal.configentry.CookieConfig + (*IngressGateway)(nil), // 22: hashicorp.consul.internal.configentry.IngressGateway + (*IngressServiceConfig)(nil), // 23: hashicorp.consul.internal.configentry.IngressServiceConfig + (*GatewayTLSConfig)(nil), // 24: hashicorp.consul.internal.configentry.GatewayTLSConfig + (*GatewayTLSSDSConfig)(nil), // 25: hashicorp.consul.internal.configentry.GatewayTLSSDSConfig + (*IngressListener)(nil), // 26: hashicorp.consul.internal.configentry.IngressListener + (*IngressService)(nil), // 27: hashicorp.consul.internal.configentry.IngressService + (*GatewayServiceTLSConfig)(nil), // 28: hashicorp.consul.internal.configentry.GatewayServiceTLSConfig + (*HTTPHeaderModifiers)(nil), // 29: hashicorp.consul.internal.configentry.HTTPHeaderModifiers + (*ServiceIntentions)(nil), // 30: hashicorp.consul.internal.configentry.ServiceIntentions + (*SourceIntention)(nil), // 31: hashicorp.consul.internal.configentry.SourceIntention + (*IntentionPermission)(nil), // 32: hashicorp.consul.internal.configentry.IntentionPermission + (*IntentionHTTPPermission)(nil), // 33: hashicorp.consul.internal.configentry.IntentionHTTPPermission + (*IntentionHTTPHeaderPermission)(nil), // 34: hashicorp.consul.internal.configentry.IntentionHTTPHeaderPermission + (*ServiceDefaults)(nil), // 35: hashicorp.consul.internal.configentry.ServiceDefaults + (*TransparentProxyConfig)(nil), // 36: hashicorp.consul.internal.configentry.TransparentProxyConfig + (*MeshGatewayConfig)(nil), // 37: hashicorp.consul.internal.configentry.MeshGatewayConfig + (*ExposeConfig)(nil), // 38: hashicorp.consul.internal.configentry.ExposeConfig + (*ExposePath)(nil), // 39: hashicorp.consul.internal.configentry.ExposePath + (*UpstreamConfiguration)(nil), // 40: hashicorp.consul.internal.configentry.UpstreamConfiguration + (*UpstreamConfig)(nil), // 41: hashicorp.consul.internal.configentry.UpstreamConfig + (*UpstreamLimits)(nil), // 42: hashicorp.consul.internal.configentry.UpstreamLimits + (*PassiveHealthCheck)(nil), // 43: hashicorp.consul.internal.configentry.PassiveHealthCheck + (*DestinationConfig)(nil), // 44: hashicorp.consul.internal.configentry.DestinationConfig + nil, // 45: hashicorp.consul.internal.configentry.MeshConfig.MetaEntry + nil, // 46: hashicorp.consul.internal.configentry.ServiceResolver.SubsetsEntry + nil, // 47: hashicorp.consul.internal.configentry.ServiceResolver.FailoverEntry + nil, // 48: hashicorp.consul.internal.configentry.ServiceResolver.MetaEntry + nil, // 49: hashicorp.consul.internal.configentry.IngressGateway.MetaEntry + nil, // 50: hashicorp.consul.internal.configentry.IngressService.MetaEntry + nil, // 51: hashicorp.consul.internal.configentry.HTTPHeaderModifiers.AddEntry + nil, // 52: hashicorp.consul.internal.configentry.HTTPHeaderModifiers.SetEntry + nil, // 53: hashicorp.consul.internal.configentry.ServiceIntentions.MetaEntry + nil, // 54: hashicorp.consul.internal.configentry.SourceIntention.LegacyMetaEntry + nil, // 55: hashicorp.consul.internal.configentry.ServiceDefaults.MetaEntry + (*pbcommon.EnterpriseMeta)(nil), // 56: hashicorp.consul.internal.common.EnterpriseMeta + (*pbcommon.RaftIndex)(nil), // 57: hashicorp.consul.internal.common.RaftIndex + (*durationpb.Duration)(nil), // 58: google.protobuf.Duration + (*timestamppb.Timestamp)(nil), // 59: google.protobuf.Timestamp +} +var file_proto_pbconfigentry_config_entry_proto_depIdxs = []int32{ + 0, // 0: hashicorp.consul.internal.configentry.ConfigEntry.Kind:type_name -> hashicorp.consul.internal.configentry.Kind + 56, // 1: hashicorp.consul.internal.configentry.ConfigEntry.EnterpriseMeta:type_name -> hashicorp.consul.internal.common.EnterpriseMeta + 57, // 2: hashicorp.consul.internal.configentry.ConfigEntry.RaftIndex:type_name -> hashicorp.consul.internal.common.RaftIndex + 6, // 3: hashicorp.consul.internal.configentry.ConfigEntry.MeshConfig:type_name -> hashicorp.consul.internal.configentry.MeshConfig + 12, // 4: hashicorp.consul.internal.configentry.ConfigEntry.ServiceResolver:type_name -> hashicorp.consul.internal.configentry.ServiceResolver + 22, // 5: hashicorp.consul.internal.configentry.ConfigEntry.IngressGateway:type_name -> hashicorp.consul.internal.configentry.IngressGateway + 30, // 6: hashicorp.consul.internal.configentry.ConfigEntry.ServiceIntentions:type_name -> hashicorp.consul.internal.configentry.ServiceIntentions + 35, // 7: hashicorp.consul.internal.configentry.ConfigEntry.ServiceDefaults:type_name -> hashicorp.consul.internal.configentry.ServiceDefaults + 7, // 8: hashicorp.consul.internal.configentry.MeshConfig.TransparentProxy:type_name -> hashicorp.consul.internal.configentry.TransparentProxyMeshConfig + 8, // 9: hashicorp.consul.internal.configentry.MeshConfig.TLS:type_name -> hashicorp.consul.internal.configentry.MeshTLSConfig + 10, // 10: hashicorp.consul.internal.configentry.MeshConfig.HTTP:type_name -> hashicorp.consul.internal.configentry.MeshHTTPConfig + 45, // 11: hashicorp.consul.internal.configentry.MeshConfig.Meta:type_name -> hashicorp.consul.internal.configentry.MeshConfig.MetaEntry + 11, // 12: hashicorp.consul.internal.configentry.MeshConfig.Peering:type_name -> hashicorp.consul.internal.configentry.PeeringMeshConfig + 9, // 13: hashicorp.consul.internal.configentry.MeshTLSConfig.Incoming:type_name -> hashicorp.consul.internal.configentry.MeshDirectionalTLSConfig + 9, // 14: hashicorp.consul.internal.configentry.MeshTLSConfig.Outgoing:type_name -> hashicorp.consul.internal.configentry.MeshDirectionalTLSConfig + 46, // 15: hashicorp.consul.internal.configentry.ServiceResolver.Subsets:type_name -> hashicorp.consul.internal.configentry.ServiceResolver.SubsetsEntry + 14, // 16: hashicorp.consul.internal.configentry.ServiceResolver.Redirect:type_name -> hashicorp.consul.internal.configentry.ServiceResolverRedirect + 47, // 17: hashicorp.consul.internal.configentry.ServiceResolver.Failover:type_name -> hashicorp.consul.internal.configentry.ServiceResolver.FailoverEntry + 58, // 18: hashicorp.consul.internal.configentry.ServiceResolver.ConnectTimeout:type_name -> google.protobuf.Duration + 17, // 19: hashicorp.consul.internal.configentry.ServiceResolver.LoadBalancer:type_name -> hashicorp.consul.internal.configentry.LoadBalancer + 48, // 20: hashicorp.consul.internal.configentry.ServiceResolver.Meta:type_name -> hashicorp.consul.internal.configentry.ServiceResolver.MetaEntry + 58, // 21: hashicorp.consul.internal.configentry.ServiceResolver.RequestTimeout:type_name -> google.protobuf.Duration + 16, // 22: hashicorp.consul.internal.configentry.ServiceResolverFailover.Targets:type_name -> hashicorp.consul.internal.configentry.ServiceResolverFailoverTarget + 18, // 23: hashicorp.consul.internal.configentry.LoadBalancer.RingHashConfig:type_name -> hashicorp.consul.internal.configentry.RingHashConfig + 19, // 24: hashicorp.consul.internal.configentry.LoadBalancer.LeastRequestConfig:type_name -> hashicorp.consul.internal.configentry.LeastRequestConfig + 20, // 25: hashicorp.consul.internal.configentry.LoadBalancer.HashPolicies:type_name -> hashicorp.consul.internal.configentry.HashPolicy + 21, // 26: hashicorp.consul.internal.configentry.HashPolicy.CookieConfig:type_name -> hashicorp.consul.internal.configentry.CookieConfig + 58, // 27: hashicorp.consul.internal.configentry.CookieConfig.TTL:type_name -> google.protobuf.Duration + 24, // 28: hashicorp.consul.internal.configentry.IngressGateway.TLS:type_name -> hashicorp.consul.internal.configentry.GatewayTLSConfig + 26, // 29: hashicorp.consul.internal.configentry.IngressGateway.Listeners:type_name -> hashicorp.consul.internal.configentry.IngressListener + 49, // 30: hashicorp.consul.internal.configentry.IngressGateway.Meta:type_name -> hashicorp.consul.internal.configentry.IngressGateway.MetaEntry + 23, // 31: hashicorp.consul.internal.configentry.IngressGateway.Defaults:type_name -> hashicorp.consul.internal.configentry.IngressServiceConfig + 25, // 32: hashicorp.consul.internal.configentry.GatewayTLSConfig.SDS:type_name -> hashicorp.consul.internal.configentry.GatewayTLSSDSConfig + 27, // 33: hashicorp.consul.internal.configentry.IngressListener.Services:type_name -> hashicorp.consul.internal.configentry.IngressService + 24, // 34: hashicorp.consul.internal.configentry.IngressListener.TLS:type_name -> hashicorp.consul.internal.configentry.GatewayTLSConfig + 28, // 35: hashicorp.consul.internal.configentry.IngressService.TLS:type_name -> hashicorp.consul.internal.configentry.GatewayServiceTLSConfig + 29, // 36: hashicorp.consul.internal.configentry.IngressService.RequestHeaders:type_name -> hashicorp.consul.internal.configentry.HTTPHeaderModifiers + 29, // 37: hashicorp.consul.internal.configentry.IngressService.ResponseHeaders:type_name -> hashicorp.consul.internal.configentry.HTTPHeaderModifiers + 50, // 38: hashicorp.consul.internal.configentry.IngressService.Meta:type_name -> hashicorp.consul.internal.configentry.IngressService.MetaEntry + 56, // 39: hashicorp.consul.internal.configentry.IngressService.EnterpriseMeta:type_name -> hashicorp.consul.internal.common.EnterpriseMeta + 25, // 40: hashicorp.consul.internal.configentry.GatewayServiceTLSConfig.SDS:type_name -> hashicorp.consul.internal.configentry.GatewayTLSSDSConfig + 51, // 41: hashicorp.consul.internal.configentry.HTTPHeaderModifiers.Add:type_name -> hashicorp.consul.internal.configentry.HTTPHeaderModifiers.AddEntry + 52, // 42: hashicorp.consul.internal.configentry.HTTPHeaderModifiers.Set:type_name -> hashicorp.consul.internal.configentry.HTTPHeaderModifiers.SetEntry + 31, // 43: hashicorp.consul.internal.configentry.ServiceIntentions.Sources:type_name -> hashicorp.consul.internal.configentry.SourceIntention + 53, // 44: hashicorp.consul.internal.configentry.ServiceIntentions.Meta:type_name -> hashicorp.consul.internal.configentry.ServiceIntentions.MetaEntry + 1, // 45: hashicorp.consul.internal.configentry.SourceIntention.Action:type_name -> hashicorp.consul.internal.configentry.IntentionAction + 32, // 46: hashicorp.consul.internal.configentry.SourceIntention.Permissions:type_name -> hashicorp.consul.internal.configentry.IntentionPermission + 2, // 47: hashicorp.consul.internal.configentry.SourceIntention.Type:type_name -> hashicorp.consul.internal.configentry.IntentionSourceType + 54, // 48: hashicorp.consul.internal.configentry.SourceIntention.LegacyMeta:type_name -> hashicorp.consul.internal.configentry.SourceIntention.LegacyMetaEntry + 59, // 49: hashicorp.consul.internal.configentry.SourceIntention.LegacyCreateTime:type_name -> google.protobuf.Timestamp + 59, // 50: hashicorp.consul.internal.configentry.SourceIntention.LegacyUpdateTime:type_name -> google.protobuf.Timestamp + 56, // 51: hashicorp.consul.internal.configentry.SourceIntention.EnterpriseMeta:type_name -> hashicorp.consul.internal.common.EnterpriseMeta + 1, // 52: hashicorp.consul.internal.configentry.IntentionPermission.Action:type_name -> hashicorp.consul.internal.configentry.IntentionAction + 33, // 53: hashicorp.consul.internal.configentry.IntentionPermission.HTTP:type_name -> hashicorp.consul.internal.configentry.IntentionHTTPPermission + 34, // 54: hashicorp.consul.internal.configentry.IntentionHTTPPermission.Header:type_name -> hashicorp.consul.internal.configentry.IntentionHTTPHeaderPermission + 3, // 55: hashicorp.consul.internal.configentry.ServiceDefaults.Mode:type_name -> hashicorp.consul.internal.configentry.ProxyMode + 36, // 56: hashicorp.consul.internal.configentry.ServiceDefaults.TransparentProxy:type_name -> hashicorp.consul.internal.configentry.TransparentProxyConfig + 37, // 57: hashicorp.consul.internal.configentry.ServiceDefaults.MeshGateway:type_name -> hashicorp.consul.internal.configentry.MeshGatewayConfig + 38, // 58: hashicorp.consul.internal.configentry.ServiceDefaults.Expose:type_name -> hashicorp.consul.internal.configentry.ExposeConfig + 40, // 59: hashicorp.consul.internal.configentry.ServiceDefaults.UpstreamConfig:type_name -> hashicorp.consul.internal.configentry.UpstreamConfiguration + 44, // 60: hashicorp.consul.internal.configentry.ServiceDefaults.Destination:type_name -> hashicorp.consul.internal.configentry.DestinationConfig + 55, // 61: hashicorp.consul.internal.configentry.ServiceDefaults.Meta:type_name -> hashicorp.consul.internal.configentry.ServiceDefaults.MetaEntry + 4, // 62: hashicorp.consul.internal.configentry.MeshGatewayConfig.Mode:type_name -> hashicorp.consul.internal.configentry.MeshGatewayMode + 39, // 63: hashicorp.consul.internal.configentry.ExposeConfig.Paths:type_name -> hashicorp.consul.internal.configentry.ExposePath + 41, // 64: hashicorp.consul.internal.configentry.UpstreamConfiguration.Overrides:type_name -> hashicorp.consul.internal.configentry.UpstreamConfig + 41, // 65: hashicorp.consul.internal.configentry.UpstreamConfiguration.Defaults:type_name -> hashicorp.consul.internal.configentry.UpstreamConfig + 56, // 66: hashicorp.consul.internal.configentry.UpstreamConfig.EnterpriseMeta:type_name -> hashicorp.consul.internal.common.EnterpriseMeta + 42, // 67: hashicorp.consul.internal.configentry.UpstreamConfig.Limits:type_name -> hashicorp.consul.internal.configentry.UpstreamLimits + 43, // 68: hashicorp.consul.internal.configentry.UpstreamConfig.PassiveHealthCheck:type_name -> hashicorp.consul.internal.configentry.PassiveHealthCheck + 37, // 69: hashicorp.consul.internal.configentry.UpstreamConfig.MeshGateway:type_name -> hashicorp.consul.internal.configentry.MeshGatewayConfig + 58, // 70: hashicorp.consul.internal.configentry.PassiveHealthCheck.Interval:type_name -> google.protobuf.Duration + 58, // 71: hashicorp.consul.internal.configentry.PassiveHealthCheck.BaseEjectionTime:type_name -> google.protobuf.Duration + 13, // 72: hashicorp.consul.internal.configentry.ServiceResolver.SubsetsEntry.value:type_name -> hashicorp.consul.internal.configentry.ServiceResolverSubset + 15, // 73: hashicorp.consul.internal.configentry.ServiceResolver.FailoverEntry.value:type_name -> hashicorp.consul.internal.configentry.ServiceResolverFailover + 74, // [74:74] is the sub-list for method output_type + 74, // [74:74] is the sub-list for method input_type + 74, // [74:74] is the sub-list for extension type_name + 74, // [74:74] is the sub-list for extension extendee + 0, // [0:74] is the sub-list for field type_name +} + +func init() { file_proto_pbconfigentry_config_entry_proto_init() } +func file_proto_pbconfigentry_config_entry_proto_init() { if File_proto_pbconfigentry_config_entry_proto != nil { return } @@ -3566,20 +4748,141 @@ func file_proto_pbconfigentry_config_entry_proto_init() { return nil } } + file_proto_pbconfigentry_config_entry_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ServiceDefaults); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_pbconfigentry_config_entry_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TransparentProxyConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_pbconfigentry_config_entry_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MeshGatewayConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_pbconfigentry_config_entry_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExposeConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_pbconfigentry_config_entry_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExposePath); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_pbconfigentry_config_entry_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpstreamConfiguration); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_pbconfigentry_config_entry_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpstreamConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_pbconfigentry_config_entry_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpstreamLimits); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_pbconfigentry_config_entry_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PassiveHealthCheck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_pbconfigentry_config_entry_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DestinationConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_proto_pbconfigentry_config_entry_proto_msgTypes[0].OneofWrappers = []interface{}{ (*ConfigEntry_MeshConfig)(nil), (*ConfigEntry_ServiceResolver)(nil), (*ConfigEntry_IngressGateway)(nil), (*ConfigEntry_ServiceIntentions)(nil), + (*ConfigEntry_ServiceDefaults)(nil), } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_pbconfigentry_config_entry_proto_rawDesc, - NumEnums: 3, - NumMessages: 40, + NumEnums: 5, + NumMessages: 51, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/pbconfigentry/config_entry.proto b/proto/pbconfigentry/config_entry.proto index fba12fb15029..002ff7f524d7 100644 --- a/proto/pbconfigentry/config_entry.proto +++ b/proto/pbconfigentry/config_entry.proto @@ -12,6 +12,7 @@ enum Kind { KindServiceResolver = 2; KindIngressGateway = 3; KindServiceIntentions = 4; + KindServiceDefaults = 5; } message ConfigEntry { @@ -26,6 +27,7 @@ message ConfigEntry { ServiceResolver ServiceResolver = 6; IngressGateway IngressGateway = 7; ServiceIntentions ServiceIntentions = 8; + ServiceDefaults ServiceDefaults = 9; } } @@ -109,6 +111,8 @@ message ServiceResolver { google.protobuf.Duration ConnectTimeout = 5; LoadBalancer LoadBalancer = 6; map Meta = 7; + // mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto + google.protobuf.Duration RequestTimeout = 8; } // mog annotation: @@ -404,3 +408,160 @@ message IntentionHTTPHeaderPermission { string Regex = 6; bool Invert = 7; } + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.ServiceConfigEntry +// output=config_entry.gen.go +// name=Structs +// ignore-fields=Kind,Name,RaftIndex,EnterpriseMeta +message ServiceDefaults { + string Protocol = 1; + // mog: func-to=proxyModeToStructs func-from=proxyModeFromStructs + ProxyMode Mode = 2; + TransparentProxyConfig TransparentProxy = 3; + MeshGatewayConfig MeshGateway = 4; + ExposeConfig Expose = 5; + string ExternalSNI = 6; + UpstreamConfiguration UpstreamConfig = 7; + DestinationConfig Destination = 8; + // mog: func-to=int func-from=int32 + int32 MaxInboundConnections = 9; + // mog: func-to=int func-from=int32 + int32 LocalConnectTimeoutMs = 10; + // mog: func-to=int func-from=int32 + int32 LocalRequestTimeoutMs = 11; + string BalanceInboundConnections = 12; + map Meta = 13; +} + +enum ProxyMode { + ProxyModeDefault = 0; + ProxyModeTransparent = 1; + ProxyModeDirect = 2; +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.TransparentProxyConfig +// output=config_entry.gen.go +// name=Structs +message TransparentProxyConfig { + // mog: func-to=int func-from=int32 + int32 OutboundListenerPort = 1; + bool DialedDirectly = 2; +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.MeshGatewayConfig +// output=config_entry.gen.go +// name=Structs +message MeshGatewayConfig { + // mog: func-to=meshGatewayModeToStructs func-from=meshGatewayModeFromStructs + MeshGatewayMode Mode = 1; +} + +enum MeshGatewayMode { + MeshGatewayModeDefault = 0; + MeshGatewayModeNone = 1; + MeshGatewayModeLocal = 2; + MeshGatewayModeRemote = 3; +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.ExposeConfig +// output=config_entry.gen.go +// name=Structs +message ExposeConfig { + bool Checks = 1; + repeated ExposePath Paths = 2; +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.ExposePath +// output=config_entry.gen.go +// name=Structs +message ExposePath { + // mog: func-to=int func-from=int32 + int32 ListenerPort = 1; + string Path = 2; + // mog: func-to=int func-from=int32 + int32 LocalPathPort = 3; + string Protocol = 4; + bool ParsedFromCheck = 5; +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.UpstreamConfiguration +// output=config_entry.gen.go +// name=Structs +message UpstreamConfiguration { + repeated UpstreamConfig Overrides = 1; + UpstreamConfig Defaults = 2; +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.UpstreamConfig +// output=config_entry.gen.go +// name=Structs +message UpstreamConfig { + string Name = 1; + // mog: func-to=enterpriseMetaToStructs func-from=enterpriseMetaFromStructs + common.EnterpriseMeta EnterpriseMeta = 2; + string EnvoyListenerJSON = 3; + string EnvoyClusterJSON = 4; + string Protocol = 5; + // mog: func-to=int func-from=int32 + int32 ConnectTimeoutMs = 6; + UpstreamLimits Limits = 7; + PassiveHealthCheck PassiveHealthCheck = 8; + MeshGatewayConfig MeshGateway = 9; + string BalanceOutboundConnections = 10; +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.UpstreamLimits +// output=config_entry.gen.go +// name=Structs +message UpstreamLimits { + // mog: func-to=pointerToIntFromInt32 func-from=int32FromPointerToInt + int32 MaxConnections = 1; + // mog: func-to=pointerToIntFromInt32 func-from=int32FromPointerToInt + int32 MaxPendingRequests = 2; + // mog: func-to=pointerToIntFromInt32 func-from=int32FromPointerToInt + int32 MaxConcurrentRequests = 3; +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.PassiveHealthCheck +// output=config_entry.gen.go +// name=Structs +message PassiveHealthCheck { + // mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto + google.protobuf.Duration Interval = 1; + uint32 MaxFailures = 2; + // mog: target=EnforcingConsecutive5xx func-to=pointerToUint32FromUint32 func-from=uint32FromPointerToUint32 + uint32 EnforcingConsecutive5xx = 3; + // mog: func-to=pointerToUint32FromUint32 func-from=uint32FromPointerToUint32 + uint32 MaxEjectionPercent = 4; + // mog: func-to=structs.DurationPointerFromProto func-from=structs.DurationPointerToProto + google.protobuf.Duration BaseEjectionTime = 5; +} + +// mog annotation: +// +// target=github.com/hashicorp/consul/agent/structs.DestinationConfig +// output=config_entry.gen.go +// name=Structs +message DestinationConfig { + repeated string Addresses = 1; + // mog: func-to=int func-from=int32 + int32 Port = 2; +} diff --git a/proto/pbconnect/connect.pb.go b/proto/pbconnect/connect.pb.go index 89100474fc55..4d6ac71f3a91 100644 --- a/proto/pbconnect/connect.pb.go +++ b/proto/pbconnect/connect.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto/pbconnect/connect.proto diff --git a/proto/pbpeering/peering.gen.go b/proto/pbpeering/peering.gen.go index 94cf1daa0161..b5b3436d4ce0 100644 --- a/proto/pbpeering/peering.gen.go +++ b/proto/pbpeering/peering.gen.go @@ -39,6 +39,7 @@ func GenerateTokenRequestToAPI(s *GenerateTokenRequest, t *api.PeeringGenerateTo t.PeerName = s.PeerName t.Partition = s.Partition t.Meta = s.Meta + t.ServerExternalAddresses = s.ServerExternalAddresses } func GenerateTokenRequestFromAPI(t *api.PeeringGenerateTokenRequest, s *GenerateTokenRequest) { if s == nil { @@ -47,6 +48,7 @@ func GenerateTokenRequestFromAPI(t *api.PeeringGenerateTokenRequest, s *Generate s.PeerName = t.PeerName s.Partition = t.Partition s.Meta = t.Meta + s.ServerExternalAddresses = t.ServerExternalAddresses } func GenerateTokenResponseToAPI(s *GenerateTokenResponse, t *api.PeeringGenerateTokenResponse) { if s == nil { diff --git a/proto/pbpeering/peering.go b/proto/pbpeering/peering.go index 511de42c5785..c50e827cd94f 100644 --- a/proto/pbpeering/peering.go +++ b/proto/pbpeering/peering.go @@ -75,10 +75,19 @@ func (req *TrustBundleListByServiceRequest) RequestDatacenter() string { // ShouldDial returns true when the peering was stored via the peering initiation endpoint, // AND the peering is not marked as terminated by our peer. -// If we generated a token for this peer we did not store our server addresses under PeerServerAddresses. +// If we generated a token for this peer we did not store our server addresses under PeerServerAddresses or ManualServerAddresses. // These server addresses are for dialing, and only the peer initiating the peering will do the dialing. func (p *Peering) ShouldDial() bool { - return len(p.PeerServerAddresses) > 0 + return len(p.PeerServerAddresses) > 0 || len(p.ManualServerAddresses) > 0 +} + +// GetAddressesToDial returns the listing of addresses that should be dialed for the peering. +// It will ensure that manual addresses take precedence, if any are defined. +func (p *Peering) GetAddressesToDial() []string { + if len(p.ManualServerAddresses) > 0 { + return p.ManualServerAddresses + } + return p.PeerServerAddresses } func (x PeeringState) GoString() string { @@ -208,6 +217,7 @@ func (s *SecretsWriteRequest) Validate() error { // ara available. If no CAPems were provided in the peering token then the // WithInsecure dial option is returned. func (p *Peering) TLSDialOption() (grpc.DialOption, error) { + //nolint:staticcheck tlsOption := grpc.WithInsecure() if len(p.PeerCAPems) > 0 { diff --git a/proto/pbpeering/peering.pb.go b/proto/pbpeering/peering.pb.go index 50ab9c849694..5e1efaad4745 100644 --- a/proto/pbpeering/peering.pb.go +++ b/proto/pbpeering/peering.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto/pbpeering/peering.proto @@ -107,6 +107,7 @@ type SecretsWriteRequest struct { // PeerID is the local UUID of the peering this request applies to. PeerID string `protobuf:"bytes,1,opt,name=PeerID,proto3" json:"PeerID,omitempty"` // Types that are assignable to Request: + // // *SecretsWriteRequest_GenerateToken // *SecretsWriteRequest_ExchangeSecret // *SecretsWriteRequest_PromotePending @@ -332,6 +333,9 @@ type Peering struct { ModifyIndex uint64 `protobuf:"varint,12,opt,name=ModifyIndex,proto3" json:"ModifyIndex,omitempty" bexpr:"-"` // Remote contains metadata about the remote peer. Remote *RemoteInfo `protobuf:"bytes,17,opt,name=Remote,proto3" json:"Remote,omitempty"` + // ManualServerAddresses provides a list of manually specified server addresses from the + // user. If this is defined, then the automatic PeerServerAddresses are ignored. + ManualServerAddresses []string `protobuf:"bytes,18,rep,name=ManualServerAddresses,proto3" json:"ManualServerAddresses,omitempty"` } func (x *Peering) Reset() { @@ -464,6 +468,13 @@ func (x *Peering) GetRemote() *RemoteInfo { return nil } +func (x *Peering) GetManualServerAddresses() []string { + if x != nil { + return x.ManualServerAddresses + } + return nil +} + // mog annotation: // // target=github.com/hashicorp/consul/api.PeeringRemoteInfo @@ -766,7 +777,6 @@ func (x *PeeringServerAddresses) GetAddresses() []string { return nil } -// @consul-rpc-glue: LeaderReadTODO type PeeringReadRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -869,7 +879,6 @@ func (x *PeeringReadResponse) GetPeering() *Peering { return nil } -// @consul-rpc-glue: LeaderReadTODO type PeeringListRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -922,8 +931,8 @@ type PeeringListResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Peerings []*Peering `protobuf:"bytes,1,rep,name=Peerings,proto3" json:"Peerings,omitempty"` - Index uint64 `protobuf:"varint,2,opt,name=Index,proto3" json:"Index,omitempty"` + Peerings []*Peering `protobuf:"bytes,1,rep,name=Peerings,proto3" json:"Peerings,omitempty"` + OBSOLETE_Index uint64 `protobuf:"varint,2,opt,name=OBSOLETE_Index,json=OBSOLETEIndex,proto3" json:"OBSOLETE_Index,omitempty"` // Deprecated in favor of gRPC metadata } func (x *PeeringListResponse) Reset() { @@ -965,9 +974,9 @@ func (x *PeeringListResponse) GetPeerings() []*Peering { return nil } -func (x *PeeringListResponse) GetIndex() uint64 { +func (x *PeeringListResponse) GetOBSOLETE_Index() uint64 { if x != nil { - return x.Index + return x.OBSOLETE_Index } return 0 } @@ -1247,8 +1256,8 @@ type TrustBundleListByServiceResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Index uint64 `protobuf:"varint,1,opt,name=Index,proto3" json:"Index,omitempty"` - Bundles []*PeeringTrustBundle `protobuf:"bytes,2,rep,name=Bundles,proto3" json:"Bundles,omitempty"` + OBSOLETE_Index uint64 `protobuf:"varint,1,opt,name=OBSOLETE_Index,json=OBSOLETEIndex,proto3" json:"OBSOLETE_Index,omitempty"` // Deprecated in favor of gRPC metadata + Bundles []*PeeringTrustBundle `protobuf:"bytes,2,rep,name=Bundles,proto3" json:"Bundles,omitempty"` } func (x *TrustBundleListByServiceResponse) Reset() { @@ -1283,9 +1292,9 @@ func (*TrustBundleListByServiceResponse) Descriptor() ([]byte, []int) { return file_proto_pbpeering_peering_proto_rawDescGZIP(), []int{16} } -func (x *TrustBundleListByServiceResponse) GetIndex() uint64 { +func (x *TrustBundleListByServiceResponse) GetOBSOLETE_Index() uint64 { if x != nil { - return x.Index + return x.OBSOLETE_Index } return 0 } @@ -1357,8 +1366,8 @@ type TrustBundleReadResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Index uint64 `protobuf:"varint,1,opt,name=Index,proto3" json:"Index,omitempty"` - Bundle *PeeringTrustBundle `protobuf:"bytes,2,opt,name=Bundle,proto3" json:"Bundle,omitempty"` + OBSOLETE_Index uint64 `protobuf:"varint,1,opt,name=OBSOLETE_Index,json=OBSOLETEIndex,proto3" json:"OBSOLETE_Index,omitempty"` // Deprecated in favor of gRPC metadata + Bundle *PeeringTrustBundle `protobuf:"bytes,2,opt,name=Bundle,proto3" json:"Bundle,omitempty"` } func (x *TrustBundleReadResponse) Reset() { @@ -1393,9 +1402,9 @@ func (*TrustBundleReadResponse) Descriptor() ([]byte, []int) { return file_proto_pbpeering_peering_proto_rawDescGZIP(), []int{18} } -func (x *TrustBundleReadResponse) GetIndex() uint64 { +func (x *TrustBundleReadResponse) GetOBSOLETE_Index() uint64 { if x != nil { - return x.Index + return x.OBSOLETE_Index } return 0 } @@ -1687,6 +1696,10 @@ type GenerateTokenRequest struct { Partition string `protobuf:"bytes,2,opt,name=Partition,proto3" json:"Partition,omitempty"` // Meta is a mapping of some string value to any other string value Meta map[string]string `protobuf:"bytes,5,rep,name=Meta,proto3" json:"Meta,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // ServerExternalAddresses is a list of addresses to put into the generated token. This could be used to specify + // load balancer(s) or external IPs to reach the servers from the dialing side, and will override any server + // addresses obtained from the "consul" service. + ServerExternalAddresses []string `protobuf:"bytes,6,rep,name=ServerExternalAddresses,proto3" json:"ServerExternalAddresses,omitempty"` } func (x *GenerateTokenRequest) Reset() { @@ -1742,6 +1755,13 @@ func (x *GenerateTokenRequest) GetMeta() map[string]string { return nil } +func (x *GenerateTokenRequest) GetServerExternalAddresses() []string { + if x != nil { + return x.ServerExternalAddresses + } + return nil +} + // mog annotation: // // target=github.com/hashicorp/consul/api.PeeringGenerateTokenResponse @@ -2335,7 +2355,7 @@ var file_proto_pbpeering_peering_proto_rawDesc = []byte{ 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x49, 0x44, 0x12, 0x28, 0x0a, 0x0f, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x49, 0x44, 0x22, 0xc1, 0x05, 0x0a, 0x07, 0x50, 0x65, 0x65, + 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x49, 0x44, 0x22, 0xf7, 0x05, 0x0a, 0x07, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, @@ -2376,284 +2396,295 @@ var file_proto_pbpeering_peering_proto_rawDesc = []byte{ 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x52, 0x65, 0x6d, - 0x6f, 0x74, 0x65, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x4a, 0x0a, 0x0a, - 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, - 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, - 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x44, 0x61, 0x74, 0x61, - 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x44, 0x61, - 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x9e, 0x02, 0x0a, 0x0c, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x49, 0x6d, 0x70, - 0x6f, 0x72, 0x74, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x10, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, - 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x10, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x12, 0x40, 0x0a, 0x0d, 0x4c, 0x61, 0x73, 0x74, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, - 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x4c, 0x61, 0x73, 0x74, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, - 0x65, 0x61, 0x74, 0x12, 0x3c, 0x0a, 0x0b, 0x4c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, - 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x4c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, - 0x65, 0x12, 0x36, 0x0a, 0x08, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x6e, 0x64, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, - 0x08, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x6e, 0x64, 0x22, 0xfe, 0x01, 0x0a, 0x12, 0x50, 0x65, - 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, - 0x12, 0x20, 0x0a, 0x0b, 0x54, 0x72, 0x75, 0x73, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x54, 0x72, 0x75, 0x73, 0x74, 0x44, 0x6f, 0x6d, 0x61, - 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, - 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, - 0x52, 0x6f, 0x6f, 0x74, 0x50, 0x45, 0x4d, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, - 0x52, 0x6f, 0x6f, 0x74, 0x50, 0x45, 0x4d, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x45, 0x78, 0x70, 0x6f, - 0x72, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x11, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x20, 0x0a, 0x0b, 0x4d, 0x6f, 0x64, 0x69, - 0x66, 0x79, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x4d, - 0x6f, 0x64, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x36, 0x0a, 0x16, 0x50, 0x65, - 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x22, 0x46, 0x0a, 0x12, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, - 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x5b, 0x0a, 0x13, 0x50, 0x65, - 0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x44, 0x0a, 0x07, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, - 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, - 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x07, - 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x32, 0x0a, 0x12, 0x50, 0x65, 0x65, 0x72, 0x69, - 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, - 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x73, 0x0a, 0x13, 0x50, - 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x46, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, + 0x6f, 0x74, 0x65, 0x12, 0x34, 0x0a, 0x15, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x12, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x15, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, 0x74, + 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x4a, 0x0a, 0x0a, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, + 0x0a, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x9e, + 0x02, 0x0a, 0x0c, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x2a, 0x0a, 0x10, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x49, 0x6d, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x45, + 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x0d, 0x4c, 0x61, 0x73, 0x74, 0x48, + 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x4c, 0x61, 0x73, 0x74, + 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x3c, 0x0a, 0x0b, 0x4c, 0x61, 0x73, + 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x4c, 0x61, 0x73, 0x74, + 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x12, 0x36, 0x0a, 0x08, 0x4c, 0x61, 0x73, 0x74, 0x53, + 0x65, 0x6e, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x6e, 0x64, 0x22, + 0xfe, 0x01, 0x0a, 0x12, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x54, 0x72, 0x75, 0x73, 0x74, 0x44, + 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, + 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x6f, 0x6f, 0x74, 0x50, 0x45, 0x4d, 0x73, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x52, 0x6f, 0x6f, 0x74, 0x50, 0x45, 0x4d, 0x73, 0x12, 0x2c, + 0x0a, 0x11, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x45, 0x78, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x20, + 0x0a, 0x0b, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0b, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x22, 0x36, 0x0a, 0x16, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x46, 0x0a, 0x12, 0x50, 0x65, 0x65, 0x72, + 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x5b, 0x0a, 0x13, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x07, 0x50, 0x65, 0x65, 0x72, 0x69, + 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, + 0x72, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x32, 0x0a, + 0x12, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x84, 0x01, 0x0a, 0x13, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x08, 0x50, 0x65, 0x65, + 0x72, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x68, 0x61, + 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, + 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, + 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x4f, 0x42, 0x53, 0x4f, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x49, 0x6e, + 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x4f, 0x42, 0x53, 0x4f, 0x4c, + 0x45, 0x54, 0x45, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0xca, 0x02, 0x0a, 0x13, 0x50, 0x65, 0x65, + 0x72, 0x69, 0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x44, 0x0a, 0x07, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, + 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, + 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x50, + 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x5e, 0x0a, 0x0e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, + 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, + 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, + 0x6e, 0x67, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, - 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, - 0x22, 0xca, 0x02, 0x0a, 0x13, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x07, 0x50, 0x65, 0x65, 0x72, - 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x68, 0x61, 0x73, 0x68, - 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, - 0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x5e, - 0x0a, 0x0e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, - 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, - 0x74, 0x73, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0e, - 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, - 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x68, - 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, - 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, - 0x4d, 0x65, 0x74, 0x61, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x16, 0x0a, - 0x14, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x48, 0x0a, 0x14, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, + 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, + 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x1a, 0x37, 0x0a, 0x09, + 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x16, 0x0a, 0x14, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, + 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x48, 0x0a, + 0x14, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, + 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, + 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x17, 0x0a, 0x15, 0x50, 0x65, 0x65, 0x72, 0x69, + 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x93, 0x01, 0x0a, 0x1f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, + 0x4c, 0x69, 0x73, 0x74, 0x42, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x22, 0x9a, 0x01, 0x0a, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x79, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x4f, + 0x42, 0x53, 0x4f, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0d, 0x4f, 0x42, 0x53, 0x4f, 0x4c, 0x45, 0x54, 0x45, 0x49, 0x6e, 0x64, + 0x65, 0x78, 0x12, 0x4f, 0x0a, 0x07, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, + 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, + 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x07, 0x42, 0x75, 0x6e, 0x64, + 0x6c, 0x65, 0x73, 0x22, 0x4a, 0x0a, 0x16, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, + 0x6c, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, - 0x17, 0x0a, 0x15, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x93, 0x01, 0x0a, 0x1f, 0x54, 0x72, 0x75, - 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x79, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, - 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, - 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x4b, 0x69, - 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x22, 0x89, - 0x01, 0x0a, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, - 0x73, 0x74, 0x42, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x4f, 0x0a, 0x07, 0x42, 0x75, 0x6e, - 0x64, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, - 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, - 0x65, 0x52, 0x07, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x22, 0x4a, 0x0a, 0x16, 0x54, 0x72, - 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, - 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x7e, 0x0a, 0x17, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, - 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x4d, 0x0a, 0x06, 0x42, 0x75, 0x6e, 0x64, 0x6c, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, - 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, - 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x06, - 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0x2d, 0x0a, 0x1b, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, - 0x67, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x49, 0x44, 0x22, 0x1e, 0x0a, 0x1c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, - 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x87, 0x01, 0x0a, 0x1e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, - 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x57, 0x72, 0x69, 0x74, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x65, 0x0a, 0x12, 0x50, 0x65, 0x65, 0x72, - 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, - 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, - 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, - 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x12, 0x50, 0x65, 0x65, - 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, - 0x21, 0x0a, 0x1f, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, - 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x53, 0x0a, 0x1f, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, + 0x8f, 0x01, 0x0a, 0x17, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, + 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x4f, + 0x42, 0x53, 0x4f, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0d, 0x4f, 0x42, 0x53, 0x4f, 0x4c, 0x45, 0x54, 0x45, 0x49, 0x6e, 0x64, + 0x65, 0x78, 0x12, 0x4d, 0x0a, 0x06, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, + 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, + 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x06, 0x42, 0x75, 0x6e, 0x64, 0x6c, + 0x65, 0x22, 0x2d, 0x0a, 0x1b, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x72, 0x6d, + 0x69, 0x6e, 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, + 0x22, 0x1e, 0x0a, 0x1c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x72, 0x6d, 0x69, + 0x6e, 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x87, 0x01, 0x0a, 0x1e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x65, 0x0a, 0x12, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, + 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, + 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x12, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x50, 0x65, + 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, + 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x53, 0x0a, + 0x1f, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, + 0x64, 0x6c, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x22, 0x22, 0x0a, 0x20, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, - 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, - 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x22, 0x0a, 0x20, 0x50, 0x65, 0x65, 0x72, 0x69, - 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xe0, 0x01, 0x0a, 0x14, - 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x55, - 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x68, - 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, - 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x04, 0x4d, 0x65, 0x74, 0x61, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x3b, - 0x0a, 0x15, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, - 0x6e, 0x67, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x50, - 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xfc, 0x01, 0x0a, 0x10, - 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, - 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x9a, 0x02, 0x0a, 0x14, 0x47, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x1a, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, + 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x55, 0x0a, 0x04, 0x4d, 0x65, 0x74, + 0x61, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x47, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, + 0x12, 0x38, 0x0a, 0x17, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x17, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, + 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x22, 0x3b, 0x0a, 0x15, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x0c, + 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x51, - 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x68, - 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, - 0x2e, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x4d, 0x65, 0x74, - 0x61, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x13, 0x0a, 0x11, 0x45, 0x73, - 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, - 0x73, 0x0a, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, - 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, - 0x0a, 0x07, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x45, - 0x53, 0x54, 0x41, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0a, 0x0a, - 0x06, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x41, 0x49, - 0x4c, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x49, - 0x4e, 0x47, 0x10, 0x05, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x45, 0x52, 0x4d, 0x49, 0x4e, 0x41, 0x54, - 0x45, 0x44, 0x10, 0x06, 0x32, 0xc0, 0x08, 0x0a, 0x0e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x82, 0x01, 0x0a, 0x0d, 0x47, 0x65, 0x6e, 0x65, - 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, - 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x47, 0x65, - 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, - 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, - 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x76, 0x0a, 0x09, - 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x33, 0x2e, 0x68, 0x61, 0x73, 0x68, - 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x45, 0x73, - 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, + 0x22, 0xfc, 0x01, 0x0a, 0x10, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x51, 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x3d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, + 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, + 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, + 0x13, 0x0a, 0x11, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x73, 0x0a, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, + 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x53, 0x54, 0x41, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x49, 0x4e, 0x47, + 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x03, 0x12, 0x0b, + 0x0a, 0x07, 0x46, 0x41, 0x49, 0x4c, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x44, + 0x45, 0x4c, 0x45, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x05, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x45, 0x52, + 0x4d, 0x49, 0x4e, 0x41, 0x54, 0x45, 0x44, 0x10, 0x06, 0x32, 0xc0, 0x08, 0x0a, 0x0e, 0x50, 0x65, + 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x82, 0x01, 0x0a, + 0x0d, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x37, + 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, + 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, + 0x6e, 0x67, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x47, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x76, 0x0a, 0x09, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x33, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, - 0x6e, 0x67, 0x2e, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7c, 0x0a, 0x0b, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, - 0x65, 0x61, 0x64, 0x12, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, + 0x6e, 0x67, 0x2e, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, - 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, - 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x68, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, - 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x7c, 0x0a, 0x0b, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, - 0x74, 0x12, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, - 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, - 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, + 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7c, 0x0a, 0x0b, 0x50, 0x65, 0x65, + 0x72, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x12, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, - 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x82, 0x01, 0x0a, 0x0d, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x12, 0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, - 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, - 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x68, 0x61, - 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, - 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7f, 0x0a, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, - 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, - 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, - 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, + 0x72, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, + 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, + 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7c, 0x0a, 0x0b, 0x50, 0x65, 0x65, 0x72, 0x69, + 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, + 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, + 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, - 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa3, 0x01, 0x0a, 0x18, 0x54, 0x72, 0x75, 0x73, 0x74, - 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x79, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x12, 0x42, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, - 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, - 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, - 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x43, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x82, 0x01, 0x0a, 0x0d, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, + 0x67, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x54, 0x72, 0x75, 0x73, - 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x79, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x88, 0x01, 0x0a, - 0x0f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x61, 0x64, - 0x12, 0x39, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, + 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, + 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x38, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, + 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, + 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7f, 0x0a, 0x0c, 0x50, 0x65, + 0x65, 0x72, 0x69, 0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x36, 0x2e, 0x68, 0x61, 0x73, + 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, + 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, + 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, + 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x57, 0x72, + 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa3, 0x01, 0x0a, 0x18, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, + 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x42, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x79, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x43, 0x2e, 0x68, + 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, + 0x2e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, + 0x42, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x88, 0x01, 0x0a, 0x0f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, + 0x65, 0x52, 0x65, 0x61, 0x64, 0x12, 0x39, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, + 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, + 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x3a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, - 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, 0x68, 0x61, - 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, - 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x8a, 0x02, 0x0a, 0x25, 0x63, 0x6f, 0x6d, 0x2e, - 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, - 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, - 0x67, 0x42, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, - 0x01, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, - 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0xa2, 0x02, - 0x04, 0x48, 0x43, 0x49, 0x50, 0xaa, 0x02, 0x21, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, - 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0xca, 0x02, 0x21, 0x48, 0x61, 0x73, 0x68, - 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x49, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0xe2, 0x02, 0x2d, - 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, - 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, - 0x67, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x24, - 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, - 0x6c, 0x3a, 0x3a, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x3a, 0x3a, 0x50, 0x65, 0x65, - 0x72, 0x69, 0x6e, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x8a, 0x02, 0x0a, + 0x25, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, + 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, + 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x42, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, + 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x70, 0x65, 0x65, 0x72, + 0x69, 0x6e, 0x67, 0xa2, 0x02, 0x04, 0x48, 0x43, 0x49, 0x50, 0xaa, 0x02, 0x21, 0x48, 0x61, 0x73, + 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0xca, 0x02, + 0x21, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, + 0x6c, 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5c, 0x50, 0x65, 0x65, 0x72, 0x69, + 0x6e, 0x67, 0xe2, 0x02, 0x2d, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, + 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5c, 0x50, + 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0xea, 0x02, 0x24, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, + 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x3a, 0x3a, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/proto/pbpeering/peering.proto b/proto/pbpeering/peering.proto index a2318319721b..21a5b06ba2b4 100644 --- a/proto/pbpeering/peering.proto +++ b/proto/pbpeering/peering.proto @@ -198,6 +198,10 @@ message Peering { // Remote contains metadata about the remote peer. RemoteInfo Remote = 17; + + // ManualServerAddresses provides a list of manually specified server addresses from the + // user. If this is defined, then the automatic PeerServerAddresses are ignored. + repeated string ManualServerAddresses = 18; } // RemoteInfo contains metadata about the remote peer. @@ -265,7 +269,6 @@ message PeeringServerAddresses { repeated string Addresses = 1; } -// @consul-rpc-glue: LeaderReadTODO message PeeringReadRequest { string Name = 1; string Partition = 2; @@ -275,14 +278,13 @@ message PeeringReadResponse { Peering Peering = 1; } -// @consul-rpc-glue: LeaderReadTODO message PeeringListRequest { string Partition = 1; } message PeeringListResponse { repeated Peering Peerings = 1; - uint64 Index = 2; + uint64 OBSOLETE_Index = 2; // Deprecated in favor of gRPC metadata } message PeeringWriteRequest { @@ -316,7 +318,7 @@ message TrustBundleListByServiceRequest { } message TrustBundleListByServiceResponse { - uint64 Index = 1; + uint64 OBSOLETE_Index = 1; // Deprecated in favor of gRPC metadata repeated PeeringTrustBundle Bundles = 2; } @@ -326,7 +328,7 @@ message TrustBundleReadRequest { } message TrustBundleReadResponse { - uint64 Index = 1; + uint64 OBSOLETE_Index = 1; // Deprecated in favor of gRPC metadata PeeringTrustBundle Bundle = 2; } @@ -365,6 +367,11 @@ message GenerateTokenRequest { // Meta is a mapping of some string value to any other string value map Meta = 5; + + // ServerExternalAddresses is a list of addresses to put into the generated token. This could be used to specify + // load balancer(s) or external IPs to reach the servers from the dialing side, and will override any server + // addresses obtained from the "consul" service. + repeated string ServerExternalAddresses = 6; } // mog annotation: diff --git a/proto/pbpeering/peering.rpcglue.pb.go b/proto/pbpeering/peering.rpcglue.pb.go deleted file mode 100644 index 1e6f94ce5d30..000000000000 --- a/proto/pbpeering/peering.rpcglue.pb.go +++ /dev/null @@ -1,89 +0,0 @@ -// Code generated by proto-gen-rpc-glue. DO NOT EDIT. - -package pbpeering - -import ( - "time" - - "github.com/hashicorp/consul/agent/structs" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ structs.RPCInfo -var _ time.Month - -// IsRead implements structs.RPCInfo -func (msg *PeeringReadRequest) IsRead() bool { - // TODO(peering): figure out read semantics here - return true -} - -// AllowStaleRead implements structs.RPCInfo -func (msg *PeeringReadRequest) AllowStaleRead() bool { - // TODO(peering): figure out read semantics here - // TODO(peering): this needs to stay false for calls to head to the leader until we sync stream tracker information - // like ImportedServicesCount, ExportedServicesCount, as well as general Status fields thru raft to make available - // to followers as well - return false -} - -// HasTimedOut implements structs.RPCInfo -func (msg *PeeringReadRequest) HasTimedOut(start time.Time, rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) (bool, error) { - // TODO(peering): figure out read semantics here - return time.Since(start) > rpcHoldTimeout, nil -} - -// SetTokenSecret implements structs.RPCInfo -func (msg *PeeringReadRequest) SetTokenSecret(s string) { - // TODO(peering): figure out read semantics here -} - -// TokenSecret implements structs.RPCInfo -func (msg *PeeringReadRequest) TokenSecret() string { - // TODO(peering): figure out read semantics here - return "" -} - -// Token implements structs.RPCInfo -func (msg *PeeringReadRequest) Token() string { - // TODO(peering): figure out read semantics here - return "" -} - -// IsRead implements structs.RPCInfo -func (msg *PeeringListRequest) IsRead() bool { - // TODO(peering): figure out read semantics here - return true -} - -// AllowStaleRead implements structs.RPCInfo -func (msg *PeeringListRequest) AllowStaleRead() bool { - // TODO(peering): figure out read semantics here - // TODO(peering): this needs to stay false for calls to head to the leader until we sync stream tracker information - // like ImportedServicesCount, ExportedServicesCount, as well as general Status fields thru raft to make available - // to followers as well - return false -} - -// HasTimedOut implements structs.RPCInfo -func (msg *PeeringListRequest) HasTimedOut(start time.Time, rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) (bool, error) { - // TODO(peering): figure out read semantics here - return time.Since(start) > rpcHoldTimeout, nil -} - -// SetTokenSecret implements structs.RPCInfo -func (msg *PeeringListRequest) SetTokenSecret(s string) { - // TODO(peering): figure out read semantics here -} - -// TokenSecret implements structs.RPCInfo -func (msg *PeeringListRequest) TokenSecret() string { - // TODO(peering): figure out read semantics here - return "" -} - -// Token implements structs.RPCInfo -func (msg *PeeringListRequest) Token() string { - // TODO(peering): figure out read semantics here - return "" -} diff --git a/proto/pbpeering/peering_oss.go b/proto/pbpeering/peering_ce.go similarity index 100% rename from proto/pbpeering/peering_oss.go rename to proto/pbpeering/peering_ce.go diff --git a/proto/pbpeerstream/peerstream.pb.go b/proto/pbpeerstream/peerstream.pb.go index d45ca3397906..fba10fef62db 100644 --- a/proto/pbpeerstream/peerstream.pb.go +++ b/proto/pbpeerstream/peerstream.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto/pbpeerstream/peerstream.proto @@ -78,6 +78,7 @@ type ReplicationMessage struct { unknownFields protoimpl.UnknownFields // Types that are assignable to Payload: + // // *ReplicationMessage_Open_ // *ReplicationMessage_Request_ // *ReplicationMessage_Response_ diff --git a/proto/pbservice/convert_oss.go b/proto/pbservice/convert_ce.go similarity index 100% rename from proto/pbservice/convert_oss.go rename to proto/pbservice/convert_ce.go diff --git a/proto/pbservice/convert_oss_test.go b/proto/pbservice/convert_ce_test.go similarity index 100% rename from proto/pbservice/convert_oss_test.go rename to proto/pbservice/convert_ce_test.go diff --git a/proto/pbservice/healthcheck.pb.go b/proto/pbservice/healthcheck.pb.go index d4dc1544e079..31e082b85279 100644 --- a/proto/pbservice/healthcheck.pb.go +++ b/proto/pbservice/healthcheck.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto/pbservice/healthcheck.proto diff --git a/proto/pbservice/node.pb.go b/proto/pbservice/node.pb.go index 6d0ebfacfb4a..cebee359f567 100644 --- a/proto/pbservice/node.pb.go +++ b/proto/pbservice/node.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto/pbservice/node.proto diff --git a/proto/pbservice/service.pb.go b/proto/pbservice/service.pb.go index 6ad9ea5394ab..9f8ee1269267 100644 --- a/proto/pbservice/service.pb.go +++ b/proto/pbservice/service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto/pbservice/service.proto diff --git a/proto/pbstatus/status.pb.go b/proto/pbstatus/status.pb.go index c69c57cbf2c8..bdc5b70d798e 100644 --- a/proto/pbstatus/status.pb.go +++ b/proto/pbstatus/status.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto/pbstatus/status.proto diff --git a/proto/pbsubscribe/subscribe.pb.go b/proto/pbsubscribe/subscribe.pb.go index 5d209df9a8f5..0077cff3a942 100644 --- a/proto/pbsubscribe/subscribe.pb.go +++ b/proto/pbsubscribe/subscribe.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0-rc.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: proto/pbsubscribe/subscribe.proto @@ -46,7 +46,7 @@ const ( Topic_MeshConfig Topic = 3 // ServiceResolver topic contains events for changes to a service resolver. Topic_ServiceResolver Topic = 4 - // ServiceResolver topic contains events for changes to an ingress gateway. + // IngressGateway topic contains events for changes to an ingress gateway. Topic_IngressGateway Topic = 5 // ServiceIntentions topic contains events for changes to service intentions. Topic_ServiceIntentions Topic = 6 @@ -56,6 +56,8 @@ const ( // // Note: WildcardSubject is the only supported Subject on this topic. Topic_ServiceList Topic = 7 + // ServiceDefaults topic contains events for changes to service-defaults. + Topic_ServiceDefaults Topic = 8 ) // Enum value maps for Topic. @@ -69,6 +71,7 @@ var ( 5: "IngressGateway", 6: "ServiceIntentions", 7: "ServiceList", + 8: "ServiceDefaults", } Topic_value = map[string]int32{ "Unknown": 0, @@ -79,6 +82,7 @@ var ( "IngressGateway": 5, "ServiceIntentions": 6, "ServiceList": 7, + "ServiceDefaults": 8, } ) @@ -320,6 +324,7 @@ type SubscribeRequest struct { // receive events (e.g. health events for a particular service). // // Types that are assignable to Subject: + // // *SubscribeRequest_WildcardSubject // *SubscribeRequest_NamedSubject Subject isSubscribeRequest_Subject `protobuf_oneof:"Subject"` @@ -471,6 +476,7 @@ type Event struct { // Payload is the actual event content. // // Types that are assignable to Payload: + // // *Event_EndOfSnapshot // *Event_NewSnapshotToFollow // *Event_EventBatch @@ -955,7 +961,7 @@ var file_proto_pbsubscribe_subscribe_proto_rawDesc = []byte{ 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x0e, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x2a, 0xa2, 0x01, 0x0a, 0x05, 0x54, + 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x2a, 0xb7, 0x01, 0x0a, 0x05, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x48, @@ -965,26 +971,27 @@ var file_proto_pbsubscribe_subscribe_proto_rawDesc = []byte{ 0x72, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x10, 0x05, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x10, 0x06, 0x12, 0x0f, - 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x10, 0x07, 0x2a, - 0x29, 0x0a, 0x09, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x4f, 0x70, 0x12, 0x0c, 0x0a, 0x08, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x65, - 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x10, 0x01, 0x32, 0x59, 0x0a, 0x17, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x62, 0x65, 0x12, 0x1b, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x53, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x10, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x22, 0x00, 0x30, 0x01, 0x42, 0x92, 0x01, 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x75, - 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x42, 0x0e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x62, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, - 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x73, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0xa2, 0x02, 0x03, 0x53, 0x58, 0x58, 0xaa, 0x02, - 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0xca, 0x02, 0x09, 0x53, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0xe2, 0x02, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x62, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, - 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x10, 0x07, 0x12, + 0x13, 0x0a, 0x0f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x73, 0x10, 0x08, 0x2a, 0x29, 0x0a, 0x09, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x4f, + 0x70, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x10, 0x00, 0x12, + 0x0e, 0x0a, 0x0a, 0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x10, 0x01, 0x32, + 0x59, 0x0a, 0x17, 0x53, 0x74, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x09, 0x53, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x1b, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x62, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, + 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x00, 0x30, 0x01, 0x42, 0x92, 0x01, 0x0a, 0x0d, 0x63, + 0x6f, 0x6d, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x42, 0x0e, 0x53, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2d, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2f, 0x70, 0x62, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0xa2, 0x02, 0x03, + 0x53, 0x58, 0x58, 0xaa, 0x02, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0xca, + 0x02, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0xe2, 0x02, 0x15, 0x53, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0xea, 0x02, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/pbsubscribe/subscribe.proto b/proto/pbsubscribe/subscribe.proto index e68a0cecc3ab..c1b3e82ebb20 100644 --- a/proto/pbsubscribe/subscribe.proto +++ b/proto/pbsubscribe/subscribe.proto @@ -58,7 +58,7 @@ enum Topic { // ServiceResolver topic contains events for changes to a service resolver. ServiceResolver = 4; - // ServiceResolver topic contains events for changes to an ingress gateway. + // IngressGateway topic contains events for changes to an ingress gateway. IngressGateway = 5; // ServiceIntentions topic contains events for changes to service intentions. @@ -70,6 +70,9 @@ enum Topic { // // Note: WildcardSubject is the only supported Subject on this topic. ServiceList = 7; + + // ServiceDefaults topic contains events for changes to service-defaults. + ServiceDefaults = 8; } message NamedSubject { diff --git a/proto/prototest/testing.go b/proto/prototest/testing.go index bf25fb0a10e0..f128e5074725 100644 --- a/proto/prototest/testing.go +++ b/proto/prototest/testing.go @@ -26,14 +26,25 @@ func AssertDeepEqual(t testing.TB, x, y interface{}, opts ...cmp.Option) { func AssertElementsMatch[V any]( t testing.TB, listX, listY []V, opts ...cmp.Option, ) { - t.Helper() + diff := diffElements(listX, listY, opts...) + if diff != "" { + t.Fatalf("assertion failed: slices do not have matching elements\n--- expected\n+++ actual\n%v", diff) + } +} +func diffElements[V any]( + listX, listY []V, opts ...cmp.Option, +) string { if len(listX) == 0 && len(listY) == 0 { - return + return "" } opts = append(opts, protocmp.Transform()) + if len(listX) != len(listY) { + return cmp.Diff(listX, listY, opts...) + } + // dump into a map keyed by sliceID mapX := make(map[int]V) for i, val := range listX { @@ -57,8 +68,8 @@ func AssertElementsMatch[V any]( } } - if len(outX) == len(outY) && len(listX) == len(listY) { - return // matches + if len(outX) == len(listX) && len(outY) == len(listY) { + return "" // matches } // dump remainder into the slice so we can generate a useful error @@ -69,7 +80,5 @@ func AssertElementsMatch[V any]( outY = append(outY, itemY) } - if diff := cmp.Diff(outX, outY, opts...); diff != "" { - t.Fatalf("assertion failed: slices do not have matching elements\n--- expected\n+++ actual\n%v", diff) - } + return cmp.Diff(outX, outY, opts...) } diff --git a/proto/prototest/testing_test.go b/proto/prototest/testing_test.go new file mode 100644 index 000000000000..22c1848821dd --- /dev/null +++ b/proto/prototest/testing_test.go @@ -0,0 +1,103 @@ +package prototest + +import ( + "strconv" + "testing" + + "github.com/stretchr/testify/require" +) + +type wrap struct { + V int + O string +} + +func (w *wrap) String() string { + return strconv.Itoa(w.V) +} + +func (w *wrap) GoString() string { + return w.String() +} + +func TestDiffElements_noProtobufs(t *testing.T) { + // NOTE: this test only tests non-protobuf slices initially + + type testcase struct { + a, b []*wrap + notSame bool + } + + run := func(t *testing.T, tc testcase) { + diff := diffElements(tc.a, tc.b) + if tc.notSame { + require.False(t, diff == "", "expected not to be the same") + } else { + require.True(t, diff == "", "expected to be the same") + } + } + + w := func(v int) *wrap { + return &wrap{V: v} + } + + cases := map[string]testcase{ + "nil": {}, + "empty": {a: []*wrap{}, b: []*wrap{}}, + "nil and empty": {a: []*wrap{}, b: nil}, + "ordered match": { + a: []*wrap{w(1), w(22), w(303), w(43004), w(-5)}, + b: []*wrap{w(1), w(22), w(303), w(43004), w(-5)}, + }, + "permuted match": { + a: []*wrap{w(1), w(22), w(303), w(43004), w(-5)}, + b: []*wrap{w(-5), w(43004), w(303), w(22), w(1)}, + }, + "duplicates": { + a: []*wrap{w(1), w(2), w(2), w(3)}, + b: []*wrap{w(2), w(1), w(3), w(2)}, + }, + // no match + "1 vs nil": { + a: []*wrap{w(1)}, + b: nil, + notSame: true, + }, + "1 vs 2": { + a: []*wrap{w(1)}, + b: []*wrap{w(2)}, + notSame: true, + }, + "1,2 vs 2,3": { + a: []*wrap{w(1), w(2)}, + b: []*wrap{w(2), w(3)}, + notSame: true, + }, + "1,2 vs 1,2,3": { + a: []*wrap{w(1), w(2)}, + b: []*wrap{w(1), w(2), w(3)}, + notSame: true, + }, + "duplicates omitted": { + a: []*wrap{w(1), w(2), w(2), w(3)}, + b: []*wrap{w(1), w(3), w(2)}, + notSame: true, + }, + } + + allCases := make(map[string]testcase) + for name, tc := range cases { + allCases[name] = tc + allCases[name+" (flipped)"] = testcase{ + a: tc.b, + b: tc.a, + notSame: tc.notSame, + } + } + + for name, tc := range allCases { + t.Run(name, func(t *testing.T) { + run(t, tc) + }) + } +} diff --git a/sdk/freeport/freeport.go b/sdk/freeport/freeport.go index 6eda1d4279b9..c51ef9815395 100644 --- a/sdk/freeport/freeport.go +++ b/sdk/freeport/freeport.go @@ -76,6 +76,9 @@ var ( // total is the total number of available ports in the block for use. total int + // seededRand is a random generator that is pre-seeded from the current time. + seededRand *rand.Rand + // stopCh is used to signal to background goroutines to terminate. Only // really exists for the safety of reset() during unit tests. stopCh chan struct{} @@ -114,7 +117,7 @@ func initialize() { panic("freeport: block size too big or too many blocks requested") } - rand.Seed(time.Now().UnixNano()) + seededRand = rand.New(rand.NewSource(time.Now().UnixNano())) // This is compatible with go 1.19 but unnecessary in >= go1.20 firstPort, lockLn = alloc() condNotEmpty = sync.NewCond(&mu) @@ -256,7 +259,7 @@ func adjustMaxBlocks() (int, error) { // be automatically released when the application terminates. func alloc() (int, net.Listener) { for i := 0; i < attempts; i++ { - block := int(rand.Int31n(int32(effectiveMaxBlocks))) + block := int(seededRand.Int31n(int32(effectiveMaxBlocks))) firstPort := lowPort + block*blockSize ln, err := net.ListenTCP("tcp", tcpAddr("127.0.0.1", firstPort)) if err != nil { diff --git a/sdk/go.mod b/sdk/go.mod index 18b289a0e8ba..7d53203ba38f 100644 --- a/sdk/go.mod +++ b/sdk/go.mod @@ -1,17 +1,24 @@ module github.com/hashicorp/consul/sdk -go 1.12 +go 1.19 require ( - github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.1 github.com/hashicorp/go-hclog v0.12.0 github.com/hashicorp/go-uuid v1.0.1 - github.com/kr/pretty v0.2.0 // indirect - github.com/mattn/go-isatty v0.0.12 // indirect + github.com/hashicorp/go-version v1.2.1 github.com/pkg/errors v0.8.1 github.com/stretchr/testify v1.4.0 - golang.org/x/sys v0.0.0-20220412211240-33da011f77ad + golang.org/x/sys v0.10.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fatih/color v1.9.0 // indirect + github.com/kr/pretty v0.2.0 // indirect + github.com/mattn/go-colorable v0.1.4 // indirect + github.com/mattn/go-isatty v0.0.12 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/yaml.v2 v2.2.8 // indirect ) diff --git a/sdk/go.sum b/sdk/go.sum index 94ec34ba4f2c..4ae643f2a586 100644 --- a/sdk/go.sum +++ b/sdk/go.sum @@ -10,6 +10,8 @@ github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tk github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -34,8 +36,8 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/sdk/iptables/iptables.go b/sdk/iptables/iptables.go index 83b5c03a1b26..653fd02b9b54 100644 --- a/sdk/iptables/iptables.go +++ b/sdk/iptables/iptables.go @@ -2,6 +2,7 @@ package iptables import ( "errors" + "fmt" "strconv" ) @@ -30,6 +31,9 @@ type Config struct { // ConsulDNSIP is the IP for Consul DNS to direct DNS queries to. ConsulDNSIP string + // ConsulDNSPort is the port for Consul DNS to direct DNS queries to. + ConsulDNSPort int + // ProxyUserID is the user ID of the proxy process. ProxyUserID string @@ -107,7 +111,7 @@ func Setup(cfg Config) error { cfg.IptablesProvider.AddRule("iptables", "-t", "nat", "-A", ProxyOutputRedirectChain, "-p", "tcp", "-j", "REDIRECT", "--to-port", strconv.Itoa(cfg.ProxyOutboundPort)) // The DNS rules are applied before the rules that directs all TCP traffic, so that the traffic going to port 53 goes through this rule first. - if cfg.ConsulDNSIP != "" { + if cfg.ConsulDNSIP != "" && cfg.ConsulDNSPort == 0 { // Traffic in the DNSChain is directed to the Consul DNS Service IP. cfg.IptablesProvider.AddRule("iptables", "-t", "nat", "-A", DNSChain, "-p", "udp", "--dport", "53", "-j", "DNAT", "--to-destination", cfg.ConsulDNSIP) cfg.IptablesProvider.AddRule("iptables", "-t", "nat", "-A", DNSChain, "-p", "tcp", "--dport", "53", "-j", "DNAT", "--to-destination", cfg.ConsulDNSIP) @@ -115,6 +119,19 @@ func Setup(cfg Config) error { // For outbound TCP and UDP traffic going to port 53 (DNS), jump to the DNSChain. cfg.IptablesProvider.AddRule("iptables", "-t", "nat", "-A", "OUTPUT", "-p", "udp", "--dport", "53", "-j", DNSChain) cfg.IptablesProvider.AddRule("iptables", "-t", "nat", "-A", "OUTPUT", "-p", "tcp", "--dport", "53", "-j", DNSChain) + } else if cfg.ConsulDNSPort != 0 { + consulDNSIP := "127.0.0.1" + if cfg.ConsulDNSIP != "" { + consulDNSIP = cfg.ConsulDNSIP + } + consulDNSHostPort := fmt.Sprintf("%s:%d", consulDNSIP, cfg.ConsulDNSPort) + // Traffic in the DNSChain is directed to the Consul DNS Service IP. + cfg.IptablesProvider.AddRule("iptables", "-t", "nat", "-A", DNSChain, "-p", "udp", "-d", consulDNSIP, "--dport", "53", "-j", "DNAT", "--to-destination", consulDNSHostPort) + cfg.IptablesProvider.AddRule("iptables", "-t", "nat", "-A", DNSChain, "-p", "tcp", "-d", consulDNSIP, "--dport", "53", "-j", "DNAT", "--to-destination", consulDNSHostPort) + + // For outbound TCP and UDP traffic going to port 53 (DNS), jump to the DNSChain. Only redirect traffic that's going to consul's DNS IP. + cfg.IptablesProvider.AddRule("iptables", "-t", "nat", "-A", "OUTPUT", "-p", "udp", "-d", consulDNSIP, "--dport", "53", "-j", DNSChain) + cfg.IptablesProvider.AddRule("iptables", "-t", "nat", "-A", "OUTPUT", "-p", "tcp", "-d", consulDNSIP, "--dport", "53", "-j", DNSChain) } // For outbound TCP traffic jump from OUTPUT chain to PROXY_OUTPUT chain. diff --git a/sdk/iptables/iptables_test.go b/sdk/iptables/iptables_test.go index 1de3122e5527..1c79fdf057b8 100644 --- a/sdk/iptables/iptables_test.go +++ b/sdk/iptables/iptables_test.go @@ -64,6 +64,63 @@ func TestSetup(t *testing.T) { "iptables -t nat -A CONSUL_PROXY_INBOUND -p tcp -j CONSUL_PROXY_IN_REDIRECT", }, }, + { + "Consul DNS port provided", + Config{ + ProxyUserID: "123", + ProxyInboundPort: 20000, + ConsulDNSPort: 8600, + IptablesProvider: &fakeIptablesProvider{}, + }, + []string{ + "iptables -t nat -N CONSUL_PROXY_INBOUND", + "iptables -t nat -N CONSUL_PROXY_IN_REDIRECT", + "iptables -t nat -N CONSUL_PROXY_OUTPUT", + "iptables -t nat -N CONSUL_PROXY_REDIRECT", + "iptables -t nat -N CONSUL_DNS_REDIRECT", + "iptables -t nat -A CONSUL_PROXY_REDIRECT -p tcp -j REDIRECT --to-port 15001", + "iptables -t nat -A CONSUL_DNS_REDIRECT -p udp -d 127.0.0.1 --dport 53 -j DNAT --to-destination 127.0.0.1:8600", + "iptables -t nat -A CONSUL_DNS_REDIRECT -p tcp -d 127.0.0.1 --dport 53 -j DNAT --to-destination 127.0.0.1:8600", + "iptables -t nat -A OUTPUT -p udp -d 127.0.0.1 --dport 53 -j CONSUL_DNS_REDIRECT", + "iptables -t nat -A OUTPUT -p tcp -d 127.0.0.1 --dport 53 -j CONSUL_DNS_REDIRECT", + "iptables -t nat -A OUTPUT -p tcp -j CONSUL_PROXY_OUTPUT", + "iptables -t nat -A CONSUL_PROXY_OUTPUT -m owner --uid-owner 123 -j RETURN", + "iptables -t nat -A CONSUL_PROXY_OUTPUT -d 127.0.0.1/32 -j RETURN", + "iptables -t nat -A CONSUL_PROXY_OUTPUT -j CONSUL_PROXY_REDIRECT", + "iptables -t nat -A CONSUL_PROXY_IN_REDIRECT -p tcp -j REDIRECT --to-port 20000", + "iptables -t nat -A PREROUTING -p tcp -j CONSUL_PROXY_INBOUND", + "iptables -t nat -A CONSUL_PROXY_INBOUND -p tcp -j CONSUL_PROXY_IN_REDIRECT", + }, + }, + { + "Consul DNS IP and port provided", + Config{ + ProxyUserID: "123", + ProxyInboundPort: 20000, + ConsulDNSIP: "10.0.34.16", + ConsulDNSPort: 8600, + IptablesProvider: &fakeIptablesProvider{}, + }, + []string{ + "iptables -t nat -N CONSUL_PROXY_INBOUND", + "iptables -t nat -N CONSUL_PROXY_IN_REDIRECT", + "iptables -t nat -N CONSUL_PROXY_OUTPUT", + "iptables -t nat -N CONSUL_PROXY_REDIRECT", + "iptables -t nat -N CONSUL_DNS_REDIRECT", + "iptables -t nat -A CONSUL_PROXY_REDIRECT -p tcp -j REDIRECT --to-port 15001", + "iptables -t nat -A CONSUL_DNS_REDIRECT -p udp -d 10.0.34.16 --dport 53 -j DNAT --to-destination 10.0.34.16:8600", + "iptables -t nat -A CONSUL_DNS_REDIRECT -p tcp -d 10.0.34.16 --dport 53 -j DNAT --to-destination 10.0.34.16:8600", + "iptables -t nat -A OUTPUT -p udp -d 10.0.34.16 --dport 53 -j CONSUL_DNS_REDIRECT", + "iptables -t nat -A OUTPUT -p tcp -d 10.0.34.16 --dport 53 -j CONSUL_DNS_REDIRECT", + "iptables -t nat -A OUTPUT -p tcp -j CONSUL_PROXY_OUTPUT", + "iptables -t nat -A CONSUL_PROXY_OUTPUT -m owner --uid-owner 123 -j RETURN", + "iptables -t nat -A CONSUL_PROXY_OUTPUT -d 127.0.0.1/32 -j RETURN", + "iptables -t nat -A CONSUL_PROXY_OUTPUT -j CONSUL_PROXY_REDIRECT", + "iptables -t nat -A CONSUL_PROXY_IN_REDIRECT -p tcp -j REDIRECT --to-port 20000", + "iptables -t nat -A PREROUTING -p tcp -j CONSUL_PROXY_INBOUND", + "iptables -t nat -A CONSUL_PROXY_INBOUND -p tcp -j CONSUL_PROXY_IN_REDIRECT", + }, + }, { "proxy outbound port is provided", Config{ diff --git a/sdk/testutil/retry/retry.go b/sdk/testutil/retry/retry.go index 8be5c0f0e43e..23d6b558f34a 100644 --- a/sdk/testutil/retry/retry.go +++ b/sdk/testutil/retry/retry.go @@ -2,14 +2,13 @@ // // A sample retry operation looks like this: // -// func TestX(t *testing.T) { -// retry.Run(t, func(r *retry.R) { -// if err := foo(); err != nil { -// r.Fatal("f: ", err) -// } -// }) -// } -// +// func TestX(t *testing.T) { +// retry.Run(t, func(r *retry.R) { +// if err := foo(); err != nil { +// r.Fatal("f: ", err) +// } +// }) +// } package retry import ( diff --git a/sdk/testutil/server.go b/sdk/testutil/server.go index 928b84299bac..fbe9941f993d 100644 --- a/sdk/testutil/server.go +++ b/sdk/testutil/server.go @@ -12,6 +12,7 @@ package testutil // otherwise cause an import cycle. import ( + "bytes" "context" "encoding/json" "fmt" @@ -31,6 +32,7 @@ import ( "github.com/hashicorp/go-cleanhttp" "github.com/hashicorp/go-uuid" + "github.com/hashicorp/go-version" "github.com/pkg/errors" "github.com/hashicorp/consul/sdk/freeport" @@ -151,17 +153,17 @@ type ServerConfigCallback func(c *TestServerConfig) // defaultServerConfig returns a new TestServerConfig struct // with all of the listen ports incremented by one. -func defaultServerConfig(t TestingTB) *TestServerConfig { +func defaultServerConfig(t TestingTB, consulVersion *version.Version) *TestServerConfig { nodeID, err := uuid.GenerateUUID() if err != nil { panic(err) } - ports := freeport.GetN(t, 8) + ports := freeport.GetN(t, 7) logBuffer := NewLogBuffer(t) - return &TestServerConfig{ + conf := &TestServerConfig{ NodeName: "node-" + nodeID, NodeID: nodeID, DisableCheckpoint: true, @@ -181,7 +183,6 @@ func defaultServerConfig(t TestingTB) *TestServerConfig { SerfWan: ports[4], Server: ports[5], GRPC: ports[6], - GRPCTLS: ports[7], }, ReadyTimeout: 10 * time.Second, StopTimeout: 10 * time.Second, @@ -197,6 +198,17 @@ func defaultServerConfig(t TestingTB) *TestServerConfig { Stderr: logBuffer, Peering: &TestPeeringConfig{Enabled: true}, } + + // Add version-specific tweaks + if consulVersion != nil { + // The GRPC TLS port did not exist prior to Consul 1.14 + // Including it will cause issues in older installations. + if consulVersion.GreaterThanOrEqual(version.Must(version.NewVersion("1.14"))) { + conf.Ports.GRPCTLS = freeport.GetOne(t) + } + } + + return conf } // TestService is used to serialize a service definition. @@ -260,7 +272,12 @@ func NewTestServerConfigT(t TestingTB, cb ServerConfigCallback) (*TestServer, er return nil, errors.Wrap(err, "failed to create tempdir") } - cfg := defaultServerConfig(t) + consulVersion, err := findConsulVersion() + if err != nil { + return nil, err + } + + cfg := defaultServerConfig(t, consulVersion) cfg.DataDir = filepath.Join(tmpdir, "data") if cb != nil { cb(cfg) @@ -331,7 +348,13 @@ func NewTestServerConfigT(t TestingTB, cb ServerConfigCallback) (*TestServer, er // Stop stops the test Consul server, and removes the Consul data // directory once we are done. func (s *TestServer) Stop() error { - defer os.RemoveAll(s.tmpdir) + defer func() { + if noCleanup { + fmt.Println("skipping cleanup because TEST_NOCLEANUP was enabled") + } else { + os.RemoveAll(s.tmpdir) + } + }() // There was no process if s.cmd == nil { @@ -565,3 +588,26 @@ func (s *TestServer) privilegedDelete(url string) (*http.Response, error) { } return s.HTTPClient.Do(req) } + +func findConsulVersion() (*version.Version, error) { + cmd := exec.Command("consul", "version", "-format=json") + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + if err := cmd.Start(); err != nil { + return nil, errors.Wrap(err, "failed to get consul version") + } + cmd.Wait() + type consulVersion struct { + Version string + } + v := consulVersion{} + if err := json.Unmarshal(stdout.Bytes(), &v); err != nil { + return nil, errors.Wrap(err, "error parsing consul version json") + } + parsed, err := version.NewVersion(v.Version) + if err != nil { + return nil, errors.Wrap(err, "error parsing consul version") + } + return parsed, nil +} diff --git a/sdk/testutil/server_wrapper.go b/sdk/testutil/server_wrapper.go index 5d963a2736fe..6d847f60c131 100644 --- a/sdk/testutil/server_wrapper.go +++ b/sdk/testutil/server_wrapper.go @@ -11,8 +11,8 @@ type WrappedServer struct { // // For example, the following code snippets are equivalent. // -// server.JoinLAN(t, "1.2.3.4") -// server.Wrap(t).JoinLAN("1.2.3.4") +// server.JoinLAN(t, "1.2.3.4") +// server.Wrap(t).JoinLAN("1.2.3.4") // // This is useful when you are calling multiple functions and save the wrapped // value as another variable to reduce the inclusion of "t". diff --git a/sentinel/sentinel_oss.go b/sentinel/sentinel_ce.go similarity index 100% rename from sentinel/sentinel_oss.go rename to sentinel/sentinel_ce.go diff --git a/snapshot/snapshot.go b/snapshot/snapshot.go index 9437cfa11cd0..672c87d2ee8b 100644 --- a/snapshot/snapshot.go +++ b/snapshot/snapshot.go @@ -51,6 +51,7 @@ func New(logger hclog.Logger, r *raft.Raft) (*Snapshot, error) { if err != nil { return nil, fmt.Errorf("failed to create snapshot file: %v", err) } + logger.Debug("creating temporary file of snapshot", "path", archive.Name()) // If anything goes wrong after this point, we will attempt to clean up // the temp file. The happy path will disarm this. @@ -110,7 +111,7 @@ func (s *Snapshot) Read(p []byte) (n int, err error) { } // Close closes the snapshot and removes any temporary storage associated with -// it. You must arrange to call this whenever NewSnapshot() has been called +// it. You must arrange to call this whenever New() has been called // successfully. This is safe to call on a nil snapshot. func (s *Snapshot) Close() error { if s == nil { diff --git a/test/ca/certindex b/test/ca/certindex index 4610614a1c4c..52333887dd37 100644 --- a/test/ca/certindex +++ b/test/ca/certindex @@ -6,3 +6,4 @@ V 170604185910Z 0E unknown /CN=testco.internal/ST=California/C=US/emailAddress= V 180606021919Z 0F unknown /CN=testco.internal/ST=California/C=US/emailAddress=james@hashicorp.com/O=End Point/OU=Testing V 21180418091009Z 10 unknown /CN=testco.internal/ST=California/C=US/emailAddress=james@hashicorp.com/O=End Point/OU=Testing V 21220322142538Z 11 unknown /CN=testco.internal/ST=California/C=US/emailAddress=do-not-reply@hashicorp.com/O=End Point/OU=Testing +V 21221008151329Z 12 unknown /CN=testco.internal/ST=California/C=US/emailAddress=do-not-reply@hashicorp.com/O=End Point/OU=Testing diff --git a/test/ca/serialfile b/test/ca/serialfile index 48082f72f087..b1bd38b62a08 100644 --- a/test/ca/serialfile +++ b/test/ca/serialfile @@ -1 +1 @@ -12 +13 diff --git a/test/client_certs/client.crt b/test/client_certs/client.crt index e464336f57aa..263da23b07d0 100644 --- a/test/client_certs/client.crt +++ b/test/client_certs/client.crt @@ -1,16 +1,16 @@ -----BEGIN CERTIFICATE----- -MIICmjCCAkGgAwIBAgIQVDAApftts3C9eO+JONBsNTAKBggqhkjOPQQDAjCBuDEL +MIICnDCCAkKgAwIBAgIQBEmjZ8EghLtV+7EC+jUSlzAKBggqhkjOPQQDAjCBuTEL MAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2Nv MRowGAYDVQQJExExMDEgU2Vjb25kIFN0cmVldDEOMAwGA1UEERMFOTQxMDUxFzAV -BgNVBAoTDkhhc2hpQ29ycCBJbmMuMT8wPQYDVQQDEzZDb25zdWwgQWdlbnQgQ0Eg -MTczNzc4NzkyNTY5MTI1NTgwMTIxMzk4OTk2MjY5OTEyNzM0NzQwHhcNMjExMTAx -MTQ0NTAzWhcNMjIxMTAxMTQ0NTAzWjAcMRowGAYDVQQDExFjbGllbnQuZGMxLmNv -bnN1bDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGF9ORXwWyUFj1bTD7GzFIvQ -U6L+eMoEiba2tD1HkKWHaDAx/I7Df3wcHmBzVaqjgMsRChjMmJ3cDDGuLt1/BHGj -gccwgcQwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF -BQcDATAMBgNVHRMBAf8EAjAAMCkGA1UdDgQiBCAka8yiBZ22z4cNL8yjkN1DOd/b -oN7QIaohoQ6ViYI9kzArBgNVHSMEJDAigCANnhDl60rkQhnDjjZwPgCC258oC68G -b9bIeY63KVL/7jAtBgNVHREEJjAkghFjbGllbnQuZGMxLmNvbnN1bIIJbG9jYWxo -b3N0hwR/AAABMAoGCCqGSM49BAMCA0cAMEQCIE4Dl1LytCVq1CDQfflE6dpIQR0z -D8EJ0v2d8Bx1YdVWAiB6Fhj7vrjevlmKGNZzk87xNZiMNB1/C3QvmWJYPpMPNQ== +BgNVBAoTDkhhc2hpQ29ycCBJbmMuMUAwPgYDVQQDEzdDb25zdWwgQWdlbnQgQ0Eg +MzI0NTYxNDUyNjQ2NDU0MDY2Mjk1MzU5NzAzNzcxNTM4MDY2MTQ1MB4XDTIyMTEw +MTE1MTczNVoXDTIzMTEwMTE1MTczNVowHDEaMBgGA1UEAxMRY2xpZW50LmRjMS5j +b25zdWwwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQJqvEGn2AswWZQ1mr0tHlt +ftn9J9lyCSdWrOADhB3+GMgz4H44CKYsYVrVtu5KMryXd2POHB/iU4xg8lm3M4GA +o4HHMIHEMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYB +BQUHAwEwDAYDVR0TAQH/BAIwADApBgNVHQ4EIgQg/GP6DmucHJbreVDyMqdZykvt +AvXQ+OagDurF1Kbic04wKwYDVR0jBCQwIoAg5ONc3k0++QDOnzWJI4N38lvRq5WS +az/dq8lQJyva894wLQYDVR0RBCYwJIIRY2xpZW50LmRjMS5jb25zdWyCCWxvY2Fs +aG9zdIcEfwAAATAKBggqhkjOPQQDAgNIADBFAiA6yknUjHv/sqbbSp0mEbW0dA5j +klHQMILw0QJqCOk/iQIhANeMu0qp9efaHAvTNIbjlUwn+EbKUIVS4tCw8ImuAMA8 -----END CERTIFICATE----- diff --git a/test/client_certs/client.key b/test/client_certs/client.key index 92e1d61055d1..17a6630af418 100644 --- a/test/client_certs/client.key +++ b/test/client_certs/client.key @@ -1,5 +1,5 @@ -----BEGIN EC PRIVATE KEY----- -MHcCAQEEIFz6x9ap6/v3Q0ZzKD8VfCXxNOlF1ELxyosxLj+yqltsoAoGCCqGSM49 -AwEHoUQDQgAEYX05FfBbJQWPVtMPsbMUi9BTov54ygSJtra0PUeQpYdoMDH8jsN/ -fBweYHNVqqOAyxEKGMyYndwMMa4u3X8EcQ== +MHcCAQEEIOEmrph3YiKjf2pUN/cy0G8LNvMVYSXM4fl7w9ylpaXLoAoGCCqGSM49 +AwEHoUQDQgAECarxBp9gLMFmUNZq9LR5bX7Z/SfZcgknVqzgA4Qd/hjIM+B+OAim +LGFa1bbuSjK8l3djzhwf4lOMYPJZtzOBgA== -----END EC PRIVATE KEY----- diff --git a/test/client_certs/consul-agent-ca-key.pem b/test/client_certs/consul-agent-ca-key.pem index cfceffc11147..4493d2f01961 100644 --- a/test/client_certs/consul-agent-ca-key.pem +++ b/test/client_certs/consul-agent-ca-key.pem @@ -1,5 +1,5 @@ -----BEGIN EC PRIVATE KEY----- -MHcCAQEEIEULa3Bb3xemvewpjiqz57wN+WwQSw/K7jUhwiUgAQXToAoGCCqGSM49 -AwEHoUQDQgAE1EENJOb0u3rmKNX7/svm4O0bXGsqZGQ+G+vHxNECsXgk4wDzi94Z -cFGIyrN8nTKJJU0j+p6YtY3P6D1K2lp9Vw== +MHcCAQEEILDGZMNL2mZRmk9LLUm+Ocp2PK31o0BtoTUZ6jqTz8lioAoGCCqGSM49 +AwEHoUQDQgAE4wstVIecTLB40vS0ujhIrF58KRdqYijsMRcZL9ZEcmPwVuA1RZ4P +VfMhqHDRirX0KwuRhunlFsCy0wQpy3XqBA== -----END EC PRIVATE KEY----- diff --git a/test/client_certs/consul-agent-ca.pem b/test/client_certs/consul-agent-ca.pem index 71281432aaa7..a62c8916e2d5 100644 --- a/test/client_certs/consul-agent-ca.pem +++ b/test/client_certs/consul-agent-ca.pem @@ -1,18 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIC6zCCApGgAwIBAgIQDRLbmPude64vjjBAnHZGAjAKBggqhkjOPQQDAjCBuDEL -MAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2Nv -MRowGAYDVQQJExExMDEgU2Vjb25kIFN0cmVldDEOMAwGA1UEERMFOTQxMDUxFzAV -BgNVBAoTDkhhc2hpQ29ycCBJbmMuMT8wPQYDVQQDEzZDb25zdWwgQWdlbnQgQ0Eg -MTczNzc4NzkyNTY5MTI1NTgwMTIxMzk4OTk2MjY5OTEyNzM0NzQwHhcNMjExMTAx -MTQ0NTAzWhcNMjYxMDMxMTQ0NTAzWjCBuDELMAkGA1UEBhMCVVMxCzAJBgNVBAgT -AkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRowGAYDVQQJExExMDEgU2Vjb25k -IFN0cmVldDEOMAwGA1UEERMFOTQxMDUxFzAVBgNVBAoTDkhhc2hpQ29ycCBJbmMu -MT8wPQYDVQQDEzZDb25zdWwgQWdlbnQgQ0EgMTczNzc4NzkyNTY5MTI1NTgwMTIx -Mzk4OTk2MjY5OTEyNzM0NzQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATUQQ0k -5vS7euYo1fv+y+bg7RtcaypkZD4b68fE0QKxeCTjAPOL3hlwUYjKs3ydMoklTSP6 -npi1jc/oPUraWn1Xo3sweTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB -/zApBgNVHQ4EIgQgDZ4Q5etK5EIZw442cD4AgtufKAuvBm/WyHmOtylS/+4wKwYD -VR0jBCQwIoAgDZ4Q5etK5EIZw442cD4AgtufKAuvBm/WyHmOtylS/+4wCgYIKoZI -zj0EAwIDSAAwRQIhAPab5jGWHNZkbDRqhQoZrA+0D9cqfJNcCOJVEB69E3f5AiBv -tbI2DANB3S6Atg8+PsRXJxCT5R1TrbPX63udY5O5GA== +MIIC7jCCApSgAwIBAgIRAPQsQxVaOlwVK7QsleZhCuEwCgYIKoZIzj0EAwIwgbkx +CzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNj +bzEaMBgGA1UECRMRMTAxIFNlY29uZCBTdHJlZXQxDjAMBgNVBBETBTk0MTA1MRcw +FQYDVQQKEw5IYXNoaUNvcnAgSW5jLjFAMD4GA1UEAxM3Q29uc3VsIEFnZW50IENB +IDMyNDU2MTQ1MjY0NjQ1NDA2NjI5NTM1OTcwMzc3MTUzODA2NjE0NTAeFw0yMjEx +MDExNTE3MzVaFw0yNzEwMzExNTE3MzVaMIG5MQswCQYDVQQGEwJVUzELMAkGA1UE +CBMCQ0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xGjAYBgNVBAkTETEwMSBTZWNv +bmQgU3RyZWV0MQ4wDAYDVQQREwU5NDEwNTEXMBUGA1UEChMOSGFzaGlDb3JwIElu +Yy4xQDA+BgNVBAMTN0NvbnN1bCBBZ2VudCBDQSAzMjQ1NjE0NTI2NDY0NTQwNjYy +OTUzNTk3MDM3NzE1MzgwNjYxNDUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATj +Cy1Uh5xMsHjS9LS6OEisXnwpF2piKOwxFxkv1kRyY/BW4DVFng9V8yGocNGKtfQr +C5GG6eUWwLLTBCnLdeoEo3sweTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zApBgNVHQ4EIgQg5ONc3k0++QDOnzWJI4N38lvRq5WSaz/dq8lQJyva894w +KwYDVR0jBCQwIoAg5ONc3k0++QDOnzWJI4N38lvRq5WSaz/dq8lQJyva894wCgYI +KoZIzj0EAwIDSAAwRQIhAKU8aWxhlJ5kiG/cqHkmfFZjY9MoweTEeSeq8ROUVYlK +AiB2nWWrkj7+KzNO4OIwNmCe8nY+JcpIMaKCK4QwhWg9uA== -----END CERTIFICATE----- diff --git a/test/client_certs/dc1-client-consul-0-key.pem b/test/client_certs/dc1-client-consul-0-key.pem index 92e1d61055d1..17a6630af418 100644 --- a/test/client_certs/dc1-client-consul-0-key.pem +++ b/test/client_certs/dc1-client-consul-0-key.pem @@ -1,5 +1,5 @@ -----BEGIN EC PRIVATE KEY----- -MHcCAQEEIFz6x9ap6/v3Q0ZzKD8VfCXxNOlF1ELxyosxLj+yqltsoAoGCCqGSM49 -AwEHoUQDQgAEYX05FfBbJQWPVtMPsbMUi9BTov54ygSJtra0PUeQpYdoMDH8jsN/ -fBweYHNVqqOAyxEKGMyYndwMMa4u3X8EcQ== +MHcCAQEEIOEmrph3YiKjf2pUN/cy0G8LNvMVYSXM4fl7w9ylpaXLoAoGCCqGSM49 +AwEHoUQDQgAECarxBp9gLMFmUNZq9LR5bX7Z/SfZcgknVqzgA4Qd/hjIM+B+OAim +LGFa1bbuSjK8l3djzhwf4lOMYPJZtzOBgA== -----END EC PRIVATE KEY----- diff --git a/test/client_certs/dc1-client-consul-0.pem b/test/client_certs/dc1-client-consul-0.pem index e464336f57aa..263da23b07d0 100644 --- a/test/client_certs/dc1-client-consul-0.pem +++ b/test/client_certs/dc1-client-consul-0.pem @@ -1,16 +1,16 @@ -----BEGIN CERTIFICATE----- -MIICmjCCAkGgAwIBAgIQVDAApftts3C9eO+JONBsNTAKBggqhkjOPQQDAjCBuDEL +MIICnDCCAkKgAwIBAgIQBEmjZ8EghLtV+7EC+jUSlzAKBggqhkjOPQQDAjCBuTEL MAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2Nv MRowGAYDVQQJExExMDEgU2Vjb25kIFN0cmVldDEOMAwGA1UEERMFOTQxMDUxFzAV -BgNVBAoTDkhhc2hpQ29ycCBJbmMuMT8wPQYDVQQDEzZDb25zdWwgQWdlbnQgQ0Eg -MTczNzc4NzkyNTY5MTI1NTgwMTIxMzk4OTk2MjY5OTEyNzM0NzQwHhcNMjExMTAx -MTQ0NTAzWhcNMjIxMTAxMTQ0NTAzWjAcMRowGAYDVQQDExFjbGllbnQuZGMxLmNv -bnN1bDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGF9ORXwWyUFj1bTD7GzFIvQ -U6L+eMoEiba2tD1HkKWHaDAx/I7Df3wcHmBzVaqjgMsRChjMmJ3cDDGuLt1/BHGj -gccwgcQwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF -BQcDATAMBgNVHRMBAf8EAjAAMCkGA1UdDgQiBCAka8yiBZ22z4cNL8yjkN1DOd/b -oN7QIaohoQ6ViYI9kzArBgNVHSMEJDAigCANnhDl60rkQhnDjjZwPgCC258oC68G -b9bIeY63KVL/7jAtBgNVHREEJjAkghFjbGllbnQuZGMxLmNvbnN1bIIJbG9jYWxo -b3N0hwR/AAABMAoGCCqGSM49BAMCA0cAMEQCIE4Dl1LytCVq1CDQfflE6dpIQR0z -D8EJ0v2d8Bx1YdVWAiB6Fhj7vrjevlmKGNZzk87xNZiMNB1/C3QvmWJYPpMPNQ== +BgNVBAoTDkhhc2hpQ29ycCBJbmMuMUAwPgYDVQQDEzdDb25zdWwgQWdlbnQgQ0Eg +MzI0NTYxNDUyNjQ2NDU0MDY2Mjk1MzU5NzAzNzcxNTM4MDY2MTQ1MB4XDTIyMTEw +MTE1MTczNVoXDTIzMTEwMTE1MTczNVowHDEaMBgGA1UEAxMRY2xpZW50LmRjMS5j +b25zdWwwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQJqvEGn2AswWZQ1mr0tHlt +ftn9J9lyCSdWrOADhB3+GMgz4H44CKYsYVrVtu5KMryXd2POHB/iU4xg8lm3M4GA +o4HHMIHEMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYB +BQUHAwEwDAYDVR0TAQH/BAIwADApBgNVHQ4EIgQg/GP6DmucHJbreVDyMqdZykvt +AvXQ+OagDurF1Kbic04wKwYDVR0jBCQwIoAg5ONc3k0++QDOnzWJI4N38lvRq5WS +az/dq8lQJyva894wLQYDVR0RBCYwJIIRY2xpZW50LmRjMS5jb25zdWyCCWxvY2Fs +aG9zdIcEfwAAATAKBggqhkjOPQQDAgNIADBFAiA6yknUjHv/sqbbSp0mEbW0dA5j +klHQMILw0QJqCOk/iQIhANeMu0qp9efaHAvTNIbjlUwn+EbKUIVS4tCw8ImuAMA8 -----END CERTIFICATE----- diff --git a/test/client_certs/dc1-server-consul-0-key.pem b/test/client_certs/dc1-server-consul-0-key.pem index d35047d487c0..9ef60bc14ebf 100644 --- a/test/client_certs/dc1-server-consul-0-key.pem +++ b/test/client_certs/dc1-server-consul-0-key.pem @@ -1,5 +1,5 @@ -----BEGIN EC PRIVATE KEY----- -MHcCAQEEIGYeUPTLPIffkIx9mAmw5stoepPHQz6hxtuwJdv2y+fvoAoGCCqGSM49 -AwEHoUQDQgAEuZ7Iacvo0TN8oB5JkSw8xvm9QC0Q6DROqE/V46XYM+1PvwhPiyoJ -ZIt2zTYATwV5Z7gIvnW1BEoGtNAt4f8pZg== +MHcCAQEEIM+Rps/EV1QvlRwMo5IT9HMqWVe1LR5vfeernws0pwo8oAoGCCqGSM49 +AwEHoUQDQgAEwt5yBcpkGKSJ+LgcS0EuqdVt2NqXYSGMFU/RTqwjeTxNeGBEmBJD +3Rrnm0kj3+y25YL/ZhssI6WM4Az4JP5D8A== -----END EC PRIVATE KEY----- diff --git a/test/client_certs/dc1-server-consul-0.pem b/test/client_certs/dc1-server-consul-0.pem index 3fbcb6bb95f8..cd8a64a1b0b4 100644 --- a/test/client_certs/dc1-server-consul-0.pem +++ b/test/client_certs/dc1-server-consul-0.pem @@ -1,17 +1,17 @@ -----BEGIN CERTIFICATE----- -MIICwzCCAmmgAwIBAgIQLMLWUI6B0ebm1Ii/WuRZ8DAKBggqhkjOPQQDAjCBuDEL +MIICxTCCAmqgAwIBAgIQQEFFmUhO6yA+4ScqpYgqoTAKBggqhkjOPQQDAjCBuTEL MAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2Nv MRowGAYDVQQJExExMDEgU2Vjb25kIFN0cmVldDEOMAwGA1UEERMFOTQxMDUxFzAV -BgNVBAoTDkhhc2hpQ29ycCBJbmMuMT8wPQYDVQQDEzZDb25zdWwgQWdlbnQgQ0Eg -MTczNzc4NzkyNTY5MTI1NTgwMTIxMzk4OTk2MjY5OTEyNzM0NzQwHhcNMjExMTAx -MTQ0NTAzWhcNMjIxMTAxMTQ0NTAzWjAcMRowGAYDVQQDExFzZXJ2ZXIuZGMxLmNv -bnN1bDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLmeyGnL6NEzfKAeSZEsPMb5 -vUAtEOg0TqhP1eOl2DPtT78IT4sqCWSLds02AE8FeWe4CL51tQRKBrTQLeH/KWaj -ge8wgewwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF -BQcDAjAMBgNVHRMBAf8EAjAAMCkGA1UdDgQiBCCg/S6k7agUE+aei8EyDz0c76Oo -rvZaXkQwVwFzjPSsRzArBgNVHSMEJDAigCANnhDl60rkQhnDjjZwPgCC258oC68G -b9bIeY63KVL/7jBVBgNVHREETjBMggtjb25zdWwudGVzdIIZc2VydmVyMC5zZXJ2 -ZXIuZGMxLmNvbnN1bIIRc2VydmVyLmRjMS5jb25zdWyCCWxvY2FsaG9zdIcEfwAA -ATAKBggqhkjOPQQDAgNIADBFAiAREeH2p06CtuScx/d9iBrA4cLJgDzjyeHJBbDH -ETHRxgIhAIzsPAVVnbuMx1+R/VWh9EWAOGvI1V/sKWqFdID8Krdp +BgNVBAoTDkhhc2hpQ29ycCBJbmMuMUAwPgYDVQQDEzdDb25zdWwgQWdlbnQgQ0Eg +MzI0NTYxNDUyNjQ2NDU0MDY2Mjk1MzU5NzAzNzcxNTM4MDY2MTQ1MB4XDTIyMTEw +MTE1MTczNVoXDTIzMTEwMTE1MTczNVowHDEaMBgGA1UEAxMRc2VydmVyLmRjMS5j +b25zdWwwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATC3nIFymQYpIn4uBxLQS6p +1W3Y2pdhIYwVT9FOrCN5PE14YESYEkPdGuebSSPf7Lblgv9mGywjpYzgDPgk/kPw +o4HvMIHsMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB +BQUHAwIwDAYDVR0TAQH/BAIwADApBgNVHQ4EIgQgbvG1NZYTXB5wRZNGjgs+hgfT +1j+klGellDDkmXIZRpMwKwYDVR0jBCQwIoAg5ONc3k0++QDOnzWJI4N38lvRq5WS +az/dq8lQJyva894wVQYDVR0RBE4wTIILY29uc3VsLnRlc3SCGXNlcnZlcjAuc2Vy +dmVyLmRjMS5jb25zdWyCEXNlcnZlci5kYzEuY29uc3Vsgglsb2NhbGhvc3SHBH8A +AAEwCgYIKoZIzj0EAwIDSQAwRgIhAIKx/BNuRx1STi9mupvpCFsl6vvTo6eKyvXk +YlMvo3X+AiEA6YTlNvH5+cWaJQORpX+ZI1Eogkl1h0oWNL4+D0lofIo= -----END CERTIFICATE----- diff --git a/test/client_certs/path/rootca.crt b/test/client_certs/path/rootca.crt index 71281432aaa7..a62c8916e2d5 100644 --- a/test/client_certs/path/rootca.crt +++ b/test/client_certs/path/rootca.crt @@ -1,18 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIC6zCCApGgAwIBAgIQDRLbmPude64vjjBAnHZGAjAKBggqhkjOPQQDAjCBuDEL -MAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2Nv -MRowGAYDVQQJExExMDEgU2Vjb25kIFN0cmVldDEOMAwGA1UEERMFOTQxMDUxFzAV -BgNVBAoTDkhhc2hpQ29ycCBJbmMuMT8wPQYDVQQDEzZDb25zdWwgQWdlbnQgQ0Eg -MTczNzc4NzkyNTY5MTI1NTgwMTIxMzk4OTk2MjY5OTEyNzM0NzQwHhcNMjExMTAx -MTQ0NTAzWhcNMjYxMDMxMTQ0NTAzWjCBuDELMAkGA1UEBhMCVVMxCzAJBgNVBAgT -AkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRowGAYDVQQJExExMDEgU2Vjb25k -IFN0cmVldDEOMAwGA1UEERMFOTQxMDUxFzAVBgNVBAoTDkhhc2hpQ29ycCBJbmMu -MT8wPQYDVQQDEzZDb25zdWwgQWdlbnQgQ0EgMTczNzc4NzkyNTY5MTI1NTgwMTIx -Mzk4OTk2MjY5OTEyNzM0NzQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATUQQ0k -5vS7euYo1fv+y+bg7RtcaypkZD4b68fE0QKxeCTjAPOL3hlwUYjKs3ydMoklTSP6 -npi1jc/oPUraWn1Xo3sweTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB -/zApBgNVHQ4EIgQgDZ4Q5etK5EIZw442cD4AgtufKAuvBm/WyHmOtylS/+4wKwYD -VR0jBCQwIoAgDZ4Q5etK5EIZw442cD4AgtufKAuvBm/WyHmOtylS/+4wCgYIKoZI -zj0EAwIDSAAwRQIhAPab5jGWHNZkbDRqhQoZrA+0D9cqfJNcCOJVEB69E3f5AiBv -tbI2DANB3S6Atg8+PsRXJxCT5R1TrbPX63udY5O5GA== +MIIC7jCCApSgAwIBAgIRAPQsQxVaOlwVK7QsleZhCuEwCgYIKoZIzj0EAwIwgbkx +CzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNj +bzEaMBgGA1UECRMRMTAxIFNlY29uZCBTdHJlZXQxDjAMBgNVBBETBTk0MTA1MRcw +FQYDVQQKEw5IYXNoaUNvcnAgSW5jLjFAMD4GA1UEAxM3Q29uc3VsIEFnZW50IENB +IDMyNDU2MTQ1MjY0NjQ1NDA2NjI5NTM1OTcwMzc3MTUzODA2NjE0NTAeFw0yMjEx +MDExNTE3MzVaFw0yNzEwMzExNTE3MzVaMIG5MQswCQYDVQQGEwJVUzELMAkGA1UE +CBMCQ0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xGjAYBgNVBAkTETEwMSBTZWNv +bmQgU3RyZWV0MQ4wDAYDVQQREwU5NDEwNTEXMBUGA1UEChMOSGFzaGlDb3JwIElu +Yy4xQDA+BgNVBAMTN0NvbnN1bCBBZ2VudCBDQSAzMjQ1NjE0NTI2NDY0NTQwNjYy +OTUzNTk3MDM3NzE1MzgwNjYxNDUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATj +Cy1Uh5xMsHjS9LS6OEisXnwpF2piKOwxFxkv1kRyY/BW4DVFng9V8yGocNGKtfQr +C5GG6eUWwLLTBCnLdeoEo3sweTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zApBgNVHQ4EIgQg5ONc3k0++QDOnzWJI4N38lvRq5WSaz/dq8lQJyva894w +KwYDVR0jBCQwIoAg5ONc3k0++QDOnzWJI4N38lvRq5WSaz/dq8lQJyva894wCgYI +KoZIzj0EAwIDSAAwRQIhAKU8aWxhlJ5kiG/cqHkmfFZjY9MoweTEeSeq8ROUVYlK +AiB2nWWrkj7+KzNO4OIwNmCe8nY+JcpIMaKCK4QwhWg9uA== -----END CERTIFICATE----- diff --git a/test/client_certs/rootca.crt b/test/client_certs/rootca.crt index 71281432aaa7..a62c8916e2d5 100644 --- a/test/client_certs/rootca.crt +++ b/test/client_certs/rootca.crt @@ -1,18 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIC6zCCApGgAwIBAgIQDRLbmPude64vjjBAnHZGAjAKBggqhkjOPQQDAjCBuDEL -MAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2Nv -MRowGAYDVQQJExExMDEgU2Vjb25kIFN0cmVldDEOMAwGA1UEERMFOTQxMDUxFzAV -BgNVBAoTDkhhc2hpQ29ycCBJbmMuMT8wPQYDVQQDEzZDb25zdWwgQWdlbnQgQ0Eg -MTczNzc4NzkyNTY5MTI1NTgwMTIxMzk4OTk2MjY5OTEyNzM0NzQwHhcNMjExMTAx -MTQ0NTAzWhcNMjYxMDMxMTQ0NTAzWjCBuDELMAkGA1UEBhMCVVMxCzAJBgNVBAgT -AkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRowGAYDVQQJExExMDEgU2Vjb25k -IFN0cmVldDEOMAwGA1UEERMFOTQxMDUxFzAVBgNVBAoTDkhhc2hpQ29ycCBJbmMu -MT8wPQYDVQQDEzZDb25zdWwgQWdlbnQgQ0EgMTczNzc4NzkyNTY5MTI1NTgwMTIx -Mzk4OTk2MjY5OTEyNzM0NzQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATUQQ0k -5vS7euYo1fv+y+bg7RtcaypkZD4b68fE0QKxeCTjAPOL3hlwUYjKs3ydMoklTSP6 -npi1jc/oPUraWn1Xo3sweTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB -/zApBgNVHQ4EIgQgDZ4Q5etK5EIZw442cD4AgtufKAuvBm/WyHmOtylS/+4wKwYD -VR0jBCQwIoAgDZ4Q5etK5EIZw442cD4AgtufKAuvBm/WyHmOtylS/+4wCgYIKoZI -zj0EAwIDSAAwRQIhAPab5jGWHNZkbDRqhQoZrA+0D9cqfJNcCOJVEB69E3f5AiBv -tbI2DANB3S6Atg8+PsRXJxCT5R1TrbPX63udY5O5GA== +MIIC7jCCApSgAwIBAgIRAPQsQxVaOlwVK7QsleZhCuEwCgYIKoZIzj0EAwIwgbkx +CzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNj +bzEaMBgGA1UECRMRMTAxIFNlY29uZCBTdHJlZXQxDjAMBgNVBBETBTk0MTA1MRcw +FQYDVQQKEw5IYXNoaUNvcnAgSW5jLjFAMD4GA1UEAxM3Q29uc3VsIEFnZW50IENB +IDMyNDU2MTQ1MjY0NjQ1NDA2NjI5NTM1OTcwMzc3MTUzODA2NjE0NTAeFw0yMjEx +MDExNTE3MzVaFw0yNzEwMzExNTE3MzVaMIG5MQswCQYDVQQGEwJVUzELMAkGA1UE +CBMCQ0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xGjAYBgNVBAkTETEwMSBTZWNv +bmQgU3RyZWV0MQ4wDAYDVQQREwU5NDEwNTEXMBUGA1UEChMOSGFzaGlDb3JwIElu +Yy4xQDA+BgNVBAMTN0NvbnN1bCBBZ2VudCBDQSAzMjQ1NjE0NTI2NDY0NTQwNjYy +OTUzNTk3MDM3NzE1MzgwNjYxNDUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATj +Cy1Uh5xMsHjS9LS6OEisXnwpF2piKOwxFxkv1kRyY/BW4DVFng9V8yGocNGKtfQr +C5GG6eUWwLLTBCnLdeoEo3sweTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zApBgNVHQ4EIgQg5ONc3k0++QDOnzWJI4N38lvRq5WSaz/dq8lQJyva894w +KwYDVR0jBCQwIoAg5ONc3k0++QDOnzWJI4N38lvRq5WSaz/dq8lQJyva894wCgYI +KoZIzj0EAwIDSAAwRQIhAKU8aWxhlJ5kiG/cqHkmfFZjY9MoweTEeSeq8ROUVYlK +AiB2nWWrkj7+KzNO4OIwNmCe8nY+JcpIMaKCK4QwhWg9uA== -----END CERTIFICATE----- diff --git a/test/client_certs/rootca.key b/test/client_certs/rootca.key index cfceffc11147..4493d2f01961 100644 --- a/test/client_certs/rootca.key +++ b/test/client_certs/rootca.key @@ -1,5 +1,5 @@ -----BEGIN EC PRIVATE KEY----- -MHcCAQEEIEULa3Bb3xemvewpjiqz57wN+WwQSw/K7jUhwiUgAQXToAoGCCqGSM49 -AwEHoUQDQgAE1EENJOb0u3rmKNX7/svm4O0bXGsqZGQ+G+vHxNECsXgk4wDzi94Z -cFGIyrN8nTKJJU0j+p6YtY3P6D1K2lp9Vw== +MHcCAQEEILDGZMNL2mZRmk9LLUm+Ocp2PK31o0BtoTUZ6jqTz8lioAoGCCqGSM49 +AwEHoUQDQgAE4wstVIecTLB40vS0ujhIrF58KRdqYijsMRcZL9ZEcmPwVuA1RZ4P +VfMhqHDRirX0KwuRhunlFsCy0wQpy3XqBA== -----END EC PRIVATE KEY----- diff --git a/test/client_certs/server.crt b/test/client_certs/server.crt index 3fbcb6bb95f8..cd8a64a1b0b4 100644 --- a/test/client_certs/server.crt +++ b/test/client_certs/server.crt @@ -1,17 +1,17 @@ -----BEGIN CERTIFICATE----- -MIICwzCCAmmgAwIBAgIQLMLWUI6B0ebm1Ii/WuRZ8DAKBggqhkjOPQQDAjCBuDEL +MIICxTCCAmqgAwIBAgIQQEFFmUhO6yA+4ScqpYgqoTAKBggqhkjOPQQDAjCBuTEL MAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2Nv MRowGAYDVQQJExExMDEgU2Vjb25kIFN0cmVldDEOMAwGA1UEERMFOTQxMDUxFzAV -BgNVBAoTDkhhc2hpQ29ycCBJbmMuMT8wPQYDVQQDEzZDb25zdWwgQWdlbnQgQ0Eg -MTczNzc4NzkyNTY5MTI1NTgwMTIxMzk4OTk2MjY5OTEyNzM0NzQwHhcNMjExMTAx -MTQ0NTAzWhcNMjIxMTAxMTQ0NTAzWjAcMRowGAYDVQQDExFzZXJ2ZXIuZGMxLmNv -bnN1bDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLmeyGnL6NEzfKAeSZEsPMb5 -vUAtEOg0TqhP1eOl2DPtT78IT4sqCWSLds02AE8FeWe4CL51tQRKBrTQLeH/KWaj -ge8wgewwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF -BQcDAjAMBgNVHRMBAf8EAjAAMCkGA1UdDgQiBCCg/S6k7agUE+aei8EyDz0c76Oo -rvZaXkQwVwFzjPSsRzArBgNVHSMEJDAigCANnhDl60rkQhnDjjZwPgCC258oC68G -b9bIeY63KVL/7jBVBgNVHREETjBMggtjb25zdWwudGVzdIIZc2VydmVyMC5zZXJ2 -ZXIuZGMxLmNvbnN1bIIRc2VydmVyLmRjMS5jb25zdWyCCWxvY2FsaG9zdIcEfwAA -ATAKBggqhkjOPQQDAgNIADBFAiAREeH2p06CtuScx/d9iBrA4cLJgDzjyeHJBbDH -ETHRxgIhAIzsPAVVnbuMx1+R/VWh9EWAOGvI1V/sKWqFdID8Krdp +BgNVBAoTDkhhc2hpQ29ycCBJbmMuMUAwPgYDVQQDEzdDb25zdWwgQWdlbnQgQ0Eg +MzI0NTYxNDUyNjQ2NDU0MDY2Mjk1MzU5NzAzNzcxNTM4MDY2MTQ1MB4XDTIyMTEw +MTE1MTczNVoXDTIzMTEwMTE1MTczNVowHDEaMBgGA1UEAxMRc2VydmVyLmRjMS5j +b25zdWwwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATC3nIFymQYpIn4uBxLQS6p +1W3Y2pdhIYwVT9FOrCN5PE14YESYEkPdGuebSSPf7Lblgv9mGywjpYzgDPgk/kPw +o4HvMIHsMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB +BQUHAwIwDAYDVR0TAQH/BAIwADApBgNVHQ4EIgQgbvG1NZYTXB5wRZNGjgs+hgfT +1j+klGellDDkmXIZRpMwKwYDVR0jBCQwIoAg5ONc3k0++QDOnzWJI4N38lvRq5WS +az/dq8lQJyva894wVQYDVR0RBE4wTIILY29uc3VsLnRlc3SCGXNlcnZlcjAuc2Vy +dmVyLmRjMS5jb25zdWyCEXNlcnZlci5kYzEuY29uc3Vsgglsb2NhbGhvc3SHBH8A +AAEwCgYIKoZIzj0EAwIDSQAwRgIhAIKx/BNuRx1STi9mupvpCFsl6vvTo6eKyvXk +YlMvo3X+AiEA6YTlNvH5+cWaJQORpX+ZI1Eogkl1h0oWNL4+D0lofIo= -----END CERTIFICATE----- diff --git a/test/client_certs/server.key b/test/client_certs/server.key index d35047d487c0..9ef60bc14ebf 100644 --- a/test/client_certs/server.key +++ b/test/client_certs/server.key @@ -1,5 +1,5 @@ -----BEGIN EC PRIVATE KEY----- -MHcCAQEEIGYeUPTLPIffkIx9mAmw5stoepPHQz6hxtuwJdv2y+fvoAoGCCqGSM49 -AwEHoUQDQgAEuZ7Iacvo0TN8oB5JkSw8xvm9QC0Q6DROqE/V46XYM+1PvwhPiyoJ -ZIt2zTYATwV5Z7gIvnW1BEoGtNAt4f8pZg== +MHcCAQEEIM+Rps/EV1QvlRwMo5IT9HMqWVe1LR5vfeernws0pwo8oAoGCCqGSM49 +AwEHoUQDQgAEwt5yBcpkGKSJ+LgcS0EuqdVt2NqXYSGMFU/RTqwjeTxNeGBEmBJD +3Rrnm0kj3+y25YL/ZhssI6WM4Az4JP5D8A== -----END EC PRIVATE KEY----- diff --git a/test/hostname/Alice.crt b/test/hostname/Alice.crt index 42d54de0f464..c9ce912a6df1 100644 --- a/test/hostname/Alice.crt +++ b/test/hostname/Alice.crt @@ -1,23 +1,23 @@ -----BEGIN CERTIFICATE----- -MIID0zCCArugAwIBAgIBLjANBgkqhkiG9w0BAQ0FADCBmTELMAkGA1UEBhMCVVMx +MIID0zCCArugAwIBAgIBMjANBgkqhkiG9w0BAQ0FADCBmTELMAkGA1UEBhMCVVMx EzARBgNVBAgTCkNhbGlmb3JuaWExFDASBgNVBAcTC0xvcyBBbmdlbGVzMRkwFwYD VQQKExBIYWhpQ29ycCBUZXN0IENBMQ0wCwYDVQQLEwRUZXN0MREwDwYDVQQDEwhD ZXJ0QXV0aDEiMCAGCSqGSIb3DQEJARYTamFtZXNAaGFzaGljb3JwLmNvbTAgFw0y -MjA0MTQyMjQxNTBaGA8yMTIyMDMyMTIyNDE1MFowgYMxDjAMBgNVBAMMBUFsaWNl +MjExMDExNTE2MzhaGA8yMTIyMTAwODE1MTYzOFowgYMxDjAMBgNVBAMMBUFsaWNl MRMwEQYDVQQIDApDYWxpZm9ybmlhMQswCQYDVQQGEwJVUzEpMCcGCSqGSIb3DQEJ ARYaZG8tbm90LXJlcGx5QGhhc2hpY29ycC5jb20xEjAQBgNVBAoMCUVuZCBQb2lu dDEQMA4GA1UECwwHVGVzdGluZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAMadRkCC0SC4FcOGn+Y7L4lTyZpjywbgim081BdWXEQCG/gPlcxZGQEPn2ZA -cglvuNbRlsDYqDs88cn9Nm9xWRJOh3x79erN/1k8AChNSj69nvTzg3cBUYx3Tz8I -5MvuG1XBp6cOK7cyUizllQVF1YX3vM5wZSP3hEe8jxGpMxS6+cKh2MHbhDNtUV78 -t7VFiDqvkT4H85VIiHyBTzK/1lMmHed820Aam8b8b0WSsdVFUZZcxUKuaKAqg6Np -YQE49IPMGJ8zidVZhEm/vZP1K9+uNJSq4mnClFBua+06Z6F7gj2MjGyNn6MlMOKs -EMAmntg4jgm/DznSng0t95XtVKUCAwEAAaM4MDYwCQYDVR0TBAIwADALBgNVHQ8E +ggEBAKOBOrkFZB7absO9wimOh36sbVtwBkKyNjM86cG07U8QIAHm4WrBBEy1VVme +N6DOV0gSgU70ZufAAx7uFxp5wlf6z1uaVHYT8y7DAFwL3cUqphchR8C+pTPgOikA +3ymDyt6jqUGnnsbcv7/ml/gr8sxTqFIFyxnfevw1JjeyOwnXDwg6DYsL3co+xTNT +igwhP+QGUEsCYuoOZ+jXDbpKLrXsxycjkC7oODuW5Vq4Tv3pZQ3ZFqlbLOg9qYto +xRz15rcY9lBHoZog+dH8Yc29COxe60J6pky6N+pE8/f+NVGRGqa/3W4qunrpNYCj +a4HmrplcnjOne2lWL5qsisGfo00CAwEAAaM4MDYwCQYDVR0TBAIwADALBgNVHQ8E BAMCBeAwHAYDVR0RBBUwE4IRc2VydmVyLmRjMS5jb25zdWwwDQYJKoZIhvcNAQEN -BQADggEBAED+jxV3/dWdqUF4O6J0MbJ0i60XRpFHvP9W7ukt8L+cMgVsWTqWPt+d -819gp0L+OAgwAVW0jFXpywi3LkdqurTFMMeG/yc9H4ryuLBAmg6TQSAexaYGznhE -jXZYJR04Wi8ct2e62GRZdAUGCzg9ZxAEr3wPRg+XW1jkYvJvPPFerG5kQPdx1bq/ -C3AQh3ONSK+ZTv1hxWumixkJbHh0aQpnPvy1Mq4AV+mHXlPlJocXfhCFh9gZag3q -DpDQ3Q56fZmDmssRQO9TLd0/+lfZ22aM94DmJyU78Dq+rpLfC4Guh8DfhLGtCK9M -60ixhLIOonbE5/Q0T8fKxW2di6DR+kc= +BQADggEBAJukWnrR9B/oJycWlVI9EV7XEwpsFsCEjpHGNM9ow7pgDUUWXL48IZbe +FtvpwFV86hQmvChdmigPy+DaM/EuXwcxQBJhTHh0qUuQZKdH1erUHtIF8XDVGhLF +VuCKD/Qb+2b/f/UcqrYXHhpov+FGnUB3NGUyRVlUVcxvq9wrtFtuNc/8521P6+L7 +HxI38L7tnltailYW/kuEmLw7mE3U+V7APVkhi4xA2yHK0g+dZcA9m34yezS/WeSI +Yht8DDadWLp8Cf/5RrgaLz66Ik+V3nuDEy4HEFW2anztcsVVz7CP73NOYV4mHcJU +synhHnqDSq1wWY94G9/UFmKAETzHU9I= -----END CERTIFICATE----- diff --git a/test/hostname/Alice.key b/test/hostname/Alice.key index 482cb3382903..466daaf56982 100644 --- a/test/hostname/Alice.key +++ b/test/hostname/Alice.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDGnUZAgtEguBXD -hp/mOy+JU8maY8sG4IptPNQXVlxEAhv4D5XMWRkBD59mQHIJb7jW0ZbA2Kg7PPHJ -/TZvcVkSTod8e/Xqzf9ZPAAoTUo+vZ7084N3AVGMd08/COTL7htVwaenDiu3MlIs -5ZUFRdWF97zOcGUj94RHvI8RqTMUuvnCodjB24QzbVFe/Le1RYg6r5E+B/OVSIh8 -gU8yv9ZTJh3nfNtAGpvG/G9FkrHVRVGWXMVCrmigKoOjaWEBOPSDzBifM4nVWYRJ -v72T9SvfrjSUquJpwpRQbmvtOmehe4I9jIxsjZ+jJTDirBDAJp7YOI4Jvw850p4N -LfeV7VSlAgMBAAECggEAVGkRK2etk5dJAKFdoc6zpEys2OXiqpiRnF2G0ihM7EZt -Np8BDikrvEy0dROco7AMwZev12P9E7gSFsN7+B8XOPWRFXHlkRZdmMIsWvSGQmX6 -gaZg0BoKW4V1c5fHDXizu12jcBdQsvo6/IPSMrx8RASHBMG16nROjuJvd5UOdZdF -wKTlCjLvJNnZsaW9HVsO3YsR1w2m1NbUdx+UYeRzy7sYzKc4Wnm2qA6r1UkzjC1S -6ho3NAy9mX4HlSyYq4qWwLT9ByIqgzjWdWJUbyJ2+ZvCRmbagONoBjGc323Og8LB -6PRswo2nlQSjxHA4G2llQaKp5TAbiwr9tPG+DaupnQKBgQDoQUkwa144jT6Bjn35 -36xl/s00vhT5dfFyEK4RPThTPP7FBKHPp8PO2kPz7z6CoL7xoV/yR2OENZ3ZxIgX -xBIw7cu25B0yp9+yH9wZGd3hNDGiXlnaJKy4oXYrs8pkh9bUXXAUsa+3Jcc29Y5I -MiboquzFMf0JRwHapx0SE9/G7wKBgQDa64Z4DlubX/QhdrQBlyJA/bT7NfTHkRoH -Oo0b9POqrh7ZiVMp8mlNDQY9VZo44UOJRrttNLzNCCl7Sce6H3GA38fp/OcszZTw -Crlfzk0Fm3D9zUUog8BO3sH1WBC1ws2cONIa5AeuNj6GuWE0UueULcGeb7bp5VYe -kN/Cx7u9qwKBgFIMPj7Mr0xrGVnLbNWJHu4pRXUMcXxvHgydt+B/MBa3xYj0SfWB -3rqEgNz796lOACZ8S9jbP1zFVC5KL4m1yndeikjh7S6n/259stNrP+b++UnS6wsV -Sa8v2v81VJqPImWDXMTywJCC2A2iUdFPZk9rkplXP3y3iQAlaS+ptbQhAoGARM49 -x0IL/LudyV67mLxdobubxFDjDE5ItfjrHNxSMVTkkU6d+tMb0YHEckaTYEk8psq6 -YcpvhKmKEBvSUGdNj0nGVX6NUgGTTBayyK/YeWivjLWVhPRT3vYYU/pH1jjR0sXx -E06UM2cNI97j9EQSUPpInnlSLhVMifLSwS9xjF0CgYEAsUd2Cy/sw1D+bv/6ktlz -5FYjAwJA2dcYCQMJ6Cds7yTgkmS0sFcb3bFOMtkTwzS6YShc07kiPlGs5d6P2uIA -cYBQLl/NNxVthCLmz8roY+g9wQH+0Bmwiigbn+vTriN+xA9F11Nie4vn6ZzQqncq -71BwLZBtCekeJsRU+ml+dSI= +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCjgTq5BWQe2m7D +vcIpjod+rG1bcAZCsjYzPOnBtO1PECAB5uFqwQRMtVVZnjegzldIEoFO9GbnwAMe +7hcaecJX+s9bmlR2E/MuwwBcC93FKqYXIUfAvqUz4DopAN8pg8reo6lBp57G3L+/ +5pf4K/LMU6hSBcsZ33r8NSY3sjsJ1w8IOg2LC93KPsUzU4oMIT/kBlBLAmLqDmfo +1w26Si617McnI5Au6Dg7luVauE796WUN2RapWyzoPamLaMUc9ea3GPZQR6GaIPnR +/GHNvQjsXutCeqZMujfqRPP3/jVRkRqmv91uKrp66TWAo2uB5q6ZXJ4zp3tpVi+a +rIrBn6NNAgMBAAECggEAamKhZNWfKXwS6gXEGeoFO2TR2tbvG+J85aXSqxkf93uU +d+hT73QbahXqrN8HbvgTTm/L9yWK92u2HB/qpG1pCHnHBeFK53Ffn6N9zmZiK/Hu +E8qxtzXUpAZXkWphyc9Y5rgyXufDpbzofuJ5Kx7dYhlkwcnHNtR0Xznt3ft38pQT +gZGA7wDY+ups2May8zGESXd96BOcYRF6PnMEiFDTuzcoSNKEhcuP0ftOvmvO/Vph +Nel0phPT0Le57njjw5wQOJBou0WkxC9GJ/UfOaDfwCC058W1yDKSTSZeZbAoGvjX +Hg9U1DAlfVHv8P0pcquoJbfB1W3+ev5nundM47qO+QKBgQDRduMGkBJ8aji5SOMj +h6xCQEDosSVl6A9Y8H6q5yro0Eu+oD2BdOTdcYGa5Y+lasi0K9uyOuzLnkaF91YB +7+aqSG2CipiQxnOXR1/pWsFD+eGNf2npybbhbi6ik6lqzDm27qAfYJjyrThJWZbE +QihuRgHKwv+Dsa2H2Iqacn+QvwKBgQDH1G29y4YmXMX3iGSiowYcG4Fy/HeWQqR+ +huuMmdEenCpMtujb7GG4MbJA1GgWK6fZhkbcAuTmtPAffq8adqauPgmv21qoHYgg +Fm+2qiSMctRELBxEBc1ym00bu4jISvU7dF26mQ9sTUGcTQI9nOkQKFKOTAYjfSG0 +d+xqZshC8wKBgHzej9aQusR6mlgykF3U+qcAIPHW8QGARu3xaMG/T4A89HqukhwD +sJAmo2nQ4kJtlzp5Tt5AbHuyXj5sxVQgTPVEeiwxLWRZOf18Kjw1wzMf2wt8Yoph +mulmwtxehMfK+bkJJmGuN1+sTfrEMrHK8slSaK0UdDhxCo8KUw5hpZSHAoGAXkXD +eBS6NwLxijPYdjm+uifnzB17NXI/NEnmejBezbgS5JouBQLhnwoi9B7A9CSoTSDh +8Q2Ue5rE5bbYWP286Nrvqv0rKcC05Z5wGZbvIytRJNBCjXzHTdgiaoDwqL1kMCZX +yZ5H/mn8GAbklbie4zaCrAsFolx4ODGTYScYNy0CgYBCFxcTBRCqhQd1Hzp6NNIf +Iqzh21FH+uGfG8LtvYE33IUFasUmdcPKq2ZlItfLrG+bOsxXqsKAwKH+Y/XtX/RA +zySeMr1aIBWRowlNZ3CihnYgJ14IZi2JrvVPfY5UIyWYUm6ykEWOANAICTYMXtKL +hIvXoK+Yj5Kq5ZZIp5cITA== -----END PRIVATE KEY----- diff --git a/test/hostname/Betty.crt b/test/hostname/Betty.crt index bba0776cecfc..3fbeb5fe8b21 100644 --- a/test/hostname/Betty.crt +++ b/test/hostname/Betty.crt @@ -1,23 +1,23 @@ -----BEGIN CERTIFICATE----- -MIID7DCCAtSgAwIBAgIBMDANBgkqhkiG9w0BAQ0FADCBmTELMAkGA1UEBhMCVVMx +MIID7DCCAtSgAwIBAgIBNDANBgkqhkiG9w0BAQ0FADCBmTELMAkGA1UEBhMCVVMx EzARBgNVBAgTCkNhbGlmb3JuaWExFDASBgNVBAcTC0xvcyBBbmdlbGVzMRkwFwYD VQQKExBIYWhpQ29ycCBUZXN0IENBMQ0wCwYDVQQLEwRUZXN0MREwDwYDVQQDEwhD ZXJ0QXV0aDEiMCAGCSqGSIb3DQEJARYTamFtZXNAaGFzaGljb3JwLmNvbTAgFw0y -MjA0MTQyMjQxNTBaGA8yMTIyMDMyMTIyNDE1MFowgYMxDjAMBgNVBAMMBUJldHR5 +MjExMDExNTE2MzhaGA8yMTIyMTAwODE1MTYzOFowgYMxDjAMBgNVBAMMBUJldHR5 MRMwEQYDVQQIDApDYWxpZm9ybmlhMQswCQYDVQQGEwJVUzEpMCcGCSqGSIb3DQEJ ARYaZG8tbm90LXJlcGx5QGhhc2hpY29ycC5jb20xEjAQBgNVBAoMCUVuZCBQb2lu dDEQMA4GA1UECwwHVGVzdGluZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBALcRmiQ3lifgSuD1f6Spc6iHSvX1ilRXlo9FJ9MuROyg1ByuxQliU4Wz4XUw -CbpzUncb3B7Sg0Dg2dfMZJoafkVcVi4k6Rv689uasp4LIciK53sL33QfZEXLw5Nt -LizfDM4IV5tb2m7s057ObVwdjjg0ICRkpgXWQgGb2OhkU3ZliPeuo4RnODCThRLR -9SvHenpn8TJldNGunQGERPRFEeF6ekNgSbfM3vjimBUGzHdlqd9L327u+fRrVC/E -k0YXTM7Ummc1NUButUaFFiA9uBFhqU5tI1NnrD+dAmsboXrzI62HsipOmWskoSAX -66gkeyi/yoDsXENd09WiqTxOaqECAwEAAaNRME8wCQYDVR0TBAIwADALBgNVHQ8E +ggEBAKQlj8NuFi8jBF3NrU1bUopIfCnJJBVUrITAa4H+m3NiipWh4QZirQctKrf0 +vaG2sZ8UJprESsYhWDyZ/6+U196b1y6KVEU9bvfXbaGEZTKsjnNrKIU90JbBbZvw +3eH1J8bMPkvkzkPrhMn7uO+ng04lorVkQ8tk6i8fzSpYFX8mxeWz0yz6KK1C8Bre +RGtBe2kcMWwCzEdCabE1BwwPLf7wn2vfePdbyc4gxS4OzQcKFRJEb1R9E+l0Gmvx +sJxK/RggPCNeHvD/ypWm69ssddLvdJ76Ut9jUAVKlQLxBb8anHm2w+ybPXlrDfnU +37Bi6QjsgNwH+EUhvjgowc9PLPUCAwEAAaNRME8wCQYDVR0TBAIwADALBgNVHQ8E BAMCBeAwNQYDVR0RBC4wLIIRc2VydmVyLmRjMi5jb25zdWyCF2JldHR5LnNlcnZl -ci5kYzIuY29uc3VsMA0GCSqGSIb3DQEBDQUAA4IBAQB+hMHxwzY7KpFe/mKhiUCE -bOrVBvXAp/98F5UPoMGbF8Qe4/nNPAhhFGvkG28lAyeai1j7HX+gqx0qxcOMHGMw -uIL/XcpetQijOazNzvCaXo8MqPMjkiFDWkdaJVR7D1BU2kwwDpHJnNpnjynBW3vl -OPkANoo9WX825vErdZ4bEHQRRZziU7v2auqxZuxB8uBf9NJiDQvyUvkDUkQkHu+a -8QAdifeavxCkcIE6aKzPAEfDgVIHylzOjAGQUpZgmaA5344jH5CltTlZ54zh33jO -MmmzFj5e0MCdFJY3JBqKcEfXswTnDdXZIvdF3Iu/kWXTmd8Fnkx2ektNd70MFK0F +ci5kYzIuY29uc3VsMA0GCSqGSIb3DQEBDQUAA4IBAQC+qTIIkbk+ekiAnijKw9ae +VdLoMgFoGTUpf/RnNjcHvHlITprQoobdHMmOKV3EXT9zFaUjNOcrUXq7Z5LQozc2 +wHhh5M3FWg2BHQqosePZx+8o5aPJgmbr3upOB9xWQtcEeTh2q+ozA6ZqjVvHQXH9 +k4VOSls0Hzv+SwOsVIul/AKm7gXlr097YxvKhaQNoYdo21eyM6Kk5t6iwYq7u+II +DcvWvMNX4p99bOPv8RfbnnKeLF85i00evZ0VW80TBGJtcBXnEIviuL6lQzZ3H1rt +zr8psCb+iOitfgh0Sv7Zk+zKGlbPc050RGYTjwNcgxnsPoPzm3hPJXZ81erq6w8O -----END CERTIFICATE----- diff --git a/test/hostname/Betty.key b/test/hostname/Betty.key index 2d1fb541b9a0..d97e32c84825 100644 --- a/test/hostname/Betty.key +++ b/test/hostname/Betty.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC3EZokN5Yn4Erg -9X+kqXOoh0r19YpUV5aPRSfTLkTsoNQcrsUJYlOFs+F1MAm6c1J3G9we0oNA4NnX -zGSaGn5FXFYuJOkb+vPbmrKeCyHIiud7C990H2RFy8OTbS4s3wzOCFebW9pu7NOe -zm1cHY44NCAkZKYF1kIBm9joZFN2ZYj3rqOEZzgwk4US0fUrx3p6Z/EyZXTRrp0B -hET0RRHhenpDYEm3zN744pgVBsx3ZanfS99u7vn0a1QvxJNGF0zO1JpnNTVAbrVG -hRYgPbgRYalObSNTZ6w/nQJrG6F68yOth7IqTplrJKEgF+uoJHsov8qA7FxDXdPV -oqk8TmqhAgMBAAECggEAcaGcYtSaAIBpGf9oTmXb44Su08KoLTf8vUs4sA1tPM+L -OY6FwRBmNXx0+k9qCnBghIwncn5KeC/ZJ+i3nSvKqvTojVXd179KNEpuikjwnFET -47134tVFYUlcSRsg6Ts98HkfH9DA4c9gf5c0LFQwHdTFCrHql37pk6QP3BfB8p9/ -BHojrxF6dFV04XR5bMTHO0w1b4OstnROiKynZYxP9nxpeMDAWG8A1/7RSCFuaXHO -2m1V7ChAsfGsF26cAcVTBQaQBonlPAaswCOVQUSqVr+PtmjhaT96EJ2mS9Wbz8Wt -Wn/opHuRbmOp7wxJKXgvroD8t0738PyHo9H+EPthQQKBgQDywIXyClZFjDjLIH0c -YhS/ceRcUuhMxI1ZPwAQG72Fxv/HMUa3neSSKKLBKRQqPFxvvfjS0IT0737WtLjK -Mst2ojEKWkveRN54VVwINwXkLTrmM0vpQrBuye7c2le+Pj6QriV4OgIlB6P6huBM -AjiksbGj217H+n67cxwLgWdVOQKBgQDBDz8lc9DpV4WH+rfOx7vBSCqqvleQ3pxV -hO/BndW6/sFo7Go6zRc7mGmEeaJUVATAMTHRsvKZ7VQQH57l8JS88V27uxAepyjz -GV8kRYbfV5mtyoq+3owcaeUbBxVv0wCNB9I5m+SuRgfwe2/FHoV8EMl44LLB+sue -x5i1sDhoqQKBgGKa+43GzyZu//7a0pc97Amb/NPXxY6xZG01HxRsAD8gB3PlO0GI -vHj2Uq49vngtjqrBMxqHIwrPYela/Zj8qxMkbOE0ro650Nh2a+zWVOlLyhoKCjLV -KQ/HrOQ/ONcJN6bTZlsAzTA3e09fjCqz2Ehl+a+Cg2yd/u6rol+2D8BZAoGALc6u -Tvah9Ru9JTyJ7Fhb5kp3RTgQkuEe+vOl56zJj6ruvTSLKBSNlKhfMP2jVJry3Z9O -kNEC2x8CuSinjSt+Py6N7QM/meZTwwqcFoEgtVGVtzS9ovgvCnbd04Hkxjmsgcn/ -SYgBxI/9RkQjiwPo7D0XcMTv5TLaqXv2cfW0DLECgYEAkf+V/kSb667hAr4MNOKn -h030GAnmuvcm/ErbqWFXC7b9VyPDr+SU8tXr+ZZIzoH53ua9gxqTxYjFkUGMIZqM -yhRv3jYpG1ar1xs7Lo7qDCggPsBlZaIUkjZSlT0YX5SZ7U8DFowh7gRID0HUiELe -aqwXam2T6fIjLBVLhkuTWjw= +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCkJY/DbhYvIwRd +za1NW1KKSHwpySQVVKyEwGuB/ptzYoqVoeEGYq0HLSq39L2htrGfFCaaxErGIVg8 +mf+vlNfem9cuilRFPW73122hhGUyrI5zayiFPdCWwW2b8N3h9SfGzD5L5M5D64TJ ++7jvp4NOJaK1ZEPLZOovH80qWBV/JsXls9Ms+iitQvAa3kRrQXtpHDFsAsxHQmmx +NQcMDy3+8J9r33j3W8nOIMUuDs0HChUSRG9UfRPpdBpr8bCcSv0YIDwjXh7w/8qV +puvbLHXS73Se+lLfY1AFSpUC8QW/Gpx5tsPsmz15aw351N+wYukI7IDcB/hFIb44 +KMHPTyz1AgMBAAECggEAAKOAxrLj9TT+rFrDhNyJGq6jhQoaUNbugOm6wVu7QRyu +C10A4iR6JeAAHY0fO8TZNhQ+/jUrUVAJ5tp2izlaCayzjqPNJiPSDbbR32IDfsn7 +F+nf03zlFeEUyxmJ03o/uF9NEsCGKO9+qcaH9q7BLQmqc2g7d0wiOSK3iqWjF8aO +QCvjtbmdZasefRD42ouhVkWBKcuEy2ATqV4l8M1Ne/iVDhExVTCshYjpqPDoBNwm +19H0k+VRoUFVQNG1t7W31E/R5Oo2p6Xu3heevqVwb/2cX1c1RDJnDEZZH1/LimN1 +qDvcl8YxEhqlMjYmraeob8aTbOaByNfGK5kS9cQnwQKBgQDOx5Avo4mG2F779YSV +oVpabAfbl9t+4hsZosIoHRgUMp5uRnxyV11qoXw61Wq08aRAjUJvXeJDP/9nceSg +4Zptlm7BOnHrL1ksho+Dx7T0qNBTiiXWe24gx5RHOyYm4LrtHujXM46nxuWG+qRU +MX19GBHyrnb91zoEcmXR7eK3JQKBgQDLOBm4AJSmkRwEBcQtxGW9svLE9psqXUBf +rEFee0Ueiv/YJiRhmPWgOED06KMhWn858aI6VxXFCt+bu9hRkRdsVuB1Jw7EdcQ3 +oi2oD0Q4c1wBASw4uJ6Z+w5AARlDE5TY0sEMNcBxQl4Sr4f/JDSjuaAgRbp0jnlH +9LNRa9ldkQKBgQC9b4Zgnmn353HdUmhMzK2B+UaZnt2vuGUrbziAl2bf2h/a1yhb +eD5U2ex92dcQPfBEUyVx8YjAI3lQw764xPY9P3vn+iszUwVXDU+dYvAc1CtG3WEc +xad20GC/gSjKpUeaxJ57yPgALO9KYYT6vPxCBjMrKTpKA0tbl5JAaLczIQKBgQDC +MuZA9C0Zz+nZ3jjPE7O2SF++4Xr+TQbLZq1BQMOYoHRFdo2lxqpTZe6NHBNoODcE +hGjnH3lqRy3QgP4DVIfxvEPbMGvoSjIsiArhY1VqLLNrMle0DJljxIqll2cwtnGz +khNxO5yfnzCO4rcvlsXHAAiJTpkT8WLs5GbIFCwwQQKBgDscsFXLFX2BCB1ouscx +yL4CE10d3NM3adODHgRWZ08YxbxG4iwX+NdfKV//tHBsyGzkDAKdWfw7m5ADf900 +l7+Re3rwEbhFKm5Adlj/BYydyrEbFJWE7cwejugJLX7+v0XsiqrnNSt3hGdGbgrN +sRMcxtzUUP89jbpLrYwg5rKX -----END PRIVATE KEY----- diff --git a/test/hostname/Bob.crt b/test/hostname/Bob.crt index 7f22c7171743..5f96a5dbee59 100644 --- a/test/hostname/Bob.crt +++ b/test/hostname/Bob.crt @@ -1,23 +1,23 @@ -----BEGIN CERTIFICATE----- -MIID6DCCAtCgAwIBAgIBLzANBgkqhkiG9w0BAQ0FADCBmTELMAkGA1UEBhMCVVMx +MIID6DCCAtCgAwIBAgIBMzANBgkqhkiG9w0BAQ0FADCBmTELMAkGA1UEBhMCVVMx EzARBgNVBAgTCkNhbGlmb3JuaWExFDASBgNVBAcTC0xvcyBBbmdlbGVzMRkwFwYD VQQKExBIYWhpQ29ycCBUZXN0IENBMQ0wCwYDVQQLEwRUZXN0MREwDwYDVQQDEwhD ZXJ0QXV0aDEiMCAGCSqGSIb3DQEJARYTamFtZXNAaGFzaGljb3JwLmNvbTAgFw0y -MjA0MTQyMjQxNTBaGA8yMTIyMDMyMTIyNDE1MFowgYExDDAKBgNVBAMMA0JvYjET +MjExMDExNTE2MzhaGA8yMTIyMTAwODE1MTYzOFowgYExDDAKBgNVBAMMA0JvYjET MBEGA1UECAwKQ2FsaWZvcm5pYTELMAkGA1UEBhMCVVMxKTAnBgkqhkiG9w0BCQEW GmRvLW5vdC1yZXBseUBoYXNoaWNvcnAuY29tMRIwEAYDVQQKDAlFbmQgUG9pbnQx EDAOBgNVBAsMB1Rlc3RpbmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQDD0RkklDCznxVHo2/jXbeBkCDJBs8CqDeJuGwscPFIZuozR5LoL0ElScYudVwC -nvECbjcwwV0fMUIfRKao+6Akyvpd1zZpUYpifHkULzSnjm0x2ea/1fscIEuoQp+2 -eNDeQ7UAgqUpE2sgtSKuXa1l0zC8xX9eeZ3tKXl+6gXe9gfuFpRCijKt8o21EVnq -Gf8fMYZpLxKcTmf7KdZGKVzqY9JO84xfukBbWvhxpFFgka6NasSxmuqIps1AFs3V -pi2cDGixgJUGsVY4HJzEp/dU5bbr6Uke01VEmNpMn35rkxJtAWkEeWdYuq5ZaVEU -0Wd2i8mOiYtSi4i43wAlh2QjAgMBAAGjTzBNMAkGA1UdEwQCMAAwCwYDVR0PBAQD +AQC34ozQD0NWzSZMzapl2NFpOZaYNcO14xEClUZsr+w6MwShUDtfumEc6IHFl/FG +WHVgVluhDlC/OhDBIYAojzHCqE5q76sQyzjvoPP9KDB1lPBFOh1CELwj7vLsbjXn +LTw8bnrPQ8pA7va5d9T1BtAWIiu6IA//YCwhJCKCgUbUascdBWtoH7jgFsYhDC9p +Bca3ix/Tm2gbdfu3sbAaDGLDUnh63oWg/wXJcaMbusXuVyifPencBxdJALf1UX8A +ohV7xqcrLPRvkMX4eR0LSSuSZbk/iiwNGy8T9mrr1Iq2LUorobWzISJEPkMOIgDD +Up43o7kgV3A6RLsGERY1cZzPAgMBAAGjTzBNMAkGA1UdEwQCMAAwCwYDVR0PBAQD AgXgMDMGA1UdEQQsMCqCEXNlcnZlci5kYzEuY29uc3VsghVib2Iuc2VydmVyLmRj -MS5jb25zdWwwDQYJKoZIhvcNAQENBQADggEBAKvTAJffhOQVrm/R0p+YJpSZxis+ -Gg5nH//a6TSuj2qPp56q1V+cbiU/eDGIPkNUMLw1yl/0lhvKrHGR1QysdDcMEtph -bXga4ZwNgwQ4BLJi28J0WJDMCDq/GRhK/6KFd0uLLiOppTe470O59qSHSa2JMjKr -uzs9153jbY461IES147/MY3GDVC5pWGgnsCxmTuFf7vqV+CpRq62QlK+ZlekHaDL -cpwG/bMSUHdHcjCUusASSDyRcbCebGvMYO91zEMGkn7+DOd8ZkQyIX709/ue1uhJ -bqSWozgd383bL8ChNqnZqItOS63PCzbLhquLZJ4oQ8pq4YddGT8PD+Bmqks= +MS5jb25zdWwwDQYJKoZIhvcNAQENBQADggEBAJvwWyA2Eg/B8Um0dAIjaibW4/Mi +2Zh4SOFqUlD7waDqqR6Nx0k4iUuOOUULGNxQI1TKcrnqYBuGJjXkpQ30GnSD014c +5n3X4ebZ1spX/3dn994vEx1anfF7xxERqIvmeKFJmJMS2zIAzvrcQ9bBEuICMdf5 +Iz/Z2h4CPYXmm8Lt7TwqamO+CuU5ekScSLSn2AAomYIuYQZ4KfqeocFeOuo7bWtN +BcWcRwE1FXrhVj1reNXLwkSQAjnhTOGnepy9StntlHHtEMkX1WF9CqwQg7rgvJ1H +pOV9ijfSDrbQqEKTQ+4alGPi3Hk2Agzgv1Hxc3qTmTdmoNweviktvlL58dQ= -----END CERTIFICATE----- diff --git a/test/hostname/Bob.key b/test/hostname/Bob.key index 5efa481dd317..32cd0c96d561 100644 --- a/test/hostname/Bob.key +++ b/test/hostname/Bob.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDD0RkklDCznxVH -o2/jXbeBkCDJBs8CqDeJuGwscPFIZuozR5LoL0ElScYudVwCnvECbjcwwV0fMUIf -RKao+6Akyvpd1zZpUYpifHkULzSnjm0x2ea/1fscIEuoQp+2eNDeQ7UAgqUpE2sg -tSKuXa1l0zC8xX9eeZ3tKXl+6gXe9gfuFpRCijKt8o21EVnqGf8fMYZpLxKcTmf7 -KdZGKVzqY9JO84xfukBbWvhxpFFgka6NasSxmuqIps1AFs3Vpi2cDGixgJUGsVY4 -HJzEp/dU5bbr6Uke01VEmNpMn35rkxJtAWkEeWdYuq5ZaVEU0Wd2i8mOiYtSi4i4 -3wAlh2QjAgMBAAECggEBAJjqspLRMxMieXC/XkIVTpfcYO375i8yBGUFY1x1OseK -rvwqubueI2amLSDcv2TAkH+QaIMnjbwtMHDQoMG39sCkzk34IeKvLb1pbPhpQNpU -rEtQ2hUXWokFY2/bz3Ok95+LCk+Cts3T/0XEjnfSafXprdbM+IFjwgOR7vJAeSM6 -auXQ24FHxSFBMt0m3Zhgp1P1qLBMJCxrEM0PTDKSnfI/HURLmUwJShu9x7+RzEb8 -pMGYGqFrXgkPOMT9gmBTjjgljMNiAYU2NZWsmP1dx3tB8lUHCd8iIp8bwNjqc8Q/ -rSNtniZ9NI+DNTu5xrAHz9KnM2AQgn92bHaerBZ+TikCgYEA53wGSaf4qW9cNBPP -p7DVAcz0FxaFEdzT4RI89KhZvKySj2bmsmywhW41dRpHhqKtBCvPgewTaI6YWGxf -YtUN8AmzrymfXZxPl+A1T6zbfV0AdP9LI/MDj0BcgkAyhdPmo4/jzAFwsRqe6HHi -dcqXBdqimuKottqWixpsJHOyITcCgYEA2I4ObI6Y4xdZfVPqj8xiMq9g1MUNRXLG -palvDGUHV1jl8oBdBCsjWZdd7cIWqLGiMxdWM42AWPZ71QKqEhd4K2z7fzeaXOZb -6Dsruxu3bG6/RNxRuCfTL6YOIpz/m5iIHcFD9g7OnODtKkvAum/8bTYiTjunHQxp -zInhKjYGenUCgYB0ywS5IQC7LC6PL/ezmeq+79Ov2nLlYk+c3YDXyCEOqtt/cuGu -4Fvn1oUuQkYYTfeRhTE7Ugsw09FVu8gcq3ZOx/ZayFtZ9cXK0RrUylgr1kKmxS/6 -QWBoZIbISO+0ygcyOyUqBwf+s3m9ucgSulacY4VrNDT/nSYbpQcvFRio3QKBgH5z -7U5MslAhKVt6rgSMJ2dLa7Ky4j4EeKTx3GuTbwb9XUEO3cH6YqkFL48Pf+W/3GQT -I331CdZpEARhiugHll9dQzqVQGkxBsgEDVQ0KhaCUOQn9vwfHT28rJJftQ6psgoV -+dZr7RBEc5j4JTF5BSDMtJmUUdAvmHQcq0PXyk6lAoGBANPIxjhoJ2tEEQq6aXxF -VeHK/zQAPTbTXE8cS7tf4AU9u5WJ8noKm8KG9NwLJcN8kNKfKj3f8VXaFh4Pg0Be -rDopAQJtk5JJlAv8RKA8Igf8ilLLw5/6AYspZZLrPNSrYYvKVGN6rszbTk83sgOi -qhTPPWMwC0CmLJQ7LDdhM4T3 +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC34ozQD0NWzSZM +zapl2NFpOZaYNcO14xEClUZsr+w6MwShUDtfumEc6IHFl/FGWHVgVluhDlC/OhDB +IYAojzHCqE5q76sQyzjvoPP9KDB1lPBFOh1CELwj7vLsbjXnLTw8bnrPQ8pA7va5 +d9T1BtAWIiu6IA//YCwhJCKCgUbUascdBWtoH7jgFsYhDC9pBca3ix/Tm2gbdfu3 +sbAaDGLDUnh63oWg/wXJcaMbusXuVyifPencBxdJALf1UX8AohV7xqcrLPRvkMX4 +eR0LSSuSZbk/iiwNGy8T9mrr1Iq2LUorobWzISJEPkMOIgDDUp43o7kgV3A6RLsG +ERY1cZzPAgMBAAECggEBAJOKi0FFfdpfsKNfQaGGXj/3nQVz3hxKnJNeAquiXAA2 +fziPj5Q3j0QKqlVInKa8wzERGWQYgGFuzZKotpPUkTCGqqTSuIc5B+39TseJP5iY +cFCbWG5xzwNl7jQWGdnrSbGTU6aJ1fZTxlL5+zy+wqd/s2Yb47ocCExvGeFsqNA1 +oAeCK961KfEjf4qDJHNP/DjdfdJdFCDxydtX4/1zTEfGV3TQj3P0nuwU60nkpJPT +LvNXwoxyu0EgSkMP3RUjZ6LHCB9eyeRZYZ3wBKmoudIudVsl0mS8wmg8GfhBpEGI +2vqVaS+631oSf0IIuIyEUIcQuU9l7Am4QAAn3YTyKkECgYEA48abEEQPGgNP9Ng1 +B6/VZAx2bghLMKtdeq+z1At3NrFNOtaooVnIeCQo0xAZK0D4aLsvTAJmvQ8cU0zg +qujSQc7uF82eCTJurQYKQjAx7w4Bcm18ylL1ovxQUCQzdneqv6P5po0kKn1Ba9ov +E1mWyR04mVUvy3EUajyteNnQ05UCgYEAzqupAXDxEfWtJeM20IcyuXo7kfmbgkPc +oOdsWyeXHHAGuXpriknDhzdHX+wVmLBK1YODY/42BywCe57ZcKLtyv+xcWJGtGLH +eimc/qPgV8QbpHEY4hWtPlRV+r51g54jrsXkaLOygVqMtISR276TdWS5QB6BcHFN +jnoh2BsYFdMCgYEA3Oh88XygjOETheq/G9JsClmP7s16Zxx8UAXiSdBI8bFprpwL +9lkGdYbUVUdysaGUiraoe3aEv+3M0flomDmv2gVgo5NXJ6JS9to5ztHBTBFwU9Ne +STfGZimBlwhVJRuQbccR1Hdk0RSkA38bUw/7jtgZUZTuAsiMPTDWKbROtTUCgYEA +rHLmcfJo5WCHWy7txTCa7dOFs3eBAEBZ79VLQACYAb2kjs4Mv/Zu9fv1TZ/0IVUx +DFpRn3U2ZeOeKsLQk0EQhKu4x3CGqOwnoNLqUjwx7WoQ2rUYW0ZVKcY7fB/CdNHW +2nX78jXHhFInSFW6U48BAhrKzSrnPQj9+x4D8YwiG8sCgYBs/gmj1JDEDcyptPTy +DpyAQ9KsgA68mEaQW4dOnydyzR4lxq8ujnED8WiDTrejvh1XcJquDFP/82Dg+Df+ +5XvXH885YZh/yNqI+rJ3zYkjEFZEK3eKJFeDKq3a6EDIJMSpnfdR170V+Db2T0JW +44Qe+CefzX8Mq7kg+D0YTgGOjA== -----END PRIVATE KEY----- diff --git a/test/hostname/Bonnie.crt b/test/hostname/Bonnie.crt index bc30780fbe84..4e71f5983824 100644 --- a/test/hostname/Bonnie.crt +++ b/test/hostname/Bonnie.crt @@ -1,24 +1,24 @@ -----BEGIN CERTIFICATE----- -MIID7jCCAtagAwIBAgIBMTANBgkqhkiG9w0BAQ0FADCBmTELMAkGA1UEBhMCVVMx +MIID7jCCAtagAwIBAgIBNTANBgkqhkiG9w0BAQ0FADCBmTELMAkGA1UEBhMCVVMx EzARBgNVBAgTCkNhbGlmb3JuaWExFDASBgNVBAcTC0xvcyBBbmdlbGVzMRkwFwYD VQQKExBIYWhpQ29ycCBUZXN0IENBMQ0wCwYDVQQLEwRUZXN0MREwDwYDVQQDEwhD ZXJ0QXV0aDEiMCAGCSqGSIb3DQEJARYTamFtZXNAaGFzaGljb3JwLmNvbTAgFw0y -MjA0MTQyMjQxNTBaGA8yMTIyMDMyMTIyNDE1MFowgYQxDzANBgNVBAMMBkJvbm5p +MjExMDExNTE2MzlaGA8yMTIyMTAwODE1MTYzOVowgYQxDzANBgNVBAMMBkJvbm5p ZTETMBEGA1UECAwKQ2FsaWZvcm5pYTELMAkGA1UEBhMCVVMxKTAnBgkqhkiG9w0B CQEWGmRvLW5vdC1yZXBseUBoYXNoaWNvcnAuY29tMRIwEAYDVQQKDAlFbmQgUG9p bnQxEDAOBgNVBAsMB1Rlc3RpbmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQDEG4RQDIbyPVcEyX8+uUcc6y5OeS95QlxkDbP5kXDaroV0VLmW3P/bkEtO -10omfCx9PFeedNI+cK6g1q6ByBkcwPmBIcfjWMmlfK5wIqb/smQJwUS2mLtSbkj/ -Eiilh6PR9mNQzosUoYFLKhQbkwYLJl+uHzMZyPVFyg/xbLBpTBkKB+2K4DAw4nAg -pojylOZo/QoC5CCUkprdLWIcvADP0rgqK/sZDrfrNltKM0I4oH2xBKPxICOMWuZD -euIKBB4y13BSMT4rWt1NfnIaVwXOhYcF9D6JXs5oXUymTR3FONm7P4QkMLdNUllW -9WZoSr7WzJ4UoZo2dqCv211t0zvNAgMBAAGjUjBQMAkGA1UdEwQCMAAwCwYDVR0P +AoIBAQDCpPFR+nO9czgQT1VLY/uCZ1O35ighW+pCuXJNSnO8xPtesXpdpV7HfijD +2G9zza5kxC3Gvg9Lh2Hj+6R1mTxJj15vqhVdj61hQrK/qbYh2NkH35BQP+z92i8x +3qp0syzCZ+Q/0CdtawZQa4milVCGtwrsBOnETCN0Qh1AzR2mJVpB7TPE49R9BbFy +GZEWlpQ1YKJu7lYDN+YFlgI5sOcVZYI9NjT+mW+RS5Zrv0nFZFsmlYuXUN+mGXmr +0rOS0Mdl1jr06EBJTxXImyfuostb8dSAJ9E7nhv5VMYrdp0ooS3XSbOxparOkh4j +2HwWY8Sv5AKqoTPjRceN/a9n7+JFAgMBAAGjUjBQMAkGA1UdEwQCMAAwCwYDVR0P BAQDAgXgMDYGA1UdEQQvMC2CEXNlcnZlci5kYzMuY29uc3Vsghhib25uaWUuc2Vy -dmVyLmRjMy5jb25zdWwwDQYJKoZIhvcNAQENBQADggEBADhkLBmIaeSLDOWvRq13 -7Ja3ufHgTIKR8dmyLU/Lmn5KIWOlz7dAk8eP4wbnxUrp3Rn4Mw7esrHtMihSBTVq -XjwpwH6BzGkT50iraaoWdv+3FojySlG10BBTDiyqoKSTfj9g5RQn65tebcxueRMO -KFlKHr3LJui/5PrkFFUDrXNqior2Qbx3ZZOhbpH0J//Rt00tJ5GDPiPV59nWcIgq -4huF7hS4F4hFf8F+Pfs535//zF0EmJYE1J7twU6RC8+XRfLBQaXHNuvLxJbZOD7X -ViqK23b1t4Xn3wYVohAkKo2OoDXj8hoKXxg9ZYPqK2BGEOWCbTPIZjz5EWX0k5vh -yrA= +dmVyLmRjMy5jb25zdWwwDQYJKoZIhvcNAQENBQADggEBABCfAENvsVaDNL88NfYF +u/C3FPjse/gIcDQYpXqTUpzbUaSZwaeV15RZEvDSu5JlFZzjW8ABaiM5+IYX3l5+ +bILkEJlVeL5VYDFAy2IymwmFXozlbAhE9kEdcubm3DCLsZtK+byP8iUCEaAu43Cr +lxny4BOsfPK+37/ojNK36DlRruUmxcuWN7Cwbg9tHCnkvZOd8e/iMY8/jPw7pzgM +TjnpahD9veEtWsTtmYpe6CiJ3JmliIeGlhlflAoVw6cw1pwgueDDiRfuFfJcsJMI +BQsSUd4DRVcgc30PgsK9cotXrCXjnFnmM7cKZUa0/JJ+8ZpoERN+6qybSZSIGns/ +tww= -----END CERTIFICATE----- diff --git a/test/hostname/Bonnie.key b/test/hostname/Bonnie.key index 82799dffefbf..da4909f39ef4 100644 --- a/test/hostname/Bonnie.key +++ b/test/hostname/Bonnie.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDEG4RQDIbyPVcE -yX8+uUcc6y5OeS95QlxkDbP5kXDaroV0VLmW3P/bkEtO10omfCx9PFeedNI+cK6g -1q6ByBkcwPmBIcfjWMmlfK5wIqb/smQJwUS2mLtSbkj/Eiilh6PR9mNQzosUoYFL -KhQbkwYLJl+uHzMZyPVFyg/xbLBpTBkKB+2K4DAw4nAgpojylOZo/QoC5CCUkprd -LWIcvADP0rgqK/sZDrfrNltKM0I4oH2xBKPxICOMWuZDeuIKBB4y13BSMT4rWt1N -fnIaVwXOhYcF9D6JXs5oXUymTR3FONm7P4QkMLdNUllW9WZoSr7WzJ4UoZo2dqCv -211t0zvNAgMBAAECggEASeIgGFSP5uXrSfdsREJjo2aLnK8VjrbMvjlXbBg6j3ke -+HQPM+JxVtRnOv3rhtJTpJ8+V4mlyDaF5DzdpDGyHF4r4lXKzEGgPwPZaI/1oPIh -tHcnHzAtquG4CLlbrPmMY8dTJZebWJt8bcgdqUHcDglYFO7WPsmydqepGAkd8Z07 -6Ze6tGhKbxoXYSDLEJ+twjLmWO52gWMUIAlDBawTikJ+ig9uzIO1EmxO7C2dUAHS -eImqoWgo4/uMKWgaFIjwFCvgLPItPmd8ej/tpAx/ASHBzAJbyOpbZM26h3+3RPte -RXwISe8Q9WSk5UnjFvy2+UKZ1KH4B1RutKGK2NM6tQKBgQDrqbzgAnCRbsW+Xy/D -jYh3JLJNpy6t+igMrV3Zzsaxf6rugJrcokvLcySeTjSD41pzkDX2JobJjP90/bAs -CFORm7e8a+M1z71JA/Hk6+nJwSlFpFynfIjPZsjTi7LgupBp+g0EGgv8kpm76l9T -lQRN96VBuePgvx62TtV4EagGGwKBgQDVB+s045fEa/KDAOJWsI1Wf589q+sztifE -02KNXWfgLGUzTDZbkGA5I+A/WTL+btRmUWlr+T9dALX8bI49Jho3CqVwGqkK1HA6 -7UykslGKaySMTcw4jU5jS64MPxCSklbeIAq9myYUESTQX7tidDjT8zMl/egiO7Ye -xMMWx/yENwKBgGPrLOzhu+69w9Pqseq8+K5jfcIU72LOnOp7Gz69QFuD4OqM1pxT -p8VURaNlTzjYTcKP04FRZnbQdIObCHYy9ZPYLTgTmlt3gC8UIBzKte5YGvKvNKXC -1JLzZpTjN223TIHShnBFxu1JDyuwvMhId3HDXWsXsPnart/nXvUwr0gfAoGBAMZm -dZvwSyxYDKgNbr6l9zwT586cCpVClI8u/54A2/lf33CDDi0ArV0KGJNnE6L6vT39 -nF0+6NBJFTReNaqljcytUZ6ydbTsXQnEb5kDqgVr+8Hfws74a4T2usYVBe479EMz -PE2R7UjLHqoiPnZXH4Xl/kDn1AXt7pOBVOAmqPrJAoGAMILgsmVBydvWvoQCYZRH -utnrswIYzDw9DeaLgktI/Sc9QJr1rswbW13Q/xMSb+czsmOV8jhUS7Vk+Xz6gzii -qtoOS9b5ojJP1Y+7gVY8sKVMsEJXm1sTA01HPd6WiN7gzbMpPzO64YzCFHYYZX1E -C+CDwDatWgLJeomG/2UNr68= +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDCpPFR+nO9czgQ +T1VLY/uCZ1O35ighW+pCuXJNSnO8xPtesXpdpV7HfijD2G9zza5kxC3Gvg9Lh2Hj ++6R1mTxJj15vqhVdj61hQrK/qbYh2NkH35BQP+z92i8x3qp0syzCZ+Q/0CdtawZQ +a4milVCGtwrsBOnETCN0Qh1AzR2mJVpB7TPE49R9BbFyGZEWlpQ1YKJu7lYDN+YF +lgI5sOcVZYI9NjT+mW+RS5Zrv0nFZFsmlYuXUN+mGXmr0rOS0Mdl1jr06EBJTxXI +myfuostb8dSAJ9E7nhv5VMYrdp0ooS3XSbOxparOkh4j2HwWY8Sv5AKqoTPjRceN +/a9n7+JFAgMBAAECggEAJv42He8nipdvbs0F0FGaTBh5DAk+ltg8CNvvyw4UO4fW +t7SkR+heIWbjscBFK5TTz/oBFaRzmfToJmz+GFT3X+Ep0QLovtKOsEJVXtIX25X+ +fHZMCdeUmZJBDCOIUFKor9VyQ1pm26OqIyg37WsuM56twHSHhDygiaTJCXdN7j+J +3JSQTUXIQI4pjwMf7GmvwaxrbOI+luxyZioXPtUbnB6fmTXrGYykuif5TV+l+C25 +QeH/nvcksJ/TnGbKFbdVVQJRSKl4oc4X3oHTujEIrn06/oQ98OGu2NTyuBTcmOGe +tkwjbMLabiPguPUml6xHh4U63oDnCVHirCrvUjlabQKBgQDpIgomMCQ7jZpkC2WO +dvtHiJPlqQAwsuhy8RziS+FKp6MZ/OcpKtTE8attxrZoEyPN9N9o4hsX2soKkWyc +IJZrppSBeBxyxAJqXXVfa1ATW4dvwCr1SUZIxqHchQFjtzsh1rTyqesCmPFvFL3w +EEIBRiadJtzQjjvbSTSXKelunwKBgQDVvHRDV60uJzJ7BmeYexzJscS9rwaMjoLI +m//4dv9u2wa3k10ZSrJQDjCT3KVzUR1x9kYp3VffAJcqYoRiHegrgBZfeziyr1gk +KbwnUN1lluPDp9f1XuZ70FTR9WW1p8vMtfFIBcEbgZHPFEr4p8KV7RuqbcHmsP8o +47VkL+UYmwKBgQDLMekIqdMauOwFIM3OYzPWgFrvw+Ivj+/8Jt0W/C4L5JrLDtvn +zLYQRdc14gmgInaFj1Wd09zraL3Kgj/YwKp6f4FWavrYqLC2RmkD1sO/a3pbU3Hd +wpTo33+6dY7le5Glh77E9oaoB+f++mQmNfVhqOQE+xdhC2duVJrq2hPkXwKBgGic +5db0OfpmCwo2F0yFrZB25xHkcfMn6ZFg8YdeTyWmJIKDqUSwz9fpKhOlIoHvyNa3 +sJ3bDaBDvLltINiZRMLN3aV8PUMQGbcRils/9C0+Dlr8cvJRMcSWMn3Ve6PO7ixT +PTaAQoVBBOnzR8Ku8cnKFQl00Twlk64izeysmJhTAoGADeHDHJ9SZGXsWx4qfAP3 +w/X0Z78hjj03F1wZy/WCT0fBo2ZPwgNvJycihs5nevvOxyh0T4kU9LcJpP4Xh9uy +xvcHXhfm730ihVVvrSbcqKipVtUQVQjKNkgi3LesUU6fVtR3cYeZjgFX8gK7qlyh +r/DA0g7GHp+pHoQ/koo15Io= -----END PRIVATE KEY----- diff --git a/test/hostname/certindex b/test/hostname/certindex index 56c177d369fb..5b723c8534b7 100644 --- a/test/hostname/certindex +++ b/test/hostname/certindex @@ -2,3 +2,7 @@ V 21220321224150Z 2E unknown /CN=Alice/ST=California/C=US/emailAddress=do-not-r V 21220321224150Z 2F unknown /CN=Bob/ST=California/C=US/emailAddress=do-not-reply@hashicorp.com/O=End Point/OU=Testing V 21220321224150Z 30 unknown /CN=Betty/ST=California/C=US/emailAddress=do-not-reply@hashicorp.com/O=End Point/OU=Testing V 21220321224150Z 31 unknown /CN=Bonnie/ST=California/C=US/emailAddress=do-not-reply@hashicorp.com/O=End Point/OU=Testing +V 21221008151638Z 32 unknown /CN=Alice/ST=California/C=US/emailAddress=do-not-reply@hashicorp.com/O=End Point/OU=Testing +V 21221008151638Z 33 unknown /CN=Bob/ST=California/C=US/emailAddress=do-not-reply@hashicorp.com/O=End Point/OU=Testing +V 21221008151638Z 34 unknown /CN=Betty/ST=California/C=US/emailAddress=do-not-reply@hashicorp.com/O=End Point/OU=Testing +V 21221008151639Z 35 unknown /CN=Bonnie/ST=California/C=US/emailAddress=do-not-reply@hashicorp.com/O=End Point/OU=Testing diff --git a/test/hostname/serialfile b/test/hostname/serialfile index f5c89552bd3e..7facc89938bb 100644 --- a/test/hostname/serialfile +++ b/test/hostname/serialfile @@ -1 +1 @@ -32 +36 diff --git a/test/integration/connect/envoy/Dockerfile-tcpdump b/test/integration/connect/envoy/Dockerfile-tcpdump index 03116e8f5a27..658cd30a2330 100644 --- a/test/integration/connect/envoy/Dockerfile-tcpdump +++ b/test/integration/connect/envoy/Dockerfile-tcpdump @@ -1,7 +1,7 @@ -FROM alpine:3.12 +FROM alpine:3.17 RUN apk add --no-cache tcpdump VOLUME [ "/data" ] CMD [ "-w", "/data/all.pcap" ] -ENTRYPOINT [ "/usr/sbin/tcpdump" ] +ENTRYPOINT [ "/usr/bin/tcpdump" ] diff --git a/test/integration/connect/envoy/case-basic/verify.bats b/test/integration/connect/envoy/case-basic/verify.bats index 65e70523d344..d89194bdab2a 100644 --- a/test/integration/connect/envoy/case-basic/verify.bats +++ b/test/integration/connect/envoy/case-basic/verify.bats @@ -33,13 +33,13 @@ load helpers @test "s1 upstream should be able to connect to s2" { run retry_default curl -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 proxy should have been configured with one rbac listener filter at L4" { LISTEN_FILTERS=$(get_envoy_listener_filters localhost:19000) - PUB=$(echo "$LISTEN_FILTERS" | grep -E "^public_listener:" | cut -f 2 -d ' ' ) - UPS=$(echo "$LISTEN_FILTERS" | grep -E "^(default\/default\/)?s2:" | cut -f 2 -d ' ' ) + PUB=$(echo "$LISTEN_FILTERS" | grep -E "^public_listener:" | cut -f 2 -d ' ') + UPS=$(echo "$LISTEN_FILTERS" | grep -E "^(default\/default\/)?s2:" | cut -f 2 -d ' ') echo "LISTEN_FILTERS = $LISTEN_FILTERS" echo "PUB = $PUB" diff --git a/test/integration/connect/envoy/case-centralconf/verify.bats b/test/integration/connect/envoy/case-centralconf/verify.bats index 0f4221ab5f1f..f2668ffcd26c 100644 --- a/test/integration/connect/envoy/case-centralconf/verify.bats +++ b/test/integration/connect/envoy/case-centralconf/verify.bats @@ -29,7 +29,7 @@ load helpers @test "s1 upstream should be able to connect to s2 with http/1.1" { run retry_default curl --http1.1 -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 proxy should be exposing metrics to prometheus from central config" { diff --git a/test/integration/connect/envoy/case-cfg-resolver-cluster-peering-failover/primary/verify.bats b/test/integration/connect/envoy/case-cfg-resolver-cluster-peering-failover/primary/verify.bats index 5b059beceb8e..b673be8cfe2c 100644 --- a/test/integration/connect/envoy/case-cfg-resolver-cluster-peering-failover/primary/verify.bats +++ b/test/integration/connect/envoy/case-cfg-resolver-cluster-peering-failover/primary/verify.bats @@ -35,7 +35,7 @@ load helpers } @test "peer the two clusters together" { - create_peering primary alpha + retry_default create_peering primary alpha } @test "s2 alpha proxies should be healthy in primary" { @@ -49,11 +49,10 @@ load helpers assert_upstream_has_endpoints_in_status 127.0.0.1:19000 failover-target~s2.default.primary-to-alpha.external HEALTHY 1 } - @test "s1 upstream should be able to connect to s2" { run retry_default curl -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 upstream made 1 connection" { @@ -68,7 +67,6 @@ load helpers assert_service_has_healthy_instances s2 0 primary } - @test "s1 upstream should have healthy endpoints for s2 in the failover cluster peer" { assert_upstream_has_endpoints_in_status 127.0.0.1:19000 failover-target~s2.default.primary.internal UNHEALTHY 1 assert_upstream_has_endpoints_in_status 127.0.0.1:19000 failover-target~s2.default.primary-to-alpha.external HEALTHY 1 @@ -85,7 +83,7 @@ load helpers @test "s1 upstream should be able to connect to s2 in the failover cluster peer" { run retry_default curl -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 upstream made 1 connection to s2 through the cluster peer" { @@ -105,7 +103,7 @@ load helpers @test "s1 upstream should be able to connect to s2 via virtual-s2" { run retry_default curl -s -f -d hello localhost:5001 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 upstream made 1 connection to s2 via virtual-s2 through the cluster peer" { diff --git a/test/integration/connect/envoy/case-cfg-resolver-svc-redirect-http/verify.bats b/test/integration/connect/envoy/case-cfg-resolver-svc-redirect-http/verify.bats index 39462d6e157f..d252e070590f 100644 --- a/test/integration/connect/envoy/case-cfg-resolver-svc-redirect-http/verify.bats +++ b/test/integration/connect/envoy/case-cfg-resolver-svc-redirect-http/verify.bats @@ -37,10 +37,9 @@ load helpers @test "s1 upstream should be able to connect to its upstream simply" { run retry_default curl -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 upstream should be able to connect to s3 via upstream s2" { assert_expected_fortio_name s3 } - diff --git a/test/integration/connect/envoy/case-cfg-resolver-svc-redirect-tcp/verify.bats b/test/integration/connect/envoy/case-cfg-resolver-svc-redirect-tcp/verify.bats index 39462d6e157f..d252e070590f 100644 --- a/test/integration/connect/envoy/case-cfg-resolver-svc-redirect-tcp/verify.bats +++ b/test/integration/connect/envoy/case-cfg-resolver-svc-redirect-tcp/verify.bats @@ -37,10 +37,9 @@ load helpers @test "s1 upstream should be able to connect to its upstream simply" { run retry_default curl -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 upstream should be able to connect to s3 via upstream s2" { assert_expected_fortio_name s3 } - diff --git a/test/integration/connect/envoy/case-cfg-splitter-cluster-peering/primary/verify.bats b/test/integration/connect/envoy/case-cfg-splitter-cluster-peering/primary/verify.bats index 718dac6e7c2f..e442e307316f 100644 --- a/test/integration/connect/envoy/case-cfg-splitter-cluster-peering/primary/verify.bats +++ b/test/integration/connect/envoy/case-cfg-splitter-cluster-peering/primary/verify.bats @@ -31,7 +31,7 @@ load helpers } @test "peer the two clusters together" { - create_peering primary alpha + retry_default create_peering primary alpha } @test "s2 alpha proxies should be healthy in primary" { diff --git a/test/integration/connect/envoy/case-cfg-splitter-peering-ingress-gateways/primary/verify.bats b/test/integration/connect/envoy/case-cfg-splitter-peering-ingress-gateways/primary/verify.bats index e12e7058ec32..fabbdf0f2837 100644 --- a/test/integration/connect/envoy/case-cfg-splitter-peering-ingress-gateways/primary/verify.bats +++ b/test/integration/connect/envoy/case-cfg-splitter-peering-ingress-gateways/primary/verify.bats @@ -2,7 +2,6 @@ load helpers - @test "ingress-primary proxy admin is up" { retry_default curl -f -s localhost:20000/stats -o /dev/null } @@ -12,7 +11,7 @@ load helpers } @test "services should be healthy in primary" { - assert_service_has_healthy_instances s1 1 alpha + assert_service_has_healthy_instances s1 1 primary } @test "services should be healthy in alpha" { @@ -26,7 +25,12 @@ load helpers } @test "peer the two clusters together" { - create_peering primary alpha + retry_long create_peering primary alpha +} + +@test "s1, s2 alpha proxies should be imported to primary" { + retry_long assert_service_has_imported primary s1 primary-to-alpha + retry_long assert_service_has_imported primary s2 primary-to-alpha } @test "s1 alpha proxies should be healthy in primary" { @@ -67,4 +71,5 @@ load helpers @test "requests through ingress to splitter should go to alpha" { retry_long assert_expected_fortio_name s1-alpha split.ingress.consul 10002 retry_long assert_expected_fortio_name s2-alpha split.ingress.consul 10002 -} \ No newline at end of file +} + diff --git a/test/integration/connect/envoy/case-cross-peer-control-plane-mgw/alpha/verify.bats b/test/integration/connect/envoy/case-cross-peer-control-plane-mgw/alpha/verify.bats index 06314df9034a..4568f6030f53 100644 --- a/test/integration/connect/envoy/case-cross-peer-control-plane-mgw/alpha/verify.bats +++ b/test/integration/connect/envoy/case-cross-peer-control-plane-mgw/alpha/verify.bats @@ -38,12 +38,6 @@ load helpers assert_upstream_has_endpoints_in_status 127.0.0.1:19003 server.primary.peering HEALTHY 1 } -# Re-peering the clusters is a way to have alpha dial out through its own gateway -# since we know it is configured with endpoints for primary from the first time they peered. -@test "re-peer the two clusters together" { - create_peering primary alpha -} - -@test "alpha servers made connection to primary servers via alpha gateway" { +@test "dialer servers in alpha made connection to primary servers via alpha gateway" { assert_envoy_metric_at_least 127.0.0.1:19003 "cluster.server.primary.peering.*cx_total" 1 -} \ No newline at end of file +} diff --git a/test/integration/connect/envoy/case-cross-peer-control-plane-mgw/primary/verify.bats b/test/integration/connect/envoy/case-cross-peer-control-plane-mgw/primary/verify.bats index bc21d5ee3fc0..784881098a28 100644 --- a/test/integration/connect/envoy/case-cross-peer-control-plane-mgw/primary/verify.bats +++ b/test/integration/connect/envoy/case-cross-peer-control-plane-mgw/primary/verify.bats @@ -31,7 +31,12 @@ load helpers } @test "peer the two clusters together" { - create_peering primary alpha + retry_default create_peering primary alpha +} + +@test "s2 alpha proxies should be imported in primary" { + retry_long assert_service_has_imported primary s2 primary-to-alpha + [ "$status" -eq 0 ] } @test "acceptor gateway-primary should have healthy endpoints for primary servers" { @@ -57,7 +62,7 @@ load helpers @test "s1 upstream should be able to connect to s2" { run retry_default curl -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 upstream made 1 connection to s2" { diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/primary/verify.bats b/test/integration/connect/envoy/case-cross-peers-http-router/primary/verify.bats index 68a3fe501105..a11c12441d4d 100644 --- a/test/integration/connect/envoy/case-cross-peers-http-router/primary/verify.bats +++ b/test/integration/connect/envoy/case-cross-peers-http-router/primary/verify.bats @@ -35,7 +35,7 @@ load helpers } @test "peer the two clusters together" { - create_peering primary alpha + retry_default create_peering primary alpha } @test "s2 alpha proxies should be healthy in primary" { @@ -57,7 +57,7 @@ load helpers @test "s1 upstream should be able to connect to s2 with http/1.1" { run retry_default curl --http1.1 -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 upstream should be able to connect to s2 via s2" { diff --git a/test/integration/connect/envoy/case-cross-peers-http/primary/config_entries.hcl b/test/integration/connect/envoy/case-cross-peers-http/primary/config_entries.hcl index 3bba325301fd..ecb777e7f96a 100644 --- a/test/integration/connect/envoy/case-cross-peers-http/primary/config_entries.hcl +++ b/test/integration/connect/envoy/case-cross-peers-http/primary/config_entries.hcl @@ -5,7 +5,8 @@ config_entries { name = "global" config { - protocol = "http" + # This shouldn't affect the imported listener's protocol, which should be http. + protocol = "tcp" } } ] diff --git a/test/integration/connect/envoy/case-cross-peers-http/primary/verify.bats b/test/integration/connect/envoy/case-cross-peers-http/primary/verify.bats index bdc7ac390f27..7ae3901d981e 100644 --- a/test/integration/connect/envoy/case-cross-peers-http/primary/verify.bats +++ b/test/integration/connect/envoy/case-cross-peers-http/primary/verify.bats @@ -31,7 +31,7 @@ load helpers } @test "peer the two clusters together" { - create_peering primary alpha + retry_default create_peering primary alpha } @test "s2 alpha proxies should be healthy in primary" { @@ -49,7 +49,7 @@ load helpers @test "s1 upstream should be able to connect to s2 with http/1.1" { run retry_default curl --http1.1 -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 upstream made 1 connection to s2" { diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/verify.bats b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/verify.bats index 1f2b26d7ac27..7524d32aac48 100644 --- a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/verify.bats +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/verify.bats @@ -31,7 +31,7 @@ load helpers } @test "peer the two clusters together" { - create_peering primary alpha + retry_default create_peering primary alpha } @test "s2 alpha proxies should be healthy in primary" { @@ -49,7 +49,7 @@ load helpers @test "s1 upstream should be able to connect to s2" { run retry_default curl -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 upstream should be able to connect to s3 via s2 due to redirect" { diff --git a/test/integration/connect/envoy/case-cross-peers/primary/verify.bats b/test/integration/connect/envoy/case-cross-peers/primary/verify.bats index af45d2ad3f11..3ded23af576f 100644 --- a/test/integration/connect/envoy/case-cross-peers/primary/verify.bats +++ b/test/integration/connect/envoy/case-cross-peers/primary/verify.bats @@ -31,7 +31,7 @@ load helpers } @test "peer the two clusters together" { - create_peering primary alpha + retry_default create_peering primary alpha } @test "s2 alpha proxies should be healthy in primary" { @@ -49,7 +49,7 @@ load helpers @test "s1 upstream should be able to connect to s2" { run retry_default curl -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 upstream made 1 connection to s2" { diff --git a/test/integration/connect/envoy/case-dogstatsd-udp/verify.bats b/test/integration/connect/envoy/case-dogstatsd-udp/verify.bats index 463f146b2b9e..55b0ad76849c 100644 --- a/test/integration/connect/envoy/case-dogstatsd-udp/verify.bats +++ b/test/integration/connect/envoy/case-dogstatsd-udp/verify.bats @@ -20,12 +20,7 @@ load helpers } @test "s1 upstream should be able to connect to s2" { - run retry_default curl -s -f -d hello localhost:5000 - - echo "OUTPUT: $output" - - [ "$status" == 0 ] - [ "$output" == "hello" ] + retry_default assert_upstream_message 5000 } @test "s1 proxy should be sending metrics to statsd" { diff --git a/test/integration/connect/envoy/case-expose-checks/verify.bats b/test/integration/connect/envoy/case-expose-checks/verify.bats index 0c4dcbb2c1c6..7467e6c55cd7 100644 --- a/test/integration/connect/envoy/case-expose-checks/verify.bats +++ b/test/integration/connect/envoy/case-expose-checks/verify.bats @@ -33,7 +33,7 @@ load helpers @test "s1 upstream should be able to connect to s2" { run retry_default curl -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s2 exposes checks on a new listener" { diff --git a/test/integration/connect/envoy/case-gateways-local/primary/verify.bats b/test/integration/connect/envoy/case-gateways-local/primary/verify.bats index 1d55c794e0b8..cde8cedb0de7 100644 --- a/test/integration/connect/envoy/case-gateways-local/primary/verify.bats +++ b/test/integration/connect/envoy/case-gateways-local/primary/verify.bats @@ -24,17 +24,17 @@ load helpers } @test "gateway-primary should have healthy endpoints for secondary" { - assert_upstream_has_endpoints_in_status 127.0.0.1:19002 secondary HEALTHY 1 + assert_upstream_has_endpoints_in_status 127.0.0.1:19002 secondary HEALTHY 1 } @test "gateway-secondary should have healthy endpoints for s2" { - assert_upstream_has_endpoints_in_status consul-secondary-client:19003 s2 HEALTHY 1 + assert_upstream_has_endpoints_in_status consul-secondary-client:19003 s2 HEALTHY 1 } @test "s1 upstream should be able to connect to s2" { run retry_default curl -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 upstream made 1 connection" { diff --git a/test/integration/connect/envoy/case-gateways-remote/primary/verify.bats b/test/integration/connect/envoy/case-gateways-remote/primary/verify.bats index 825872e57d53..9bbfeb6a89dd 100644 --- a/test/integration/connect/envoy/case-gateways-remote/primary/verify.bats +++ b/test/integration/connect/envoy/case-gateways-remote/primary/verify.bats @@ -22,7 +22,7 @@ load helpers @test "s1 upstream should be able to connect to s2" { run retry_default curl -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 upstream made 1 connection" { diff --git a/test/integration/connect/envoy/case-http/verify.bats b/test/integration/connect/envoy/case-http/verify.bats index 0f65d46d3042..434abbd2095c 100644 --- a/test/integration/connect/envoy/case-http/verify.bats +++ b/test/integration/connect/envoy/case-http/verify.bats @@ -30,13 +30,13 @@ load helpers @test "s1 upstream should be able to connect to s2 with http/1.1" { run retry_default curl --http1.1 -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 proxy should have been configured with http connection managers" { LISTEN_FILTERS=$(get_envoy_listener_filters localhost:19000) - PUB=$(echo "$LISTEN_FILTERS" | grep -E "^public_listener:" | cut -f 2 -d ' ' ) - UPS=$(echo "$LISTEN_FILTERS" | grep -E "^(default\/default\/)?s2:" | cut -f 2 -d ' ' ) + PUB=$(echo "$LISTEN_FILTERS" | grep -E "^public_listener:" | cut -f 2 -d ' ') + UPS=$(echo "$LISTEN_FILTERS" | grep -E "^(default\/default\/)?s2:" | cut -f 2 -d ' ') echo "LISTEN_FILTERS = $LISTEN_FILTERS" echo "PUB = $PUB" @@ -48,7 +48,7 @@ load helpers @test "s2 proxy should have been configured with an http connection manager" { LISTEN_FILTERS=$(get_envoy_listener_filters localhost:19001) - PUB=$(echo "$LISTEN_FILTERS" | grep -E "^public_listener:" | cut -f 2 -d ' ' ) + PUB=$(echo "$LISTEN_FILTERS" | grep -E "^public_listener:" | cut -f 2 -d ' ') echo "LISTEN_FILTERS = $LISTEN_FILTERS" echo "PUB = $PUB" @@ -58,8 +58,8 @@ load helpers @test "s1 proxy should have been configured with http rbac filters" { HTTP_FILTERS=$(get_envoy_http_filters localhost:19000) - PUB=$(echo "$HTTP_FILTERS" | grep -E "^public_listener:" | cut -f 2 -d ' ' ) - UPS=$(echo "$HTTP_FILTERS" | grep -E "^(default\/default\/)?s2:" | cut -f 2 -d ' ' ) + PUB=$(echo "$HTTP_FILTERS" | grep -E "^public_listener:" | cut -f 2 -d ' ') + UPS=$(echo "$HTTP_FILTERS" | grep -E "^(default\/default\/)?s2:" | cut -f 2 -d ' ') echo "HTTP_FILTERS = $HTTP_FILTERS" echo "PUB = $PUB" @@ -71,7 +71,7 @@ load helpers @test "s2 proxy should have been configured with http rbac filters" { HTTP_FILTERS=$(get_envoy_http_filters localhost:19001) - PUB=$(echo "$HTTP_FILTERS" | grep -E "^public_listener:" | cut -f 2 -d ' ' ) + PUB=$(echo "$HTTP_FILTERS" | grep -E "^public_listener:" | cut -f 2 -d ' ') echo "HTTP_FILTERS = $HTTP_FILTERS" echo "PUB = $PUB" diff --git a/test/integration/connect/envoy/case-ingress-gateway-peering-failover/primary/verify.bats b/test/integration/connect/envoy/case-ingress-gateway-peering-failover/primary/verify.bats index 9429a9d60e36..630a4d4ec227 100644 --- a/test/integration/connect/envoy/case-ingress-gateway-peering-failover/primary/verify.bats +++ b/test/integration/connect/envoy/case-ingress-gateway-peering-failover/primary/verify.bats @@ -23,7 +23,7 @@ load helpers } @test "peer the two clusters together" { - create_peering primary alpha + retry_default create_peering primary alpha } @test "s2 alpha proxies should be healthy in primary" { @@ -37,7 +37,6 @@ load helpers assert_upstream_has_endpoints_in_status 127.0.0.1:20000 failover-target~s2.default.primary-to-alpha.external HEALTHY 1 } - @test "ingress-gateway should be able to connect to s2" { assert_expected_fortio_name s2 127.0.0.1 10000 } @@ -54,7 +53,6 @@ load helpers assert_service_has_healthy_instances s2 0 primary } - @test "s1 upstream should have healthy endpoints for s2 in the failover cluster peer" { assert_upstream_has_endpoints_in_status 127.0.0.1:20000 failover-target~s2.default.primary.internal UNHEALTHY 1 assert_upstream_has_endpoints_in_status 127.0.0.1:20000 failover-target~s2.default.primary-to-alpha.external HEALTHY 1 diff --git a/test/integration/connect/envoy/case-ingress-gateway-simple/verify.bats b/test/integration/connect/envoy/case-ingress-gateway-simple/verify.bats index 9d0735b42ce0..ea83b36d1468 100644 --- a/test/integration/connect/envoy/case-ingress-gateway-simple/verify.bats +++ b/test/integration/connect/envoy/case-ingress-gateway-simple/verify.bats @@ -42,5 +42,5 @@ load helpers @test "ingress should be able to connect to s1 via configured port" { run retry_default curl -s -f -d hello localhost:9999 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } diff --git a/test/integration/connect/envoy/case-ingress-gateway-tls/verify.bats b/test/integration/connect/envoy/case-ingress-gateway-tls/verify.bats index 6ee2288908d0..61eaaf97ccdf 100644 --- a/test/integration/connect/envoy/case-ingress-gateway-tls/verify.bats +++ b/test/integration/connect/envoy/case-ingress-gateway-tls/verify.bats @@ -19,7 +19,7 @@ load helpers } @test "ingress-gateway should have healthy endpoints for s1" { - assert_upstream_has_endpoints_in_status 127.0.0.1:20000 s1 HEALTHY 1 + assert_upstream_has_endpoints_in_status 127.0.0.1:20000 s1 HEALTHY 1 } @test "should be able to connect to s1 through the TLS-enabled ingress port" { @@ -30,7 +30,7 @@ load helpers --resolve s1.ingress.consul:9998:127.0.0.1 \ https://s1.ingress.consul:9998 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "should be able to connect to s1 through the TLS-enabled ingress port using the custom host" { @@ -39,5 +39,5 @@ load helpers --resolve test.example.com:9999:127.0.0.1 \ https://test.example.com:9999 [ "$status" -eq 0 ] - [ "$output" = "hello" ] -} \ No newline at end of file + [[ "$output" == *"hello"* ]] +} diff --git a/test/integration/connect/envoy/case-ingress-mesh-gateways-resolver/primary/verify.bats b/test/integration/connect/envoy/case-ingress-mesh-gateways-resolver/primary/verify.bats index f8376ee342d3..b621bdfc5119 100644 --- a/test/integration/connect/envoy/case-ingress-mesh-gateways-resolver/primary/verify.bats +++ b/test/integration/connect/envoy/case-ingress-mesh-gateways-resolver/primary/verify.bats @@ -19,21 +19,21 @@ load helpers } @test "gateway-primary should have healthy endpoints for secondary" { - assert_upstream_has_endpoints_in_status 127.0.0.1:19002 secondary HEALTHY 1 + assert_upstream_has_endpoints_in_status 127.0.0.1:19002 secondary HEALTHY 1 } @test "gateway-secondary should have healthy endpoints for s1" { - assert_upstream_has_endpoints_in_status consul-secondary-client:19003 s1 HEALTHY 1 + assert_upstream_has_endpoints_in_status consul-secondary-client:19003 s1 HEALTHY 1 } @test "gateway-secondary should have healthy endpoints for s2" { - assert_upstream_has_endpoints_in_status consul-secondary-client:19003 s2 HEALTHY 1 + assert_upstream_has_endpoints_in_status consul-secondary-client:19003 s2 HEALTHY 1 } @test "ingress should be able to connect to s1" { run retry_default curl -s -f -d hello localhost:10000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "ingress made 1 connection to s1" { @@ -47,7 +47,7 @@ load helpers @test "ingress should be able to connect to s2" { run retry_default curl -s -f -d hello localhost:9999 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "ingress made 1 connection to s2" { diff --git a/test/integration/connect/envoy/case-multidc-rsa-ca/primary/verify.bats b/test/integration/connect/envoy/case-multidc-rsa-ca/primary/verify.bats index 57f3f4a64052..00d2afc34d48 100644 --- a/test/integration/connect/envoy/case-multidc-rsa-ca/primary/verify.bats +++ b/test/integration/connect/envoy/case-multidc-rsa-ca/primary/verify.bats @@ -21,7 +21,7 @@ load helpers @test "s1 upstream should be able to connect to s2" { run retry_default curl -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 upstream made 1 connection" { @@ -40,4 +40,4 @@ load helpers echo "KEY_TYPE: $KEY_TYPE" [ "$KEY_TYPE" == "rsa" ] -} \ No newline at end of file +} diff --git a/test/integration/connect/envoy/case-prometheus/verify.bats b/test/integration/connect/envoy/case-prometheus/verify.bats index 3d886b60bd46..efaba3815787 100644 --- a/test/integration/connect/envoy/case-prometheus/verify.bats +++ b/test/integration/connect/envoy/case-prometheus/verify.bats @@ -30,7 +30,7 @@ load helpers @test "s1 upstream should be able to connect to s2 with http/1.1" { run retry_default curl --http1.1 -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 proxy should be exposing metrics to prometheus" { diff --git a/test/integration/connect/envoy/case-stats-proxy/verify.bats b/test/integration/connect/envoy/case-stats-proxy/verify.bats index 285cdd6cbc09..2d02010dc185 100644 --- a/test/integration/connect/envoy/case-stats-proxy/verify.bats +++ b/test/integration/connect/envoy/case-stats-proxy/verify.bats @@ -30,7 +30,7 @@ load helpers @test "s1 upstream should be able to connect to s2 with http/1.1" { run retry_default curl --http1.1 -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "s1 proxy should be exposing the /stats prefix" { @@ -47,16 +47,16 @@ load helpers # Response should include the http public listener. retry_default \ - must_match_in_stats_proxy_response localhost:1239 \ + must_match_in_stats_proxy_response localhost:1239 \ 'stats' 'http.public_listener' # /stats/prometheus should also be reachable and labelling the local cluster. retry_default \ - must_match_in_stats_proxy_response localhost:1239 \ + must_match_in_stats_proxy_response localhost:1239 \ 'stats/prometheus' '[\{,]consul_source_service="s1"[,}]' # /stats/prometheus should also be reachable and exposing metrics. retry_default \ - must_match_in_stats_proxy_response localhost:1239 \ + must_match_in_stats_proxy_response localhost:1239 \ 'stats/prometheus' 'envoy_http_downstream_rq_active' } diff --git a/test/integration/connect/envoy/case-statsd-udp/verify.bats b/test/integration/connect/envoy/case-statsd-udp/verify.bats index 05d37614a3dc..f32f54e505de 100644 --- a/test/integration/connect/envoy/case-statsd-udp/verify.bats +++ b/test/integration/connect/envoy/case-statsd-udp/verify.bats @@ -20,9 +20,7 @@ load helpers } @test "s1 upstream should be able to connect to s2" { - run retry_default curl -s -f -d hello localhost:5000 - [ "$status" == 0 ] - [ "$output" == "hello" ] + retry_default assert_upstream_message 5000 } @test "s1 proxy should be sending metrics to statsd" { diff --git a/test/integration/connect/envoy/case-terminating-gateway-hostnames/verify.bats b/test/integration/connect/envoy/case-terminating-gateway-hostnames/verify.bats index af76cb426bb0..f00a783eefdf 100644 --- a/test/integration/connect/envoy/case-terminating-gateway-hostnames/verify.bats +++ b/test/integration/connect/envoy/case-terminating-gateway-hostnames/verify.bats @@ -15,7 +15,7 @@ load helpers } @test "terminating-gateway should have healthy endpoints for s4" { - assert_upstream_has_endpoints_in_status 127.0.0.1:20000 s4 HEALTHY 1 + assert_upstream_has_endpoints_in_status 127.0.0.1:20000 s4 HEALTHY 1 } @test "s1 upstream should have healthy endpoints for s4" { @@ -25,7 +25,7 @@ load helpers @test "s1 upstream should be able to connect to s4" { run retry_default curl -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "terminating-gateway is used for the upstream connection" { diff --git a/test/integration/connect/envoy/case-terminating-gateway-simple/verify.bats b/test/integration/connect/envoy/case-terminating-gateway-simple/verify.bats index 48983be21e9d..13ba7a911597 100644 --- a/test/integration/connect/envoy/case-terminating-gateway-simple/verify.bats +++ b/test/integration/connect/envoy/case-terminating-gateway-simple/verify.bats @@ -15,7 +15,7 @@ load helpers } @test "terminating-gateway should have healthy endpoints for s2" { - assert_upstream_has_endpoints_in_status 127.0.0.1:20000 s2 HEALTHY 1 + assert_upstream_has_endpoints_in_status 127.0.0.1:20000 s2 HEALTHY 1 } @test "s1 upstream should have healthy endpoints for s2" { @@ -25,7 +25,7 @@ load helpers @test "s1 upstream should be able to connect to s2" { run retry_default curl -s -f -d hello localhost:5000 [ "$status" -eq 0 ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } @test "terminating-gateway is used for the upstream connection" { diff --git a/test/integration/connect/envoy/case-terminating-gateway-subsets/capture.sh b/test/integration/connect/envoy/case-terminating-gateway-subsets/capture.sh index 2ef0c41a215e..261bf4e29a6c 100644 --- a/test/integration/connect/envoy/case-terminating-gateway-subsets/capture.sh +++ b/test/integration/connect/envoy/case-terminating-gateway-subsets/capture.sh @@ -2,3 +2,4 @@ snapshot_envoy_admin localhost:20000 terminating-gateway primary || true snapshot_envoy_admin localhost:19000 s1 primary || true +snapshot_envoy_admin localhost:19001 s3 primary || true diff --git a/test/integration/connect/envoy/case-terminating-gateway-subsets/service_s3.hcl b/test/integration/connect/envoy/case-terminating-gateway-subsets/service_s3.hcl new file mode 100644 index 000000000000..eb84c578ee9e --- /dev/null +++ b/test/integration/connect/envoy/case-terminating-gateway-subsets/service_s3.hcl @@ -0,0 +1,17 @@ +services { + id = "s3" + name = "s3" + port = 8184 + connect { + sidecar_service { + proxy { + upstreams = [ + { + destination_name = "s2" + local_bind_port = 8185 + } + ] + } + } + } +} diff --git a/test/integration/connect/envoy/case-terminating-gateway-subsets/setup.sh b/test/integration/connect/envoy/case-terminating-gateway-subsets/setup.sh index 850b47c68c9a..198e5a14ae37 100644 --- a/test/integration/connect/envoy/case-terminating-gateway-subsets/setup.sh +++ b/test/integration/connect/envoy/case-terminating-gateway-subsets/setup.sh @@ -11,4 +11,5 @@ register_services primary # terminating gateway will act as s2's proxy gen_envoy_bootstrap s1 19000 +gen_envoy_bootstrap s3 19001 gen_envoy_bootstrap terminating-gateway 20000 primary true diff --git a/test/integration/connect/envoy/case-terminating-gateway-subsets/vars.sh b/test/integration/connect/envoy/case-terminating-gateway-subsets/vars.sh index 9e52629b8bed..d4a4d75bdd88 100644 --- a/test/integration/connect/envoy/case-terminating-gateway-subsets/vars.sh +++ b/test/integration/connect/envoy/case-terminating-gateway-subsets/vars.sh @@ -4,5 +4,6 @@ export REQUIRED_SERVICES=" s1 s1-sidecar-proxy s2-v1 +s3 s3-sidecar-proxy terminating-gateway-primary " diff --git a/test/integration/connect/envoy/case-terminating-gateway-subsets/verify.bats b/test/integration/connect/envoy/case-terminating-gateway-subsets/verify.bats index 64a2499e3575..028ddea85ade 100644 --- a/test/integration/connect/envoy/case-terminating-gateway-subsets/verify.bats +++ b/test/integration/connect/envoy/case-terminating-gateway-subsets/verify.bats @@ -38,3 +38,7 @@ load helpers assert_envoy_metric_at_least 127.0.0.1:20000 "v1.s2.default.primary.*cx_total" 1 } +@test "terminating-gateway is used for the upstream connection of the proxy" { + # make sure we resolve the terminating gateway as endpoint for the upstream + assert_upstream_has_endpoint_port 127.0.0.1:19001 "v1.s2" 8443 +} diff --git a/test/integration/connect/envoy/case-upstream-config/service_s1.hcl b/test/integration/connect/envoy/case-upstream-config/service_s1.hcl index b3d4db73b8fd..57969842f284 100644 --- a/test/integration/connect/envoy/case-upstream-config/service_s1.hcl +++ b/test/integration/connect/envoy/case-upstream-config/service_s1.hcl @@ -17,6 +17,9 @@ services { passive_health_check { interval = "22s" max_failures = 4 + enforcing_consecutive_5xx = 99 + max_ejection_percent = 50 + base_ejection_time = "60s" } } } diff --git a/test/integration/connect/envoy/case-upstream-config/verify.bats b/test/integration/connect/envoy/case-upstream-config/verify.bats index a6c025ac89a6..fbe8ef401d02 100644 --- a/test/integration/connect/envoy/case-upstream-config/verify.bats +++ b/test/integration/connect/envoy/case-upstream-config/verify.bats @@ -49,4 +49,7 @@ load helpers [ "$(echo $CLUSTER_CONFIG | jq --raw-output '.outlier_detection.consecutive_5xx')" = "4" ] [ "$(echo $CLUSTER_CONFIG | jq --raw-output '.outlier_detection.interval')" = "22s" ] + [ "$(echo $CLUSTER_CONFIG | jq --raw-output '.outlier_detection.enforcing_consecutive_5xx')" = "99" ] + [ "$(echo $CLUSTER_CONFIG | jq --raw-output '.outlier_detection.max_ejection_percent')" = "50" ] + [ "$(echo $CLUSTER_CONFIG | jq --raw-output '.outlier_detection.base_ejection_time')" = "60s" ] } diff --git a/test/integration/connect/envoy/case-zipkin/verify.bats b/test/integration/connect/envoy/case-zipkin/verify.bats index 98f11056ef1e..d771d523639a 100644 --- a/test/integration/connect/envoy/case-zipkin/verify.bats +++ b/test/integration/connect/envoy/case-zipkin/verify.bats @@ -28,9 +28,7 @@ load helpers } @test "s1 upstream should be able to connect to s2" { - run retry_default curl -s -f -d hello localhost:5000 - [ "$status" == "0" ] - [ "$output" == "hello" ] + retry_default assert_upstream_message 5000 } @test "s1 proxy should send trace spans to zipkin/jaeger" { diff --git a/test/integration/connect/envoy/consul-base-cfg/peering_server.hcl b/test/integration/connect/envoy/consul-base-cfg/peering_server.hcl deleted file mode 100644 index ccbba6939c43..000000000000 --- a/test/integration/connect/envoy/consul-base-cfg/peering_server.hcl +++ /dev/null @@ -1,6 +0,0 @@ -ports { - grpc_tls = 8503 -} -connect { - enabled = true -} \ No newline at end of file diff --git a/test/integration/connect/envoy/helpers.bash b/test/integration/connect/envoy/helpers.bash index 760eaea1a8e6..3ac4d4d3f5d4 100755 --- a/test/integration/connect/envoy/helpers.bash +++ b/test/integration/connect/envoy/helpers.bash @@ -11,18 +11,14 @@ function retry { shift local errtrace=0 - if grep -q "errtrace" <<< "$SHELLOPTS" - then + if grep -q "errtrace" <<<"$SHELLOPTS"; then errtrace=1 set +E fi - for ((i=1;i<=$max;i++)) - do - if "$@" - then - if test $errtrace -eq 1 - then + for ((i = 1; i <= $max; i++)); do + if "$@"; then + if test $errtrace -eq 1; then set -E fi return 0 @@ -32,8 +28,7 @@ function retry { fi done - if test $errtrace -eq 1 - then + if test $errtrace -eq 1; then set -E fi return 1 @@ -51,23 +46,42 @@ function retry_long { retry 30 1 "$@" } +# assert_upstream_message asserts both the returned code +# and message from upstream service +function assert_upstream_message { + local HOSTPORT=$1 + run curl -s -d hello localhost:$HOSTPORT + + if [ "$status" -ne 0 ]; then + echo "Command failed" + return 1 + fi + + if (echo $output | grep 'hello'); then + return 0 + fi + + echo "expected message not found in $output" + return 1 +} + function is_set { - # Arguments: - # $1 - string value to check its truthiness - # - # Return: - # 0 - is truthy (backwards I know but allows syntax like `if is_set ` to work) - # 1 - is not truthy - - local val=$(tr '[:upper:]' '[:lower:]' <<< "$1") - case $val in - 1 | t | true | y | yes) - return 0 - ;; - *) - return 1 - ;; - esac + # Arguments: + # $1 - string value to check its truthiness + # + # Return: + # 0 - is truthy (backwards I know but allows syntax like `if is_set ` to work) + # 1 - is not truthy + + local val=$(tr '[:upper:]' '[:lower:]' <<<"$1") + case $val in + 1 | t | true | y | yes) + return 0 + ;; + *) + return 1 + ;; + esac } function get_cert { @@ -79,7 +93,7 @@ function get_cert { SNI_FLAG="-servername $SERVER_NAME" fi CERT=$(openssl s_client -connect $HOSTPORT $SNI_FLAG -showcerts "${OUTDIR}/config_dump.json" - docker_wget "$DC" "http://${HOSTPORT}/clusters?format=json" -q -O - > "${OUTDIR}/clusters.json" - docker_wget "$DC" "http://${HOSTPORT}/stats" -q -O - > "${OUTDIR}/stats.txt" - docker_wget "$DC" "http://${HOSTPORT}/stats/prometheus" -q -O - > "${OUTDIR}/stats_prometheus.txt" + docker_wget "$DC" "http://${HOSTPORT}/config_dump" -q -O - >"${OUTDIR}/config_dump.json" + docker_wget "$DC" "http://${HOSTPORT}/clusters?format=json" -q -O - >"${OUTDIR}/clusters.json" + docker_wget "$DC" "http://${HOSTPORT}/stats" -q -O - >"${OUTDIR}/stats.txt" + docker_wget "$DC" "http://${HOSTPORT}/stats/prometheus" -q -O - >"${OUTDIR}/stats_prometheus.txt" } function reset_envoy_metrics { @@ -323,6 +337,49 @@ function get_envoy_metrics { get_all_envoy_metrics $HOSTPORT | grep "$METRICS" } +function get_upstream_endpoint { + local HOSTPORT=$1 + local CLUSTER_NAME=$2 + run curl -s -f "http://${HOSTPORT}/clusters?format=json" + [ "$status" -eq 0 ] + echo "$output" | jq --raw-output " +.cluster_statuses[] +| select(.name|startswith(\"${CLUSTER_NAME}\"))" +} + +function get_upstream_endpoint_port { + local HOSTPORT=$1 + local CLUSTER_NAME=$2 + local PORT_VALUE=$3 + run curl -s -f "http://${HOSTPORT}/clusters?format=json" + [ "$status" -eq 0 ] + echo "$output" | jq --raw-output " +.cluster_statuses[] +| select(.name|startswith(\"${CLUSTER_NAME}\")) +| [.host_statuses[].address.socket_address.port_value] +| [select(.[] == ${PORT_VALUE})] +| length" +} + +function assert_upstream_has_endpoint_port_once { + local HOSTPORT=$1 + local CLUSTER_NAME=$2 + local PORT_VALUE=$3 + + GOT_COUNT=$(get_upstream_endpoint_port $HOSTPORT $CLUSTER_NAME $PORT_VALUE) + + [ "$GOT_COUNT" -eq 1 ] +} + +function assert_upstream_has_endpoint_port { + local HOSTPORT=$1 + local CLUSTER_NAME=$2 + local PORT_VALUE=$3 + + run retry_long assert_upstream_has_endpoint_port_once $HOSTPORT $CLUSTER_NAME $PORT_VALUE + [ "$status" -eq 0 ] +} + function get_upstream_endpoint_in_status_count { local HOSTPORT=$1 local CLUSTER_NAME=$2 @@ -345,15 +402,37 @@ function assert_upstream_has_endpoints_in_status_once { GOT_COUNT=$(get_upstream_endpoint_in_status_count $HOSTPORT $CLUSTER_NAME $HEALTH_STATUS) + echo "GOT: $GOT_COUNT" [ "$GOT_COUNT" -eq $EXPECT_COUNT ] } +function assert_upstream_missing_once { + local HOSTPORT=$1 + local CLUSTER_NAME=$2 + + run get_upstream_endpoint $HOSTPORT $CLUSTER_NAME + [ "$status" -eq 0 ] + echo "$output" + [ "" == "$output" ] +} + +function assert_upstream_missing { + local HOSTPORT=$1 + local CLUSTER_NAME=$2 + run retry_long assert_upstream_missing_once $HOSTPORT $CLUSTER_NAME + echo "OUTPUT: $output $status" + + [ "$status" -eq 0 ] +} + function assert_upstream_has_endpoints_in_status { local HOSTPORT=$1 local CLUSTER_NAME=$2 local HEALTH_STATUS=$3 local EXPECT_COUNT=$4 run retry_long assert_upstream_has_endpoints_in_status_once $HOSTPORT $CLUSTER_NAME $HEALTH_STATUS $EXPECT_COUNT + echo "$output" + [ "$status" -eq 0 ] } @@ -365,22 +444,19 @@ function assert_envoy_metric { METRICS=$(get_envoy_metrics $HOSTPORT "$METRIC") - if [ -z "${METRICS}" ] - then + if [ -z "${METRICS}" ]; then echo "Metric not found" 1>&2 return 1 fi - GOT_COUNT=$(awk -F: '{print $2}' <<< "$METRICS" | head -n 1 | tr -d ' ') + GOT_COUNT=$(awk -F: '{print $2}' <<<"$METRICS" | head -n 1 | tr -d ' ') - if [ -z "$GOT_COUNT" ] - then + if [ -z "$GOT_COUNT" ]; then echo "Couldn't parse metric count" 1>&2 return 1 fi - if [ $EXPECT_COUNT -ne $GOT_COUNT ] - then + if [ $EXPECT_COUNT -ne $GOT_COUNT ]; then echo "$METRIC - expected count: $EXPECT_COUNT, actual count: $GOT_COUNT" 1>&2 return 1 fi @@ -394,22 +470,19 @@ function assert_envoy_metric_at_least { METRICS=$(get_envoy_metrics $HOSTPORT "$METRIC") - if [ -z "${METRICS}" ] - then + if [ -z "${METRICS}" ]; then echo "Metric not found" 1>&2 return 1 fi - GOT_COUNT=$(awk -F: '{print $2}' <<< "$METRICS" | head -n 1 | tr -d ' ') + GOT_COUNT=$(awk -F: '{print $2}' <<<"$METRICS" | head -n 1 | tr -d ' ') - if [ -z "$GOT_COUNT" ] - then + if [ -z "$GOT_COUNT" ]; then echo "Couldn't parse metric count" 1>&2 return 1 fi - if [ $EXPECT_COUNT -gt $GOT_COUNT ] - then + if [ $EXPECT_COUNT -gt $GOT_COUNT ]; then echo "$METRIC - expected >= count: $EXPECT_COUNT, actual count: $GOT_COUNT" 1>&2 return 1 fi @@ -423,22 +496,19 @@ function assert_envoy_aggregate_metric_at_least { METRICS=$(get_envoy_metrics $HOSTPORT "$METRIC") - if [ -z "${METRICS}" ] - then + if [ -z "${METRICS}" ]; then echo "Metric not found" 1>&2 return 1 fi - GOT_COUNT=$(awk '{ sum += $2 } END { print sum }' <<< "$METRICS") + GOT_COUNT=$(awk '{ sum += $2 } END { print sum }' <<<"$METRICS") - if [ -z "$GOT_COUNT" ] - then + if [ -z "$GOT_COUNT" ]; then echo "Couldn't parse metric count" 1>&2 return 1 fi - if [ $EXPECT_COUNT -gt $GOT_COUNT ] - then + if [ $EXPECT_COUNT -gt $GOT_COUNT ]; then echo "$METRIC - expected >= count: $EXPECT_COUNT, actual count: $GOT_COUNT" 1>&2 return 1 fi @@ -541,13 +611,13 @@ function docker_consul_for_proxy_bootstrap { local DC=$1 shift 1 - docker run -i --rm --network container:envoy_consul-${DC}_1 consul:local "$@" 2> /dev/null + docker run -i --rm --network container:envoy_consul-${DC}_1 consul:local "$@" 2>/dev/null } function docker_wget { local DC=$1 shift 1 - docker run --rm --network container:envoy_consul-${DC}_1 docker.mirror.hashicorp.services/alpine:3.9 wget "$@" + docker run --rm --network container:envoy_consul-${DC}_1 docker.mirror.hashicorp.services/alpine:3.17 wget "$@" } function docker_curl { @@ -557,8 +627,7 @@ function docker_curl { } function docker_exec { - if ! docker exec -i "$@" - then + if ! docker exec -i "$@"; then echo "Failed to execute: docker exec -i $@" 1>&2 return 1 fi @@ -582,7 +651,7 @@ function must_match_in_statsd_logs { run cat /workdir/${DC}/statsd/statsd.log echo "$output" - COUNT=$( echo "$output" | grep -Ec $1 ) + COUNT=$(echo "$output" | grep -Ec $1) echo "COUNT of '$1' matches: $COUNT" @@ -592,7 +661,7 @@ function must_match_in_statsd_logs { function must_match_in_prometheus_response { run curl -f -s $1/metrics - COUNT=$( echo "$output" | grep -Ec $2 ) + COUNT=$(echo "$output" | grep -Ec $2) echo "OUTPUT head -n 10" echo "$output" | head -n 10 @@ -604,7 +673,7 @@ function must_match_in_prometheus_response { function must_match_in_stats_proxy_response { run curl -f -s $1/$2 - COUNT=$( echo "$output" | grep -Ec $3 ) + COUNT=$(echo "$output" | grep -Ec $3) echo "OUTPUT head -n 10" echo "$output" | head -n 10 @@ -638,7 +707,7 @@ function must_pass_tcp_connection { echo "OUTPUT $output" [ "$status" == "0" ] - [ "$output" = "hello" ] + [[ "$output" == *"hello"* ]] } # must_fail_http_connection see must_fail_tcp_connection but this expects Envoy @@ -669,17 +738,17 @@ function must_pass_http_request { extra_args="-H x-test-debug:${DEBUG_HEADER_VALUE}" fi case "$METHOD" in - GET) - ;; - DELETE) - extra_args="$extra_args -X${METHOD}" - ;; - PUT|POST) - extra_args="$extra_args -d'{}' -X${METHOD}" - ;; - *) - return 1 - ;; + GET) ;; + + DELETE) + extra_args="$extra_args -X${METHOD}" + ;; + PUT | POST) + extra_args="$extra_args -d'{}' -X${METHOD}" + ;; + *) + return 1 + ;; esac run curl --no-keepalive -v -s -f $extra_args "$URL" @@ -696,23 +765,23 @@ function must_fail_http_request { local extra_args if [[ -n "${DEBUG_HEADER_VALUE}" ]]; then - extra_args="-H x-test-debug:${DEBUG_HEADER_VALUE}" + extra_args="-H x-test-debug:${DEBUG_HEADER_VALUE}" fi case "$METHOD" in - HEAD) - extra_args="$extra_args -I" - ;; - GET) - ;; - DELETE) - extra_args="$extra_args -X${METHOD}" - ;; - PUT|POST) - extra_args="$extra_args -d'{}' -X${METHOD}" - ;; - *) - return 1 - ;; + HEAD) + extra_args="$extra_args -I" + ;; + GET) ;; + + DELETE) + extra_args="$extra_args -X${METHOD}" + ;; + PUT | POST) + extra_args="$extra_args -d'{}' -X${METHOD}" + ;; + *) + return 1 + ;; esac # Attempt to curl through upstream @@ -731,8 +800,7 @@ function gen_envoy_bootstrap { EXTRA_ENVOY_BS_ARGS="${5-}" PROXY_ID="$SERVICE" - if ! is_set "$IS_GW" - then + if ! is_set "$IS_GW"; then PROXY_ID="$SERVICE-sidecar-proxy" fi @@ -742,7 +810,7 @@ function gen_envoy_bootstrap { -admin-bind 0.0.0.0:$ADMIN_PORT ${EXTRA_ENVOY_BS_ARGS} 2>&1); then # All OK, write config to file - echo "$output" > workdir/${DC}/envoy/$SERVICE-bootstrap.json + echo "$output" >workdir/${DC}/envoy/$SERVICE-bootstrap.json else status=$? # Command failed, instead of swallowing error (printed on stdout by docker @@ -794,7 +862,7 @@ function setup_upsert_l4_intention { local ACTION=$3 retry_default docker_curl primary -sL -XPUT "http://127.0.0.1:8500/v1/connect/intentions/exact?source=${SOURCE}&destination=${DESTINATION}" \ - -d"{\"Action\": \"${ACTION}\"}" >/dev/null + -d"{\"Action\": \"${ACTION}\"}" >/dev/null } function upsert_l4_intention { @@ -803,7 +871,7 @@ function upsert_l4_intention { local ACTION=$3 retry_default curl -sL -XPUT "http://127.0.0.1:8500/v1/connect/intentions/exact?source=${SOURCE}&destination=${DESTINATION}" \ - -d"{\"Action\": \"${ACTION}\"}" >/dev/null + -d"{\"Action\": \"${ACTION}\"}" >/dev/null } function get_ca_root { @@ -822,15 +890,16 @@ function set_ttl_check_state { local DC=${3:-primary} case "$CHECK_STATE" in - pass) - ;; - warn) - ;; - fail) - ;; - *) - echo "invalid ttl check state '${CHECK_STATE}'" >&2 - return 1 + pass) ;; + + warn) ;; + + fail) ;; + + *) + echo "invalid ttl check state '${CHECK_STATE}'" >&2 + return 1 + ;; esac retry_default docker_curl "${DC}" -sL -XPUT "http://localhost:8500/v1/agent/check/warn/${CHECK_ID}" @@ -843,7 +912,7 @@ function get_upstream_fortio_name { local DEBUG_HEADER_VALUE="${4:-""}" local extra_args if [[ -n "${DEBUG_HEADER_VALUE}" ]]; then - extra_args="-H x-test-debug:${DEBUG_HEADER_VALUE}" + extra_args="-H x-test-debug:${DEBUG_HEADER_VALUE}" fi # split proto if https:// is at the front of the host since the --resolve # string needs just a bare host. @@ -857,7 +926,7 @@ function get_upstream_fortio_name { # We use --resolve instead of setting a Host header since we need the right # name to be sent for SNI in some cases too. run retry_default curl -v -s -f --resolve "${HOST}:${PORT}:127.0.0.1" $extra_args \ - "${PROTO}${HOST}:${PORT}${PREFIX}/debug?env=dump" + "${PROTO}${HOST}:${PORT}${PREFIX}/debug?env=dump" # Useful Debugging but breaks the expectation that the value output is just # the grep output when things don't fail @@ -893,7 +962,7 @@ function assert_expected_fortio_name_pattern { GOT=$(get_upstream_fortio_name ${HOST} ${PORT} "${URL_PREFIX}" "${DEBUG_HEADER_VALUE}") if [[ "$GOT" =~ $EXPECT_NAME_PATTERN ]]; then - : + : else echo "expected name pattern: $EXPECT_NAME_PATTERN, actual name: $GOT" 1>&2 return 1 @@ -907,10 +976,10 @@ function get_upstream_fortio_host_header { local DEBUG_HEADER_VALUE="${4:-""}" local extra_args if [[ -n "${DEBUG_HEADER_VALUE}" ]]; then - extra_args="-H x-test-debug:${DEBUG_HEADER_VALUE}" + extra_args="-H x-test-debug:${DEBUG_HEADER_VALUE}" fi run retry_default curl -v -s -f -H"Host: ${HOST}" $extra_args \ - "localhost:${PORT}${PREFIX}/debug" + "localhost:${PORT}${PREFIX}/debug" [ "$status" == 0 ] echo "$output" | grep -E "^Host: " } @@ -944,6 +1013,30 @@ function create_peering { run curl -sLv -XPOST "http://consul-${ESTABLISH_PEER}-client:8500/v1/peering/establish" -d"{ \"PeerName\" : \"${ESTABLISH_PEER}-to-${GENERATE_PEER}\", \"PeeringToken\" : \"${token}\" }" # echo "$output" >&3 [ "$status" == 0 ] + + sleep 1 + run curl -s -f "http://consul-${GENERATE_PEER}-client:8500/v1/peering/${GENERATE_PEER}-to-${ESTABLISH_PEER}" + state="$(echo "$output" | jq --raw-output .State)" + + if [ "$state" != "ACTIVE" ]; then + echo "fail to peering: $output" + return 1 + fi +} + +function assert_service_has_imported { + local DC=${1:-primary} + local SERVICE_NAME=$2 + local PEER_NAME=$3 + + run curl -s -f "http://consul-${DC}-client:8500/v1/peering/${PEER_NAME}" + [ "$status" == 0 ] + + echo "$output" | jq --raw-output '.StreamStatus.ImportedServices' | grep -e "${SERVICE_NAME}" + if [ $? -ne 0 ]; then + echo "Error finding service: ${SERVICE_NAME}" + return 1 + fi } function get_lambda_envoy_http_filter { @@ -959,13 +1052,13 @@ function register_lambdas { local DC=${1:-primary} # register lambdas to the catalog for f in $(find workdir/${DC}/register -type f -name 'lambda_*.json'); do - retry_default curl -sL -XPUT -d @${f} "http://localhost:8500/v1/catalog/register" >/dev/null && \ + retry_default curl -sL -XPUT -d @${f} "http://localhost:8500/v1/catalog/register" >/dev/null && echo "Registered Lambda: $(jq -r .Service.Service $f)" done # write service-defaults config entries for lambdas for f in $(find workdir/${DC}/register -type f -name 'service_defaults_*.json'); do varsub ${f} AWS_LAMBDA_REGION AWS_LAMBDA_ARN - retry_default curl -sL -XPUT -d @${f} "http://localhost:8500/v1/config" >/dev/null && \ + retry_default curl -sL -XPUT -d @${f} "http://localhost:8500/v1/config" >/dev/null && echo "Wrote config: $(jq -r '.Kind + " / " + .Name' $f)" done } @@ -992,7 +1085,8 @@ function assert_lambda_envoy_dynamic_http_filter_exists { } function varsub { - local file=$1 ; shift + local file=$1 + shift for v in "$@"; do sed -i "s/\${$v}/${!v}/g" $file done @@ -1016,4 +1110,4 @@ function assert_url_header { run get_url_header "$URL" "$HEADER" [ "$status" == 0 ] [ "$VALUE" = "$output" ] -} \ No newline at end of file +} diff --git a/test/integration/connect/envoy/main_test.go b/test/integration/connect/envoy/main_test.go index 6b60efab5d6b..b4b473f01ce0 100644 --- a/test/integration/connect/envoy/main_test.go +++ b/test/integration/connect/envoy/main_test.go @@ -50,7 +50,7 @@ func runCmd(t *testing.T, c string, env ...string) { } } -// Discover the cases so we pick up both oss and ent copies. +// Discover the cases so we pick up both CE and ent copies. func discoverCases() ([]string, error) { cwd, err := os.Getwd() if err != nil { diff --git a/test/integration/connect/envoy/run-tests.sh b/test/integration/connect/envoy/run-tests.sh index d32092e7a906..c773c5be5865 100755 --- a/test/integration/connect/envoy/run-tests.sh +++ b/test/integration/connect/envoy/run-tests.sh @@ -104,13 +104,6 @@ function init_workdir { mv workdir/${CLUSTER}/consul/server.hcl workdir/${CLUSTER}/consul-server/server.hcl fi - if test -f "workdir/${CLUSTER}/consul/peering_server.hcl" -a $REQUIRE_PEERS = "1" - then - mv workdir/${CLUSTER}/consul/peering_server.hcl workdir/${CLUSTER}/consul-server/peering_server.hcl - else - rm workdir/${CLUSTER}/consul/peering_server.hcl - fi - # copy the ca-certs for SDS so we can verify the right ones are served mkdir -p workdir/test-sds-server/certs cp test-sds-server/certs/ca-root.crt workdir/test-sds-server/certs/ca-root.crt @@ -318,8 +311,7 @@ function pre_service_setup { } function start_services { - # Push the state to the shared docker volume (note this is because CircleCI - # can't use shared volumes) + # Push the state to the shared docker volume docker cp workdir/. envoy_workdir_1:/workdir # Start containers required @@ -480,8 +472,7 @@ function run_tests { # Wipe state wipe_volumes - # Push the state to the shared docker volume (note this is because CircleCI - # can't use shared volumes) + # Push the state to the shared docker volume docker cp workdir/. envoy_workdir_1:/workdir start_consul primary @@ -563,10 +554,6 @@ function suite_setup { echo "Rebuilding 'bats-verify' image..." retry_default docker build -t bats-verify -f Dockerfile-bats . - # if this fails on CircleCI your first thing to try would be to upgrade - # the machine image to the latest version using this listing: - # - # https://circleci.com/docs/2.0/configuration-reference/#available-linux-machine-images echo "Checking bats image..." docker run --rm -t bats-verify -v diff --git a/test/integration/connect/envoy/test-sds-server/go.mod b/test/integration/connect/envoy/test-sds-server/go.mod index 7aa65b58157d..dfca9e528ab0 100644 --- a/test/integration/connect/envoy/test-sds-server/go.mod +++ b/test/integration/connect/envoy/test-sds-server/go.mod @@ -5,5 +5,6 @@ go 1.16 require ( github.com/envoyproxy/go-control-plane v0.9.9 github.com/hashicorp/go-hclog v0.16.2 + golang.org/x/net v0.13.0 // indirect google.golang.org/grpc v1.40.0 ) diff --git a/test/integration/connect/envoy/test-sds-server/go.sum b/test/integration/connect/envoy/test-sds-server/go.sum index f4cb806dfc58..31c77e9c6885 100644 --- a/test/integration/connect/envoy/test-sds-server/go.sum +++ b/test/integration/connect/envoy/test-sds-server/go.sum @@ -64,40 +64,75 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY= +golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/test/integration/consul-container/go.mod b/test/integration/consul-container/go.mod index 4f282f40bedf..a3f6bae91430 100644 --- a/test/integration/consul-container/go.mod +++ b/test/integration/consul-container/go.mod @@ -1,65 +1,186 @@ module github.com/hashicorp/consul/test/integration/consul-container -go 1.18 +go 1.20 require ( github.com/docker/docker v20.10.11+incompatible - github.com/hashicorp/consul/api v1.15.2 - github.com/hashicorp/consul/sdk v0.11.0 - github.com/hashicorp/go-uuid v1.0.2 - github.com/hashicorp/hcl v1.0.0 - github.com/stretchr/testify v1.7.0 + github.com/docker/go-connections v0.4.0 + github.com/hashicorp/consul v1.14.1 + github.com/hashicorp/consul/api v1.18.0 + github.com/hashicorp/consul/sdk v0.13.0 + github.com/hashicorp/serf v0.10.1 + github.com/itchyny/gojq v0.12.9 + github.com/pkg/errors v0.9.1 + github.com/stretchr/testify v1.8.3 + github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 github.com/testcontainers/testcontainers-go v0.13.0 ) require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect - github.com/Microsoft/go-winio v0.4.17 // indirect + github.com/DataDog/datadog-go v4.8.2+incompatible // indirect + github.com/Microsoft/go-winio v0.5.1 // indirect github.com/Microsoft/hcsshim v0.8.24 // indirect + github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e // indirect github.com/armon/go-metrics v0.3.10 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect + github.com/aws/aws-sdk-go v1.44.289 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/boltdb/bolt v1.3.1 // indirect github.com/cenkalti/backoff/v4 v4.1.2 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible // indirect + github.com/circonus-labs/circonusllhist v0.1.3 // indirect github.com/containerd/cgroups v1.0.3 // indirect github.com/containerd/containerd v1.5.13 // indirect + github.com/coreos/go-oidc v2.1.0+incompatible // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/distribution v2.7.1+incompatible // indirect - github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect - github.com/fatih/color v1.10.0 // indirect + github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-openapi/analysis v0.21.4 // indirect + github.com/go-openapi/errors v0.20.3 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/loads v0.21.2 // indirect + github.com/go-openapi/runtime v0.25.0 // indirect + github.com/go-openapi/spec v0.20.8 // indirect + github.com/go-openapi/strfmt v0.21.3 // indirect + github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-openapi/validate v0.22.1 // indirect + github.com/go-ozzo/ozzo-validation v3.6.0+incompatible // indirect + github.com/go-test/deep v1.0.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.3 // indirect + github.com/google/btree v1.0.1 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.3.0 // indirect + github.com/gorilla/mux v1.7.3 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 // indirect + github.com/hashicorp/consul-awsauth v0.0.0-20220713182709-05ac1c5c2706 // indirect + github.com/hashicorp/consul-net-rpc v0.0.0-20220307172752-3602954411b4 // indirect + github.com/hashicorp/consul/proto-public v0.2.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-bexpr v0.1.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-hclog v0.16.2 // indirect + github.com/hashicorp/go-connlimit v0.3.0 // indirect + github.com/hashicorp/go-hclog v1.2.1 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-memdb v1.3.4 // indirect + github.com/hashicorp/go-msgpack v1.1.5 // indirect + github.com/hashicorp/go-msgpack/v2 v2.0.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-raftchunking v0.6.2 // indirect + github.com/hashicorp/go-retryablehttp v0.6.7 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-syslog v1.0.0 // indirect + github.com/hashicorp/go-uuid v1.0.2 // indirect + github.com/hashicorp/go-version v1.2.1 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/hashicorp/serf v0.10.1 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hashicorp/hcp-scada-provider v0.2.3 // indirect + github.com/hashicorp/hcp-sdk-go v0.44.1-0.20230508124639-28da4c5b03f3 // indirect + github.com/hashicorp/hil v0.0.0-20200423225030-a18a1cd20038 // indirect + github.com/hashicorp/memberlist v0.5.0 // indirect + github.com/hashicorp/net-rpc-msgpackrpc/v2 v2.0.0 // indirect + github.com/hashicorp/raft v1.3.11 // indirect + github.com/hashicorp/raft-autopilot v0.1.6 // indirect + github.com/hashicorp/raft-boltdb/v2 v2.2.2 // indirect + github.com/hashicorp/vault/api v1.0.5-0.20200717191844-f687267c8086 // indirect + github.com/hashicorp/vault/sdk v0.1.14-0.20200519221838-e0cfd64bc267 // indirect + github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect + github.com/imdario/mergo v0.3.13 // indirect + github.com/itchyny/timefmt-go v0.1.4 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/magiconair/properties v1.8.5 // indirect - github.com/mattn/go-colorable v0.1.8 // indirect - github.com/mattn/go-isatty v0.0.12 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/miekg/dns v1.1.50 // indirect + github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect + github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/mapstructure v1.4.2 // indirect + github.com/mitchellh/go-testing-interface v1.14.0 // indirect + github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/pointerstructure v1.2.1 // indirect + github.com/mitchellh/reflectwalk v1.0.1 // indirect github.com/moby/sys/mount v0.2.0 // indirect github.com/moby/sys/mountinfo v0.5.0 // indirect github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/oklog/ulid v1.3.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect github.com/opencontainers/runc v1.1.4 // indirect - github.com/pkg/errors v0.9.1 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect + github.com/pierrec/lz4 v2.5.2+incompatible // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect + github.com/prometheus/client_golang v1.14.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.39.0 // indirect + github.com/prometheus/procfs v0.8.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/sirupsen/logrus v1.8.1 // indirect - go.opencensus.io v0.22.3 // indirect - golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect - golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect - google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect - google.golang.org/grpc v1.41.0 // indirect - google.golang.org/protobuf v1.27.1 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect + github.com/stretchr/objx v0.5.0 // indirect + github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 // indirect + go.etcd.io/bbolt v1.3.5 // indirect + go.mongodb.org/mongo-driver v1.11.0 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/otel v1.11.1 // indirect + go.opentelemetry.io/otel/trace v1.11.1 // indirect + golang.org/x/crypto v0.12.0 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/net v0.14.0 // indirect + golang.org/x/oauth2 v0.6.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/term v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef // indirect + google.golang.org/grpc v1.52.3 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/square/go-jose.v2 v2.5.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.26.1 // indirect + k8s.io/apimachinery v0.26.1 // indirect + k8s.io/client-go v0.26.1 // indirect + k8s.io/klog/v2 v2.90.0 // indirect + k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect + k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) replace github.com/hashicorp/consul/api => ../../../api replace github.com/hashicorp/consul/sdk => ../../../sdk + +replace github.com/hashicorp/consul => ../../.. diff --git a/test/integration/consul-container/go.sum b/test/integration/consul-container/go.sum index 643599e21f68..a1da04f25f06 100644 --- a/test/integration/consul-container/go.sum +++ b/test/integration/consul-container/go.sum @@ -38,7 +38,10 @@ github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/datadog-go v4.8.2+incompatible h1:qbcKSx29aBLD+5QLvlQZlGmRMF/FfGqFLFev/1TDzRo= +github.com/DataDog/datadog-go v4.8.2+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= @@ -46,8 +49,9 @@ github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.4.17 h1:iT12IBVClFevaf8PuVyi3UmZOVh4OqnaLxDTW2O6j3w= github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= +github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= @@ -70,19 +74,29 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= +github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs= github.com/armon/go-metrics v0.3.10 h1:FR+drcQStOe+32sYyJYyZ7FIdgoGGBnwLl+flodp8Uo= github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= +github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.44.289 h1:5CVEjiHFvdiVlKPBzv0rjG4zH/21W/onT18R5AH/qx0= +github.com/aws/aws-sdk-go v1.44.289/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= @@ -90,6 +104,8 @@ github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edY github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= @@ -101,6 +117,8 @@ github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInq github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= @@ -113,12 +131,12 @@ github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible h1:C29Ae4G5GtYyYMm1aztcyj/J5ckgJm2zwdDajFbx1NY= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= @@ -213,6 +231,7 @@ github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkE github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -267,47 +286,122 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-ldap/ldap/v3 v3.1.3/go.mod h1:3rbOH3jRS2u6jg2rJnKAMLE/xQyCKIveG2Sa/Cohzb8= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= +github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= +github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= +github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc= +github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= +github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= +github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= +github.com/go-openapi/runtime v0.25.0 h1:7yQTCdRbWhX8vnIjdzU8S00tBYf7Sg71EBeorlPHvhc= +github.com/go-openapi/runtime v0.25.0/go.mod h1:Ux6fikcHXyyob6LNWxtE96hWwjBPYF0DXgVFuMTneOs= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/spec v0.20.8 h1:ubHmXNY3FCIOinT8RNrrPfGc9t7I1qhPtdOGoG2AxRU= +github.com/go-openapi/spec v0.20.8/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= +github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= +github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o= +github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= +github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= +github.com/go-ozzo/ozzo-validation v3.6.0+incompatible h1:msy24VGS42fKO9K1vLz82/GeYW1cILu7Nuuj1N3BBkE= +github.com/go-ozzo/ozzo-validation v3.6.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= +github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= +github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= +github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= @@ -328,8 +422,9 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -352,9 +447,15 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -362,12 +463,15 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -376,6 +480,7 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/tcpproxy v0.0.0-20180808230851-dfa16c61dad2 h1:AtvtonGEH/fZK0XPNNBdB6swgy7Iudfx88wzyIpwqJ8= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -387,65 +492,122 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= -github.com/gorilla/mux v1.7.2 h1:zoNxOV7WjqXptQOVngLmcSQgXmgk4NMz1HibBchjl/I= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/consul-awsauth v0.0.0-20220713182709-05ac1c5c2706 h1:1ZEjnveDe20yFa6lSkfdQZm5BR/b271n0MsB5R2L3us= +github.com/hashicorp/consul-awsauth v0.0.0-20220713182709-05ac1c5c2706/go.mod h1:1Cs8FlmD1BfSQXJGcFLSV5FuIx1AbJP+EJGdxosoS2g= +github.com/hashicorp/consul-net-rpc v0.0.0-20220307172752-3602954411b4 h1:Com/5n/omNSBusX11zdyIYtidiqewLIanchbm//McZA= +github.com/hashicorp/consul-net-rpc v0.0.0-20220307172752-3602954411b4/go.mod h1:vWEAHAeAqfOwB3pSgHMQpIu8VH1jL+Ltg54Tw0wt/NI= +github.com/hashicorp/consul/proto-public v0.2.1 h1:9dZGW68IEuajEkaAAdXCUovVuKyccBOS0jub4Gee5II= +github.com/hashicorp/consul/proto-public v0.2.1/go.mod h1:iWNlBDJIZQJC3bBiCThoqg9i7uk/4RQZYkqH1wiQrss= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-bexpr v0.1.2 h1:ijMXI4qERbzxbCnkxmfUtwMyjrrk3y+Vt0MxojNCbBs= +github.com/hashicorp/go-bexpr v0.1.2/go.mod h1:ANbpTX1oAql27TZkKVeW8p1w8NTdnyzPe/0qqPCKohU= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-connlimit v0.3.0 h1:oAojHGjFxUTTTA8c5XXnDqWJ2HLuWbDiBPTpWvNzvqM= +github.com/hashicorp/go-connlimit v0.3.0/go.mod h1:OUj9FGL1tPIhl/2RCfzYHrIiWj+VVPGNyVPnUX8AqS0= +github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= +github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= -github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.1 h1:YQsLlGDJgwhXFpucSPyVbCBviQtjlHv3jLTlp8YmtEw= +github.com/hashicorp/go-hclog v1.2.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jUIEJnBlbgKS1N2Q61QkHiZyR1g= +github.com/hashicorp/go-memdb v1.3.4 h1:XSL3NR682X/cVk2IeV0d70N4DZ9ljI885xAEU8IoK3c= +github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6KvJWs= +github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4= +github.com/hashicorp/go-msgpack/v2 v2.0.0 h1:c1fiLq1LNghmLOry1ipGhvLDi+/zEoaEP2JrE1oFJ9s= +github.com/hashicorp/go-msgpack/v2 v2.0.0/go.mod h1:JIxYkkFJRDDRSoWQBSh7s9QAVThq+82iWmUpmE4jKak= github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= +github.com/hashicorp/go-raftchunking v0.6.2 h1:imj6CVkwXj6VzgXZQvzS+fSrkbFCzlJ2t00F3PacnuU= +github.com/hashicorp/go-raftchunking v0.6.2/go.mod h1:cGlg3JtDy7qy6c/3Bu660Mic1JF+7lWqIwCFSb08fX0= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.6.7 h1:8/CAEZt/+F7kR7GevNHulKkUjLht3CPmn7egmhieNKo= +github.com/hashicorp/go-retryablehttp v0.6.7/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/hcp-scada-provider v0.2.3 h1:AarYR+/Pcv+cMvPdAlb92uOBmZfEH6ny4+DT+4NY2VQ= +github.com/hashicorp/hcp-scada-provider v0.2.3/go.mod h1:ZFTgGwkzNv99PLQjTsulzaCplCzOTBh0IUQsPKzrQFo= +github.com/hashicorp/hcp-sdk-go v0.44.1-0.20230508124639-28da4c5b03f3 h1:9QstZdsLIS6iPyYxQoyymRz8nBw9jMdEbGy29gtgzVQ= +github.com/hashicorp/hcp-sdk-go v0.44.1-0.20230508124639-28da4c5b03f3/go.mod h1:hZqky4HEzsKwvLOt4QJlZUrjeQmb4UCZUhDP2HyQFfc= +github.com/hashicorp/hil v0.0.0-20200423225030-a18a1cd20038 h1:n9J0rwVWXDpNd5iZnwY7w4WZyq53/rROeI7OVvLW8Ok= +github.com/hashicorp/hil v0.0.0-20200423225030-a18a1cd20038/go.mod h1:n2TSygSNwsLJ76m8qFXTSc7beTb+auJxYdqrnoqwZWE= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM= github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= +github.com/hashicorp/net-rpc-msgpackrpc/v2 v2.0.0 h1:kBpVVl1sl3MaSrs97e0+pDQhSrqJv9gVbSUrPpVfl1w= +github.com/hashicorp/net-rpc-msgpackrpc/v2 v2.0.0/go.mod h1:6pdNz0vo0mF0GvhwDG56O3N18qBrAz/XRIcfINfTbwo= +github.com/hashicorp/raft v1.1.0/go.mod h1:4Ak7FSPnuvmb0GV6vgIAJ4vYT4bek9bb6Q+7HVbyzqM= +github.com/hashicorp/raft v1.1.1/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8= +github.com/hashicorp/raft v1.2.0/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8= +github.com/hashicorp/raft v1.3.11 h1:p3v6gf6l3S797NnK5av3HcczOC1T5CLoaRvg0g9ys4A= +github.com/hashicorp/raft v1.3.11/go.mod h1:J8naEwc6XaaCfts7+28whSeRvCqTd6e20BlCU3LtEO4= +github.com/hashicorp/raft-autopilot v0.1.6 h1:C1q3RNF2FfXNZfHWbvVAu0QixaQK8K5pX4O5lh+9z4I= +github.com/hashicorp/raft-autopilot v0.1.6/go.mod h1:Af4jZBwaNOI+tXfIqIdbcAnh/UyyqIMj/pOISIfhArw= +github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk= +github.com/hashicorp/raft-boltdb v0.0.0-20210409134258-03c10cc3d4ea/go.mod h1:qRd6nFJYYS6Iqnc/8HcUmko2/2Gw8qTFEmxDLii6W5I= +github.com/hashicorp/raft-boltdb v0.0.0-20211202195631-7d34b9fb3f42 h1:Ye8SofeDHJzu9xvvaMmpMkqHELWW7rTcXwdUR0CWW48= +github.com/hashicorp/raft-boltdb/v2 v2.2.2 h1:rlkPtOllgIcKLxVT4nutqlTH2NRFn+tO1wwZk/4Dxqw= +github.com/hashicorp/raft-boltdb/v2 v2.2.2/go.mod h1:N8YgaZgNJLpZC+h+by7vDu5rzsRgONThTEeUS3zWbfY= github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= +github.com/hashicorp/vault/api v1.0.5-0.20200717191844-f687267c8086 h1:OKsyxKi2sNmqm1Gv93adf2AID2FOBFdCbbZn9fGtIdg= +github.com/hashicorp/vault/api v1.0.5-0.20200717191844-f687267c8086/go.mod h1:R3Umvhlxi2TN7Ex2hzOowyeNb+SfbVWI973N+ctaFMk= +github.com/hashicorp/vault/sdk v0.1.14-0.20200519221838-e0cfd64bc267 h1:e1ok06zGrWJW91rzRroyl5nRNqraaBe4d5hiKcVZuHM= +github.com/hashicorp/vault/sdk v0.1.14-0.20200519221838-e0cfd64bc267/go.mod h1:WX57W2PwkrOPQ6rVQk+dy5/htHIaB4aBM70EwKThu10= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= +github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= @@ -453,26 +615,45 @@ github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/itchyny/gojq v0.12.9 h1:biKpbKwMxVYhCU1d6mR7qMr3f0Hn9F5k5YykCVb3gmM= +github.com/itchyny/gojq v0.12.9/go.mod h1:T4Ip7AETUXeGpD+436m+UEl3m3tokRgajd5pRfsR5oE= +github.com/itchyny/timefmt-go v0.1.4 h1:hFEfWVdwsEi+CY8xY2FtgWHGQaBaC3JeHd+cve0ynVM= +github.com/itchyny/timefmt-go v0.1.4/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -492,39 +673,70 @@ github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= +github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= +github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.14.0 h1:/x0XQ6h+3U3nAyk1yx+bHPURrKa9sVVvYbuqZ7pIAtI= +github.com/mitchellh/go-testing-interface v1.14.0/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452 h1:hOY53G+kBFhbYFpRVxHl5eS7laP6B1+Cq+Z9Dry1iMU= +github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= -github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw= +github.com/mitchellh/pointerstructure v1.2.1/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= +github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/sys/mount v0.2.0 h1:WhCW5B355jtxndN5ovugJlMFJawbUODuW8fSnEH6SSM= github.com/moby/sys/mount v0.2.0/go.mod h1:aAivFE2LB3W4bACsUXChRHQ0qKWsetY4Y9V7sxOougM= @@ -537,18 +749,26 @@ github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/f github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE= github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -557,12 +777,15 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -592,12 +815,20 @@ github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqi github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI= +github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -608,27 +839,38 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU= +github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= +github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -638,13 +880,18 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= @@ -655,12 +902,15 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -676,30 +926,44 @@ github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzu github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= +github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 h1:xzABM9let0HLLqFypcxvLmlvEciCHL7+Lv+4vwZqecI= +github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569/go.mod h1:2Ly+NIftZN4de9zRmENdYbvPQeaVIYKWpLFStLFEBgI= github.com/testcontainers/testcontainers-go v0.13.0 h1:OUujSlEGsXVo/ykPVZk3KanBNGN0TYb/7oKIPVn15JA= github.com/testcontainers/testcontainers-go v0.13.0/go.mod h1:z1abufU633Eb/FmSBTzV6ntZAC1eZBYPtaFsn4nPuDk= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -714,30 +978,50 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17 github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= +go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= +go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= +go.mongodb.org/mongo-driver v1.11.0 h1:FZKhBSTydeuffHj9CBjXlR8vQLee1cQyTWYPA6/tqiE= +go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4= +go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= +go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZpKxs= +go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= +go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -745,16 +1029,23 @@ golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -786,11 +1077,15 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -815,8 +1110,8 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -824,39 +1119,55 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211108170745-6635138e15ea/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -910,33 +1221,51 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -946,9 +1275,14 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -958,6 +1292,7 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -977,10 +1312,13 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= +golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -998,6 +1336,8 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1019,15 +1359,18 @@ google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4 google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef h1:uQ2vjV/sHTsWSqdKeLqmwitzgvjMl7o4IdtHwUDXSJY= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= @@ -1036,11 +1379,9 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E= -google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= +google.golang.org/grpc v1.52.3 h1:pf7sOysg4LdgBqduXveGKrcEwbStiK2rtfghdzlUYDQ= +google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1053,38 +1394,46 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/gotestsum v1.7.0/go.mod h1:V1m4Jw3eBerhI/A6qCxUE07RnCg7ACkKj9BYcAm09V8= @@ -1100,15 +1449,21 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= +k8s.io/api v0.26.1 h1:f+SWYiPd/GsiWwVRz+NbFyCgvv75Pk9NK6dlkZgpCRQ= +k8s.io/api v0.26.1/go.mod h1:xd/GBNgR0f707+ATNyPmQ1oyKSgndzXij81FzWGsejg= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= +k8s.io/apimachinery v0.26.1 h1:8EZ/eGJL+hY/MYCNwhmDzVqq2lPl3N3Bo8rvweJwXUQ= +k8s.io/apimachinery v0.26.1/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= +k8s.io/client-go v0.26.1 h1:87CXzYJnAMGaa/IDDfRdhTzxk/wzGZ+/HUQpqgVSZXU= +k8s.io/client-go v0.26.1/go.mod h1:IWNSglg+rQ3OcvDkhY6+QLeasV4OYHDjdqeWkDQZwGE= k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= @@ -1119,15 +1474,27 @@ k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.90.0 h1:VkTxIV/FjRXn1fgNNcKGM8cfmL1Z33ZjXRTVxKCoF5M= +k8s.io/klog/v2 v2.90.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/test/integration/consul-container/libs/agent/agent.go b/test/integration/consul-container/libs/agent/agent.go new file mode 100644 index 000000000000..e964757797f3 --- /dev/null +++ b/test/integration/consul-container/libs/agent/agent.go @@ -0,0 +1,29 @@ +package agent + +import ( + "context" + + "github.com/hashicorp/consul/api" +) + +// Agent represent a Consul agent abstraction +type Agent interface { + GetAddr() (string, int) + GetClient() *api.Client + GetName() string + GetConfig() Config + GetDatacenter() string + IsServer() bool + RegisterTermination(func() error) + Terminate() error + Upgrade(ctx context.Context, config Config, index int) error +} + +// Config is a set of configurations required to create a Agent +type Config struct { + JSON string + Certs map[string]string + Image string + Version string + Cmd []string +} diff --git a/test/integration/consul-container/libs/agent/builder.go b/test/integration/consul-container/libs/agent/builder.go new file mode 100644 index 000000000000..477a061360e5 --- /dev/null +++ b/test/integration/consul-container/libs/agent/builder.go @@ -0,0 +1,266 @@ +package agent + +import ( + "encoding/json" + "path/filepath" + + "github.com/pkg/errors" + + agentconfig "github.com/hashicorp/consul/agent/config" + "github.com/hashicorp/consul/test/integration/consul-container/libs/utils" + "github.com/hashicorp/consul/tlsutil" +) + +const ( + remoteCertDirectory = "/consul/config/certs" +) + +// BuildContext provides a reusable object meant to share common configuration settings +// between agent configuration builders. +type BuildContext struct { + datacenter string + encryptKey string + caCert string + caKey string + index int // keeps track of the certificates issued for naming purposes + injectAutoEncryption bool // initialize the built-in CA and set up agents to use auto-encrpt + injectCerts bool // initializes the built-in CA and distributes client certificates to agents + injectGossipEncryption bool // setup the agents to use a gossip encryption key +} + +// BuildOptions define the desired automated test setup overrides that are +// applied across agents in the cluster +type BuildOptions struct { + Datacenter string // Override datacenter for agents + InjectCerts bool // Provides a CA for all agents and (future) agent certs. + InjectAutoEncryption bool // Configures auto-encrypt for TLS and sets up certs. Overrides InjectCerts. + InjectGossipEncryption bool // Provides a gossip encryption key for all agents. +} + +func NewBuildContext(opts BuildOptions) (*BuildContext, error) { + ctx := &BuildContext{ + datacenter: opts.Datacenter, + injectAutoEncryption: opts.InjectAutoEncryption, + injectCerts: opts.InjectCerts, + injectGossipEncryption: opts.InjectGossipEncryption, + } + + if opts.InjectGossipEncryption { + serfKey, err := newSerfEncryptionKey() + if err != nil { + return nil, errors.Wrap(err, "could not generate serf encryption key") + } + ctx.encryptKey = serfKey + } + + if opts.InjectAutoEncryption || opts.InjectCerts { + // This is the same call that 'consul tls ca create` will run + caCert, caKey, err := tlsutil.GenerateCA(tlsutil.CAOpts{Domain: "consul", PermittedDNSDomains: []string{"consul", "localhost"}}) + if err != nil { + return nil, errors.Wrap(err, "could not generate built-in CA root pair") + } + ctx.caCert = caCert + ctx.caKey = caKey + } + return ctx, nil +} + +func (c *BuildContext) GetCerts() (cert string, key string) { + return c.caCert, c.caKey +} + +type Builder struct { + conf *agentconfig.Config + certs map[string]string + context *BuildContext +} + +// NewConfigBuilder instantiates a builder object with sensible defaults for a single consul instance +// This includes the following: +// * default ports with no plaintext options +// * debug logging +// * single server with bootstrap +// * bind to all interfaces, advertise on 'eth0' +// * connect enabled +func NewConfigBuilder(ctx *BuildContext) *Builder { + b := &Builder{ + certs: map[string]string{}, + conf: &agentconfig.Config{ + AdvertiseAddrLAN: utils.StringToPointer(`{{ GetInterfaceIP "eth0" }}`), + BindAddr: utils.StringToPointer("0.0.0.0"), + Bootstrap: utils.BoolToPointer(true), + ClientAddr: utils.StringToPointer("0.0.0.0"), + Connect: agentconfig.Connect{ + Enabled: utils.BoolToPointer(true), + }, + LogLevel: utils.StringToPointer("DEBUG"), + ServerMode: utils.BoolToPointer(true), + }, + context: ctx, + } + + // These are the default ports, disabling plaintext transport + b.conf.Ports = agentconfig.Ports{ + DNS: utils.IntToPointer(8600), + HTTP: nil, + HTTPS: utils.IntToPointer(8501), + GRPC: utils.IntToPointer(8502), + GRPCTLS: utils.IntToPointer(8503), + SerfLAN: utils.IntToPointer(8301), + SerfWAN: utils.IntToPointer(8302), + Server: utils.IntToPointer(8300), + } + + return b +} + +func (b *Builder) Bootstrap(servers int) *Builder { + if servers < 1 { + b.conf.Bootstrap = nil + b.conf.BootstrapExpect = nil + } else if servers == 1 { + b.conf.Bootstrap = utils.BoolToPointer(true) + b.conf.BootstrapExpect = nil + } else { + b.conf.Bootstrap = nil + b.conf.BootstrapExpect = utils.IntToPointer(servers) + } + return b +} + +func (b *Builder) Client() *Builder { + b.conf.Ports.Server = nil + b.conf.ServerMode = nil + b.conf.Bootstrap = nil + b.conf.BootstrapExpect = nil + return b +} + +func (b *Builder) Datacenter(name string) *Builder { + b.conf.Datacenter = utils.StringToPointer(name) + return b +} + +func (b *Builder) Peering(enable bool) *Builder { + b.conf.Peering = agentconfig.Peering{ + Enabled: utils.BoolToPointer(enable), + } + return b +} + +func (b *Builder) RetryJoin(names ...string) *Builder { + b.conf.RetryJoinLAN = names + return b +} + +func (b *Builder) Telemetry(statSite string) *Builder { + b.conf.Telemetry = agentconfig.Telemetry{ + StatsiteAddr: utils.StringToPointer(statSite), + } + return b +} + +// ToAgentConfig renders the builders configuration into a string +// representation of the json config file for agents. +// DANGER! Some fields may not have json tags in the Agent Config. +// You may need to add these yourself. +func (b *Builder) ToAgentConfig() (*Config, error) { + b.injectContextOptions() + + out, err := json.MarshalIndent(b.conf, "", " ") + if err != nil { + return nil, errors.Wrap(err, "could not marshall builder") + } + + conf := &Config{ + Certs: b.certs, + Cmd: []string{"agent"}, + Image: utils.TargetImage, + JSON: string(out), + Version: utils.TargetVersion, + } + + return conf, nil +} + +func (b *Builder) injectContextOptions() { + if b.context == nil { + return + } + + var dc string + if b.context.datacenter != "" { + b.conf.Datacenter = utils.StringToPointer(b.context.datacenter) + dc = b.context.datacenter + } + if b.conf.Datacenter == nil || *b.conf.Datacenter == "" { + dc = "dc1" + } + + server := b.conf.ServerMode != nil && *b.conf.ServerMode + + if b.context.encryptKey != "" { + b.conf.EncryptKey = utils.StringToPointer(b.context.encryptKey) + } + + // For any TLS setup, we add the CA to agent conf + if b.context.caCert != "" { + // Add the ca file to the list of certs that will be mounted to consul + filename := filepath.Join(remoteCertDirectory, "consul-agent-ca.pem") + b.certs[filename] = b.context.caCert + + b.conf.TLS = agentconfig.TLS{ + Defaults: agentconfig.TLSProtocolConfig{ + CAFile: utils.StringToPointer(filename), + VerifyOutgoing: utils.BoolToPointer(true), // Secure settings + }, + InternalRPC: agentconfig.TLSProtocolConfig{ + VerifyServerHostname: utils.BoolToPointer(true), + }, + } + } + + // Also for any TLS setup, generate server key pairs from the CA + if b.context.caCert != "" && server { + keyFileName, priv, certFileName, pub := newServerTLSKeyPair(dc, b.context) + + // Add the key pair to the list that will be mounted to consul + certFileName = filepath.Join(remoteCertDirectory, certFileName) + keyFileName = filepath.Join(remoteCertDirectory, keyFileName) + + b.certs[certFileName] = pub + b.certs[keyFileName] = priv + + b.conf.TLS.Defaults.CertFile = utils.StringToPointer(certFileName) + b.conf.TLS.Defaults.KeyFile = utils.StringToPointer(keyFileName) + b.conf.TLS.Defaults.VerifyIncoming = utils.BoolToPointer(true) // Only applies to servers for auto-encrypt + } + + // This assumes we've already gone through the CA/Cert setup in the previous conditional + if b.context.injectAutoEncryption && server { + b.conf.AutoEncrypt = agentconfig.AutoEncrypt{ + AllowTLS: utils.BoolToPointer(true), // This setting is different between client and servers + } + + b.conf.TLS.GRPC = agentconfig.TLSProtocolConfig{ + UseAutoCert: utils.BoolToPointer(true), // This is required for peering to work over the non-GRPC_TLS port + } + + // VerifyIncoming does not apply to client agents for auto-encrypt + } + + if b.context.injectAutoEncryption && !server { + b.conf.AutoEncrypt = agentconfig.AutoEncrypt{ + TLS: utils.BoolToPointer(true), // This setting is different between client and servers + } + + b.conf.TLS.GRPC = agentconfig.TLSProtocolConfig{ + UseAutoCert: utils.BoolToPointer(true), // This is required for peering to work over the non-GRPC_TLS port + } + } + + if b.context.injectCerts && !b.context.injectAutoEncryption { + panic("client certificate distribution not implemented") + } + b.context.index++ +} diff --git a/test/integration/consul-container/libs/agent/container.go b/test/integration/consul-container/libs/agent/container.go new file mode 100644 index 000000000000..e8a35a2ae975 --- /dev/null +++ b/test/integration/consul-container/libs/agent/container.go @@ -0,0 +1,421 @@ +package agent + +import ( + "context" + "encoding/json" + "fmt" + "os" + "path/filepath" + "strconv" + "time" + + dockercontainer "github.com/docker/docker/api/types/container" + "github.com/docker/docker/pkg/ioutils" + "github.com/pkg/errors" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" + + "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/test/integration/consul-container/libs/utils" +) + +const bootLogLine = "Consul agent running" +const disableRYUKEnv = "TESTCONTAINERS_RYUK_DISABLED" + +// consulContainerNode implements the Agent interface by running a Consul agent +// in a container. +type consulContainerNode struct { + ctx context.Context + client *api.Client + pod testcontainers.Container + container testcontainers.Container + serverMode bool + ip string + port int + datacenter string + config Config + podReq testcontainers.ContainerRequest + consulReq testcontainers.ContainerRequest + certDir string + dataDir string + network string + id int + terminateFuncs []func() error +} + +// NewConsulContainer starts a Consul agent in a container with the given config. +func NewConsulContainer(ctx context.Context, config Config, network string, index int) (Agent, error) { + license, err := readLicense() + if err != nil { + return nil, err + } + + pc, err := readSomeConfigFileFields(config.JSON) + if err != nil { + return nil, err + } + + consulType := "client" + if pc.Server { + consulType = "server" + } + name := utils.RandName(fmt.Sprintf("%s-consul-%s-%d", pc.Datacenter, consulType, index)) + + // Inject new Agent name + config.Cmd = append(config.Cmd, "-node", name) + + tmpDirData, err := ioutils.TempDir("", name) + if err != nil { + return nil, err + } + err = os.Chmod(tmpDirData, 0777) + if err != nil { + return nil, err + } + + configFile, err := createConfigFile(config.JSON) + if err != nil { + return nil, err + } + + tmpCertData, err := ioutils.TempDir("", fmt.Sprintf("%s-certs", name)) + if err != nil { + return nil, err + } + err = os.Chmod(tmpCertData, 0777) + if err != nil { + return nil, err + } + + for filename, cert := range config.Certs { + err := createCertFile(tmpCertData, filename, cert) + if err != nil { + return nil, errors.Wrapf(err, "failed to write file %s", filename) + } + } + + opts := containerOpts{ + name: name, + certDir: tmpCertData, + configFile: configFile, + dataDir: tmpDirData, + license: license, + addtionalNetworks: []string{"bridge", network}, + hostname: fmt.Sprintf("agent-%d", index), + } + podReq, consulReq := newContainerRequest(config, opts) + + podContainer, err := startContainer(ctx, podReq) + if err != nil { + return nil, err + } + + localIP, err := podContainer.Host(ctx) + if err != nil { + return nil, err + } + + mappedPort, err := podContainer.MappedPort(ctx, "8500") + if err != nil { + return nil, err + } + + ip, err := podContainer.ContainerIP(ctx) + if err != nil { + return nil, err + } + + consulContainer, err := startContainer(ctx, consulReq) + if err != nil { + return nil, err + } + + if err := consulContainer.StartLogProducer(ctx); err != nil { + return nil, err + } + consulContainer.FollowOutput(&LogConsumer{ + Prefix: name, + }) + + uri := fmt.Sprintf("http://%s:%s", localIP, mappedPort.Port()) + apiConfig := api.DefaultConfig() + apiConfig.Address = uri + apiClient, err := api.NewClient(apiConfig) + if err != nil { + return nil, err + } + + return &consulContainerNode{ + config: config, + pod: podContainer, + container: consulContainer, + serverMode: pc.Server, + ip: ip, + port: mappedPort.Int(), + datacenter: pc.Datacenter, + client: apiClient, + ctx: ctx, + podReq: podReq, + consulReq: consulReq, + dataDir: tmpDirData, + certDir: tmpCertData, + network: network, + id: index, + }, nil +} + +func (c *consulContainerNode) GetName() string { + name, err := c.container.Name(c.ctx) + if err != nil { + return "" + } + return name +} + +func (c *consulContainerNode) GetConfig() Config { + return c.config +} + +func (c *consulContainerNode) GetDatacenter() string { + return c.datacenter +} + +func (c *consulContainerNode) IsServer() bool { + return c.serverMode +} + +// GetClient returns an API client that can be used to communicate with the Agent. +func (c *consulContainerNode) GetClient() *api.Client { + return c.client +} + +// GetAddr return the network address associated with the Agent. +func (c *consulContainerNode) GetAddr() (string, int) { + return c.ip, c.port +} + +func (c *consulContainerNode) RegisterTermination(f func() error) { + c.terminateFuncs = append(c.terminateFuncs, f) +} + +func (c *consulContainerNode) Upgrade(ctx context.Context, config Config, index int) error { + pc, err := readSomeConfigFileFields(config.JSON) + if err != nil { + return err + } + + consulType := "client" + if pc.Server { + consulType = "server" + } + name := utils.RandName(fmt.Sprintf("%s-consul-%s-%d", pc.Datacenter, consulType, index)) + + // Inject new Agent name + config.Cmd = append(config.Cmd, "-node", name) + + file, err := createConfigFile(config.JSON) + if err != nil { + return err + } + + for filename, cert := range config.Certs { + err := createCertFile(c.certDir, filename, cert) + if err != nil { + return errors.Wrapf(err, "failed to write file %s", filename) + } + } + + // We'll keep the same pod. + opts := containerOpts{ + name: c.consulReq.Name, + certDir: c.certDir, + configFile: file, + dataDir: c.dataDir, + license: "", + addtionalNetworks: []string{"bridge", c.network}, + hostname: fmt.Sprintf("agent-%d", c.id), + } + _, consulReq2 := newContainerRequest(config, opts) + consulReq2.Env = c.consulReq.Env // copy license + + _ = c.container.StopLogProducer() + if err := c.container.Terminate(ctx); err != nil { + return err + } + + c.consulReq = consulReq2 + + container, err := startContainer(ctx, c.consulReq) + if err != nil { + return err + } + + if err := container.StartLogProducer(ctx); err != nil { + return err + } + container.FollowOutput(&LogConsumer{ + Prefix: name, + }) + + c.container = container + + return nil +} + +// Terminate attempts to terminate the agent container. +// This might also include running termination functions for containers associated with the agent. +// On failure, an error will be returned and the reaper process (RYUK) will handle cleanup. +func (c *consulContainerNode) Terminate() error { + + // Services might register a termination function that should also fire + // when the "agent" is cleaned up + for _, f := range c.terminateFuncs { + err := f() + if err != nil { + + } + } + + if c.container == nil { + return nil + } + + err := c.container.StopLogProducer() + + if err1 := c.container.Terminate(c.ctx); err == nil { + err = err1 + } + + c.container = nil + + return err +} + +func startContainer(ctx context.Context, req testcontainers.ContainerRequest) (testcontainers.Container, error) { + return testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) +} + +const pauseImage = "k8s.gcr.io/pause:3.3" + +type containerOpts struct { + certDir string + configFile string + dataDir string + hostname string + index int + license string + name string + addtionalNetworks []string +} + +func newContainerRequest(config Config, opts containerOpts) (podRequest, consulRequest testcontainers.ContainerRequest) { + skipReaper := isRYUKDisabled() + + pod := testcontainers.ContainerRequest{ + Image: pauseImage, + AutoRemove: false, + Name: opts.name + "-pod", + SkipReaper: skipReaper, + ExposedPorts: []string{"8500/tcp"}, + Hostname: opts.hostname, + Networks: opts.addtionalNetworks, + } + + // For handshakes like auto-encrypt, it can take 10's of seconds for the agent to become "ready". + // If we only wait until the log stream starts, subsequent commands to agents will fail. + // TODO: optimize the wait strategy + app := testcontainers.ContainerRequest{ + NetworkMode: dockercontainer.NetworkMode("container:" + opts.name + "-pod"), + Image: utils.ImageName(config.Image, config.Version), + WaitingFor: wait.ForLog(bootLogLine).WithStartupTimeout(60 * time.Second), // See note above + AutoRemove: false, + Name: opts.name, + Mounts: []testcontainers.ContainerMount{ + {Source: testcontainers.DockerBindMountSource{HostPath: opts.certDir}, Target: "/consul/config/certs"}, + {Source: testcontainers.DockerBindMountSource{HostPath: opts.configFile}, Target: "/consul/config/config.json"}, + {Source: testcontainers.DockerBindMountSource{HostPath: opts.dataDir}, Target: "/consul/data"}, + }, + Cmd: config.Cmd, + SkipReaper: skipReaper, + Env: map[string]string{"CONSUL_LICENSE": opts.license}, + } + return pod, app +} + +// isRYUKDisabled returns whether the reaper process (RYUK) has been disabled +// by an environment variable. +// +// https://github.com/testcontainers/moby-ryuk +func isRYUKDisabled() bool { + skipReaperStr := os.Getenv(disableRYUKEnv) + skipReaper, err := strconv.ParseBool(skipReaperStr) + if err != nil { + return false + } + return skipReaper +} + +func readLicense() (string, error) { + license := os.Getenv("CONSUL_LICENSE") + if license == "" { + licensePath := os.Getenv("CONSUL_LICENSE_PATH") + if licensePath != "" { + licenseBytes, err := os.ReadFile(licensePath) + if err != nil { + return "", err + } + license = string(licenseBytes) + } + } + return license, nil +} + +func createConfigFile(JSON string) (string, error) { + tmpDir, err := ioutils.TempDir("", "consul-container-test-config") + if err != nil { + return "", err + } + err = os.Chmod(tmpDir, 0777) + if err != nil { + return "", err + } + err = os.Mkdir(tmpDir+"/config", 0777) + if err != nil { + return "", err + } + configFile := tmpDir + "/config/config.hcl" + err = os.WriteFile(configFile, []byte(JSON), 0644) + if err != nil { + return "", err + } + return configFile, nil +} + +func createCertFile(dir, filename, cert string) error { + filename = filepath.Base(filename) + path := filepath.Join(dir, filename) + err := os.WriteFile(path, []byte(cert), 0644) + if err != nil { + return errors.Wrap(err, "could not write cert file") + } + return nil +} + +type parsedConfig struct { + Datacenter string `json:"datacenter"` + Server bool `json:"server"` +} + +func readSomeConfigFileFields(JSON string) (parsedConfig, error) { + var pc parsedConfig + if err := json.Unmarshal([]byte(JSON), &pc); err != nil { + return pc, errors.Wrap(err, "failed to parse config file") + } + if pc.Datacenter == "" { + pc.Datacenter = "dc1" + } + return pc, nil +} diff --git a/test/integration/consul-container/libs/agent/encryption.go b/test/integration/consul-container/libs/agent/encryption.go new file mode 100644 index 000000000000..a486dcb5b88b --- /dev/null +++ b/test/integration/consul-container/libs/agent/encryption.go @@ -0,0 +1,58 @@ +package agent + +import ( + "crypto/rand" + "crypto/x509" + "encoding/base64" + "fmt" + "net" + + "github.com/pkg/errors" + + "github.com/hashicorp/consul/tlsutil" +) + +func newSerfEncryptionKey() (string, error) { + key := make([]byte, 32) + n, err := rand.Reader.Read(key) + if err != nil { + return "", errors.Wrap(err, "error reading random data") + } + if n != 32 { + return "", errors.Wrap(err, "couldn't read enough entropy. Generate more entropy!") + } + + return base64.StdEncoding.EncodeToString(key), nil +} + +func newServerTLSKeyPair(dc string, ctx *BuildContext) (string, string, string, string) { + // Generate agent-specific key pair. Borrowed from 'consul tls cert create -server -dc ' + name := fmt.Sprintf("server.%s.%s", dc, "consul") + + dnsNames := []string{ + name, + "localhost", + } + ipAddresses := []net.IP{net.ParseIP("127.0.0.1")} + extKeyUsage := []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth} + + signer, err := tlsutil.ParseSigner(ctx.caKey) + if err != nil { + panic("could not parse signer from CA key") + } + + pub, priv, err := tlsutil.GenerateCert(tlsutil.CertOpts{ + Signer: signer, CA: ctx.caCert, Name: name, Days: 365, + DNSNames: dnsNames, IPAddresses: ipAddresses, ExtKeyUsage: extKeyUsage, + }) + + prefix := fmt.Sprintf("%s-server-%s", dc, "consul") + certFileName := fmt.Sprintf("%s-%d.pem", prefix, ctx.index) + keyFileName := fmt.Sprintf("%s-%d-key.pem", prefix, ctx.index) + + if err = tlsutil.Verify(ctx.caCert, pub, name); err != nil { + panic(fmt.Sprintf("could not verify keypair for %s and %s", certFileName, keyFileName)) + } + + return keyFileName, priv, certFileName, pub +} diff --git a/test/integration/consul-container/libs/node/log.go b/test/integration/consul-container/libs/agent/log.go similarity index 62% rename from test/integration/consul-container/libs/node/log.go rename to test/integration/consul-container/libs/agent/log.go index 58b63f2ea02b..c46f486b193a 100644 --- a/test/integration/consul-container/libs/node/log.go +++ b/test/integration/consul-container/libs/agent/log.go @@ -1,4 +1,4 @@ -package node +package agent import ( "fmt" @@ -7,13 +7,13 @@ import ( "github.com/testcontainers/testcontainers-go" ) -type NodeLogConsumer struct { +type LogConsumer struct { Prefix string } -var _ testcontainers.LogConsumer = (*NodeLogConsumer)(nil) +var _ testcontainers.LogConsumer = (*LogConsumer)(nil) -func (c *NodeLogConsumer) Accept(log testcontainers.Log) { +func (c *LogConsumer) Accept(log testcontainers.Log) { switch log.LogType { case "STDOUT": fmt.Fprint(os.Stdout, c.Prefix+" ~~ "+string(log.Content)) diff --git a/test/integration/consul-container/libs/assert/common.go b/test/integration/consul-container/libs/assert/common.go new file mode 100644 index 000000000000..d7b5ef1ae9f4 --- /dev/null +++ b/test/integration/consul-container/libs/assert/common.go @@ -0,0 +1,10 @@ +package assert + +import ( + "time" +) + +const ( + defaultTimeout = 5 * time.Second + defaultWait = 500 * time.Millisecond +) diff --git a/test/integration/consul-container/libs/assert/peering.go b/test/integration/consul-container/libs/assert/peering.go new file mode 100644 index 000000000000..87fd2bf8c72d --- /dev/null +++ b/test/integration/consul-container/libs/assert/peering.go @@ -0,0 +1,44 @@ +package assert + +import ( + "context" + "testing" + "time" + + "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/sdk/testutil/retry" +) + +// PeeringStatus verifies the peering connection is the specified state with a default retry. +func PeeringStatus(t *testing.T, client *api.Client, peerName string, status api.PeeringState) { + failer := func() *retry.Timer { + return &retry.Timer{Timeout: 20 * time.Second, Wait: defaultWait} + } + + retry.RunWith(failer(), t, func(r *retry.R) { + peering, _, err := client.Peerings().Read(context.Background(), peerName, &api.QueryOptions{}) + if err != nil { + r.Fatal("error reading peering data") + } + if status != peering.State { + r.Fatal("peering state did not match: got ", peering.State, " want ", status) + } + }) +} + +// PeeringExports verifies the correct number of exported services with a default retry. +func PeeringExports(t *testing.T, client *api.Client, peerName string, exports int) { + failer := func() *retry.Timer { + return &retry.Timer{Timeout: defaultTimeout, Wait: defaultWait} + } + + retry.RunWith(failer(), t, func(r *retry.R) { + peering, _, err := client.Peerings().Read(context.Background(), peerName, &api.QueryOptions{}) + if err != nil { + r.Fatal("error reading peering data") + } + if exports != len(peering.StreamStatus.ExportedServices) { + r.Fatal("peering exported services did not match: got ", len(peering.StreamStatus.ExportedServices), " want ", exports) + } + }) +} diff --git a/test/integration/consul-container/libs/assert/service.go b/test/integration/consul-container/libs/assert/service.go new file mode 100644 index 000000000000..266dbdd71d11 --- /dev/null +++ b/test/integration/consul-container/libs/assert/service.go @@ -0,0 +1,62 @@ +package assert + +import ( + "fmt" + "io" + "net/http" + "strings" + "testing" + "time" + + "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/sdk/testutil/retry" +) + +const ( + defaultHTTPTimeout = 30 * time.Second + defaultHTTPWait = defaultWait +) + +// HTTPServiceEchoes verifies that a post to the given ip/port combination returns the data +// in the response body +func HTTPServiceEchoes(t *testing.T, ip string, port int) { + phrase := "hello" + failer := func() *retry.Timer { + return &retry.Timer{Timeout: defaultHTTPTimeout, Wait: defaultHTTPWait} + } + + client := http.DefaultClient + url := fmt.Sprintf("http://%s:%d", ip, port) + + retry.RunWith(failer(), t, func(r *retry.R) { + t.Logf("making call to %s", url) + reader := strings.NewReader(phrase) + res, err := client.Post(url, "text/plain", reader) + if err != nil { + r.Fatal("could not make call to service ", url) + } + defer res.Body.Close() + + body, err := io.ReadAll(res.Body) + if err != nil { + r.Fatal("could not read response body ", url) + } + + if !strings.Contains(string(body), phrase) { + r.Fatal("received an incorrect response ", body) + } + }) +} + +// CatalogServiceExists verifies the service name exists in the Consul catalog +func CatalogServiceExists(t *testing.T, c *api.Client, svc string) { + retry.Run(t, func(r *retry.R) { + services, _, err := c.Catalog().Service(svc, "", nil) + if err != nil { + r.Fatal("error reading peering data") + } + if len(services) == 0 { + r.Fatal("did not find catalog entry for ", svc) + } + }) +} diff --git a/test/integration/consul-container/libs/cluster/cluster.go b/test/integration/consul-container/libs/cluster/cluster.go index 89b7fac9ef22..9e8c9d838810 100644 --- a/test/integration/consul-container/libs/cluster/cluster.go +++ b/test/integration/consul-container/libs/cluster/cluster.go @@ -2,99 +2,157 @@ package cluster import ( "context" - "crypto/rand" - "encoding/base64" "fmt" "strings" "testing" "time" + "github.com/hashicorp/serf/serf" + "github.com/pkg/errors" + "github.com/stretchr/testify/require" + "github.com/teris-io/shortid" + "github.com/testcontainers/testcontainers-go" + "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/sdk/testutil/retry" - "github.com/hashicorp/consul/test/integration/consul-container/libs/node" - "github.com/stretchr/testify/require" + libagent "github.com/hashicorp/consul/test/integration/consul-container/libs/agent" ) // Cluster provides an interface for creating and controlling a Consul cluster -// in integration tests, with nodes running in containers. +// in integration tests, with agents running in containers. +// These fields are public in the event someone might want to surgically +// craft a test case. type Cluster struct { - Nodes []node.Node - EncryptKey string + Agents []libagent.Agent + CACert string + CAKey string + ID string + Index int + Network testcontainers.Network + NetworkName string } -// New creates a Consul cluster. A node will be started for each of the given +// New creates a Consul cluster. An agent will be started for each of the given // configs and joined to the cluster. -func New(configs []node.Config) (*Cluster, error) { - serfKey, err := newSerfEncryptionKey() +// +// A cluster has its own docker network for DNS connectivity, but is also joined +func New(configs []libagent.Config) (*Cluster, error) { + id, err := shortid.Generate() if err != nil { - return nil, err + return nil, errors.Wrap(err, "could not cluster id") + } + + name := fmt.Sprintf("consul-int-cluster-%s", id) + network, err := createNetwork(name) + if err != nil { + return nil, errors.Wrap(err, "could not create cluster container network") } cluster := Cluster{ - EncryptKey: serfKey, + ID: id, + Network: network, + NetworkName: name, + } + + if err := cluster.Add(configs); err != nil { + return nil, errors.Wrap(err, "could not start or join all agents") } + return &cluster, nil +} - nodes := make([]node.Node, len(configs)) - for idx, c := range configs { - c.HCL += fmt.Sprintf(" encrypt=%q", serfKey) +// Add starts an agent with the given configuration and joins it with the existing cluster +func (c *Cluster) Add(configs []libagent.Config) error { - n, err := node.NewConsulContainer(context.Background(), c) + agents := make([]libagent.Agent, len(configs)) + for idx, conf := range configs { + n, err := libagent.NewConsulContainer(context.Background(), conf, c.NetworkName, c.Index) if err != nil { - return nil, err + return errors.Wrapf(err, "could not add container index %d", idx) } - nodes[idx] = n + agents[idx] = n + c.Index++ } - if err := cluster.AddNodes(nodes); err != nil { - return nil, err + if err := c.Join(agents); err != nil { + return errors.Wrapf(err, "could not join agent") } - return &cluster, nil + return nil } -// AddNodes joins the given nodes to the cluster. -func (c *Cluster) AddNodes(nodes []node.Node) error { +// Join joins the given agent to the cluster. +func (c *Cluster) Join(agents []libagent.Agent) error { var joinAddr string - if len(c.Nodes) >= 1 { - joinAddr, _ = c.Nodes[0].GetAddr() - } else if len(nodes) >= 1 { - joinAddr, _ = nodes[0].GetAddr() + if len(c.Agents) >= 1 { + joinAddr, _ = c.Agents[0].GetAddr() + } else if len(agents) >= 1 { + joinAddr, _ = agents[0].GetAddr() } - for _, node := range nodes { - err := node.GetClient().Agent().Join(joinAddr, false) + for _, n := range agents { + err := n.GetClient().Agent().Join(joinAddr, false) if err != nil { - return err + return errors.Wrapf(err, "could not join agent %s to %s", n.GetName(), joinAddr) + } + c.Agents = append(c.Agents, n) + } + return nil +} + +// Remove instructs the agent to leave the cluster then removes it +// from the cluster Agent list. +func (c *Cluster) Remove(n libagent.Agent) error { + err := n.GetClient().Agent().Leave() + if err != nil { + return errors.Wrapf(err, "could not remove agent %s", n.GetName()) + } + + foundIdx := -1 + for idx, this := range c.Agents { + if this == n { + foundIdx = idx + break } - c.Nodes = append(c.Nodes, node) } + + if foundIdx == -1 { + return errors.New("could not find agent in cluster") + } + + c.Agents = append(c.Agents[:foundIdx], c.Agents[foundIdx+1:]...) return nil } -// Terminate will attempt to terminate all nodes in the cluster. If any node +// Terminate will attempt to terminate all agents in the cluster and its network. If any agent // termination fails, Terminate will abort and return an error. func (c *Cluster) Terminate() error { - for _, n := range c.Nodes { + for _, n := range c.Agents { err := n.Terminate() if err != nil { return err } } + + // Testcontainers seems to clean this the network. + // Trigger it now will throw an error while the containers are still shutting down + //if err := c.Network.Remove(context.Background()); err != nil { + // return errors.Wrapf(err, "could not terminate cluster network %s", c.ID) + //} return nil } -// Leader returns the cluster leader node, or an error if no leader is +// Leader returns the cluster leader agent, or an error if no leader is // available. -func (c *Cluster) Leader() (node.Node, error) { - if len(c.Nodes) < 1 { - return nil, fmt.Errorf("no node available") +func (c *Cluster) Leader() (libagent.Agent, error) { + if len(c.Agents) < 1 { + return nil, fmt.Errorf("no agent available") } - n0 := c.Nodes[0] + n0 := c.Agents[0] - leaderAdd, err := GetLeader(n0.GetClient()) + leaderAdd, err := getLeader(n0.GetClient()) if err != nil { return nil, err } - for _, n := range c.Nodes { + for _, n := range c.Agents { addr, _ := n.GetAddr() if strings.Contains(leaderAdd, addr) { return n, nil @@ -103,31 +161,59 @@ func (c *Cluster) Leader() (node.Node, error) { return nil, fmt.Errorf("leader not found") } -func newSerfEncryptionKey() (string, error) { - key := make([]byte, 32) - n, err := rand.Reader.Read(key) +func getLeader(client *api.Client) (string, error) { + leaderAdd, err := client.Status().Leader() if err != nil { - return "", fmt.Errorf("Error reading random data: %w", err) + return "", errors.Wrap(err, "could not query leader") } - if n != 32 { - return "", fmt.Errorf("Couldn't read enough entropy. Generate more entropy!") + if leaderAdd == "" { + return "", errors.New("no leader available") } - - return base64.StdEncoding.EncodeToString(key), nil + return leaderAdd, nil } -func GetLeader(client *api.Client) (string, error) { - leaderAdd, err := client.Status().Leader() +// Followers returns the cluster following servers. +func (c *Cluster) Followers() ([]libagent.Agent, error) { + var followers []libagent.Agent + + leader, err := c.Leader() if err != nil { - return "", err + return nil, fmt.Errorf("could not determine leader: %w", err) } - if leaderAdd == "" { - return "", fmt.Errorf("no leader available") + + for _, n := range c.Agents { + if n != leader && n.IsServer() { + followers = append(followers, n) + } } - return leaderAdd, nil + return followers, nil +} + +// Servers returns the handle to server agents +func (c *Cluster) Servers() ([]libagent.Agent, error) { + var servers []libagent.Agent + + for _, n := range c.Agents { + if n.IsServer() { + servers = append(servers, n) + } + } + return servers, nil } -const retryTimeout = 20 * time.Second +// Clients returns the handle to client agents +func (c *Cluster) Clients() ([]libagent.Agent, error) { + var clients []libagent.Agent + + for _, n := range c.Agents { + if !n.IsServer() { + clients = append(clients, n) + } + } + return clients, nil +} + +const retryTimeout = 90 * time.Second const retryFrequency = 500 * time.Millisecond func LongFailer() *retry.Timer { @@ -148,7 +234,7 @@ func WaitForLeader(t *testing.T, cluster *Cluster, client *api.Client) { func waitForLeaderFromClient(t *testing.T, client *api.Client) { retry.RunWith(LongFailer(), t, func(r *retry.R) { - leader, err := GetLeader(client) + leader, err := getLeader(client) require.NoError(r, err) require.NotEmpty(r, leader) }) @@ -157,7 +243,13 @@ func waitForLeaderFromClient(t *testing.T, client *api.Client) { func WaitForMembers(t *testing.T, client *api.Client, expectN int) { retry.RunWith(LongFailer(), t, func(r *retry.R) { members, err := client.Agent().Members(false) + var activeMembers int + for _, member := range members { + if serf.MemberStatus(member.Status) == serf.StatusAlive { + activeMembers++ + } + } require.NoError(r, err) - require.Len(r, members, expectN) + require.Equal(r, expectN, activeMembers) }) } diff --git a/test/integration/consul-container/libs/cluster/network.go b/test/integration/consul-container/libs/cluster/network.go new file mode 100644 index 000000000000..89abf6f7e552 --- /dev/null +++ b/test/integration/consul-container/libs/cluster/network.go @@ -0,0 +1,23 @@ +package cluster + +import ( + "context" + + "github.com/pkg/errors" + "github.com/testcontainers/testcontainers-go" +) + +func createNetwork(name string) (testcontainers.Network, error) { + req := testcontainers.GenericNetworkRequest{ + NetworkRequest: testcontainers.NetworkRequest{ + Name: name, + Attachable: true, + CheckDuplicate: true, + }, + } + network, err := testcontainers.GenericNetwork(context.Background(), req) + if err != nil { + return nil, errors.Wrap(err, "could not create network") + } + return network, nil +} diff --git a/test/integration/consul-container/libs/node/consul-container.go b/test/integration/consul-container/libs/node/consul-container.go deleted file mode 100644 index 418530843312..000000000000 --- a/test/integration/consul-container/libs/node/consul-container.go +++ /dev/null @@ -1,295 +0,0 @@ -package node - -import ( - "context" - "fmt" - "os" - "strconv" - "time" - - dockercontainer "github.com/docker/docker/api/types/container" - "github.com/docker/docker/pkg/ioutils" - "github.com/hashicorp/consul/api" - "github.com/hashicorp/hcl" - "github.com/testcontainers/testcontainers-go" - "github.com/testcontainers/testcontainers-go/wait" - - "github.com/hashicorp/consul/test/integration/consul-container/libs/utils" -) - -const bootLogLine = "Consul agent running" -const disableRYUKEnv = "TESTCONTAINERS_RYUK_DISABLED" - -// consulContainerNode implements the Node interface by running a Consul node -// in a container. -type consulContainerNode struct { - ctx context.Context - client *api.Client - pod testcontainers.Container - container testcontainers.Container - ip string - port int - config Config - podReq testcontainers.ContainerRequest - consulReq testcontainers.ContainerRequest - dataDir string -} - -func (c *consulContainerNode) GetConfig() Config { - return c.config -} - -func startContainer(ctx context.Context, req testcontainers.ContainerRequest) (testcontainers.Container, error) { - return testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ - ContainerRequest: req, - Started: true, - }) -} - -// NewConsulContainer starts a Consul node in a container with the given config. -func NewConsulContainer(ctx context.Context, config Config) (Node, error) { - license, err := readLicense() - if err != nil { - return nil, err - } - name := utils.RandName("consul-") - - tmpDirData, err := ioutils.TempDir("", name) - if err != nil { - return nil, err - } - err = os.Chmod(tmpDirData, 0777) - if err != nil { - return nil, err - } - - pc, err := readSomeConfigFileFields(config.HCL) - if err != nil { - return nil, err - } - - configFile, err := createConfigFile(config.HCL) - if err != nil { - return nil, err - } - - podReq, consulReq := newContainerRequest(config, name, configFile, tmpDirData, license) - - podContainer, err := startContainer(ctx, podReq) - if err != nil { - return nil, err - } - - localIP, err := podContainer.Host(ctx) - if err != nil { - return nil, err - } - - mappedPort, err := podContainer.MappedPort(ctx, "8500") - if err != nil { - return nil, err - } - - ip, err := podContainer.ContainerIP(ctx) - if err != nil { - return nil, err - } - - consulContainer, err := startContainer(ctx, consulReq) - if err != nil { - return nil, err - } - - if err := consulContainer.StartLogProducer(ctx); err != nil { - return nil, err - } - consulContainer.FollowOutput(&NodeLogConsumer{ - Prefix: pc.NodeName, - }) - - uri := fmt.Sprintf("http://%s:%s", localIP, mappedPort.Port()) - apiConfig := api.DefaultConfig() - apiConfig.Address = uri - apiClient, err := api.NewClient(apiConfig) - if err != nil { - return nil, err - } - - return &consulContainerNode{ - config: config, - pod: podContainer, - container: consulContainer, - ip: ip, - port: mappedPort.Int(), - client: apiClient, - ctx: ctx, - podReq: podReq, - consulReq: consulReq, - dataDir: tmpDirData, - }, nil -} - -const pauseImage = "k8s.gcr.io/pause:3.3" - -func newContainerRequest(config Config, name, configFile, dataDir, license string) (podRequest, consulRequest testcontainers.ContainerRequest) { - skipReaper := isRYUKDisabled() - - pod := testcontainers.ContainerRequest{ - Image: pauseImage, - AutoRemove: false, - Name: name + "-pod", - SkipReaper: skipReaper, - ExposedPorts: []string{"8500/tcp"}, - } - - app := testcontainers.ContainerRequest{ - NetworkMode: dockercontainer.NetworkMode("container:" + name + "-pod"), - Image: config.Image + ":" + config.Version, - WaitingFor: wait.ForLog(bootLogLine).WithStartupTimeout(10 * time.Second), - AutoRemove: false, - Name: name, - Mounts: []testcontainers.ContainerMount{ - {Source: testcontainers.DockerBindMountSource{HostPath: configFile}, Target: "/consul/config/config.hcl"}, - {Source: testcontainers.DockerBindMountSource{HostPath: dataDir}, Target: "/consul/data"}, - }, - Cmd: config.Cmd, - SkipReaper: skipReaper, - Env: map[string]string{"CONSUL_LICENSE": license}, - } - - return pod, app -} - -// GetClient returns an API client that can be used to communicate with the Node. -func (c *consulContainerNode) GetClient() *api.Client { - return c.client -} - -// GetAddr return the network address associated with the Node. -func (c *consulContainerNode) GetAddr() (string, int) { - return c.ip, c.port -} - -func (c *consulContainerNode) Upgrade(ctx context.Context, config Config) error { - pc, err := readSomeConfigFileFields(config.HCL) - if err != nil { - return err - } - - file, err := createConfigFile(config.HCL) - if err != nil { - return err - } - - // We'll keep the same pod. - _, consulReq2 := newContainerRequest( - config, - c.consulReq.Name, - file, - c.dataDir, - "", - ) - consulReq2.Env = c.consulReq.Env // copy license - - _ = c.container.StopLogProducer() - if err := c.container.Terminate(ctx); err != nil { - return err - } - - c.consulReq = consulReq2 - - container, err := startContainer(ctx, c.consulReq) - if err != nil { - return err - } - - if err := container.StartLogProducer(ctx); err != nil { - return err - } - container.FollowOutput(&NodeLogConsumer{ - Prefix: pc.NodeName, - }) - - c.container = container - - return nil -} - -// Terminate attempts to terminate the container. On failure, an error will be -// returned and the reaper process (RYUK) will handle cleanup. -func (c *consulContainerNode) Terminate() error { - if c.container == nil { - return nil - } - - err := c.container.StopLogProducer() - - if err1 := c.container.Terminate(c.ctx); err == nil { - err = err1 - } - - c.container = nil - - return err -} - -// isRYUKDisabled returns whether the reaper process (RYUK) has been disabled -// by an environment variable. -// -// https://github.com/testcontainers/moby-ryuk -func isRYUKDisabled() bool { - skipReaperStr := os.Getenv(disableRYUKEnv) - skipReaper, err := strconv.ParseBool(skipReaperStr) - if err != nil { - return false - } - return skipReaper -} - -func readLicense() (string, error) { - license := os.Getenv("CONSUL_LICENSE") - if license == "" { - licensePath := os.Getenv("CONSUL_LICENSE_PATH") - if licensePath != "" { - licenseBytes, err := os.ReadFile(licensePath) - if err != nil { - return "", err - } - license = string(licenseBytes) - } - } - return license, nil -} - -func createConfigFile(HCL string) (string, error) { - tmpDir, err := ioutils.TempDir("", "consul-container-test-config") - if err != nil { - return "", err - } - err = os.Chmod(tmpDir, 0777) - if err != nil { - return "", err - } - err = os.Mkdir(tmpDir+"/config", 0777) - if err != nil { - return "", err - } - configFile := tmpDir + "/config/config.hcl" - err = os.WriteFile(configFile, []byte(HCL), 0644) - if err != nil { - return "", err - } - return configFile, nil -} - -type parsedConfig struct { - NodeName string `hcl:"node_name"` -} - -func readSomeConfigFileFields(HCL string) (parsedConfig, error) { - var pc parsedConfig - if err := hcl.Decode(&pc, HCL); err != nil { - return pc, fmt.Errorf("Failed to parse config file: %w", err) - } - return pc, nil -} diff --git a/test/integration/consul-container/libs/node/consul-container_oss.go b/test/integration/consul-container/libs/node/consul-container_oss.go deleted file mode 100644 index 515e9dbbb55d..000000000000 --- a/test/integration/consul-container/libs/node/consul-container_oss.go +++ /dev/null @@ -1,4 +0,0 @@ -//go:build !consulent -// +build !consulent - -package node diff --git a/test/integration/consul-container/libs/node/node.go b/test/integration/consul-container/libs/node/node.go deleted file mode 100644 index 14cf3ab8d466..000000000000 --- a/test/integration/consul-container/libs/node/node.go +++ /dev/null @@ -1,24 +0,0 @@ -package node - -import ( - "context" - - "github.com/hashicorp/consul/api" -) - -// Node represent a Consul node abstraction -type Node interface { - Terminate() error - GetClient() *api.Client - GetAddr() (string, int) - GetConfig() Config - Upgrade(ctx context.Context, config Config) error -} - -// Config is a set of configurations required to create a Node -type Config struct { - HCL string - Image string - Version string - Cmd []string -} diff --git a/test/integration/consul-container/libs/service/assets/Dockerfile-consul-envoy b/test/integration/consul-container/libs/service/assets/Dockerfile-consul-envoy new file mode 100644 index 000000000000..5ea9d3ae5e74 --- /dev/null +++ b/test/integration/consul-container/libs/service/assets/Dockerfile-consul-envoy @@ -0,0 +1,8 @@ +# Note this arg has to be before the first FROM +ARG CONSUL_IMAGE +ARG ENVOY_VERSION + +FROM ${CONSUL_IMAGE} as consul + +FROM docker.mirror.hashicorp.services/envoyproxy/envoy:v${ENVOY_VERSION} +COPY --from=consul /bin/consul /bin/consul diff --git a/test/integration/consul-container/libs/service/common.go b/test/integration/consul-container/libs/service/common.go new file mode 100644 index 000000000000..ef114f58a68a --- /dev/null +++ b/test/integration/consul-container/libs/service/common.go @@ -0,0 +1,60 @@ +package service + +import ( + "archive/tar" + "bytes" + _ "embed" + "os" + + "github.com/testcontainers/testcontainers-go" +) + +const ( + envoyEnvKey = "ENVOY_VERSION" + envoyLogLevel = "debug" + envoyVersion = "1.23.1" + + hashicorpDockerProxy = "docker.mirror.hashicorp.services" +) + +//go:embed assets/Dockerfile-consul-envoy +var consulEnvoyDockerfile string + +// getDevContainerDockerfile returns the necessary context to build a combined consul and +// envoy image for running "consul connect envoy ..." +func getDevContainerDockerfile() (testcontainers.FromDockerfile, error) { + var buf bytes.Buffer + tw := tar.NewWriter(&buf) + + dockerfileBytes := []byte(consulEnvoyDockerfile) + + hdr := &tar.Header{ + Name: "Dockerfile", + Mode: 0600, + Size: int64(len(dockerfileBytes)), + } + if err := tw.WriteHeader(hdr); err != nil { + return testcontainers.FromDockerfile{}, err + } + + if _, err := tw.Write(dockerfileBytes); err != nil { + return testcontainers.FromDockerfile{}, err + } + + if err := tw.Close(); err != nil { + return testcontainers.FromDockerfile{}, err + } + reader := bytes.NewReader(buf.Bytes()) + fromDockerfile := testcontainers.FromDockerfile{ + ContextArchive: reader, + } + + return fromDockerfile, nil +} + +func getEnvoyVersion() string { + if version, ok := os.LookupEnv(envoyEnvKey); ok && version != "" { + return version + } + return envoyVersion +} diff --git a/test/integration/consul-container/libs/service/connect.go b/test/integration/consul-container/libs/service/connect.go new file mode 100644 index 000000000000..53b549c48f05 --- /dev/null +++ b/test/integration/consul-container/libs/service/connect.go @@ -0,0 +1,146 @@ +package service + +import ( + "context" + "fmt" + "time" + + "github.com/docker/go-connections/nat" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" + + libnode "github.com/hashicorp/consul/test/integration/consul-container/libs/agent" + "github.com/hashicorp/consul/test/integration/consul-container/libs/utils" +) + +// ConnectContainer +type ConnectContainer struct { + ctx context.Context + container testcontainers.Container + ip string + appPort int + adminPort int + req testcontainers.ContainerRequest +} + +func (g ConnectContainer) GetName() string { + name, err := g.container.Name(g.ctx) + if err != nil { + return "" + } + return name +} + +func (g ConnectContainer) GetAddr() (string, int) { + return g.ip, g.appPort +} + +func (g ConnectContainer) Start() error { + if g.container == nil { + return fmt.Errorf("container has not been initialized") + } + return g.container.Start(context.Background()) +} + +func (g ConnectContainer) GetAdminAddr() (string, int) { + return "localhost", g.adminPort +} + +// Terminate attempts to terminate the container. On failure, an error will be +// returned and the reaper process (RYUK) will handle cleanup. +func (c ConnectContainer) Terminate() error { + if c.container == nil { + return nil + } + + err := c.container.StopLogProducer() + + if err1 := c.container.Terminate(c.ctx); err == nil { + err = err1 + } + + c.container = nil + + return err +} + +func NewConnectService(ctx context.Context, name string, serviceName string, serviceBindPort int, node libnode.Agent) (*ConnectContainer, error) { + namePrefix := fmt.Sprintf("%s-service-connect-%s", node.GetDatacenter(), name) + containerName := utils.RandName(namePrefix) + + envoyVersion := getEnvoyVersion() + agentConfig := node.GetConfig() + buildargs := map[string]*string{ + "ENVOY_VERSION": utils.StringToPointer(envoyVersion), + "CONSUL_IMAGE": utils.StringToPointer(agentConfig.Image), + } + + dockerfileCtx, err := getDevContainerDockerfile() + if err != nil { + return nil, err + } + dockerfileCtx.BuildArgs = buildargs + + nodeIP, _ := node.GetAddr() + + req := testcontainers.ContainerRequest{ + FromDockerfile: dockerfileCtx, + WaitingFor: wait.ForLog("").WithStartupTimeout(100 * time.Second), + AutoRemove: false, + Name: containerName, + Cmd: []string{ + "consul", "connect", "envoy", + "-sidecar-for", serviceName, + "-service", name, + "-admin-bind", "0.0.0.0:19000", + "-grpc-addr", fmt.Sprintf("%s:8502", nodeIP), + "-http-addr", fmt.Sprintf("%s:8500", nodeIP), + "--", + "--log-level", envoyLogLevel}, + ExposedPorts: []string{ + fmt.Sprintf("%d/tcp", serviceBindPort), // Envoy Listener + "19000/tcp", // Envoy Admin Port + }, + } + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + return nil, err + } + + ip, err := container.ContainerIP(ctx) + if err != nil { + return nil, err + } + + mappedAppPort, err := container.MappedPort(ctx, nat.Port(fmt.Sprintf("%d", serviceBindPort))) + if err != nil { + return nil, err + } + mappedAdminPort, err := container.MappedPort(ctx, nat.Port(fmt.Sprintf("%d", 19000))) + if err != nil { + return nil, err + } + + if err := container.StartLogProducer(ctx); err != nil { + return nil, err + } + container.FollowOutput(&LogConsumer{ + Prefix: containerName, + }) + + // Register the termination function the agent so the containers can stop together + terminate := func() error { + return container.Terminate(context.Background()) + } + node.RegisterTermination(terminate) + + return &ConnectContainer{ + container: container, + ip: ip, + appPort: mappedAppPort.Int(), + adminPort: mappedAdminPort.Int(), + }, nil +} diff --git a/test/integration/consul-container/libs/service/examples.go b/test/integration/consul-container/libs/service/examples.go new file mode 100644 index 000000000000..184b82045591 --- /dev/null +++ b/test/integration/consul-container/libs/service/examples.go @@ -0,0 +1,113 @@ +package service + +import ( + "context" + "fmt" + "time" + + "github.com/docker/go-connections/nat" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" + + libnode "github.com/hashicorp/consul/test/integration/consul-container/libs/agent" + "github.com/hashicorp/consul/test/integration/consul-container/libs/utils" +) + +// exampleContainer +type exampleContainer struct { + ctx context.Context + container testcontainers.Container + ip string + httpPort int + grpcPort int + req testcontainers.ContainerRequest +} + +func (g exampleContainer) GetName() string { + name, err := g.container.Name(g.ctx) + if err != nil { + return "" + } + return name +} + +func (g exampleContainer) GetAddr() (string, int) { + return g.ip, g.httpPort +} + +func (g exampleContainer) Start() error { + if g.container == nil { + return fmt.Errorf("container has not been initialized") + } + return g.container.Start(context.Background()) +} + +// Terminate attempts to terminate the container. On failure, an error will be +// returned and the reaper process (RYUK) will handle cleanup. +func (c exampleContainer) Terminate() error { + if c.container == nil { + return nil + } + + err := c.container.StopLogProducer() + + if err1 := c.container.Terminate(c.ctx); err == nil { + err = err1 + } + + c.container = nil + + return err +} + +func NewExampleService(ctx context.Context, name string, httpPort int, grpcPort int, node libnode.Agent) (Service, error) { + namePrefix := fmt.Sprintf("%s-service-example-%s", node.GetDatacenter(), name) + containerName := utils.RandName(namePrefix) + + req := testcontainers.ContainerRequest{ + Image: hashicorpDockerProxy + "/fortio/fortio", + WaitingFor: wait.ForLog("").WithStartupTimeout(100 * time.Second), + AutoRemove: false, + Name: containerName, + Cmd: []string{"server", "-http-port", fmt.Sprintf("%d", httpPort), "-grpc-port", fmt.Sprintf("%d", grpcPort), "-redirect-port", "-disabled"}, + Env: map[string]string{"FORTIO_NAME": name}, + ExposedPorts: []string{ + fmt.Sprintf("%d/tcp", httpPort), // HTTP Listener + fmt.Sprintf("%d/tcp", grpcPort), // GRPC Listener + }, + } + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + return nil, err + } + ip, err := container.ContainerIP(ctx) + if err != nil { + return nil, err + } + mappedHTPPPort, err := container.MappedPort(ctx, nat.Port(fmt.Sprintf("%d", httpPort))) + if err != nil { + return nil, err + } + + mappedGRPCPort, err := container.MappedPort(ctx, nat.Port(fmt.Sprintf("%d", grpcPort))) + if err != nil { + return nil, err + } + + if err := container.StartLogProducer(ctx); err != nil { + return nil, err + } + container.FollowOutput(&LogConsumer{ + Prefix: containerName, + }) + + terminate := func() error { + return container.Terminate(context.Background()) + } + node.RegisterTermination(terminate) + + return &exampleContainer{container: container, ip: ip, httpPort: mappedHTPPPort.Int(), grpcPort: mappedGRPCPort.Int()}, nil +} diff --git a/test/integration/consul-container/libs/service/gateway.go b/test/integration/consul-container/libs/service/gateway.go new file mode 100644 index 000000000000..7b0ab924c7d6 --- /dev/null +++ b/test/integration/consul-container/libs/service/gateway.go @@ -0,0 +1,130 @@ +package service + +import ( + "context" + "fmt" + "time" + + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" + + libnode "github.com/hashicorp/consul/test/integration/consul-container/libs/agent" + "github.com/hashicorp/consul/test/integration/consul-container/libs/utils" +) + +// gatewayContainer +type gatewayContainer struct { + ctx context.Context + container testcontainers.Container + ip string + port int + req testcontainers.ContainerRequest +} + +func (g gatewayContainer) GetName() string { + name, err := g.container.Name(g.ctx) + if err != nil { + return "" + } + return name +} + +func (g gatewayContainer) GetAddr() (string, int) { + return g.ip, g.port +} + +func (g gatewayContainer) Start() error { + if g.container == nil { + return fmt.Errorf("container has not been initialized") + } + return g.container.Start(context.Background()) +} + +// Terminate attempts to terminate the container. On failure, an error will be +// returned and the reaper process (RYUK) will handle cleanup. +func (c gatewayContainer) Terminate() error { + if c.container == nil { + return nil + } + + err := c.container.StopLogProducer() + + if err1 := c.container.Terminate(c.ctx); err == nil { + err = err1 + } + + c.container = nil + + return err +} + +func NewGatewayService(ctx context.Context, name string, kind string, node libnode.Agent) (Service, error) { + namePrefix := fmt.Sprintf("%s-service-gateway-%s", node.GetDatacenter(), name) + containerName := utils.RandName(namePrefix) + + envoyVersion := getEnvoyVersion() + agentConfig := node.GetConfig() + buildargs := map[string]*string{ + "ENVOY_VERSION": utils.StringToPointer(envoyVersion), + "CONSUL_IMAGE": utils.StringToPointer(agentConfig.Image), + } + + dockerfileCtx, err := getDevContainerDockerfile() + if err != nil { + return nil, err + } + dockerfileCtx.BuildArgs = buildargs + + nodeIP, _ := node.GetAddr() + + req := testcontainers.ContainerRequest{ + FromDockerfile: dockerfileCtx, + WaitingFor: wait.ForLog("").WithStartupTimeout(100 * time.Second), + AutoRemove: false, + Name: containerName, + Cmd: []string{ + "consul", "connect", "envoy", + fmt.Sprintf("-gateway=%s", kind), + "-register", + "-service", name, + "-address", "{{ GetInterfaceIP \"eth0\" }}:8443", + fmt.Sprintf("-grpc-addr=%s:%d", nodeIP, 8502), + "-admin-bind", "0.0.0.0:19000", + "--", + "--log-level", envoyLogLevel}, + Env: map[string]string{"CONSUL_HTTP_ADDR": fmt.Sprintf("%s:%d", nodeIP, 8500)}, + ExposedPorts: []string{ + "8443/tcp", // Envoy Gateway Listener + "19000/tcp", // Envoy Admin Port + }, + } + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + return nil, err + } + ip, err := container.ContainerIP(ctx) + if err != nil { + return nil, err + } + mappedPort, err := container.MappedPort(ctx, "8443") + if err != nil { + return nil, err + } + + if err := container.StartLogProducer(ctx); err != nil { + return nil, err + } + container.FollowOutput(&LogConsumer{ + Prefix: containerName, + }) + + terminate := func() error { + return container.Terminate(context.Background()) + } + node.RegisterTermination(terminate) + + return &gatewayContainer{container: container, ip: ip, port: mappedPort.Int()}, nil +} diff --git a/test/integration/consul-container/libs/service/helpers.go b/test/integration/consul-container/libs/service/helpers.go new file mode 100644 index 000000000000..92e35079c4fa --- /dev/null +++ b/test/integration/consul-container/libs/service/helpers.go @@ -0,0 +1,148 @@ +package service + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/hashicorp/consul/api" + libnode "github.com/hashicorp/consul/test/integration/consul-container/libs/agent" +) + +func CreateAndRegisterStaticServerAndSidecar(node libnode.Agent) (Service, Service, error) { + // Create a service and proxy instance + serverService, err := NewExampleService(context.Background(), "static-server", 8080, 8079, node) + if err != nil { + return nil, nil, err + } + + serverConnectProxy, err := NewConnectService(context.Background(), "static-server-sidecar", "static-server", 8080, node) // bindPort not used + if err != nil { + return nil, nil, err + } + + serverServiceIP, _ := serverService.GetAddr() + serverConnectProxyIP, _ := serverConnectProxy.GetAddr() + + // Register the static-server service and sidecar + req := &api.AgentServiceRegistration{ + Name: "static-server", + Port: 8080, + Address: serverServiceIP, + Connect: &api.AgentServiceConnect{ + SidecarService: &api.AgentServiceRegistration{ + Name: "static-server-sidecar-proxy", + Port: 20000, + Address: serverConnectProxyIP, + Kind: api.ServiceKindConnectProxy, + Checks: api.AgentServiceChecks{ + &api.AgentServiceCheck{ + Name: "Connect Sidecar Listening", + TCP: fmt.Sprintf("%s:%d", serverConnectProxyIP, 20000), + Interval: "10s", + Status: api.HealthPassing, + }, + &api.AgentServiceCheck{ + Name: "Connect Sidecar Aliasing Static Server", + AliasService: "static-server", + Status: api.HealthPassing, + }, + }, + Proxy: &api.AgentServiceConnectProxyConfig{ + DestinationServiceName: "static-server", + LocalServiceAddress: serverServiceIP, + LocalServicePort: 8080, + }, + }, + }, + Check: &api.AgentServiceCheck{ + Name: "Static Server Listening", + TCP: fmt.Sprintf("%s:%d", serverServiceIP, 8080), + Interval: "10s", + Status: api.HealthPassing, + }, + } + + err = node.GetClient().Agent().ServiceRegister(req) + if err != nil { + return serverService, serverConnectProxy, err + } + + return serverService, serverConnectProxy, nil +} + +func CreateAndRegisterStaticClientSidecar(node libnode.Agent, peerName string, localMeshGateway bool) (*ConnectContainer, error) { + // Create a service and proxy instance + clientConnectProxy, err := NewConnectService(context.Background(), "static-client-sidecar", "static-client", 5000, node) + if err != nil { + return nil, err + } + + clientConnectProxyIP, _ := clientConnectProxy.GetAddr() + + mgwMode := api.MeshGatewayModeRemote + if localMeshGateway { + mgwMode = api.MeshGatewayModeLocal + } + + // Register the static-client service and sidecar + req := &api.AgentServiceRegistration{ + Name: "static-client", + Port: 8080, + Connect: &api.AgentServiceConnect{ + SidecarService: &api.AgentServiceRegistration{ + Name: "static-client-sidecar-proxy", + Port: 20000, + Kind: api.ServiceKindConnectProxy, + Checks: api.AgentServiceChecks{ + &api.AgentServiceCheck{ + Name: "Connect Sidecar Listening", + TCP: fmt.Sprintf("%s:%d", clientConnectProxyIP, 20000), + Interval: "10s", + Status: api.HealthPassing, + }, + }, + Proxy: &api.AgentServiceConnectProxyConfig{ + Upstreams: []api.Upstream{ + { + DestinationName: "static-server", + DestinationPeer: peerName, + LocalBindAddress: "0.0.0.0", + LocalBindPort: 5000, + MeshGateway: api.MeshGatewayConfig{ + Mode: mgwMode, + }, + }, + }, + }, + }, + }, + Checks: api.AgentServiceChecks{}, + } + + err = node.GetClient().Agent().ServiceRegister(req) + if err != nil { + return clientConnectProxy, err + } + + return clientConnectProxy, nil +} + +func GetEnvoyConfigDump(port int) (string, error) { + client := http.DefaultClient + url := fmt.Sprintf("http://localhost:%d/config_dump?include_eds", port) + + res, err := client.Get(url) + if err != nil { + return "", err + } + defer res.Body.Close() + + body, err := io.ReadAll(res.Body) + if err != nil { + return "", err + } + + return string(body), nil +} diff --git a/test/integration/consul-container/libs/service/log.go b/test/integration/consul-container/libs/service/log.go new file mode 100644 index 000000000000..d210f35c8a5b --- /dev/null +++ b/test/integration/consul-container/libs/service/log.go @@ -0,0 +1,23 @@ +package service + +import ( + "fmt" + "os" + + "github.com/testcontainers/testcontainers-go" +) + +type LogConsumer struct { + Prefix string +} + +var _ testcontainers.LogConsumer = (*LogConsumer)(nil) + +func (c *LogConsumer) Accept(log testcontainers.Log) { + switch log.LogType { + case "STDOUT": + fmt.Fprint(os.Stdout, c.Prefix+" ~~ "+string(log.Content)) + case "STDERR": + fmt.Fprint(os.Stderr, c.Prefix+" ~~ "+string(log.Content)) + } +} diff --git a/test/integration/consul-container/libs/service/service.go b/test/integration/consul-container/libs/service/service.go new file mode 100644 index 000000000000..3ecdf87689d1 --- /dev/null +++ b/test/integration/consul-container/libs/service/service.go @@ -0,0 +1,10 @@ +package service + +// Service represents a process that will be registered with the +// Consul catalog, including Consul components such as sidecars and gateways +type Service interface { + Terminate() error + GetName() string + GetAddr() (string, int) + Start() (err error) +} diff --git a/test/integration/consul-container/libs/utils/helpers.go b/test/integration/consul-container/libs/utils/helpers.go new file mode 100644 index 000000000000..6dace27b27b6 --- /dev/null +++ b/test/integration/consul-container/libs/utils/helpers.go @@ -0,0 +1,17 @@ +package utils + +import ( + "github.com/hashicorp/consul/api" +) + +func ApplyDefaultProxySettings(c *api.Client) (bool, error) { + req := &api.ProxyConfigEntry{ + Name: "global", + Kind: "proxy-defaults", + Config: map[string]any{ + "protocol": "tcp", + }, + } + ok, _, err := c.ConfigEntries().Set(req, &api.WriteOptions{}) + return ok, err +} diff --git a/test/integration/consul-container/libs/utils/utils.go b/test/integration/consul-container/libs/utils/utils.go index 552b85d0b701..c95307e49064 100644 --- a/test/integration/consul-container/libs/utils/utils.go +++ b/test/integration/consul-container/libs/utils/utils.go @@ -1,13 +1,60 @@ package utils import ( - "github.com/hashicorp/go-uuid" + "encoding/json" + "fmt" + + "github.com/itchyny/gojq" + "github.com/teris-io/shortid" ) func RandName(name string) string { - generateUUID, err := uuid.GenerateUUID() + shortID, err := shortid.New(1, shortid.DefaultABC, 6666) + id, err := shortID.Generate() if err != nil { return "" } - return name + generateUUID + return name + "-" + id +} + +// JQFilter uses the provided "jq" filter to parse json. +// Matching results are returned as a slice of strings. +func JQFilter(config, filter string) ([]string, error) { + result := []string{} + query, err := gojq.Parse(filter) + if err != nil { + return nil, err + } + + var m interface{} + err = json.Unmarshal([]byte(config), &m) + if err != nil { + return nil, err + } + + iter := query.Run(m) + for { + v, ok := iter.Next() + if !ok { + break + } + if err, ok := v.(error); ok { + return nil, err + } + s := fmt.Sprintf("%v", v) + result = append(result, s) + } + return result, nil +} + +func IntToPointer(i int) *int { + return &i +} + +func BoolToPointer(b bool) *bool { + return &b +} + +func StringToPointer(s string) *string { + return &s } diff --git a/test/integration/consul-container/libs/utils/version.go b/test/integration/consul-container/libs/utils/version.go new file mode 100644 index 000000000000..b2e14156e1c7 --- /dev/null +++ b/test/integration/consul-container/libs/utils/version.go @@ -0,0 +1,21 @@ +package utils + +import ( + "flag" +) + +var ( + TargetImage string + TargetVersion string + + LatestImage string + LatestVersion string +) + +func init() { + flag.StringVar(&TargetImage, "target-image", DefaultImageName, "docker image name to be used under test (Default: "+DefaultImageName+")") + flag.StringVar(&TargetVersion, "target-version", "local", "docker image version to be used as UUT (unit under test)") + + flag.StringVar(&LatestImage, "latest-image", DefaultImageName, "docker image name to be used under test (Default: "+DefaultImageName+")") + flag.StringVar(&LatestVersion, "latest-version", "latest", "docker image to be used as latest") +} diff --git a/test/integration/consul-container/libs/utils/version_ce.go b/test/integration/consul-container/libs/utils/version_ce.go new file mode 100644 index 000000000000..37f4410c956b --- /dev/null +++ b/test/integration/consul-container/libs/utils/version_ce.go @@ -0,0 +1,12 @@ +//go:build !consulent +// +build !consulent + +package utils + +const ( + DefaultImageName = "consul" +) + +func ImageName(image, version string) string { + return image + ":" + version +} diff --git a/test/integration/consul-container/libs/utils/version_oss.go b/test/integration/consul-container/libs/utils/version_oss.go deleted file mode 100644 index 5f65ebc9ae7c..000000000000 --- a/test/integration/consul-container/libs/utils/version_oss.go +++ /dev/null @@ -1,14 +0,0 @@ -//go:build !consulent -// +build !consulent - -package utils - -import "flag" - -// TODO: need a better way to abstract the container creation and configuration; -// please refer to the discussion in github PR - -var TargetImage = flag.String("target-image", "consul", "docker image name to be used under test (Default: consul)") -var TargetVersion = flag.String("target-version", "local", "docker image version to be used as UUT (unit under test)") -var LatestImage = flag.String("latest-image", "consul", "docker image name to be used under test (Default: consul)") -var LatestVersion = flag.String("latest-version", "1.11", "docker image to be used as latest") diff --git a/test/integration/consul-container/test/basic/connect_service_test.go b/test/integration/consul-container/test/basic/connect_service_test.go new file mode 100644 index 000000000000..099b7d728d82 --- /dev/null +++ b/test/integration/consul-container/test/basic/connect_service_test.go @@ -0,0 +1,88 @@ +package basic + +import ( + "testing" + + "github.com/stretchr/testify/require" + + libagent "github.com/hashicorp/consul/test/integration/consul-container/libs/agent" + libassert "github.com/hashicorp/consul/test/integration/consul-container/libs/assert" + libcluster "github.com/hashicorp/consul/test/integration/consul-container/libs/cluster" + libservice "github.com/hashicorp/consul/test/integration/consul-container/libs/service" + "github.com/hashicorp/consul/test/integration/consul-container/libs/utils" +) + +// TestBasicConnectService Summary +// This test makes sure two services in the same datacenter have connectivity. +// A simulated client (a direct HTTP call) talks to it's upstream proxy through the +// +// Steps: +// * Create a single agent cluster. +// * Create the example static-server and sidecar containers, then register them both with Consul +// * Create an example static-client sidecar, then register both the service and sidecar with Consul +// * Make sure a call to the client sidecar local bind port returns a response from the upstream, static-server +func TestBasicConnectService(t *testing.T) { + cluster := createCluster(t) + defer terminate(t, cluster) + + clientService := createServices(t, cluster) + _, port := clientService.GetAddr() + + libassert.HTTPServiceEchoes(t, "localhost", port) +} + +func terminate(t *testing.T, cluster *libcluster.Cluster) { + err := cluster.Terminate() + require.NoError(t, err) +} + +// createCluster +func createCluster(t *testing.T) *libcluster.Cluster { + opts := libagent.BuildOptions{ + InjectAutoEncryption: true, + InjectGossipEncryption: true, + } + ctx, err := libagent.NewBuildContext(opts) + require.NoError(t, err) + + conf, err := libagent.NewConfigBuilder(ctx).ToAgentConfig() + require.NoError(t, err) + t.Logf("Cluster config:\n%s", conf.JSON) + + configs := []libagent.Config{*conf} + + cluster, err := libcluster.New(configs) + require.NoError(t, err) + + node := cluster.Agents[0] + client := node.GetClient() + libcluster.WaitForLeader(t, cluster, client) + libcluster.WaitForMembers(t, client, 1) + + // Default Proxy Settings + ok, err := utils.ApplyDefaultProxySettings(client) + require.NoError(t, err) + require.True(t, ok) + + return cluster +} + +func createServices(t *testing.T, cluster *libcluster.Cluster) libservice.Service { + node := cluster.Agents[0] + client := node.GetClient() + + // Create a service and proxy instance + _, _, err := libservice.CreateAndRegisterStaticServerAndSidecar(node) + require.NoError(t, err) + + libassert.CatalogServiceExists(t, client, "static-server-sidecar-proxy") + libassert.CatalogServiceExists(t, client, "static-server") + + // Create a client proxy instance with the server as an upstream + clientConnectProxy, err := libservice.CreateAndRegisterStaticClientSidecar(node, "", false) + require.NoError(t, err) + + libassert.CatalogServiceExists(t, client, "static-client-sidecar-proxy") + + return clientConnectProxy +} diff --git a/test/integration/consul-container/metrics/leader_test.go b/test/integration/consul-container/test/metrics/leader_test.go similarity index 69% rename from test/integration/consul-container/metrics/leader_test.go rename to test/integration/consul-container/test/metrics/leader_test.go index 96a9e8d99c00..964b1bd7b76f 100644 --- a/test/integration/consul-container/metrics/leader_test.go +++ b/test/integration/consul-container/test/metrics/leader_test.go @@ -12,55 +12,40 @@ import ( "github.com/stretchr/testify/require" + "github.com/hashicorp/consul/test/integration/consul-container/libs/agent" + libagent "github.com/hashicorp/consul/test/integration/consul-container/libs/agent" libcluster "github.com/hashicorp/consul/test/integration/consul-container/libs/cluster" - "github.com/hashicorp/consul/test/integration/consul-container/libs/node" "github.com/hashicorp/consul/test/integration/consul-container/libs/utils" ) // Given a 3-server cluster, when the leader is elected, then leader's isLeader is 1 and non-leader's 0 func TestLeadershipMetrics(t *testing.T) { - var configs []node.Config - configs = append(configs, - node.Config{ - HCL: `node_name="` + utils.RandName("consul-server") + `" - log_level="DEBUG" - server=true - telemetry { - statsite_address = "127.0.0.1:2180" - }`, - Cmd: []string{"agent", "-client=0.0.0.0"}, - Version: *utils.TargetVersion, - Image: *utils.TargetImage, - }) + var configs []agent.Config + statsConf, err := libagent.NewConfigBuilder(nil).Telemetry("127.0.0.0:2180").ToAgentConfig() + require.NoError(t, err) + configs = append(configs, *statsConf) + + conf, err := libagent.NewConfigBuilder(nil).Bootstrap(3).ToAgentConfig() + require.NoError(t, err) numServer := 3 for i := 1; i < numServer; i++ { - configs = append(configs, - node.Config{ - HCL: `node_name="` + utils.RandName("consul-server") + `" - log_level="DEBUG" - bootstrap_expect=3 - server=true`, - Cmd: []string{"agent", "-client=0.0.0.0"}, - Version: *utils.TargetVersion, - Image: *utils.TargetImage, - }) - + configs = append(configs, *conf) } cluster, err := libcluster.New(configs) require.NoError(t, err) defer terminate(t, cluster) - svrCli := cluster.Nodes[0].GetClient() + svrCli := cluster.Agents[0].GetClient() libcluster.WaitForLeader(t, cluster, svrCli) libcluster.WaitForMembers(t, svrCli, 3) - retryWithBackoff := func(agentNode node.Node, expectedStr string) error { + retryWithBackoff := func(agent agent.Agent, expectedStr string) error { waiter := &utils.Waiter{ MaxWait: 5 * time.Minute, } - _, port := agentNode.GetAddr() + _, port := agent.GetAddr() ctx := context.Background() for { if waiter.Failures() > 5 { @@ -78,14 +63,14 @@ func TestLeadershipMetrics(t *testing.T) { } } - leaderNode, err := cluster.Leader() + leader, err := cluster.Leader() require.NoError(t, err) - leadAddr, leaderPort := leaderNode.GetAddr() + leadAddr, leaderPort := leader.GetAddr() - for i, n := range cluster.Nodes { + for i, n := range cluster.Agents { addr, port := n.GetAddr() if addr == leadAddr && port == leaderPort { - err = retryWithBackoff(leaderNode, ".server.isLeader\",\"Value\":1,") + err = retryWithBackoff(leader, ".server.isLeader\",\"Value\":1,") require.NoError(t, err, "%dth node(leader): could not find the metric %q in the /v1/agent/metrics response", i, ".server.isLeader\",\"Value\":1,") } else { err = retryWithBackoff(n, ".server.isLeader\",\"Value\":0,") diff --git a/test/integration/consul-container/test/peering/rotate_server_and_ca_then_fail_test.go b/test/integration/consul-container/test/peering/rotate_server_and_ca_then_fail_test.go new file mode 100644 index 000000000000..6c36efb07bdf --- /dev/null +++ b/test/integration/consul-container/test/peering/rotate_server_and_ca_then_fail_test.go @@ -0,0 +1,387 @@ +package peering + +import ( + "context" + "encoding/pem" + "fmt" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/sdk/testutil/retry" + libagent "github.com/hashicorp/consul/test/integration/consul-container/libs/agent" + libassert "github.com/hashicorp/consul/test/integration/consul-container/libs/assert" + libcluster "github.com/hashicorp/consul/test/integration/consul-container/libs/cluster" + libservice "github.com/hashicorp/consul/test/integration/consul-container/libs/service" + "github.com/hashicorp/consul/test/integration/consul-container/libs/utils" +) + +const ( + acceptingPeerName = "accepting-to-dialer" + dialingPeerName = "dialing-to-acceptor" +) + +// TestPeering_RotateServerAndCAThenFail_ +// This test runs a few scenarios back to back +// 1. It makes sure that the peering stream send server address updates between peers. +// It also verifies that dialing clusters will use this stored information to supersede the addresses +// encoded in the peering token. +// 2. Rotate the CA in the exporting cluster and ensure services don't break +// 3. Terminate the server nodes in the exporting cluster and make sure the importing cluster can still dial it's +// upstream. +// +// ## Steps +// ### Part 1 +// - Create an accepting cluster with 3 servers. 1 client should be used to host a service for export +// - Create a single agent dialing cluster. +// - Create the peering and export the service. Verify it is working +// - Incrementally replace the follower nodes. +// - Replace the leader agent +// - Verify the dialer can reach the new server nodes and the service becomes available. +// +// ### Part 2 +// - Push an update to the CA Configuration in the exporting cluster and wait for the new root to be generated +// - Verify envoy client sidecar has two certificates for the upstream server +// - Make sure there is still service connectivity from the importing cluster +// +// ### Part 3 +// - Terminate the server nodes in the exporting cluster +// - Make sure there is still service connectivity from the importing cluster +func TestPeering_RotateServerAndCAThenFail_(t *testing.T) { + var acceptingCluster, dialingCluster *libcluster.Cluster + var acceptingClient, dialingClient *api.Client + var acceptingCtx *libagent.BuildContext + var clientSidecarService libservice.Service + + var wg sync.WaitGroup + + wg.Add(1) + go func() { + acceptingCluster, acceptingClient, acceptingCtx = creatingAcceptingClusterAndSetup(t) + wg.Done() + }() + defer func() { + terminate(t, acceptingCluster) + }() + + wg.Add(1) + go func() { + dialingCluster, dialingClient, clientSidecarService = createDialingClusterAndSetup(t) + wg.Done() + }() + defer func() { + terminate(t, dialingCluster) + }() + + wg.Wait() + + generateReq := api.PeeringGenerateTokenRequest{ + PeerName: acceptingPeerName, + } + generateRes, _, err := acceptingClient.Peerings().GenerateToken(context.Background(), generateReq, &api.WriteOptions{}) + require.NoError(t, err) + + establishReq := api.PeeringEstablishRequest{ + PeerName: dialingPeerName, + PeeringToken: generateRes.PeeringToken, + } + _, _, err = dialingClient.Peerings().Establish(context.Background(), establishReq, &api.WriteOptions{}) + require.NoError(t, err) + + libassert.PeeringStatus(t, acceptingClient, acceptingPeerName, api.PeeringStateActive) + libassert.PeeringExports(t, acceptingClient, acceptingPeerName, 1) + + _, port := clientSidecarService.GetAddr() + libassert.HTTPServiceEchoes(t, "localhost", port) + + t.Run("test rotating servers", func(t *testing.T) { + + // Start by replacing the Followers + leader, err := acceptingCluster.Leader() + require.NoError(t, err) + + followers, err := acceptingCluster.Followers() + require.NoError(t, err) + require.Len(t, followers, 2) + + for idx, follower := range followers { + t.Log("Removing follower", idx) + rotateServer(t, acceptingCluster, acceptingClient, acceptingCtx, follower) + } + + t.Log("Removing leader") + rotateServer(t, acceptingCluster, acceptingClient, acceptingCtx, leader) + + libassert.PeeringStatus(t, acceptingClient, acceptingPeerName, api.PeeringStateActive) + libassert.PeeringExports(t, acceptingClient, acceptingPeerName, 1) + + libassert.HTTPServiceEchoes(t, "localhost", port) + }) + + t.Run("rotate exporting cluster's root CA", func(t *testing.T) { + // we will verify that the peering on the dialing side persists the updates CAs + peeringBefore, peerMeta, err := dialingClient.Peerings().Read(context.Background(), dialingPeerName, &api.QueryOptions{}) + require.NoError(t, err) + + _, caMeta, err := acceptingClient.Connect().CAGetConfig(&api.QueryOptions{}) + require.NoError(t, err) + + // There should be one root cert + rootList, _, err := acceptingClient.Connect().CARoots(&api.QueryOptions{}) + require.NoError(t, err) + require.Len(t, rootList.Roots, 1) + + req := &api.CAConfig{ + Provider: "consul", + Config: map[string]interface{}{ + "PrivateKeyType": "ec", + "PrivateKeyBits": 384, + }, + } + _, err = acceptingClient.Connect().CASetConfig(req, &api.WriteOptions{}) + require.NoError(t, err) + + // wait up to 30 seconds for the update + _, _, err = acceptingClient.Connect().CAGetConfig(&api.QueryOptions{ + WaitIndex: caMeta.LastIndex, + WaitTime: 30 * time.Second, + }) + require.NoError(t, err) + + // The peering object should reflect the update + peeringAfter, _, err := dialingClient.Peerings().Read(context.Background(), dialingPeerName, &api.QueryOptions{ + WaitIndex: peerMeta.LastIndex, + WaitTime: 30 * time.Second, + }) + require.NotEqual(t, peeringBefore.PeerCAPems, peeringAfter.PeerCAPems) + require.Len(t, peeringAfter.PeerCAPems, 2) + require.NoError(t, err) + + // There should be two root certs now on the accepting side + rootList, _, err = acceptingClient.Connect().CARoots(&api.QueryOptions{}) + require.NoError(t, err) + require.Len(t, rootList.Roots, 2) + + // Connectivity should still be contained + _, port := clientSidecarService.GetAddr() + libassert.HTTPServiceEchoes(t, "localhost", port) + + verifySidecarHasTwoRootCAs(t, clientSidecarService) + }) + + t.Run("terminate exporting clusters servers and ensure imported services are still reachable", func(t *testing.T) { + // Keep this list for later + newNodes, err := acceptingCluster.Clients() + require.NoError(t, err) + + serverNodes, err := acceptingCluster.Servers() + require.NoError(t, err) + for _, node := range serverNodes { + require.NoError(t, node.Terminate()) + } + + // Remove the nodes from the cluster to prevent double-termination + acceptingCluster.Agents = newNodes + + // ensure any transitory actions like replication cleanup would not affect the next verifications + time.Sleep(30 * time.Second) + + _, port := clientSidecarService.GetAddr() + libassert.HTTPServiceEchoes(t, "localhost", port) + }) +} + +func terminate(t *testing.T, cluster *libcluster.Cluster) { + err := cluster.Terminate() + require.NoError(t, err) +} + +// creatingAcceptingClusterAndSetup creates a cluster with 3 servers and 1 client. +// It also creates and registers a service+sidecar. +// The API client returned is pointed at the client agent. +func creatingAcceptingClusterAndSetup(t *testing.T) (*libcluster.Cluster, *api.Client, *libagent.BuildContext) { + var configs []libagent.Config + + opts := libagent.BuildOptions{ + InjectAutoEncryption: true, + InjectGossipEncryption: true, + } + ctx, err := libagent.NewBuildContext(opts) + require.NoError(t, err) + + numServer := 3 + for i := 0; i < numServer; i++ { + serverConf, err := libagent.NewConfigBuilder(ctx). + Bootstrap(3). + Peering(true). + RetryJoin(fmt.Sprintf("agent-%d", (i+1)%3)). // Round-robin join the servers + ToAgentConfig() + require.NoError(t, err) + t.Logf("dc1 server config %d: \n%s", i, serverConf.JSON) + + configs = append(configs, *serverConf) + } + + // Add a stable client to register the service + clientConf, err := libagent.NewConfigBuilder(ctx). + Client(). + Peering(true). + RetryJoin("agent-0", "agent-1", "agent-2"). + ToAgentConfig() + require.NoError(t, err) + + t.Logf("dc1 client config: \n%s", clientConf.JSON) + + configs = append(configs, *clientConf) + + cluster, err := libcluster.New(configs) + require.NoError(t, err) + + // Use the client agent as the HTTP endpoint since we will not rotate it + clientNode := cluster.Agents[3] + client := clientNode.GetClient() + libcluster.WaitForLeader(t, cluster, client) + libcluster.WaitForMembers(t, client, 4) + + // Default Proxy Settings + ok, err := utils.ApplyDefaultProxySettings(client) + require.NoError(t, err) + require.True(t, ok) + + // Create the mesh gateway for dataplane traffic + _, err = libservice.NewGatewayService(context.Background(), "mesh", "mesh", clientNode) + require.NoError(t, err) + + // Create a service and proxy instance + _, _, err = libservice.CreateAndRegisterStaticServerAndSidecar(clientNode) + require.NoError(t, err) + + libassert.CatalogServiceExists(t, client, "static-server") + libassert.CatalogServiceExists(t, client, "static-server-sidecar-proxy") + + // Export the service + config := &api.ExportedServicesConfigEntry{ + Name: "default", + Services: []api.ExportedService{ + { + Name: "static-server", + Consumers: []api.ServiceConsumer{ + {Peer: acceptingPeerName}, + }, + }, + }, + } + ok, _, err = client.ConfigEntries().Set(config, &api.WriteOptions{}) + require.NoError(t, err) + require.True(t, ok) + + return cluster, client, ctx +} + +// createDialingClusterAndSetup creates a cluster for peering with a single dev agent +func createDialingClusterAndSetup(t *testing.T) (*libcluster.Cluster, *api.Client, libservice.Service) { + opts := libagent.BuildOptions{ + Datacenter: "dc2", + InjectAutoEncryption: true, + InjectGossipEncryption: true, + } + ctx, err := libagent.NewBuildContext(opts) + require.NoError(t, err) + + conf, err := libagent.NewConfigBuilder(ctx). + Peering(true). + ToAgentConfig() + require.NoError(t, err) + t.Logf("dc2 server config: \n%s", conf.JSON) + + configs := []libagent.Config{*conf} + + cluster, err := libcluster.New(configs) + require.NoError(t, err) + + node := cluster.Agents[0] + client := node.GetClient() + libcluster.WaitForLeader(t, cluster, client) + libcluster.WaitForMembers(t, client, 1) + + // Default Proxy Settings + ok, err := utils.ApplyDefaultProxySettings(client) + require.NoError(t, err) + require.True(t, ok) + + // Create the mesh gateway for dataplane traffic + _, err = libservice.NewGatewayService(context.Background(), "mesh", "mesh", node) + require.NoError(t, err) + + // Create a service and proxy instance + clientProxyService, err := libservice.CreateAndRegisterStaticClientSidecar(node, dialingPeerName, true) + require.NoError(t, err) + + libassert.CatalogServiceExists(t, client, "static-client-sidecar-proxy") + + return cluster, client, clientProxyService +} + +// rotateServer add a new server agent to the cluster, then forces the prior agent to leave. +func rotateServer(t *testing.T, cluster *libcluster.Cluster, client *api.Client, ctx *libagent.BuildContext, node libagent.Agent) { + conf, err := libagent.NewConfigBuilder(ctx). + Bootstrap(0). + Peering(true). + RetryJoin("agent-3"). // Always use the client agent since it never leaves the cluster + ToAgentConfig() + require.NoError(t, err) + + err = cluster.Add([]libagent.Config{*conf}) + require.NoError(t, err, "could not start new node") + + libcluster.WaitForMembers(t, client, 5) + + require.NoError(t, cluster.Remove(node)) + + libcluster.WaitForMembers(t, client, 4) +} + +func verifySidecarHasTwoRootCAs(t *testing.T, sidecar libservice.Service) { + connectContainer, ok := sidecar.(*libservice.ConnectContainer) + require.True(t, ok) + _, adminPort := connectContainer.GetAdminAddr() + + failer := func() *retry.Timer { + return &retry.Timer{Timeout: 30 * time.Second, Wait: 1 * time.Second} + } + + retry.RunWith(failer(), t, func(r *retry.R) { + dump, err := libservice.GetEnvoyConfigDump(adminPort) + if err != nil { + r.Fatal("could not curl envoy configuration") + } + + // Make sure there are two certs in the sidecar + filter := `.configs[] | select(.["@type"] | contains("type.googleapis.com/envoy.admin.v3.ClustersConfigDump")).dynamic_active_clusters[] | select(.cluster.name | contains("static-server.default.dialing-to-acceptor.external")).cluster.transport_socket.typed_config.common_tls_context.validation_context.trusted_ca.inline_string` + results, err := utils.JQFilter(dump, filter) + if err != nil { + r.Fatal("could not parse envoy configuration") + } + if len(results) != 1 { + r.Fatal("could not find certificates in cluster TLS context") + } + + rest := []byte(results[0]) + var count int + for len(rest) > 0 { + var p *pem.Block + p, rest = pem.Decode(rest) + if p == nil { + break + } + count++ + } + + if count != 2 { + r.Fatalf("expected 2 TLS certificates and %d present", count) + } + }) +} diff --git a/test/integration/consul-container/upgrade/README.md b/test/integration/consul-container/test/upgrade/README.md similarity index 98% rename from test/integration/consul-container/upgrade/README.md rename to test/integration/consul-container/test/upgrade/README.md index f552ca1db217..2f1ba11de2e6 100644 --- a/test/integration/consul-container/upgrade/README.md +++ b/test/integration/consul-container/test/upgrade/README.md @@ -5,4 +5,4 @@ To specify targets and latest image pass `target-version` and `latest-version` to the tests. By default, it uses the `consul` docker image with respectively `local` and `latest` tags. -To use dev consul image, pass `target-image` and `target-version`, `-target-image hashicorppreview/consul -target-version 1.14-dev`. \ No newline at end of file +To use dev consul image, pass `target-image` and `target-version`, `-target-image hashicorppreview/consul -target-version 1.14-dev`. diff --git a/test/integration/consul-container/upgrade/healthcheck_test.go b/test/integration/consul-container/test/upgrade/healthcheck_test.go similarity index 65% rename from test/integration/consul-container/upgrade/healthcheck_test.go rename to test/integration/consul-container/test/upgrade/healthcheck_test.go index e3d298c17bbd..e2f793c36189 100644 --- a/test/integration/consul-container/upgrade/healthcheck_test.go +++ b/test/integration/consul-container/test/upgrade/healthcheck_test.go @@ -10,8 +10,8 @@ import ( "github.com/hashicorp/consul/api" + libagent "github.com/hashicorp/consul/test/integration/consul-container/libs/agent" libcluster "github.com/hashicorp/consul/test/integration/consul-container/libs/cluster" - "github.com/hashicorp/consul/test/integration/consul-container/libs/node" "github.com/hashicorp/consul/test/integration/consul-container/libs/utils" ) @@ -22,14 +22,14 @@ func TestTargetServersWithLatestGAClients(t *testing.T) { numClients = 1 ) - cluster := serversCluster(t, numServers, *utils.TargetVersion, *utils.TargetImage) + cluster := serversCluster(t, numServers, utils.TargetImage, utils.TargetVersion) defer terminate(t, cluster) - clients := clientsCreate(t, numClients, *utils.LatestImage, *utils.LatestVersion, cluster.EncryptKey) + clients := clientsCreate(t, numClients, utils.LatestImage, utils.LatestVersion, cluster) - require.NoError(t, cluster.AddNodes(clients)) + require.NoError(t, cluster.Join(clients)) - client := cluster.Nodes[0].GetClient() + client := cluster.Agents[0].GetClient() libcluster.WaitForLeader(t, cluster, client) libcluster.WaitForMembers(t, client, 4) @@ -71,29 +71,32 @@ func TestTargetServersWithLatestGAClients(t *testing.T) { // Test health check GRPC call using Mixed (majority latest) Servers and Latest GA Clients func TestMixedServersMajorityLatestGAClient(t *testing.T) { - var configs []node.Config - configs = append(configs, - node.Config{ - HCL: `node_name="` + utils.RandName("consul-server") + `" - log_level="DEBUG" - server=true`, - Cmd: []string{"agent", "-client=0.0.0.0"}, - Version: *utils.TargetVersion, - Image: *utils.TargetImage, - }) + var configs []libagent.Config + + leaderConf, err := libagent.NewConfigBuilder(nil).ToAgentConfig() + require.NoError(t, err) + + configs = append(configs, *leaderConf) + + // This needs a specialized config since it is using an older version of the agent. + // That is missing fields like GRPC_TLS and PEERING, which are passed as defaults + serverConf := `{ + "advertise_addr": "{{ GetInterfaceIP \"eth0\" }}", + "bind_addr": "0.0.0.0", + "client_addr": "0.0.0.0", + "log_level": "DEBUG", + "server": true, + "bootstrap_expect": 3 + }` for i := 1; i < 3; i++ { configs = append(configs, - node.Config{ - HCL: `node_name="` + utils.RandName("consul-server") + `" - log_level="DEBUG" - bootstrap_expect=3 - server=true`, - Cmd: []string{"agent", "-client=0.0.0.0"}, - Version: *utils.LatestVersion, - Image: *utils.LatestImage, + libagent.Config{ + JSON: serverConf, + Cmd: []string{"agent"}, + Version: utils.LatestVersion, + Image: utils.LatestImage, }) - } cluster, err := libcluster.New(configs) @@ -104,9 +107,9 @@ func TestMixedServersMajorityLatestGAClient(t *testing.T) { numClients = 1 ) - clients := clientsCreate(t, numClients, *utils.LatestImage, *utils.LatestVersion, cluster.EncryptKey) + clients := clientsCreate(t, numClients, utils.LatestImage, utils.LatestVersion, cluster) - require.NoError(t, cluster.AddNodes(clients)) + require.NoError(t, cluster.Join(clients)) client := clients[0].GetClient() @@ -149,28 +152,28 @@ func TestMixedServersMajorityLatestGAClient(t *testing.T) { // Test health check GRPC call using Mixed (majority target) Servers and Latest GA Clients func TestMixedServersMajorityTargetGAClient(t *testing.T) { - var configs []node.Config - for i := 0; i < 2; i++ { - configs = append(configs, - node.Config{ - HCL: `node_name="` + utils.RandName("consul-server") + `" - log_level="DEBUG" - bootstrap_expect=3 - server=true`, - Cmd: []string{"agent", "-client=0.0.0.0"}, - Version: *utils.TargetVersion, - Image: *utils.TargetImage, - }) + var configs []libagent.Config + for i := 0; i < 2; i++ { + serverConf, err := libagent.NewConfigBuilder(nil).Bootstrap(3).ToAgentConfig() + require.NoError(t, err) + configs = append(configs, *serverConf) } + + leaderConf := `{ + "advertise_addr": "{{ GetInterfaceIP \"eth0\" }}", + "bind_addr": "0.0.0.0", + "client_addr": "0.0.0.0", + "log_level": "DEBUG", + "server": true + }` + configs = append(configs, - node.Config{ - HCL: `node_name="` + utils.RandName("consul-server") + `" - log_level="DEBUG" - server=true`, - Cmd: []string{"agent", "-client=0.0.0.0"}, - Version: *utils.LatestVersion, - Image: *utils.LatestImage, + libagent.Config{ + JSON: leaderConf, + Cmd: []string{"agent"}, + Version: utils.LatestVersion, + Image: utils.LatestImage, }) cluster, err := libcluster.New(configs) @@ -181,9 +184,9 @@ func TestMixedServersMajorityTargetGAClient(t *testing.T) { numClients = 1 ) - clients := clientsCreate(t, numClients, *utils.LatestImage, *utils.LatestVersion, cluster.EncryptKey) + clients := clientsCreate(t, numClients, utils.LatestImage, utils.LatestVersion, cluster) - require.NoError(t, cluster.AddNodes(clients)) + require.NoError(t, cluster.Join(clients)) client := clients[0].GetClient() @@ -211,7 +214,7 @@ func TestMixedServersMajorityTargetGAClient(t *testing.T) { &api.AgentServiceRegistration{Name: serviceName, Port: 9998}, )) - timer := time.NewTimer(1 * time.Second) + timer := time.NewTimer(3 * time.Second) select { case err := <-errCh: require.NoError(t, err) @@ -224,20 +227,29 @@ func TestMixedServersMajorityTargetGAClient(t *testing.T) { } } -func clientsCreate(t *testing.T, numClients int, image string, version string, serfKey string) []node.Node { - clients := make([]node.Node, numClients) +func clientsCreate(t *testing.T, numClients int, image string, version string, cluster *libcluster.Cluster) []libagent.Agent { + clients := make([]libagent.Agent, numClients) + + // This needs a specialized config since it is using an older version of the agent. + // That is missing fields like GRPC_TLS and PEERING, which are passed as defaults + conf := `{ + "advertise_addr": "{{ GetInterfaceIP \"eth0\" }}", + "bind_addr": "0.0.0.0", + "client_addr": "0.0.0.0", + "log_level": "DEBUG" + }` + for i := 0; i < numClients; i++ { var err error - clients[i], err = node.NewConsulContainer(context.Background(), - node.Config{ - HCL: fmt.Sprintf(` - node_name = %q - log_level = "DEBUG" - encrypt = %q`, utils.RandName("consul-client"), serfKey), - Cmd: []string{"agent", "-client=0.0.0.0"}, + clients[i], err = libagent.NewConsulContainer(context.Background(), + libagent.Config{ + JSON: conf, + Cmd: []string{"agent"}, Version: version, Image: image, - }) + }, + cluster.NetworkName, + cluster.Index) require.NoError(t, err) } return clients @@ -256,24 +268,24 @@ func serviceCreate(t *testing.T, client *api.Client, serviceName string) uint64 return meta.LastIndex } -func serversCluster(t *testing.T, numServers int, version string, image string) *libcluster.Cluster { - var configs []node.Config +func serversCluster(t *testing.T, numServers int, image string, version string) *libcluster.Cluster { + var configs []libagent.Config + + conf, err := libagent.NewConfigBuilder(nil). + Bootstrap(3). + ToAgentConfig() + require.NoError(t, err) + conf.Image = image + conf.Version = version + for i := 0; i < numServers; i++ { - configs = append(configs, node.Config{ - HCL: `node_name="` + utils.RandName("consul-server") + `" - log_level="DEBUG" - bootstrap_expect=3 - server=true`, - Cmd: []string{"agent", "-client=0.0.0.0"}, - Version: version, - Image: image, - }) + configs = append(configs, *conf) } cluster, err := libcluster.New(configs) require.NoError(t, err) libcluster.WaitForLeader(t, cluster, nil) - libcluster.WaitForMembers(t, cluster.Nodes[0].GetClient(), numServers) + libcluster.WaitForMembers(t, cluster.Agents[0].GetClient(), numServers) return cluster } diff --git a/test/key/ourdomain.cer b/test/key/ourdomain.cer index bae6090851b2..3d48f12e74f3 100644 --- a/test/key/ourdomain.cer +++ b/test/key/ourdomain.cer @@ -1,26 +1,26 @@ -----BEGIN CERTIFICATE----- -MIIETTCCAzWgAwIBAgIBETANBgkqhkiG9w0BAQ0FADCBmDELMAkGA1UEBhMCVVMx +MIIETTCCAzWgAwIBAgIBEjANBgkqhkiG9w0BAQ0FADCBmDELMAkGA1UEBhMCVVMx CzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRwwGgYDVQQKExNI YXNoaUNvcnAgVGVzdCBDZXJ0MQwwCgYDVQQLEwNEZXYxFjAUBgNVBAMTDXRlc3Qu aW50ZXJuYWwxIDAeBgkqhkiG9w0BCQEWEXRlc3RAaW50ZXJuYWwuY29tMCAXDTIy -MDQxNTE0MjUzOFoYDzIxMjIwMzIyMTQyNTM4WjCBjTEYMBYGA1UEAwwPdGVzdGNv +MTEwMTE1MTMyOVoYDzIxMjIxMDA4MTUxMzI5WjCBjTEYMBYGA1UEAwwPdGVzdGNv LmludGVybmFsMRMwEQYDVQQIDApDYWxpZm9ybmlhMQswCQYDVQQGEwJVUzEpMCcG CSqGSIb3DQEJARYaZG8tbm90LXJlcGx5QGhhc2hpY29ycC5jb20xEjAQBgNVBAoM CUVuZCBQb2ludDEQMA4GA1UECwwHVGVzdGluZzCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAK6g0P0eGgLw2B63xyXjRhy5WnbYegJoQJtpnJ0NvgJyZfCz -G6vIw/xjtriyW2rcw9qoEQ7aerN93UdUQaECe3J4QalobFbw9VCGIPJEblBBBKAk -Y8Ek3Ldv6WWO0hWhho11JgjhpGfpFJtDKKs9vZ/tDwiU549ra5tTppMvyZIce+nW -SVkQAlq7zFUshgBu0k1tliU9bOUwZlRnT5xnDTHhKAqyBNGX5pVxhLXv+FM9UMHw -UbCbbucWb3oF1wbARTtLnDsmI0V9PPsUVAbc+sZ4ZQKcNmq92zKq3MjB93Kitfx+ -IdSGCJ+bP8mTQCTDrqDVVCsCaeOZ4Ufa+9kRvcsCAwEAAaOBqDCBpTAJBgNVHRME -AjAAMB0GA1UdDgQWBBTCmo+KBFV1kXzUsiC7xtwK8I9udjAfBgNVHSMEGDAWgBSj +ggEPADCCAQoCggEBANmKHQFznmOmtmvLSA2/f5xjUmJrscZkYa7ooy5bqkFxBKSa +cZn+rru0PjuUIElw2r6iOgVSTmWvBd78ej5qS9+xqfOpWUOBOnl2G6uit676Hlzb +/B/obEek8rmbTYHPT/Lz39oFbmJLc36Wdqp7hq/FMMJd7jEr3r5TIny1eHi1A8Iv +aTa/2vHpW79YMMkGifTO4NsdXgNXuomgnZgUWesDfDQ4zlQZeMrGT5JO6VcNICuR +MNCklBqWYONjdG62AePEu8hCePok3qec9ibhCWotqFpEPe+Myu0gCAxhKUVa6GNd +4iBle1eHbsOsYJcq7aLvujGyixd1EqigqizIvX8CAwEAAaOBqDCBpTAJBgNVHRME +AjAAMB0GA1UdDgQWBBRNjhD63/a2jm+hawLfWZXrJIBFTDAfBgNVHSMEGDAWgBSj +es5+q9t57ZWSVUogWXJARu4lTALBgNVHQ8EBAMCBaAwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMCwGA1UdHwQlMCMwIaAfoB2GG2h0dHA6Ly9wYXRoLnRv -LmNybC9teWNhLmNybDANBgkqhkiG9w0BAQ0FAAOCAQEAr/evKySRc48PNzFovBbx -vWtHgIunJ9JOE8vJyomiuup99AaLvUkRvDIdQjLRac/0rgCD3NXjqQIb5QZPmuVy -w4obNwQaqfJdLys+pQUo1Ly0nPTs5ValIyICDAUf066lcMKNIh6oSn9y9kp/DqBP -feucrJLpwVKHsuUddDCbDPUNwgSbOC6mGvDfA2Q5bd9DMDuBWeRrU7qnfyNCVbem -V2mljJl5TOEc/Yn2vES7rFv987QXOhZGw1Eerhxazi+gwJvxiC1oE5urNk9k1UL/ -byayC5BQiDSee9oyE0YDvKRD9lcvQuk7hVLBv2rY1rqNsPaJKncrnXTtJBqMQHVA -cg== +LmNybC9teWNhLmNybDANBgkqhkiG9w0BAQ0FAAOCAQEAHQ5n79cM6G789AGKKjB9 +cbOld9SwzRUzb1MFrG3rs48ZaOp65mdm9zdI2Cmh9SkoT+lOK6+g1wAQ3p22p+2X +xY3BEFE9gpjdryvR0KFeGkS1fpvIrFAp/cDa67elQR1fX/ADvxSj8GA7gibpS3Ov +DfuUek8GP7HJEdwM+/0Q6g5qKZcZVb6UU/4WySGkuScukmIxbJTrdtctusthHBp9 ++WJtCHKGnziA0VlWTDCkfX04Mpyixzno4jk1QPdEiOB8PHonvJF7RUsLbuDVv5p2 +SXw4zUgFoTPQ5FuUVN0GInObUJ1IKZ3V4VuAIoTw5kZ165PjLiRRwQuFjLrCmVQR +AQ== -----END CERTIFICATE----- diff --git a/test/key/ourdomain.key b/test/key/ourdomain.key index 7a02cadd0649..0550aac70d80 100644 --- a/test/key/ourdomain.key +++ b/test/key/ourdomain.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCuoND9HhoC8Nge -t8cl40YcuVp22HoCaECbaZydDb4CcmXwsxuryMP8Y7a4sltq3MPaqBEO2nqzfd1H -VEGhAntyeEGpaGxW8PVQhiDyRG5QQQSgJGPBJNy3b+lljtIVoYaNdSYI4aRn6RSb -QyirPb2f7Q8IlOePa2ubU6aTL8mSHHvp1klZEAJau8xVLIYAbtJNbZYlPWzlMGZU -Z0+cZw0x4SgKsgTRl+aVcYS17/hTPVDB8FGwm27nFm96BdcGwEU7S5w7JiNFfTz7 -FFQG3PrGeGUCnDZqvdsyqtzIwfdyorX8fiHUhgifmz/Jk0Akw66g1VQrAmnjmeFH -2vvZEb3LAgMBAAECggEBAIVRvXwhKRaprTX2dJIWa4auc8RcDPodgYWlIa49uZzA -ndcfxrZltkrQDcYAVQ7GsLgUq8E9R4QVSYSVbO1xqbGA4hBl6qCNoZvyauDLIbUf -jlp8rbPdYqyhQf0JBpcBFGqWz4zkR9IU/mhy42+o2UZpg5q3o/m4txSEzp18VFW5 -KiuArjFmnfrIMvIcL/CEYUCbr1hhPoySOikQZbAObNXgOKurGXR52TgUztMwt32A -oJUAmtLu+ti4Q/ffKhaV0pfRhB0Byqsbm/ONDVTdKUwKDiMrBV8CqRquXunHWJ7D -sqBi8EnM6Ke08ZLqobqQWKmjVMT41rQYAk/1FqEGWJECgYEA3UfggUMX6nysXzVs -MZ7RNbjoSwISa/4I2QGSf3moW7N7G2NTcHPjOM2qhZ2IqR5QTQ8Q9zpPpeOtWquj -3+G45fGCT8aB1A6Pt1d/oTU1g5s7cHn0DzDNB4+5iWwPE+x5XdaZU1kzm6hTS6H6 -Roby7/Hm1PUw+0SXyKSQ9vw4HTcCgYEAygcO5SB0LqjTumRjhAM0OQSRU+rADaJA -X6g5IkjFMm20AH9cA/rg7ZVw3D3ZPZg0yd+qqhE5rIFvVyLUhkaFobZ17i+pUKcf -GH9m5BIuYyg7n78uy/0F9RTZbv2U0nHObUdg5jK4/9PQvhLihEIBEbl7X4RWlgtU -3oZKsP36zg0CgYABUDzn54ML1EOdqQ6EWOH7BKb0UwXS+EYLK7Q353v1V2Jirjs/ -jqCJpMbfVikKf/CQFIfQP9tbK7fKsvwdBxT24HEakh4RKSj3OKC8TzmLF2/J4h9t -u6dr5RF/3FFWl++8e9qbIQtqYBxmdYarxn9Ip1Hsb6wjwat4+GkX3jVjDwKBgQDH -CMkd5ylPRrjBa2G3j0iF3AApQp9PT0hIdX1ET5kno3iw/Mh0i1fJ+W6lLLG3wxpO -wHJs9mdxkltU51WlrBi/RvlMXdxbPyqdgfamP1tACUUkjr/V7ENQPugwNtfFtKWA -d8/5OoOUVuPSPty3HCfdhHUNl12OmT9Vs8wmLzJGiQKBgQDDC8MU/Llbg/Lhl76j -VuOrOci4p6fc5ICagFYBUyms0wsyP7RWseCgFQtthDPuBCArewY4j7AqmRgkDrqa -gOCrJeptdKT2oCkn6AlxBc9kP2Y0N5vLEkwkkrQAbP/3iG/d4raOSTKMOT8voXpv -f4HT3Zolz4FPrtFKVOi0VA3Z5A== +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDZih0Bc55jprZr +y0gNv3+cY1Jia7HGZGGu6KMuW6pBcQSkmnGZ/q67tD47lCBJcNq+ojoFUk5lrwXe +/Ho+akvfsanzqVlDgTp5dhuroreu+h5c2/wf6GxHpPK5m02Bz0/y89/aBW5iS3N+ +lnaqe4avxTDCXe4xK96+UyJ8tXh4tQPCL2k2v9rx6Vu/WDDJBon0zuDbHV4DV7qJ +oJ2YFFnrA3w0OM5UGXjKxk+STulXDSArkTDQpJQalmDjY3RutgHjxLvIQnj6JN6n +nPYm4QlqLahaRD3vjMrtIAgMYSlFWuhjXeIgZXtXh27DrGCXKu2i77oxsosXdRKo +oKosyL1/AgMBAAECggEAI6qSUN+c82es9wVwPdjM2l4qbrqLfiSNI3k+7+XVhz85 +bKdpwr7P9TR7E5eYp5HaO3ErpB23ftJwWvv4Ku2QnQ9q9ukoGnpAlRN5O+3Ewep+ +OelTcAPSZPi1VxsQXR0ZVZMIe51yWKlYOUQAFrmD/qOM+AEggW1Y6smEmP/Dzb5K +cILo3+lEMXxc5ffZ8foS4l5ub3mdYvpjW30s+jzAzfPo2gj0CeMAYKQo+ndTlp6C +3sXPvpgjomq29EBijHCIehiYVj2D1sk0tkfqSzaFcypWfGC8oKTGpUb20aOrcMY2 +hBFGlU0yLntIerja9LhYlFrysa8NPByY1kPLtk6gGQKBgQD4Xnc7FINyn5xR6gN8 +2YjZXlCi4F2oBBsuH0Tkm5GYD6rqLiaEnk5KTEZVHqOgAKQVnGBeEzbx43z/+/EI +rEXEImjc8nGS/KiBkDiUBPA4QeEIFuUrKmz1cC1ryaTRLn3DQJL0uMuXuwn8Ufn8 +CvU1bVkqbkp6IxbGS/SBrNLxawKBgQDgOSjdCZ8QgiDbjqXgd/XXvuSTRnzKKaaD +pple5OH8I84CN5WiMztFqRwvL3+XDlxtF8mHg8AoetlmQ/muMBpm0I66AXF0E1UQ +dV3v10DswRgl1UVFSznR9fDGCRFHSDa4ZErsfE9yvGeNgl3MOHUok0eIYuW4rc13 +lXrpk1JlPQKBgQDAPDWit8Tp4hoW2L6sUp72R2a4OlqjIdJ7x14GZ1awUGgka2YK +vZCxNwo09csFm5lk1K1OAydC36WvaCxuXxB8t3lckhZQA1jVN3BjONNJZ8wp+7aS +y3qcGaA+TktQUOCsUH2uBp4mKXGYJ0cKytxx5tnd2pGwqRoGj2GHQOHgUwKBgQCP +X71jaW2Orsa33cTvfYVzyRp7mczdsDhLYlIbvZtLENH/1O8XYk76QiJFgcfCHWq4 +T0eMIZDT0YoFvF2BJj0blSxOf/G92UbBWWsRm8BmIyp/tpmur2VvfiXRW6byv5hN +28OU6AAdS5+jesLjfQ5dPZ+19BcUOf5yAuEvTgaXuQKBgQDM47vsNeStbvNvuW2w +LYCavmz1ci/H1LDStRwMn3kFVT6S30BQZW5WCa9JH1VJPLCZyAsXqMiMqVwbRkrP +ThY6k+OynaDaEKFURHFZ9TH7QnvAwq0fHRy7nVVUoh5A3I8hqx/lPTyBzJdfEZ/2 +yqxT1bclUFf59IlXukMf/pXxCw== -----END PRIVATE KEY----- diff --git a/test/load/README.md b/test/load/README.md index f0b7f648b96e..23fd927a861b 100644 --- a/test/load/README.md +++ b/test/load/README.md @@ -4,9 +4,6 @@ Consul Load Testing is used to capture baseline performance metrics for Consul u This relies on the [Gruntwork's Terraform AWS Consul Module](https://github.com/hashicorp/terraform-aws-consul) which *by default* creates 3 Consul servers across 3 availability zones. A load test instance which has an image that is configured with the necessary scripts and [k6](https://k6.io/) is created and sends traffic to a load balancer. The load balancer will distribute requests across the Consul clients who will ultimately forward the requests to the servers. - -# Load Test Automation -This can only be run on PRs that a Dev Build has been made for. When a PR has the `pr/load-test` Github Label applied this will kick off a Github Action. This Github Action will trigger Circle CI to run a Terraform Apply that runs a load test against the Dev Build Consul binary. The GitHub Action will paste the CircleCI load test workflow URL to the PR as a comment. ## How to use [Terraform](https://www.terraform.io/downloads.html) and [Packer](https://www.packer.io/downloads), AWS and [Datadog](https://docs.datadoghq.com/getting_started/) are required to use this. All of this, except the AWS resources that will be utilized, are free. diff --git a/tlsutil/config.go b/tlsutil/config.go index b6d54b30bf9b..027db6617a8c 100644 --- a/tlsutil/config.go +++ b/tlsutil/config.go @@ -770,8 +770,16 @@ func (c *Configurator) IncomingGRPCConfig() *tls.Config { c.base.GRPC, c.base.GRPC.VerifyIncoming, ) - config.GetConfigForClient = func(*tls.ClientHelloInfo) (*tls.Config, error) { - return c.IncomingGRPCConfig(), nil + config.GetConfigForClient = func(info *tls.ClientHelloInfo) (*tls.Config, error) { + conf := c.IncomingGRPCConfig() + // Do not enforce mutualTLS for peering SNI entries. This is necessary, because + // there is no way to specify an mTLS cert when establishing a peering connection. + // This bypass is only safe because the `grpc-middleware.AuthInterceptor` explicitly + // restricts the list of endpoints that can be called when peering SNI is present. + if c.autoTLS.peeringServerName != "" && info.ServerName == c.autoTLS.peeringServerName { + conf.ClientAuth = tls.NoClientCert + } + return conf, nil } config.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { if c.autoTLS.peeringServerName != "" && info.ServerName == c.autoTLS.peeringServerName { @@ -950,6 +958,12 @@ func (c *Configurator) AutoEncryptCert() *x509.Certificate { return cert } +func (c *Configurator) PeeringServerName() string { + c.lock.RLock() + defer c.lock.RUnlock() + return c.autoTLS.peeringServerName +} + func (c *Configurator) log(name string) { if c.logger != nil && c.logger.IsTrace() { c.logger.Trace(name, "version", atomic.LoadUint64(&c.version)) diff --git a/tlsutil/config_test.go b/tlsutil/config_test.go index cd3e07a08201..cc796acb461b 100644 --- a/tlsutil/config_test.go +++ b/tlsutil/config_test.go @@ -907,7 +907,7 @@ func TestConfigurator_outgoingWrapperALPN_serverHasNoNodeNameInSAN(t *testing.T) _, err = wrap("dc1", "bob", "foo", client) require.Error(t, err) - _, ok := err.(x509.HostnameError) + _, ok := err.(*tls.CertificateVerificationError) require.True(t, ok) client.Close() @@ -1481,7 +1481,7 @@ func TestConfigurator_AutoEncryptCert(t *testing.T) { cert, err = loadKeyPair("../test/key/ourdomain.cer", "../test/key/ourdomain.key") require.NoError(t, err) c.autoTLS.cert = cert - require.Equal(t, int64(4803632738), c.AutoEncryptCert().NotAfter.Unix()) + require.Equal(t, int64(4820915609), c.AutoEncryptCert().NotAfter.Unix()) } func TestConfigurator_AuthorizeInternalRPCServerConn(t *testing.T) { diff --git a/ui/README.md b/ui/README.md index dc3f8e64b656..850cff2ab45c 100644 --- a/ui/README.md +++ b/ui/README.md @@ -53,7 +53,7 @@ List of available project commands. `yarn run ` | Command | Description | |---------------------|------------------------------------| | doc:toc | Re-builds the ToC for this README. | -| compliance:licenses | Checks that all dependencies have OSS-compatible licenses. | +| compliance:licenses | Checks that all dependencies have CE-compatible licenses. | ## Contributing diff --git a/ui/packages/consul-peerings/app/components/consul/peer/address/list/index.hbs b/ui/packages/consul-peerings/app/components/consul/peer/address/list/index.hbs index c603c22f7607..727b0e7e7ddb 100644 --- a/ui/packages/consul-peerings/app/components/consul/peer/address/list/index.hbs +++ b/ui/packages/consul-peerings/app/components/consul/peer/address/list/index.hbs @@ -1,15 +1,25 @@ - - -

- {{item}} - -

-
-
+ + {{#if p.data.height}} +
+ +
  • +
    {{address}}
    + +
  • +
    +
    + {{/if}} +
    \ No newline at end of file diff --git a/ui/packages/consul-peerings/app/components/consul/peer/form/generate/fieldsets/index.hbs b/ui/packages/consul-peerings/app/components/consul/peer/form/generate/fieldsets/index.hbs index f6fd4fcbc0f4..e9ba548c939a 100644 --- a/ui/packages/consul-peerings/app/components/consul/peer/form/generate/fieldsets/index.hbs +++ b/ui/packages/consul-peerings/app/components/consul/peer/form/generate/fieldsets/index.hbs @@ -1,38 +1,54 @@ -
    +
    + @src={{require + "/machines/validate.xstate" + from="/components/consul/peer/form/generate/fieldsets" + }} + as |fsm| + > {{#let (hash help=(concat - (t 'common.validations.dns-hostname.help') - (t 'common.validations.immutable.help') + (t "common.validations.dns-hostname.help") + (t "common.validations.immutable.help") ) Name=(array (hash - test=(t 'common.validations.dns-hostname.test') - error=(t 'common.validations.dns-hostname.error' name="Name") + test=(t "common.validations.dns-hostname.test") + error=(t "common.validations.dns-hostname.error" name="Name") ) ) ) - as |Name|}} + as |Name| + }}
    - {{yield (hash - valid=(not (state-matches fsm.state 'error')) - )}} + {{yield (hash valid=(not (state-matches fsm.state "error")))}} +
    + + {{/let}} + + {{#let + (hash help=(t "common.validations.server-external-addresses.help")) + as |ServerExternalAddresses| + }} +
    + + {{yield (hash valid=(not (state-matches fsm.state "error")))}}
    {{/let}} diff --git a/ui/packages/consul-peerings/app/components/consul/peer/form/generate/fieldsets/index.js b/ui/packages/consul-peerings/app/components/consul/peer/form/generate/fieldsets/index.js new file mode 100644 index 000000000000..ea90d9406090 --- /dev/null +++ b/ui/packages/consul-peerings/app/components/consul/peer/form/generate/fieldsets/index.js @@ -0,0 +1,15 @@ +import Component from '@glimmer/component'; +import { action } from '@ember/object'; + +export default class PeerGenerateFieldSets extends Component { + @action + onInput(addresses) { + if (addresses) { + addresses = addresses.split(',').map(address => address.trim()); + } else { + addresses = []; + } + + this.args.item.ServerExternalAddresses = addresses; + } +} diff --git a/ui/packages/consul-peerings/app/components/consul/peer/form/generate/index.hbs b/ui/packages/consul-peerings/app/components/consul/peer/form/generate/index.hbs index 0e4e63a65893..de818b1b5fe2 100644 --- a/ui/packages/consul-peerings/app/components/consul/peer/form/generate/index.hbs +++ b/ui/packages/consul-peerings/app/components/consul/peer/form/generate/index.hbs @@ -1,88 +1,81 @@ -
    +
    + @src={{require + "./chart.xstate" + from="/components/consul/peer/form/generate" + }} + @initial={{if @regenerate "loading" "idle"}} + as |fsm| + > - {{#let - (unique-id) - as |id reset|}} -
    + {{#let (unique-id) as |id reset|}} + - - - - -

    - Error
    - {{fsm.state.context.error.message}} -

    -
    -
    -
    - {{yield (hash - Fieldsets=(component "consul/peer/form/generate/fieldsets" - item=@item - ) - Actions=(component "consul/peer/form/generate/actions" - item=@item - id=id - ) - )}} -
    - - - + + + +

    + Error
    + {{fsm.state.context.error.message}} +

    +
    +
    +
    + {{yield (hash - partition=@item.Partition - nspace='' - dc=@item.Datacenter - name=@item.Name + Fieldsets=(component + "consul/peer/form/generate/fieldsets" item=@item + ) + Actions=(component + "consul/peer/form/generate/actions" item=@item id=id + ) ) }} - @onchange={{queue - @onchange - (pick 'data' (fn fsm.dispatch 'SUCCESS')) - }} - @onerror={{queue - (fn fsm.dispatch 'ERROR') - }} - /> -
    + - - {{yield (hash - Fieldsets=(component "consul/peer/form/token/fieldsets" - item=@item - token=fsm.state.context.PeeringToken - regenerate=@regenerate - onclick=(queue - (set @item 'Name' '') - (fn fsm.dispatch 'RESET') + + + + + + {{yield + (hash + Fieldsets=(component + "consul/peer/form/token/fieldsets" + item=@item + token=fsm.state.context.PeeringToken + regenerate=@regenerate + onclick=(queue (set @item "Name" "") (fn fsm.dispatch "RESET")) + ) + Actions=(component + "consul/peer/form/token/actions" + token=fsm.state.context.PeeringToken + item=@item + id=id + ) ) - ) - Actions=(component "consul/peer/form/token/actions" - token=fsm.state.context.PeeringToken - item=@item - id=id - ) - )}} - + }} + -
    - {{/let}} + + {{/let}}
    diff --git a/ui/packages/consul-peerings/app/components/consul/peer/form/index.hbs b/ui/packages/consul-peerings/app/components/consul/peer/form/index.hbs index b8d09b8c8c48..8f56517f9cfd 100644 --- a/ui/packages/consul-peerings/app/components/consul/peer/form/index.hbs +++ b/ui/packages/consul-peerings/app/components/consul/peer/form/index.hbs @@ -1,42 +1,34 @@ -
    +
    + @src={{require "./chart.xstate" from="/components/consul/peer/form"}} + as |fsm| + > - + + {{yield + (hash Form=(component "consul/peer/form/generate" item=source.data)) }} - as |source|> - {{yield (hash - Form=(component 'consul/peer/form/generate' - item=source.data - ) - ) - }} @@ -44,20 +36,15 @@ + {{yield + (hash Form=(component "consul/peer/form/initiate" item=source.data)) }} - as |source|> - {{yield (hash - Form=(component 'consul/peer/form/initiate' - item=source.data - ) - ) - }} -
    diff --git a/ui/packages/consul-peerings/app/components/consul/peer/form/initiate/index.hbs b/ui/packages/consul-peerings/app/components/consul/peer/form/initiate/index.hbs index 8b29c46b8c4f..f7daf88cf407 100644 --- a/ui/packages/consul-peerings/app/components/consul/peer/form/initiate/index.hbs +++ b/ui/packages/consul-peerings/app/components/consul/peer/form/initiate/index.hbs @@ -1,54 +1,43 @@ -
    +
    - - - -

    - Error
    - {{error.message}} -

    -
    -
    -
    - -{{#let - (unique-id) -as |id|}} -
    - {{yield (hash - Fieldsets=(component "consul/peer/form/initiate/fieldsets" - item=@item - ) - Actions=(component "consul/peer/form/initiate/actions" - item=@item - id=id + as |writer| + > + + + +

    + Error
    + {{error.message}} +

    +
    +
    +
    + + {{#let (unique-id) as |id|}} + + {{yield + (hash + Fieldsets=(component + "consul/peer/form/initiate/fieldsets" item=@item + ) + Actions=(component + "consul/peer/form/initiate/actions" item=@item id=id + ) ) - )}} + }} -{{/let}} + {{/let}}
    -
    +
    \ No newline at end of file diff --git a/ui/packages/consul-peerings/app/components/consul/peer/form/token/fieldsets/index.hbs b/ui/packages/consul-peerings/app/components/consul/peer/form/token/fieldsets/index.hbs index b2a53bdd0606..ba1cf4ddda58 100644 --- a/ui/packages/consul-peerings/app/components/consul/peer/form/token/fieldsets/index.hbs +++ b/ui/packages/consul-peerings/app/components/consul/peer/form/token/fieldsets/index.hbs @@ -19,7 +19,7 @@
  • Switch to the peer
    - Someone on your team should log into the Datacenter (OSS) or Admin Partition (Enterprise) that you want this one to connect with. + Someone on your team should log into the Datacenter (CE) or Admin Partition (Enterprise) that you want this one to connect with.
  • Initiate the peering
    diff --git a/ui/packages/consul-peerings/app/controllers/dc/peers/index.js b/ui/packages/consul-peerings/app/controllers/dc/peers/index.js new file mode 100644 index 000000000000..e8812e4861c0 --- /dev/null +++ b/ui/packages/consul-peerings/app/controllers/dc/peers/index.js @@ -0,0 +1,12 @@ +import Controller from "@ember/controller"; +import { inject as service } from "@ember/service"; + +export default class DcPeersIndexController extends Controller { + @service router; + + redirectToPeerShow = (modalCloseFn, peerModel) => { + modalCloseFn?.(); + + this.router.transitionTo("dc.peers.show", peerModel.Name); + }; +} diff --git a/ui/packages/consul-peerings/app/templates/dc/peers/index.hbs b/ui/packages/consul-peerings/app/templates/dc/peers/index.hbs index 75ee9afa7774..2d57dec8d2d5 100644 --- a/ui/packages/consul-peerings/app/templates/dc/peers/index.hbs +++ b/ui/packages/consul-peerings/app/templates/dc/peers/index.hbs @@ -1,235 +1,231 @@ - + + ) + }} + as |loader| + > - + -{{#let - - (hash - value=(or sortBy "State:asc") - change=(action (mut sortBy) value="target.selected") - ) - - (hash - state=(hash - value=(if state (split state ',') undefined) - change=(action (mut state) value="target.selectedItems") - ) - searchproperty=(hash - value=(if (not-eq searchproperty undefined) - (split searchproperty ',') - searchProperties - ) - change=(action (mut searchproperty) value="target.selectedItems") - default=searchProperties - ) - ) - - loader.data - -as |sort filters items|}} - - -

    - -

    -
    - - - {{#if (gt items.length 0)}} - - {{/if}} - - - - - - - - {{did-insert (set this 'create' modal)}} -

    - Add peer connection -

    -
    - - - {{#if modal.opened}} - - - {{did-insert (set this 'form' form)}} - - - - {{/if}} - - - - - -
    - - Add peer connection - - -
    - - - - - - - - + searchproperty=(hash + value=(if + (not-eq searchproperty undefined) + (split searchproperty ",") + searchProperties + ) + change=(action (mut searchproperty) value="target.selectedItems") + default=searchProperties + ) + ) + loader.data + as |sort filters items| + }} + + +

    + +

    +
    + + + {{#if (gt items.length 0)}} + + {{/if}} + + + + @aria={{hash label="Add peer connection"}} + class="peer-create-modal" + as |modal| + > - {{did-insert (set this 'regenerate' modal)}} + {{did-insert (set this "create" modal)}}

    - Regenerate token + Add peer connection

    - {{#if this.item}} - - {{did-insert (set this 'regenerateForm' form)}} - - + + {{#if modal.opened}} + + + {{did-insert (set this "form" form)}} + + + {{/if}} + - +
    - - + Add peer connection + + +
    + + + - - - + + + + + - - - {{!-- TODO: do we need to check permissions here or will we receive an error automatically? --}} - + {{did-insert (set this "regenerate" modal)}}

    - {{t 'routes.dc.peers.index.empty.header' - items=items.length - }} + Regenerate token

    -

    - {{t 'routes.dc.peers.index.empty.body' - items=items.length - canUsePartitions=(can "use partitions") - canUseACLs=(can "use acls") - htmlSafe=true - }} -

    + {{#if this.item}} + + {{did-insert (set this "regenerateForm" form)}} + + + {{/if}}
    -
  • - + - - - - - - - -{{/let}} + + + + + + + + + + {{! TODO: do we need to check permissions here or will we receive an error automatically? }} + + +

    + {{t + "routes.dc.peers.index.empty.header" + items=items.length + }} +

    +
    + +

    + {{t + "routes.dc.peers.index.empty.body" + items=items.length + canUsePartitions=(can "use partitions") + canUseACLs=(can "use acls") + htmlSafe=true + }} +

    +
    + + + + +
    +
    +
    + + + + + {{/let}} - + \ No newline at end of file diff --git a/ui/packages/consul-ui/GNUmakefile b/ui/packages/consul-ui/GNUmakefile index 0855de1dab0a..68ad9cc414d3 100644 --- a/ui/packages/consul-ui/GNUmakefile +++ b/ui/packages/consul-ui/GNUmakefile @@ -34,6 +34,7 @@ start-api: deps # things with 'view' will open your browser for you # otherwise its headless +# TODO(spatel): CE refactor # oss is currently with namespace support disabled test: deps test-node yarn run test diff --git a/ui/packages/consul-ui/app/adapters/token.js b/ui/packages/consul-ui/app/adapters/token.js index 5502dbd8994e..4a9f2fa03958 100644 --- a/ui/packages/consul-ui/app/adapters/token.js +++ b/ui/packages/consul-ui/app/adapters/token.js @@ -80,6 +80,7 @@ export default class TokenAdapter extends Adapter { ${{ Description: serialized.Description, + AccessorID: serialized.AccessorID, Policies: serialized.Policies, Roles: serialized.Roles, ServiceIdentities: serialized.ServiceIdentities, diff --git a/ui/packages/consul-ui/app/models/peer.js b/ui/packages/consul-ui/app/models/peer.js index 6695253d8f0a..0e03544b95e3 100644 --- a/ui/packages/consul-ui/app/models/peer.js +++ b/ui/packages/consul-ui/app/models/peer.js @@ -17,6 +17,8 @@ export default class Peer extends Model { @attr('string') Name; @attr('string') State; @attr('string') ID; + @attr('string') ServerExternalAddresses; + @nullValue([]) @attr() ServerExternalAddresses; // only the side that establishes will hold this property @attr('string') PeerID; diff --git a/ui/packages/consul-ui/app/models/service.js b/ui/packages/consul-ui/app/models/service.js index 7b50315d7763..0e06f81a8ebd 100644 --- a/ui/packages/consul-ui/app/models/service.js +++ b/ui/packages/consul-ui/app/models/service.js @@ -5,7 +5,7 @@ import { fragment } from 'ember-data-model-fragments/attributes'; import replace, { nullValue } from 'consul-ui/decorators/replace'; export const PRIMARY_KEY = 'uid'; -export const SLUG_KEY = 'Name'; +export const SLUG_KEY = 'Name,PeerName'; export const Collection = class Collection { @tracked items; diff --git a/ui/packages/consul-ui/app/services/client/http.js b/ui/packages/consul-ui/app/services/client/http.js index d36c70260ef0..49c095bb3699 100644 --- a/ui/packages/consul-ui/app/services/client/http.js +++ b/ui/packages/consul-ui/app/services/client/http.js @@ -252,7 +252,7 @@ export default class HttpService extends Service { // we can use them later for store reconciliation. Namespace // will look at the ns query parameter first, followed by the // Namespace property of the users token, defaulting back to - // 'default' which will mainly be used in OSS + // 'default' which will mainly be used in CE [CONSUL_DATACENTER]: params.data.dc, [CONSUL_NAMESPACE]: params.data.ns || token.Namespace || 'default', [CONSUL_PARTITION]: params.data.partition || token.Partition || 'default', diff --git a/ui/packages/consul-ui/app/services/repository/peer.js b/ui/packages/consul-ui/app/services/repository/peer.js index c39accbb512e..63f65e38ad05 100644 --- a/ui/packages/consul-ui/app/services/repository/peer.js +++ b/ui/packages/consul-ui/app/services/repository/peer.js @@ -44,8 +44,11 @@ export default class PeerService extends RepositoryService { }); } - @dataSource('/:partition/:ns/:dc/peering/token-for/:name') - async fetchToken({ dc, ns, partition, name }, configuration, request) { + @dataSource('/:partition/:ns/:dc/peering/token-for/:name/:externalAddresses') + async fetchToken({ dc, ns, partition, name, externalAddresses }, configuration, request) { + const ServerExternalAddresses = + externalAddresses?.length > 0 ? externalAddresses.split(',') : []; + return ( await request` POST /v1/peering/token @@ -53,6 +56,7 @@ export default class PeerService extends RepositoryService { ${{ PeerName: name, Partition: partition || undefined, + ServerExternalAddresses, }} ` )((headers, body, cache) => body); diff --git a/ui/packages/consul-ui/app/utils/create-fingerprinter.js b/ui/packages/consul-ui/app/utils/create-fingerprinter.js index bc6481647932..f2f46576303e 100644 --- a/ui/packages/consul-ui/app/utils/create-fingerprinter.js +++ b/ui/packages/consul-ui/app/utils/create-fingerprinter.js @@ -1,4 +1,5 @@ import { get } from '@ember/object'; +import { isEmpty } from '@ember/utils'; export default function (foreignKey, nspaceKey, partitionKey, hash = JSON.stringify) { return function (primaryKey, slugKey, foreignKeyValue, nspaceValue, partitionValue) { @@ -10,17 +11,26 @@ export default function (foreignKey, nspaceKey, partitionKey, hash = JSON.string ); } const slugKeys = slugKey.split(','); - const slugValues = slugKeys.map(function (slugKey) { - const slug = get(item, slugKey); - if (slug == null || slug.length < 1) { - throw new Error( - `Unable to create fingerprint, missing slug. Looking for value in \`${slugKey}\` got \`${slug}\`` - ); - } - return slug; - }); + const slugValues = slugKeys + .map(function (slugKey) { + const slug = get(item, slugKey); + + const isSlugEmpty = isEmpty(slug); + + if (isSlugEmpty) { + // PeerName should be optional as part of id + if (slugKey === 'PeerName') { + return; + } + throw new Error( + `Unable to create fingerprint, missing slug. Looking for value in \`${slugKey}\` got \`${slug}\`` + ); + } + return slug; + }) + .compact(); // This ensures that all data objects have a Namespace and a Partition - // value set, even in OSS. + // value set, even in CE. if (typeof item[nspaceKey] === 'undefined') { if (nspaceValue === '*') { nspaceValue = 'default'; diff --git a/ui/packages/consul-ui/config/environment.js b/ui/packages/consul-ui/config/environment.js index 4913c4cc8232..1289a2ca3719 100644 --- a/ui/packages/consul-ui/config/environment.js +++ b/ui/packages/consul-ui/config/environment.js @@ -70,6 +70,7 @@ module.exports = function (environment, $ = process.env) { CONSUL_COPYRIGHT_YEAR: env('CONSUL_COPYRIGHT_YEAR', repositoryYear), CONSUL_GIT_SHA: env('CONSUL_GIT_SHA', repositorySHA), CONSUL_VERSION: env('CONSUL_VERSION', binaryVersion), + // TODO(spatel): CE refactor CONSUL_BINARY_TYPE: env('CONSUL_BINARY_TYPE', 'oss'), // These can be overwritten by the UI user at runtime by setting localStorage values diff --git a/ui/packages/consul-ui/config/utils.js b/ui/packages/consul-ui/config/utils.js index c24172a037fe..6b3e24d708ad 100644 --- a/ui/packages/consul-ui/config/utils.js +++ b/ui/packages/consul-ui/config/utils.js @@ -9,16 +9,9 @@ const repositorySHA = function (sha = exec('git rev-parse --short HEAD')) { return sha.toString().trim(); }; const binaryVersion = function (repositoryRoot) { - return function (versionFileContents = read(`${repositoryRoot}/version/version.go`)) { + return function (versionFileContents = read(`${repositoryRoot}/version/VERSION`)) { // see /scripts/dist.sh:8 - return versionFileContents - .toString() - .split('\n') - .find(function (item, i, arr) { - return item.indexOf('Version =') !== -1; - }) - .trim() - .split('"')[1]; + return versionFileContents.toString(); }; }; const env = function ($) { diff --git a/ui/packages/consul-ui/docs/significant-patterns.mdx b/ui/packages/consul-ui/docs/significant-patterns.mdx index 0cd9d4365518..f60e2d287006 100644 --- a/ui/packages/consul-ui/docs/significant-patterns.mdx +++ b/ui/packages/consul-ui/docs/significant-patterns.mdx @@ -116,7 +116,7 @@ Please see our package.json file dependencies. ### Namespace support -Whilst Consul namespaces are a OSS feature of Consul, we almost always build +Whilst Consul namespaces are a CE feature of Consul, we almost always build things 'pretending' that namespaces are always enabled. Then there is code within the data layer of the application that removes any namespace related query parameters. diff --git a/ui/packages/consul-ui/docs/upgrades.mdx b/ui/packages/consul-ui/docs/upgrades.mdx index 76cbab129794..7a830fc6ffbc 100644 --- a/ui/packages/consul-ui/docs/upgrades.mdx +++ b/ui/packages/consul-ui/docs/upgrades.mdx @@ -6,7 +6,7 @@ Node upgrades should be done when it is convienient, preferably using the latest Active LTS version (https://nodejs.org/en/about/releases/) that also corresponds with the ember version we are on (https://github.com/ember-cli/ember-cli/blob/master/docs/node-support.md) -Aswell as bumping our `.nvmrc` and `.circleci/config.yml` files, when bumping +Aswell as bumping our `.nvmrc` file, when bumping node versions, please check with the rest of the team to see if there are other repositories that should track the same node version as this repository. diff --git a/ui/packages/consul-ui/ember-cli-build.js b/ui/packages/consul-ui/ember-cli-build.js index aa5d243074d1..6a1f6bc9522b 100644 --- a/ui/packages/consul-ui/ember-cli-build.js +++ b/ui/packages/consul-ui/ember-cli-build.js @@ -17,6 +17,7 @@ module.exports = function (defaults, $ = process.env) { $ = utils.env($); const env = EmberApp.env(); + const isProd = ['production'].includes(env); const prodlike = ['production', 'staging']; const devlike = ['development', 'staging']; const sourcemaps = !['production'].includes(env) && !$('BABEL_DISABLE_SOURCEMAPS', false); @@ -197,6 +198,7 @@ module.exports = function (defaults, $ = process.env) { autoImport: { // allows use of a CSP without 'unsafe-eval' directive forbidEval: true, + publicAssetURL: isProd ? '{{.ContentPath}}assets' : undefined, }, codemirror: { keyMaps: ['sublime'], diff --git a/ui/packages/consul-ui/node-tests/config/utils.js b/ui/packages/consul-ui/node-tests/config/utils.js index 243ac81fea6b..6b8a778db93d 100644 --- a/ui/packages/consul-ui/node-tests/config/utils.js +++ b/ui/packages/consul-ui/node-tests/config/utils.js @@ -12,13 +12,7 @@ test('utils.respositoryYear parses the year out correctly', function (t) { }); test('utils.binaryVersion parses the version out correctly', function (t) { const expected = '1.9.0'; - const actual = utils.binaryVersion()(` - - Version = "1.9.0" - - VersionPrerelease = "dev" - -`); + const actual = utils.binaryVersion()(`1.9.0`); t.equal(actual, expected, 'It parses the version correctly'); t.end(); }); diff --git a/ui/packages/consul-ui/tests/acceptance/dc/peers/create.feature b/ui/packages/consul-ui/tests/acceptance/dc/peers/create.feature index 4cfe29db70a9..27136139049c 100644 --- a/ui/packages/consul-ui/tests/acceptance/dc/peers/create.feature +++ b/ui/packages/consul-ui/tests/acceptance/dc/peers/create.feature @@ -22,6 +22,7 @@ Feature: dc / peers / create: Peer Create Token --- body: PeerName: new-peer + ServerExternalAddresses: [] --- Then I see the text "an-encoded-token" in ".consul-peer-form-generate code" When I click ".consul-peer-form-generate button[type=reset]" @@ -33,11 +34,13 @@ Feature: dc / peers / create: Peer Create Token Then I fill in with yaml --- Name: another-new-peer + ServerExternalAddresses: "1.1.1.1:123,1.2.3.4:3202" --- When I click ".peer-create-modal .modal-dialog-footer button" Then a POST request was made to "/v1/peering/token" from yaml --- body: PeerName: another-new-peer + ServerExternalAddresses: ["1.1.1.1:123","1.2.3.4:3202"] --- Then I see the text "another-encoded-token" in ".consul-peer-form-generate code" diff --git a/ui/packages/consul-ui/tests/acceptance/dc/peers/establish.feature b/ui/packages/consul-ui/tests/acceptance/dc/peers/establish.feature index f037d45725c3..c773155aca8b 100644 --- a/ui/packages/consul-ui/tests/acceptance/dc/peers/establish.feature +++ b/ui/packages/consul-ui/tests/acceptance/dc/peers/establish.feature @@ -28,3 +28,4 @@ Feature: dc / peers / establish: Peer Establish Peering --- And "[data-notification]" has the "notification-update" class And "[data-notification]" has the "success" class + And the url should be /dc-1/peers/new-peer/imported-services diff --git a/ui/packages/consul-ui/translations/common/en-us.yaml b/ui/packages/consul-ui/translations/common/en-us.yaml index 8fce904302de..5c584540eda6 100644 --- a/ui/packages/consul-ui/translations/common/en-us.yaml +++ b/ui/packages/consul-ui/translations/common/en-us.yaml @@ -81,4 +81,6 @@ validations: error: "{name} must be a valid DNS hostname." immutable: help: Once created, this cannot be changed. - + server-external-addresses: + help: | + Enter a comma separated list of this peer's fallback server address(es) to be used in the event of failed automatic updates. This field is required for HCP-managed clusters. diff --git a/ui/packages/consul-ui/translations/components/consul/en-us.yaml b/ui/packages/consul-ui/translations/components/consul/en-us.yaml index 0809332f43d9..b8ee183e3121 100644 --- a/ui/packages/consul-ui/translations/components/consul/en-us.yaml +++ b/ui/packages/consul-ui/translations/components/consul/en-us.yaml @@ -14,6 +14,12 @@ peer: name: Status asc: Pending to Deleting desc: Deleting to Pending + form: + generate-label: Generate token + establish-label: Establish peering + generate: + name: 'Name of peer' + addresses: 'Server address(es)' service: search-bar: kind: Service Type diff --git a/ui/packages/consul-ui/translations/routes/en-us.yaml b/ui/packages/consul-ui/translations/routes/en-us.yaml index f9cd5ad10df1..57ed8aaff4ae 100644 --- a/ui/packages/consul-ui/translations/routes/en-us.yaml +++ b/ui/packages/consul-ui/translations/routes/en-us.yaml @@ -158,7 +158,7 @@ dc:
    {items, select, 0 {Services must be exported from one peer to another to enable service communication across two peers. There don't seem to be any services imported from {name} yet, or you may not have services:read permissions to access to this view.} - other {No services where found matching that search, or you may not have access to view the services you are searching for.} + other {No services were found matching that search, or you may not have access to view the services you are searching for.} }
    exported: @@ -168,7 +168,7 @@ dc:
    {items, select, 0 {Services must be exported from one peer to another to enable service communication across two peers. There don't seem to be any services exported to {name} yet, or you may not have services:read permissions to access to this view.} - other {No services where found matching that search, or you may not have access to view the services you are searching for.} + other {No services were found matching that search, or you may not have access to view the services you are searching for.} }
    diff --git a/version/VERSION b/version/VERSION new file mode 100644 index 000000000000..4283bbad54c9 --- /dev/null +++ b/version/VERSION @@ -0,0 +1 @@ +1.14.10-dev diff --git a/version/version.go b/version/version.go index 8930a432a8e0..36b2eacfa5a1 100644 --- a/version/version.go +++ b/version/version.go @@ -1,6 +1,7 @@ package version import ( + _ "embed" "fmt" "strings" ) @@ -10,20 +11,20 @@ var ( // compiler. GitCommit string - // The next version number that will be released. This will be updated after every release. - // + // The next version number that will be released. This will be updated after every release // Version must conform to the format expected by github.com/hashicorp/go-version // for tests to work. - Version = "1.14.0" + // A pre-release marker for the version can also be specified (e.g -dev). If this is omitted + // then it means that it is a final release. Otherwise, this is a pre-release + // such as "dev" (in development), "beta", "rc1", etc. + //go:embed VERSION + fullVersion string + + Version, VersionPrerelease, _ = strings.Cut(strings.TrimSpace(fullVersion), "-") // https://semver.org/#spec-item-10 VersionMetadata = "" - // A pre-release marker for the version. If this is "" (empty string) - // then it means that it is a final release. Otherwise, this is a pre-release - // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" - // The date/time of the build (actually the HEAD commit in git, to preserve stability) // This isn't just informational, but is also used by the licensing system. Default is chosen to be flagantly wrong. BuildDate string = "1970-01-01T00:00:01Z" diff --git a/website/content/api-docs/acl/tokens.mdx b/website/content/api-docs/acl/tokens.mdx index 7988e5f75423..2310a91a29ca 100644 --- a/website/content/api-docs/acl/tokens.mdx +++ b/website/content/api-docs/acl/tokens.mdx @@ -676,7 +676,7 @@ The table below shows this endpoint's support for The corresponding CLI command is [`consul acl token list`](/commands/acl/token/list). -## Query Parameters +### Query Parameters - `policy` `(string: "")` - Filters the token list to those tokens that are linked with this specific policy ID. @@ -684,6 +684,9 @@ The corresponding CLI command is [`consul acl token list`](/commands/acl/token/l - `role` `(string: "")` - Filters the token list to those tokens that are linked with this specific role ID. +- `servicename` `(string: "")` - Filters the token list to those tokens that are + linked with this specific service name in their service identity. + - `authmethod` `(string: "")` - Filters the token list to those tokens that are linked with this specific named auth method. @@ -695,7 +698,7 @@ The corresponding CLI command is [`consul acl token list`](/commands/acl/token/l The namespace may be specified as '\*' to return results for all namespaces. You can also [specify the namespace through other methods](#methods-to-specify-namespace). -## Sample Request +### Sample Request ```shell-session $ curl --request GET http://127.0.0.1:8500/v1/acl/tokens diff --git a/website/content/api-docs/agent/check.mdx b/website/content/api-docs/agent/check.mdx index 98f33cf32837..8e93aa558e61 100644 --- a/website/content/api-docs/agent/check.mdx +++ b/website/content/api-docs/agent/check.mdx @@ -6,8 +6,7 @@ description: The /agent/check endpoints interact with checks on the local agent # Check - Agent HTTP API -Consul's health check capabilities are described in the -[health checks overview](/docs/discovery/checks). +Refer to [Define Health Checks](/consul/docs/services/usage/checks) for information about Consul health check capabilities. The `/agent/check` endpoints interact with health checks managed by the local agent in Consul. These should not be confused with checks in the catalog. diff --git a/website/content/api-docs/agent/service.mdx b/website/content/api-docs/agent/service.mdx index afeb4abbc823..5c3e323692fd 100644 --- a/website/content/api-docs/agent/service.mdx +++ b/website/content/api-docs/agent/service.mdx @@ -170,6 +170,8 @@ The table below shows this endpoint's support for ### Sample Request +The following example request calls the `web-sidecar-proxy` service: + ```shell-session $ curl \ http://127.0.0.1:8500/v1/agent/service/web-sidecar-proxy @@ -177,6 +179,11 @@ $ curl \ ### Sample Response +The response contains the fields specified in the [service +definition](/consul/docs/services/configuration/services-configuration-reference), but it includes an extra `ContentHash` field that contains the [hash-based blocking +query](/consul/api-docs/features/blocking#hash-based-blocking-queries) hash for the result. The +same hash is also present in `X-Consul-ContentHash`. + ```json { "Kind": "connect-proxy", @@ -227,12 +234,6 @@ $ curl \ } ``` -The response has the same structure as the [service -definition](/docs/discovery/services) with one extra field `ContentHash` which -contains the [hash-based blocking -query](/api-docs/features/blocking#hash-based-blocking-queries) hash for the result. The -same hash is also present in `X-Consul-ContentHash`. - ## Get local service health Retrieve an aggregated state of service(s) on the local agent by name. @@ -599,21 +600,18 @@ The corresponding CLI command is [`consul services register`](/commands/services ### JSON Request Body Schema -Note that this endpoint, unlike most also [supports `snake_case`](/docs/discovery/services#service-definition-parameter-case) -service definition keys for compatibility with the config file format. +The `/agent/service/register` endpoint supports camel case and _snake case_ for service definition keys. Snake case is a convention in which keys with two or more words have underscores between them. Snake case ensures compatibility with the agent configuration file format. - `Name` `(string: )` - Specifies the logical name of the service. Many service instances may share the same logical service name. We recommend using - [valid DNS labels](https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_hostnames) - for [compatibility with external DNS](/docs/discovery/services#service-and-tag-names-with-dns). + valid DNS labels for service definition names. Refer to the Internet Engineering Task Force's [RFC 1123](https://datatracker.ietf.org/doc/html/rfc1123#page-72) for additional information. Service names that conform to standard usage ensures compatibility with external DNSs. Refer to [Services Configuration Reference](/consul/docs/services/configuration/services-configuration-reference#name) for additional information. - `ID` `(string: "")` - Specifies a unique ID for this service. This must be unique per _agent_. This defaults to the `Name` parameter if not provided. - `Tags` `(array: nil)` - Specifies a list of tags to assign to the - service. These tags can be used for later filtering and are exposed via the APIs. - We recommend using [valid DNS labels](https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_hostnames) - for [compatibility with external DNS](/docs/discovery/services#service-and-tag-names-with-dns) + service. Tags enable you to filter when querying for the services and are exposed in Consul APIs. We recommend using + valid DNS labels for tags. Refer to the Internet Engineering Task Force's [RFC 1123](https://datatracker.ietf.org/doc/html/rfc1123#page-72) for additional information. Tags that conform to standard usage ensures compatibility with external DNSs. Refer to [Services Configuration Reference](/consul/docs/services/configuration/services-configuration-reference#tags) for additional information. - `Address` `(string: "")` - Specifies the address of the service. If not provided, the agent's address is used as the address for the service during @@ -635,7 +633,7 @@ service definition keys for compatibility with the config file format. - `Kind` `(string: "")` - The kind of service. Defaults to "" which is a typical Consul service. This value may also be "connect-proxy" for [Connect](/docs/connect) proxies representing another service, - "mesh-gateway" for instances of a [mesh gateway](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters), + "mesh-gateway" for instances of a [mesh gateway](/docs/connect/gateways/mesh-gateway#connect-proxy-configuration), "terminating-gateway" for instances of a [terminating gateway](/docs/connect/gateways/terminating-gateway), or "ingress-gateway" for instances of a [ingress gateway](/docs/connect/gateways/ingress-gateway). @@ -676,19 +674,15 @@ service definition keys for compatibility with the config file format. service's port _and_ the tags would revert to the original value and all modifications would be lost. -- `Weights` `(Weights: nil)` - Specifies weights for the service. Please see the - [service documentation](/docs/discovery/services) for more information about - weights. If this field is not provided weights will default to +- `Weights` `(Weights: nil)` - Specifies weights for the service. Refer to + [Services Configuration Reference](/consul/docs/services/configuraiton/services-configuration-reference#weights) for additional information. Default is `{"Passing": 1, "Warning": 1}`. - It is important to note that this applies only to the locally registered - service. If you have multiple nodes all registering the same service their - `EnableTagOverride` configuration and all other service configuration items - are independent of one another. Updating the tags for the service registered - on one node is independent of the same service (by name) registered on - another node. If `EnableTagOverride` is not specified the default value is - `false`. See [anti-entropy syncs](/docs/architecture/anti-entropy) for - more info. + Weights only apply to the locally registered service. + If multiple nodes register the same service, each node implements `EnableTagOverride` and other service configuration items independently. Updating the tags for the service registered + on one node does not necessarily update the same tags on services with the same name registered on another node. If `EnableTagOverride` is not specified the default value is + `false`. See [anti-entropy syncs](/consul/docs/architecture/anti-entropy) for + additional information. #### Connect Structure diff --git a/website/content/api-docs/api-structure.mdx b/website/content/api-docs/api-structure.mdx index 5f7ef44dfba8..1e2530db7807 100644 --- a/website/content/api-docs/api-structure.mdx +++ b/website/content/api-docs/api-structure.mdx @@ -89,7 +89,7 @@ However, we generally recommend using resource names that don't require URL-enco Depending on the validation that Consul applies to a resource name, Consul may still reject a request if it considers the resource name invalid for that endpoint. And even if Consul considers the resource name valid, it may degrade other functionality, -such as failed [DNS lookups](/docs/discovery/dns) +such as failed [DNS lookups](/consul/docs/services/discovery/dns-overview) for nodes or services with names containing invalid DNS characters. This HTTP API capability also allows the diff --git a/website/content/api-docs/catalog.mdx b/website/content/api-docs/catalog.mdx index 51f3c18da8e5..af476316e543 100644 --- a/website/content/api-docs/catalog.mdx +++ b/website/content/api-docs/catalog.mdx @@ -55,15 +55,16 @@ The table below shows this endpoint's support for - `NodeMeta` `(map: nil)` - Specifies arbitrary KV metadata pairs for filtering purposes. -- `Service` `(Service: nil)` - Specifies to register a service. If `ID` is not - provided, it will be defaulted to the value of the `Service.Service` property. - Only one service with a given `ID` may be present per node. We recommend using - [valid DNS labels](https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_hostnames) - for service definition names for [compatibility with external DNS](/docs/discovery/services#service-and-tag-names-with-dns). - The service `Tags`, `Address`, `Meta`, and `Port` fields are all optional. For more - information about these fields and the implications of setting them, - see the [Service - Agent API](/api-docs/agent/service) page - as registering services differs between using this or the Services Agent endpoint. +- `Service` `(Service: nil)` - Contains an object the specifies the service to register. The the `Service.Service` field is required. If `Service.ID` is not provided, the default is the `Service.Service`. + You can only specify one service with a given `ID` per node. We recommend using + valid DNS labels for service definition names. Refer to the Internet Engineering Task Force's [RFC 1123](https://datatracker.ietf.org/doc/html/rfc1123#page-72) for additional information. Service names that conform to standard usage ensures compatibility with external DNSs. Refer to [Services Configuration Reference](/consul/docs/services/configuration/services-configuration-reference#name) for additional information. + The following fields are optional: + - `Tags` + - `Address` + - `Meta` + - `Port` + + For additional information configuring services, refer to [Service - Agent API](/consul/api-docs/agent/service). The `/catalog` endpoint had different behaviors than the `/services` endpoint. - `Check` `(Check: nil)` - Specifies to register a check. The register API manipulates the health check entry in the Catalog, but it does not setup the @@ -78,8 +79,7 @@ The table below shows this endpoint's support for treated as a service level health check, instead of a node level health check. The `Status` must be one of `passing`, `warning`, or `critical`. - The `Definition` field can be provided with details for a TCP or HTTP health - check. For more information, see the [Health Checks](/docs/discovery/checks) page. + You can provide defaults for TCP and HTTP health checks to the `Definition` field. Refer to [Health Checks](/consul/docs/services/usage/checks) for additional information. Multiple checks can be provided by replacing `Check` with `Checks` and sending an array of `Check` objects. @@ -399,9 +399,9 @@ The table below shows this endpoint's support for [agent caching](/api-docs/features/caching), and [required ACLs](/api-docs/api-structure#authentication). -| Blocking Queries | Consistency Modes | Agent Caching | ACL Required | -| ---------------- | ----------------- | ------------- | -------------- | -| `YES` | `all` | `simple` | `service:read` | +| Blocking Queries | Consistency Modes | Agent Caching | ACL Required | +| ---------------- | ----------------- | -------------------- | -------------- | +| `YES` | `all` | `background refresh` | `service:read` | The corresponding CLI command is [`consul catalog services`](/commands/catalog/services). diff --git a/website/content/api-docs/connect/ca.mdx b/website/content/api-docs/connect/ca.mdx index 3d3e456c18f3..2229b1566c6b 100644 --- a/website/content/api-docs/connect/ca.mdx +++ b/website/content/api-docs/connect/ca.mdx @@ -169,6 +169,13 @@ The table below shows this endpoint's support for The corresponding CLI command is [`consul connect ca set-config`](/commands/connect/ca#set-config). +~> **If currently using Vault CA provider:** + If you intend to change the CA provider from Vault to another, + or to change the Vault provider's [`RootPKIPath`](/docs/connect/ca/vault#rootpkipath), + you must temporarily elevate the privileges of the Vault token + or auth method in use as described in the + [Vault CA provider documentation](/docs/connect/ca/vault#additional-vault-acl-policies-for-sensitive-operations). + ### JSON Request Body Schema - `Provider` `(string: )` - Specifies the CA provider type to use. @@ -177,11 +184,14 @@ The corresponding CLI command is [`consul connect ca set-config`](/commands/conn for the chosen provider. For more information on configuring the Connect CA providers, see [Provider Config](/docs/connect/ca). -- `ForceWithoutCrossSigning` `(bool: )` - Indicates that the CA change - should be forced to complete even if the current CA doesn't support cross - signing. Changing root without cross-signing may cause temporary connection - failures until the rollout completes. See [Forced Rotation Without - Cross-Signing](/docs/connect/ca#forced-rotation-without-cross-signing) +- `ForceWithoutCrossSigning` `(bool: false)` - Indicates that the CA change + should be forced to complete even if the current CA doesn't support root cross-signing. + + ~> **Caution:** Setting this field to `true` will cause temporary connection failures + until service mesh proxies and/or Consul client agents receive a new certificate + that establishes trust with the new root. + Do not use this field unless you are sure you need it. + Refer to [Forced Rotation Without Cross-Signing](/docs/connect/ca#forced-rotation-without-cross-signing) for more detail. ### Sample Payload diff --git a/website/content/api-docs/connect/intentions.mdx b/website/content/api-docs/connect/intentions.mdx index a979a3e6d779..801a1a80c465 100644 --- a/website/content/api-docs/connect/intentions.mdx +++ b/website/content/api-docs/connect/intentions.mdx @@ -48,7 +48,7 @@ The table below shows this endpoint's support for

    1 Intention ACL rules are specified as part of a{' '} service rule. See{' '} - + Intention Management Permissions {' '} for more details. @@ -154,7 +154,7 @@ The table below shows this endpoint's support for

    1 Intention ACL rules are specified as part of a{' '} service rule. See{' '} - + Intention Management Permissions {' '} for more details. @@ -251,7 +251,7 @@ The table below shows this endpoint's support for

    1 Intention ACL rules are specified as part of a{' '} service rule. See{' '} - + Intention Management Permissions {' '} for more details. @@ -305,7 +305,7 @@ The table below shows this endpoint's support for

    1 Intention ACL rules are specified as part of a{' '} service rule. See{' '} - + Intention Management Permissions {' '} for more details. @@ -377,7 +377,7 @@ The table below shows this endpoint's support for

    1 Intention ACL rules are specified as part of a{' '} service rule. See{' '} - + Intention Management Permissions {' '} for more details. @@ -440,7 +440,7 @@ The table below shows this endpoint's support for

    1 Intention ACL rules are specified as part of a{' '} service rule. See{' '} - + Intention Management Permissions {' '} for more details. @@ -527,7 +527,7 @@ The table below shows this endpoint's support for

    1 Intention ACL rules are specified as part of a{' '} service rule. See{' '} - + Intention Management Permissions {' '} for more details. @@ -582,7 +582,7 @@ The table below shows this endpoint's support for

    1 Intention ACL rules are specified as part of a{' '} service rule. See{' '} - + Intention Management Permissions {' '} for more details. @@ -608,9 +608,7 @@ This endpoint evaluates the intentions for a specific source and destination and returns whether the connection would be authorized or not given the current Consul configuration and set of intentions. --> **Note:** This endpoint will always evaluate intentions with `Permissions` -defined as _deny_ intentions during. This endpoint is only suited for -networking layer 4 (e.g. TCP) integration. +-> **Note:** This endpoint will always evaluate matching intentions with L7 `Permissions` defined as _deny_ intentions because there is no request to check against. For performance and reliability reasons it is desirable to implement intention enforcement by listing [intentions that match the @@ -638,7 +636,7 @@ The table below shows this endpoint's support for

    1 Intention ACL rules are specified as part of a{' '} service rule. See{' '} - + Intention Management Permissions {' '} for more details. @@ -698,7 +696,7 @@ The table below shows this endpoint's support for

    1 Intention ACL rules are specified as part of a{' '} service rule. See{' '} - + Intention Management Permissions {' '} for more details. diff --git a/website/content/api-docs/discovery-chain.mdx b/website/content/api-docs/discovery-chain.mdx index 3d483415d6a4..c501d5d9a60f 100644 --- a/website/content/api-docs/discovery-chain.mdx +++ b/website/content/api-docs/discovery-chain.mdx @@ -93,7 +93,7 @@ The table below shows this endpoint's support for parameter. - `OverrideMeshGateway` `(MeshGatewayConfig: )` - Overrides the final - [mesh gateway configuration](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters#connect-proxy-configuration) + [mesh gateway configuration](/docs/connect/gateways/mesh-gateway#connect-proxy-configuration) for this any service resolved in the compiled chain. This value comes from either the [proxy diff --git a/website/content/api-docs/features/consistency.mdx b/website/content/api-docs/features/consistency.mdx index 692b2e1fb023..9567d32774e3 100644 --- a/website/content/api-docs/features/consistency.mdx +++ b/website/content/api-docs/features/consistency.mdx @@ -131,7 +131,7 @@ The following diagrams show the cross-datacenter request paths when Consul serve ### Consul DNS Queries -When DNS queries are issued to [Consul's DNS interface](/docs/discovery/dns), +When DNS queries are issued to [Consul's DNS interface](/consul/docs/services/discovery/dns-overview), Consul uses the `stale` consistency mode by default when interfacing with its underlying Consul service discovery HTTP APIs ([Catalog](/api-docs/catalog), [Health](/api-docs/health), and [Prepared Query](/api-docs/query)). diff --git a/website/content/api-docs/health.mdx b/website/content/api-docs/health.mdx index ba5eef9788a0..a9d9536a220f 100644 --- a/website/content/api-docs/health.mdx +++ b/website/content/api-docs/health.mdx @@ -222,8 +222,7 @@ The table below shows this endpoint's support for | `YES` 1 | `all` | `background refresh` | `node:read,service:read` |

    - 1some query parameters will use the - streaming backend + 1some query parameters will use the streaming backend for blocking queries.

    ### Path Parameters diff --git a/website/content/api-docs/operator/index.mdx b/website/content/api-docs/operator/index.mdx index 6bfaf034d291..28b69a7e7f08 100644 --- a/website/content/api-docs/operator/index.mdx +++ b/website/content/api-docs/operator/index.mdx @@ -17,7 +17,7 @@ If ACLs are enabled then a token with operator privileges may be required in order to use this interface. Check the [ACL Rules documentation](/docs/security/acl/acl-rules#operator-rules) for more information. -Check the [Outage Recovery](https://learn.hashicorp.com/tutorials/consul/recovery-outage) tutorial for some examples of +Check the [Disaster recovery for Consul clusters](/consul/tutorials/datacenter-operations/recovery-outage) tutorial for some examples of how these capabilities are used. Please choose a sub-section in the navigation for more information. diff --git a/website/content/api-docs/peering.mdx b/website/content/api-docs/peering.mdx index 910172fe732b..f30cf4b5b2a0 100644 --- a/website/content/api-docs/peering.mdx +++ b/website/content/api-docs/peering.mdx @@ -6,11 +6,6 @@ description: The /peering endpoints allow for managing cluster peerings. # Cluster Peering - HTTP API -~> **Cluster peering is currently in technical preview:** Functionality associated -with cluster peering is subject to change. You should never use the technical -preview release in secure environments or production scenarios. Features in -technical preview may have performance issues, scaling issues, and limited support. - The functionality described here is available only in [Consul](https://www.hashicorp.com/products/consul/) version 1.13.0 and later. @@ -42,6 +37,9 @@ The table below shows this endpoint's support for - `Partition` `(string: "")` - The admin partition that the peering token is generated from. Uses `default` when not specified. +- `ServerExternalAddresses` `([]string: )` - The addresses for the cluster that generates the peering token. Addresses take the form `{host or IP}:port`. +You can specify one or more load balancers or external IPs that route external traffic to this cluster's Consul servers. + - `Meta` `(map: )` - Specifies KV metadata to associate with the peering. This parameter is not required and does not directly impact the cluster peering process. @@ -156,7 +154,7 @@ The table below shows this endpoint's support for | Blocking Queries | Consistency Modes | Agent Caching | ACL Required | | ---------------- | ----------------- | ------------- | -------------- | -| `NO` | `consistent` | `none` | `peering:read` | +| `YES` | `consistent` | `none` | `peering:read` | ### Path Parameters @@ -265,9 +263,9 @@ The table below shows this endpoint's support for [agent caching](/api-docs/features/caching), and [required ACLs](/api-docs/api-structure#authentication). -| Blocking Queries | Consistency Modes | Agent Caching | ACL Required | -| ---------------- | ----------------- | ------------- | -------------- | -| `NO` | `consistent` | `none` | `peering:read` | +| Blocking Queries | Consistency Modes | Agent Caching | ACL Required | +| ---------------- | ----------------- | -------------------- | -------------- | +| `YES` | `consistent` | `background refresh` | `peering:read` | ### Query Parameters diff --git a/website/content/api-docs/query.mdx b/website/content/api-docs/query.mdx index 67b278731b9a..e1a8df3ad3dc 100644 --- a/website/content/api-docs/query.mdx +++ b/website/content/api-docs/query.mdx @@ -9,10 +9,9 @@ description: The /query endpoints manage and execute prepared queries in Consul. The `/query` endpoints create, update, destroy, and execute prepared queries. Prepared queries allow you to register a complex service query and then execute -it later via its ID or name to get a set of healthy nodes that provide a given -service. This is particularly useful in combination with Consul's -[DNS Interface](/docs/discovery/dns#prepared-query-lookups) as it allows for much richer queries than -would be possible given the limited entry points exposed by DNS. +it later by specifying the query ID or name. Consul returns a set of healthy nodes that provide a given +service. Refer to +[Enable Dynamic DNS Queries](/consul/docs/services/discovery/dns-dynamic-lookups) for additional information. Check the [Geo Failover tutorial](https://learn.hashicorp.com/tutorials/consul/automate-geo-failover) for details and examples for using prepared queries to implement geo failover for services. diff --git a/website/content/commands/acl/token/create.mdx b/website/content/commands/acl/token/create.mdx index 189f7beac807..77128d700eff 100644 --- a/website/content/commands/acl/token/create.mdx +++ b/website/content/commands/acl/token/create.mdx @@ -76,10 +76,14 @@ Usage: `consul acl token create [options] [args]` ## Examples -Create a new token: +The following examples describe how to create ACL tokens for common scenarios. + +### Create a token with policy by name + +The following example creates a token that includes a policy by its name. ```shell-session -$ consul acl token create -description "Read Nodes and Services" -policy-id 06acc965 +$ consul acl token create -description "Read Nodes and Services" -policy-name node-services-read AccessorID: 986193b5-e2b5-eb26-6264-b524ea60cc6d SecretID: ec15675e-2999-d789-832e-8c4794daa8d7 Description: Read Nodes and Services @@ -89,42 +93,54 @@ Policies: 06acc965-df4b-5a99-58cb-3250930c6324 - node-services-read ``` -Create a new local token: +### Create a token for a service + +The following example creates a token with the privileges necessary +for registering a service named `my-api`. +If `my-api` is in the service mesh, the token also has the privileges necessary +to register its associated sidecar proxy and must be provided to the proxy when +launched with [`consul connect envoy`](/consul/commands/connect/envoy#sidecar-proxy-with-acls-enabled). ```shell-session -$ consul acl token create -description "Read Nodes and Services" -policy-id 06acc965 -local -AccessorID: 4fdf0ec8-d251-3865-079c-7247c974fc50 -SecretID: 02143514-abf2-6c23-0aa1-ec2107e68f6b -Description: Read Nodes and Services -Local: true -Create Time: 2018-10-22 15:34:19.330265 -0400 EDT -Policies: - 06acc965-df4b-5a99-58cb-3250930c6324 - node-services-read +$ consul acl token create -description 'my-api token' -service-identity 'my-api' +AccessorID: 0c083aca-6c15-f0cc-c4d9-30578db54cd9 +SecretID: 930dafb6-5c08-040b-23fb-a368a95256f9 +Description: api token +Local: false +Create Time: 2019-04-25 16:45:49.337687334 -0500 CDT +Service Identities: + my-api (Datacenters: all) ``` -Create a new token and link with policies by name: +### Create a temporary and highly-privileged token + +The following example creates a token with a lifetime of 15 minutes that +includes the built-in [`global-management` policy](/consul/docs/security/acl/acl-policies#global-management). ```shell-session -$ consul acl token create -description "Super User" -policy-name global-management +$ consul acl token create -description "Temp Super User" -policy-name global-management -expires-ttl '15m' AccessorID: 59f86a9b-d3b6-166c-32a0-be4ab3f94caa SecretID: ada7f751-f654-8872-7f93-498e799158b6 -Description: Super User +Description: Temp Super User Local: false -Create Time: 2018-10-22 15:35:28.787003 -0400 EDT +Create Time: 2019-04-25 16:45:49.337687334 -0500 CDT +Expiration Time: 2019-04-25 17:00:49.337687334 -0500 CDT Policies: 00000000-0000-0000-0000-000000000001 - global-management ``` -Create a new token with one service identity that expires in 15 minutes: +### Create a local token with policy by ID + +The following example creates a token that is only valid in this datacenter +and includes a policy by its UUID. ```shell-session -$ consul acl token create -description 'crawler token' -service-identity 'crawler' -expires-ttl '15m' -AccessorID: 0c083aca-6c15-f0cc-c4d9-30578db54cd9 -SecretID: 930dafb6-5c08-040b-23fb-a368a95256f9 -Description: crawler token -Local: false -Create Time: 2019-04-25 16:45:49.337687334 -0500 CDT -Expiration Time: 2019-04-25 17:00:49.337687334 -0500 CDT -Service Identities: - crawler (Datacenters: all) +$ consul acl token create -description "Read Nodes and Services" -policy-id 06acc965 -local +AccessorID: 986193b5-e2b5-eb26-6264-b524ea60cc6d +SecretID: ec15675e-2999-d789-832e-8c4794daa8d7 +Description: Read Nodes and Services +Local: true +Create Time: 2018-10-22 15:33:39.01789 -0400 EDT +Policies: + 06acc965-df4b-5a99-58cb-3250930c6324 - node-services-read ``` diff --git a/website/content/commands/connect/ca.mdx b/website/content/commands/connect/ca.mdx index e571258f5a62..587d4379c516 100644 --- a/website/content/commands/connect/ca.mdx +++ b/website/content/commands/connect/ca.mdx @@ -97,6 +97,13 @@ Configuration updated! The return code will indicate success or failure. +~> **If currently using Vault CA provider:** + If you intend to change the CA provider from Vault to another, + or to change the Vault provider's [`RootPKIPath`](/docs/connect/ca/vault#rootpkipath), + you must temporarily elevate the privileges of the Vault token + or auth method in use as described in the + [Vault CA provider documentation](/docs/connect/ca/vault#additional-vault-acl-policies-for-sensitive-operations). + #### Command Options - `-config-file` - (required) Specifies a JSON-formatted file to use for the new configuration. @@ -104,10 +111,13 @@ The return code will indicate success or failure. [Update CA Configuration API](/api-docs/connect/ca#update-ca-configuration). - `-force-without-cross-signing` `(bool: )` - Indicates that the CA change - should be forced to complete even if the current CA doesn't support cross - signing. Changing root without cross-signing may cause temporary connection - failures until the rollout completes. See [Forced Rotation Without - Cross-Signing](/docs/connect/ca#forced-rotation-without-cross-signing) + should be forced to complete even if the current CA doesn't support root cross-signing. + + ~> **Caution:** Use of this flag will cause temporary connection failures + until service mesh proxies and/or Consul client agents receive a new certificate + that establishes trust with the new root. + Do not use this flag unless you are sure you need it. + Refer to [Forced Rotation Without Cross-Signing](/docs/connect/ca#forced-rotation-without-cross-signing) for more detail. #### API Options diff --git a/website/content/commands/connect/envoy.mdx b/website/content/commands/connect/envoy.mdx index 83db635c33dc..55251d2f17bd 100644 --- a/website/content/commands/connect/envoy.mdx +++ b/website/content/commands/connect/envoy.mdx @@ -13,6 +13,10 @@ The connect Envoy command is used to generate a bootstrap configuration for [Envoy proxy](https://envoyproxy.io) for use with [Consul Connect](/docs/connect/). +Refer to the [examples](#examples) for guidance on common use cases, +such as [launching a service instance's sidecar proxy +when ACLs are enabled](#sidecar-proxy-with-acls-enabled). + The default behavior is to generate the necessary bootstrap configuration for Envoy based on the environment variables and options provided and by talking to the local Consul agent. It `exec`s an external Envoy binary with that @@ -57,12 +61,32 @@ Usage: `consul connect envoy [options] [-- pass-through options]` - `-envoy-version` - The version of envoy that is being started. Default is `1.23.1`. This is required so that the correct configuration can be generated. +- `-grpc-ca-file` - Path to a CA file to use for TLS when communicating with the + Consul agent through xDS. This can also be specified via the CONSUL_GRPC_CACERT + environment variable. + +- `-grpc-ca-path` - Path to a directory of CA certificates to use for TLS when + communicating with the Consul agent through xDS. This can also be specified via + the CONSUL_GRPC_CAPATH environment variable. + - `-no-central-config` - By default the proxy's bootstrap configuration can be customized centrally. This requires that the command run on the same agent as the proxy will and that the agent is reachable when the command is run. In cases where either assumption is violated this flag will prevent the command attempting to resolve config from the local agent. +- `-envoy-ready-bind-address` - By default the proxy does not have a readiness probe + configured on it. This flag in conjunction with the `envoy-ready-bind-port` flag + configures where the envoy readiness probe is configured on the proxy. A `/ready` HTTP + endpoint will be instantiated at the specified address and port. When configured, Consul + uses `/ready` HTTP endpoints to check proxy health. + +- `-envoy-ready-bind-port` - By default the proxy does not have a readiness probe + configured on it. This flag in conjunction with the `envoy-ready-bind-address` flag + configures where the envoy readiness probe is configured on the proxy. A `/ready` HTTP + endpoint will be instantiated at the specified address and port. When configured, Consul + uses `/ready` HTTP endpoints to check proxy health. + - `-prometheus-backend-port` - Sets the backend port for the "prometheus_backend" cluster that `envoy_prometheus_bind_addr` will point to. Without this flag, `envoy_prometheus_bind_addr` would point to the "self_admin" cluster where Envoy metrics @@ -98,6 +122,8 @@ Usage: `consul connect envoy [options] [-- pass-through options]` always specifies `--config-file` and `--v2-config-only` and by default passes `--disable-hot-restart` see [hot restart](#envoy-hot-restart). +- `-enable-config-gen-logging` - This flag enables debug message logging when generating the Envoy bootstrap configuration to help troubleshoot issues. Logs output to `stderr`. For more information about generating the Envoy bootstrap configuration, refer to [Envoy proxy configuration](/consul/docs/connect/proxies/envoy#bootstrap-configuration). + #### Envoy Sidecar Proxy Options - `-sidecar-for` - The _ID_ (not name if they differ) of the service instance @@ -207,7 +233,7 @@ service { } ``` -### Basic Sidecar Proxy +### Basic sidecar proxy The sidecar Envoy process can be started with. @@ -219,6 +245,32 @@ This example assumes that the correct [environment variables](#api-options) are used to set the local agent connection information and ACL token, or that the agent is using all-default configuration. +### Sidecar proxy with ACLs enabled + +In secure deployments, Consul's ACL system is enabled with a default `deny` policy. +To access Consul API resources, an API request must present a Consul ACL token +with the necessary privileges. If ACLs are enabled, you must provide an ACL token to the sidecar proxy. The token must grant the proxy privileges to register itself and the service it fronts and to access all potential upstreams of that service. +We recommend [using a service identity](/consul/commands/acl/token/create#create-a-token-for-a-service) +to directly create a token with the privileges necessary for a service and its sidecar proxy, +rather than creating a unique ACL policy for every service. + +After creating a token using a service identity, provide the token when +launching the Envoy sidecar proxy instance with the `consul connect envoy` command. +You can provide the token through an environment variable or CLI flag. + +Environment variables: +- [`CONSUL_HTTP_TOKEN`](/consul/commands#consul_http_token) or +- [`CONSUL_HTTP_TOKEN_FILE`](/consul/commands#consul_http_token_file) + +CLI flags: +- [`-token`](/consul/commands/connect/envoy#token) or +- [`-token-file`](/consul/commands/connect/envoy#token-file) + +```shell-session +$ export CONSUL_HTTP_TOKEN="" +$ consul connect envoy -sidecar-for web +``` + ### Additional Envoy Arguments To pass additional arguments directly to Envoy, for example output logging diff --git a/website/content/commands/connect/redirect-traffic.mdx b/website/content/commands/connect/redirect-traffic.mdx index 688429bfb56f..aa87e69ef9f6 100644 --- a/website/content/commands/connect/redirect-traffic.mdx +++ b/website/content/commands/connect/redirect-traffic.mdx @@ -36,6 +36,8 @@ Usage: `consul connect redirect-traffic [options]` - `-consul-dns-ip` - The IP address of the Consul DNS resolver. If provided, DNS queries will be redirected to the provided IP address for name resolution. +- `-consul-dns-port` - The port of the Consul DNS resolver. If provided, DNS queries will be redirected to the provided IP address for name resolution. + - `-proxy-id` - The [proxy service](/docs/connect/registration/service-registration) ID. This service ID must already be registered with the local agent. diff --git a/website/content/commands/debug.mdx b/website/content/commands/debug.mdx index 202fefd747cd..7402cf24c8a3 100644 --- a/website/content/commands/debug.mdx +++ b/website/content/commands/debug.mdx @@ -43,12 +43,12 @@ or otherwise. `Usage: consul debug [options]` By default, the debug command will capture an archive at the current path for -all targets for 2 minutes. +all targets for 5 minutes. #### Command Options - `-duration` - Optional, the total time to capture data for from the target agent. Must - be greater than the interval and longer than 10 seconds. Defaults to 2 minutes. + be greater than the interval and longer than 10 seconds. Defaults to 5 minutes. - `-interval` - Optional, the interval at which to capture dynamic data, such as heap and metrics. Must be longer than 5 seconds. Defaults to 30 seconds. @@ -77,7 +77,7 @@ information when `debug` is running. By default, it captures all information. | `host` | Information about resources on the host running the target agent such as CPU, memory, and disk. | | `members` | A list of all the WAN and LAN members in the cluster. | | `metrics` | Metrics from the in-memory metrics endpoint in the target, captured at the interval. | -| `logs` | `DEBUG` level logs for the target agent, captured for the duration. | +| `logs` | `TRACE` level logs for the target agent, captured for the duration. | | `pprof` | Golang heap, CPU, goroutine, and trace profiling. CPU and traces are captured for `duration` in a single file while heap and goroutine are separate snapshots for each `interval`. This information is not retrieved unless [`enable_debug`](/docs/agent/config/config-files#enable_debug) is set to `true` on the target agent or ACLs are enable and an ACL token with `operator:read` is provided. | ## Examples diff --git a/website/content/commands/intention/check.mdx b/website/content/commands/intention/check.mdx index 8fc7a48706a6..e5cb6b06eeeb 100644 --- a/website/content/commands/intention/check.mdx +++ b/website/content/commands/intention/check.mdx @@ -34,7 +34,7 @@ are not supported from commands, but may be from the corresponding HTTP endpoint

    1 Intention ACL rules are specified as part of a{' '} service rule. See{' '} - + Intention Management Permissions {' '} for more details. diff --git a/website/content/commands/intention/create.mdx b/website/content/commands/intention/create.mdx index b81ba49dfae1..851b42144ddf 100644 --- a/website/content/commands/intention/create.mdx +++ b/website/content/commands/intention/create.mdx @@ -28,7 +28,7 @@ are not supported from commands, but may be from the corresponding HTTP endpoint

    1 Intention ACL rules are specified as part of a{' '} service rule. See{' '} - + Intention Management Permissions {' '} for more details. diff --git a/website/content/commands/intention/delete.mdx b/website/content/commands/intention/delete.mdx index 136e5e5ae891..ed648c2c2579 100644 --- a/website/content/commands/intention/delete.mdx +++ b/website/content/commands/intention/delete.mdx @@ -22,7 +22,7 @@ are not supported from commands, but may be from the corresponding HTTP endpoint

    1 Intention ACL rules are specified as part of a{' '} service rule. See{' '} - + Intention Management Permissions {' '} for more details. diff --git a/website/content/commands/intention/get.mdx b/website/content/commands/intention/get.mdx index 3da1688f6ec3..55e4f0c2ce2d 100644 --- a/website/content/commands/intention/get.mdx +++ b/website/content/commands/intention/get.mdx @@ -27,7 +27,7 @@ are not supported from commands, but may be from the corresponding HTTP endpoint

    1 Intention ACL rules are specified as part of a{' '} service rule. See{' '} - + Intention Management Permissions {' '} for more details. diff --git a/website/content/commands/intention/list.mdx b/website/content/commands/intention/list.mdx index 9748494b8fa0..f0091dfb2328 100644 --- a/website/content/commands/intention/list.mdx +++ b/website/content/commands/intention/list.mdx @@ -22,7 +22,7 @@ are not supported from commands, but may be from the corresponding HTTP endpoint

    1 Intention ACL rules are specified as part of a{' '} service rule. See{' '} - + Intention Management Permissions {' '} for more details. diff --git a/website/content/commands/intention/match.mdx b/website/content/commands/intention/match.mdx index ee41469249b3..d2de07949004 100644 --- a/website/content/commands/intention/match.mdx +++ b/website/content/commands/intention/match.mdx @@ -27,7 +27,7 @@ are not supported from commands, but may be from the corresponding HTTP endpoint

    1 Intention ACL rules are specified as part of a{' '} service rule. See{' '} - + Intention Management Permissions {' '} for more details. diff --git a/website/content/commands/license.mdx b/website/content/commands/license.mdx index 4a4887cf8c9c..393b212d67b8 100644 --- a/website/content/commands/license.mdx +++ b/website/content/commands/license.mdx @@ -167,7 +167,8 @@ Licensed Features: Corresponding HTTP API Endpoint: [\[GET\] /v1/operator/license](/api-docs/operator/license#getting-the-consul-license) -This command gets the Consul Enterprise license. +This command gets the Consul Enterprise license. If the leader hasn't been updated with the newer license, the followers +will display the outdated license in their GET output. The table below shows this command's [required ACLs](/api-docs/api-structure#authentication). Configuration of [blocking queries](/api-docs/features/blocking) and [agent caching](/api-docs/features/caching) diff --git a/website/content/commands/lock.mdx b/website/content/commands/lock.mdx index 8abf4c12cdd7..fb80f6554776 100644 --- a/website/content/commands/lock.mdx +++ b/website/content/commands/lock.mdx @@ -24,6 +24,8 @@ If the lock holder count is more than one, then a semaphore is used instead. A semaphore allows more than a single holder, but this is less efficient than a simple lock. This follows the [semaphore algorithm](https://learn.hashicorp.com/consul/developer-configuration/semaphore). +To apply a lock to a remote WAN federated datacenter, run the command with the `-datacenter=` flag on a server agent. You cannot use the command with `-datacenter` on client agents because they are unavailable to the remote datacenter. + All locks using the same prefix must agree on the value of `-n`. If conflicting values of `-n` are provided, an error will be returned. diff --git a/website/content/commands/members.mdx b/website/content/commands/members.mdx index a8dd69d1fcf2..c94ceea1fac5 100644 --- a/website/content/commands/members.mdx +++ b/website/content/commands/members.mdx @@ -48,6 +48,12 @@ Usage: `consul members [options]` in the WAN gossip pool. These are generally all the server nodes in each datacenter. +- `-filter=` - Expression to use for filtering the results, + e.g., `-filter='Tags["dc"] == dc2'`. + See the [`/catalog/nodes` API documentation](/consul/api-docs/catalog#filtering) for a + description of what is filterable. + + #### Enterprise Options @include 'http_api_partition_options.mdx' diff --git a/website/content/commands/operator/index.mdx b/website/content/commands/operator/index.mdx index af34e1814399..02318fb5fbc6 100644 --- a/website/content/commands/operator/index.mdx +++ b/website/content/commands/operator/index.mdx @@ -20,7 +20,7 @@ order to use this command. Requests are forwarded internally to the leader if required, so this can be run from any Consul node in a cluster. See the [ACL Guide](https://learn.hashicorp.com/tutorials/consul/access-control-setup-production) for more information. -See the [Outage Recovery](https://learn.hashicorp.com/tutorials/consul/recovery-outage) guide for some examples of how +See the [Disaster recovery for Consul clusters](/consul/tutorials/datacenter-operations/recovery-outage) guide for some examples of how this command is used. For an API to perform these operations programmatically, please see the documentation for the [Operator](/api-docs/operator) endpoint. diff --git a/website/content/commands/operator/raft.mdx b/website/content/commands/operator/raft.mdx index b6a10dab6e68..5c2ee9974f2a 100644 --- a/website/content/commands/operator/raft.mdx +++ b/website/content/commands/operator/raft.mdx @@ -46,10 +46,10 @@ Usage: `consul operator raft list-peers -stale=[true|false]` The output looks like this: ```text -Node ID Address State Voter RaftProtocol -alice 127.0.0.1:8300 127.0.0.1:8300 follower true 2 -bob 127.0.0.2:8300 127.0.0.2:8300 leader true 3 -carol 127.0.0.3:8300 127.0.0.3:8300 follower true 2 +Node ID Address State Voter RaftProtocol Commit Index Trails Leader By +alice 127.0.0.1:8300 127.0.0.1:8300 follower true 2 1167 0 commits +bob 127.0.0.2:8300 127.0.0.2:8300 leader true 3 1167 - +carol 127.0.0.3:8300 127.0.0.3:8300 follower true 2 1159 8 commits ``` `Node` is the node name of the server, as known to Consul, or "(unknown)" if @@ -66,11 +66,15 @@ Raft configuration. `Voter` is "true" or "false", indicating if the server has a vote in the Raft configuration. +`Commit Index` is the last log index the server has a record of in its Raft log. + +`Trails Leader By` is the number of commits a follower trails the leader by. + #### Command Options - `-stale` - Enables non-leader servers to provide cluster state information. If the cluster is in an outage state without a leader, - we recommend setting this option to `true. + we recommend setting this option to `true`. Default is `false`. ## remove-peer diff --git a/website/content/commands/peering/generate-token.mdx b/website/content/commands/peering/generate-token.mdx index a4a99392ffcd..60aec62f1c91 100644 --- a/website/content/commands/peering/generate-token.mdx +++ b/website/content/commands/peering/generate-token.mdx @@ -34,6 +34,10 @@ If the previously-generated token is not actively being used for a peer connecti - `-meta==` - Specifies key/value pairs to associate with the peering connection token in `-meta="key"="value"` format. You can use the flag multiple times to set multiple metadata fields. +- `-server-external-addresses=[,string,...]` - Specifies a comma-separated list of addresses +to put into the generated token. Addresses are of the form of `{host or IP}:port`. +You can specify one or more load balancers or external IPs that route external traffic to this cluster's Consul servers. + - `-format={pretty|json}` - Command output format. The default value is `pretty`. #### Enterprise Options @@ -52,3 +56,12 @@ The following example generates a peering token for a cluster called "cluster-02 $ consul peering generate-token -name cluster-02 eyJDQSI6bnVs...5Yi0wNzk5NTA1YTRmYjYifQ== ``` + +### Using a Load Balancer for Consul Servers + +The following example generates a token for a cluster where servers are proxied by a load balancer: + +```shell-session hideClipboard +$ consul peering generate-token -server-external-addresses my-load-balancer-1234567890abcdef.elb.us-east-2.amazonaws.com -name cluster-02 +eyJDQSI6bnVs...5Yi0wNzk5NTA1YTRmYjYifQ== +``` diff --git a/website/content/commands/services/deregister.mdx b/website/content/commands/services/deregister.mdx index c143620955a5..f417579d4370 100644 --- a/website/content/commands/services/deregister.mdx +++ b/website/content/commands/services/deregister.mdx @@ -11,23 +11,19 @@ Corresponding HTTP API Endpoint: [\[PUT\] /v1/agent/service/deregister/:service_ The `services deregister` command deregisters a service with the local agent. Note that this command can only deregister services that were registered -with the agent specified (defaults to the local agent) and is meant to -be paired with `services register`. +with the agent specified and is intended to be paired with `services register`. +By default, the command deregisters services on the local agent. -This is just one method for service deregistration. If the service was -registered with a configuration file, then deleting that file and -[reloading](/commands/reload) Consul is the correct method to -deregister. See [Service Definition](/docs/discovery/services) for more -information about registering services generally. +We recommend deregistering services registered with a configuration file by deleting the file and [reloading](/consul/commands/reload) Consul. Refer to [Services Overview](/consul/docs/services/services) for additional information about services. -The table below shows this command's [required ACLs](/api-docs/api-structure#authentication). Configuration of -[blocking queries](/api-docs/features/blocking) and [agent caching](/api-docs/features/caching) -are not supported from commands, but may be from the corresponding HTTP endpoint. +The following table shows the [ACLs](/consul/api-docs/api-structure#authentication) required to run the `consul services deregister` command: | ACL Required | | --------------- | | `service:write` | +You cannot use the Consul command line to configure [blocking queries](/consul/api-docs/features/blocking) and [agent caching](/consul/api-docs/features/caching), you can configure them from the corresponding HTTP endpoint. + ## Usage Usage: `consul services deregister [options] [FILE...]` diff --git a/website/content/commands/services/register.mdx b/website/content/commands/services/register.mdx index 68d3f6deab16..f472b249414b 100644 --- a/website/content/commands/services/register.mdx +++ b/website/content/commands/services/register.mdx @@ -12,24 +12,16 @@ Corresponding HTTP API Endpoint: [\[PUT\] /v1/agent/service/register](/api-docs/ The `services register` command registers a service with the local agent. This command returns after registration and must be paired with explicit service deregistration. This command simplifies service registration from -scripts, in dev mode, etc. +scripts. Refer to [Register Services and Health Checks](/consul/docs/services/usage/register-services-checks) for information about other service registeration methods. -This is just one method of service registration. Services can also be -registered by placing a [service definition](/docs/discovery/services) -in the Consul agent configuration directory and issuing a -[reload](/commands/reload). This approach is easiest for -configuration management systems that other systems that have access to -the configuration directory. Clients may also use the -[HTTP API](/api-docs/agent/service) directly. - -The table below shows this command's [required ACLs](/api-docs/api-structure#authentication). Configuration of -[blocking queries](/api-docs/features/blocking) and [agent caching](/api-docs/features/caching) -are not supported from commands, but may be from the corresponding HTTP endpoint. +The following table shows the [ACLs](/consul/api-docs/api-structure#authentication) required to use the `consul services register` command: | ACL Required | | --------------- | | `service:write` | +You cannot use the Consul command line to configure [blocking queries](/consul/api-docs/features/blocking) and [agent caching](/consul/api-docs/features/caching), you can configure them from the corresponding HTTP endpoint. + ## Usage Usage: `consul services register [options] [FILE...]` @@ -63,9 +55,7 @@ The flags below should only be set if _no arguments_ are given. If no arguments are given, the flags below can be used to register a single service. -Note that the behavior of each of the fields below is exactly the same -as when constructing a standard [service definition](/docs/discovery/services). -Please refer to that documentation for full details. +The following fields specify identical parameters in a standard service definition file. Refer to [Services Configuration Reference](/consul/docs/services/configuration/services-configuration-reference) for details about each configuration option. - `-id` - The ID of the service. This will default to `-name` if not set. diff --git a/website/content/commands/snapshot/agent.mdx b/website/content/commands/snapshot/agent.mdx index b82152f97ec5..4ff46dee3841 100644 --- a/website/content/commands/snapshot/agent.mdx +++ b/website/content/commands/snapshot/agent.mdx @@ -170,6 +170,12 @@ Usage: `consul snapshot agent [options]` "aws_storage": { "access_key_id": "", "secret_access_key": "", + "session_token": "", + "iam_endpoint": "", + "role_arn": "", + "role_session_name": "", + "web_identity_token_file": "", + "sts_endpoint": "", "s3_region": "", "s3_bucket": "", "s3_key_prefix": "consul-snapshot", @@ -265,16 +271,30 @@ if desired. Note that despite the AWS references, any S3-compatible endpoint can be specified with `-aws-s3-endpoint`. -- `-aws-access-key-id` and `-aws-secret-access-key` - These arguments supply +- `-aws-access-key-id`, `-aws-secret-access-key` and `-aws-session-token` - These arguments supply static authentication information for connecting to S3. These may also be supplied using the following alternative methods:
    - - `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables + - `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and `AWS_SESSION_TOKEN` environment variables - A credentials file (`~/.aws/credentials` or the file at the path specified by the `AWS_SHARED_CREDENTIALS_FILE` environment variable) - ECS task role metadata (container-specific) - EC2 instance role metadata +- `-aws-iam-endpoint` - IAM endpoint to use when authenticating with static credentials. + Default is to use the global IAM endpoint. + +- `-aws-role-arn`, `-aws-role-session-name`, and `-aws-web-identity-token-file` - These arguments are + used to obtain temporary credentials by assuming an IAM role. These may also be supplied using + the following alternative methods:
    + + - `AWS_ROLE_ARN`, `AWS_ROLE_SESSION_NAME`, and `AWS_WEB_IDENTITY_TOKEN_FILE` environment variables. + - A credentials file (~/.aws/credentials or the file at the path specified by the + `AWS_SHARED_CREDENTIALS_FILE` environment variable) + +- `-aws-sts-endpoint` - STS endpoint to use for obtaining temporary credentials. + Default is to use the global STS endpoint. + - `-aws-s3-bucket` - S3 bucket to use. Required for S3 storage, and setting this disables local storage. This should be only the bucket name without any part of the key prefix. @@ -284,8 +304,8 @@ Note that despite the AWS references, any S3-compatible endpoint can be specifie - `-aws-s3-region` - S3 region to use. Required for S3 storage. -- `-aws-s3-endpoint` - Optional S3 endpoint to use. Can also be specified using the - AWS_S3_ENDPOINT environment variable. +- `-aws-s3-endpoint` - S3 endpoint to use. Can also be specified using the + `AWS_S3_ENDPOINT` environment variable. Defaults to the regional S3 endpoint. - `-aws-s3-server-side-encryption` - Enables saving snapshots to S3 using server side encryption with [Amazon S3-Managed Encryption Keys](http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingServerSideEncryption.html) diff --git a/website/content/commands/snapshot/save.mdx b/website/content/commands/snapshot/save.mdx index 6ecf82293765..cfb6241e78c8 100644 --- a/website/content/commands/snapshot/save.mdx +++ b/website/content/commands/snapshot/save.mdx @@ -18,7 +18,8 @@ If ACLs are enabled, a management token must be supplied in order to perform a snapshot save. -> Note that saving a snapshot involves the server process writing the snapshot to a -temporary file on-disk before sending that file to the CLI client. The default location +temporary file on-disk before sending that file to the CLI client. Upon successful completion, +Consul removes the temporary file. The default location of the temporary file can vary depending on operating system, but typically is `/tmp`. You can get more detailed information on default locations in the Go documentation for [os.TempDir](https://golang.org/pkg/os/#TempDir). If you need to change this location, you can do so by setting the `TMPDIR` environment @@ -26,6 +27,7 @@ variable for the Consul server processes. Keep in mind that setting the environm the CLI client attempting to perform a snapshot save will have no effect. It _must_ be set in the context of the server process. If you're using Systemd to manage your Consul server processes, then adding `Environment=TMPDIR=/path/to/dir` to your Consul unit file will work. +As a result of the Raft snapshot, Consul also saves one snapshot file at `data_dir/raft/snapshots`. The table below shows this command's [required ACLs](/api-docs/api-structure#authentication). Configuration of [blocking queries](/api-docs/features/blocking) and [agent caching](/api-docs/features/caching) @@ -45,6 +47,10 @@ Usage: `consul snapshot save [options] FILE` @include 'http_api_options_server.mdx' +- `-append-filename=` - Value can be - version,dc,node,status +Adds consul version, datacenter name, node name, and status (leader/follower) +to the file name before the extension separated by `-` + ## Examples To create a snapshot from the leader server and save it to "backup.snap": @@ -73,5 +79,16 @@ This is useful for situations where a cluster is in a degraded state and no leader is available. To target a specific server for a snapshot, you can run the `consul snapshot save` command on that specific server. -Please see the [HTTP API](/api-docs/snapshot) documentation for +To create snapshot file with consul version and datacenter run + +```shell-session +$ consul snapshot save -append-filename version,dc backup.snap +#... +``` + +File name created will be like backup-%CONSUL_VERSION%-%DC_NAME%.snap +example - backup-1.17.0-dc1-local-machine-leader.tgz +Note Version is always the leader's consul version + +Please see the [HTTP API](/consul/api-docs/snapshot) documentation for more details about snapshot internals. diff --git a/website/content/docs/agent/config/cli-flags.mdx b/website/content/docs/agent/config/cli-flags.mdx index 8c480778d90d..a2261a690b58 100644 --- a/website/content/docs/agent/config/cli-flags.mdx +++ b/website/content/docs/agent/config/cli-flags.mdx @@ -92,7 +92,7 @@ information. only the given `-encrypt` key will be available on startup. This defaults to false. - `-enable-script-checks` ((#\_enable_script_checks)) This controls whether - [health checks that execute scripts](/docs/discovery/checks) are enabled on this + [health checks that execute scripts](/consul/docs/services/usage/checks) are enabled on this agent, and defaults to `false` so operators must opt-in to allowing these. This was added in Consul 0.9.0. @@ -157,8 +157,8 @@ information. - `-segment` ((#\_segment)) - This flag is used to set the name of the network segment the agent belongs to. An agent can only join and communicate with other agents within its network segment. Ensure the [join - operation uses the correct port for this segment](/docs/enterprise/network-segments#join_a_client_to_a_segment). - Review the [Network Segments documentation](/docs/enterprise/network-segments) + operation uses the correct port for this segment](/consul/docs/enterprise/network-segments/create-network-segment#configure-clients-to-join-segments). + Review the [Network Segments documentation](/consul/docs/enterprise/network-segments/create-network-segment) for more details. By default, this is an empty string, which is the `` network segment. @@ -335,13 +335,9 @@ information. [go-sockaddr] template that is resolved at runtime. - If Consul is running on the non-default Serf LAN port, the port must - be specified in the join address, or configured as the agent's default Serf port - using the [`ports.serf_lan`](/docs/agent/config/config-files#serf_lan_port) configuration option or - [`-serf-lan-port`](#_serf_lan_port) command line flag. + If Consul is running on a non-default Serf LAN port, you must specify the port number in the address when using the `-retry-join` flag. Alternatively, you can specify the custom port number as the default in the agent's [`ports.serf_lan`](/docs/agent/config/config-files#serf_lan_port) configuration or with the [`-serf-lan-port`](#_serf_lan_port) command line flag when starting the agent. - If using network segments (Enterprise), see [additional documentation on - joining a client to a segment](/docs/enterprise/network-segments#join_a_client_to_a_segment). + If your network contains network segments, refer to the [network segements documentation](/docs/enterprise/network-segments/create-network-segment) for additional information. Here are some examples of using `-retry-join`: @@ -403,8 +399,8 @@ information. - `-retry-interval` ((#\_retry_interval)) - Time to wait between join attempts. Defaults to 30s. -- `-retry-max` ((#\_retry_max)) - The maximum number of [`-join`](#_join) - attempts to be made before exiting with return code 1. By default, this is set +- `-retry-max` ((#\_retry_max)) - The maximum number of join attempts if using + [`-retry-join`](#_retry_join) before exiting with return code 1. By default, this is set to 0 which is interpreted as infinite retries. - `-join-wan` ((#\_join_wan)) - Address of another wan agent to join upon @@ -482,6 +478,7 @@ information. - `-node` ((#\_node)) - The name of this node in the cluster. This must be unique within the cluster. By default this is the hostname of the machine. + The node name cannot contain whitespace or quotation marks. To query the node from DNS, the name must only contain alphanumeric characters and hyphens (`-`). - `-node-id` ((#\_node_id)) - Available in Consul 0.7.3 and later, this is a unique identifier for this node across all time, even if the name of the node @@ -512,7 +509,7 @@ information. the data directory. This is useful when running multiple Consul agents on the same host for testing. This defaults to false in Consul prior to version 0.8.5 and in 0.8.5 and later defaults to true, so you must opt-in for host-based IDs. Host-based - IDs are generated using [gopsutil](https://github.com/shirou/gopsutil/tree/master/v3/host), which + IDs are generated using [gopsutil](https://github.com/shirou/gopsutil/), which is shared with HashiCorp's [Nomad](https://www.nomadproject.io/), so if you opt-in to host-based IDs then Consul and Nomad will use information on the host to automatically assign the same ID in both systems. diff --git a/website/content/docs/agent/config/config-files.mdx b/website/content/docs/agent/config/config-files.mdx index 68a98503ee0d..4e365176aa32 100644 --- a/website/content/docs/agent/config/config-files.mdx +++ b/website/content/docs/agent/config/config-files.mdx @@ -7,6 +7,10 @@ description: >- # Agents Configuration File Reference ((#configuration_files)) +This topic describes the parameters for configuring Consul agents. For information about how to start Consul agents, refer to [Starting the Consul Agent](/consul/docs/agent#starting-the-consul-agent). + +## Overview + You can create one or more files to configure the Consul agent on startup. We recommend grouping similar configurations into separate files, such as ACL parameters, to make it easier to manage configuration changes. Using external files may be easier than @@ -18,13 +22,6 @@ easily readable and editable by both humans and computers. JSON formatted configuration consists of a single JSON object with multiple configuration keys specified within it. -Configuration files are used for more than just setting up the agent. -They are also used to provide check and service definitions that -announce the availability of system servers to the rest of the cluster. -These definitions are documented separately under [check configuration](/docs/discovery/checks) and -[service configuration](/docs/discovery/services) respectively. Service and check -definitions support being updated during a reload. - ```hcl @@ -66,15 +63,27 @@ telemetry { -# Configuration Key Reference ((#config_key_reference)) +### Time-to-live values + +Consul uses the Go `time` package to parse all time-to-live (TTL) values used in Consul agent configuration files. Specify integer and float values as a string and include one or more of the following units of time: --> **Note:** All the TTL values described below are parsed by Go's `time` package, and have the following -[formatting specification](https://golang.org/pkg/time/#ParseDuration): "A -duration string is a possibly signed sequence of decimal numbers, each with -optional fraction and a unit suffix, such as '300ms', '-1.5h' or '2h45m'. -Valid time units are 'ns', 'us' (or 'µs'), 'ms', 's', 'm', 'h'." +- `ns` +- `us` +- `µs` +- `ms` +- `s` +- `m` +- `h` -## General +Examples: + +- `'300ms'` +- `'1.5h'` +- `'2h45m'` + +Refer to the [formatting specification](https://golang.org/pkg/time/#ParseDuration) for additional information. + +## General parameters - `addresses` - This is a nested object that allows setting bind addresses. In Consul 1.0 and later these can be set to a space-separated list @@ -102,6 +111,7 @@ Valid time units are 'ns', 'us' (or 'µs'), 'ms', 's', 'm', 'h'." - `http` - The HTTP API. Defaults to `client_addr` - `https` - The HTTPS API. Defaults to `client_addr` - `grpc` - The gRPC API. Defaults to `client_addr` + - `grpc_tls` - The gRPC API with TLS. Defaults to `client_addr` - `alt_domain` Equivalent to the [`-alt-domain` command-line flag](/docs/agent/config/cli-flags#_alt_domain) @@ -556,7 +566,7 @@ Valid time units are 'ns', 'us' (or 'µs'), 'ms', 's', 'm', 'h'." The following sub-keys are available: - - `enabled` ((#peering_enabled)) (Defaults to `false`) Controls whether cluster peering is enabled. + - `enabled` ((#peering_enabled)) (Defaults to `true`) Controls whether cluster peering is enabled. When disabled, the UI won't show peering, all peering APIs will return an error, any peerings stored in Consul already will be ignored (but they will not be deleted), and all peering connections from other clusters will be rejected. This was added in Consul 1.13.0. @@ -607,14 +617,12 @@ Valid time units are 'ns', 'us' (or 'µs'), 'ms', 's', 'm', 'h'." - `grpc` ((#grpc_port)) - The gRPC API, -1 to disable. Default -1 (disabled). **We recommend using `8502` for `grpc`** as your conventional gRPC port number, as it allows some tools to work automatically. This parameter is set to `8502` by default when the agent runs - in `-dev` mode. The `grpc` port currently supports either plaintext or TLS traffic for - backwards-compatibility, but TLS support is deprecated and will be removed in a future - release. Refer to `grpc_tls` for more information on configuring a TLS-enabled port. - - `grpc_tls` ((#grpc_tls_port)) - The gRPC API with TLS connections, -1 to disable. Default -1 (disabled). - **We recommend using `8502` for `grpc_tls`** as your conventional gRPC port number, as it allows some + in `-dev` mode. The `grpc` port only supports plaintext traffic starting in Consul 1.14. + Refer to `grpc_tls` for more information on configuring a TLS-enabled port. + - `grpc_tls` ((#grpc_tls_port)) - The gRPC API with TLS connections, -1 to disable. gRPC_TLS is enabled by default on port 8503 for Consul servers. + **We recommend using `8503` for `grpc_tls`** as your conventional gRPC port number, as it allows some tools to work automatically. `grpc_tls` is always guaranteed to be encrypted. Both `grpc` and `grpc_tls` - can be configured at the same time, but they may not utilize the same port number. If both `grpc` and - `grpc_tls` are defined, then `grpc` will always be plaintext. This field was added in Consul 1.14. + can be configured at the same time, but they may not utilize the same port number. This field was added in Consul 1.14. - `serf_lan` ((#serf_lan_port)) - The Serf LAN port. Default 8301. TCP and UDP. Equivalent to the [`-serf-lan-port` command line flag](/docs/agent/config/cli-flags#_serf_lan_port). - `serf_wan` ((#serf_wan_port)) - The Serf WAN port. Default 8302. @@ -705,7 +713,7 @@ Valid time units are 'ns', 'us' (or 'µs'), 'ms', 's', 'm', 'h'." - `segments` - (Server agents only) This is a list of nested objects that specifies user-defined network segments, not including the `` segment, which is - created automatically. Review the [Network Segments documentation](/docs/enterprise/network-segments) + created automatically. Refer to the [network segments documentation](/docs/enterprise/network-segments/create-network-segment)for additional information. for more details. - `name` ((#segment_name)) - The name of the segment. Must be a string @@ -911,6 +919,27 @@ Valid time units are 'ns', 'us' (or 'µs'), 'ms', 's', 'm', 'h'." - `agent_master` ((#acl_tokens_agent_master)) **Renamed in Consul 1.11 to [`acl.tokens.agent_recovery`](#acl_tokens_agent_recovery).** + - `config_file_service_registration` ((#acl_tokens_config_file_service_registration)) - Specifies the ACL + token the agent uses to register services and checks from [service](/consul/docs/services/usage/define-services) and [check](/consul/docs/services/usage/checks) definitions + specified in configuration files or fragments passed to the agent using the `-hcl` + flag. + + If the `token` field is defined in the service or check definition, then that token is used to + register the service or check instead. If the `config_file_service_registration` token is not + defined and if the `token` field is not defined in the service or check definition, then the + agent uses the [`default`](#acl_tokens_default) token to register the service or check. + + This token needs write permission to register all services and checks defined in this agent's + configuration. For example, if there are two service definitions in the agent's configuration + files for services "A" and "B", then the token needs `service:write` permissions for both + services "A" and "B" in order to successfully register both services. If the token is missing + `service:write` permissions for service "B", the agent will successfully register service "A" + and fail to register service "B". Failed registration requests are eventually retried as part + of [anti-entropy enforcement](/consul/docs/architecture/anti-entropy). If a registration request is + failing due to missing permissions, the the token for this agent can be updated with + additional policy rules or the `config_file_service_registration` token can be replaced using + the [Set Agent Token](/consul/commands/acl/set-agent-token) CLI command. + - `replication` ((#acl_tokens_replication)) - The ACL token used to authorize secondary datacenters with the primary datacenter for replication operations. This token is required for servers outside the [`primary_datacenter`](#primary_datacenter) when ACLs are enabled. This token may be provided later using the [agent token API](/api-docs/agent#update-acl-tokens) on each server. This token must have at least "read" permissions on ACL data but if ACL token replication is enabled then it must have "write" permissions. This also enables Connect replication, for which the token will require both operator "write" and intention "read" permissions for replicating CA and Intention data. @@ -1061,7 +1090,7 @@ Valid time units are 'ns', 'us' (or 'µs'), 'ms', 's', 'm', 'h'." The following sub-keys are available: - - `enabled` ((#connect_enabled)) (Defaults to `false`) Controls whether Connect features are + - `enabled` ((#connect_enabled)) (Defaults to `true`) Controls whether Connect features are enabled on this agent. Should be enabled on all servers in the cluster in order for Connect to function properly. Will be set to `true` automatically if `auto_config.enabled` or `auto_encrypt.allow_tls` is `true`. @@ -1347,7 +1376,7 @@ Valid time units are 'ns', 'us' (or 'µs'), 'ms', 's', 'm', 'h'." of `1ns` instead of 0. - `prefer_namespace` ((#dns_prefer_namespace)) **Deprecated in Consul 1.11. - Use the [canonical DNS format for enterprise service lookups](/docs/discovery/dns#service-lookups-for-consul-enterprise) instead.** - + Use the [canonical DNS format for enterprise service lookups](/consul/docs/services/discovery/dns-static-lookups#service-lookups-for-consul-enterprise) instead.** - When set to `true`, in a DNS query for a service, a single label between the domain and the `service` label is treated as a namespace name instead of a datacenter. When set to `false`, the default, the behavior is the same as non-Enterprise @@ -1496,6 +1525,16 @@ Valid time units are 'ns', 'us' (or 'µs'), 'ms', 's', 'm', 'h'." part of the cluster before declaring it dead, giving that suspect node more time to refute if it is indeed still alive. The default is 6. +## Self-managed HCP Parameters + +- `cloud` This object specifies settings for connecting self-managed clusters to HCP. This was added in Consul 1.14 + + - `client_id` The OAuth2 client ID for authentication with HCP. This can be overridden using the `HCP_CLIENT_ID` environment variable. + + - `client_secret` The OAuth2 client secret for authentication with HCP. This can be overridden using the `HCP_CLIENT_SECRET` environment variable. + + - `resource_id` The HCP resource identifier. This can be overridden using the `HCP_RESOURCE_ID` environment variable. + ## Join Parameters - `rejoin_after_leave` Equivalent to the [`-rejoin` command-line flag](/docs/agent/config/cli-flags#_rejoin). @@ -1504,6 +1543,8 @@ Valid time units are 'ns', 'us' (or 'µs'), 'ms', 's', 'm', 'h'." - `retry_interval` Equivalent to the [`-retry-interval` command-line flag](/docs/agent/config/cli-flags#_retry_interval). +- `retry_max` - Equivalent to the [`-retry-max`](/docs/agent/config/cli-flags#_retry_max) command-line flag. + - `retry_join_wan` Equivalent to the [`-retry-join-wan` command-line flag](/docs/agent/config/cli-flags#_retry_join_wan). Takes a list of addresses to attempt joining to WAN every [`retry_interval_wan`](#_retry_interval_wan) until at least one join works. - `retry_interval_wan` Equivalent to the [`-retry-interval-wan` command-line flag](/docs/agent/config/cli-flags#_retry_interval_wan). @@ -1985,8 +2026,8 @@ specially crafted certificate signed by the CA can be used to gain full access t - `tls_cipher_suites` ((#tls_defaults_tls_cipher_suites)) This specifies the list of supported ciphersuites as a comma-separated-list. Applicable - to TLS 1.2 and below only. The list of all supported ciphersuites is - available through [this search](https://github.com/hashicorp/consul/search?q=goTLSCipherSuites+%3D+map). + to TLS 1.2 and below only. The list of all ciphersuites supported by Consul is + available in [the TLS configuration source code](https://github.com/hashicorp/consul/search?q=%22var+goTLSCipherSuites%22). ~> **Note:** The ordering of cipher suites will not be guaranteed from Consul 1.11 onwards. See this [post](https://go.dev/blog/tls-cipher-suites) @@ -2212,10 +2253,14 @@ default will automatically work with some tooling. - `xds`: This object allows you to configure the behavior of Consul's [xDS protocol](https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol) -server. +server. - `update_max_per_second`: Specifies the number of proxy configuration updates across all connected xDS streams that are allowed per second. This configuration prevents updates to global resources, such as wildcard intentions, from consuming system resources at the expense of other processes, such as Raft and Gossip, which could cause general cluster instability. - The default value is `250`. It is based on a load test of 5,000 streams connected to a single server with two CPU cores. + The default value is `250`. It is based on a load test of 5,000 streams connected to a single server with two CPU cores. + + If necessary, you can lower or increase the limit without a rolling restart by using the `consul reload` command or by sending the server a `SIGHUP`. + + - If necessary, you can lower or increase the limit without a rolling restart by using the `consul reload` command or by sending the server a `SIGHUP`. +[go-sockaddr]: https://godoc.org/github.com/hashicorp/go-sockaddr/template diff --git a/website/content/docs/agent/config/index.mdx b/website/content/docs/agent/config/index.mdx index ca9dbc33443b..18b875a20731 100644 --- a/website/content/docs/agent/config/index.mdx +++ b/website/content/docs/agent/config/index.mdx @@ -51,9 +51,12 @@ required ports and their default settings. ## Reloadable Configuration -Reloading configuration does not reload all configuration items. The -items which are reloaded include: +Some agent configuration options are reloadable at runtime. +You can run the [`consul reload` command](/commands/reload) to manually reload supported options from configuration files in the configuration directory. +To configure the agent to automatically reload configuration files updated on disk, +set the [`auto_reload_config` configuration option](/consul/docs/agent/config/config-files#auto_reload_config) parameter to `true`. +The following agent configuration options are reloadable at runtime: - ACL Tokens - [Configuration Entry Bootstrap](/docs/agent/config/config-files#config_entries_bootstrap) - Checks diff --git a/website/content/docs/agent/index.mdx b/website/content/docs/agent/index.mdx index 48f652a19ce9..2ff62cd0b8a0 100644 --- a/website/content/docs/agent/index.mdx +++ b/website/content/docs/agent/index.mdx @@ -316,7 +316,7 @@ tls { ### Client Node Registering a Service Using Consul as a central service registry is a common use case. -The following example configuration includes common settings to register a service with a Consul agent and enable health checks (see [Checks](/docs/discovery/checks) to learn more about health checks): +The following example configuration includes common settings to register a service with a Consul agent and enable health checks. Refer to [Define Health Checks](/consul/docs/services/usage/checks) to learn more about health checks. diff --git a/website/content/docs/agent/telemetry.mdx b/website/content/docs/agent/telemetry.mdx index 79ae6d9c146b..8c5acf03b26f 100644 --- a/website/content/docs/agent/telemetry.mdx +++ b/website/content/docs/agent/telemetry.mdx @@ -355,34 +355,34 @@ This is a full list of metrics emitted by Consul. | `consul.client.rpc` | Increments whenever a Consul agent in client mode makes an RPC request to a Consul server. This gives a measure of how much a given agent is loading the Consul servers. Currently, this is only generated by agents in client mode, not Consul servers. | requests | counter | | `consul.client.rpc.exceeded` | Increments whenever a Consul agent in client mode makes an RPC request to a Consul server gets rate limited by that agent's [`limits`](/docs/agent/config/config-files#limits) configuration. This gives an indication that there's an abusive application making too many requests on the agent, or that the rate limit needs to be increased. Currently, this only applies to agents in client mode, not Consul servers. | rejected requests | counter | | `consul.client.rpc.failed` | Increments whenever a Consul agent in client mode makes an RPC request to a Consul server and fails. | requests | counter | -| `consul.client.api.catalog_register.` | Increments whenever a Consul agent receives a catalog register request. | requests | counter | -| `consul.client.api.success.catalog_register.` | Increments whenever a Consul agent successfully responds to a catalog register request. | requests | counter | -| `consul.client.rpc.error.catalog_register.` | Increments whenever a Consul agent receives an RPC error for a catalog register request. | errors | counter | -| `consul.client.api.catalog_deregister.` | Increments whenever a Consul agent receives a catalog deregister request. | requests | counter | -| `consul.client.api.success.catalog_deregister.` | Increments whenever a Consul agent successfully responds to a catalog deregister request. | requests | counter | -| `consul.client.rpc.error.catalog_deregister.` | Increments whenever a Consul agent receives an RPC error for a catalog deregister request. | errors | counter | -| `consul.client.api.catalog_datacenters.` | Increments whenever a Consul agent receives a request to list datacenters in the catalog. | requests | counter | -| `consul.client.api.success.catalog_datacenters.` | Increments whenever a Consul agent successfully responds to a request to list datacenters. | requests | counter | -| `consul.client.rpc.error.catalog_datacenters.` | Increments whenever a Consul agent receives an RPC error for a request to list datacenters. | errors | counter | -| `consul.client.api.catalog_nodes.` | Increments whenever a Consul agent receives a request to list nodes from the catalog. | requests | counter | -| `consul.client.api.success.catalog_nodes.` | Increments whenever a Consul agent successfully responds to a request to list nodes. | requests | counter | -| `consul.client.rpc.error.catalog_nodes.` | Increments whenever a Consul agent receives an RPC error for a request to list nodes. | errors | counter | -| `consul.client.api.catalog_services.` | Increments whenever a Consul agent receives a request to list services from the catalog. | requests | counter | -| `consul.client.api.success.catalog_services.` | Increments whenever a Consul agent successfully responds to a request to list services. | requests | counter | -| `consul.client.rpc.error.catalog_services.` | Increments whenever a Consul agent receives an RPC error for a request to list services. | errors | counter | -| `consul.client.api.catalog_service_nodes.` | Increments whenever a Consul agent receives a request to list nodes offering a service. | requests | counter | -| `consul.client.api.success.catalog_service_nodes.` | Increments whenever a Consul agent successfully responds to a request to list nodes offering a service. | requests | counter | -| `consul.client.api.error.catalog_service_nodes.` | Increments whenever a Consul agent receives an RPC error for request to list nodes offering a service. | requests | counter | -| `consul.client.rpc.error.catalog_service_nodes.` | Increments whenever a Consul agent receives an RPC error for a request to list nodes offering a service.   | errors | counter | -| `consul.client.api.catalog_node_services.` | Increments whenever a Consul agent receives a request to list services registered in a node.   | requests | counter | -| `consul.client.api.success.catalog_node_services.` | Increments whenever a Consul agent successfully responds to a request to list services in a node.   | requests | counter | -| `consul.client.rpc.error.catalog_node_services.` | Increments whenever a Consul agent receives an RPC error for a request to list services in a node.   | errors | counter | +| `consul.client.api.catalog_register` | Increments whenever a Consul agent receives a catalog register request. | requests | counter | +| `consul.client.api.success.catalog_register` | Increments whenever a Consul agent successfully responds to a catalog register request. | requests | counter | +| `consul.client.rpc.error.catalog_register` | Increments whenever a Consul agent receives an RPC error for a catalog register request. | errors | counter | +| `consul.client.api.catalog_deregister` | Increments whenever a Consul agent receives a catalog deregister request. | requests | counter | +| `consul.client.api.success.catalog_deregister` | Increments whenever a Consul agent successfully responds to a catalog deregister request. | requests | counter | +| `consul.client.rpc.error.catalog_deregister` | Increments whenever a Consul agent receives an RPC error for a catalog deregister request. | errors | counter | +| `consul.client.api.catalog_datacenters` | Increments whenever a Consul agent receives a request to list datacenters in the catalog. | requests | counter | +| `consul.client.api.success.catalog_datacenters` | Increments whenever a Consul agent successfully responds to a request to list datacenters. | requests | counter | +| `consul.client.rpc.error.catalog_datacenters` | Increments whenever a Consul agent receives an RPC error for a request to list datacenters. | errors | counter | +| `consul.client.api.catalog_nodes` | Increments whenever a Consul agent receives a request to list nodes from the catalog. | requests | counter | +| `consul.client.api.success.catalog_nodes` | Increments whenever a Consul agent successfully responds to a request to list nodes. | requests | counter | +| `consul.client.rpc.error.catalog_nodes` | Increments whenever a Consul agent receives an RPC error for a request to list nodes. | errors | counter | +| `consul.client.api.catalog_services` | Increments whenever a Consul agent receives a request to list services from the catalog. | requests | counter | +| `consul.client.api.success.catalog_services` | Increments whenever a Consul agent successfully responds to a request to list services. | requests | counter | +| `consul.client.rpc.error.catalog_services` | Increments whenever a Consul agent receives an RPC error for a request to list services. | errors | counter | +| `consul.client.api.catalog_service_nodes` | Increments whenever a Consul agent receives a request to list nodes offering a service. | requests | counter | +| `consul.client.api.success.catalog_service_nodes` | Increments whenever a Consul agent successfully responds to a request to list nodes offering a service. | requests | counter | +| `consul.client.api.error.catalog_service_nodes` | Increments whenever a Consul agent receives an RPC error for request to list nodes offering a service. | requests | counter | +| `consul.client.rpc.error.catalog_service_nodes` | Increments whenever a Consul agent receives an RPC error for a request to list nodes offering a service.   | errors | counter | +| `consul.client.api.catalog_node_services` | Increments whenever a Consul agent receives a request to list services registered in a node.   | requests | counter | +| `consul.client.api.success.catalog_node_services` | Increments whenever a Consul agent successfully responds to a request to list services in a node.   | requests | counter | +| `consul.client.rpc.error.catalog_node_services` | Increments whenever a Consul agent receives an RPC error for a request to list services in a node.   | errors | counter | | `consul.client.api.catalog_node_service_list` | Increments whenever a Consul agent receives a request to list a node's registered services. | requests | counter | | `consul.client.rpc.error.catalog_node_service_list` | Increments whenever a Consul agent receives an RPC error for request to list a node's registered services. | errors | counter | | `consul.client.api.success.catalog_node_service_list` | Increments whenever a Consul agent successfully responds to a request to list a node's registered services. | requests | counter | -| `consul.client.api.catalog_gateway_services.` | Increments whenever a Consul agent receives a request to list services associated with a gateway. | requests | counter | -| `consul.client.api.success.catalog_gateway_services.` | Increments whenever a Consul agent successfully responds to a request to list services associated with a gateway. | requests | counter | -| `consul.client.rpc.error.catalog_gateway_services.` | Increments whenever a Consul agent receives an RPC error for a request to list services associated with a gateway. | errors | counter | +| `consul.client.api.catalog_gateway_services` | Increments whenever a Consul agent receives a request to list services associated with a gateway. | requests | counter | +| `consul.client.api.success.catalog_gateway_services` | Increments whenever a Consul agent successfully responds to a request to list services associated with a gateway. | requests | counter | +| `consul.client.rpc.error.catalog_gateway_services` | Increments whenever a Consul agent receives an RPC error for a request to list services associated with a gateway. | errors | counter | | `consul.runtime.num_goroutines` | Tracks the number of running goroutines and is a general load pressure indicator. This may burst from time to time but should return to a steady state value. | number of goroutines | gauge | | `consul.runtime.alloc_bytes` | Measures the number of bytes allocated by the Consul process. This may burst from time to time but should return to a steady state value. | bytes | gauge | | `consul.runtime.heap_objects` | Measures the number of objects allocated on the heap and is a general memory pressure indicator. This may burst from time to time but should return to a steady state value. | number of objects | gauge | @@ -396,8 +396,8 @@ This is a full list of metrics emitted by Consul. | `consul.members.clients` | Measures the current number of client agents registered with Consul. It is only emitted by Consul servers. Added in v1.9.6. | number of clients | gauge | | `consul.members.servers` | Measures the current number of server agents registered with Consul. It is only emitted by Consul servers. Added in v1.9.6. | number of servers | gauge | | `consul.dns.stale_queries` | Increments when an agent serves a query within the allowed stale threshold. | queries | counter | -| `consul.dns.ptr_query.` | Measures the time spent handling a reverse DNS query for the given node. | ms | timer | -| `consul.dns.domain_query.` | Measures the time spent handling a domain query for the given node. | ms | timer | +| `consul.dns.ptr_query` | Measures the time spent handling a reverse DNS query for the given node. | ms | timer | +| `consul.dns.domain_query` | Measures the time spent handling a domain query for the given node. | ms | timer | | `consul.system.licenseExpiration` | This measures the number of hours remaining on the agents license. | hours | gauge | | `consul.version` | Represents the Consul version. | agents | gauge | @@ -456,8 +456,8 @@ These metrics are used to monitor the health of the Consul servers. | `consul.raft.leader.oldestLogAge` | The number of milliseconds since the _oldest_ log in the leader's log store was written. This can be important for replication health where write rate is high and the snapshot is large as followers may be unable to recover from a restart if restoring takes longer than the minimum value for the current leader. Compare this with `consul.raft.fsm.lastRestoreDuration` and `consul.raft.rpc.installSnapshot` to monitor. In normal usage this gauge value will grow linearly over time until a snapshot completes on the leader and the log is truncated. Note: this metric won't be emitted until the leader writes a snapshot. After an upgrade to Consul 1.10.0 it won't be emitted until the oldest log was written after the upgrade. | ms | gauge | | `consul.raft.replication.heartbeat` | Measures the time taken to invoke appendEntries on a peer, so that it doesn't timeout on a periodic basis. | ms | timer | | `consul.raft.replication.appendEntries` | Measures the time it takes to replicate log entries to followers. This is a general indicator of the load pressure on the Consul servers, as well as the performance of the communication between the servers. | ms | timer | -| `consul.raft.replication.appendEntries.rpc` | Measures the time taken by the append entries RFC, to replicate the log entries of a leader agent onto its follower agent(s) | ms | timer | -| `consul.raft.replication.appendEntries.logs` | Measures the number of logs replicated to an agent, to bring it up to speed with the leader's logs. | logs appended/ interval | counter | +| `consul.raft.replication.appendEntries.rpc` | Measures the time taken by the append entries RPC to replicate the log entries of a leader agent onto its follower agent(s). | ms | timer | +| `consul.raft.replication.appendEntries.logs` | Counts the number of logs replicated to an agent to bring it up to speed with the leader's logs. | logs appended/ interval | counter | | `consul.raft.restore` | Counts the number of times the restore operation has been performed by the agent. Here, restore refers to the action of raft consuming an external snapshot to restore its state. | operation invoked / interval | counter | | `consul.raft.restoreUserSnapshot` | Measures the time taken by the agent to restore the FSM state from a user's snapshot | ms | timer | | `consul.raft.rpc.appendEntries` | Measures the time taken to process an append entries RPC call from an agent. | ms | timer | @@ -516,12 +516,12 @@ These metrics are used to monitor the health of the Consul servers. | `consul.leader.replication.namespaces.status` | This will only be emitted by the leader in a secondary datacenter. The value will be a 1 if the last round of namespace replication was successful or 0 if there was an error. | healthy | gauge | | `consul.leader.replication.namespaces.index` | This will only be emitted by the leader in a secondary datacenter. Increments to the index of namespaces in the primary datacenter that have been successfully replicated. | index | gauge | | `consul.prepared-query.apply` | Measures the time it takes to apply a prepared query update. | ms | timer | -| `consul.prepared-query.explain` | Measures the time it takes to process a prepared query explain request. | ms | timer | -| `consul.prepared-query.execute` | Measures the time it takes to process a prepared query execute request. | ms | timer | | `consul.prepared-query.execute_remote` | Measures the time it takes to process a prepared query execute request that was forwarded to another datacenter. | ms | timer | +| `consul.prepared-query.execute` | Measures the time it takes to process a prepared query execute request. | ms | timer | +| `consul.prepared-query.explain` | Measures the time it takes to process a prepared query explain request. | ms | timer | | `consul.rpc.raft_handoff` | Increments when a server accepts a Raft-related RPC connection. | connections | counter | -| `consul.rpc.request_error` | Increments when a server returns an error from an RPC request. | errors | counter | | `consul.rpc.request` | Increments when a server receives a Consul-related RPC request. | requests | counter | +| `consul.rpc.request_error` | Increments when a server returns an error from an RPC request. | errors | counter | | `consul.rpc.query` | Increments when a server receives a read RPC request, indicating the rate of new read queries. See consul.rpc.queries_blocking for the current number of in-flight blocking RPC calls. This metric changed in 1.7.0 to only increment on the the start of a query. The rate of queries will appear lower, but is more accurate. | queries | counter | | `consul.rpc.queries_blocking` | The current number of in-flight blocking queries the server is handling. | queries | gauge | | `consul.rpc.cross-dc` | Increments when a server sends a (potentially blocking) cross datacenter RPC query. | queries | counter | @@ -531,14 +531,14 @@ These metrics are used to monitor the health of the Consul servers. | `consul.session_ttl.invalidate` | Measures the time spent invalidating an expired session. | ms | timer | | `consul.txn.apply` | Measures the time spent applying a transaction operation. | ms | timer | | `consul.txn.read` | Measures the time spent returning a read transaction. | ms | timer | -| `consul.grpc.client.request.count` | Counts the number of gRPC requests made by the client agent to a Consul server. | requests | counter | -| `consul.grpc.client.connection.count` | Counts the number of new gRPC connections opened by the client agent to a Consul server. | connections | counter | -| `consul.grpc.client.connections` | Measures the number of active gRPC connections open from the client agent to any Consul servers. | connections | gauge | -| `consul.grpc.server.request.count` | Counts the number of gRPC requests received by the server. | requests | counter | -| `consul.grpc.server.connection.count` | Counts the number of new gRPC connections received by the server. | connections | counter | -| `consul.grpc.server.connections` | Measures the number of active gRPC connections open on the server. | connections | gauge | -| `consul.grpc.server.stream.count` | Counts the number of new gRPC streams received by the server. | streams | counter | -| `consul.grpc.server.streams` | Measures the number of active gRPC streams handled by the server. | streams | gauge | +| `consul.grpc.client.request.count` | Counts the number of gRPC requests made by the client agent to a Consul server. Includes a `server_type` label indicating either the `internal` or `external` gRPC server. | requests | counter | +| `consul.grpc.client.connection.count` | Counts the number of new gRPC connections opened by the client agent to a Consul server. Includes a `server_type` label indicating either the `internal` or `external` gRPC server. | connections | counter | +| `consul.grpc.client.connections` | Measures the number of active gRPC connections open from the client agent to any Consul servers. Includes a `server_type` label indicating either the `internal` or `external` gRPC server. | connections | gauge | +| `consul.grpc.server.request.count` | Counts the number of gRPC requests received by the server. Includes a `server_type` label indicating either the `internal` or `external` gRPC server. | requests | counter | +| `consul.grpc.server.connection.count` | Counts the number of new gRPC connections received by the server. Includes a `server_type` label indicating either the `internal` or `external` gRPC server. | connections | counter | +| `consul.grpc.server.connections` | Measures the number of active gRPC connections open on the server. Includes a `server_type` label indicating either the `internal` or `external` gRPC server. | connections | gauge | +| `consul.grpc.server.stream.count` | Counts the number of new gRPC streams received by the server. Includes a `server_type` label indicating either the `internal` or `external` gRPC server. | streams | counter | +| `consul.grpc.server.streams` | Measures the number of active gRPC streams handled by the server. Includes a `server_type` label indicating either the `internal` or `external` gRPC server. | streams | gauge | | `consul.xds.server.streams` | Measures the number of active xDS streams handled by the server split by protocol version. | streams | gauge | | `consul.xds.server.idealStreamsMax` | The maximum number of xDS streams per server, chosen to achieve a roughly even spread of load across servers. | streams | gauge | | `consul.xds.server.streamDrained` | Counts the number of xDS streams that are drained when rebalancing the load between servers. | streams | counter | diff --git a/website/content/docs/api-gateway/configuration/gatewayclassconfig.mdx b/website/content/docs/api-gateway/configuration/gatewayclassconfig.mdx index 15ae326b8f0e..2aba347737e5 100644 --- a/website/content/docs/api-gateway/configuration/gatewayclassconfig.mdx +++ b/website/content/docs/api-gateway/configuration/gatewayclassconfig.mdx @@ -20,7 +20,7 @@ The following outline shows how to format the configurations in the `GatewayClas * [`consul`](#consul): object | optional * [`address`](#consul-address): string | optional * [`authentication`](#consul-authentication): object | optional - * [`account`]([#consul-authentication-account): string | optional + * [`account`](#consul-authentication-account): string | optional * [`managed`](#consul-authentication-managed): bool | optional * [`method`](#consul-authentication-method): string | optional * [`namespace`](#consul-authentication-namespace): string | optional diff --git a/website/content/docs/api-gateway/configuration/meshservice.mdx b/website/content/docs/api-gateway/configuration/meshservice.mdx index 2dd377fb68d8..8847495874fb 100644 --- a/website/content/docs/api-gateway/configuration/meshservice.mdx +++ b/website/content/docs/api-gateway/configuration/meshservice.mdx @@ -11,7 +11,9 @@ This topic provides full details about the `MeshService` resource. ## Introduction -A `MeshService` is a resource in the Kubernetes cluster that enables Kubernetes configuration models, such as `HTTPRoute` and `TCPRoute`, to reference services that only exist in Consul. A `MeshService` represents a service in the Consul service mesh outside the Kubernetes cluster where Consul API Gateway is deployed. The service represented by the `MeshService` resource must be in the same Consul datacenter as the Kubernetes cluster. +A `MeshService` is a resource in the Kubernetes cluster that enables Kubernetes configuration models, such as `HTTPRoute` and `TCPRoute`, to reference services that only exist in Consul. +A `MeshService` represents a service in the Consul service mesh outside the Kubernetes cluster where Consul API Gateway is deployed. +The service represented by the `MeshService` resource must either be in the same Consul datacenter as the Kubernetes cluster or imported from a peered Consul cluster. ## Configuration Model @@ -19,6 +21,7 @@ A `MeshService` is a resource in the Kubernetes cluster that enables Kubernetes The following outline shows how to format the configurations in the `MeshService` object. Click on a property name to view details about the configuration. * [`name`](#name): string | required +* [`peer`](#peer): string | optional ## Specification @@ -29,3 +32,11 @@ This topic provides details about the configuration parameters. Specifies the name of the service in the Consul service mesh to send traffic to. * Type: string * Required: required + +### peer +Specifies the name of the peered Consul cluster from where the service is exported. If not specified, Consul defaults to the local datacenter. + +You must apply a [`ServiceResolver`](/docs/connect/config-entries/service-resolver) for the referenced service. The `ServiceResolver` configuration entry enables Consul to resolve routes to upstream service instances. + +* Type: string +* Required: optional diff --git a/website/content/docs/api-gateway/configuration/routes.mdx b/website/content/docs/api-gateway/configuration/routes.mdx index 1b44a8ccef88..692eb28c58b1 100644 --- a/website/content/docs/api-gateway/configuration/routes.mdx +++ b/website/content/docs/api-gateway/configuration/routes.mdx @@ -168,7 +168,7 @@ The following example creates a route named `example-route` in namespace `gatewa ### rules.filters -The `filters` block defines steps for processing requests. You can configure filters to modify the properties of matching incoming requests and enable Consul API Gateway features, such as rewriting path prefixes (refer to [Reroute HTTP requests](/docs/api-gateway/usage#reroute-http-requests) for additional information). +The `filters` block defines steps for processing requests. You can configure filters to modify the properties of matching incoming requests and enable Consul API Gateway features, such as rewriting path prefixes (refer to [Reroute HTTP requests](/consul/docs/api-gateway/usage/reroute-http-requests) for additional information). * Type: Array of objects * Required: Optional @@ -203,7 +203,7 @@ Specifies rules for rewriting the URL of incoming requests when `rules.filters.t ### rules.filters.urlRewrite.path -Specifies a list of objects that determine how Consul API Gateway rewrites URL paths (refer to [Reroute HTTP requests](/docs/api-gateway/usage#reroute-http-requests) for additional information). +Specifies a list of objects that determine how Consul API Gateway rewrites URL paths (refer to [Reroute HTTP requests](/consul/docs/api-gateway/usage/reroute-http-requests) for additional information). The following table describes the parameters for `path`: diff --git a/website/content/docs/api-gateway/install.mdx b/website/content/docs/api-gateway/install.mdx index ac6e36ab6cee..ecf25f52da42 100644 --- a/website/content/docs/api-gateway/install.mdx +++ b/website/content/docs/api-gateway/install.mdx @@ -18,7 +18,7 @@ Ensure that the environment you are deploying Consul API Gateway in meets the re 1. Set the version of Consul API Gateway you are installing as an environment variable. The following steps use this environment variable in commands and configurations. ```shell-session - $ export VERSION=0.3.0 + $ export VERSION=0.5.1 ``` 1. Issue the following command to install the CRDs: @@ -37,8 +37,6 @@ Ensure that the environment you are deploying Consul API Gateway in meets the re name: consul connectInject: enabled: true - controller: - enabled: true apiGateway: enabled: true image: hashicorp/consul-api-gateway:$VERSION @@ -62,7 +60,7 @@ Ensure that the environment you are deploying Consul API Gateway in meets the re ``` ```shell-session - $ consul-k8s install -config-file=values.yaml -set global.image=hashicorp/consul:1.12.2 + $ consul-k8s install -config-file=values.yaml -set global.image=hashicorp/consul:1.14.3 ``` @@ -76,7 +74,7 @@ Ensure that the environment you are deploying Consul API Gateway in meets the re Install Consul with API Gateway on your Kubernetes cluster by specifying the `values.yaml` file. ```shell-session - $ helm install consul hashicorp/consul --version 0.45.0 --values values.yaml --create-namespace --namespace consul + $ helm install consul hashicorp/consul --version 1.0.2 --values values.yaml --create-namespace --namespace consul ``` diff --git a/website/content/docs/api-gateway/tech-specs.mdx b/website/content/docs/api-gateway/tech-specs.mdx index d4ae15b2001f..b0a0e4fadafb 100644 --- a/website/content/docs/api-gateway/tech-specs.mdx +++ b/website/content/docs/api-gateway/tech-specs.mdx @@ -21,7 +21,7 @@ Your datacenter must meet the following requirements prior to configuring the Co - Kubernetes 1.24 is not supported at this time. - `kubectl` 1.21+ - Consul 1.11.2+ -- HashiCorp Consul Helm chart 0.45.0+ +- HashiCorp Consul Helm chart 0.47.1+ - Consul Service Mesh must be deployed on the Kubernetes cluster that API Gateway is deployed on. - Envoy: Envoy proxy support is determined by the Consul version deployed. Refer to [Envoy Integration](/docs/connect/proxies/envoy) for details. diff --git a/website/content/docs/api-gateway/usage/errors.mdx b/website/content/docs/api-gateway/usage/errors.mdx new file mode 100644 index 000000000000..40f1d4011e7c --- /dev/null +++ b/website/content/docs/api-gateway/usage/errors.mdx @@ -0,0 +1,60 @@ +--- +layout: docs +page_title: Use Consul API Gateway +description: >- + Learn how to apply a configured Consul API Gateway to your Kubernetes cluster, review the required fields for rerouting HTTP requests, and troubleshoot an error message. +--- + +# Error Messages + +This topic provides information about potential error messages associated with Consul API Gateway. If you receive an error message that does not appear in this section, refer to the following resources: + +* [Common Consul errors](/docs/troubleshoot/common-errors#common-errors-on-kubernetes) +* [Consul troubleshooting guide](/docs/troubleshoot/common-errors) +* [Consul Discuss forum](https://discuss.hashicorp.com/) + + + +## Helm installation failed: "no matches for kind" + +```log +Error: INSTALLATION FAILED: unable to build kubernetes objects from release manifest: [unable to recognize "": no matches for kind "GatewayClass" in version "gateway.networking.k8s.io/v1alpha2", unable to recognize "": no matches for kind "GatewayClassConfig" in version "api-gateway.consul.hashicorp.com/v1alpha1"] +``` +**Conditions:** +Consul API Gateway generates this error when the required CRD files have not been installed in Kubernetes prior to installing Consul API Gateway. + +**Impact:** +The installation process typically fails after this error message is generated. + +**Resolution:** +Install the required CRDs. Refer to the [Consul API Gateway installation instructions](/docs/api-gateway/install#installation) for instructions. \ No newline at end of file diff --git a/website/content/docs/api-gateway/usage/reroute-http-requests.mdx b/website/content/docs/api-gateway/usage/reroute-http-requests.mdx new file mode 100644 index 000000000000..8f457e934f17 --- /dev/null +++ b/website/content/docs/api-gateway/usage/reroute-http-requests.mdx @@ -0,0 +1,58 @@ +--- +layout: docs +page_title: Reroute HTTP Requests +description: >- + Learn how to configure Consul API Gateway to reroute HTTP requests to a specific path. +--- + +# Reroute HTTP Requests + +This topic describes how to configure Consul API Gateway to reroute HTTP requests. + +## Requirements + +1. Verify that the [requirements](/docs/api-gateway/tech-specs) have been met. +1. Verify that the Consul API Gateway CRDs and controller have been installed and applied. Refer to [Installation](/docs/api-gateway/install) for details. + +## Configuration + +Configure the following fields in your `Route` configuration to use this feature. Refer to the [Route configuration reference](/docs/api-gateway/configuration/routes) for details about the parameters. + +* [`rules.filters.type`](/docs/api-gateway/configuration/routes#rules-filters-type): Set this parameter to `URLRewrite` to instruct Consul API Gateway to rewrite the URL when specific conditions are met. +* [`rules.filters.urlRewrite`](/docs/api-gateway/configuration/routes#rules-filters-urlrewrite): Specify the `path` configuration. +* [`rules.filters.urlRewrite.path`](/docs/api-gateway/configuration/routes#rules-filters-urlrewrite-path): Contains the paths that incoming requests should be rewritten to based on the match conditions. + +Note that if the route is configured to accept paths with and without a trailing slash, you must make two separate routes to handle each case. + +### Example + +In the following example, requests to` /incoming-request-prefix/` are forwarded to the `backendRef` as `/prefix-backend-receives/`. A request to `/incoming-request-prefix/request-path`, for instance, is received by the `backendRef` as `/prefix-backend-receives/request-path`. + + + +```yaml hideClipboard +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: HTTPRoute +metadata: + name: example-route + ##... +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: api-gateway + rules: + - backendRefs: + . . . + filters: + - type: URLRewrite + urlRewrite: + path: + replacePrefixMatch: /prefix-backend-receives/ + type: ReplacePrefixMatch + matches: + - path: + type: PathPrefix + value: /incoming–request-prefix/ +``` + \ No newline at end of file diff --git a/website/content/docs/api-gateway/usage/route-to-peered-services.mdx b/website/content/docs/api-gateway/usage/route-to-peered-services.mdx new file mode 100644 index 000000000000..63dda381771d --- /dev/null +++ b/website/content/docs/api-gateway/usage/route-to-peered-services.mdx @@ -0,0 +1,77 @@ +--- +page_title: Route Traffic to Peered Services +description: Learn how to configure Consul API Gateway to route traffic to services connected to the mesh through a peering connection. +--- + +# Route Traffic to Peered Services + +This topic describes how to configure Consul API Gateway to route traffic to services connected to the mesh through a peering connection. + +## Requirements + +1. Verify that the [requirements](/docs/api-gateway/tech-specs) have been met. +1. Verify that the Consul API Gateway CRDs and controller have been installed and applied. Refer to [Installation](/docs/api-gateway/install) for details. +1. A peering connection must already be established between Consul clusters. Refer to [Cluster Peering on Kubernetes](/docs/connect/cluster-peering/k8s) for instructions. +1. The Consul service you want to route traffic to must be exported to the cluster containing your `Gateway`. Refer to [Cluster Peering on Kubernetes](/docs/connect/cluster-peering/k8s) for instructions. +1. A `ServiceResolver` for the Consul service you want to route traffic to must be created in the cluster that contains your `Gateway`. Refer to [Service Resolver Configuration Entry](/docs/connect/config-entries/service-resolver) for instructions. + +## Configuration + +Configure the following fields in your `MeshService` configuration to use this feature. Refer to the [MeshService configuration reference](/consul/docs/api-gateway/configuration/meshservice) for details about the parameters. + +* [`name`](/docs/api-gateway/configuration/meshservice#name) +* [`peer`](/docs/api-gateway/configuration/meshservice#peer) + +## Example + +In the following example, routes that use `example-mesh-service` as a backend are configured to send requests to the `echo` service exported by the peered Consul cluster `cluster-02`. + + + +```yaml hideClipboard +apiVersion: consul.hashicorp.com/v1alpha1 +kind: ServiceResolver +metadata: + name: echo +spec: + redirect: + peer: cluster-02 + service: echo +``` + + + + +```yaml hideClipboard +apiVersion: api-gateway.consul.hashicorp.com/v1alpha1 +kind: MeshService +metadata: + name: example-mesh-service + ##... +spec: + name: echo + peer: cluster-02 +``` + + +After applying the configuration, an `HTTPRoute` may then reference `example-mesh-service` as its `backendRef`. + + + +```yaml hideClipboard +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: HTTPRoute +metadata: + name: example-route + ##... +spec: + ... + rules: + - backendRefs: + - group: api-gateway.consul.hashicorp.com + kind: MeshService + name: example-mesh-service + port: 3000 + ... +``` + diff --git a/website/content/docs/api-gateway/usage.mdx b/website/content/docs/api-gateway/usage/usage.mdx similarity index 54% rename from website/content/docs/api-gateway/usage.mdx rename to website/content/docs/api-gateway/usage/usage.mdx index f5199d0c8f5b..0665e3cf9c1d 100644 --- a/website/content/docs/api-gateway/usage.mdx +++ b/website/content/docs/api-gateway/usage/usage.mdx @@ -5,76 +5,38 @@ description: >- Learn how to apply a configured Consul API Gateway to your Kubernetes cluster, review the required fields for rerouting HTTP requests, and troubleshoot an error message. --- -# Use Consul API Gateway +# Basic Consul API Gateway Usage This topic describes how to use Consul API Gateway. -## Basic usage +## Requirements Complete the following steps to use Consul API Gateway in your network. 1. Verify that the [requirements](/docs/api-gateway/tech-specs) have been met. 1. Verify that the Consul API Gateway CRDs and controller have been installed and applied. Refer to [Installation](/docs/api-gateway/install) for details. -1. Configure your [`Gateway`](/docs/api-gateway/configuration/gateway) and [`Routes`](/docs/api-gateway/configuration/routes) as describe in the [Configuration](/docs/api-gateway/configuration) section. + +## Configuration + +Configure your [`Gateway`](/docs/api-gateway/configuration/gateway) and [`Routes`](/docs/api-gateway/configuration/routes) as describe in the [Configuration](/docs/api-gateway/configuration) section. - ```yaml - apiGateway: - enabled: true - managedGatewayClass: - ``` + ```yaml + apiGateway: + enabled: true + managedGatewayClass: + ``` -1. Issue the `kubectl apply` command to implement the configurations: +## Apply configurations - ```shell-session - $ kubectl apply -f gateway.yaml routes.yaml - ``` +Issue the `kubectl apply` command to implement the configurations: -## Reroute HTTP requests - -Configure the following fields in your `Route` configuration to use this feature. Refer to the [Route configuration reference](/docs/api-gateway/configuration/routes) for details about the parameters. - -* [`rules.filters.type`](/docs/api-gateway/configuration/routes#rules-filters-type): Set this parameter to `URLRewrite` to instruct Consul API Gateway to rewrite the URL when specific conditions are met. -* [`rules.filters.urlRewrite`](/docs/api-gateway/configuration/routes#rules-filters-urlrewrite): Specify the `path` configuration. -* [`rules.filters.urlRewrite.path`](/docs/api-gateway/configuration/routes#rules-filters-urlrewrite-path): Contains the paths that incoming requests should be rewritten to based on the match conditions. - -Note that if the route is configured to accept paths with and without a trailing slash, you must make two separate routes to handle each case. - -### Example - -In the following example, requests to` /incoming-request-prefix/` are forwarded to the `backendRef` as `/prefix-backend-receives/`. A request to `/incoming-request-prefix/request-path`, for instance, is received by the `backendRef` as `/prefix-backend-receives/request-path`. - - - -```yaml hideClipboard -apiVersion: gateway.networking.k8s.io/v1beta1 -kind: HTTPRoute -metadata: - name: example-route - ##... -spec: - parentRefs: - - group: gateway.networking.k8s.io - kind: Gateway - name: api-gateway - rules: - - backendRefs: - . . . - filters: - - type: URLRewrite - urlRewrite: - path: - replacePrefixMatch: /prefix-backend-receives/ - type: ReplacePrefixMatch - matches: - - path: - type: PathPrefix - value: /incoming–request-prefix/ +```shell-session +$ kubectl apply -f gateway.yaml routes.yaml ``` - -## Error Messages - -This topic provides information about potential error messages associated with Consul API Gateway. If you receive an error message that does not appear in this section, refer to the following resources: - -* [Common Consul errors](/docs/troubleshoot/common-errors#common-errors-on-kubernetes) -* [Consul troubleshooting guide](/docs/troubleshoot/common-errors) -* [Consul Discuss forum](https://discuss.hashicorp.com/) - - - -### Helm installation failed: "no matches for kind" - -```log -Error: INSTALLATION FAILED: unable to build kubernetes objects from release manifest: [unable to recognize "": no matches for kind "GatewayClass" in version "gateway.networking.k8s.io/v1alpha2", unable to recognize "": no matches for kind "GatewayClassConfig" in version "api-gateway.consul.hashicorp.com/v1alpha1"] -``` -**Conditions:** -Consul API Gateway generates this error when the required CRD files have not been installed in Kubernetes prior to installing Consul API Gateway. - -**Impact:** -The installation process typically fails after this error message is generated. -**Recommended Action:** -Install the required CRDs by using the command in Step 1 of the [Consul API Gateway installation instructions](/docs/api-gateway/install#installation) and then retry installing Consul API Gateway. diff --git a/website/content/docs/architecture/anti-entropy.mdx b/website/content/docs/architecture/anti-entropy.mdx index 1ac3d2ba992e..995ab0bae81e 100644 --- a/website/content/docs/architecture/anti-entropy.mdx +++ b/website/content/docs/architecture/anti-entropy.mdx @@ -26,7 +26,7 @@ health checks and updating their local state. Services and checks within the context of an agent have a rich set of configuration options available. This is because the agent is responsible for generating information about its services and their health through the use of -[health checks](/docs/discovery/checks). +[health checks](/consul/docs/services/usage/checks). #### Catalog @@ -117,8 +117,7 @@ the source of truth for tag information. For example, the Redis database and its monitoring service Redis Sentinel have this kind of relationship. Redis instances are responsible for much of their configuration, but Sentinels determine whether the Redis instance is a -primary or a secondary. Using the Consul service configuration item -[enable_tag_override](/docs/discovery/services) you can instruct the -Consul agent on which the Redis database is running to NOT update the -tags during anti-entropy synchronization. For more information see -[Services](/docs/discovery/services#enable-tag-override-and-anti-entropy) page. +primary or a secondary. Enable the +[`enable_tag_override`](/consul/docs/services/configuration/services-configuration-reference#enable_tag_override) parameter in your service definition file to tell the Consul agent where the Redis database is running to bypass +tags during anti-entropy synchronization. Refer to +[Modify anti-entropy synchronozation](/consul/docs/services/usage/define-services#modify-anti-entropy-synchronization) for additional information. diff --git a/website/content/docs/architecture/improving-consul-resilience.mdx b/website/content/docs/architecture/improving-consul-resilience.mdx index f1fa41171e0d..8438cfb77939 100644 --- a/website/content/docs/architecture/improving-consul-resilience.mdx +++ b/website/content/docs/architecture/improving-consul-resilience.mdx @@ -31,7 +31,7 @@ Without a quorum, Consul experiences an outage: it cannot provide most of its capabilities because they rely on the availability of this state information. If Consul has an outage, normal operation can be restored by following the -[outage recovery guide](https://learn.hashicorp.com/tutorials/consul/recovery-outage). +[Disaster recovery for Consul clusters guide](/consul/tutorials/datacenter-operations/recovery-outage). If Consul is deployed with 3 servers, the quorum size is 2. The deployment can lose 1 server and still maintain quorum, so it has a fault tolerance of 1. diff --git a/website/content/docs/architecture/index.mdx b/website/content/docs/architecture/index.mdx index 36b703496d57..b4ae02e2ac48 100644 --- a/website/content/docs/architecture/index.mdx +++ b/website/content/docs/architecture/index.mdx @@ -2,7 +2,7 @@ layout: docs page_title: Consul Architecture description: >- - Consul datacenters consist of clusters of server agents (control plane) and client agents deployed alongside service instances (dataplane). Learn how these components and their different communication methods make Consul possible. + Consul datacenters consist of clusters of server agents (control plane) and client agents deployed alongside service instances (data plane). Learn how these components and their different communication methods make Consul possible. --- # Consul Architecture @@ -47,13 +47,15 @@ Consul servers establish consensus using the Raft algorithm on port `8300`. Refe ### Client agents -Consul clients report node and service health status to the Consul cluster. In a typical deployment, you must run client agents on every compute node in your datacenter. Clients use remote procedure calls (RPC) to interact with servers. By default, clients send RPC requests to the servers on port `8300`. +Consul clients report node and service health status to the Consul cluster. In a typical deployment, you must run client agents on every compute node in your datacenter. Clients use remote procedure calls (RPC) to interact with servers. By default, clients send RPC requests to the servers on port `8300`. There are no limits to the number of client agents or services you can use with Consul, but production deployments should distribute services across multiple Consul datacenters. Using a multi-datacenter deployment enhances infrastructure resilience and limits control plane issues. We recommend deploying a maximum of 5,000 client agents per datacenter. Some large organizations have deployed tens of thousands of client agents and hundreds of thousands of service instances across a multi-datacenter deployment. Refer to [Cross-datacenter requests](#cross-datacenter-requests) for additional information. +You can also run Consul with an alternate service mesh configuration that deploys Envoy proxies but not client agents. Refer to [Simplified Service Mesh with Consul Dataplanes](/docs/connect/dataplane) for more information. + ## LAN gossip pool -Client and server agents participate in a LAN gossip pool so that they can distribute and perform node [health checks](/docs/discovery/checks). Agents in the pool propagate the health check information across the cluster. Agent gossip communication occurs on port `8301` using UDP. Agent gossip falls back to TCP if UDP is not available. Refer to [Gossip Protocol](/docs/architecture/gossip) for additional information. +Client and server agents participate in a LAN gossip pool so that they can distribute and perform node [health checks](/consul/docs/services/usage/checks). Agents in the pool propagate the health check information across the cluster. Agent gossip communication occurs on port `8301` using UDP. Agent gossip falls back to TCP if UDP is not available. Refer to [Gossip Protocol](/consul/docs/architecture/gossip) for additional information. The following simplified diagram shows the interactions between servers and clients. @@ -105,10 +107,8 @@ In the following diagram, the servers in each data center participate in a WAN g -### Cluster peering (beta) +### Cluster peering You can create peering connections between two or more independent clusters so that services deployed to different datacenters or admin partitions can communicate. An [admin partition](/docs/enterprise/admin-partitions) is a feature in Consul Enterprise that enables you to define isolated network regions that use the same Consul servers. In the cluster peering model, you create a token in one of the datacenters or partitions and configure another datacenter or partition to present the token to establish the connection. - --> **Cluster peering is currently in beta:** Functionality associated with cluster peering is subject to change. You should never use the beta release in secure environments or production scenarios. Features in beta may have performance issues, scaling issues, and limited support. -Refer to [What is Cluster Peering?](/docs/connect/cluster-peering) for additional information. \ No newline at end of file +Refer to [What is Cluster Peering?](/docs/connect/cluster-peering) for additional information. diff --git a/website/content/docs/architecture/scale.mdx b/website/content/docs/architecture/scale.mdx new file mode 100644 index 000000000000..a94e649c7d41 --- /dev/null +++ b/website/content/docs/architecture/scale.mdx @@ -0,0 +1,283 @@ +--- +layout: docs +page_title: Recommendations for operating Consul at scale +description: >- + When using Consul for large scale deployments, you can ensure network resilience by tailoring your network to your needs. Learn more about HashiCorp's recommendations for deploying Consul at scale. +--- + +# Operating Consul at Scale + +This page describes how Consul's architecture and impact its performance with large scale deployments, and shares recommendations for operating Consul in production at scale. + +## Overview + +Consul is a distributed service networking system deployed as a centralized set of servers that coordinate network activity using sidecars that are located alongside user workloads. When Consul is used for its service mesh capabilities, servers also generate configurations for Envoy proxies that run alongside service instances. These proxies support service mesh capabilities like end-to-end TLS and progressive deployments. + +Consul can be deployed in either a single datacenter or across multiple datacenters by establishing WAN federation or peering connections. In this context, a datacenter refers to a named environment whose hosts can communicate with low networking latency. Typically, users map a Consul datacenter to a cloud provider region such as AWS us-east-1 or Azure East US. + +To ensure consistency and high availability, Consul servers share data using the [Raft consensus protocol](/consul/docs/architecture/consensus). When persisting data, Consul uses Boltdb to store Raft logs and a custom file format for state snapshots. For more information, refer to [Consul architecture](/consul/docs/architecture). + +## General deployment recommendations + +This section provides general configuration and monitoring recommendations for operating Consul at scale. + +### Data plane resiliency + +To make service-to-service communication resilient against outages and failures, we recommend spreading multiple service instances for a service across fault domains: + +- Spread service instances across _multiple infrastructure-level availability zones_. +- Spread service instances across _multiple runtime platform instances_, such as multiple Kubernetes clusters. +- Spread service instances across _multiple Consul datacenters_. + +In the event that any individual domain experiences a failure, service failover ensures that healthy instances in other domains remain discoverable. Consul automatically provides service failover between instances within a single admin partition or datacenter. + +Service failover across Consul datacenters must be configured in the datacenters before you can use it. Use one of the following methods to configure failover across datacenters: + +- **If you are using Consul service mesh**: Implement failover using [service-resolver configuration entries](/consul/docs/connect/config-entries/service-resolver#failover). +- **If you are using Consul service discovery without service mesh**: Implement [geo-redundant failover using prepared queries](consul/tutorials/developer-discovery/automate-geo-failover). + +### Control plane resiliency + +Because the control plane’s larger size can slow network performance as deployments grow, it is important to manage the size of your datacenters. To make the control plane more resilient, limit its size by spreading deployments across availability zones, runtimes, and datacenters. + +#### Datacenter size + +To ensure resiliency, we recommend limiting deployments to a maximum of 5,000 Consul client agents per Consul datacenter. There are two reasons for this recommendation: + +1. **Blast radius reduction**: When Consul suffers a server outage in a datacenter or region, _blast radius_ refers to the number of Consul clients or dataplanes attached to that datacenter that can no longer communicate as a result. We recommend limiting the total number of clients attached to a single Consul datacenter in order to reduce the size of its blast radius. Even though Consul is able to run clusters with 10,000 or more nodes, it takes longer to bring larger deployments back online after an outage, which impacts time to recovery. +2. **Agent gossip management**: Consul agents use the [gossip protocol](/consul/docs/architecture/gossip) to share membership information in a gossip pool. By default, all client agents in a single Consul datacenter are in a single gossip pool. Whenever an agent joins or leaves the gossip pool, the other agents propagate that event throughout the pool. If a Consul datacenter experiences _agent churn_, or a consistently high rate of agents joining and leaving a single pool, cluster performance may be affected by gossip messages being generated faster than they can be transmitted. The result is an ever-growing message queue. + +To mitigate these risks, we recommend a maximum of 5,000 Consul client agents in a single gossip pool. There are several strategies for making gossip pools smaller: + +1. Run exactly one Consul agent per host in the infrastructure. +1. Break up the single Consul datacenter into multiple smaller datacenters. +1. Enterprise users can define [network segments](/consul/docs/enterprise/network-segments/network-segments-overview) to divide the single gossip pool in the Consul datacenter into multiple smaller pools. + +If appropriate for your use case, we recommend breaking up a single Consul datacenter into multiple smaller datacenters. Running multiple datacenters reduces your network’s blast radius more than applying network segments. + +Be aware that the number 5,000 is a heuristic for deployments. The number of agents you deploy per datacenter is limited by performance, not Consul itself. Because gossip stability risk is determined by _the rate of agent churn_ rather than _the number of nodes_, a gossip pool with mostly static nodes may be able to operate effectively with more than 5,000 agents. Meanwhile, a gossip pool with highly dynamic agents, such as spot fleet instances and serverless functions where 10% of agents are replaced each day, may need to be smaller than 5,000 agents. + +For most use cases, a limit of 5,000 agents is appropriate. When the `consul.serf.queue.Intent` metric is consistently high, it is an indication that the gossip pool cannot keep up with the sustained level of churn. In this situation, reduce the churn by lowering the number agents per datacenter. + +#### Kubernetes-specific guidance + +In Kubernetes, even though it is possible to deploy Consul agents inside pods alongside services running in the same pod, this unsupported deployment pattern has known performance issues at scale. At large volumes, pod registration and deregistration in Kubernetes causes gossip instability that can lead to cascading failures as services are marked unhealthy, resulting in further cluster churn. + +In Consul v1.14 and higher, Consul on Kubernetes does not need to run client agents on every node in a cluster for service discovery and service mesh. This deployment configuration lowers Consul’s resource usage in the data plane. To learn more, refer to [simplified service mesh with Consul Dataplane](/consul/docs/connect/dataplane). + +**If you use Kubernetes and Consul as a backend for Vault**: Use Vault’s integrated storage backend instead of Consul. A runtime dependency conflict prevents Consul dataplanes from being compatible with Vault. If you need to use Consul v1.14 and over as a backend for Vault in your Kubernetes deployment, create a separate Consul datacenter that is not federated or peered to your other Consul servers. You can size this datacenter according to your needs and use it exclusively for backend storage for Vault. + +## Consul server deployment recommendations + +Consul server agents are an important part of Consul’s architecture. This section summarizes the differences between running managed and self-managed servers, as well as recommendations on the number of servers to run, how to deploy servers across redundancy zones, hardware requirements, and cloud provider integrations. + +### Consul server runtimes + +Consul servers can be deployed on a few different runtimes: + +- **HashiCorp Cloud Platform (HCP) Consul (Managed)**. These Consul servers are deployed in a hosted environment managed by HCP. To get started with HCP Consul servers in Kubernetes or VM deployments, refer to the Deploy HCP Consul tutorial. +- **VMs or bare metal servers (Self-managed)**. To get started with Consul on VMs or bare metal servers, refer to the Deploy Consul server tutorial.For a full list of configuration options, refer to Agents Overview. +- **Kubernetes (Self-managed)**. To get started with Consul on Kubernetes, refer to the Deploy Consul on Kubernetes tutorial. +- **Other container environments, including Docker, Rancher, and Mesos (Self-managed)**. + +When operating Consul at scale, self-managed VM or bare metal server deployments offer the most flexibility. Some Consul Enterprise features that can enhance fault tolerance and read scalability, such as [redundancy zones](/consul/docs/enterprise/redundancy) and [read replicas](/consul/docs/enterprise/read-scale), are not available to server agents on Kubernetes runtimes. To learn more, refer to [Consul Enterprise feature availability by runtime](/consul/docs/enterprise#feature-availability-by-runtime). + +### Number of Consul servers + +Determining the number of Consul servers to deploy on your network has two key considerations: + +- **Fault tolerance**: The number of server outages your deployment can tolerate while maintaining quorum. Additional servers increase a network’s fault tolerance. +- **Performance scalability**: To handle more requests, additional servers produce latency and slow the quorum process. Too many servers impedes your network instead of helping it. + +Fault tolerance should determine your initial decision for how many Consul server agents to deploy. Our recommendation for the number of servers to deploy depends on whether you have access to Consul Enterprise redundancy zones: + +- **With redundancy zones**: Deploy 6 Consul servers across 3 availability zones. This deployment provides the performance of a 3 server deployment with the fault tolerance of a 7 server deployment. +- **Without redundancy zones**: Deploy 5 Consul servers across 3 availability zones. All 5 servers should be voting servers, not [read replicas](/consul/docs/enterprise/read-scale). + +For more details, refer to [Improving Consul Resilience](/consul/docs/architecture/improving-consul-resilience). + +### Server requirements + +To ensure your server nodes are a sufficient size, we recommend reviewing [hardware sizing for Consul servers](/consul/tutorials/production-deploy/reference-architecture#hardware-sizing-for-consul-servers). If your network needs to handle heavy workloads, refer to our recommendations in [read-heavy workload sources and solutions](#read-heavy-workload-sources-and-solutions) and [write-heavy workload sources and solutions](#write-heavy-workload-sources-and-solutions). + +#### File descriptors + +Consul's agents use network sockets for gossip communication with the other nodes and agents. As a result, servers create file descriptors for connections from clients, connections from other servers, watch handlers, health checks, and log files. For write-heavy clusters, you must increase the size limit for the number of file descriptions from the default value, 1024. We recommend using a number that is two times higher than your expected number of clients in the cluster. + +#### Auto scaling groups + +Auto scaling groups (ASGs) are infrastructure associations in cloud providers used to ensure a specific number of replicas are available for a deployment. When using ASGs for Consul servers, there are specific requirements and processes for bootstrapping Raft and maintaining quorum. + +We recommend using the [`bootstrap-expect` command-line flag](/consul/docs/agent/config/cli-flags#_bootstrap_expect) during cluster creation, but when spawning new servers to add to a cluster or upgrading servers, do not configure them to automatically bootstrap. If `bootstrap-expect` is set on these replicas, it is possible for them to create a separate Raft system, which causes a _split brain_ and leads to errors and general cluster instability. + +#### NUMA architecture awareness + +Some cloud providers offer extremely large instance sizes with Non-Uniform Memory Access (NUMA) architectures. Because the Go runtime is not NUMA aware, Consul is not NUMA aware. + +### Consistency modes + +Consul offers different [consistency modes](/consul/api-docs/features/consistency#stale) for both its DNS and HTTP APIs. + +#### DNS + +We strongly recommend utilizing the recommendations in the [DNS Caching tutorial](/consul/tutorials/networking/dns-caching) for stale consistency. Consul uses [stale consistency mode](/consul/api-docs/features/consistency#stale) to optimize for performance over consistency in DNS API responses. + +If you need to improve consistency at the expense of an increased workload, you can set `dns_config.allow_stale` to `default`. In addition, you can configure TTLs for services and nodes to improve DNS resolving at the client and avoid server round trips. + +We also recommend that you do not configure [`dns_config.max_stale` to limit the staleness of DNS responses](/consul/api-docs/features/consistency#limiting-staleness-advanced-usage), as it may result in a prolonged outage if your Consul servers become overloaded. If bounded result consistency is required by a service, consider modifying the service to use consistent service discovery HTTP API queries instead of DNS lookups. + +Avoid using [`dns_config.use_cache`](/consul/docs/agent/config/config-files#dns_use_cache) when operating Consul at scale. The agent cache allocates memory for each requested route and each allocation can live up to 3 days, resulting in severe memory issues. + +#### HTTP API + +By default, all HTTP API read requests use the [`default` consistency mode](/consul/api-docs/features/consistency#default-1) unless overridden on a per-request basis. We do not recommend changing the default consistency mode for HTTP API requests. + +We also recommend that you do not configure [`http_config.discovery_max_stale`](/consul/api-docs/features/consistency#changing-the-default-consistency-mode-advanced-usage) to limit the staleness of HTTP responses. + +## Resource usage and metrics recommendations + +While operating Consul, monitor the CPU load on the Consul server agents and use metrics from agent telemetry to figure out the cause. Procedures for mitigating heavy resource usage depend on whether the load is caused by read operations, write operations, or Consul’s consensus protocol. + +### Read-heavy workload sources and solutions + +The highest CPU load usually belongs to the current leader. If the CPU load is high, request load is likely a major contributor. Check the following [server health metrics](/consul/docs/agent/telemetry#server-health): + +- `consul.rpc.*` - Traditional RPC metrics. The most relevant metrics for understanding server CPU load in read-heavy workloads are `consul.rpc.query` and `consul.rpc.queries_blocking`. +- `consul.grpc.server.*` - Metrics for the number of streams being processed by the server. +- `consul.xds.server.*` - Metrics for the Envoy xDS resources being processed by the server. In Consul v1.14 and higher, these metrics are a significant source of read load. Refer to [Consul dataplanes](/consul/docs/connect/dataplane) for more information. + +Depending on your needs, choose one of the following strategies to mitigate server CPU load: + +- The fastest mitigation strategy is to vertically scale servers. However, this strategy increases compute costs and does not scale indefinitely. +- The most effective long term mitigation strategy is to use [stale consistency mode](/consul/api-docs/features/consistency#stale) for as many read requests as possible. In Consul v1.12 and higher, operators can use the [`consul.rpc.server.call` metric](/consul/docs/agent/telemetry#server-workload) to identify the most frequent type of read requests made to the Consul servers. Cross reference the results with each endpoint’s [HTTP API documentation](/consul/api-docs) and use stale consistency for endpoints that support it. +- If most read requests already use stale consistency mode and you still need to reduce your request load, add more non-voting servers to your deployment. You can use either [redundancy zones](/consul/docs/enterprise/redundancy) or [read replicas](/consul/docs/enterprise/read-scale) to scale reads without impacting write latency. We recommend adding more servers to redundancy zones because they improve both fault tolerance and stale read scalability. +- In Consul v1.14 and higher, servers handle Envoy XDS streams for [Consul Dataplane deployments](/consul/docs/connect/dataplane) in stale consistency mode. As a result, server consistency mode is not configurable. Use the `consul.xds.server.*` metrics to identify issues related to XDS streams. + +### Write-heavy workload sources and solutions + +Consul is write-limited by disk I/O. For write-heavy workloads, we recommend using NVMe disks. + +As a starting point, you should make sure your hardware meets the requirements for [large size server clusters](/consul/tutorials/production-deploy/reference-architecture#hardware-sizing-for-consul-servers), which has 7500+ IOps and 250+ MB/s disk throughput. IOps should be around 5 to 10 times the expected write rate. Conduct further analysis around disk sizing and your expected write rates to understand your network’s specific needs. + +If you use network storage, such as AWS EBS, we recommend provisioned I/O volumes. While general purpose volumes function properly, their burstable IOps make it harder to capacity plan. A small peak in writes may not trigger alerts, but as usage grows you may reach a point where the burst limit runs out and workload performance worsens. + +For more information, refer to the [server performance read/write tuning](/consul/docs/install/performance#read-write-tuning). + +### Raft database performance sources and solutions + +Consul servers use the [Raft consensus protocol](/consul/docs/architecture/consensus) to maintain a consistent and fault-tolerant state. Raft stores most Consul data in a MemDB database, which is an in-memory database with indexing. In order to tolerate restarts and power outages, Consul writes Raft logs to disk using BoltDB. Refer to [Agent telemetry](/consul/docs/agent/telemetry) for more information on metrics for detecting write health. + +To monitor overall transaction performance, check for spikes in the [Transaction timing metrics](/consul/docs/agent/telemetry#transaction-timing). You can also use the [Raft replication capacity issues metrics](/consul/docs/agent/telemetry#raft-replication-capacity-issues) to monitor Raft log snapshots and restores, as spikes and longer durations can be symptoms of overall write and disk contention issues. + +In Consul v1.11 and higher, you can also monitor Raft performance with the [`consul.raft.boltdb.*` metrics](/consul/docs/agent/telemetry#bolt-db-performance). We recommend monitoring `consul.raft.boltdb.storeLogs` for increased activity above normal operating patterns. + +Refer to [Consul agent telemetry](/consul/docs/agent/telemetry#bolt-db-performance) for more information on agent metrics and how to use them. + +#### Raft database size + +Raft writes logs to BoltDB, which is designed as a single grow-only file. As a result, if you add 1GB of log entries and then you take a snapshot, only a small number of recent log entries may appear in the file. However, the actual file on disk never shrinks smaller than the 1GB size it grew. + +If you need to reclaim disk space, use the `bbolt` CLI to copy the data to a new database and repoint to the new database in the process. However, be aware that the `bbolt compact` command requires the database to be offline while being pointed to the new database. + +In many cases disk space is not a primary concern because Raft logs rarely grow larger than a small number of GiB, even in large clusters. However, an inflated file with lots of free space significantly degrades write performance overall due to _freelist management_. + +After they are written to disk, Raft logs are eventually captured in a snapshot and log nodes are removed from BoltDB. BoltDB keeps track of the pages for the removed nodes in its freelist. BoltDB also writes this freelist to disk every time there is a Raft write. When the Raft log grows large quickly and then gets truncated, the size of the freelist can become very large. In the worst case reported to us, the freelist was over 10MB. When this large freelist is written to disk on every Raft commit, the result is a large write amplification for what should be a small Raft commit. + +To figure out if a Consul server’s disk performance issues are the result of BoldDB’s freelist, try the following strategies: + +- Compare network bandwidth inbound to the server against disk write bandwidth. If _disk write bandwidth_ is greater than or equal to 5 times the _inbound network bandwidth_, the disks are likely experiencing freelist management performance issues. While BoltDB freelist may cause problems at ratios lower than 5 to 1, high write bandwidth to inbound bandwidth ratios are a reliable indicator that BoltDB freelist is causing a problem. +- Use the [`consul.raft.leader.dispatchLog` metric](/consul/docs/agent/telemetry#server-health) to get information about how long it takes to write a batch of logs to disk. +- In Consul v1.13 and higher, you can use [Raft thread saturation metrics](/consul/docs/agent/telemetry#raft-thread-saturation) to figure out if Raft is experiencing back pressure and is unable to accept new work due disk limitations. + +In Consul v1.11 and higher, you can prevent BoltDB from writing the freelist to disk by setting [`raftboltdb.NoFreelistSync`](/consul/docs/agent/config/config-files#NoFreelistSync) to `true`. This setting causes BoltDB to retain the freelist in memory instead. However, be aware that when BoltDB restarts, it needs to scan the database file to manually create the freelist. Small delays in startup may occur. On a fast disk, we measured these delays at the order of tens of seconds for a raft.db file that was 5GiB in size with only 250MiB of used pages. + +In general, set [`raftboltdb.NoFreelistSync`](/consul/docs/agent/config/config-files#NoFreelistSync) to `true` to produce the following effects: + +- Reduce the amount of data written to disk +- Increase the amount of time it takes to load the raft.db file on startup + +We recommend operators optimize networks according to their individual concerns. For example, if your server runs into disk performance issues but Consul servers do not restart often, setting [`raftboltdb.NoFreelistSync`](consul/docs/agent/config/config-files#NoFreelistSync) to `true` may solve your problems but it causes issues for deployments with large database files and frequent server restarts. + +#### Raft snapshots + +Each state change produces a Raft log entry, and each Consul server receives the same sequence of log entries, which results in servers sharing the same state. The sequence of Raft logs is periodically compacted by the leader into a _snapshot_ of state history. These snapshots are internal to Raft and are not the same as the snapshots generated through Consul's API, although they contain the same data. Raft snapshots are stored in the server's data directory in the `raft/` folder, alongside the logs in `raft.db`. + +When you add a new Consul server, it must catch up to the current state. It receives the latest snapshot from the leader followed by the sequence of logs between that snapshot and the leader’s current state. Each Raft log has a sequence number and each snapshot contains the last sequence number included in the snapshot. A combination of write-heavy workloads, a large state, congested networks, or busy servers makes it possible for new servers to struggle to catch up to the current state before the next log they need from the leader has already been truncated. The result is a _snapshot install loop_. + +For example, if snapshot A on the leader has an index of 99 and the current index is 150, then when a new server comes online the leader streams snapshot A to the new server for it to restore. However, this snapshot only enables the new server to catch up to index 99. Not only does the new server still need to catch up to index 150, but the leader continued to commit Raft logs in the meantime. + +When the leader takes snapshot B at index 199, it truncates the logs that accumulated between snapshot A and snapshot B, which means it truncates Raft logs with indexes between 100 and 199. + +Because the new server restored snapshot A, the new server has a current index of 99. It requests logs 100 to 150 because index 150 was the current index when it started the replication restore process. At this point, the leader recognizes that it only has logs 200 and higher, and does not have logs for indexes 100 to 150. The leader determines that the new server’s state is stale and starts the process over by sending the new server the latest snapshot, snapshot B. + +Consul keeps a configurable number of [Raft trailing logs](/consul/docs/agent/config/config-files#raft_trailing_logs) to prevent the snapshot install loop from repeating. The trailing logs are the last logs that went into the snapshot, and the new server can more easily catch up to the current state using these logs. The default Raft trailing logs configuration value is suitable for most deployments. + +In Consul v1.10 and higher, operators can try to prevent a snapshot install loop by monitoring and comparing Consul servers’ `consul.raft.rpc.installSnapshot` and `consul.raft.leader.oldestLogAge` timing metrics. Monitor these metrics for the following situations: + +- After truncation, the lowest number on `consul.raft.leader.oldestLogAge` should always be at least two times higher than the lowest number for `consul.raft.rpc.installSnapshot`. +- If these metrics are too close, increase the number of Raft trailing logs, which increases `consul.raft.leader.oldestLogAge`. Do not set the Raft trailing logs higher than necessary, as it can negatively affect write throughput and latency. + +For more information, refer to [Raft Replication Capacity Issues](h/consul/docs/agent/telemetry#raft-replication-capacity-issues). + +## Performance considerations for specific use cases + +This section provides configuration and monitoring recommendations for Consul deployments according to the features you prioritize and their use cases. + +### Service discovery + +To optimize performance for service discovery, we recommend deploying multiple small clusters with consistent numbers of service instances and watches. + +Several factors influence Consul performance at scale when used primarily for its service discovery and health check features. The factors you have control over include: + +- The overall number of registered service instances +- The use of [stale reads](/consul/api-docs/features/consistency#consul-dns-queries) for DNS queries +- Max number of service instances for a given service - Are there services that are registered in every node or in a large percentage of nodes in the fleet? +- Number of [watches](/consul/docs/dynamic-app-config/watches) monitoring for changes to a service. +- Rate of catalog updates, which is affected by the following events: + - A service instance’s health check status changes + - A service instance’s node loses connectivity to Consul servers + - The contents of the [service definition file](/consul/docs/services/configuration/services-configuration-reference) changes + - Service instances are registered or deregistered + - Orchestrators such as Kubernetes or Nomad move a service to a new node + +These factors can occur in combination with one another. Overall, the amount of work the servers complete for service discovery is the product of these factors: + +- Data size, which changes as the number of services and service instances increases +- The catalog update rate +- The number of active watches + +Because it is typical for these factors to increase in number as clusters grow, the CPU and network resources the servers require to distribute updates may eventually exceed linear growth. + +In situations where you can’t run a Consul client agent alongside the service instance you want to register with Consul, such as instances hosted externally or on legacy infrastructure, we recommend using [Consul ESM](https://github.com/hashicorp/consul-esm). + +Consul ESM enables health checks and monitoring for external services. When using Consul ESM, we recommend running multiple instances to ensure redundancy. + +### Service mesh + +Because Consul’s service mesh uses service discovery subsystems, service mesh performance is also optimized by deploying multiple small clusters with consistent numbers of service instances and watches. Service mesh performance is influenced by the following additional factors: + +- The [transparent proxy](/consul/docs/connect/transparent-proxy) feature causes client agents to listen for service instance updates across all services instead of a subset. To prevent performance issues, we recommend that you do not use the permissive intention, `default: allow`, with the transparent proxy feature. When combined, every service instance update propagates to every proxy, which causes additional server load. +- When you use the [built in CA provider](/consul/docs/connect/ca/consul#built-in-ca), Consul leaders are responsible for signing certificates used for mTLS across the service mesh. The impact on CPU utilization depends on the total number of service instances and configured certificate TTLs. You can use the [CA provider configuration options](/consul/docs/agent/config/config-files#common-ca-config-options) to control the number of requests a server processes. We recommend adjusting [`csr_max_concurrent`](/consul/docs/agent/config/config-files#ca_csr_max_concurrent) and [`csr_max_per_second`](/consul/docs/agent/config/config-files#ca_csr_max_concurrent) to suit your environment. + +### K/V store + +While the K/V store in Consul has some similarities to object stores we recommend that you do not use it as a primary application data store. + +When using Consul's K/V store for application configuration and metadata, we recommend the following to optimize performance: + +- Values must be below 512 KB and transactions should be below 64 operations. +- The keyspace must be well bound. While 10,000 keys may not affect performance, millions of keys are more likely to cause performance issues. +- Total data size must fit in memory, with additional room for indexes. We recommend that the in-memory size is 3 times the raw key value size. +- Total data size should remain below 1 GB. Larger snapshots are possible on suitably fast hardware, but they significantly increase recovery times and the operational complexity needed for replication. We recommend limiting data size to keep the cluster healthy and able to recover during maintenance and outages. +- The K/V store is optimized for reading. To know when you need to make changes to server resources and capacity, we recommend carefully monitoring update rates after they exceed more than a hundred updates per second across the cluster. +- We recommend that you do not use the K/V store as a general purpose database or object store. + +In addition, we recommend that you do not use the [blocking query mechanism](/consul/api-docs/features/blocking) to listen for updates when your K/V store’s update rate is high. When a K/V result is updated too fast, blocking query loops degrade into busy loops. These loops consume excessive client CPU and cause high server load until appropriately throttled. Watching large key prefixes is unlikely to solve the issue because returning the entire key prefix every time it updates can quickly consume a lot of bandwidth. + +### Backend for Vault + +At scale, using Consul as a backend for Vault results in increased memory and CPU utilization on Consul servers. It also produces unbounded growth in Consul’s data persistence layer that is proportional to both the amount of data being stored in Vault and the rate the data is updated. + +In situations where Consul handles large amounts of data and has high write throughput, we recommend adding monitoring for the [capacity and health of raft replication on servers](/consul/docs/agent/telemetry#raft-replication-capacity-issues). If the server experiences heavy load when the size of its stored data is large enough, a follower may be unable to catch up on replication and become a voter after restarting. This situation occurs when the time it takes for a server to restore from disk takes longer than it takes for the leader to write a new snapshot and truncate its logs. Refer to [Raft snapshots](#raft-snapshots) for more information. + +Vault v1.4 and higher provides [integrated storage](/vault/docs/concepts/integrated-storage) as its recommended storage option. If you currently use Consul as a storage backend for Vault, we recommend switching to integrated storage. For a comparison between Vault's integrated storage and Consul as a backend for Vault, refer to [storage backends in the Vault documentation](/vault/docs/configuration/storage#integrated-storage-vs-consul-as-vault-storage). For detailed guidance on migrating the Vault backend from Consul to Vault's integrated storage, refer to the [storage migration tutorial](/vault/docs/configuration/storage#integrated-storage-vs-consul-as-vault-storage). Integrated storage improves resiliency by preventing a Consul outage from also affecting Vault functionality. diff --git a/website/content/docs/concepts/service-discovery.mdx b/website/content/docs/concepts/service-discovery.mdx index b1b4123e21d0..122e5a05bfc6 100644 --- a/website/content/docs/concepts/service-discovery.mdx +++ b/website/content/docs/concepts/service-discovery.mdx @@ -21,7 +21,7 @@ Service discovery provides benefits for all organizations, ranging from simplifi - Faster deployment times achieved by high-speed discovery - Automated service registration and de-registration -## How does a service mesh work? +## How does service discovery work? Service discovery uses a service's identity instead of traditional access information (IP address and port). This allows you to dynamically map services and track any changes within a service catalog. Service consumers (users or other services) then use DNS to dynamically retrieve other service's access information from the service catalog. The lifecycle of a service may look like the following: diff --git a/website/content/docs/connect/ca/vault.mdx b/website/content/docs/connect/ca/vault.mdx index 420045ec360f..2a37462241ef 100644 --- a/website/content/docs/connect/ca/vault.mdx +++ b/website/content/docs/connect/ca/vault.mdx @@ -7,38 +7,30 @@ description: >- # Vault as a Service Mesh Certificate Authority -Consul can be used with [Vault](https://www.vaultproject.io/) to -manage and sign certificates. -The Vault CA provider uses the -[Vault PKI secrets engine](https://www.vaultproject.io/docs/secrets/pki) -to generate and sign certificates. +You can configure Consul to use [Vault](https://www.vaultproject.io/) as the certificate authority (CA) so that Vault can manage and sign certificates distributed to services in the mesh. +The Vault CA provider uses the [Vault PKI secrets engine](https://www.vaultproject.io/docs/secrets/pki) to generate and sign certificates. +This page describes how configure the Vault CA provider. -This page documents the specifics of the Vault CA provider. -Please read the [certificate management overview](/docs/connect/ca) -page first to understand how Consul manages certificates with configurable -CA providers. - --> **Tip:** Complete the [tutorial](https://learn.hashicorp.com/tutorials/consul/vault-pki-consul-connect-ca?in=consul/vault-secure) to learn how to configure Vault as the Consul Connect service mesh Certification Authority. +> **Tutorial:** Complete the [Vault as Consul Service Mesh Certification Authority](/consul/tutorials/vault-secure/vault-pki-consul-connect-ca) tutorial for hands-on guidance on how to configure Vault as the Consul service mesh certification authority. ## Requirements -Prior to using Vault as a CA provider for Consul, the following requirements -must be met: +- Refer to [Service Mesh Certificate Authority Overview](/docs/connect/ca) for important background information about how Consul manages certificates with configurable CA providers. -- **Vault 0.10.3 or later.** Consul uses URI SANs in the PKI engine which - were introduced in Vault 0.10.3. Prior versions of Vault are not - compatible with Connect. +- Vault 0.10.3 to 1.10.x. -## Configuration +~> **Compatibility warning:** Do not use Vault v1.11.0+ as Consul's Connect CA provider — the intermediate CA becomes unable to issue the leaf nodes required by service mesh, and by Consul client agents if using auto-encrypt or auto-config and using TLS for agent communication. If you are already using Vault 1.11+ as a Connect CA, refer to this [Knowledge Base article](https://support.hashicorp.com/hc/en-us/articles/11308460105491) for more information about the underlying cause and recommended workaround. -The Vault CA is enabled by setting the CA provider to `"vault"` and -setting the required configuration values. +## Enable Vault as the CA -The configuration may either be provided in the agent's configuration file using -the [`ca_provider`] and [`ca_config`] options, or configured using the -[`/connect/ca/configuration`] API endpoint. +You can enable Vault as the CA by configuring Consul to use `"vault"` as the CA provider +and including the required provider configuration options. +You can provide the CA configuration in the server agents' configuration file +or in the body of a `PUT` request to the +[`/connect/ca/configuration`](/api-docs/connect/ca#update-ca-configuration) API endpoint. +Refer to the [Configuration Reference](#configuration-reference) for details about configuration options and for example use cases. -Example configurations are shown below: +The following example shows the required configurations for a default implementation: @@ -51,9 +43,9 @@ connect { ca_provider = "vault" ca_config { address = "http://localhost:8200" - token = "..." + token = "" root_pki_path = "connect-root" - intermediate_pki_path = "connect-intermediate" + intermediate_pki_path = "connect-dc1-intermediate" } } ``` @@ -67,9 +59,9 @@ connect { "Provider": "vault", "Config": { "Address": "http://localhost:8200", - "Token": "", + "Token": "", "RootPKIPath": "connect-root", - "IntermediatePKIPath": "connect-intermediate" + "IntermediatePKIPath": "connect-dc1-intermediate" } } ``` @@ -78,11 +70,12 @@ connect { -The configuration options are listed below. +## Configuration Reference --> **NOTE**: The first key is the value used in API calls, and the second key - (after the `/`) is used if you are adding the configuration to the agent's - configuration file. +You can specify the following configuration options. +Note that a configuration option's name may differ between API calls and the agent configuration file. +The first key refers to the option name for use in API calls. +The key after the slash refers to the corresponding option name in the agent configuration file. - `Address` / `address` (`string: `) - The address of the Vault server. @@ -113,7 +106,6 @@ The configuration options are listed below. default mount path `/var/run/secrets/kubernetes.io/serviceaccount/token` if the `jwt` parameter is not provided. - - `RootPKIPath` / `root_pki_path` (`string: `) - The path to a PKI secrets engine for the root certificate. @@ -128,7 +120,7 @@ The configuration options are listed below. When WAN Federation is enabled, each secondary datacenter must use the same Vault cluster and share the same `root_pki_path` with the primary datacenter. - To use an intermediate certificate as the primary CA in Consul initialize the + To use an intermediate certificate as the primary CA in Consul, initialize the `RootPKIPath` in Vault with a PEM bundle. The first certificate in the bundle must be the intermediate certificate that Consul will use as the primary CA. The last certificate in the bundle must be a root certificate. The bundle @@ -179,124 +171,199 @@ The configuration options are listed below. @include 'http_api_connect_ca_common_options.mdx' -## Root and Intermediate PKI Paths +### Root and Intermediate PKI Paths The Vault CA provider uses two separately configured [PKI secrets engines](https://www.vaultproject.io/docs/secrets/pki) -for managing Connect certificates. +for managing Consul service mesh certificates. -The `RootPKIPath` is the PKI engine for the root certificate. Consul will -use this root certificate to sign the intermediate certificate. Consul will -never attempt to write or modify any data within the root PKI path. +The `RootPKIPath` is the PKI engine for the root certificate. +Consul uses this root certificate to sign the intermediate certificate. +Consul does not attempt to write or modify any data within the root PKI path. The `IntermediatePKIPath` is the PKI engine used for storing the intermediate -signed with the root certificate. The intermediate is used to sign all leaf -certificates and Consul may periodically generate new intermediates for +signed with the root certificate. The intermediate signs all leaf +certificates, and Consul may periodically generate new intermediates for automatic rotation. Therefore, Consul requires write access to this path. -If either path does not exist, then Consul will attempt to mount and -initialize it. This requires additional privileges by the Vault token in use. -If the paths already exist, Consul will use them as configured. +For each path, if the path does not exist, Consul attempts to mount and initialize +a PKI secrets engine at that path. For this operation to succeed, +the provided [Vault token](#token) must have the [required Vault privileges](#vault-acl-policies). +If the path does already exist, Consul uses the PKI secrets engine at that path as configured. -## Vault ACL Policies +### Configure Vault ACL policies ((#vault-acl-policies)) -Vault PKI can be managed by either Consul or by Vault. If you want to manually create and tune the PKI secret engines used to store the root and intermediate certificates, use Vault Managed PKI Paths. If you want to have the PKI automatically managed for you, use Consul Managed PKI Paths. +The Vault CA provider requires a [Vault token](#token) with a specific set of Vault privileges +depending on whether you would prefer to control mount configuration from Vault or to delegate +that responsibility to Consul. -### Vault Managed PKI Paths +Use [Vault-managed PKI paths](#vault-managed-pki-paths) to obtain the following benefits: +- Enables use of a root CA external to Consul by instantiating the PKI secrets engine at + [`RootPKIPath`](#rootpkipath) with an intermediate certificate +- Retain full control over PKI mount creation, and over `RootPKIPath` mount configuration -The following Vault policy allows Consul to use pre-existing PKI paths in Vault. -Consul is granted read-only access to the PKI mount points and the Root CA, but is -granted full control of the Intermediate or Leaf CA for Connect clients. +Otherwise, use [Consul-managed PKI paths](#consul-managed-pki-paths) to let Consul fully automate PKI management. -In this example the `RootPKIPath` is `connect_root` and the `IntermediatePKIPath` -is `connect_inter`. These values should be updated for your environment. +The following sections describe the Vault policy needed for both options. +The policy snippets use placeholder values for `RootPKIPath` and `IntermediatePKIPath`. +Replace them to match the path values in your CA provider configuration. - +#### Define a policy for Vault-managed PKI paths ((#vault-managed-pki-paths)) -```hcl -# Existing PKI Mounts -path "/sys/mounts" { - capabilities = [ "read" ] -} +To use Vault-managed PKI paths, you must first instantiate and configure PKI secrets engines at +`RootPKIPath` and `IntermediatePKIPath`. -path "/sys/mounts/connect_root" { - capabilities = [ "read" ] -} +Then, attach the following Vault ACL policy to the CA provider's +[Vault token](#token) or [auth method](#authmethod): -path "/sys/mounts/connect_inter" { - capabilities = [ "read" ] -} +1. Allow Consul to read both PKI mounts and to manage the intermediate PKI mount configuration: -# Needed for Consul 1.11+ -path "/sys/mounts/connect_inter/tune" { - capabilities = [ "update" ] -} + -path "/connect_root/" { - capabilities = [ "read" ] -} + ```hcl + path "/sys/mounts/" { + capabilities = [ "read" ] + } -path "/connect_root/root/sign-intermediate" { - capabilities = [ "update" ] -} + path "/sys/mounts/" { + capabilities = [ "read" ] + } -path "/connect_inter/*" { - capabilities = [ "create", "read", "update", "delete", "list" ] -} + path "/sys/mounts//tune" { + capabilities = [ "update" ] + } + ``` -path "auth/token/renew-self" { - capabilities = [ "update" ] -} + -path "auth/token/lookup-self" { - capabilities = [ "read" ] -} -``` +1. Allow Consul read-only access to the root PKI engine, to automatically rotate + intermediate CAs as needed, and full use of the intermediate PKI engine: - + -### Consul Managed PKI Paths + ```hcl + path "//" { + capabilities = [ "read" ] + } + + path "//root/sign-intermediate" { + capabilities = [ "update" ] + } -The following Vault policy allows Consul to create and manage the PKI paths in Vault. -Consul is granted the ability to create the PKI mount points and given full -control of the Root and Intermediate or Leaf CA for Connect clients. + path "//*" { + capabilities = [ "create", "read", "update", "delete", "list" ] + } + ``` + -In this example the `RootPKIPath` is `connect_root` and the `IntermediatePKIPath` -is `connect_inter`. These values should be updated for your environment. +1. Allow Consul to renew its Vault token if the token is renewable. + The rule enables the token to be renewed whether it is provided + [directly](#token) in the CA provider configuration or presented in an [auth method](#authmethod). - + -```hcl -# Consul Managed PKI Mounts -path "/sys/mounts" { - capabilities = [ "read" ] -} + ```hcl + path "auth/token/renew-self" { + capabilities = [ "update" ] + } -path "/sys/mounts/connect_root" { - capabilities = [ "create", "read", "update", "delete", "list" ] -} + path "auth/token/lookup-self" { + capabilities = [ "read" ] + } + ``` + + -path "/sys/mounts/connect_inter" { - capabilities = [ "create", "read", "update", "delete", "list" ] -} +#### Define a policy for Consul-managed PKI paths ((#consul-managed-pki-paths)) -# Needed for Consul 1.11+ -path "/sys/mounts/connect_inter/tune" { - capabilities = [ "update" ] -} +To use Consul-managed PKI paths, ensure no PKI secrets engines are mounted at +`RootPKIPath` and `IntermediatePKIPath`. -path "/connect_root/*" { - capabilities = [ "create", "read", "update", "delete", "list" ] -} +Then, attach the following Vault ACL policy to the CA provider's +[Vault token](#token) or [auth method](#authmethod): -path "/connect_inter/*" { - capabilities = [ "create", "read", "update", "delete", "list" ] +1. Allow Consul to create and manage both PKI engines: + + + + ```hcl + path "/sys/mounts/" { + capabilities = [ "create", "read", "update", "delete", "list" ] + } + + path "/sys/mounts/" { + capabilities = [ "create", "read", "update", "delete", "list" ] + } + + path "/sys/mounts//tune" { + capabilities = [ "update" ] + } + ``` + + +1. Allow Consul full use of both PKI engines: + + + + ```hcl + path "//*" { + capabilities = [ "create", "read", "update", "delete", "list" ] + } + + path "//*" { + capabilities = [ "create", "read", "update", "delete", "list" ] + } + ``` + + + +1. Allow Consul to renew its Vault token if the token is renewable. + The rule enables the token to be renewed whether it is provided + [directly](#token) in the CA provider configuration or presented in an [auth method](#authmethod). + + + + ```hcl + path "auth/token/renew-self" { + capabilities = [ "update" ] + } + + path "auth/token/lookup-self" { + capabilities = [ "read" ] + } + ``` + + + +#### Additional Vault ACL policies for sensitive operations + +Additional Vault permissions are required while you perform the +following CA provider configuration changes: +- Changing the provider from Vault to a different provider, such as Consul's built-in provider +- Changing the `RootPKIPath` + +Those configuration modifications trigger a root CA change that requires an +extremely privileged root cross-sign operation. +For that operation to succeed, the CA provider's [Vault token](#token) or +[auth method](#authmethod) must contain the following rule: + + + +```hcl +path "/root/sign-self-issued" { + capabilities = [ "sudo", "update" ] } ``` - - -[`ca_config`]: /docs/agent/config/config-files#connect_ca_config -[`ca_provider`]: /docs/agent/config/config-files#connect_ca_provider -[`/connect/ca/configuration`]: /api-docs/connect/ca#update-ca-configuration +We recommend using the following process when performing such a CA provider +configuration change to minimize the time that a privileged Vault token is in use: +1. Create a new Vault token that includes both the `root/sign-self-issued` + permission and the standard permissions for the current Consul or Vault + managed PKI paths. +1. Modify the CA provider configuration to use that new Vault token. +1. Perform the CA provider configuration change that triggers the extremely privileged + root cross-sign operation. If the configuration change maintains Vault + as the provider but modifies `RootPKIPath`, the configuration change must + include a Vault token or auth method with standard permissions for the new + Consul or Vault managed PKI paths. diff --git a/website/content/docs/connect/cluster-peering/create-manage-peering.mdx b/website/content/docs/connect/cluster-peering/create-manage-peering.mdx deleted file mode 100644 index a2b08d9ee89d..000000000000 --- a/website/content/docs/connect/cluster-peering/create-manage-peering.mdx +++ /dev/null @@ -1,526 +0,0 @@ ---- -layout: docs -page_title: Cluster Peering - Create and Manage Connections -description: >- - Generate a peering token to establish communication, export services, and authorize requests for cluster peering connections. Learn how to create, list, read, check, and delete peering connections. ---- - - -# Create and Manage Cluster Peering Connections - -~> **Cluster peering is currently in beta:** Functionality associated with cluster peering is subject to change. You should never use the beta release in secure environments or production scenarios. Features in beta may have performance issues, scaling issues, and limited support.

    Cluster peering is not currently available in the HCP Consul offering. - -A peering token enables cluster peering between different datacenters. Once you generate a peering token, you can use it to establish a connection between clusters. Then you can export services and create intentions so that peered clusters can call those services. - -## Create a peering connection - -Cluster peering is not enabled by default on Consul servers. To peer clusters, you must first configure all Consul servers so that `peering` is `enabled` and the gRPC port(8502) accepts traffic from the peering cluster (e.g., `client_addr="0.0.0.0"`). For additional information, refer to [Configuration Files](/docs/agent/config/config-files). - -After enabling peering for all Consul servers, complete the following steps in order: - -1. Create a peering token -1. Establish a connection between clusters -1. Export services between clusters -1. Authorize services for peers - -You can generate peering tokens and initiate connections on any available agent using either the API or the Consul UI. If you use the API, we recommend performing these operations through a client agent in the partition you want to connect. - -The UI does not currently support exporting services between clusters or authorizing services for peers. - -### Create a peering token - -To begin the cluster peering process, generate a peering token in one of your clusters. The other cluster uses this token to establish the peering connection. - -Every time you generate a peering token, a single-use establishment secret is embedded in the token. Because regenerating a peering token invalidates the previously generated secret, you must use the most recently created token to establish peering connections. - - - - -In `cluster-01`, use the [`/peering/token` endpoint](/api-docs/peering#generate-a-peering-token) to issue a request for a peering token. - -```shell-session -$ curl --request POST --data '{"PeerName":"cluster-02"}' --url http://localhost:8500/v1/peering/token -``` - -The CLI outputs the peering token, which is a base64-encoded string containing the token details. - -Create a JSON file that contains the first cluster's name and the peering token. - - - -```json -{ - "PeerName": "cluster-01", - "PeeringToken": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImF1ZCI6IlNvbHIifQ.5T7L_L1MPfQ_5FjKGa1fTPqrzwK4bNSM812nW6oyjb8" -} -``` - - - - - - -In `cluster-01`, use the [`consul peering generate-token` command](/commands/peering/generate-token) to issue a request for a peering token. - -```shell-session -$ consul peering generate-token -name cluster-02 -``` - -The CLI outputs the peering token, which is a base64-encoded string containing the token details. -Save this value to a file or clipboard to be used in the next step on `cluster-02`. - - - - - -1. In the Consul UI for the datacenter associated with `cluster-01`, click **Peers**. -1. Click **Add peer connection**. -1. In the **Generate token** tab, enter `cluster-02` in the **Name of peer** field. -1. Click the **Generate token** button. -1. Copy the token before you proceed. You cannot view it again after leaving this screen. If you lose your token, you must generate a new one. - - - - -### Establish a connection between clusters - -Next, use the peering token to establish a secure connection between the clusters. - - - - -In one of the client agents in "cluster-02," use `peering_token.json` and the [`/peering/establish` endpoint](/api-docs/peering#establish-a-peering-connection) to establish the peering connection. This endpoint does not generate an output unless there is an error. - -```shell-session -$ curl --request POST --data @peering_token.json http://127.0.0.1:8500/v1/peering/establish -``` - -When you connect server agents through cluster peering, their default behavior is to peer to the `default` partition. To establish peering connections for other partitions through server agents, you must add the `Partition` field to `peering_token.json` and specify the partitions you want to peer. For additional configuration information, refer to [Cluster Peering - HTTP API](/api-docs/peering). - -You can dial the `peering/establish` endpoint once per peering token. Peering tokens cannot be reused after being used to establish a connection. If you need to re-establish a connection, you must generate a new peering token. - - - - - -In one of the client agents in "cluster-02," issue the [`consul peering establish` command](/commands/peering/establish) and specify the token generated in the previous step. The command establishes the peering connection. -The commands prints "Successfully established peering connection with cluster-01" after the connection is established. - -```shell-session -$ consul peering establish -name cluster-01 -peering-token token-from-generate -``` - -When you connect server agents through cluster peering, they peer their default partitions. -To establish peering connections for other partitions through server agents, you must add the `-partition` flag to the `establish` command and specify the partitions you want to peer. -For additional configuration information, refer to [`consul peering establish` command](/commands/peering/establish) . - -You can run the `peering establish` command once per peering token. -Peering tokens cannot be reused after being used to establish a connection. -If you need to re-establish a connection, you must generate a new peering token. - - - - - -1. In the Consul UI for the datacenter associated with `cluster 02`, click **Peers** and then **Add peer connection**. -1. Click **Establish peering**. -1. In the **Name of peer** field, enter `cluster-01`. Then paste the peering token in the **Token** field. -1. Click **Add peer**. - - - - -### Export services between clusters - -After you establish a connection between the clusters, you need to create a configuration entry that defines the services that are available for other clusters. Consul uses this configuration entry to advertise service information and support service mesh connections across clusters. - -First, create a configuration entry and specify the `Kind` as `"exported-services"`. - - - -```hcl -Kind = "exported-services" -Name = "default" -Services = [ - { - ## The name and namespace of the service to export. - Name = "service-name" - Namespace = "default" - - ## The list of peer clusters to export the service to. - Consumers = [ - { - ## The peer name to reference in config is the one set - ## during the peering process. - Peer = "cluster-02" - } - ] - } -] -``` - - - -Then, add the configuration entry to your cluster. - -```shell-session -$ consul config write peering-config.hcl -``` - -Before you proceed, wait for the clusters to sync and make services available to their peers. You can issue an endpoint query to [check the peered cluster status](#check-peered-cluster-status). - -### Authorize services for peers - -Before you can call services from peered clusters, you must set service intentions that authorize those clusters to use specific services. Consul prevents services from being exported to unauthorized clusters. - -First, create a configuration entry and specify the `Kind` as `"service-intentions"`. Declare the service on "cluster-02" that can access the service in "cluster-01." The following example sets service intentions so that "frontend-service" can access "backend-service." - - - -```hcl -Kind = "service-intentions" -Name = "backend-service" - -Sources = [ - { - Name = "frontend-service" - Peer = "cluster-02" - Action = "allow" - } -] -``` - - - -If the peer's name is not specified in `Peer`, then Consul assumes that the service is in the local cluster. - -Then, add the configuration entry to your cluster. - -```shell-session -$ consul config write peering-intentions.hcl -``` - -## Manage peering connections - -After you establish a peering connection, you can get a list of all active peering connections, read a specific peering connection's information, check peering connection health, and delete peering connections. - -### List all peering connections - -You can list all active peering connections in a cluster. - - - - -After you establish a peering connection, [query the `/peerings/` endpoint](/api-docs/peering#list-all-peerings) to get a list of all peering connections. For example, the following command requests a list of all peering connections on `localhost` and returns the information as a series of JSON objects: - -```shell-session -$ curl http://127.0.0.1:8500/v1/peerings - -[ - { - "ID": "462c45e8-018e-f19d-85eb-1fc1bcc2ef12", - "Name": "cluster-02", - "State": "ACTIVE", - "Partition": "default", - "PeerID": "e83a315c-027e-bcb1-7c0c-a46650904a05", - "PeerServerName": "server.dc1.consul", - "PeerServerAddresses": [ - "10.0.0.1:8300" - ], - "CreateIndex": 89, - "ModifyIndex": 89 - }, - { - "ID": "1460ada9-26d2-f30d-3359-2968aa7dc47d", - "Name": "cluster-03", - "State": "INITIAL", - "Partition": "default", - "Meta": { - "env": "production" - }, - "CreateIndex": 109, - "ModifyIndex": 119 - }, -] -``` - - - - -After you establish a peering connection, run the [`consul peering list`](/commands/peering/list) command to get a list of all peering connections. -For example, the following command requests a list of all peering connections and returns the information in a table: - -```shell-session -$ consul peerings list - -Name State Imported Svcs Exported Svcs Meta -cluster-02 ACTIVE 0 2 env=production -cluster-03 PENDING 0 0 - ``` - - - - -In the Consul UI, click **Peers**. The UI lists peering connections you created for clusters in a datacenter. - -The name that appears in the list is the name of the cluster in a different datacenter with an established peering connection. - - - -### Read a peering connection - -You can get information about individual peering connections between clusters. - - - - -After you establish a peering connection, [query the `/peering/` endpoint](/api-docs/peering#read-a-peering-connection) to get peering information about for a specific cluster. For example, the following command requests peering connection information for "cluster-02" and returns the info as a JSON object: - -```shell-session -$ curl http://127.0.0.1:8500/v1/peering/cluster-02 - -{ - "ID": "462c45e8-018e-f19d-85eb-1fc1bcc2ef12", - "Name": "cluster-02", - "State": "INITIAL", - "PeerID": "e83a315c-027e-bcb1-7c0c-a46650904a05", - "PeerServerName": "server.dc1.consul", - "PeerServerAddresses": [ - "10.0.0.1:8300" - ], - "CreateIndex": 89, - "ModifyIndex": 89 -} -``` - - - - -After you establish a peering connection, run the [`consul peering read`](/commands/peering/list) command to get peering information about for a specific cluster. -For example, the following command requests peering connection information for "cluster-02": - -```shell-session -$ consul peering read -name cluster-02 - -Name: cluster-02 -ID: 3b001063-8079-b1a6-764c-738af5a39a97 -State: ACTIVE -Meta: - env=production - -Peer ID: e83a315c-027e-bcb1-7c0c-a46650904a05 -Peer Server Name: server.dc1.consul -Peer CA Pems: 0 -Peer Server Addresses: - 10.0.0.1:8300 - -Imported Services: 0 -Exported Services: 2 - -Create Index: 89 -Modify Index: 89 - -``` - - - - -In the Consul UI, click **Peers**. The UI lists peering connections you created for clusters in that datacenter. Click the name of a peered cluster to view additional details about the peering connection. - - - -### Check peering connection health - -You can check the status of your peering connection to perform health checks. - -To confirm that the peering connection between your clusters remains healthy, query the [`health/service` endpoint](/api-docs/health) of one cluster from the other cluster. For example, in "cluster-02," query the endpoint and add the `peer=cluster-01` query parameter to the end of the URL. - -```shell-session -$ curl \ - "http://127.0.0.1:8500/v1/health/service/?peer=cluster-01" -``` - -A successful query includes service information in the output. - -### Delete peering connections - -You can disconnect the peered clusters by deleting their connection. Deleting a peering connection stops data replication to the peer and deletes imported data, including services and CA certificates. - - - - -In "cluster-01," request the deletion through the [`/peering/ endpoint`](/api-docs/peering#delete-a-peering-connection). - -```shell-session -$ curl --request DELETE http://127.0.0.1:8500/v1/peering/cluster-02 -``` - - - - -In "cluster-01," request the deletion through the [`consul peering delete`](/commands/peering/list) command. - -```shell-session -$ consul peering delete -name cluster-02 - -Successfully submitted peering connection, cluster-02, for deletion -``` - - - - -In the Consul UI, click **Peers**. The UI lists peering connections you created for clusters in that datacenter. - -Next to the name of the peer, click **More** (three horizontal dots) and then **Delete**. Click **Delete** to confirm and remove the peering connection. - - - - -## L7 traffic management between peers - -The following sections describe how to enable L7 traffic management features between peered clusters. - -### Service resolvers for redirects and failover - -As of Consul v1.14, you can use [dynamic traffic management](/consul/docs/connect/l7-traffic) to configure your service mesh so that services automatically failover and redirect between peers. The following examples update the [`service-resolver` config entry](/docs/connect/config-entries/) in `cluster-01` so that Consul redirects traffic intended for the `frontend` service to a backup instance in peer `cluster-02` when it detects multiple connection failures. - - - -```hcl -Kind = "service-resolver" -Name = "frontend" -ConnectTimeout = "15s" -Failover = { - "*" = { - Targets = [ - {Peer = "cluster-02"} - ] - } -} -``` - -```yaml -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceResolver -metadata: - name: frontend -spec: - connectTimeout: 15s - failover: - '*': - targets: - - peer: 'cluster-02' - service: 'frontend' - namespace: 'default' -``` - -```json -{ - "ConnectTimeout": "15s", - "Kind": "service-resolver", - "Name": "frontend", - "Failover": { - "*": { - "Targets": [ - { - "Peer": "cluster-02" - } - ] - } - }, - "CreateIndex": 250, - "ModifyIndex": 250 -} -``` - - - -### Service splitters and custom routes - -The `service-splitter` and `service-router` configuration entry kinds do not support directly targeting a service instance hosted on a peer. To split or route traffic to a service on a peer, you must combine the definition with a `service-resolver` configuration entry that defines the service hosted on the peer as an upstream service. For example, to split traffic evenly between `frontend` services hosted on peers, first define the desired behavior locally: - - - -```hcl -Kind = "service-splitter" -Name = "frontend" -Splits = [ - { - Weight = 50 - ## defaults to service with same name as configuration entry ("frontend") - }, - { - Weight = 50 - Service = "frontend-peer" - }, -] -``` - -```yaml -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceSplitter -metadata: - name: frontend -spec: - splits: - - weight: 50 - ## defaults to service with same name as configuration entry ("web") - - weight: 50 - service: frontend-peer -``` - -```json -{ - "Kind": "service-splitter", - "Name": "frontend", - "Splits": [ - { - "Weight": 50 - }, - { - "Weight": 50, - "Service": "frontend-peer" - } - ] -} -``` - - - -Then, create a local `service-resolver` configuration entry named `frontend-peer` and define a redirect targeting the peer and its service: - - - -```hcl -Kind = "service-resolver" -Name = "frontend-peer" -Redirect { - Service = frontend - Peer = "cluster-02" -} -``` - -```yaml -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceResolver -metadata: - name: frontend-peer -spec: - redirect: - peer: 'cluster-02' - service: 'frontend' -``` - -```json -{ - "Kind": "service-resolver", - "Name": "frontend-peer", - "Redirect": { - "Service": "frontend", - "Peer": "cluster-02" - } -} -``` - - -
    diff --git a/website/content/docs/connect/cluster-peering/index.mdx b/website/content/docs/connect/cluster-peering/index.mdx index dfff85d7b873..8a54c86899ca 100644 --- a/website/content/docs/connect/cluster-peering/index.mdx +++ b/website/content/docs/connect/cluster-peering/index.mdx @@ -1,32 +1,37 @@ --- layout: docs -page_title: Service Mesh - What is Cluster Peering? +page_title: Cluster Peering Overview description: >- - Cluster peering establishes communication between independent clusters in Consul, allowing services to interact across datacenters. Learn about the cluster peering process, differences with WAN federation for multi-datacenter deployments, and technical constraints. + Cluster peering establishes communication between independent clusters in Consul, allowing services to interact across datacenters. Learn how cluster peering works, its differences with WAN federation for multi-datacenter deployments, and how to troubleshoot common issues. --- -# What is Cluster Peering? +# Cluster peering overview -~> **Cluster peering is currently in beta**: Functionality associated with cluster peering is subject to change. You should never use the beta release in secure environments or production scenarios. Features in beta may have performance issues, scaling issues, and limited support.

    Cluster peering is not currently available in the HCP Consul offering. +This topic provides an overview of cluster peering, which lets you connect two or more independent Consul clusters so that services deployed to different partitions or datacenters can communicate. +Cluster peering is enabled in Consul by default. For specific information about cluster peering configuration and usage, refer to following pages. -You can create peering connections between two or more independent clusters so that services deployed to different partitions or datacenters can communicate. +## What is cluster peering? -## Overview +Consul supports cluster peering connections between two [admin partitions](/consul/docs/enterprise/admin-partitions) _in different datacenters_. Deployments without an Enterprise license can still use cluster peering because every datacenter automatically includes a default partition. Meanwhile, admin partitions _in the same datacenter_ do not require cluster peering connections because you can export services between them without generating or exchanging a peering token. -Cluster peering is a process that allows Consul clusters to communicate with each other. The cluster peering process consists of the following steps: +The following diagram describes Consul's cluster peering architecture. -1. Create a peering token in one cluster. -1. Use the peering token to establish peering with a second cluster. -1. Export services between clusters. -1. Create intentions to authorize services for peers. +![Diagram of cluster peering with admin partitions](/img/cluster-peering-diagram.png) -For detailed instructions on establishing cluster peering connections, refer to [Create and Manage Peering Connections](/docs/connect/cluster-peering/create-manage-peering). +In this diagram, the `default` partition in Consul DC 1 has a cluster peering connection with the `web` partition in Consul DC 2. Enforced by their respective mesh gateways, this cluster peering connection enables `Service B` to communicate with `Service C` as a service upstream. -> To learn how to peer clusters and connect services across peers in AWS Elastic Kubernetes Service (EKS) environments, complete the [Consul Cluster Peering on Kubernetes tutorial](https://learn.hashicorp.com/tutorials/consul/cluster-peering-aws?utm_source=docs). +Cluster peering leverages several components of Consul's architecture to enforce secure communication between services: -### Differences between WAN federation and cluster peering +- A _peering token_ contains an embedded secret that securely establishes communication when shared symetrically between datacenters. Sharing this token enables each datacenter's server agents to recognize requests from authorized peers, similar to how the [gossip encryption key secures agent LAN gossip](/consul/docs/security/encryption#gossip-encryption). +- A _mesh gateway_ encrypts outgoing traffic, decrypts incoming traffic, and directs traffic to healthy services. Consul's service mesh features must be enabled in order to use mesh gateways. Mesh gateways support the specific admin partitions they are deployed on. Refer to [Mesh gateways](/consul/docs/connect/gateways/mesh-gateway) for more information. +- An _exported service_ communicates with downstreams deployed in other admin partitions. They are explicitly defined in an [`exported-services` configuration entry](/consul/docs/connect/config-entries/exported-services). +- A _service intention_ secures [service-to-service communication in a service mesh](/consul/docs/connect/intentions). Intentions enable identity-based access between services by exchanging TLS certificates, which the service's sidecar proxy verifies upon each request. -WAN federation and cluster peering are different ways to connect Consul deployments. WAN federation connects multiple datacenters to make them function as if they were a single cluster, while cluster peering treats each datacenter as a separate cluster. As a result, WAN federation requires a primary datacenter to maintain and replicate global states such as ACLs and configuration entries, but cluster peering does not. +### Compared with WAN federation + +WAN federation and cluster peering are different ways to connect services through mesh gateways so that they can communicate across datacenters. WAN federation connects multiple datacenters to make them function as if they were a single cluster, while cluster peering treats each datacenter as a separate cluster. As a result, WAN federation requires a primary datacenter to maintain and replicate global states such as ACLs and configuration entries, but cluster peering does not. + +WAN federation and cluster peering also treat encrypted traffic differently. While mesh gateways between WAN federated datacenters use mTLS to keep data encrypted, mesh gateways between peers terminate mTLS sessions, decrypt data to HTTP services, and then re-encrypt traffic to send to services. Data must be decrypted in order to evaluate and apply dynamic routing rules at the destination cluster, which reduces coupling between peers. Regardless of whether you connect your clusters through WAN federation or cluster peering, human and machine users can use either method to discover services in other clusters or dial them through the service mesh. @@ -40,24 +45,49 @@ Regardless of whether you connect your clusters through WAN federation or cluste | Gossip protocol: Requires LAN gossip only | ❌ | ✅ | | Forwards service requests for service discovery | ✅ | ❌ | | Shares key/value stores | ✅ | ❌ | +| Can replicate ACL tokens, policies, and roles | ✅ | ❌ | + +## Guidance + +The following resources are available to help you use Consul's cluster peering features. + +### Tutorials + +- To learn how to peer clusters and connect services across peers in AWS Elastic Kubernetes Service (EKS) and Google Kubernetes Engine (GKE) environments, complete the [Connect services between Consul datacenters with cluster peering tutorial](/consul/tutorials/developer-mesh/cluster-peering). + +### Usage documentation + +- [Establish cluster peering connections](/consul/docs/connect/cluster-peering/usage/establish-cluster-peering) +- [Manage cluster peering connections](/consul/docs/connect/cluster-peering/usage/manage-connections) +- [Manage L7 traffic with cluster peering](/consul/docs/connect/cluster-peering/usage/peering-traffic-management) + +### Kubernetes documentation + +- [Cluster peering on Kubernetes technical specifications](/consul/docs/k8s/connect/cluster-peering/tech-specs) +- [Establish cluster peering connections on Kubernetes](/consul/docs/k8s/connect/cluster-peering/usage/establish-peering) +- [Manage cluster peering connections on Kubernetes](/consul/docs/k8s/connect/cluster-peering/usage/manage-peering) +- [Manage L7 traffic with cluster peering on Kubernetes](/consul/docs/k8s/connect/cluster-peering/usage/l7-traffic) + +### HCP Consul documentation + +- [Cluster peering](/hcp/docs/consul/usage/cluster-peering) +- [Cluster peering topologies](/hcp/docs/consul/usage/cluster-peering/topologies) +- [Establish cluster peering connnections on HCP Consul](/hcp/docs/consul/usage/cluster-peering/create-connections) +- [Cluster peering with management plane](/hcp/docs/consul/usage/management-plane#cluster-peering) -## Beta release features and constraints +### Reference documentation -The cluster peering beta release includes the following features and functionality: +- [Cluster peering technical specifications](/consul/docs/connect/cluster-peering/tech-specs) +- [HTTP API reference: `/peering/` endpoint](/consul/api-docs/peering) +- [CLI reference: `peering` command](/consul/commands/peering). -- **Consul v1.14 beta only**: Dynamic traffic control with a service resolver config entry can target failover and redirects to service instances in a peered cluster. -- Consul datacenters that are already federated stay federated. You do not need to migrate WAN federated clusters to cluster peering. -- Mesh gateways for _service to service traffic_ between clusters are available. For more information on configuring mesh gateways across peers, refer to [Service-to-service Traffic Across Peered Clusters](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-peers). -- You can generate peering tokens, establish, list, read, and delete peerings, and manage intentions for peering connections with both the API and the UI. -- You can configure [transparent proxies](/docs/connect/transparent-proxy) for peered services. -- You can use the [`peering` rule for ACL enforcement](/docs/security/acl/acl-rules#peering) of peering APIs. +## Basic troubleshooting -Not all features and functionality are available in the beta release. In particular, consider the following technical constraints: +If you experience errors when using Consul's cluster peering features, refer to the following list of technical constraints. -- Mesh gateways for _server to server traffic_ are not available. -- Services with node, instance, and check definitions totaling more than 50MB cannot be exported to a peer. -- The `service-splitter` and `service-router` configuration entry kinds cannot directly target a peer. To split or route traffic to a service instance on a peer, you must supplement your desired dynamic routing definition with a `service-resolver` config entry on the dialing cluster. Refer to [L7 traffic management between peers](/docs/connect/cluster-peering/create-manage-peering#L7-traffic) for more information. -- The `consul intention` CLI command is not supported. To manage intentions that specify services in peered clusters, use [configuration entries](/docs/connect/config-entries/service-intentions). +- Peer names can only contain lowercase characters. +- Services with node, instance, and check definitions totaling more than 8MB cannot be exported to a peer. +- Two admin partitions in the same datacenter cannot be peered. Use the [`exported-services` configuration entry](/consul/docs/connect/config-entries/exported-services#exporting-services-to-peered-clusters) instead. +- To manage intentions that specify services in peered clusters, use [configuration entries](/consul/docs/connect/config-entries/service-intentions). The `consul intention` CLI command is not supported. +- The Consul UI does not support exporting services between clusters or creating service intentions. Use either the API or the CLI to complete these required steps when establishing new cluster peering connections. - Accessing key/value stores across peers is not supported. -- Because non-Enterprise Consul instances are restricted to the `default` namespace, Consul Enterprise instances cannot export services from outside of the `default` namespace to non-Enterprise peers. -- Cross-cluster mesh gateways are supported in `remote` mode only. diff --git a/website/content/docs/connect/cluster-peering/k8s.mdx b/website/content/docs/connect/cluster-peering/k8s.mdx deleted file mode 100644 index 1bddbd5d3c3e..000000000000 --- a/website/content/docs/connect/cluster-peering/k8s.mdx +++ /dev/null @@ -1,499 +0,0 @@ ---- -layout: docs -page_title: Cluster Peering on Kubernetes -description: >- - If you use Consul on Kubernetes, learn how to enable cluster peering, create peering CRDs, and then manage peering connections in consul-k8s. ---- - -# Cluster Peering on Kubernetes - -~> **Cluster peering is currently in beta:** Functionality associated -with cluster peering is subject to change. You should never use the beta release in secure environments or production scenarios. Features in -beta may have performance issues, scaling issues, and limited support.

    Cluster peering is not currently available in the HCP Consul offering. - -To establish a cluster peering connection on Kubernetes, you need to enable the feature in the Helm chart and create custom resource definitions (CRDs) for each side of the peering. - -The following CRDs are used to create and manage a peering connection: - -- `PeeringAcceptor`: Generates a peering token and accepts an incoming peering connection. -- `PeeringDialer`: Uses a peering token to make an outbound peering connection with the cluster that generated the token. - -As of Consul v1.14, you can also [implement service failovers and redirects to control traffic](/consul/docs/connect/l7-traffic) between peers. - -> To learn how to peer clusters and connect services across peers in AWS Elastic Kubernetes Service (EKS) environments, complete the [Consul Cluster Peering on Kubernetes tutorial](https://learn.hashicorp.com/tutorials/consul/cluster-peering-aws?utm_source=docs). - -## Prerequisites - -You must implement the following requirements to create and use cluster peering connections with Kubernetes: - -- Consul v1.13.1 or later -- At least two Kubernetes clusters -- The installation must be running on Consul on Kubernetes version 0.47.1 or later - -### Prepare for installation - -Complete the following procedure after you have provisioned a Kubernetes cluster and set up your kubeconfig file to manage access to multiple Kubernetes clusters. - -1. Use the `kubectl` command to export the Kubernetes context names and then set them to variables for future use. For more information on how to use kubeconfig and contexts, refer to the [Kubernetes docs on configuring access to multiple clusters](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/). - - You can use the following methods to get the context names for your clusters: - - - Use the `kubectl config current-context` command to get the context for the cluster you are currently in. - - Use the `kubectl config get-contexts` command to get all configured contexts in your kubeconfig file. - - ```shell-session - $ export CLUSTER1_CONTEXT= - $ export CLUSTER2_CONTEXT= - ``` - -1. To establish cluster peering through Kubernetes, create a `values.yaml` file with the following Helm values. - - - - ```yaml - global: - name: consul - image: "hashicorp/consul:1.13.1" - peering: - enabled: true - connectInject: - enabled: true - dns: - enabled: true - enableRedirection: true - server: - exposeService: - enabled: true - controller: - enabled: true - meshGateway: - enabled: true - replicas: 1 - ``` - - - - These Helm values configure the servers in each cluster so that they expose ports over a Kubernetes load balancer service. For additional configuration options, refer to [`server.exposeService`](/docs/k8s/helm#v-server-exposeservice). - - When generating a peering token from one of the clusters, Consul includes a load balancer address in the token so that the peering stream goes through the load balancer in front of the servers. For additional configuration options, refer to [`global.peering.tokenGeneration`](/docs/k8s/helm#v-global-peering-tokengeneration). - -### Install Consul on Kubernetes - -Install Consul on Kubernetes by using the CLI to apply `values.yaml` to each cluster. - - 1. In `cluster-01`, run the following commands: - - ```shell-session - $ export HELM_RELEASE_NAME=cluster-01 - ``` - - ```shell-session - $ helm install ${HELM_RELEASE_NAME} hashicorp/consul --create-namespace --namespace consul --version "0.47.1" --values values.yaml --kube-context $CLUSTER1_CONTEXT - ``` - - 1. In `cluster-02`, run the following commands: - - ```shell-session - $ export HELM_RELEASE_NAME=cluster-02 - ``` - - ```shell-session - $ helm install ${HELM_RELEASE_NAME} hashicorp/consul --create-namespace --namespace consul --version "0.47.1" --values values.yaml --kube-context $CLUSTER2_CONTEXT - ``` - -## Create a peering connection for Consul on Kubernetes - -To peer Kubernetes clusters running Consul, you need to create a peering token and share it with the other cluster. Complete the following steps to create the peer connection. - -### Create a peering token - -Peers identify each other using the `metadata.name` values you establish when creating the `PeeringAcceptor` and `PeeringDialer` CRDs. - -1. In `cluster-01`, create the `PeeringAcceptor` custom resource. - - - - ```yaml - apiVersion: consul.hashicorp.com/v1alpha1 - kind: PeeringAcceptor - metadata: - name: cluster-02 ## The name of the peer you want to connect to - spec: - peer: - secret: - name: "peering-token" - key: "data" - backend: "kubernetes" - ``` - - - -1. Apply the `PeeringAcceptor` resource to the first cluster. - - ```shell-session - $ kubectl --context $CLUSTER1_CONTEXT apply --filename acceptor.yaml - ```` - -1. Save your peering token so that you can export it to the other cluster. - - ```shell-session - $ kubectl --context $CLUSTER1_CONTEXT get secret peering-token --output yaml > peering-token.yaml - ``` - -### Establish a peering connection between clusters - -1. Apply the peering token to the second cluster. - - ```shell-session - $ kubectl --context $CLUSTER2_CONTEXT apply --filename peering-token.yaml - ``` - -1. In `cluster-02`, create the `PeeringDialer` custom resource. - - - - ```yaml - apiVersion: consul.hashicorp.com/v1alpha1 - kind: PeeringDialer - metadata: - name: cluster-01 ## The name of the peer you want to connect to - spec: - peer: - secret: - name: "peering-token" - key: "data" - backend: "kubernetes" - ``` - - - -1. Apply the `PeeringDialer` resource to the second cluster. - - ```shell-session - $ kubectl --context $CLUSTER2_CONTEXT apply --filename dialer.yaml - ``` - -### Export services between clusters - -The examples described in this section demonstrate how to export a service named `backend`. You should change instances of `backend` in the example code to the name of the service you want to export. - -1. For the service in `cluster-02` that you want to export, add the `"consul.hashicorp.com/connect-inject": "true"` annotation to your service's pods prior to deploying. The annotation allows the workload to join the mesh. It is highlighted in the following example: - - - - ```yaml - # Service to expose backend - apiVersion: v1 - kind: Service - metadata: - name: backend - spec: - selector: - app: backend - ports: - - name: http - protocol: TCP - port: 80 - targetPort: 9090 - --- - apiVersion: v1 - kind: ServiceAccount - metadata: - name: backend - --- - # Deployment for backend - apiVersion: apps/v1 - kind: Deployment - metadata: - name: backend - labels: - app: backend - spec: - replicas: 1 - selector: - matchLabels: - app: backend - template: - metadata: - labels: - app: backend - annotations: - "consul.hashicorp.com/connect-inject": "true" - spec: - serviceAccountName: backend - containers: - - name: backend - image: nicholasjackson/fake-service:v0.22.4 - ports: - - containerPort: 9090 - env: - - name: "LISTEN_ADDR" - value: "0.0.0.0:9090" - - name: "NAME" - value: "backend" - - name: "MESSAGE" - value: "Response from backend" - ``` - - - -1. In `cluster-02`, create an `ExportedServices` custom resource. - - - - ```yaml - apiVersion: consul.hashicorp.com/v1alpha1 - kind: ExportedServices - metadata: - name: default ## The name of the partition containing the service - spec: - services: - - name: backend ## The name of the service you want to export - consumers: - - peer: cluster-01 ## The name of the peer that receives the service - ``` - - - -1. Apply the service file and the `ExportedServices` resource to the second cluster. - - ```shell-session - $ kubectl apply --context $CLUSTER2_CONTEXT --filename backend.yaml --filename exportedsvc.yaml - ``` - -### Authorize services for peers - -1. Create service intentions for the second cluster. - - - - ```yaml - apiVersion: consul.hashicorp.com/v1alpha1 - kind: ServiceIntentions - metadata: - name: backend-deny - spec: - destination: - name: backend - sources: - - name: "*" - action: deny - - name: frontend - action: allow - ``` - - - -1. Apply the intentions to the second cluster. - - ```shell-session - $ kubectl --context $CLUSTER2_CONTEXT apply --filename intention.yml - ``` - -1. Add the `"consul.hashicorp.com/connect-inject": "true"` annotation to your service's pods before deploying the workload so that the services in `cluster-01` can dial `backend` in `cluster-02`. To dial the upstream service from an application, configure the application so that that requests are sent to the correct DNS name as specified in [Service Virtual IP Lookups](/docs/discovery/dns#service-virtual-ip-lookups). In the following example, the annotation that allows the workload to join the mesh and the configuration provided to the workload that enables the workload to dial the upstream service using the correct DNS name is highlighted. - - - - ```yaml - # Service to expose frontend - apiVersion: v1 - kind: Service - metadata: - name: frontend - spec: - selector: - app: frontend - ports: - - name: http - protocol: TCP - port: 9090 - targetPort: 9090 - --- - apiVersion: v1 - kind: ServiceAccount - metadata: - name: frontend - --- - apiVersion: apps/v1 - kind: Deployment - metadata: - name: frontend - labels: - app: frontend - spec: - replicas: 1 - selector: - matchLabels: - app: frontend - template: - metadata: - labels: - app: frontend - annotations: - "consul.hashicorp.com/connect-inject": "true" - spec: - serviceAccountName: frontend - containers: - - name: frontend - image: nicholasjackson/fake-service:v0.22.4 - securityContext: - capabilities: - add: ["NET_ADMIN"] - ports: - - containerPort: 9090 - env: - - name: "LISTEN_ADDR" - value: "0.0.0.0:9090" - - name: "UPSTREAM_URIS" - value: "http://backend.virtual.cluster-02.consul" - - name: "NAME" - value: "frontend" - - name: "MESSAGE" - value: "Hello World" - - name: "HTTP_CLIENT_KEEP_ALIVES" - value: "false" - ``` - - - -1. Apply the service file to the first cluster. - - ```shell-session - $ kubectl --context $CLUSTER1_CONTEXT apply --filename frontend.yaml - ``` - -1. Run the following command in `frontend` and then check the output to confirm that you peered your clusters successfully. - - ```shell-session - $ kubectl --context $CLUSTER1_CONTEXT exec -it $(kubectl --context $CLUSTER1_CONTEXT get pod -l app=frontend -o name) -- curl localhost:9090 - - { - "name": "frontend", - "uri": "/", - "type": "HTTP", - "ip_addresses": [ - "10.16.2.11" - ], - "start_time": "2022-08-26T23:40:01.167199", - "end_time": "2022-08-26T23:40:01.226951", - "duration": "59.752279ms", - "body": "Hello World", - "upstream_calls": { - "http://backend.virtual.cluster-02.consul": { - "name": "backend", - "uri": "http://backend.virtual.cluster-02.consul", - "type": "HTTP", - "ip_addresses": [ - "10.32.2.10" - ], - "start_time": "2022-08-26T23:40:01.223503", - "end_time": "2022-08-26T23:40:01.224653", - "duration": "1.149666ms", - "headers": { - "Content-Length": "266", - "Content-Type": "text/plain; charset=utf-8", - "Date": "Fri, 26 Aug 2022 23:40:01 GMT" - }, - "body": "Response from backend", - "code": 200 - } - }, - "code": 200 - } - ``` - -## End a peering connection - -To end a peering connection, delete both the `PeeringAcceptor` and `PeeringDialer` resources. - -1. Delete the `PeeringDialer` resource from the second cluster. - - ```shell-session - $ kubectl --context $CLUSTER2_CONTEXT delete --filename dialer.yaml - ``` - -1. Delete the `PeeringAcceptor` resource from the first cluster. - - ```shell-session - $ kubectl --context $CLUSTER1_CONTEXT delete --filename acceptor.yaml - ```` - -1. Confirm that you deleted your peering connection in `cluster-01` by querying the the `/health` HTTP endpoint. The peered services should no longer appear. - - 1. Exec into the server pod for the first cluster. - - ```shell-session - $ kubectl exec -it consul-server-0 -- /bin/sh - ``` - - 1. Export an ACL token to access the `/health` HTP endpoint for services. The bootstrap token may be used if an ACL token is not already provisioned. - - ```shell-session - $ export CONSUL_HTTP_TOKEN= - ``` - - 1. Query the the `/health` HTTP endpoint. The peered services should no longer appear. - - ```shell-session - $ curl "localhost:8500/v1/health/connect/backend?peer=cluster-02" - ``` - -## Recreate or reset a peering connection - -To recreate or reset the peering connection, you need to generate a new peering token from the cluster where you created the `PeeringAcceptor`. - -1. In the `PeeringAcceptor` CRD, add the annotation `consul.hashicorp.com/peering-version`. If the annotation already exists, update its value to a higher version. - - - - ```yaml - apiVersion: consul.hashicorp.com/v1alpha1 - kind: PeeringAcceptor - metadata: - name: cluster-02 - annotations: - consul.hashicorp.com/peering-version: 1 ## The peering version you want to set. - spec: - peer: - secret: - name: "peering-token" - key: "data" - backend: "kubernetes" - ``` - - - -1. After updating `PeeringAcceptor`, repeat the following steps to create a peering connection: - 1. [Create a peering token](#create-a-peering-token) - 1. [Establish a peering connection between clusters](#establish-a-peering-connection-between-clusters) - 1. [Export services between clusters](#export-services-between-clusters) - 1. [Authorize services for peers](#authorize-services-for-peers) - - Your peering connection is re-established with the updated token. - -~> **Note:** The only way to create or set a new peering token is to manually adjust the value of the annotation `consul.hashicorp.com/peering-version`. Creating a new token causes the previous token to expire. - -## Traffic management between peers - -As of Consul v1.14, you can use [dynamic traffic management](/consul/docs/connect/l7-traffic) to configure your service mesh so that services automatically failover and redirect between peers. - -To configure automatic service failovers and redirect, edit the `ServiceResolver` CRD so that traffic resolves to a backup service instance on a peer. The following example updates the `ServiceResolver` CRD in `cluster-01` so that Consul redirects traffic intended for the `frontend` service to a backup instance in `cluster-02` when it detects multiple connection failures to the primary instance. - - - -```yaml -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceResolver -metadata: - name: frontend -spec: - connectTimeout: 15s - failover: - '*': - targets: - - peer: 'cluster-02' - service: 'backup' - namespace: 'default' -``` - - diff --git a/website/content/docs/connect/cluster-peering/tech-specs.mdx b/website/content/docs/connect/cluster-peering/tech-specs.mdx new file mode 100644 index 000000000000..c406f73e0f9c --- /dev/null +++ b/website/content/docs/connect/cluster-peering/tech-specs.mdx @@ -0,0 +1,74 @@ +--- +layout: docs +page_title: Cluster Peering Technical Specifications +description: >- + Cluster peering connections in Consul interact with mesh gateways, sidecar proxies, exported services, and ACLs. Learn about the configuration requirements for these components. +--- + +# Cluster peering technical specifications + +This reference topic describes the technical specifications associated with using cluster peering in your deployments. These specifications include required Consul components and their configurations. To learn more about Consul's cluster peering feature, refer to [cluster peering overview](/consul/docs/connect/cluster-peering). + +For cluster peering requirements in Kubernetes deployments, refer to [cluster peering on Kubernetes technical specifications](/consul/docs/k8s/connect/cluster-peering/tech-specs). + +## Requirements + +To use cluster peering features, make sure your Consul environment meets the following prerequisites: + +- Consul v1.14 or higher. +- A local Consul agent is required to manage mesh gateway configuration. +- Use [Envoy proxies](/consul/docs/connect/proxies/envoy). Envoy is the only proxy with mesh gateway capabilities in Consul. + +In addition, the following service mesh components are required in order to establish cluster peering connections: + +- [Cluster peering technical specifications](#cluster-peering-technical-specifications) + - [Requirements](#requirements) + - [Mesh gateway requirements](#mesh-gateway-requirements) + - [Mesh gateway modes](#mesh-gateway-modes) + - [Sidecar proxy requirements](#sidecar-proxy-requirements) + - [Exported service requirements](#exported-service-requirements) + - [ACL requirements](#acl-requirements) + +### Mesh gateway requirements + +Mesh gateways are required for routing service mesh traffic between partitions with cluster peering connections. Consider the following general requirements for mesh gateways when using cluster peering: + +- A cluster requires a registered mesh gateway in order to export services to peers. +- For Enterprise, this mesh gateway must also be registered in the same partition as the exported services and their `exported-services` configuration entry. +- To use the `local` mesh gateway mode, you must register a mesh gateway in the importing cluster. + +In addition, you must define the `Proxy.Config` settings using opaque parameters compatible with your proxy. Refer to the [Gateway options](/consul/docs/connect/proxies/envoy#gateway-options) and [Escape-hatch Overrides](/consul/docs/connect/proxies/envoy#escape-hatch-overrides) documentation for additional Envoy proxy configuration information. + +#### Mesh gateway modes + +By default, all cluster peering connections use mesh gateways in [remote mode](/consul/docs/connect/gateways/mesh-gateway/service-to-service-traffic-wan-datacenters#remote). Be aware of these additional requirements when changing a mesh gateway's mode. + +- For mesh gateways that connect peered clusters, you can set the `mode` as either `remote` or `local`. +- The `none` mode is invalid for mesh gateways with cluster peering connections. + +Refer to [mesh gateway modes](/consul/docs/connect/gateways/mesh-gateway#modes) for more information. + +## Sidecar proxy requirements + +The Envoy proxies that function as sidecars in your service mesh require configuration in order to properly route traffic to peers. Sidecar proxies are defined in the [service definition](/consul/docs/services/usage/define-services). + +- Configure the `proxy.upstreams` parameters to route traffic to the correct service, namespace, and peer. Refer to the [`upstreams`](/consul/docs/connect/registration/service-registration#upstream-configuration-reference) documentation for details. +- The `proxy.upstreams.destination_name` parameter is always required. +- The `proxy.upstreams.destination_peer` parameter must be configured to enable cross-cluster traffic. +- The `proxy.upstream/destination_namespace` configuration is only necessary if the destination service is in a non-default namespace. + +## Exported service requirements + +The `exported-services` configuration entry is required in order for services to communicate across partitions with cluster peering connections. + +Basic guidance on using the `exported-services` configuration entry is included in [Establish cluster peering connections](/consul/docs/k8s/connect/cluster-peering/usage/establish-peering). + +Refer to the [`exported-services` configuration entry](/consul/docs/connect/config-entries/exported-services) reference for more information. + +## ACL requirements + +If ACLs are enabled, you must add tokens to grant the following permissions: + +- Grant `service:write` permissions to services that define mesh gateways in their server definition. +- Grant `service:read` permissions for all services on the partition. +- Grant `mesh:write` permissions to the mesh gateways that participate in cluster peering connections. This permission allows a leaf certificate to be issued for mesh gateways to terminate TLS sessions for HTTP requests. \ No newline at end of file diff --git a/website/content/docs/connect/cluster-peering/usage/establish-cluster-peering.mdx b/website/content/docs/connect/cluster-peering/usage/establish-cluster-peering.mdx new file mode 100644 index 000000000000..ad4e7998b4a7 --- /dev/null +++ b/website/content/docs/connect/cluster-peering/usage/establish-cluster-peering.mdx @@ -0,0 +1,271 @@ +--- +layout: docs +page_title: Establish Cluster Peering Connections +description: >- + Generate a peering token to establish communication, export services, and authorize requests for cluster peering connections. Learn how to establish peering connections with Consul's HTTP API, CLI or UI. +--- + +# Establish cluster peering connections + +This page details the process for establishing a cluster peering connection between services deployed to different datacenters. You can interact with Consul's cluster peering features using the CLI, the HTTP API, or the UI. The overall process for establishing a cluster peering connection consists of the following steps: + +1. Create a peering token in one cluster. +1. Use the peering token to establish peering with a second cluster. +1. Export services between clusters. +1. Create intentions to authorize services for peers. + +Cluster peering between services cannot be established until all four steps are complete. + +For Kubernetes guidance, refer to [Establish cluster peering connections on Kubernetes](/consul/docs/k8s/connect/cluster-peering/usage/establish-peering). For HCP Consul guidance, refer to [Establish cluster peering connections on HCP Consul](/hcp/docs/consul/usage/cluster-peering/create-connections). + +## Requirements + +You must meet the following requirements to use cluster peering: + +- Consul v1.14.1 or higher +- Services hosted in admin partitions on separate datacenters + +If you need to make services available to an admin partition in the same datacenter, do not use cluster peering. Instead, use the [`exported-services` configuration entry](/consul/docs/connect/config-entries/exported-services) to make service upstreams available to other admin partitions in a single datacenter. + +### Mesh gateway requirements + +Mesh gateways are required for all cluster peering connections. Consider the following architectural requirements when creating mesh gateways: + +- A registered mesh gateway is required in order to export services to peers. +- For Enterprise, the mesh gateway that exports services must be registered in the same partition as the exported services and their `exported-services` configuration entry. +- To use the `local` mesh gateway mode, you must register a mesh gateway in the importing cluster. + +## Create a peering token + +To begin the cluster peering process, generate a peering token in one of your clusters. The other cluster uses this token to establish the peering connection. + +Every time you generate a peering token, a single-use secret for establishing the secret is embedded in the token. Because regenerating a peering token invalidates the previously generated secret, you must use the most recently created token to establish peering connections. + + + + +1. In `cluster-01`, use the [`consul peering generate-token` command](/consul/commands/peering/generate-token) to issue a request for a peering token. + + ```shell-session + $ consul peering generate-token -name cluster-02 + ``` + + The CLI outputs the peering token, which is a base64-encoded string containing the token details. + +1. Save this value to a file or clipboard to use in the next step on `cluster-02`. + + + + +1. In `cluster-01`, use the [`/peering/token` endpoint](/consul/api-docs/peering#generate-a-peering-token) to issue a request for a peering token. + + ```shell-session + $ curl --request POST --data '{"Peer":"cluster-02"}' --url http://localhost:8500/v1/peering/token + ``` + + The CLI outputs the peering token, which is a base64-encoded string containing the token details. + +1. Create a JSON file that contains the first cluster's name and the peering token. + + + + ```json + { + "Peer": "cluster-01", + "PeeringToken": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImF1ZCI6IlNvbHIifQ.5T7L_L1MPfQ_5FjKGa1fTPqrzwK4bNSM812nW6oyjb8" + } + ``` + + + + + + +To begin the cluster peering process, generate a peering token in one of your clusters. The other cluster uses this token to establish the peering connection. + +Every time you generate a peering token, a single-use secret for establishing the secret is embedded in the token. Because regenerating a peering token invalidates the previously generated secret, you must use the most recently created token to establish peering connections. + +1. In the Consul UI for the datacenter associated with `cluster-01`, click **Peers**. +1. Click **Add peer connection**. +1. In the **Generate token** tab, enter `cluster-02` in the **Name of peer** field. +1. Click the **Generate token** button. +1. Copy the token before you proceed. You cannot view it again after leaving this screen. If you lose your token, you must generate a new one. + + + + +## Establish a connection between clusters + +Next, use the peering token to establish a secure connection between the clusters. + + + + +1. In one of the client agents deployed to "cluster-02," issue the [`consul peering establish` command](/consul/commands/peering/establish) and specify the token generated in the previous step. + + ```shell-session + $ consul peering establish -name cluster-01 -peering-token token-from-generate + "Successfully established peering connection with cluster-01" + ``` + +When you connect server agents through cluster peering, they peer their default partitions. To establish peering connections for other partitions through server agents, you must add the `-partition` flag to the `establish` command and specify the partitions you want to peer. For additional configuration information, refer to [`consul peering establish` command](/consul/commands/peering/establish). + +You can run the `peering establish` command once per peering token. Peering tokens cannot be reused after being used to establish a connection. If you need to re-establish a connection, you must generate a new peering token. + + + + +1. In one of the client agents in "cluster-02," use `peering_token.json` and the [`/peering/establish` endpoint](/consul/api-docs/peering#establish-a-peering-connection) to establish the peering connection. This endpoint does not generate an output unless there is an error. + + ```shell-session + $ curl --request POST --data @peering_token.json http://127.0.0.1:8500/v1/peering/establish + ``` + +When you connect server agents through cluster peering, their default behavior is to peer to the `default` partition. To establish peering connections for other partitions through server agents, you must add the `Partition` field to `peering_token.json` and specify the partitions you want to peer. For additional configuration information, refer to [Cluster Peering - HTTP API](/consul/api-docs/peering). + +You can dial the `peering/establish` endpoint once per peering token. Peering tokens cannot be reused after being used to establish a connection. If you need to re-establish a connection, you must generate a new peering token. + + + + + +1. In the Consul UI for the datacenter associated with `cluster 02`, click **Peers** and then **Add peer connection**. +1. Click **Establish peering**. +1. In the **Name of peer** field, enter `cluster-01`. Then paste the peering token in the **Token** field. +1. Click **Add peer**. + + + + +## Export services between clusters + +After you establish a connection between the clusters, you need to create an `exported-services` configuration entry that defines the services that are available for other clusters. Consul uses this configuration entry to advertise service information and support service mesh connections across clusters. + +An `exported-services` configuration entry makes services available to another admin partition. While it can target admin partitions either locally or remotely. Clusters peers always export services to remote partitions. Refer to [exported service consumers](/consul/docs/connect/config-entries/exported-services#consumers-1) for more information. + +You must use the Consul CLI to complete this step. The HTTP API and the Consul UI do not support `exported-services` configuration entries. + + + + +1. Create a configuration entry and specify the `Kind` as `"exported-services"`. + + + + ```hcl + Kind = "exported-services" + Name = "default" + Services = [ + { + ## The name and namespace of the service to export. + Name = "service-name" + Namespace = "default" + + ## The list of peer clusters to export the service to. + Consumers = [ + { + ## The peer name to reference in config is the one set + ## during the peering process. + Peer = "cluster-02" + } + ] + } + ] + ``` + + + +1. Add the configuration entry to your cluster. + + ```shell-session + $ consul config write peering-config.hcl + ``` + +Before you proceed, wait for the clusters to sync and make services available to their peers. To check the peered cluster status, [read the cluster peering connection](/consul/docs/connect/cluster-peering/usage/manage-connections#read-a-peering-connection). + + + + +## Authorize services for peers + +Before you can call services from peered clusters, you must set service intentions that authorize those clusters to use specific services. Consul prevents services from being exported to unauthorized clusters. + +You must use the HTTP API or the Consul CLI to complete this step. The Consul UI supports intentions for local clusters only. + + + + +1. Create a configuration entry and specify the `Kind` as `"service-intentions"`. Declare the service on "cluster-02" that can access the service in "cluster-01." In the following example, the service intentions configuration entry authorizes the `backend-service` to communicate with the `frontend-service` that is hosted on remote peer `cluster-02`: + + + + ```hcl + Kind = "service-intentions" + Name = "backend-service" + + Sources = [ + { + Name = "frontend-service" + Peer = "cluster-02" + Action = "allow" + } + ] + ``` + + + + If the peer's name is not specified in `Peer`, then Consul assumes that the service is in the local cluster. + +1. Add the configuration entry to your cluster. + + ```shell-session + $ consul config write peering-intentions.hcl + ``` + + + + +1. Create a configuration entry and specify the `Kind` as `"service-intentions"`. Declare the service on "cluster-02" that can access the service in "cluster-01." In the following example, the service intentions configuration entry authorizes the `backend-service` to communicate with the `frontend-service` that is hosted on remote peer `cluster-02`: + + + + ```hcl + Kind = "service-intentions" + Name = "backend-service" + + Sources = [ + { + Name = "frontend-service" + Peer = "cluster-02" + Action = "allow" + } + ] + ``` + + + + If the peer's name is not specified in `Peer`, then Consul assumes that the service is in the local cluster. + +1. Add the configuration entry to your cluster. + + ```shell-session + $ curl --request PUT --data @peering-intentions.hcl http://127.0.0.1:8500/v1/config + ``` + + + + +### Authorize service reads with ACLs + +If ACLs are enabled on a Consul cluster, sidecar proxies that access exported services as an upstream must have an ACL token that grants read access. + +Read access to all imported services is granted using either of the following rules associated with an ACL token: + +- `service:write` permissions for any service in the sidecar's partition. +- `service:read` and `node:read` for all services and nodes, respectively, in sidecar's namespace and partition. + +For Consul Enterprise, the permissions apply to all imported services in the service's partition. These permissions are satisfied when using a [service identity](/consul/docs/security/acl/acl-roles#service-identities). + +Refer to [Reading servers](/consul/docs/connect/config-entries/exported-services#reading-services) in the `exported-services` configuration entry documentation for example rules. + +For additional information about how to configure and use ACLs, refer to [ACLs system overview](/consul/docs/security/acl). \ No newline at end of file diff --git a/website/content/docs/connect/cluster-peering/usage/manage-connections.mdx b/website/content/docs/connect/cluster-peering/usage/manage-connections.mdx new file mode 100644 index 000000000000..31cbc5e51bab --- /dev/null +++ b/website/content/docs/connect/cluster-peering/usage/manage-connections.mdx @@ -0,0 +1,137 @@ +--- +layout: docs +page_title: Manage Cluster Peering Connections +description: >- + Learn how to list, read, and delete cluster peering connections using Consul. You can use the HTTP API, the CLI, or the Consul UI to manage cluster peering connections. +--- + +# Manage cluster peering connections + +This usage topic describes how to manage cluster peering connections using the CLI, the HTTP API, and the UI. + +After you establish a cluster peering connection, you can get a list of all active peering connections, read a specific peering connection's information, and delete peering connections. + +For Kubernetes-specific guidance for managing cluster peering connections, refer to [Manage cluster peering connections on Kubernetes](/consul/docs/k8s/connect/cluster-peering/usage/manage-peering). + +## List all peering connections + +You can list all active peering connections in a cluster. + + + + + ```shell-session + $ consul peering list + Name State Imported Svcs Exported Svcs Meta + cluster-02 ACTIVE 0 2 env=production + cluster-03 PENDING 0 0 + ``` + +For more information, including optional flags and parameters, refer to the [`consul peering list` CLI command reference](/consul/commands/peering/list). + + + + +The following example shows how to format an API request to list peering connections: + + ```shell-session + $ curl --header "X-Consul-Token: 0137db51-5895-4c25-b6cd-d9ed992f4a52" http://127.0.0.1:8500/v1/peerings + ``` + +For more information, including optional parameters and sample responses, refer to the [`/peering` endpoint reference](/consul/api-docs/peering#list-all-peerings). + + + + +In the Consul UI, click **Peers**. + +The UI lists peering connections you created for clusters in a datacenter. The name that appears in the list is the name of the cluster in a different datacenter with an established peering connection. + + + + +## Read a peering connection + +You can get information about individual peering connections between clusters. + + + + + +The following example outputs information about a peering connection locally referred to as "cluster-02": + + ```shell-session + $ consul peering read -name cluster-02 + Name: cluster-02 + ID: 3b001063-8079-b1a6-764c-738af5a39a97 + State: ACTIVE + Meta: + env=production + + Peer ID: e83a315c-027e-bcb1-7c0c-a46650904a05 + Peer Server Name: server.dc1.consul + Peer CA Pems: 0 + Peer Server Addresses: + 10.0.0.1:8300 + + Imported Services: 0 + Exported Services: 2 + + Create Index: 89 + Modify Index: 89 + ``` + +For more information, including optional flags and parameters, refer to the [`consul peering read` CLI command reference](/consul/commands/peering/read). + + + + + ```shell-session + $ curl --header "X-Consul-Token: b23b3cad-5ea1-4413-919e-c76884b9ad60" http://127.0.0.1:8500/v1/peering/cluster-02 + ``` + +For more information, including optional parameters and sample responses, refer to the [`/peering` endpoint reference](/consul/api-docs/peering#read-a-peering-connection). + + + + +1. In the Consul UI, click **Peers**. + +1. Click the name of a peered cluster to view additional details about the peering connection. + + + + +## Delete peering connections + +You can disconnect the peered clusters by deleting their connection. Deleting a peering connection stops data replication to the peer and deletes imported data, including services and CA certificates. + + + + + The following examples deletes a peering connection to a cluster locally referred to as "cluster-02": + + ```shell-session + $ consul peering delete -name cluster-02 + Successfully submitted peering connection, cluster-02, for deletion + ``` + +For more information, including optional flags and parameters, refer to the [`consul peering delete` CLI command reference](/consul/commands/peering/delete). + + + + + ```shell-session + $ curl --request DELETE --header "X-Consul-Token: b23b3cad-5ea1-4413-919e-c76884b9ad60" http://127.0.0.1:8500/v1/peering/cluster-02 + ``` + +This endpoint does not return a response. For more information, including optional parameters, refer to the [`/peering` endpoint reference](/consul/api-docs/peering#delete-a-peering-connection). + + + +1. In the Consul UI, click **Peers**. The UI lists peering connections you created for clusters in that datacenter. +1. Next to the name of the peer, click **More** (three horizontal dots) and then **Delete**. +1. Click **Delete** to confirm and remove the peering connection. + + + diff --git a/website/content/docs/connect/cluster-peering/usage/peering-traffic-management.mdx b/website/content/docs/connect/cluster-peering/usage/peering-traffic-management.mdx new file mode 100644 index 000000000000..64183c98104c --- /dev/null +++ b/website/content/docs/connect/cluster-peering/usage/peering-traffic-management.mdx @@ -0,0 +1,168 @@ +--- +layout: docs +page_title: Cluster Peering L7 Traffic Management +description: >- + Combine service resolver configurations with splitter and router configurations to manage L7 traffic in Consul deployments with cluster peering connections. Learn how to define dynamic traffic rules to target peers for redirects and failover. +--- + +# Manage L7 traffic with cluster peering + +This usage topic describes how to configure and apply the [`service-resolver` configuration entry](/consul/docs/connect/config-entries/service-resolver) to set up redirects and failovers between services that have an existing cluster peering connection. + +For Kubernetes-specific guidance for managing L7 traffic with cluster peering, refer to [Manage L7 traffic with cluster peering on Kubernetes](/consul/docs/k8s/connect/cluster-peering/usage/l7-traffic). + +## Service resolvers for redirects and failover + +When you use cluster peering to connect datacenters through their admin partitions, you can use [dynamic traffic management](/consul/docs/connect/l7-traffic) to configure your service mesh so that services automatically forward traffic to services hosted on peer clusters. + +However, the `service-splitter` and `service-router` configuration entry kinds do not natively support directly targeting a service instance hosted on a peer. Before you can split or route traffic to a service on a peer, you must define the service hosted on the peer as an upstream service by configuring a failover in the `service-resolver` configuration entry. Then, you can set up a redirect in a second service resolver to interact with the peer service by name. + +For more information about formatting, updating, and managing configuration entries in Consul, refer to [How to use configuration entries](/consul/docs/agent/config-entries). + +## Configure dynamic traffic between peers + +To configure L7 traffic management behavior in deployments with cluster peering connections, complete the following steps in order: + +1. Define the peer cluster as a failover target in the service resolver configuration. + + The following examples update the [`service-resolver` configuration entry](/consul/docs/connect/config-entries/service-resolver) in `cluster-01` so that Consul redirects traffic intended for the `frontend` service to a backup instance in peer `cluster-02` when it detects multiple connection failures. + + + + ```hcl + Kind = "service-resolver" + Name = "frontend" + ConnectTimeout = "15s" + Failover = { + "*" = { + Targets = [ + {Peer = "cluster-02"} + ] + } + } + ``` + + ```json + { + "ConnectTimeout": "15s", + "Kind": "service-resolver", + "Name": "frontend", + "Failover": { + "*": { + "Targets": [ + { + "Peer": "cluster-02" + } + ] + } + }, + "CreateIndex": 250, + "ModifyIndex": 250 + } + ``` + + ```yaml + apiVersion: consul.hashicorp.com/v1alpha1 + kind: ServiceResolver + metadata: + name: frontend + spec: + connectTimeout: 15s + failover: + '*': + targets: + - peer: 'cluster-02' + service: 'frontend' + namespace: 'default' + ``` + + + +1. Define the desired behavior in `service-splitter` or `service-router` configuration entries. + + The following example splits traffic evenly between `frontend` services hosted on peers by defining the desired behavior locally: + + + + ```hcl + Kind = "service-splitter" + Name = "frontend" + Splits = [ + { + Weight = 50 + ## defaults to service with same name as configuration entry ("frontend") + }, + { + Weight = 50 + Service = "frontend-peer" + }, + ] + ``` + + ```json + { + "Kind": "service-splitter", + "Name": "frontend", + "Splits": [ + { + "Weight": 50 + }, + { + "Weight": 50, + "Service": "frontend-peer" + } + ] + } + ``` + + ```yaml + apiVersion: consul.hashicorp.com/v1alpha1 + kind: ServiceSplitter + metadata: + name: frontend + spec: + splits: + - weight: 50 + ## defaults to service with same name as configuration entry ("frontend") + - weight: 50 + service: frontend-peer + ``` + + + +1. Create a local `service-resolver` configuration entry named `frontend-peer` and define a redirect targeting the peer and its service: + + + + ```hcl + Kind = "service-resolver" + Name = "frontend-peer" + Redirect { + Service = frontend + Peer = "cluster-02" + } + ``` + + ```json + { + "Kind": "service-resolver", + "Name": "frontend-peer", + "Redirect": { + "Service": "frontend", + "Peer": "cluster-02" + } + } + ``` + + ```yaml + apiVersion: consul.hashicorp.com/v1alpha1 + kind: ServiceResolver + metadata: + name: frontend-peer + spec: + redirect: + peer: 'cluster-02' + service: 'frontend' + ``` + + diff --git a/website/content/docs/connect/config-entries/exported-services.mdx b/website/content/docs/connect/config-entries/exported-services.mdx index 5c6dd2a09d2c..283f9f56d934 100644 --- a/website/content/docs/connect/config-entries/exported-services.mdx +++ b/website/content/docs/connect/config-entries/exported-services.mdx @@ -62,7 +62,7 @@ spec: services: - name: consumers: - - peerName: + - peer: ``` ```json @@ -113,7 +113,7 @@ spec: - name: namespace: consumers: - - peerName: + - peer: ``` ```json @@ -266,10 +266,10 @@ spec: services: - name: payments consumers: - - peerName: web-shop + - peer: web-shop - name: refunds consumers: - - peerName: web-shop + - peer: web-shop ``` ```json @@ -341,11 +341,11 @@ spec: - name: payments namespace: billing consumers: - - peerName: web-shop + - peer: web-shop - name: refunds namespace: billing consumers: - - peerName: web-shop + - peer: web-shop ``` ```json @@ -494,8 +494,8 @@ spec: services: - name: * consumers: - - peerName: monitoring - - peerName: platform + - peer: monitoring + - peer: platform ``` ```json @@ -557,8 +557,8 @@ spec: - name: * namespace: * consumers: - - peerName: monitoring - - peerName: platform + - peer: monitoring + - peer: platform ``` ```json @@ -661,20 +661,236 @@ The following example queries the `finance` peer for the imported `payments` ser ```shell-session $ curl 'localhost:8500/v1/health/service/payments?peer=finance' ``` +An ACL token with either of the following permissions is required in the cluster where the query is made: +- `service:write` permissions for any service. +- `service:read` and `node:read` for all services and nodes, respectively. + +If the call in the previous example is made from a service named `web`, then the request requires either: +- A token with `service:write` permissions to `web`. +- A token with `service:read` and `node:read` to all names in the datacenter. + + + +```hcl +service "web" { + policy = "write" +} + +# OR + +service_prefix "" { + policy = "read" +} +node_prefix "" { + policy = "read" +} +``` + +```json +{ + "service": { + "web": { + "policy": "write" + } + } +} + +## OR + +{ + "service_prefix": { + "": { + "policy": "read" + } + }, + "node_prefix": { + "": { + "policy": "read" + } + } +} + +``` + + + - + The following example queries the `finance` partition for the imported `payments` service: ```shell-session $ curl 'localhost:8500/v1/health/service/payments?partition=finance' ``` + +An ACL token with either of the following permissions is required in the cluster where the query is made: +- `service:write` permissions for any service in the partition where the query is made. +- `service:read` and `node:read` for all services and nodes, respectively, in any namespace and the exact partition where the query is made. + +If the call in the previous example is made from a service named `web` in a partition named `frontend`, then the request requires either: +- A token with `service:write` permissions to `web` in the `frontend` partition. +- A token with `service:read` and `node:read` to all names in the `frontend` partition, for any namespace. + + + +```hcl +partition "frontend" { + namespace "dev" { # This could be any namespace + service "web" { + policy = "write" + } + } +} + +# OR + +partition "frontend" { + namespace "dev" { # This could be any namespace + service_prefix "" { + policy = "read" + } + node_prefix "" { + policy = "read" + } + } +} +``` + +```json +{ + "partition": { + "frontend": { + "namespace": { + ## The following could be any namespace + "dev": { + "service": { + "web": { + "policy": "write" + } + } + } + } + } + } +} + +## OR + +{ + "partition": { + "frontend": { + "namespace": { + ## The following could be any namespace + "dev": { + "service_prefix": { + "": { + "policy": "read" + } + }, + "node_prefix": { + "": { + "policy": "read" + } + } + } + } + } + } +} +``` + + + - -An ACL token with `service:write` permissions is required for the cluster the query is made from. If the call in the previous example is made from a service named `web` in a partition named `frontend`, then the request requires a token with `write` permissions to `web` in the `frontend` partition. + + +The following example queries the `finance` peer for the imported `payments` service: + +```shell-session +$ curl 'localhost:8500/v1/health/service/payments?peer=finance' +``` + +An ACL token with either of the following permissions is required in the cluster where the query is made: +- `service:write` permissions for any service in the partition where the query is made. +- `service:read` and `node:read` for all services and nodes, respectively, in any namespace and the exact partition where the query is made. + +If the call in the previous example is made from a service named `web` in a partition named `frontend`, then the request requires either: +- A token with `service:write` permissions to `web` in the `frontend` partition. +- A token with `service:read` and `node:read` to all names in the `frontend` partition, for any namespace. -Exports are available to all services in the consumer cluster. In the previous example, any service with `write` permissions for the `frontend` partition can read exports. + + +```hcl +partition "frontend" { + namespace "dev" { # This could be any namespace + service "web" { + policy = "write" + } + } +} + +# OR + +partition "frontend" { + namespace "dev" { # This could be any namespace + service_prefix "" { + policy = "read" + } + node_prefix "" { + policy = "read" + } + } +} +``` + +```json +{ + "partition": { + "frontend": { + "namespace": { + ## The following could be any namespace + "dev": { + "service": { + "web": { + "policy": "write" + } + } + } + } + } + } +} + +## OR + +{ + "partition": { + "frontend": { + "namespace": { + ## The following could be any namespace + "dev": { + "service_prefix": { + "": { + "policy": "read" + } + }, + "node_prefix": { + "": { + "policy": "read" + } + } + } + } + } + } +} +``` + + + + + -For additional information, refer to [Health HTTP Endpoint](/api-docs/health). \ No newline at end of file +For additional information, refer to [Health HTTP Endpoint](/api-docs/health). diff --git a/website/content/docs/connect/config-entries/index.mdx b/website/content/docs/connect/config-entries/index.mdx index ec92c57b2a6d..23e3d0bd2382 100644 --- a/website/content/docs/connect/config-entries/index.mdx +++ b/website/content/docs/connect/config-entries/index.mdx @@ -17,8 +17,8 @@ The following configuration entries are supported: - [Mesh](/docs/connect/config-entries/mesh) - controls mesh-wide configuration that applies across namespaces and federated datacenters. -- [Exported Services](/docs/connect/config-entries/exported-services) - enables - Consul to export service instances to other admin partitions. +- [Exported Services](/docs/connect/config-entries/exported-services) - enables + Consul to export service instances to other peers or to other admin partitions local or remote to the datacenter. - [Proxy Defaults](/docs/connect/config-entries/proxy-defaults) - controls proxy configuration diff --git a/website/content/docs/connect/config-entries/ingress-gateway.mdx b/website/content/docs/connect/config-entries/ingress-gateway.mdx index 785dff91a49c..ff30edcd369c 100644 --- a/website/content/docs/connect/config-entries/ingress-gateway.mdx +++ b/website/content/docs/connect/config-entries/ingress-gateway.mdx @@ -93,6 +93,9 @@ spec: + +For Kubernetes environments, the configuration entry is always created in the same partition as the Kubernetes cluster. + ```hcl @@ -122,7 +125,6 @@ kind: IngressGateway metadata: name: namespace: - partition: spec: listeners: @@ -177,10 +179,9 @@ gateway: - All services with the same [protocol](/docs/connect/config-entries/ingress-gateway#protocol) as the listener will be routable. -- The ingress gateway will route traffic based on the host/authority header, - expecting a value matching `.ingress.*`, or if using namespaces, - `.ingress..*`. This matches the [Consul DNS - ingress subdomain](/docs/discovery/dns#ingress-service-lookups). +- The ingress gateway routes traffic based on the host or authority header and expects a value matching either `.ingress.*` or + `.ingress..*`. The query matches the [Consul DNS + ingress subdomain](/consul/docs/services/discovery/dns-static-lookups#ingress-service-lookups). A wildcard specifier cannot be set on a listener of protocol `tcp`. diff --git a/website/content/docs/connect/config-entries/proxy-defaults.mdx b/website/content/docs/connect/config-entries/proxy-defaults.mdx index a26c724e0998..ca3e8e415089 100644 --- a/website/content/docs/connect/config-entries/proxy-defaults.mdx +++ b/website/content/docs/connect/config-entries/proxy-defaults.mdx @@ -344,7 +344,7 @@ spec: name: 'MeshGateway', type: 'MeshGatewayConfig: ', description: `Controls the default - [mesh gateway configuration](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters#connect-proxy-configuration) + [mesh gateway configuration](/docs/connect/gateways/mesh-gateway#connect-proxy-configuration) for all proxies. Added in v1.6.0.`, children: [ { diff --git a/website/content/docs/connect/config-entries/service-defaults.mdx b/website/content/docs/connect/config-entries/service-defaults.mdx index 0ba3d56f525f..1e8d83f708fd 100644 --- a/website/content/docs/connect/config-entries/service-defaults.mdx +++ b/website/content/docs/connect/config-entries/service-defaults.mdx @@ -1,29 +1,1157 @@ --- layout: docs -page_title: Service Defaults - Configuration Entry Reference -description: >- - The service defaults configuration entry kind defines sets of default configurations that apply to all services in the mesh. Use the examples learn how to define a default protocol, default upstream configuration, and default terminating gateway. +page_title: Service Defaults Configuration Reference +description: -> + Use the service-defaults configuration entry to set default configurations for services, such as upstreams, protocols, and namespaces. Learn how to configure service-defaults. --- -# Service Defaults Configuration Entry +# Service Defaults Configuration Reference +This topic describes how to configure service defaults configuration entries. The service defaults configuration entry contains common configuration settings for service mesh services, such as upstreams and gateways. Refer to [Define service defaults](/consul/docs/services/usage/define-services#define-service-defaults) for usage information. --> **v1.8.4+:** On Kubernetes, the `ServiceDefaults` custom resource is supported in Consul versions 1.8.4+.
    -**v1.5.0+:** On other platforms, this config entry is supported in Consul versions 1.5.0+. +## Configuration model -The `service-defaults` config entry kind (`ServiceDefaults` on Kubernetes) controls default global values for a -service, such as its protocol. +The following outline shows how to format the service splitter configuration entry. Click on a property name to view details about the configuration. -## Sample Config Entries + + + +- [`Kind`](#kind): string | required +- [`Name`](#name): string | required +- [`Namespace`](#namespace): string +- [`Partition`](#partition): string +- [`Meta`](#meta): map | no default +- [`Protocol`](#protocol): string | default: `tcp` +- [`BalanceInboundConnections`](#balanceinboundconnections): string | no default +- [`Mode`](#mode): string | no default +- [`UpstreamConfig`](#upstreamconfig): map | no default + - [`Overrides`](#upstreamconfig-overrides): map | no default + - [`Name`](#upstreamconfig-overrides-name): string | no default + - [`Namespace`](#upstreamconfig-overrides-namespace): string | no default + - [`Protocol`](#upstreamconfig-overrides-protocol): string | no default + - [`ConnectTimeoutMs`](#upstreamconfig-overrides-connecttimeoutms): int | default: `5000` + - [`MeshGateway`](#upstreamconfig-overrides-meshgateway): map | no default + - [`mode`](#upstreamconfig-overrides-meshgateway): string | no default + - [`BalanceOutboundConnections`](#upstreamconfig-overrides-balanceoutboundconnections): string | no default + - [`Limits`](#upstreamconfig-overrides-limits): map | optional + - [`MaxConnections`](#upstreamconfig-overrides-limits): integer | `0` + - [`MaxPendingRequests`](#upstreamconfig-overrides-limits): integer | `0` + - [`MaxConcurrentRequests`](#upstreamconfig-overrides-limits): integer | `0` + - [`PassiveHealthCheck`](#upstreamconfig-overrides-passivehealthcheck): map | optional + - [`Interval`](#upstreamconfig-overrides-passivehealthcheck): string | `0s` + - [`MaxFailures`](#upstreamconfig-overrides-passivehealthcheck): integer | `0` + - [`EnforcingConsecutive5xx`](#upstreamconfig-overrides-passivehealthcheck): integer | `100` + - [`Defaults`](#upstreamconfig-defaults): map | no default + - [`Protocol`](#upstreamconfig-defaults-protocol): string | no default + - [`ConnectTimeoutMs`](#upstreamconfig-defaults-connecttimeoutms): int | default: `5000` + - [`MeshGateway`](#upstreamconfig-defaults-meshgateway): map | no default + - [`mode`](#upstreamconfig-defaults-meshgateway): string | no default + - [`BalanceOutboundConnections`](#upstreamconfig-defaults-balanceoutboundconnections): string | no default + - [`Limits`](#upstreamconfig-defaults-limits): map | optional + - [`MaxConnections`](#upstreamconfig-defaults-limits): integer | `0` + - [`MaxPendingRequests`](#upstreamconfig-defaults-limits): integer | `0` + - [`MaxConcurrentRequests`](#upstreamconfig-defaults-limits): integer | `0` + - [`PassiveHealthCheck`](#upstreamconfig-defaults-passivehealthcheck): map | optional + - [`Interval`](#upstreamconfig-defaults-passivehealthcheck): string | `0s` + - [`MaxFailures`](#upstreamconfig-defaults-passivehealthcheck): integer | `0` + - [`EnforcingConsecutive5xx`](#upstreamconfig-defaults-passivehealthcheck): integer | +- [`TransparentProxy`](#transparentproxy): map | no default + - [`OutboundListenerPort`](#transparentproxy): integer | `15001` + - [`DialedDirectly`](#transparentproxy ): boolean | `false` +- [`Destination`](#destination): map | no default + - [`Addresses`](#destination): list | no default + - [`Port`](#destination): integer | `0` +- [`MaxInboundConnections`](#maxinboundconnections): integer | `0` +- [`LocalConnectTimeoutMs`](#localconnecttimeoutms): integer | `0` +- [`LocalRequestTimeoutMs`](#localrequesttimeoutms): integer | `0` +- [`MeshGateway`](#meshgateway): map | no default + - [`Mode`](#meshgateway): string | no default +- [`ExternalSNI`](#externalsni): string | no default +- [`Expose`](#expose): map | no default + - [`Checks`](#expose-checks): boolean | `false` + - [`Paths`](#expose-paths): list | no default + - [`Path`](#expose-paths): string | no default + - [`LocalPathPort`](#expose-paths): integer | `0` + - [`ListenerPort`](#expose-paths): integer | `0` + - [`Protocol`](#expose-paths): string | `http` + + + + +- [`apiVersion`](#apiversion): string | must be set to `consul.hashicorp.com/v1alpha1` +- [`kind`](#kind): string | no default +- [`metadata`](#metadata): map | no default + - [`name`](#name): string | no default + - [`namespace`](#namespace): string | no default | +- [`spec`](#spec): map | no default + - [`protocol`](#protocol): string | default: `tcp` + - [`balanceInboundConnections`](#balanceinboundconnections): string | no default + - [`mode`](#mode): string | no default + - [`upstreamConfig`](#upstreamconfig): map | no default + - [`overrides`](#upstreamconfig-overrides): list | no default + - [`name`](#upstreamconfig-overrides-name): string | no default + - [`namespace`](#upstreamconfig-overrides-namespace): string | no default + - [`protocol`](#upstreamconfig-overrides-protocol): string | no default + - [`connectTimeoutMs`](#upstreamconfig-overrides-connecttimeoutms): int | default: `5000` + - [`meshGateway`](#upstreamconfig-overrides-meshgateway): map | no default + - [`mode`](#upstreamconfig-overrides-meshgateway): string | no default + - [`balanceOutboundConnections`](#overrides-balanceoutboundconnections): string | no default + - [`limits`](#upstreamconfig-overrides-limits): map | optional + - [`maxConnections`](#upstreamconfig-overrides-limits): integer | `0` + - [`maxPendingRequests`](#upstreamconfig-overrides-limits): integer | `0` + - [`maxConcurrentRequests`](#upstreamconfig-overrides-limits): integer | `0` + - [`passiveHealthCheck`](#upstreamconfig-overrides-passivehealthcheck): map | optional + - [`interval`](#upstreamconfig-overrides-passivehealthcheck): string | `0s` + - [`maxFailures`](#upstreamconfig-overrides-passivehealthcheck): integer | `0` + - [`mnforcingConsecutive5xx`](#upstreamconfig-overrides-passivehealthcheck): integer | `100` + - [`defaults`](#upstreamconfig-defaults): map | no default + - [`protocol`](#upstreamconfig-defaults-protocol): string | no default + - [`connectTimeoutMs`](#upstreamconfig-defaults-connecttimeoutms): int | default: `5000` + - [`meshGateway`](#upstreamconfig-defaults-meshgateway): map | no default + - [`mode`](#upstreamconfig-defaults-meshgateway): string | no default + - [`balanceOutboundConnections`](#upstreamconfig-defaults-balanceoutboundconnections): string | no default + - [`limits`](#upstreamconfig-defaults-limits): map | optional + - [`maxConnections`](#upstreamconfig-defaults-limits): integer | `0` + - [`maxPendingRequests`](#upstreamconfig-defaults-limits): integer | `0` + - [`maxConcurrentRequests`](#upstreamconfig-defaults-limits): integer | `0` + - [`passiveHealthCheck`](#upstreamconfig-defaults-passivehealthcheck): map | optional + - [`interval`](#upstreamconfig-defaults-passivehealthcheck): string | `0s` + - [`maxFailures`](#upstreamconfig-defaults-passivehealthcheck): integer | `0` + - [`enforcingConsecutive5xx`](#upstreamconfig-defaults-passivehealthcheck): integer | + - [`transparentProxy`](#transparentproxy): map | no default + - [`outboundListenerPort`](#transparentproxy): integer | `15001` + - [`dialedDirectly`](#transparentproxy): boolean | `false` + - [`destination`](#destination): map | no default + - [`addresses`](#destination): list | no default + - [`port`](#destination): integer | `0` + - [`maxInboundConnections`](#maxinboundconnections): integer | `0` + - [`localConnectTimeoutMs`](#localconnecttimeoutms): integer | `0` + - [`localRequestTimeoutMs`](#localrequesttimeoutms): integer | `0` + - [`meshGateway`](#meshgateway): map | no default + - [`mode`](#meshgateway): string | no default + - [`externalSNI`](#externalsni): string | no defaiult + - [`expose`](#expose): map | no default + - [`checks`](#expose-checks): boolean | `false` + - [`paths`](#expose-paths): list | no default + - [`path`](#expose-paths): string | no default + - [`localPathPort`](#expose-paths): integer | `0` + - [`listenerPort`](#expose-paths): integer | `0` + - [`protocol`](#expose-paths): string | `http` + + + + +## Complete configuration + +When every field is defined, a service splitter configuration entry has the following form: + + + + +```hcl +Kind = "service-defaults" +Name = "service_name" +Namespace = "namespace" +Partition = "partition" +Meta = { + Key = "value" +} +Protocol = "tcp" +BalanceInboundConnections = "exact_balance" +Mode = "transparent" +UpstreamConfig = { + Overrides = { + Name = "name-of-upstreams-to-override" + Namespace = "namespace-containing-upstreams-to-override" + Protocol = "http" + ConnectTimeoutMs = 100 + MeshGateway = { + mode = "remote" + } + BalanceOutboundConnections = "exact_balance" + Limits = { + MaxConnections = 10 + MaxPendingRequests = 50 + MaxConcurrentRequests = 100 + } + PassiveHealthCheck = { + Interval = "5s" + MaxFailures = 5 + EnforcingConsecutive5xx = 99 + } + } + Defaults = { + Protocol = "http2" + ConnectTimeoutMs = 2000 + MeshGateway = { + mode = "local" + } + BalanceOutboundConnections = "exact_balance" + Limits = { + MaxConnections = 100 + MaxPendingRequests = 500 + MaxConcurrentRequests = 1000 + } + PassiveHealthCheck = { + Interval = "1s" + MaxFailures = 1 + EnforcingConsecutive5xx = 89 + } + } +} +TransparentProxy = { + OutboundListenerPort = 15002 + DialedDirectly = true +} +Destination = { + Addresses = [ + "First IP address", + "Second IP address" + ] + Port = 88 +} +MaxInboundConnections = 100 +LocalConnectTimeoutMs = 10 +LocalRequestTimeoutMs = 10 +MeshGateway = { + Mode = "remote" +} +ExternalSNI = "sni-server-host" +Expose = { + Checks = true + Paths = [ + { + Path = "/local/dir" + LocalPathPort = 99 + LocalListenerPort = 98 + Protocol = "http2" + } + ] +} +``` + + + + +```yaml +apiVersion: consul.hashicorp.com/v1alpha1 +kind: ServiceDefaults +metadata: + name: + namespace: +spec: + protocol: tcp + balanceInboundConnnections: exact_balance + mode: transparent + upstreamConfig: + overrides: + - name: + namespace: + protocol: + connectTimeoutMs: 5000 + meshGateway: + mode: + balanceOutboundConnections: exact_balance + limits: + maxConnections: 0 + maxPendingRequests: 0 + maxConcurrentRequests: 0 + passiveHealthCheck: + interval: 0s + maxFailures: 0 + enforcingConsecutive5xx: 100 + defaults: + protocol: + connectTimeoutMs: 5000 + meshGateway: + mode: + balanceOutboundConnections: exact_balance + limits: + maxConnections: 0 + maxPendingRequests: 0 + maxConcurrentRequests: 0 + passiveHealthCheck: + interval: 0s + maxFailures: 0 + enforcingConsecutive5xx: 100 + transparentProxy: + outboundListenerPort: 15001 + dialedDirectly: false + destination: + addresses: + - + + port: 0 + maxInboundConnections: 0 + meshGateway: + mode: + externalSNI: + expose: + checks: false + paths: + - path: + localPathPort: 0 + listenerPort: 0 + protocol: http +``` + + + + + +```json +{ + "apiVersion": "consul.hashicorp.com/v1alpha1", + "kind": "ServiceDefaults", + "metadata": { + "name": "", + "namespace": "", + "partition": "" + }, + "spec": { + "protocol": "tcp", + "balanceInboundConnnections": "exact_balance", + "mode": "transparent", + "upstreamConfig": { + "overrides": [ + { + "name": "", + "namespace": "", + "protocol": "", + "connectTimeoutMs": 5000, + "meshGateway": { + "mode": "" + }, + "balanceOutboundConnections": "exact_balance", + "limits": { + "maxConnections": 0, + "maxPendingRequests": 0, + "maxConcurrentRequests": 0 + }, + "passiveHealthCheck": { + "interval": "0s", + "maxFailures": 0, + "enforcingConsecutive5xx": 100 + } + } + ], + "defaults": { + "protocol": "", + "connectTimeoutMs": 5000, + "meshGateway": { + "mode": "" + }, + "balanceOutboundConnections": "exact_balance", + "limits": { + "maxConnections": 0, + "maxPendingRequests": 0, + "maxConcurrentRequests": 0 + }, + "passiveHealthCheck": { + "interval": "0s", + "maxFailures": 0, + "enforcingConsecutive5xx": 100 + } + } + }, + "transparentProxy": { + "outboundListenerPort": 15001, + "dialedDirectly": false + }, + "destination": { + "addresses": [ + "", + "" + ], + "port": 0 + }, + "maxInboundConnections": 0, + "meshGateway": { + "mode": "" + }, + "externalSNI": "", + "expose": { + "checks": false, + "paths": [ + { + "path": "", + "localPathPort": 0, + "listenerPort": 0, + "protocol": "http" + } + ] + } + } +} +``` + + + + + +## Specification + +This section provides details about the fields you can configure in the service defaults configuration entry. + + + + +### `Kind` + +Specifies the configuration entry type. + +#### Values + +- Default: none +- This field is required. +- Data type: String value that must be set to `service-defaults`. + +### `Name` + +Specifies the name of the service you are setting the defaults for. + +#### Values + +- Default: none +- This field is required. +- Data type: string + +### `Namespace` + +Specifies the Consul namespace that the configuration entry applies to. + +#### Values + +- Default: `default` +- Data type: string + +### `Partition` + +Specifies the name of the name of the Consul admin partition that the configuration entry applies to. Refer to [Admin Partitions](/consul/docs/enterprise/admin-partitions) for additional information. + +#### Values + +- Default: `default` +- Data type: string + +### `Meta` + +Specifies a set of custom key-value pairs to add to the [Consul KV](/consul/docs/dynamic-app-config/kv) store. + +#### Values + +- Default: none +- Data type: Map of one or more key-value pairs. + - keys: string + - values: string, integer, or float + +### `Protocol` + +Specifies the default protocol for the service. In service mesh use cases, the `protocol` configuration is required to enable the following features and components: + +- [observability](/consul/docs/connect/observability) +- [service splitter configuration entry](/consul/docs/connect/config-entries/service-splitter) +- [service router configuration entry](/consul/docs/connect/config-entries/service-router) +- [L7 intentions](/consul/docs/connect/intentions) + +You can set the global protocol for proxies in the [`proxy-defaults`](/consul/docs/connect/config-entries/proxy-defaults#default-protocol) configuration entry, but the protocol specified in the `service-defaults` configuration entry overrides the `proxy-defaults` configuration. + +#### Values + +- Default: `tcp` +- You can speciyf one of the following string values: + - `tcp` (default) + - `http` + - `http2` + - `grpc` + +Refer to [Set the default protocol](#set-the-default-protocol) for an example configuration. + +### `BalanceInboundConnections` + +Specifies the strategy for allocating inbound connections to the service across Envoy proxy threads. The only supported value is `exact_balance`. By default, no connections are balanced. Refer to the [Envoy documentation](https://cloudnative.to/envoy/api-v3/config/listener/v3/listener.proto.html#config-listener-v3-listener-connectionbalanceconfig) for details. + +#### Values + +- Default: none +- Data type: string + +### `Mode` + +Specifies a mode for how the service directs inbound and outbound traffic. + +- Default: none +- You can specify the following string values: + - `direct`: The proxy's listeners must be dialed directly by the local application and other proxies. + - `transparent`: The service captures inbound and outbound traffic and redirects it through the proxy. The mode does not enable the traffic redirection. It instructs Consul to configure Envoy as if traffic is already being redirected. + + +### `UpstreamConfig` + +Controls default upstream connection settings and custom overrides for individual upstream services. If your network contains federated datacenters, individual upstream configurations apply to all pairs of source and upstream destination services in the network. Refer to the following fields for details: + +- [`UpstreamConfig.Overrides`](#upstreamconfig-overrides) +- [`UpstreamConfig.Defaults`](#upstreamconfig-defaults) + +#### Values + +- Default: none +- Data type: map + +### `UpstreamConfig.Overrides[]` + +Specifies options that override the [default upstream configurations](#upstreamconfig-defaults) for individual upstreams. + +#### Values + +- Default: none +- Data type: list + +### `UpstreamConfig.Overrides[].Name` + +Specifies the name of the upstream service that the configuration applies to. We recommend that you do not use the `*` wildcard to avoid applying the configuration to unintended upstreams. + +#### Values + +- Default: none +- Data type: string + +### `UpstreamConfig.Overrides[].Namespace` + +Specifies the namespace containing the upstream service that the configuration applies to. Do not use the `*` wildcard to prevent the configuration from appling to unintended upstreams. + +#### Values + +- Default: none +- Data type: string + +### `UpstreamConfig.Overrides[].Protocol` +Specifies the protocol to use for requests to the upstream listener. + +We recommend configuring the protocol in the main [`Protocol`](#protocol) field of the configuration entry so that you can leverage [L7 features](/consul/docs/connect/l7-traffic). Setting the protocol in an upstream configuration limits L7 management functionality. + +#### Values + +- Default: none +- Data type: string + + +### `UpstreamConfig.Overrides[].ConnectTimeoutMs` + +Specifies how long in milliseconds that the service should attempt to establish an upstream connection before timing out. + +We recommend configuring the upstream timeout in the [`connection_timeout`](/consul/docs/connect/config-entries/service-resolver#connecttimeout) field of the `service-resolver` configuration entry for the upstream destination service. Doing so enables you to leverage [L7 features](/consul/docs/connect/l7-traffic). Configuring the timeout in the `service-defaults` upstream configuration limits L7 management functionality. + +#### Values + +- Default: `5000` +- Data type: integer + +### `UpstreamConfig.Overrides[].MeshGateway` + +Map that contains the default mesh gateway `mode` field for the upstream. Refer to [Connect Proxy Configuration](/consul/docs/connect/gateways/mesh-gateway#connect-proxy-configuration) in the mesh gateway documentation for additional information. + +#### Values + +- Default: `none` +- You can specify the following string values for the `mode` field: + - `none`: The service does not make outbound connections through a mesh gateway. Instead, the service makes outbound connections directly to the destination services. + - `local`: The service mesh proxy makes an outbound connection to a gateway running in the same datacenter. + - `remote`: The service mesh proxy makes an outbound connection to a gateway running in the destination datacenter. + + +### `UpstreamConfig.Overrides[].BalanceOutboundConnections` + +Sets the strategy for allocating outbound connections from the upstream across Envoy proxy threads. + +#### Values + +The only supported value is `exact_balance`. By default, no connections are balanced. Refer to the [Envoy documentation](https://cloudnative.to/envoy/api-v3/config/listener/v3/listener.proto.html#config-listener-v3-listener-connectionbalanceconfig) for details. + +- Default: none +- Data type: string + +### `UpstreamConfig.Overrides[].Limits` + +Map that specifies a set of limits to apply to when connecting to individual upstream services. + +#### Values + +The following table describes limits you can configure: + +| Limit | Description | Data type | Default | +| --- | --- | --- | --- | +| `MaxConnections` | Specifies the maximum number of connections a service instance can establish against the upstream. Define this limit for HTTP/1.1 traffic. | integer | `0` | +| `MaxPendingRequests` | Specifies the maximum number of requests that are queued while waiting for a connection to establish. An L7 protocol must be defined in the [`protocol`](#protocol) field for this limit to take effect. | integer | `0` | +| `MaxConcurrentRequests` | Specifies the maximum number of concurrent requests. Define this limit for HTTP/2 traffic. An L7 protocol must be defined in the [`protocol`](#protocol) field for this limit to take effect. | integer | `0` | + +Refer to the [upstream configuration example](#upstream-configuration) for additional guidance. + +### `UpstreamConfig.Overrides[].PassiveHealthCheck` + +Map that specifies a set of rules that enable Consul to remove hosts from the upstream cluster that are unreachable or that return errors. + +#### Values + +The following table describes passive health check parameters you can configure: + +| Limit | Description | Data type | Default | +| --- | --- | --- | --- | +| `Interval` | Specifies the time between checks. | string | `0s` | +| `MaxFailures` | Specifies the number of consecutive failures allowed per check interval. If exceeded, Consul removes the host from the load balancer. | integer | `0` | +| `EnforcingConsecutive5xx ` | Specifies a percentage that indicates how many times out of 100 that Consul ejects the host when it detects an outlier status. The outlier status is determined by consecutive errors in the 500-599 response range. | integer | `100` | + +### `UpstreamConfig.Defaults` + +Specifies configurations that set default upstream settings. For information about overriding the default configurations for in for individual upstreams, refer to [`UpstreamConfig.Overrides`](#upstreamconfig-overrides). + +#### Values + +- Default: none +- Data type: map + +### `UpstreamConfig.Defaults.Protocol` + +Specifies default protocol for upstream listeners. + +We recommend configuring the protocol in the main [`Protocol`](#protocol) field of the configuration entry so that you can leverage [L7 features](/consul/docs/connect/l7-traffic). Setting the protocol in an upstream configuration limits L7 management functionality. + +- Default: none +- Data type: string + +### `UpstreamConfig.Defaults.ConnectTimeoutMs` + +Specifies how long in milliseconds that all services should continue attempting to establish an upstream connection before timing out. + +For non-Kubernetes environments, we recommend configuring the upstream timeout in the [`connection_timeout`](/consul/docs/connect/config-entries/service-resolver#connecttimeout) field of the `service-resolver` configuration entry for the upstream destination service. Doing so enables you to leverage [L7 features](/consul/docs/connect/l7-traffic). Configuring the timeout in the `service-defaults` upstream configuration limits L7 management functionality. + +- Default: `5000` +- Data type: integer + +### `UpstreamConfig.Defaults.MeshGateway` + +Specifies the default mesh gateway `mode` field for all upstreams. Refer to [Connect Proxy Configuration](/consul/docs/connect/gateways/mesh-gateway#connect-proxy-configuration) in the mesh gateway documentation for additional information. + +You can specify the following string values for the `mode` field: + +- `none`: The service does not make outbound connections through a mesh gateway. Instead, the service makes outbound connections directly to the destination services. +- `local`: The service mesh proxy makes an outbound connection to a gateway running in the same datacenter. +- `remote`: The service mesh proxy makes an outbound connection to a gateway running in the destination datacenter. + +### `UpstreamConfig.Defaults.BalanceOutboundConnections` + +Sets the strategy for allocating outbound connections from upstreams across Envoy proxy threads. The only supported value is `exact_balance`. By default, no connections are balanced. Refer to the [Envoy documentation](https://cloudnative.to/envoy/api-v3/config/listener/v3/listener.proto.html#config-listener-v3-listener-connectionbalanceconfig) for details. + +- Default: none +- Data type: string + +### `UpstreamConfig.Defaults.Limits` + +Map that specifies a set of limits to apply to when connecting upstream services. The following table describes limits you can configure: + +| Limit | Description | Data type | Default | +| --- | --- | --- | --- | +| `MaxConnections` | Specifies the maximum number of connections a service instance can establish against the upstream. Define this limit for HTTP/1.1 traffic. | integer | `0` | +| `MaxPendingRequests` | Specifies the maximum number of requests that are queued while waiting for a connection to establish. An L7 protocol must be defined in the [`protocol`](#protocol) field for this limit to take effect. | integer | `0` | +| `MaxConcurrentRequests` | Specifies the maximum number of concurrent requests. Define this limit for HTTP/2 traffic. An L7 protocol must be defined in the [`protocol`](#protocol) field for this limit to take effect. | integer | `0` | + +### `UpstreamConfig.Defaults.PassiveHealthCheck` + +Map that specifies a set of rules that enable Consul to remove hosts from the upstream cluster that are unreachable or that return errors. The following table describes the health check parameters you can configure: + +| Limit | Description | Data type | Default | +| --- | --- | --- | --- | +| `Interval` | Specifies the time between checks. | string | `0s` | +| `MaxFailures` | Specifies the number of consecutive failures allowed per check interval. If exceeded, Consul removes the host from the load balancer. | integer | `0` | +| `EnforcingConsecutive5xx ` | Specifies a percentage that indicates how many times out of 100 that Consul ejects the host when it detects an outlier status. The outlier status is determined by consecutive errors in the 500-599 response range. | integer | `100` | + +### `TransparentProxy` + +Controls configurations specific to proxies in transparent mode. Refer to [Transparent Proxy](/consul/docs/connect/transparent-proxy) for additional information. + +You can configure the following parameters in the `TransparentProxy` block: + +| Parameter | Description | Data type | Default | +| --- | --- | --- | --- | +| `OutboundListenerPort` | Specifies the port that the proxy listens on for outbound traffic. This must be the same port number where outbound application traffic is redirected. | integer | `15001` | +| `DialedDirectly` | Enables transparent proxies to dial the proxy instance's IP address directly when set to `true`. Transparent proxies commonly dial upstreams at the `"virtual"` tagged address, which load balances across instances. Dialing individual instances can be helpful for stateful services, such as a database cluster with a leader. | boolean | `false` | + +### `Destination[]` + +Configures the destination for service traffic through terminating gateways. Refer to [Terminating Gateway](/consul/docs/connect/gateways/terminating-gateway) for additional information. + +You can configure the following parameters in the `Destination` block: + +| Parameter | Description | Data type | Default | +| --- | --- | --- | --- | +| `Address` | Specifies a list of addresses for the destination. You can configure a list of hostnames and IP addresses. Wildcards are not supported. | list | none | +| `Port` | Specifies the port number of the destination. | integer | `0` | -### Default protocol +### `MaxInboundConnections` --> **NOTE**: The default protocol can also be configured globally for all proxies -using the [proxy defaults](/docs/connect/config-entries/proxy-defaults#default-protocol) -config entry. However, if the protocol value is specified in a service defaults -config entry for a given service, that value will take precedence over the -globally configured value from proxy defaults. +Specifies the maximum number of concurrent inbound connections to each service instance. -Set the default protocol for a service in the default namespace to HTTP: +- Default: `0` +- Data type: integer + + +### `LocalConnectTimeoutMs` + +Specifies the number of milliseconds allowed for establishing connections to the local application instance before timing out. + +- Default: `5000` +- Data type: integer + +### `LocalRequestTimeoutMs` + +Specifies the timeout for HTTP requests to the local application instance. Applies to HTTP-based protocols only. If not specified, inherits the Envoy default for route timeouts. + +- Default: Inherits `15s` from Envoy as the default +- Data type: string + +### `MeshGateway` + +Specifies the default mesh gateway `mode` field for the service. Refer to [Connect Proxy Configuration](/consul/docs/connect/gateways/mesh-gateway#connect-proxy-configuration) in the mesh gateway documentation for additional information. + +You can specify the following string values for the `mode` field: + +- `none`: The service does not make outbound connections through a mesh gateway. Instead, the service makes outbound connections directly to the destination services. +- `local`: The service mesh proxy makes an outbound connection to a gateway running in the same datacenter. +- `remote`: The service mesh proxy makes an outbound connection to a gateway running in the destination datacenter. + +### `ExternalSNI` + +Specifies the TLS server name indication (SNI) when federating with an external system. + +- Default: none +- Data type: string + +### `Expose` + +Specifies default configurations for exposing HTTP paths through Envoy. Exposing paths through Envoy enables services to listen on localhost only. Applications that are not Consul service mesh-enabled can still contact an HTTP endpoint. Refer to [Expose Paths Configuration Reference](/consul/docs/connect/registration/service-registration#expose-paths-configuration-reference) for additional information and example configurations. + +- Default: none +- Data type: map + +### `Expose.Checks` + +Exposes all HTTP and gRPC checks registered with the agent if set to `true`. Envoy exposes listeners for the checks and only accepts connections originating from localhost or Consul's [`advertise_addr`](/consul/docs/agent/config/config-files#advertise_addr). The ports for the listeners are dynamically allocated from the agent's [`expose_min_port`](/consul/docs/agent/config/config-files#expose_min_port) and [`expose_max_port`](/consul/docs/agent/config/config-files#expose_max_port) configurations. + +We recommend enabling the `Checks` configuration when a Consul client cannot reach registered services over localhost, such as when Consul agents run in their own pods in Kubernetes. + +- Default: `false` +- Data type: boolean + +### `Expose.Paths[]` + +Specifies a list of configuration maps that define paths to expose through Envoy when `Expose.Checks` is set to `true`. You can configure the following parameters for each map in the list: + +| Parameter | Description | Data type | Default | +| --- | --- | --- | --- | +| `Path` | Specifies the HTTP path to expose. You must prepend the path with a forward slash (`/`). | string | none | +| `LocalPathPort` | Specifies the port where the local service listens for connections to the path. | integer | `0` | +| `ListenPort` | Specifies the port where the proxy listens for connections. The port must be available. If the port is unavailable, Envoy does not expose a listener for the path and the proxy registration still succeeds. | integer | `0` | +| `Protocol` | Specifies the protocol of the listener. You can configure one of the following values:

  • `http`
  • `http2`: Use with gRPC traffic
  • | integer | `http` | + + + + + +### `apiVersion` + +Specifies the version of the Consul API for integrating with Kubernetes. The value must be `consul.hashicorp.com/v1alpha1`. The `apiVersion` field is not supported for non-Kubernetes deployments. + +- Default: none +- This field is required. +- String value that must be set to `consul.hashicorp.com/v1alpha1`. + +### `kind` + +Specifies the configuration entry type. Must be ` ServiceDefaults`. + +- Required: required +- String value that must be set to `ServiceDefaults`. + +### `metadata` + +Map that contains the service name, namespace, and admin partition that the configuration entry applies to. + +#### Values + +- Default: none +- Map containing the following strings: + - [`name`](#name) + - [`namespace`](#namespace) + - [`partition`](#partition) + + +### `metadata.name` + +Specifies the name of the service you are setting the defaults for. + +#### Values + +- Default: none +- This field is required +- Data type: string + +### `metadata.namespace` + +Specifies the Consul namespace that the configuration entry applies to. Refer to [Consul Enterprise](/consul/docs/k8s/crds#consul-enterprise) for information about how Consul namespaces map to Kubernetes Namespaces. Open source Consul distributions (Consul OSS) ignore the `metadata.namespace` configuration. + +- Default: `default` +- Data type: string + +### `spec` + +Map that contains the details about the `ServiceDefaults` configuration entry. The `apiVersion`, `kind`, and `metadata` fields are siblings of the `spec` field. All other configurations are children. + +### `spec.protocol` + +Specifies the default protocol for the service. In service service mesh use cases, the `protocol` configuration is required to enable the following features and components: + +- [observability](/consul/docs/connect/observability) +- [`service-splitter` configuration entry](/consul/docs/connect/config-entries/service-splitter) +- [`service-router` configuration entry](/consul/docs/connect/config-entries/service-router) +- [L7 intentions](/consul/docs/connect/intentions) + +You can set the global protocol for proxies in the [`ProxyDefaults` configuration entry](/consul/docs/connect/config-entries/proxy-defaults#default-protocol), but the protocol specified in the `ServiceDefaults` configuration entry overrides the `ProxyDefaults` configuration. + +#### Values + +- Default: `tcp` +- You can specify one of the following string values: + - `tcp` + - `http` + - `http2` + - `grpc` + +Refer to [Set the default protocol](#set-the-default-protocol) for an example configuration. + +### `spec.balanceInboundConnections` + +Specifies the strategy for allocating inbound connections to the service across Envoy proxy threads. The only supported value is `exact_balance`. By default, no connections are balanced. Refer to the [Envoy documentation](https://cloudnative.to/envoy/api-v3/config/listener/v3/listener.proto.html#config-listener-v3-listener-connectionbalanceconfig) for details. + +#### Values + +- Default: none +- Data type: string + +### `spec.mode` + +Specifies a mode for how the service directs inbound and outbound traffic. + +#### Values + +- Default: none +- Required: optional +- You can specified the following string values: + +- `direct`: The proxy's listeners must be dialed directly by the local application and other proxies. +- `transparent`: The service captures inbound and outbound traffic and redirects it through the proxy. The mode does not enable the traffic redirection. It instructs Consul to configure Envoy as if traffic is already being redirected. + +### `spec.upstreamConfig` + +Specifies a map that controls default upstream connection settings and custom overrides for individual upstream services. If your network contains federated datacenters, individual upstream configurations apply to all pairs of source and upstream destination services in the network. + +#### Values + +- Default: none +- Map that contains the following configurations: + - [`UpstreamConfig.Overrides`](#upstreamconfig-overrides) + - [`UpstreamConfig.Defaults`](#upstreamconfig-defaults) + +### `spec.upstreamConfig.overrides[]` + +Specifies options that override the [default upstream configurations](#spec-upstreamconfig-defaults) for individual upstreams. + +#### Values + +- Default: none +- Data type: list + +### `spec.upstreamConfig.overrides[].name` + +Specifies the name of the upstream service that the configuration applies to. Do not use the `*` wildcard to prevent the configuration from applying to unintended upstreams. + +#### Values + +- Default: none +- Data type: string + +### `spec.upstreamConfig.overrides[].namespace` + +Specifies the namespace containing the upstream service that the configuration applies to. Do not use the `*` wildcard to prevent the configuration from applying to unintended upstreams. + +#### Values + +- Default: none +- Data type: string + +### `spec.upstreamConfig.overrides[].protocol` + +Specifies the protocol to use for requests to the upstream listener. We recommend configuring the protocol in the main [`protocol`](#protocol) field of the configuration entry so that you can leverage [L7 features](/consul/docs/connect/l7-traffic). Setting the protocol in an upstream configuration limits L7 management functionality. + +#### Values + +- Default: inherits the main [`protocol`](#protocol) configuration +- Data type: string + + +### `spec.upstreamConfig.overrides[].connectTimeoutMs` + +Specifies how long in milliseconds that the service should attempt to establish an upstream connection before timing out. + +We recommend configuring the upstream timeout in the [`connectTimeout`](/consul/docs/connect/config-entries/service-resolver#connecttimeout) field of the `ServiceResolver` CRD for the upstream destination service. Doing so enables you to leverage [L7 features](/consul/docs/connect/l7-traffic). Configuring the timeout in the `ServiceDefaults` upstream configuration limits L7 management functionality. + +#### Values + +- Default: `5000` +- Data type: integer + +### `spec.upstreamConfig.overrides[].meshGateway.mode` + +Map that contains the default mesh gateway `mode` field for the upstream. Refer to [Connect Proxy Configuration](/consul/docs/connect/gateways/mesh-gateway#connect-proxy-configuration) in the mesh gateway documentation for additional information. + +#### Values + +You can specify the following string values for the `mode` field: + +- `none`: The service does not make outbound connections through a mesh gateway. Instead, the service makes outbound connections directly to the destination services. +- `local`: The service mesh proxy makes an outbound connection to a gateway running in the same datacenter. +- `remote`: The service mesh proxy makes an outbound connection to a gateway running in the destination datacenter. + +### `spec.upstreamConfig.overrides[].balanceInboundConnections` + +Sets the strategy for allocating outbound connections from the upstream across Envoy proxy threads. The only supported value is `exact_balance`. By default, no connections are balanced. Refer to the [Envoy documentation](https://cloudnative.to/envoy/api-v3/config/listener/v3/listener.proto.html#config-listener-v3-listener-connectionbalanceconfig) for details. + +#### Values + +- Default: none +- Data type: string + +### `spec.upstreamConfig.overrides[].limits` + +Map that specifies a set of limits to apply to when connecting to individual upstream services. + +#### Values + +The following table describes limits you can configure: + +| Limit | Description | Data type | Default | +| --- | --- | --- | --- | +| `maxConnections` | Specifies the maximum number of connections a service instance can establish against the upstream. Define this limit for HTTP/1.1 traffic. | integer | `0` | +| `maxPendingRequests` | Specifies the maximum number of requests that are queued while waiting for a connection to establish. An L7 protocol must be defined in the [`protocol`](#protocol) field for this limit to take effect. | integer | `0` | +| `maxConcurrentRequests` | Specifies the maximum number of concurrent requests. Define this limit for HTTP/2 traffic. An L7 protocol must be defined in the [`protocol`](#protocol) field for this limit to take effect. | integer | `0` | + +### `spec.upstreamConfig.overrides[].passiveHealthCheck` + +Map that specifies a set of rules that enable Consul to remove hosts from the upstream cluster that are unreachable or that return errors. + +#### Values + +The following table describes passive health check parameters you can configure: + +| Limit | Description | Data type | Default | +| --- | --- | --- | --- | +| `interval` | Specifies the time between checks. | string | `0s` | +| `maxFailures` | Specifies the number of consecutive failures allowed per check interval. If exceeded, Consul removes the host from the load balancer. | integer | `0` | +| `enforcingConsecutive5xx ` | Specifies a percentage that indicates how many times out of 100 that Consul ejects the host when it detects an outlier status. The outlier status is determined by consecutive errors in the 500-599 response range. | integer | `100` | + +### `spec.upstreamConfig.defaults` + +Map of configurations that set default upstream configurations for the service. For information about overriding the default configurations for in for individual upstreams, refer to [`spec.upstreamConfig.overrides`](#spec-upstreamconfig-overrides). + +#### Values + +- Default: none +- Data type: list + +### `spec.upstreamConfig.defaults.protocol` + +Specifies default protocol for upstream listeners. We recommend configuring the protocol in the main [`Protocol`](#protocol) field of the configuration entry so that you can leverage [L7 features](/consul/docs/connect/l7-traffic). Setting the protocol in an upstream configuration limits L7 management functionality. + +#### Values + +- Default: none +- Data type: string + +### `spec.upstreamConfig.default.connectTimeoutMs` + +Specifies how long in milliseconds that all services should continue attempting to establish an upstream connection before timing out. + +We recommend configuring the upstream timeout in the [`connectTimeout`](/consul/docs/connect/config-entries/service-resolver#connecttimeout) field of the `ServiceResolver` CRD for upstream destination services. Doing so enables you to leverage [L7 features](/consul/docs/connect/l7-traffic). Configuring the timeout in the `ServiceDefaults` upstream configuration limits L7 management functionality. + +#### Values + +- Default: `5000` +- Data type: integer + +### `spec.upstreamConfig.defaults.meshGateway.mode` + +Specifies the default mesh gateway `mode` field for all upstreams. Refer to [Connect Proxy Configuration](/consul/docs/connect/gateways/mesh-gateway#connect-proxy-configuration) in the mesh gateway documentation for additional information. + +#### Values + +You can specify the following string values for the `mode` field: + +- `none`: The service does not make outbound connections through a mesh gateway. Instead, the service makes outbound connections directly to the destination services. +- `local`: The service mesh proxy makes an outbound connection to a gateway running in the same datacenter. +- `remote`: The service mesh proxy makes an outbound connection to a gateway running in the destination datacenter. + +### `spec.upstreamConfig.defaults.balanceInboundConnections` + +Sets the strategy for allocating outbound connections from upstreams across Envoy proxy threads. The only supported value is `exact_balance`. By default, no connections are balanced. Refer to the [Envoy documentation](https://cloudnative.to/envoy/api-v3/config/listener/v3/listener.proto.html#config-listener-v3-listener-connectionbalanceconfig) for details. + +#### Values + +- Default: none +- Data type: string + +### `spec.upstreamConfig.defaults.limits` + +Map that specifies a set of limits to apply to when connecting upstream services. + +#### Values + +The following table describes limits you can configure: + +| Limit | Description | Data type | Default | +| --- | --- | --- | --- | +| `maxConnections` | Specifies the maximum number of connections a service instance can establish against the upstream. Define this limit for HTTP/1.1 traffic. | integer | `0` | +| `maxPendingRequests` | Specifies the maximum number of requests that are queued while waiting for a connection to establish. An L7 protocol must be defined in the [`protocol`](#protocol) field for this limit to take effect. | integer | `0` | +| `maxConcurrentRequests` | Specifies the maximum number of concurrent requests. Define this limit for HTTP/2 traffic. An L7 protocol must be defined in the [`protocol`](#protocol) field for this limit to take effect. | integer | `0` | + +### `spec.upstreamConfig.defaults.passiveHealthCheck` +Map that specifies a set of rules that enable Consul to remove hosts from the upstream cluster that are unreachable or that return errors. + +#### Values + +The following table describes the health check parameters you can configure: + +| Limit | Description | Data type | Default | +| --- | --- | --- | --- | +| `interval` | Specifies the time between checks. | string | `0s` | +| `maxFailures` | Specifies the number of consecutive failures allowed per check interval. If exceeded, Consul removes the host from the load balancer. | integer | `0` | +| `enforcingConsecutive5xx ` | Specifies a percentage that indicates how many times out of 100 that Consul ejects the host when it detects an outlier status. The outlier status is determined by consecutive errors in the 500-599 response range. | integer | `100` | + +### `spec.transparentProxy` + +Map of configurations specific to proxies in transparent mode. Refer to [Transparent Proxy](/consul/docs/connect/transparent-proxy) for additional information. + +#### Values + +You can configure the following parameters in the `TransparentProxy` block: + +| Parameter | Description | Data type | Default | +| --- | --- | --- | --- | +| `outboundListenerPort` | Specifies the port that the proxy listens on for outbound traffic. This must be the same port number where outbound application traffic is redirected. | integer | `15001` | +| `dialedDirectly` | Enables transparent proxies to dial the proxy instance's IP address directly when set to `true`. Transparent proxies commonly dial upstreams at the `"virtual"` tagged address, which load balances across instances. Dialing individual instances can be helpful for stateful services, such as a database cluster with a leader. | boolean | `false` | + +### `spec.destination` + +Map of configurations that specify one or more destinations for service traffic routed through terminating gateways. Refer to [Terminating Gateway](/consul/docs/connect/gateways/terminating-gateway) for additional information. + +#### Values + +You can configure the following parameters in the `Destination` block: + +| Parameter | Description | Data type | Default | +| --- | --- | --- | --- | +| `address` | Specifies a list of addresses for the destination. You can configure a list of hostnames and IP addresses. Wildcards are not supported. | list | none | +| `port` | Specifies the port number of the destination. | integer | `0` | + +### `spec.maxInboundConnections` + +Specifies the maximum number of concurrent inbound connections to each service instance. + +#### Values + +- Default: `0` +- Data type: integer + +### `spec.localConnectTimeoutMs` + +Specifies the number of milliseconds allowed for establishing connections to the local application instance before timing out. + +#### Values + +- Default: `5000` +- Data type: integer + +### `spec.localRequestTimeoutMs` + +Specifies the timeout for HTTP requests to the local application instance. Applies to HTTP-based protocols only. If not specified, inherits the Envoy default for route timeouts. + +#### Values + +- Default of `15s` is inherited from Envoy +- Data type: string + +### `spec.meshGateway.mode` +Specifies the default mesh gateway `mode` field for the service. Refer to [Connect Proxy Configuration](/consul/docs/connect/gateways/mesh-gateway#connect-proxy-configuration) in the mesh gateway documentation for additional information. + +#### Values + +You can specify the following string values for the `mode` field: + +- `none`: The service does not make outbound connections through a mesh gateway. Instead, the service makes outbound connections directly to the destination services. +- `local`: The service mesh proxy makes an outbound connection to a gateway running in the same datacenter. +- `remote`: The service mesh proxy makes an outbound connection to a gateway running in the destination datacenter. + +### `spec.externalSNI` + +Specifies the TLS server name indication (SNI) when federating with an external system. + +#### Values + +- Default: none +- Data type: string + +### `spec.expose` + +Specifies default configurations for exposing HTTP paths through Envoy. Exposing paths through Envoy enables services to listen on localhost only. Applications that are not Consul service mesh-enabled can still contact an HTTP endpoint. Refer to [Expose Paths Configuration Reference](/consul/docs/connect/registration/service-registration#expose-paths-configuration-reference) for additional information and example configurations. + +#### Values + +- Default: none +- Data type: string + +### `spec.expose.checks` + +Exposes all HTTP and gRPC checks registered with the agent if set to `true`. Envoy exposes listeners for the checks and only accepts connections originating from localhost or Consul's [`advertise_addr`](/consul/docs/agent/config/config-files#advertise_addr). The ports for the listeners are dynamically allocated from the agent's [`expose_min_port`](/consul/docs/agent/config/config-files#expose_min_port) and [`expose_max_port`](/consul/docs/agent/config/config-files#expose_max_port) configurations. + +We recommend enabling the `Checks` configuration when a Consul client cannot reach registered services over localhost, such as when Consul agents run in their own pods in Kubernetes. + +#### Values + +- Default: `false` +- Data type: boolean + +### `spec.expose.paths[]` + +Specifies an list of maps that define paths to expose through Envoy when `spec.expose.checks` is set to `true`. + +#### Values + +The following table describes the parameters for each map: + +| Parameter | Description | Data type | Default | +| --- | --- | --- | --- | +| `path` | Specifies the HTTP path to expose. You must prepend the path with a forward slash (`/`). | string | none | +| `localPathPort` | Specifies the port where the local service listens for connections to the path. | integer | `0` | +| `listenPort` | Specifies the port where the proxy listens for connections. The port must be available. If the port is unavailable, Envoy does not expose a listener for the path and the proxy registration still succeeds. | integer | `0` | +| `protocol` | Specifies the protocol of the listener. You can configure one of the following values:
  • `http`
  • `http2`: Use with gRPC traffic
  • | integer | `http` | + +
    + + +## Example configurations + +The following examples describe common `service-defaults` configurations. + +### Set the default protocol + +In the following example, protocol for the `web` service in the `default` namespace is set to `http`: @@ -54,20 +1182,21 @@ spec: +You can also set the global default protocol for all proxies in the [`proxy-defaults` configuration entry](/consul/docs/connect/config-entries/proxy-defaults#default-protocol), but the protocol specified for individual service instances in the `service-defaults` configuration entry takes precedence over the globally-configured value set in the `proxy-defaults`. + ### Upstream configuration -Set default connection limits and mesh gateway mode across all upstreams -of "counting", and also override the mesh gateway mode used when dialing -the "dashboard" service. +The following example sets default connection limits and mesh gateway mode across all upstreams of the `dashboard` service. +It also overrides the mesh gateway mode used when dialing its `counting` upstream service. ```hcl Kind = "service-defaults" -Name = "counting" +Name = "dashboard" UpstreamConfig = { Defaults = { @@ -83,7 +1212,7 @@ UpstreamConfig = { Overrides = [ { - Name = "dashboard" + Name = "counting" MeshGateway = { Mode = "remote" } @@ -96,7 +1225,7 @@ UpstreamConfig = { apiVersion: consul.hashicorp.com/v1alpha1 kind: ServiceDefaults metadata: - name: counting + name: dashboard spec: upstreamConfig: defaults: @@ -107,7 +1236,7 @@ spec: maxPendingRequests: 512 maxConcurrentRequests: 512 overrides: - - name: dashboard + - name: counting meshGateway: mode: remote ``` @@ -115,7 +1244,7 @@ spec: ```json { "Kind": "service-defaults", - "Name": "counting", + "Name": "dashboard", "UpstreamConfig": { "Defaults": { "MeshGateway": { @@ -129,7 +1258,7 @@ spec: }, "Overrides": [ { - "Name": "dashboard", + "Name": "counting", "MeshGateway": { "Mode": "remote" } @@ -144,15 +1273,13 @@ spec: -Set default connection limits and mesh gateway mode across all upstreams -of "counting" and also override the mesh gateway mode used when dialing -the "dashboard" service in the "frontend" namespace. +The following example configures the default connection limits and mesh gateway mode for all of the `counting` service's upstreams. It also overrides the mesh gateway mode used when dialing the `dashboard` service in the `frontend` namespace. ```hcl Kind = "service-defaults" -Name = "counting" +Name = "dashboard" Namespace = "product" UpstreamConfig = { @@ -169,8 +1296,8 @@ UpstreamConfig = { Overrides = [ { - Name = "dashboard" - Namespace = "frontend" + Name = "counting" + Namespace = "backend" MeshGateway = { Mode = "remote" } @@ -183,7 +1310,7 @@ UpstreamConfig = { apiVersion: consul.hashicorp.com/v1alpha1 kind: ServiceDefaults metadata: - name: counting + name: dashboard namespace: product spec: upstreamConfig: @@ -195,8 +1322,8 @@ spec: maxPendingRequests: 512 maxConcurrentRequests: 512 overrides: - - name: dashboard - namespace: frontend + - name: counting + namespace: backend meshGateway: mode: remote ``` @@ -204,7 +1331,7 @@ spec: ```json { "Kind": "service-defaults", - "Name": "counting", + "Name": "dashboard", "Namespace": "product", "UpstreamConfig": { "Defaults": { @@ -219,8 +1346,8 @@ spec: }, "Overrides": [ { - "Name": "dashboard", - "Namespace": "frontend", + "Name": "counting", + "Namespace": "backend", "MeshGateway": { "Mode": "remote" } @@ -237,8 +1364,8 @@ spec: ### Terminating gateway destination -Create a default destination that will be assigned to a terminating gateway. A destination -represents a location outside the Consul cluster. They can be dialed directly when transparent proxy mode is enabled. +The following examples creates a default destination assigned to a terminating gateway. A destination +represents a location outside the Consul cluster. Services can dial destinations dialed directly when transparent proxy mode is enabled. @@ -258,6 +1385,7 @@ represents a location outside the Consul cluster. They can be dialed directly wh metadata: name: test-destination spec: + protocol: tcp destination: addresses: - "test.com" @@ -269,7 +1397,7 @@ represents a location outside the Consul cluster. They can be dialed directly wh { "Kind": "service-defaults", "Name": "test-destination", - "Protocol": "http", + "Protocol": "tcp", "Destination": { "Addresses": ["test.com","test.org"], "Port": 443 @@ -279,6 +1407,7 @@ represents a location outside the Consul cluster. They can be dialed directly wh + diff --git a/website/content/docs/connect/config-entries/service-intentions.mdx b/website/content/docs/connect/config-entries/service-intentions.mdx index 108762893967..b2c991c62a9e 100644 --- a/website/content/docs/connect/config-entries/service-intentions.mdx +++ b/website/content/docs/connect/config-entries/service-intentions.mdx @@ -335,6 +335,57 @@ spec: ``` +### Cluster peering + +When using cluster peering connections, intentions secure your deployments with authorized service-to-service communication between remote datacenters. In the following example, the service intentions configuration entry authorizes the `backend-service` to communicate with the `frontend-service` that is hosted on remote peer `cluster-02`: + + + + ```hcl + Kind = "service-intentions" + Name = "backend-service" + + Sources = [ + { + Name = "frontend-service" + Peer = "cluster-02" + Action = "allow" + } + ] + ``` + + ```yaml + ```yaml + apiVersion: consul.hashicorp.com/v1alpha1 + kind: ServiceIntentions + metadata: + name: backend-deny + spec: + destination: + name: backend + sources: + - name: "*" + action: deny + - name: frontend + action: allow + peer: cluster-01 ## The peer of the source service + ``` + + ```json + { + "Kind": "service-intentions", + "Name": "backend-service", + "Sources": [ + { + "Name": "frontend-service", + "Peer": "cluster-02", + "Action": "allow" + } + ] + } + ``` + + ## Available Fields - There are many configuration options exposed for Consul service mesh. The only option that must be set is the `connect.enabled` option on Consul servers to enable Consul service mesh. -All other configurations are optional and have reasonable defaults. +All other configurations are optional and have defaults suitable for many environments. -Consul Connect is the component shipped with Consul that enables service mesh functionality. The terms _Consul Connect_ and _Consul service mesh_ are used interchangeably throughout this documentation. +The terms _Consul Connect_ and _Consul service mesh_ are used interchangeably throughout this documentation. --> **Tip:** Service mesh is enabled by default when running Consul in -dev mode with `consul agent -dev`. - -## Agent Configuration +## Agent configuration Begin by enabling Connect for your Consul cluster. By default, Connect is disabled. Enabling Connect requires changing @@ -75,18 +72,12 @@ automatically ensure complete security. Please read the [Connect production tutorial](https://learn.hashicorp.com/tutorials/consul/service-mesh-production-checklist) to understand the additional steps needed for a secure deployment. -## Centralized Proxy and Service Configuration - -To account for common Connect use cases where you have many instances of the -same service, and many colocated sidecar proxies, Consul allows you to customize -the settings for all of your proxies or all the instances of a given service at -once using [Configuration Entries](/docs/agent/config-entries). +## Centralized proxy and service configuration -You can override centralized configurations for individual proxy instances in -their -[sidecar service definitions](/docs/connect/registration/sidecar-service), +If your network contains many instances of the same service and many colocated sidecar proxies, you can specify global settings for proxies or services in [Configuration Entries](/consul/docs/agent/config-entries). You can override the centralized configurations for individual proxy instances in their +[sidecar service definitions](/consul/docs/connect/registration/sidecar-service), and the default protocols for service instances in their [service -registrations](/docs/discovery/services). +definitions](/consul/docs/services/usage/define-services). ## Schedulers diff --git a/website/content/docs/connect/connect-internals.mdx b/website/content/docs/connect/connect-internals.mdx index 51c38063837c..436de4eafb99 100644 --- a/website/content/docs/connect/connect-internals.mdx +++ b/website/content/docs/connect/connect-internals.mdx @@ -2,7 +2,7 @@ layout: docs page_title: Service Mesh - How it Works description: >- - Consul's service mesh enforces secure service communication using mutual TLS (mTLS) encryption and explicit authorization. Learn how the service mesh certificate authorities, intentions, and agents work together in the ""Connect"" subsystem to provide Consul’s service mesh capabilities. + Consul's service mesh enforces secure service communication using mutual TLS (mTLS) encryption and explicit authorization. Learn how the service mesh certificate authorities, intentions, and agents work together to provide Consul’s service mesh capabilities. --- # How Service Mesh Works @@ -11,21 +11,20 @@ This topic describes how many of the core features of Consul's service mesh func It is not a prerequisite, but this information will help you understand how Consul service mesh behaves in more complex scenarios. -Consul Connect is the component shipped with Consul that enables service mesh functionality. The terms _Consul Connect_ and _Consul service mesh_ are used interchangeably throughout this documentation. - +Consul Service Mesh is the component shipped with Consul that enables service mesh functionality. To try service mesh locally, complete the [Getting Started with Consul service mesh](https://learn.hashicorp.com/tutorials/consul/service-mesh?utm_source=docs) tutorial. ## Mutual Transport Layer Security (mTLS) -The core of Connect is based on [mutual TLS](https://en.wikipedia.org/wiki/Mutual_authentication). +The core of Consul service mesh is based on [mutual TLS](https://en.wikipedia.org/wiki/Mutual_authentication). -Connect provides each service with an identity encoded as a TLS certificate. +Consul Service Mesh provides each service with an identity encoded as a TLS certificate. This certificate is used to establish and accept connections to and from other services. The identity is encoded in the TLS certificate in compliance with the [SPIFFE X.509 Identity Document](https://github.com/spiffe/spiffe/blob/master/standards/X509-SVID.md). -This enables Connect services to establish and accept connections with +This enables Consul Service Mesh services to establish and accept connections with other SPIFFE-compliant systems. The client service verifies the destination service certificate @@ -50,24 +49,24 @@ requires no other dependencies, and also ships with built-in support for [Vault](/docs/connect/ca/vault). The PKI system is designed to be pluggable and can be extended to support any system by adding additional CA providers. -All APIs required for Connect typically respond in microseconds and impose -minimal overhead to existing services. To ensure this, Connect-related API calls +All APIs required for Consul Service Mesh typically respond in microseconds and impose +minimal overhead to existing services. To ensure this, Consul Service Mesh-related API calls are all made to the local Consul agent over a loopback interface, and all [agent -Connect endpoints](/api-docs/agent/connect) implement local caching, background +Consul Service Mesh endpoints](/api-docs/agent/connect) implement local caching, background updating, and support blocking queries. Most API calls operate on purely local in-memory data. ## Agent Caching and Performance To enable fast responses on endpoints such as the [agent Connect -API](/api-docs/agent/connect), the Consul agent locally caches most Connect-related +API](/api-docs/agent/connect), the Consul agent locally caches most Consul Service Mesh-related data and sets up background [blocking queries](/api-docs/features/blocking) against the server to update the cache in the background. This allows most API calls such as retrieving certificates or authorizing connections to use in-memory data and respond very quickly. All data cached locally by the agent is populated on demand. Therefore, if -Connect is not used at all, the cache does not store any data. On first request, +Consul Service Mesh is not used at all, the cache does not store any data. On first request, the data is loaded from the server and cached. The set of data cached is: public CA root certificates, leaf certificates, intentions, and service discovery results for upstreams. For leaf certificates and intentions, only data related @@ -79,9 +78,9 @@ may see data it shouldn't from the cache. This results in higher memory usage for cached data since it is duplicated per ACL token, but with the benefit of simplicity and security. -With Connect enabled, you'll likely see increased memory usage by the +With Consul Service Mesh enabled, you'll likely see increased memory usage by the local Consul agent. The total memory is dependent on the number of intentions -related to the services registered with the agent accepting Connect-based +related to the services registered with the agent accepting Consul Service Mesh-based connections. The other data (leaf certificates and public CA certificates) is a relatively fixed size per service. In most cases, the overhead per service should be relatively small: single digit kilobytes at most. @@ -116,7 +115,7 @@ be set in the secondary datacenter server's configuration. ## Certificate Authority Federation -The primary datacenter also acts as the root Certificate Authority (CA) for Connect. +The primary datacenter also acts as the root Certificate Authority (CA) for Consul Service Mesh. The primary datacenter generates a trust-domain UUID and obtains a root certificate from the configured CA provider which defaults to the built-in one. @@ -124,7 +123,7 @@ Secondary datacenters fetch the root CA public key and trust-domain ID from the primary and generate their own key and Certificate Signing Request (CSR) for an intermediate CA certificate. This CSR is signed by the root in the primary datacenter and the certificate is returned. The secondary datacenter can now use -this intermediate to sign new Connect certificates in the secondary datacenter +this intermediate to sign new Consul Service Mesh certificates in the secondary datacenter without WAN communication. CA keys are never replicated between datacenters. The secondary maintains watches on the root CA certificate in the primary. If the diff --git a/website/content/docs/connect/connectivity-tasks.mdx b/website/content/docs/connect/connectivity-tasks.mdx index d25e3a0d4350..880d4b75f166 100644 --- a/website/content/docs/connect/connectivity-tasks.mdx +++ b/website/content/docs/connect/connectivity-tasks.mdx @@ -19,13 +19,15 @@ in different clouds or runtime environments where general interconnectivity betw isn't feasible. One scenario where this is useful is when connecting networks with overlapping IP address space. These gateways operate by sniffing the SNI header out of the mTLS connection and then routing the connection to the -appropriate destination based on the server name requested. The data within the mTLS session is not decrypted by -the Gateway. +appropriate destination based on the server name requested. As of Consul 1.8.0, mesh gateways can also forward gossip and RPC traffic between Consul servers. This is enabled by [WAN federation via mesh gateways](/docs/connect/gateways/mesh-gateway/wan-federation-via-mesh-gateways). -For more information about mesh gateways, review the [complete documentation](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters) +As of Consul 1.14.0, mesh gateways can route both data-plane (service-to-service) and control-plane (consul-to-consul) traffic for peered clusters. +See [Mesh Gateways for Peering Control Plane Traffic](/docs/connect/gateways/mesh-gateway/peering-via-mesh-gateways) + +For more information about mesh gateways, review the [complete documentation](/docs/connect/gateways/mesh-gateway) and the [mesh gateway tutorial](https://learn.hashicorp.com/tutorials/consul/service-mesh-gateways). ![Mesh Gateway Architecture](/img/mesh-gateways.png) diff --git a/website/content/docs/connect/dataplane/consul-dataplane.mdx b/website/content/docs/connect/dataplane/consul-dataplane.mdx index 375f3e59674d..87910b2acd4a 100644 --- a/website/content/docs/connect/dataplane/consul-dataplane.mdx +++ b/website/content/docs/connect/dataplane/consul-dataplane.mdx @@ -7,7 +7,7 @@ description: >- # Consul Dataplane CLI Reference -The `consul-dataplane` command interacts with the binary for [simplified service mesh with Consul Dataplane](/consul/docs/k8s/dataplane). Use this command to install Consul Dataplane, configure its Envoy proxies, and secure Dataplane deployments. +The `consul-dataplane` command interacts with the binary for [simplified service mesh with Consul Dataplane](/consul/docs/connect/dataplane). Use this command to install Consul Dataplane, configure its Envoy proxies, and secure Dataplane deployments. ## Usage @@ -15,50 +15,79 @@ Usage: `consul-dataplane [options]` ### Requirements -Consul Dataplane requires servers running Consul version `v1.14-beta+`. To find a specific version of Consul, refer to [Hashicorp's Official Release Channels](https://www.hashicorp.com/official-release-channels). +Consul Dataplane requires servers running Consul version `v1.14+`. To find a specific version of Consul, refer to [Hashicorp's Official Release Channels](https://www.hashicorp.com/official-release-channels). ### Startup The following options are required when starting `consul-dataplane` with the CLI: + + + - `-addresses` - `-service-node-name` - `-proxy-service-id` + + + + +- `-addresses` +- `-service-node-name` +- `-service-namespace` +- `-service-partition` +- `-proxy-service-id` + + + + + ### Command Options -- `-addresses` - Consul server gRPC addresses. Can be a DNS name or an executable command. Refer to [go-netaddrs](https://github.com/hashicorp/go-netaddrs#summary) for details and examples. -- `-ca-certs` - The path to a file or directory containing CA certificates used to verify the server's certificate. -- `-credential-type` - The type of credentials used to authenticate with Consul servers, either `"static"` or `"login"`. -- `-envoy-admin-bind-address` - The address the Envoy admin server is available on. Default is `"127.0.0.1"`. -- `-envoy-admin-bind-port` - The port the Envoy admin server is available on. Default is `19000`. -- `-envoy-concurrency` - The number of worker threads that Envoy uses. Default is `2`. -- `-envoy-ready-bind-address` - The address Envoy's readiness probe is available on. -- `-grpc-port` - The Consul server gRPC port to which consul-dataplane connects. Default is `8502`. -- `-log-json` - Enables log messages in JSON format. Default is `false`. -- `-log-level` - Log level of the messages to print. Available log levels are `"trace"`, `"debug"`, `"info"`, `"warn"`, and `"error"`. Default is `"info"`. -- `-login-auth-method` - The auth method used to log in. -- `-login-bearer-token` - The bearer token presented to the auth method. -- `-login-bearer-token-path` - The path to a file containing the bearer token presented to the auth method. -- `-login-datacenter` - The datacenter containing the auth method. -- `-login-meta` - A set of key/value pairs to attach to the ACL token. Each pair is formatted as `=`. This flag may be passed multiple times. -- `-login-namespace` - The Consul Enterprise namespace containing the auth method. -- `-login-partition` - The Consul Enterprise partition containing the auth method. -- `-proxy-service-id` - The proxy service instance's ID. -- `-server-watch-disabled` - Prevent `consul-dataplane` from consuming the server update stream. Use this flag when Consul servers are behind a load balancer. Default is `false`. -- `-service-namespace` - The Consul Enterprise namespace in which the proxy service instance is registered. -- `-service-node-id` - The ID of the Consul node to which the proxy service instance is registered. -- `-service-node-name` - The name of the Consul node to which the proxy service instance is registered. -- `-service-partition` - The Consul Enterprise partition in which the proxy service instance is registered. -- `-static-token` - The ACL token used to authenticate requests to Consul servers when `-credential-type` is set to `"static"`. -- `-telemetry-use-central-config` - Controls whether the proxy applies the central telemetry configuration. Default is `true`. -- `-tls-cert` - The path to a client certificate file. This flag is required if `tls.grpc.verify_incoming` is enabled on the server. -- `-tls-disabled` - Communicate with Consul servers over a plaintext connection. Useful for testing, but not recommended for production. Default is `false`. -- `-tls-insecure-skip-verify` - Do not verify the server's certificate. Useful for testing, but not recommended for production. Default is `false`. -- `-tls-key` - The path to a client private key file. This flag is required if `tls.grpc.verify_incoming` is enabled on the server. -- `-tls-server-name` - The hostname to expect in the server certificate's subject. This flag is required if `-addresses` is not a DNS name. +- `-addresses` - Consul server gRPC addresses. Can be a DNS name or an executable command. Accepted environment variable is `DP_CONSUL_ADDRESSES`. Refer to [go-netaddrs](https://github.com/hashicorp/go-netaddrs#summary) for details and examples. +- `-ca-certs` - The path to a file or directory containing CA certificates used to verify the server's certificate. Accepted environment variable is `DP_CA_CERTS`. +- `-consul-dns-bind-addr` - The address bound to the Consul DNS proxy. Default is `"127.0.0.1"`. Accepted environment variable is `DP_CONSUL_DNS_BIND_ADDR`. +- `-consul-dns-bind-port` - The port that the Consul DNS proxy listens on. Default is `-1`, which disables the DNS proxy. Accepted environment variable is `DP_CONSUL_DNS_BIND_PORT`. +- `-credential-type` - The type of credentials used to authenticate with Consul servers, either `"static"` or `"login"`. Accepted environment variable is `DP_CREDENTIAL_TYPE`. +- `-envoy-admin-bind-address` - The address the Envoy admin server is available on. Default is `"127.0.0.1"`. Accepted environment variable is `DP_ENVOY_ADMIN_BIND_ADDRESS`. +- `-envoy-admin-bind-port` - The port the Envoy admin server is available on. Default is `19000`. Accepted environment variable is `DP_ENVOY_ADMIN_BIND_PORT`. +- `-envoy-concurrency` - The number of worker threads that Envoy uses. Default is `2`. Accepted environment variable is `DP_ENVOY_CONCURRENCY`. +- `-envoy-ready-bind-address` - The address Envoy's readiness probe is available on. Accepted environment variable is `DP_ENVOY_READY_BIND_ADDRESS`. +- `-envoy-ready-bind-port` - The port Envoy's readiness probe is available on. Accepted environment variable is `DP_ENVOY_READY_BIND_PORT`. +- `-grpc-port` - The Consul server gRPC port to which `consul-dataplane` connects. Default is `8502`. Accepted environment variable is `DP_CONSUL_GRPC_PORT`. +- `-log-json` - Enables log messages in JSON format. Default is `false`. Accepted environment variable is `DP_LOG_JSON`. +- `-log-level` - Log level of the messages to print. Available log levels are `"trace"`, `"debug"`, `"info"`, `"warn"`, and `"error"`. Default is `"info"`. Accepted environment variable is `DP_LOG_LEVEL`. +- `-login-auth-method` - The auth method used to log in. Accepted environment variable is `DP_CREDENTIAL_LOGIN_AUTH_METHOD`. +- `-login-bearer-token` - The bearer token presented to the auth method. Accepted environment variable is `DP_CREDENTIAL_LOGIN_BEARER_TOKEN`. +- `-login-bearer-token-path` - The path to a file containing the bearer token presented to the auth method. Accepted environment variable is `DP_CREDENTIAL_LOGIN_BEARER_TOKEN_PATH`. +- `-login-datacenter` - The datacenter containing the auth method. Accepted environment variable is `DP_CREDENTIAL_LOGIN_DATACENTER`. +- `-login-meta` - A set of key/value pairs to attach to the ACL token. Each pair is formatted as `=`. This flag may be passed multiple times. Accepted environment variables are `DP_CREDENTIAL_LOGIN_META{1..9}`. +- `-login-namespace` - The Consul Enterprise namespace containing the auth method. Accepted environment variable is `DP_CREDENTIAL_LOGIN_NAMESPACE`. +- `-login-partition` - The Consul Enterprise partition containing the auth method. Accepted environment variable is `DP_CREDENTIAL_LOGIN_PARTITION`. +- `-proxy-service-id` - The proxy service instance's ID. Accepted environment variable is `DP_PROXY_SERVICE_ID`. +- `-proxy-service-id-path` - The path to a file containing the proxy service instance's ID. Accepted environment variable is `DP_PROXY_SERVICE_ID_PATH`. +- `-server-watch-disabled` - Prevent `consul-dataplane` from consuming the server update stream. Use this flag when Consul servers are behind a load balancer. Default is `false`. Accepted environment variable is `DP_SERVER_WATCH_DISABLED`. +- `-service-namespace` - The Consul Enterprise namespace in which the proxy service instance is registered. Accepted environment variable is `DP_SERVICE_NAMESPACE`. +- `-service-node-id` - The ID of the Consul node to which the proxy service instance is registered. Accepted environment variable is `DP_SERVICE_NODE_ID`. +- `-service-node-name` - The name of the Consul node to which the proxy service instance is registered. Accepted environment variable is `DP_SERVICE_NODE_NAME`. +- `-service-partition` - The Consul Enterprise partition in which the proxy service instance is registered. Accepted environment variable is `DP_SERVICE_PARTITION`. +- `-static-token` - The ACL token used to authenticate requests to Consul servers when `-credential-type` is set to `"static"`. Accepted environment variable is `DP_CREDENTIAL_STATIC_TOKEN`. +- `-telemetry-prom-ca-certs-path` - The path to a file or directory containing CA certificates used to verify the Prometheus server's certificate. Accepted environment variable is `DP_TELEMETRY_PROM_CA_CERTS_PATH`. +- `-telemetry-prom-cert-file` - The path to the client certificate used to serve Prometheus metrics. Accepted environment variable is `DP_TELEMETRY_PROM_CERT_FILE`. +- `-telemetry-prom-key-file` - The path to the client private key used to serve Prometheus metrics. Accepted environment variable is `DP_TELEMETRY_PROM_KEY_FILE`. +- `-telemetry-prom-merge-port` - The local port used to serve merged Prometheus metrics. Default is `20100`. If your service instance uses the same default port, this flag must be set to a different port in order to avoid a port conflict. Accepted environment variable is `DP_TELEMETRY_PROM_MERGE_PORT`. +- `-telemetry-prom-retention-time` - The duration for Prometheus metrics aggregation. Default is `1m0s`. Accepted environment variable is `DP_TELEMETRY_PROM_RETENTION_TIME`. Refer to [`prometheus_retention_time`](/docs/agent/config/config-files#telemetry-prometheus_retention_time) for details on setting this value. +- `-telemetry-prom-scrape-path` - The URL path where Envoy serves Prometheus metrics. Default is `"/metrics"`. Accepted environment variable is `DP_TELEMETRY_PROM_SCRAPE_PATH`. +- `-telemetry-prom-service-metrics-url` - The URL where your service instance serves Prometheus metrics. If this is set, the metrics at this URL are included in Consul Dataplane's merged Prometheus metrics. Accepted environment variable is `DP_TELEMETRY_PROM_SERVICE_METRICS_URL`. +- `-telemetry-use-central-config` - Controls whether the proxy applies the central telemetry configuration. Default is `true`. Accepted environment variable is `DP_TELEMETRY_USE_CENTRAL_CONFIG`. +- `-tls-cert` - The path to a client certificate file. This flag is required if `tls.grpc.verify_incoming` is enabled on the server. Accepted environment variable is `DP_TLS_CERT`. +- `-tls-disabled` - Communicate with Consul servers over a plaintext connection. Useful for testing, but not recommended for production. Default is `false`. Accepted environment variable is `DP_TLS_DISABLED`. +- `-tls-insecure-skip-verify` - Do not verify the server's certificate. Useful for testing, but not recommended for production. Default is `false`. `DP_TLS_INSECURE_SKIP_VERIFY`. +- `-tls-key` - The path to a client private key file. This flag is required if `tls.grpc.verify_incoming` is enabled on the server. Accepted environment variable is `DP_TLS_KEY`. +- `-tls-server-name` - The hostname to expect in the server certificate's subject. This flag is required if `-addresses` is not a DNS name. Accepted environment variable is `DP_TLS_SERVER_NAME`. - `-version` - Print the current version of `consul-dataplane`. -- `-xds-bind-addr` - The address the Envoy xDS server is available on. Default is `"127.0.0.1"`. +- `-xds-bind-addr` - The address the Envoy xDS server is available on. Default is `"127.0.0.1"`. Accepted environment variable is `DP_XDS_BIND_ADDR`. +- `-xds-bind-port` - The port on which the Envoy xDS server is available. Default is `0`. When set to `0`, an available port is selected at random. Accepted environment variable is `DP_XDS_BIND_PORT`. ## Examples @@ -105,6 +134,21 @@ A static ACL token is passed to Consul Dataplane. Consul Dataplane logs in to one of Consul's supported [auth methods](/consul/docs/security/acl/auth-methods). + + + + ```shell-session + $ consul-dataplane -credential-type "login" + -login-auth-method \ + -login-bearer-token \ ## Or -login-bearer-token-path + -login-datacenter \ + -login-meta key1=val1 -login-meta key2=val2 \ + ``` + + + + + ```shell-session $ consul-dataplane -credential-type "login" -login-auth-method \ @@ -115,6 +159,9 @@ Consul Dataplane logs in to one of Consul's supported [auth methods](/consul/doc -login-partition ``` + + + ### Consul Servers Behind a Load Balancer When Consul servers are behind a load balancer, you must pass `-server-watch-disabled` to Consul @@ -127,4 +174,4 @@ $ consul-dataplane -server-watch-disabled By default, Consul Dataplane opens a server watch stream to a Consul server, which enables the server to inform Consul Dataplane of new or different Consul server addresses. However, if Consul Dataplane is connecting through a load balancer, then it must ignore the Consul server addresses that are -returned from the server watch stream. \ No newline at end of file +returned from the server watch stream. diff --git a/website/content/docs/connect/dataplane/index.mdx b/website/content/docs/connect/dataplane/index.mdx index c7d142ddd490..266bb6dd1ba2 100644 --- a/website/content/docs/connect/dataplane/index.mdx +++ b/website/content/docs/connect/dataplane/index.mdx @@ -7,17 +7,29 @@ description: >- # Simplified Service Mesh with Consul Dataplane -~> **Consul Dataplane is currently in beta:** Functionality associated with Consul Dataplane is subject to change. You should never use the beta release in secure environments or production scenarios. Features in beta may have performance issues, scaling issues, and limited support. - This topic provides an overview of Consul Dataplane, a lightweight process for managing Envoy proxies introduced in Consul v1.14.0. Consul Dataplane removes the need to run client agents on every node in a cluster for service discovery and service mesh. Instead, Consul deploys sidecar proxies that provide lower latency, support additional runtimes, and integrate with cloud infrastructure providers. -Consul Dataplane requires servers running Consul v1.14.0-beta1+ and Consul K8s v1.0.0-beta1+. +Consul Dataplane requires servers running Consul v1.14.0+ and Consul K8s v1.0.0+. ## What is Consul Dataplane? -In standard deployments, Consul uses a control plane that contains both *server agents* and *client agents*. Server agents maintain the service catalog and service mesh, including its security and consistency, while client agents manage communications between service instances, their sidecar proxies, and the servers. While this model is optimal for applications deployed on virtual machines or bare metal servers, orchestrators such as Kubernetes already include components called *kubelets* that support health checking and service location functions typically provided by the client agent. +In standard deployments, Consul uses a control plane that contains both _server agents_ and _client agents_. Server agents maintain the service catalog and service mesh, including its security and consistency, while client agents manage communications between service instances, their sidecar proxies, and the servers. While this model is optimal for applications deployed on virtual machines or bare metal servers, orchestrators such as Kubernetes already include components called _kubelets_ that support health checking and service location functions typically provided by the client agent. + +Consul Dataplane manages Envoy proxies and leaves responsibility for other functions to the orchestrator. As a result, it removes the need to run client agents on every node. In addition, services no longer need to be reregistered to a local client agent after restarting a service instance, as a client agent’s lack of access to persistent data storage in Kubernetes deployments is no longer an issue. + +![Diagram of Consul Dataplanes in Kubernetes deployment](/img/k8s-dataplanes-architecture.png) + +### Impact on performance + +The most significant differences between traditional deployments and Consul Dataplane deployments result from the removal of node-level client agents with gossip communication. They are replaced by _dataplanes_, which are the sidecars injected alongside each service instance that handle communication between Consul servers and Envoy proxies. While dataplanes use fewer resources than client agents, Consul servers need to consume additional resources in order to generate xDS resources for Envoy proxies. -Consul Dataplane manages Envoy proxies and leaves responsibility for other functions to the orchestrator. As a result, it removes the need to run client agents on every pod. In addition, services no longer need to be reregistered to a local client agent after restarting a service instance, as a client agent’s lack of access to persistent data storage in Kubernetes deployments is no longer an issue. +As a result, small deployments require fewer resources overall. For deployments that are especially large or expected to experience high levels of churn, consider the following impacts to your network's performance: + +1. In our internal tests, which used 5000 proxies and services flapping every 2 seconds, additional CPU utilization remained under 10% on the control plane. +1. As you deploy more services, the resource usage for dataplanes grows on a linear scale. +1. Envoy reconfigurations are rate limited to prevent excessive configuration changes from generating significant load on the servers. +1. To avoid generating significant load on an individual server, proxy configuration is load balanced proactively. +1. The frequency of the orchestrator's liveness and readiness probes determine how quickly Consul's control plane can become aware of failures. There is no impact on service mesh applications, however, as Envoy proxies have a passive ability to detect endpoint failure and steer traffic to healthy instances. ## Benefits @@ -25,7 +37,8 @@ Consul Dataplane manages Envoy proxies and leaves responsibility for other funct **Simplified set up**: Because there are no client agents to engage in gossip, you do not have to generate and distribute a gossip encryption key to agents during the initial bootstrapping process. Securing agent communication also becomes simpler, with fewer tokens to track, distribute, and rotate. -**Additional environment and runtime support**: Current Consul on Kubernetes deployments require using `hostPorts` and `DaemonSets` for client agents, which limits Consul’s ability to be deployed in environments where those features are not supported. As a result, Consul Dataplane supports AWS Fargate and GKE Autopilot. +**Additional environment and runtime support**: Consul on Kubernetes versions *prior* to 1.0 (Consul 1.14) require using hostPorts and DaemonSets for client agents, which limits Consul’s ability to be deployed in environments where those features are not supported. +As of Consul on Kubernetes version 1.0 (Consul 1.14) with the new Consul Dataplane, `hostPorts` are no longer required and Consul now supports AWS Fargate and GKE Autopilot. **Easier upgrades**: With Consul Dataplane, updating Consul to a new version no longer requires upgrading client agents. Consul Dataplane also has better compatibility across Consul server versions, so the process to upgrade Consul servers becomes easier. @@ -39,40 +52,39 @@ To get started with Consul Dataplane, use the following reference resources: ### Installation -To install the beta release of Consul Dataplane, set `VERSION` to `1.0.0-beta` and then follow the instructions to install a specific version of Consul [with the Helm Chart](/docs/k8s/installation/install#install-consul) or [with the Consul-k8s CLI](/docs/k8s/installation/install-cli#install-a-previous-version). +To install Consul Dataplane, set `VERSION` to `1.0.0` and then follow the instructions to install a specific version of Consul [with the Helm Chart](/docs/k8s/installation/install#install-consul) or [with the Consul-k8s CLI](/docs/k8s/installation/install-cli#install-a-previous-version). #### Helm ```shell-session -$ export VERSION=1.0.0-beta3 +$ export VERSION=1.0.0 $ helm install consul hashicorp/consul --set global.name=consul --version ${VERSION} --create-namespace --namespace consul ``` #### Consul-k8s CLI ```shell-session -$ export VERSION=1.0.0-beta3 && \ +$ export VERSION=1.0.0 && \ curl --location "https://releases.hashicorp.com/consul-k8s/${VERSION}/consul-k8s_${VERSION}_darwin_amd64.zip" --output consul-k8s-cli.zip ``` -## Beta release features +### Upgrading + +Before you upgrade Consul to a version that uses Consul Dataplane, you must edit your Helm chart so that client agents are removed from your deployments. Refer to [upgrading to Consul Dataplane](/docs/k8s/upgrade#upgrading-to-consul-dataplanes) for more information. -The beta release of Consul Dataplane supports the following features: +## Feature support + +Consul Dataplane supports the following features: - Single and multi-cluster installations, including those with WAN federation, cluster peering, and admin partitions are supported. - Ingress, terminating, and mesh gateways are supported. - Running Consul service mesh in AWS Fargate and GKE Autopilot is supported. - xDS load balancing is supported. - Servers running in Kubernetes and servers external to Kubernetes are both supported. - -Integration with HCP Consul is being tested in an invitation-only closed beta. HCP Consul support for Dataplane will be available for all users in a future release. +- HCP Consul is supported. ### Technical Constraints Be aware of the following limitations and recommendations for Consul Dataplane: -- Metrics and telemetry are not currently available for services deployed with Dataplane. -- Consul API Gateway is not currently supported. -- Transparent proxies are not supported. -- Using `proxy-defaults` and `service-defaults` to configure default proxy behavior is not supported. - Consul Dataplane is not supported on Windows. diff --git a/website/content/docs/connect/dataplane/telemetry.mdx b/website/content/docs/connect/dataplane/telemetry.mdx new file mode 100644 index 000000000000..e9de1e3a5d3b --- /dev/null +++ b/website/content/docs/connect/dataplane/telemetry.mdx @@ -0,0 +1,43 @@ +--- +layout: docs +page_title: Consul Dataplane - Enable Telemetry Metrics +description: >- + Configure telemetry to collect metrics you can use to debug and observe Consul Dataplane behavior and performance. +--- + +# Consul Dataplane Telemetry + +Consul Dataplane collects metrics about its own status and performance. +The following external metrics stores are supported: + +- [DogstatsD](https://docs.datadoghq.com/developers/dogstatsd/) +- [Prometheus](https://prometheus.io/docs/prometheus/latest/) +- [StatsD](https://github.com/statsd/statsd) + +Consul Dataplane uses the same external metrics store that is configured for Envoy. To enable +telemetry for Consul Dataplane, enable telemetry for Envoy by specifying an external metrics store +in the proxy-defaults configuration entry or directly in the proxy.config field of the proxy service +definition. Refer to the [Envoy bootstrap +configuration](/docs/connect/proxies/envoy#bootstrap-configuration) for details. + +## Prometheus Metrics Merging + +When Prometheus metrics are used, Consul Dataplane configures Envoy to serve merged metrics through +a single endpoint. Metrics from the following sources are collected and merged: + +- Consul Dataplane +- The Envoy process managed by Consul Dataplane +- (optionally) Your service instance running alongside Consul Dataplane + +## Metrics Reference + +Consul Dataplane supports the following metrics: + +| Metric Name | Description | Unit | Type | +| :------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------- | :------ | +| `consul_dataplane.connect_duration` | Measures the time `consul-dataplane` spends connecting to a Consul server, including the time to discover Consul server addresses and to complete other setup prior to Envoy opening the xDS stream. | ms | timer | +| `consul_dataplane.connected` | Indicates whether `consul-dataplane` is currently connected to a Consul server. | 1 or 0 | gauge | +| `consul_dataplane.connection_errors` | Measures the number of errors encountered on gRPC streams. This is labeled with the gRPC error status code. | number of errors | gauge | +| `consul_dataplane.discover_servers_duration` | Measures the time `consul-dataplane` spends discovering Consul server IP addresses. | ms | timer | +| `consul_dataplane.envoy_connected` | Indicates whether Envoy is currently connected to `consul-dataplane` and able to receive xDS updates. | 1 or 0 | gauge | +| `consul_dataplane.login_duration` | Measures the time `consul-dataplane` spends logging in to an ACL auth method. | ms | timer | diff --git a/website/content/docs/connect/distributed-tracing.mdx b/website/content/docs/connect/distributed-tracing.mdx index 9c177b82dd9b..46a3721af42f 100644 --- a/website/content/docs/connect/distributed-tracing.mdx +++ b/website/content/docs/connect/distributed-tracing.mdx @@ -214,7 +214,7 @@ config to take effect. ```yaml apiVersion: consul.hashicorp.com/v1alpha1 - kind: ProxyDefaults + kind: ServiceDefaults metadata: name: service-name spec: diff --git a/website/content/docs/connect/gateways/index.mdx b/website/content/docs/connect/gateways/index.mdx index 040492a7f09d..01727380507e 100644 --- a/website/content/docs/connect/gateways/index.mdx +++ b/website/content/docs/connect/gateways/index.mdx @@ -23,13 +23,15 @@ Mesh gateways enable service mesh traffic to be routed between different Consul in different clouds or runtime environments where general interconnectivity between all services in all datacenters isn't feasible. -They operate by sniffing and extracting the server name indication (SNI) header from the service mesh session and routing the connection to the appropriate destination based on the server name requested. The gateway does not decrypt the data within the mTLS session. +They operate by sniffing and extracting the server name indication (SNI) header from the service mesh session and routing the connection to the appropriate destination based on the server name requested. Mesh gateways enable the following scenarios: * **Federate multiple datacenters across a WAN**. Since Consul 1.8.0, mesh gateways can forward gossip and RPC traffic between Consul servers. See [WAN federation via mesh gateways](/docs/connect/gateways/mesh-gateway/wan-federation-via-mesh-gateways) for additional information. -- **Service-to-service communication across datacenters**. Refer to [Enabling Service-to-service Traffic Across Datacenters](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters) for additional information. +- **Service-to-service communication across WAN-federated datacenters**. Refer to [Enabling Service-to-service Traffic Across Datacenters](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-wan-datacenters) for additional information. - **Service-to-service communication across admin partitions**. Since Consul 1.11.0, you can create administrative boundaries for single Consul deployments called "admin partitions". You can use mesh gateways to facilitate cross-partition communication. Refer to [Enabling Service-to-service Traffic Across Admin Partitions](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-partitions) for additional information. +- **Bridge multiple datacenters using Cluster Peering**. Since Consul 1.14.0, mesh gateways can be used to route peering control-plane traffic between peered Consul Servers. See [Mesh Gateways for Peering Control Plane Traffic](/docs/connect/gateways/mesh-gateway/peering-via-mesh-gateways) for more information. +- **Service-to-service communication across peered datacenters**. Refer to [Mesh Gateways between Peered Clusters](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-peers) for more information. -> **Mesh gateway tutorial**: Follow the [mesh gateway tutorial](https://learn.hashicorp.com/tutorials/consul/service-mesh-gateways) to learn concepts associated with mesh gateways. diff --git a/website/content/docs/connect/gateways/ingress-gateway.mdx b/website/content/docs/connect/gateways/ingress-gateway.mdx index 8a30a1e34b4b..2a09e4f44bf8 100644 --- a/website/content/docs/connect/gateways/ingress-gateway.mdx +++ b/website/content/docs/connect/gateways/ingress-gateway.mdx @@ -20,7 +20,7 @@ to a set of backing [services](/docs/connect/config-entries/ingress-gateway#services). To enable easier service discovery, a new Consul [DNS -subdomain](/docs/discovery/dns#ingress-service-lookups) is provided, on +subdomain](/consul/docs/services/discovery/dns-static-lookups#ingress-service-lookups) is provided, on `.ingress.`. For listeners with a @@ -29,8 +29,8 @@ For listeners with a case, the ingress gateway relies on host/authority headers to decide the service that should receive the traffic. The host used to match traffic defaults to the [Consul DNS ingress -subdomain](/docs/discovery/dns#ingress-service-lookups), but can be changed using -the [hosts](/docs/connect/config-entries/ingress-gateway#hosts) field. +subdomain](/consul/docs/services/discovery/dns-static-lookups#ingress-service-lookups), but can be changed using +the [hosts](/consul/docs/connect/config-entries/ingress-gateway#hosts) field. ![Ingress Gateway Architecture](/img/ingress-gateways.png) diff --git a/website/content/docs/connect/gateways/mesh-gateway/index.mdx b/website/content/docs/connect/gateways/mesh-gateway/index.mdx new file mode 100644 index 000000000000..206f724e8e1d --- /dev/null +++ b/website/content/docs/connect/gateways/mesh-gateway/index.mdx @@ -0,0 +1,259 @@ +--- +layout: docs +page_title: Mesh Gateways +description: >- + Mesh gateways are specialized proxies that route data between services that cannot communicate directly. Learn how mesh gateways are used in different Consul configurations. +--- + +# Mesh Gateways + +Mesh gateways enable service mesh traffic to be routed between different Consul datacenters. +Datacenters can reside in different clouds or runtime environments where general interconnectivity between all services in all datacenters isn't feasible. + +## Prerequisites + +Mesh gateways can be used with any of the following Consul configrations for managing separate datacenters or partitions. + +1. WAN Federation + * [Mesh gateways can be used to route service-to-service traffic between datacenters](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-wan-datacenters) + * [Mesh gateways can be used to route all WAN traffic, including from Consul servers](/docs/connect/gateways/mesh-gateway/wan-federation-via-mesh-gateways) +2. Cluster Peering + * [Mesh gateways can be used to route service-to-service traffic between datacenters](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-peers) + * [Mesh gateways can be used to route control-plane traffic from Consul servers](/docs/connect/gateways/mesh-gateway/peering-via-mesh-gateways) +3. Admin Partitions + * [Mesh gateways can be used to route service-to-service traffic between admin partitions in the same Consul datacenter](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-partitions) + +### Consul + +Review the [specific guide](#prerequisites) for your use case to determine the required version of Consul. + +### Network + +* General network connectivity to all services within its local Consul datacenter. +* General network connectivity to all mesh gateways within remote Consul datacenters. + +### Proxy + +Envoy is the only proxy with mesh gateway capabilities in Consul. + +Mesh gateway proxies receive their configuration through Consul, which automatically generates it based on the proxy's registration. +Consul can only translate mesh gateway registration information into Envoy configuration. + +Sidecar proxies that send traffic to an upstream service through a gateway need to know the location of that gateway. They discover the gateway based on their sidecar proxy registrations. Consul can only translate the gateway registration information into Envoy configuration. + +Sidecar proxies that do not send upstream traffic through a gateway are not affected when you deploy gateways. If you are using Consul's built-in proxy as a Connect sidecar it will continue to work for intra-datacenter traffic and will receive incoming traffic even if that traffic has passed through a gateway. + +## Configuration + +Configure the following settings to register the mesh gateway as a service in Consul. + +* Specify `mesh-gateway` in the `kind` field to register the gateway with Consul. +* Configure the `proxy.upstreams` parameters to route traffic to the correct service, namespace, and datacenter. Refer to the [`upstreams` documentation](/docs/connect/registration/service-registration#upstream-configuration-reference) for details. The service `proxy.upstreams.destination_name` is always required. The `proxy.upstreams.datacenter` must be configured to enable cross-datacenter traffic. The `proxy.upstreams.destination_namespace` configuration is only necessary if the destination service is in a different namespace. +* Define the `Proxy.Config` settings using opaque parameters compatible with your proxy (i.e., Envoy). For Envoy, refer to the [Gateway Options](/docs/connect/proxies/envoy#gateway-options) and [Escape-hatch Overrides](/docs/connect/proxies/envoy#escape-hatch-overrides) documentation for additional configuration information. +* If ACLs are enabled, a token granting `service:write` for the gateway's service name and `service:read` for all services in the datacenter or partition must be added to the gateway's service definition. These permissions authorize the token to route communications for other Consul service mesh services, but does not allow decrypting any of their communications. + +### Modes + +Each upstream associated with a service mesh proxy can be configured so that it is routed through a mesh gateway. +Depending on your network, the proxy's connection to the gateway can operate in one of the following modes: + +* `none` - No gateway is used and a service mesh connect proxy makes its outbound connections directly + to the destination services. This is the default for WAN federation. This setting is invalid for peered clusters + and will be treated as remote instead. + +* `local` - The service mesh connect proxy makes an outbound connection to a gateway running in the + same datacenter. That gateway is responsible for ensuring that the data is forwarded to gateways in the destination datacenter. + +* `remote` - The service mesh proxy makes an outbound connection to a gateway running in the destination datacenter. + The gateway forwards the data to the final destination service. This is the default for peered clusters. + +### Connect Proxy Configuration + +Set the proxy to the preferred [mode](#modes) to configure the service mesh proxy. You can specify the mode globally or within child configurations to control proxy behaviors at a lower level. Consul recognizes the following order of precedence if the gateway mode is configured in multiple locations the order of precedence: + +1. Upstream definition (highest priority) +2. Service instance definition +3. Centralized `service-defaults` configuration entry +4. Centralized `proxy-defaults` configuration entry + +## Example Configurations + +Use the following example configurations to help you understand some of the common scenarios. + +### Enabling Gateways Globally + +The following `proxy-defaults` configuration will enable gateways for all Connect services in the `local` mode. + + + +```hcl +Kind = "proxy-defaults" +Name = "global" +MeshGateway { + Mode = "local" +} +``` + +```yaml +Kind: proxy-defaults +MeshGateway: +- Mode: local +Name: global +``` + + +### Enabling Gateways Per Service + +The following `service-defaults` configuration will enable gateways for all Connect services with the name `web`. + + + +```hcl +Kind = "service-defaults" +Name = "web" +MeshGateway { + Mode = "local" +} +``` + +```yaml +Kind: service-defaults +MeshGateway: +- Mode: local +Name: web +``` + + + +### Enabling Gateways for a Service Instance + +The following [Proxy Service Registration](/docs/connect/registration/service-registration) +definition will enable gateways for the service instance in the `remote` mode. + + + +```hcl +service { + name = "web-sidecar-proxy" + kind = "connect-proxy" + port = 8181 + proxy { + destination_service_name = "web" + mesh_gateway { + mode = "remote" + } + upstreams = [ + { + destination_name = "api" + datacenter = "secondary" + local_bind_port = 10000 + } + ] + } +} + +# Or alternatively inline with the service definition: + +service { + name = "web" + port = 8181 + connect { + sidecar_service { + proxy { + mesh_gateway { + mode = "remote" + } + upstreams = [ + { + destination_name = "api" + datacenter = "secondary" + local_bind_port = 10000 + } + ] + } + } + } +} +``` + +```yaml +service: +- kind: connect-proxy + name: web-sidecar-proxy + port: 8181 + proxy: + - destination_service_name: web + mesh_gateway: + - mode: remote + upstreams: + - datacenter: secondary + destination_name: api + local_bind_port: 100 +``` + + + +### Enabling Gateways for a Proxy Upstream + +The following service definition will enable gateways in the `local` mode for one upstream, the `remote` mode for a second upstream and will disable gateways for a third upstream. + + + +```hcl +service { + name = "web-sidecar-proxy" + kind = "connect-proxy" + port = 8181 + proxy { + destination_service_name = "web" + upstreams = [ + { + destination_name = "api" + destination_peer = "cluster-01" + local_bind_port = 10000 + mesh_gateway { + mode = "remote" + } + }, + { + destination_name = "db" + datacenter = "secondary" + local_bind_port = 10001 + mesh_gateway { + mode = "local" + } + }, + { + destination_name = "logging" + datacenter = "secondary" + local_bind_port = 10002 + mesh_gateway { + mode = "none" + } + }, + ] + } +} +``` +```yaml +service: +- kind: connect-proxy + name: web-sidecar-proxy + port: 8181 + proxy: + - destination_service_name: web + upstreams: + - destination_name: api + local_bind_port: 10000 + mesh_gateway: + - mode: remote + - destination_name: db + local_bind_port: 10001 + mesh_gateway: + - mode: local + - destination_name: logging + local_bind_port: 10002 + mesh_gateway: + - mode: none + ``` + diff --git a/website/content/docs/connect/gateways/mesh-gateway/peering-via-mesh-gateways.mdx b/website/content/docs/connect/gateways/mesh-gateway/peering-via-mesh-gateways.mdx new file mode 100644 index 000000000000..6751e28bd4ca --- /dev/null +++ b/website/content/docs/connect/gateways/mesh-gateway/peering-via-mesh-gateways.mdx @@ -0,0 +1,135 @@ +--- +layout: docs +page_title: Enabling Peering Control Plane Traffic +description: >- + Mesh gateways are specialized proxies that route data between services that cannot communicate directly. Learn how to enable traffic across clusters in different datacenters or admin partitions that have an established peering connection. +--- + +# Enabling Peering Control Plane Traffic + +In addition to [service-to-service traffic routing](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-peers), +we recommend routing control plane traffic between cluster peers through mesh gateways +to simplfy networking requirements. + +Control plane traffic between cluster peers includes +the initial secret handshake and the bi-directional stream replicating peering data. +This data is not decrypted by the mesh gateway(s). +Instead, it is transmitted end-to-end using the accepting cluster’s auto-generated TLS certificate on the gRPC TLS port. + + + + +[![Cluster peering with mesh gateways](/img/consul-connect/mesh-gateway/cluster-peering-connectivity-with-mesh-gateways.png)](/img/consul-connect/mesh-gateway/cluster-peering-connectivity-with-mesh-gateways.png) + + + + + +[![Cluster peering without mesh gateways](/img/consul-connect/mesh-gateway/cluster-peering-connectivity-without-mesh-gateways.png)](/img/consul-connect/mesh-gateway/cluster-peering-connectivity-without-mesh-gateways.png) + + + + +## Prerequisites + +To configure mesh gateways for cluster peering control plane traffic, make sure your Consul environment meets the following requirements: + +- Consul version 1.14.0 or newer. +- A local Consul agent in both clusters is required to manage mesh gateway configuration. +- Use [Envoy proxies](/docs/connect/proxies/envoy). Envoy is the only proxy with mesh gateway capabilities in Consul. + +## Configuration + +Configure the following settings to register and use the mesh gateway as a service in Consul. + +### Gateway registration + +Register a mesh gateway in each of cluster that will be peered. + +- Specify `mesh-gateway` in the `kind` field to register the gateway with Consul. +- Define the `Proxy.Config` settings using opaque parameters compatible with your proxy. For Envoy, refer to the [Gateway Options](/docs/connect/proxies/envoy#gateway-options) and [Escape-hatch Overrides](/docs/connect/proxies/envoy#escape-hatch-overrides) documentation for additional configuration information. +- Apply a [Mesh config entry](/docs/connect/config-entries/mesh#peer-through-mesh-gateways) with `PeerThroughMeshGateways = true`. See [modes](#modes) for a discussion of when to apply this. + +Alternatively, you can also use the CLI to spin up and register a gateway in Consul. For additional information, refer to the [`consul connect envoy` command](/commands/connect/envoy#mesh-gateways). + +For Consul Enterprise clusters, mesh gateways must be registered in the "default" partition because this is implicitly where Consul servers are assigned. + +### ACL configuration + + + + +In addition to the [ACL Configuration](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-peers#acl-configuration) necessary for service-to-service traffic, mesh gateways that route peering control plane traffic must be granted `peering:read` access to all peerings. +This access allows the mesh gateway to list all peerings in a Consul cluster and generate unique routing per peered datacenter. + + + +```hcl +peering = "read" +``` + +```json +{ + "peering": "read" +} +``` + + + + + + + +In addition to the [ACL Configuration](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-peers#acl-configuration) necessary for service-to-service traffic, mesh gateways that route peering control plane traffic must be granted `peering:read` access to all peerings in all partitions. +This access allows the mesh gateway to list all peerings in a Consul cluster and generate unique routing per peered partition. + + + +```hcl +partition_prefix "" { + peering = "read" +} +``` + +```json +{ + "partition_prefix": { + "": { + "peering": "read" + } + } +} +``` + + + + + + +### Modes + +Connect proxy configuration [Modes](/docs/connect/gateways/mesh-gateway#connect-proxy-configuration#modes) are not applicable to peering control plane traffic. +The flow of control plane traffic through the gateway is implied by the presence of a [Mesh config entry](/docs/connect/config-entries/mesh#peer-through-mesh-gateways) with `PeerThroughMeshGateways = true`. + + + +```hcl +Kind = "mesh" +Peering { + PeerThroughMeshGateways = true +} +``` + +```yaml +Kind: mesh +Peeering: + PeerThroughMeshGateways: true +``` + + +By setting this mesh config on a cluster before [creating a peering token](/docs/connect/cluster-peering/create-manage-peering#create-a-peering-token), inbound control plane traffic will be sent through the mesh gateway registered this cluster, also known the accepting cluster. +As mesh gateway instances are registered at the accepting cluster, their addresses will be exposed to the dialing cluster over the bi-directional peering stream. + +Setting this mesh config on a cluster before [establishing a connection](/docs/connect/cluster-peering/create-manage-peering#establish-a-connection-between-clusters) will cause the outbound control plane traffic to flow through the mesh gateway. + +To route all peering control plane traffic though mesh gateways, both the accepting and dialing cluster must have the mesh config entry applied. diff --git a/website/content/docs/connect/gateways/mesh-gateway/service-to-service-traffic-partitions.mdx b/website/content/docs/connect/gateways/mesh-gateway/service-to-service-traffic-partitions.mdx index 585ae4100da3..409705d6b81a 100644 --- a/website/content/docs/connect/gateways/mesh-gateway/service-to-service-traffic-partitions.mdx +++ b/website/content/docs/connect/gateways/mesh-gateway/service-to-service-traffic-partitions.mdx @@ -1,11 +1,11 @@ --- layout: docs -page_title: Mesh Gateways between Admin Partitions +page_title: Enabling Service-to-service Traffic Across Admin Partitions description: >- Mesh gateways are specialized proxies that route data between services that cannot communicate directly with upstreams. Learn how to enable service-to-service traffic across admin partitions and review example configuration entries. --- -# Mesh Gateways between Admin Partitions +# Enabling Service-to-service Traffic Across Admin Partitions -> **Consul Enterprise 1.11.0+:** Admin partitions are supported in Consul Enterprise versions 1.11.0 and newer. @@ -25,7 +25,7 @@ Ensure that your Consul environment meets the following requirements. * A local Consul agent is required to manage its configuration. * Consul service mesh must be enabled in all partitions. Refer to the [`connect` documentation](/docs/agent/config/config-files#connect) for details. * Each partition must have a unique name. Refer to the [admin partitions documentation](/docs/enterprise/admin-partitions) for details. -* If you want to [enable gateways globally](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters#enabling-gateways-globally) you must enable [centralized configuration](/docs/agent/config/config-files#enable_central_service_config). +* If you want to [enable gateways globally](/docs/connect/gateways/mesh-gateway#enabling-gateways-globally) you must enable [centralized configuration](/docs/agent/config/config-files#enable_central_service_config). ### Proxy diff --git a/website/content/docs/connect/gateways/mesh-gateway/service-to-service-traffic-peers.mdx b/website/content/docs/connect/gateways/mesh-gateway/service-to-service-traffic-peers.mdx deleted file mode 100644 index c971c0a2751b..000000000000 --- a/website/content/docs/connect/gateways/mesh-gateway/service-to-service-traffic-peers.mdx +++ /dev/null @@ -1,54 +0,0 @@ ---- -layout: docs -page_title: Mesh Gateways between Peered Clusters -description: >- - Mesh gateways are specialized proxies that route data between services that cannot communicate directly. Learn how to enable service-to-service traffic across clusters in different datacenters or admin partitions that have an established peering connection. ---- - -# Mesh Gateways between Peered Clusters - -~> **Cluster peering is currently in beta**: Functionality associated with cluster peering is subject to change. You should never use the beta release in secure environments or production scenarios. Features in beta may have performance issues, scaling issues, and limited support. - -Mesh gateways are required for you to route service mesh traffic between different Consul clusters. Clusters can reside in different clouds or runtime environments where general interconnectivity between all services in all clusters is not feasible. - -Unlike mesh gateways for datacenters and partitions, mesh gateways between peers terminate mTLS sessions to decrypt data to HTTP services and then re-encrypt traffic to send to services. Data must be decrypted in order to evaluate and apply dynamic routing rules at the destination cluster, which reduces coupling between peers. - -## Prerequisites - -To configure mesh gateways for cluster peering, make sure your Consul environment meets the following requirements: - -- Consul version 1.13.0 or newer. -- A local Consul agent is required to manage mesh gateway configuration. -- [Enable Consul service mesh](/docs/agent/config/config-files#connect-parameters) in all clusters. -- [Enable `peering`](/docs/agent/config/config-files) on all Consul servers. -- Use [Envoy proxies](/docs/connect/proxies/envoy). Envoy is the only proxy with mesh gateway capabilities in Consul. - -## Configuration - -Configure the following settings to register and use the mesh gateway as a service in Consul. - -### Gateway registration - -- Specify `mesh-gateway` in the `kind` field to register the gateway with Consul. -- Define the `Proxy.Config` settings using opaque parameters compatible with your proxy. For Envoy, refer to the [Gateway Options](/docs/connect/proxies/envoy#gateway-options) and [Escape-hatch Overrides](/docs/connect/proxies/envoy#escape-hatch-overrides) documentation for additional configuration information. - -Alternatively, you can also use the CLI to spin up and register a gateway in Consul. For additional information, refer to the [`consul connect envoy` command](/commands/connect/envoy#mesh-gateways). - -### Sidecar registration - -- Configure the `proxy.upstreams` parameters to route traffic to the correct service, namespace, and peer. Refer to the [`upstreams` documentation](/docs/connect/registration/service-registration#upstream-configuration-reference) for details. -- The service `proxy.upstreams.destination_name` is always required. -- The `proxy.upstreams.destination_peer` must be configured to enable cross-cluster traffic. -- The `proxy.upstream/destination_namespace` configuration is only necessary if the destination service is in a non-default namespace. - -### Service exports - -- Include the `exported-services` configuration entry to enable Consul to export services contained in a cluster to one or more additional clusters. For additional information, refer to the [Exported Services documentation](/docs/connect/config-entries/exported-services). - -### ACL configuration - -- If ACLs are enabled, you must add a token granting `service:write` for the gateway's service name and `service:read` for all services in the Enterprise admin partition or OSS datacenter to the gateway's service definition. These permissions authorize the token to route communications for other Consul service mesh services. - -### Modes - -Modes are not configurable for mesh gateways that connect peered clusters. By default, all proxies connecting to peered clusters use mesh gateways in [remote mode](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters#remote). diff --git a/website/content/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters.mdx b/website/content/docs/connect/gateways/mesh-gateway/service-to-service-traffic-wan-datacenters.mdx similarity index 95% rename from website/content/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters.mdx rename to website/content/docs/connect/gateways/mesh-gateway/service-to-service-traffic-wan-datacenters.mdx index 9630ac4b766f..32370c8e34f1 100644 --- a/website/content/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters.mdx +++ b/website/content/docs/connect/gateways/mesh-gateway/service-to-service-traffic-wan-datacenters.mdx @@ -1,11 +1,11 @@ --- layout: docs -page_title: Mesh Gateways between Datacenters +page_title: Enabling Service-to-service Traffic Across WAN Federated Datacenters description: >- - Mesh gateways are specialized proxies that route data between services that cannot communicate directly. Learn how to enable service-to-service traffic across datacenters and review example configuration entries. + Mesh gateways are specialized proxies that route data between services that cannot communicate directly. Learn how to enable service-to-service traffic across wan-federated datacenters and review example configuration entries. --- -# Mesh Gateways between Datacenters +# Enabling Service-to-service Traffic Across WAN Federated Datacenters -> **1.6.0+:** This feature is available in Consul versions 1.6.0 and newer. @@ -34,7 +34,7 @@ Ensure that your Consul environment meets the following requirements. * Each datacenters must be [WAN joined](https://learn.hashicorp.com/consul/security-networking/datacenters). * The [primary datacenter](/docs/agent/config/config-files#primary_datacenter) must be set to the same value in both datacenters. This specifies which datacenter is the authority for Connect certificates and is required for services in all datacenters to establish mutual TLS with each other. * [gRPC](/docs/agent/config/config-files#grpc_port) must be enabled. -* If you want to [enable gateways globally](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters#enabling-gateways-globally) you must enable [centralized configuration](/docs/agent/config/config-files#enable_central_service_config). +* If you want to [enable gateways globally](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-wan-datacenters#enabling-gateways-globally) you must enable [centralized configuration](/docs/agent/config/config-files#enable_central_service_config). ### Network diff --git a/website/content/docs/connect/gateways/mesh-gateway/wan-federation-via-mesh-gateways.mdx b/website/content/docs/connect/gateways/mesh-gateway/wan-federation-via-mesh-gateways.mdx index 55a8194f5415..21c68d23ab7b 100644 --- a/website/content/docs/connect/gateways/mesh-gateway/wan-federation-via-mesh-gateways.mdx +++ b/website/content/docs/connect/gateways/mesh-gateway/wan-federation-via-mesh-gateways.mdx @@ -1,15 +1,15 @@ --- layout: docs -page_title: Mesh Gateways for WAN Federation +page_title: Enabling WAN Federation Control Plane Traffic description: >- You can use mesh gateways to simplify the networking requirements for WAN federated Consul datacenters. Mesh gateways reduce cross-datacenter connection paths, ports, and communication protocols. --- -# Mesh Gateways for WAN Federation +# Enabling WAN Federation Control Plane Traffic -> **1.8.0+:** This feature is available in Consul versions 1.8.0 and higher -~> This topic requires familiarity with [mesh gateways](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters). +~> This topic requires familiarity with [mesh gateways](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-wan-datacenters). WAN federation via mesh gateways allows for Consul servers in different datacenters to be federated exclusively through mesh gateways. @@ -38,7 +38,7 @@ Sometimes this prerequisite is difficult or undesirable to meet: Operators looking to simplify their WAN deployment and minimize the exposed security surface area can elect to join these datacenters together using [mesh -gateways](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters) to do so. +gateways](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-wan-datacenters) to do so. [![WAN federation with mesh gateways](/img/wan-federation-connectivity-mesh-gateways.png)](/img/wan-federation-connectivity-mesh-gateways.png) @@ -184,3 +184,18 @@ expected result: - Ensure any API request that activates datacenter request forwarding. such as [`/v1/catalog/services?dc=`](/api-docs/catalog#dc-1) succeeds. + +### Upgrading the primary gateways + +Once federation is established, secondary datacenters will continuously request +updated mesh gateway addresses from the primary datacenter. Consul routes the requests + through the primary datacenter's mesh gateways. This is because +secondary datacenters cannot directly dial the primary datacenter's Consul servers. +If the primary gateways are upgraded, and their previous instances are decommissioned +before the updates are propagated, then the primary datacenter will become unreachable. + +To safely upgrade primary gateways, we recommend that you apply one of the following policies: +- Avoid decommissioning primary gateway IP addresses. This is because the [primary_gateways](/docs/agent/config/config-files#primary_gateways) addresses configured on the secondary servers act as a fallback mechanism for re-establishing connectivity to the primary. + +- Verify that addresses of the new mesh gateways in the primary were propagated +to the secondary datacenters before decommissioning the old mesh gateways in the primary. diff --git a/website/content/docs/connect/gateways/terminating-gateway.mdx b/website/content/docs/connect/gateways/terminating-gateway.mdx index 37468e08169d..17f1726d0a69 100644 --- a/website/content/docs/connect/gateways/terminating-gateway.mdx +++ b/website/content/docs/connect/gateways/terminating-gateway.mdx @@ -27,7 +27,7 @@ for filtering by instance. ~> We recommend that terminating gateways are not exposed to the WAN or open internet. This is because terminating gateways hold certificates to decrypt Consul Connect traffic directed at them and may be configured with credentials to connect -to linked services. Connections over the WAN or open internet should flow through [mesh gateways](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters) +to linked services. Connections over the WAN or open internet should flow through [mesh gateways](/docs/connect/gateways/mesh-gateway) whenever possible since they are not capable of decrypting traffic or connecting directly to services. By specifying a path to a [CA file](/docs/connect/config-entries/terminating-gateway#cafile) connections diff --git a/website/content/docs/connect/l7-traffic/discovery-chain.mdx b/website/content/docs/connect/l7-traffic/discovery-chain.mdx index 8fb905b0ae0d..e96070e7d172 100644 --- a/website/content/docs/connect/l7-traffic/discovery-chain.mdx +++ b/website/content/docs/connect/l7-traffic/discovery-chain.mdx @@ -228,7 +228,7 @@ A single node in the compiled discovery chain. be considered healthy. - `MeshGateway` `(MeshGatewayConfig)` - The [mesh gateway - configuration](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters#connect-proxy-configuration) + configuration](/docs/connect/gateways/mesh-gateway#connect-proxy-configuration) to use when connecting to this target's service instances. - `Mode` `(string: "")` - One of `none`, `local`, or `remote`. diff --git a/website/content/docs/connect/native/index.mdx b/website/content/docs/connect/native/index.mdx index bae584ca366e..87ef0c88a1b8 100644 --- a/website/content/docs/connect/native/index.mdx +++ b/website/content/docs/connect/native/index.mdx @@ -54,7 +54,7 @@ Details on the steps are below: - **Service discovery** - This is normal service discovery using Consul, a static IP, or any other mechanism. If you're using Consul DNS, the - [`.connect`](/docs/discovery/dns#connect-capable-service-lookups) + [`.connect`](/consul/docs/services/discovery/dns-static-lookups#service-mesh-enabled-service-lookups) syntax to find Connect-capable endpoints for a service. After service discovery, choose one address from the list of **service addresses**. @@ -94,7 +94,7 @@ Details on the steps are below: HTTP) aware it can safely enforce intentions per _request_ instead of the coarser per _connection_ model. -## Updating Certificates and Certificate Roots +## Update certificates and certificate roots The leaf certificate and CA roots can be updated at any time and the natively integrated application must react to this relatively quickly @@ -129,14 +129,14 @@ Some language libraries such as the [Go library](/docs/connect/native/go) automatically handle updating and locally caching the certificates. -## Service Registration +## Service registration Connect-native applications must tell Consul that they support Connect natively. This enables the service to be returned as part of service -discovery for Connect-capable services, used by other Connect-native applications -and client [proxies](/docs/connect/proxies). +discovery for service mesh-capable services used by other Connect-native applications +and client [proxies](/consul/docs/connect/proxies). -This can be specified directly in the [service definition](/docs/discovery/services): +You can enable native service mesh support directly in the [service definition](/consul/docs/services/configuration/services-configuration-reference#connect) by configuring the `connect` block. In the following example, the `redis` service is configured to support service mesh natively: ```json { diff --git a/website/content/docs/connect/nomad.mdx b/website/content/docs/connect/nomad.mdx index fc88d86c7199..ca0663834c09 100644 --- a/website/content/docs/connect/nomad.mdx +++ b/website/content/docs/connect/nomad.mdx @@ -1,6 +1,6 @@ --- layout: docs -page_title: Sevice Mesh - Nomad Integration +page_title: Service Mesh - Nomad Integration description: >- Consul's service mesh can be applied to provide secure communication between services managed by Nomad's scheduler and orchestrator functions, including Nomad jobs and task groups. Use the guide and reference documentation to learn more. --- diff --git a/website/content/docs/connect/observability/index.mdx b/website/content/docs/connect/observability/index.mdx index b56611dab866..1bb3dbbc9c1b 100644 --- a/website/content/docs/connect/observability/index.mdx +++ b/website/content/docs/connect/observability/index.mdx @@ -26,7 +26,7 @@ configuration](/docs/agent/config/config-files#enable_central_service_config). If you are using Kubernetes, the Helm chart can simplify much of the configuration needed to enable observability. See our [Kubernetes observability docs](/docs/k8s/connect/observability/metrics) for more information. -### Metrics Destination +### Metrics destination For Envoy the metrics destination can be configured in the proxy configuration entry's `config` section. @@ -41,18 +41,18 @@ config { Find other possible metrics syncs in the [Connect Envoy documentation](/docs/connect/proxies/envoy#bootstrap-configuration). -### Service Protocol +### Service protocol -You can specify the [service protocol](/docs/connect/config-entries/service-defaults#protocol) -in the `service-defaults` configuration entry. You can override it in the -[service registration](/docs/discovery/services). By default, proxies only give -you L4 metrics. This protocol allows proxies to handle requests at the right L7 -protocol and emit richer L7 metrics. It also allows proxies to make per-request +You can specify the [`protocol`](/consul/docs/connect/config-entries/service-defaults#protocol) +for all service instances in the `service-defaults` configuration entry. You can also override the default protocol when defining and registering proxies in a service definition file. Refer to [Expose Paths Configuration Reference](/consul/docs/connect/registration/service-registration#expose-paths-configuration-reference) for additional information. + +By default, proxies only provide L4 metrics. +Defining the protocol allows proxies to handle requests at the L7 +protocol and emit L7 metrics. It also allows proxies to make per-request load balancing and routing decisions. -### Service Upstreams +### Service upstreams You can set the upstream for each service using the proxy's -[`upstreams`](/docs/connect/registration/service-registration#upstreams) -sidecar parameter, which can be defined in a service's [sidecar -registration](/docs/connect/registration/sidecar-service). +[`upstreams`](/consul/docs/connect/registration/service-registration#upstreams) +sidecar parameter, which can be defined in a service's [sidecar registration](/consul/docs/connect/registration/sidecar-service). diff --git a/website/content/docs/connect/proxies/envoy.mdx b/website/content/docs/connect/proxies/envoy.mdx index e95e25ccf513..9346866b2dc2 100644 --- a/website/content/docs/connect/proxies/envoy.mdx +++ b/website/content/docs/connect/proxies/envoy.mdx @@ -24,9 +24,9 @@ Consul can configure Envoy sidecars to proxy traffic over the following protocol On Consul 1.5.0 and older, Envoy proxies can only proxy TCP traffic at L4. -Some [L7 features](/docs/connect/l7-traffic) can be configured using [configuration entries](/docs/agent/config-entries). You can add [custom Envoy configurations](#advanced-configuration) to the [proxy service definition](/docs/connect/registration/service-registration) to use Envoy features that are not currently exposed through configuration entries. Adding custom Envoy configurations to the service definition is an interim solution that enables you to use the more powerful features of Envoy. +Some [L7 features](/consul/docs/connect/l7-traffic) can be configured using [configuration entries](/consul/docs/agent/config-entries). You can add [custom Envoy configurations](#advanced-configuration) to the [proxy service definition](/consul/docs/connect/registration/service-registration) to use Envoy features that are not currently exposed through configuration entries. Adding custom Envoy configurations to the service definition is an interim solution that enables you to use the more powerful features of Envoy. -~> **Note:** When using Envoy with Consul and not using the [`consul connect envoy` command](/commands/connect/envoy) +~> **Note:** When using Envoy with Consul and not using the [`consul connect envoy` command](/consul/commands/connect/envoy) Envoy must be run with the `--max-obj-name-len` option set to `256` or greater for Envoy versions prior to 1.11.0. ## Supported Versions @@ -39,22 +39,20 @@ Consul supports **four major Envoy releases** at the beginning of each major Con | Consul Version | Compatible Envoy Versions | | ------------------- | -----------------------------------------------------------------------------------| +| 1.14.x | 1.24.10, 1.23.12, 1.22.11, 1.21.6 | | 1.13.x | 1.23.1, 1.22.5, 1.21.5, 1.20.7 | | 1.12.x | 1.22.5, 1.21.5, 1.20.7, 1.19.5 | -| 1.11.x | 1.20.7, 1.19.5, 1.18.6, 1.17.41 | 1. Envoy 1.20.1 and earlier are vulnerable to [CVE-2022-21654](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21654) and [CVE-2022-21655](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21655). Both CVEs were patched in Envoy versions 1.18.6, 1.19.3, and 1.20.2. Envoy 1.16.x and older releases are no longer supported (see [HCSEC-2022-07](https://discuss.hashicorp.com/t/hcsec-2022-07-consul-s-connect-service-mesh-affected-by-recent-envoy-security-releases/36332)). Consul 1.9.x clusters should be upgraded to 1.10.x and Envoy upgraded to the latest supported Envoy version for that release, 1.18.6. ### Envoy and Consul Dataplane -~> **Note:** Consul Dataplane is currently in beta. - Consul Dataplane is a feature introduced in Consul v1.14. Because each version of Consul Dataplane supports one specific version of Envoy, you must use the following versions of Consul, Consul Dataplane, and Envoy together. | Consul Version | Consul Dataplane Version | Bundled Envoy Version | | ------------------- | ------------------------ | ---------------------- | -| 1.14.x | 1.0.x | 1.23.x | +| 1.14.x | 1.0.x | 1.24.x | ## Getting Started @@ -80,7 +78,7 @@ The dynamic configuration Consul Connect provides to each Envoy instance include - Service-discovery results for upstreams to enable each sidecar proxy to load-balance outgoing connections. - L7 configuration including timeouts and protocol-specific options. -- Configuration to [expose specific HTTP paths](/docs/connect/registration/service-registration#expose-paths-configuration-reference). +- Configuration to [expose specific HTTP paths](/consul/docs/connect/registration/service-registration#expose-paths-configuration-reference). For more information on the parts of the Envoy proxy runtime configuration that are currently controllable via Consul Connect see [Dynamic @@ -96,8 +94,8 @@ responsibility for correctly configuring Envoy and ensuring version support etc. ## Intention Enforcement -[Intentions] are enforced using Envoy's RBAC filters. Depending on the -configured [protocol] of the proxied service, intentions are either enforced +[Intentions](/consul/docs/connect/intentions) are enforced using Envoy's RBAC filters. Depending on the +configured [protocol](/consul/docs/connect/config-entries/service-defaults#protocol) of the proxied service, intentions are either enforced per-connection (L4) using a network filter, or per-request (L7) using an HTTP filter. @@ -106,41 +104,51 @@ per-connection (L4) using an `ext_authz` network filter. ## Fetching Certificates -Envoy will use the [`CONSUL_HTTP_TOKEN`](/commands#consul_http_token) and [`CONSUL_HTTP_ADDR`](/commands#consul_http_addr) environment variables to contact Consul to fetch certificates if the following conditions are met: +Envoy will use the [`CONSUL_HTTP_TOKEN`](/consul/commands#consul_http_token) and [`CONSUL_HTTP_ADDR`](/consul/commands#consul_http_addr) environment variables to contact Consul to fetch certificates if the following conditions are met: - The `CONSUL_HTTP_TOKEN` environment variable contains a Consul ACL token. - The Consul ACL token has the necessary permissions to read configuration for that service. If TLS is enabled on Consul, you will also need to add the following environment variables _prior_ to starting Envoy: -- [`CONSUL_CACERT`](/commands#consul_cacert) -- [`CONSUL_CLIENT_CERT`](/commands#consul_client_cert) -- [`CONSUL_CLIENT_KEY`](/commands#consul_client_key) -- [`CONSUL_HTTP_SSL`](/commands#consul_http_ssl) +- [`CONSUL_CACERT`](/consul/commands#consul_cacert) +- [`CONSUL_CLIENT_CERT`](/consul/commands#consul_client_cert) +- [`CONSUL_CLIENT_KEY`](/consul/commands#consul_client_key) +- [`CONSUL_HTTP_SSL`](/consul/commands#consul_http_ssl) ## Bootstrap Configuration -Envoy requires an initial bootstrap configuration file. The easiest way to -create this is using the [`consul connect envoy` -command](/commands/connect/envoy). The command can either output the -bootstrap configuration directly to stdout, or generate the configuration and issue an `exec` command -to the Envoy binary as a convenience wrapper. For more information about using `exec` to bootstrap Envoy, refer to [Exec Security Details](/consul/commands/connect/envoy#exec-security-details). +Envoy requires an initial bootstrap configuration file. You can either create the file manually using the Consul command line or configure Consul Dataplane to generate the file. + +### Generate the bootstrap file on the Consul CLI + +Connect to a local Consul client agent and run the [`consul connect envoy` command](/consul/commands/connect/envoy) to create the Envoy bootstrap configuration. The command either outputs the bootstrap configuration directly to stdout or generates the configuration and issues an `exec` command to the Envoy binary as a convenience wrapper. For more information about using `exec` to bootstrap Envoy, refer to [Exec Security Details](/consul/commands/connect/envoy#exec-security-details). + +If you experience issues when bootstrapping Envoy proxies from the CLI, use the +`-enable-config-gen-logging` flag to enable debug message logging. These logs can +help you troubleshoot issues that occur during the bootstrapping process. +For more information about available flags and parameters, refer to the +[`consul connect envoy CLI` reference](/consul/commands/connect/envoy). + +### Generate the bootstrap file from Consul Dataplane + +Consul Dataplane automatically configures and manages an Envoy process. Consul Dataplane generates the Envoy bootstrap configuration file prior to starting Envoy. To configure how Consul Dataplane starts Envoy, refer to the [Consul Dataplane CLI reference](/consul/docs/connect/dataplane/consul-dataplane). + +### Control bootstrap configuration from proxy configuration -Because some Envoy configuration options, such as metrics and tracing sinks, can only be -specified via the bootstrap configuration, Connect as of Consul 1.5.0 adds -the ability to control some parts of the bootstrap config via proxy configuration options. +Consul service mesh can control some parts of the bootstrap configuration by specifying Envoy proxy configuration options. -Add the following configuration items to the [global `proxy-defaults` -configuration entry](/docs/connect/config-entries/proxy-defaults) or override them directly in the `proxy.config` field -of a [proxy service -definition](/docs/connect/registration/service-registration) or -[`sidecar_service`](/docs/connect/registration/sidecar-service) block. +Add the following configuration items to the [global `proxy-defaults` configuration +entry](/consul/docs/connect/config-entries/proxy-defaults) or override them directly in the `proxy.config` +field of a [proxy service definition](/consul/docs/connect/registration/service-registration). When +connected to a Consul client agent, you can place the configuration in the `proxy.config` field of +the [`sidecar_service`](/consul/docs/connect/registration/sidecar-service) block. - `envoy_statsd_url` - A URL in the form `udp://ip:port` identifying a UDP StatsD listener that Envoy should deliver metrics to. For example, this may be `udp://127.0.0.1:8125` if every host has a local StatsD listener. In this case users can configure this property once in the [global `proxy-defaults` - configuration entry](/docs/connect/config-entries/proxy-defaults) for convenience. Currently, TCP is not supported. + configuration entry](/consul/docs/connect/config-entries/proxy-defaults) for convenience. Currently, TCP is not supported. ~> **Note:** currently the url **must use an ip address** not a dns name due to the way Envoy is setup for StatsD. @@ -154,7 +162,7 @@ definition](/docs/connect/registration/service-registration) or pod in a Kubernetes cluster to learn of a pod-specific IP address for StatsD when the Envoy instance is bootstrapped while still allowing global configuration of all proxies to use StatsD in the [global `proxy-defaults` - configuration entry](/docs/connect/config-entries/proxy-defaults). The env + configuration entry](/consul/docs/connect/config-entries/proxy-defaults). The env variable must contain a full valid URL value as specified above and nothing else. - `envoy_dogstatsd_url` - The same as `envoy_statsd_url` with the following @@ -188,7 +196,7 @@ The [Advanced Configuration](#advanced-configuration) section describes addition ### Bootstrap Envoy on Windows VMs -> Complete the [Connect Services on Windows Workloads to Consul Service Mesh tutorial](https://learn.hashicorp.com/tutorials/consul/consul-windows-workloads?utm_source=docs) to learn how to deploy Consul and use its service mesh on Windows VMs. +> Complete the [Connect Services on Windows Workloads to Consul Service Mesh tutorial](/consul/tutorials/developer-mesh/consul-windows-workloads) to learn how to deploy Consul and use its service mesh on Windows VMs. If you are running Consul on a Windows VM, attempting to bootstrap Envoy with the `consul connect envoy` command returns the following output: @@ -251,13 +259,14 @@ $ envoy -c bootstrap.json Consul automatically generates Envoy's dynamic configuration based on its knowledge of the cluster. Users may specify default configuration options for -each service such as which protocol they speak. Consul will use this information -to configure appropriate proxy settings for that service's proxies and also for -the upstream listeners of any downstream service. - -One example is how users can define a service's protocol in a [`service-defaults` configuration -entry](/docs/connect/config-entries/service-defaults). Agents with -[`enable_central_service_config`](/docs/agent/config/config-files#enable_central_service_config) +a service through the available fields in the [`service-defaults` configuration +entry](/consul/docs/connect/config-entries/service-defaults). Consul will use this +information to configure appropriate proxy settings for that service's proxies +and also for the upstream listeners used by the service. + +One example is how users can define a service's protocol in the `Protocol` field of [`service-defaults` configuration +entry](/consul/docs/connect/config-entries/service-defaults). Agents with +[`enable_central_service_config`](/consul/docs/agent/config/config-files#enable_central_service_config) set to true will automatically discover the protocol when configuring a proxy for a service. The proxy will discover the main protocol of the service it represents and use this to configure its main public listener. It will also @@ -266,18 +275,18 @@ automatically configure its upstream listeners appropriately too as below. This automated discovery results in Consul auto-populating the `proxy.config` and `proxy.upstreams[*].config` fields of the [proxy service -definition](/docs/connect/registration/service-registration) that is +definition](/consul/docs/connect/registration/service-registration) that is actually registered. To learn about other options that can be configured centrally see the -[Configuration Entries](/docs/agent/config-entries) docs. +[Configuration Entries](/consul/docs/agent/config-entries) docs. ### Proxy Config Options -These fields may also be overridden explicitly in the [proxy service -definition](/docs/connect/registration/service-registration), or defined in +These fields may also be overridden explicitly in `proxy.config` of the [proxy service +definition](/consul/docs/connect/registration/service-registration), or defined in the [global `proxy-defaults` configuration -entry](/docs/connect/config-entries/proxy-defaults) to act as +entry](/consul/docs/connect/config-entries/proxy-defaults) to act as defaults that are inherited by all services. - `protocol` - The protocol the service speaks. Connect's Envoy integration @@ -304,12 +313,12 @@ defaults that are inherited by all services. metrics with `gRPC-status` trailer codes. ~> **Note:** The protocol of a service should ideally be configured via the - [`protocol`](/docs/connect/config-entries/service-defaults#protocol) + [`protocol`](/consul/docs/connect/config-entries/service-defaults#protocol) field of a - [`service-defaults`](/docs/connect/config-entries/service-defaults) + [`service-defaults`](/consul/docs/connect/config-entries/service-defaults) config entry for the service. Configuring it in a proxy config will not fully enable some [L7 - features](/docs/connect/l7-traffic). + features](/consul/docs/connect/l7-traffic). It is supported here for backwards compatibility with Consul versions prior to 1.6.0. - `bind_address` - Override the address Envoy's public listener binds to. By @@ -327,11 +336,19 @@ defaults that are inherited by all services. specified, inherits the Envoy default for route timeouts (15s). A value of 0 will disable request timeouts. +- `local_idle_timeout_ms` - In milliseconds, the idle timeout for HTTP requests + to the local application instance. Applies to HTTP based protocols only. If not + specified, inherits the Envoy default for route idle timeouts (15s). A value of 0 + disables request timeouts. + +- `max_inbound_connections` - The maximum number of concurrent inbound connections + to the local application instance. If not specified, inherits the Envoy default (1024). + - `balance_inbound_connections` - The strategy used for balancing inbound connections across Envoy worker threads. Consul service mesh Envoy integration supports the following `balance_inbound_connections` values: - - `""` - Empty string (default). No connection balancing strategy is used. Consul does not balance inbound connections. + - `""` - Empty string (default). No connection balancing strategy is used. Consul does not balance inbound connections. - `exact_balance` - Inbound connections to the service use the [Envoy Exact Balance Strategy.](https://cloudnative.to/envoy/api-v3/config/listener/v3/listener.proto.html#config-listener-v3-listener-connectionbalanceconfig-exactbalance) @@ -339,19 +356,19 @@ defaults that are inherited by all services. The following configuration items may be overridden directly in the `proxy.upstreams[].config` field of a [proxy service -definition](/docs/connect/registration/service-registration) or -[`sidecar_service`](/docs/connect/registration/sidecar-service) block. +definition](/consul/docs/connect/registration/service-registration) or +[`sidecar_service`](/consul/docs/connect/registration/sidecar-service) block. - `protocol` - Same as above in main config but affects the listener setup for the upstream. ~> **Note:** The protocol of a service should ideally be configured via the - [`protocol`](/docs/connect/config-entries/service-defaults#protocol) + [`protocol`](/consul/docs/connect/config-entries/service-defaults#protocol) field of a - [`service-defaults`](/docs/connect/config-entries/service-defaults) + [`service-defaults`](/consul/docs/connect/config-entries/service-defaults) config entry for the upstream destination service. Configuring it in a proxy upstream config will not fully enable some [L7 - features](/docs/connect/l7-traffic). + features](/consul/docs/connect/l7-traffic). It is supported here for backwards compatibility with Consul versions prior to 1.6.0. - `connect_timeout_ms` - The number of milliseconds to allow when making upstream @@ -360,9 +377,9 @@ definition](/docs/connect/registration/service-registration) or ~> **Note:** The connection timeout for a service should ideally be configured via the - [`connect_timeout`](/docs/connect/config-entries/service-resolver#connecttimeout) + [`connect_timeout`](/consul/docs/connect/config-entries/service-resolver#connecttimeout) field of a - [`service-resolver`](/docs/connect/config-entries/service-resolver) + [`service-resolver`](/consul/docs/connect/config-entries/service-resolver) config entry for the upstream destination service. Configuring it in a proxy upstream config will override any values defined in config entries. It is supported here for backwards compatibility with Consul versions prior to 1.6.0. @@ -398,16 +415,16 @@ definition](/docs/connect/registration/service-registration) or across Envoy worker threads. Consul service mesh Envoy integration supports the following `balance_outbound_connections` values: - - `""` - Empty string (default). No connection balancing strategy is used. Consul does not balance outbound connections. + - `""` - Empty string (default). No connection balancing strategy is used. Consul does not balance outbound connections. - `exact_balance` - Outbound connections from the upstream use the [Envoy Exact Balance Strategy.](https://cloudnative.to/envoy/api-v3/config/listener/v3/listener.proto.html#config-listener-v3-listener-connectionbalanceconfig-exactbalance) ### Gateway Options These fields may also be overridden explicitly in the [proxy service -definition](/docs/connect/registration/service-registration), or defined in +definition](/consul/docs/connect/registration/service-registration), or defined in the [global `proxy-defaults` configuration -entry](/docs/connect/config-entries/proxy-defaults) to act as +entry](/consul/docs/connect/config-entries/proxy-defaults) to act as defaults that are inherited by all services. Prior to 1.8.0 these settings were specific to Mesh Gateways. The deprecated @@ -417,7 +434,7 @@ will continue to be supported. - `connect_timeout_ms` - The number of milliseconds to allow when making upstream connections before timing out. Defaults to 5000 (5 seconds). If the upstream service has the configuration option - [`connect_timeout_ms`](/docs/connect/config-entries/service-resolver#connecttimeout) + [`connect_timeout_ms`](/consul/docs/connect/config-entries/service-resolver#connecttimeout) set for the `service-resolver`, that timeout value will take precedence over this gateway option. @@ -577,12 +594,12 @@ EOF Users may add the following configuration items to the [global `proxy-defaults` configuration -entry](/docs/connect/config-entries/proxy-defaults) or +entry](/consul/docs/connect/config-entries/proxy-defaults) or override them directly in the `proxy.config` field of a [proxy service -definition](/docs/connect/registration/service-registration) or -[`sidecar_service`](/docs/connect/registration/sidecar-service) block. +definition](/consul/docs/connect/registration/service-registration) or +[`sidecar_service`](/consul/docs/connect/registration/sidecar-service) block. -- `envoy_extra_static_clusters_json` - Specifies one or more [Envoy clusters][pb-cluster] +- `envoy_extra_static_clusters_json` - Specifies one or more [Envoy clusters](https://www.envoyproxy.io/docs/envoy/v1.17.2/api-v3/config/cluster/v3/cluster.proto) that will be appended to the array of [static clusters](https://www.envoyproxy.io/docs/envoy/v1.17.2/api-v3/config/bootstrap/v3/bootstrap.proto#envoy-v3-api-field-config-bootstrap-v3-bootstrap-staticresources-clusters) in the bootstrap config. This enables you to add custom clusters for tracing sinks, @@ -620,7 +637,7 @@ definition](/docs/connect/registration/service-registration) or - `envoy_extra_static_listeners_json` - Similar to - `envoy_extra_static_clusters_json` but appends one or more [Envoy listeners][pb-listener] to the array of [static + `envoy_extra_static_clusters_json` but appends one or more [Envoy listeners](https://www.envoyproxy.io/docs/envoy/v1.17.2/api-v3/config/listener/v3/listener.proto) to the array of [static listener](https://www.envoyproxy.io/docs/envoy/v1.17.2/api-v3/config/bootstrap/v3/bootstrap.proto#envoy-v3-api-field-config-bootstrap-v3-bootstrap-staticresources-listeners) definitions. Can be used to setup limited access that bypasses Connect mTLS or authorization for health checks or metrics. @@ -758,23 +775,23 @@ definition](/docs/connect/registration/service-registration) or Users may add the following configuration items to the [global `proxy-defaults` configuration -entry](/docs/connect/config-entries/proxy-defaults) or +entry](/consul/docs/connect/config-entries/proxy-defaults) or override them directly in the `proxy.config` field of a [proxy service -definition](/docs/connect/registration/service-registration) or -[`sidecar_service`](/docs/connect/registration/sidecar-service) block. +definition](/consul/docs/connect/registration/service-registration) or +[`sidecar_service`](/consul/docs/connect/registration/sidecar-service) block. - `envoy_bootstrap_json_tpl` - Specifies a template in Go template syntax that is used in place of [the default template](https://github.com/hashicorp/consul/blob/71d45a34601423abdfc0a64d44c6a55cf88fa2fc/command/connect/envoy/bootstrap_tpl.go#L129) when generating bootstrap via [`consul connect envoy` - command](/commands/connect/envoy). The variables that are available + command](/consul/commands/connect/envoy). The variables that are available to be interpolated are [documented here](https://github.com/hashicorp/consul/blob/71d45a34601423abdfc0a64d44c6a55cf88fa2fc/command/connect/envoy/bootstrap_tpl.go#L5). This offers complete control of the proxy's bootstrap although major deviations from the default template may break Consul's ability to correctly manage the proxy or enforce its security model. -- `envoy_public_listener_json` - Specifies a complete [Envoy listener][pb-listener] +- `envoy_public_listener_json` - Specifies a complete [Envoy listener](https://www.envoyproxy.io/docs/envoy/v1.17.2/api-v3/config/listener/v3/listener.proto) to be delivered in place of the main public listener that the proxy used to accept inbound connections. This will be used verbatim with the following exceptions: @@ -910,7 +927,7 @@ definition](/docs/connect/registration/service-registration) or -- `envoy_local_cluster_json` - Specifies a complete [Envoy cluster][pb-cluster] +- `envoy_local_cluster_json` - Specifies a complete [Envoy cluster](https://www.envoyproxy.io/docs/envoy/v1.17.2/api-v3/config/cluster/v3/cluster.proto) to be delivered in place of the local application cluster. This allows customization of timeouts, rate limits, load balancing strategy etc. @@ -957,17 +974,17 @@ definition](/docs/connect/registration/service-registration) or The following configuration items may be overridden directly in the `proxy.upstreams[].config` field of a [proxy service -definition](/docs/connect/registration/service-registration) or -[`sidecar_service`](/docs/connect/registration/sidecar-service) block. +definition](/consul/docs/connect/registration/service-registration) or +[`sidecar_service`](/consul/docs/connect/registration/sidecar-service) block. ~> **Note:** - When a -[`service-router`](/docs/connect/config-entries/service-router), -[`service-splitter`](/docs/connect/config-entries/service-splitter), or -[`service-resolver`](/docs/connect/config-entries/service-resolver) config +[`service-router`](/consul/docs/connect/config-entries/service-router), +[`service-splitter`](/consul/docs/connect/config-entries/service-splitter), or +[`service-resolver`](/consul/docs/connect/config-entries/service-resolver) config entry exists for a service the below escape hatches are ignored and will log a warning. -- `envoy_listener_json` - Specifies a complete [Listener][pb-listener] +- `envoy_listener_json` - Specifies a complete [Listener](https://www.envoyproxy.io/docs/envoy/v1.17.2/api-v3/config/listener/v3/listener.proto) to be delivered in place of the upstream listener that the proxy exposes to the application for outbound connections. This will be used verbatim with the following exceptions: @@ -1051,7 +1068,7 @@ warning. ``` -- `envoy_cluster_json` - Specifies a complete [Envoy cluster][pb-cluster] +- `envoy_cluster_json` - Specifies a complete [Envoy cluster](https://www.envoyproxy.io/docs/envoy/v1.17.2/api-v3/config/cluster/v3/cluster.proto) to be delivered in place of the discovered upstream cluster. This allows customization of timeouts, circuit breaking, rate limits, load balancing strategy etc. @@ -1084,9 +1101,3 @@ warning. } ``` - -[protocol]: /docs/connect/config-entries/service-defaults#protocol -[intentions]: /docs/connect/intentions -[intentions]: /docs/connect/intentions -[pb-cluster]: https://www.envoyproxy.io/docs/envoy/v1.17.2/api-v3/config/cluster/v3/cluster.proto -[pb-listener]: https://www.envoyproxy.io/docs/envoy/v1.17.2/api-v3/config/listener/v3/listener.proto diff --git a/website/content/docs/connect/proxies/index.mdx b/website/content/docs/connect/proxies/index.mdx index bb83041439d5..fd66e05e5fcc 100644 --- a/website/content/docs/connect/proxies/index.mdx +++ b/website/content/docs/connect/proxies/index.mdx @@ -7,29 +7,23 @@ description: >- # Service Mesh Proxy Overview -A Connect-aware proxy enables unmodified applications to use Connect. A +Proxies enable unmodified applications to connect to other services in the service mesh. A per-service proxy sidecar transparently handles inbound and outbound service connections, automatically wrapping and verifying TLS connections. Consul -includes its own built-in L4 proxy and has first class support for Envoy. You -can choose other proxies to plug in as well. This section describes how to +ships with a built-in L4 proxy and has first class support for Envoy. You +can plug other proxies into your environment as well. This section describes how to configure Envoy or the built-in proxy using Connect, and how to integrate the proxy of your choice. -To ensure that services only allow external connections established via -the Connect protocol, you should configure all services to only accept connections on a loopback address. +To ensure that services only allow external connections established through +the service mesh protocol, you should configure all services to only accept connections on a loopback address. -~> **Deprecation Note:** Managed Proxies are a deprecated method for deploying -sidecar proxies, and have been removed in Consul 1.6. See [managed proxy -deprecation](/docs/connect/proxies/managed-deprecated) for more -information. If you are using managed proxies we strongly recommend that you -switch service definitions for registering proxies. +## Dynamic upstreams require native integration -## Dynamic Upstreams Require Native Integration +Service mesh proxies do not support dynamic upstreams. If an application requires dynamic dependencies that are only available -at runtime, it must [natively integrate](/docs/connect/native) -with Connect. After natively integrating, the HTTP API or -[DNS interface](/docs/discovery/dns#connect-capable-service-lookups) +at runtime, you must [natively integrate](/consul/docs/connect/native) +the application with Consul service mesh. After natively integrating, the HTTP API or +[DNS interface](/consul/docs/services/discovery/dns-static-lookups#service-mesh-enabled-service-lookups) can be used. - -!> Connect proxies do not currently support dynamic upstreams. diff --git a/website/content/docs/connect/proxies/integrate.mdx b/website/content/docs/connect/proxies/integrate.mdx index f61605dd68d8..58e3a854b8f8 100644 --- a/website/content/docs/connect/proxies/integrate.mdx +++ b/website/content/docs/connect/proxies/integrate.mdx @@ -138,7 +138,7 @@ documentation for details about supported configuration parameters. ### Service Discovery -Proxies can use Consul's [service discovery API](`/v1/health/connect/:service_id`) to return all available, Connect-capable endpoints for a given service. This endpoint supports a `cached` query parameter, which uses [agent caching](/api-docs/features/caching) to improve +Proxies can use Consul's [service discovery API](/consul/api-docs/health#list-service-instances-for-connect-enabled-service) to return all available, Connect-capable endpoints for a given service. This endpoint supports a `cached` query parameter, which uses [agent caching](/consul/api-docs/features/caching) to improve performance. The API package provides a [`UseCache`] query option to leverage caching. In addition to performance improvements, using the cache makes the mesh more resilient to Consul server outages. This is because the mesh "fails static" with the last known set of service instances still used, rather than errors on new connections. diff --git a/website/content/docs/connect/proxies/managed-deprecated.mdx b/website/content/docs/connect/proxies/managed-deprecated.mdx deleted file mode 100644 index 2f39cd3fc703..000000000000 --- a/website/content/docs/connect/proxies/managed-deprecated.mdx +++ /dev/null @@ -1,278 +0,0 @@ ---- -layout: docs -page_title: Managed Proxy for Connect (Legacy) -description: >- - Consul's service mesh originally included a proxy manager that was deprecated in version 1.6. Learn about the reasons for its deprecation and how it worked with this legacy documentation. ---- - -# Managed Proxy for Connect Legacy Documentation - -Consul Connect was first released as a beta feature in Consul 1.2.0. The initial -release included a feature called "Managed Proxies". Managed proxies were -Connect proxies where the proxy process was started, configured, and stopped by -Consul. They were enabled via basic configurations within the service -definition. - -!> **Consul 1.6.0 removes Managed Proxies completely.** -This documentation is provided for prior versions only. You may consider using -[sidecar service -registrations](/docs/connect/registration/sidecar-service) instead. - -Managed proxies have been deprecated since Consul 1.3 and have been fully removed -in Consul 1.6. Anyone using Managed Proxies should aim to change their workflow -as soon as possible to avoid issues with a later upgrade. - -After transitioning away from all managed proxy usage, the `proxy` subdirectory inside [`data_dir`](/docs/agent/config/cli-flags#_data_dir) (specified in Consul config) can be deleted to remove extraneous configuration files and free up disk space. - -**new and known issues will not be fixed**. - -## Deprecation Rationale - -Originally managed proxies traded higher implementation complexity for an easier -"getting started" user experience. After seeing how Connect was investigated and -adopted during beta it became obvious that they were not the best trade off. - -Managed proxies only really helped in local testing or VM-per-service based -models whereas a lot of users jumped straight to containers where they are not -helpful. They also add only targeted fairly basic supervisor features which -meant most people would want to use something else in production for consistency -with other workloads. So the high implementation cost of building robust process -supervision didn't actually benefit most real use-cases. - -Instead of this Connect 1.3.0 introduces the concept of [sidecar service -registrations](/docs/connect/registration/sidecar-service) which -have almost all of the benefits of simpler configuration but without any of the -additional process management complexity. As a result they can be used to -simplify configuration in both container-based and realistic production -supervisor settings. - -## Managed Proxy Documentation - -As the managed proxy features continue to be supported for now, the rest of this -page will document how they work in the interim. - --> **Deprecation Note:** It's _strongly_ recommended you do not build anything -using Managed proxies and consider using [sidecar service -registrations](/docs/connect/registration/sidecar-service) instead. - -Managed proxies are given -a unique proxy-specific ACL token that allows read-only access to Connect -information for the specific service the proxy is representing. This ACL -token is more restrictive than can be currently expressed manually in -an ACL policy. - -The default managed proxy is a basic proxy built-in to Consul and written -in Go. Having a basic built-in proxy allows Consul to have a reasonable default -with performance that is good enough for most workloads. In some basic -benchmarks, the service-to-service communication over the built-in proxy -could sustain 5 Gbps with sub-millisecond latency. Therefore, -the performance impact of even the basic built-in proxy is minimal. - -Consul will be integrating with advanced proxies in the near future to support -more complex configurations and higher performance. The configuration below is -all for the built-in proxy. - --> **Security Note:** 1.) Managed proxies can only be configured -via agent configuration files. They _cannot_ be registered via the HTTP API. -And 2.) Managed proxies are not started at all if Consul is running as root. -Both of these default configurations help prevent arbitrary process -execution or privilege escalation. This behavior can be configured -[per-agent](/docs/agent/config). - -### Lifecycle - -The Consul agent starts managed proxies on demand and supervises them, -restarting them if they crash. The lifecycle of the proxy process is decoupled -from the agent so if the agent crashes or is restarted for an upgrade, the -managed proxy instances will _not_ be stopped. - -Note that this behavior while desirable in production might leave proxy -processes running indefinitely if you manually stop the agent and clear its -data dir during testing. - -To terminate a managed proxy cleanly you need to deregister the service that -requested it. If the agent is already stopped and will not be restarted again, -you may choose to locate the proxy processes and kill them manually. - -While in `-dev` mode, unless a `-data-dir` is explicitly set, managed proxies -switch to being killed when the agent exits since it can't store state in order -to re-adopt them on restart. - -### Minimal Configuration - -Managed proxies are configured within a -[service definition](/docs/discovery/services). The simplest possible -managed proxy configuration is an empty configuration. This enables the -default managed proxy and starts a listener for that service: - -```json -{ - "service": { - "name": "redis", - "port": 6379, - "connect": { "proxy": {} } - } -} -``` - -The listener is started on random port within the configured Connect -port range. It can be discovered using the -[DNS interface](/docs/discovery/dns#connect-capable-service-lookups) -or -[Catalog API](#). -In most cases, service-to-service communication is established by -a proxy configured with upstreams (described below), which handle the -discovery transparently. - -### Upstream Configuration - -To transparently discover and establish Connect-based connections to -dependencies, they must be configured with a static port on the managed -proxy configuration: - -```json -{ - "service": { - "name": "web", - "port": 8080, - "connect": { - "proxy": { - "upstreams": [ - { - "destination_name": "redis", - "local_bind_port": 1234 - } - ] - } - } - } -} -``` - -In the example above, -"redis" is configured as an upstream with static port 1234 for service "web". -When a TCP connection is established on port 1234, the proxy -will find Connect-compatible "redis" services via Consul service discovery -and establish a TLS connection identifying as "web". - -~> **Security:** Any application that can communicate to the configured -static port will be able to masquerade as the source service ("web" in the -example above). You must either trust any loopback access on that port or -use namespacing techniques provided by your operating system. - --> **Deprecation Note:** versions 1.2.0 to 1.3.0 required specifying `upstreams` -as part of the opaque `config` that is passed to the proxy. However, since -1.3.0, the `upstreams` configuration is now specified directly under the -`proxy` key. Old service definitions using the nested config will continue to -work and have the values copied into the new location. This allows the upstreams -to be registered centrally rather than being part of the local-only config -passed to the proxy instance. - -For full details of the additional configurable options available when using the -built-in proxy see the [built-in proxy configuration -reference](/docs/connect/configuration). - -### Prepared Query Upstreams - -The upstream destination may also be a -[prepared query](/api-docs/query). -This allows complex service discovery behavior such as connecting to -the nearest neighbor or filtering by tags. - -For example, given a prepared query named "nearest-redis" that is -configured to route to the nearest Redis instance, an upstream can be -configured to route to this query. In the example below, any TCP connection -to port 1234 will attempt a Connect-based connection to the nearest Redis -service. - -```json -{ - "service": { - "name": "web", - "port": 8080, - "connect": { - "proxy": { - "upstreams": [ - { - "destination_name": "redis", - "destination_type": "prepared_query", - "local_bind_port": 1234 - } - ] - } - } - } -} -``` - -For full details of the additional configurable options available when using the -built-in proxy see the [built-in proxy configuration -reference](/docs/connect/configuration). - -### Custom Managed Proxy - -[Custom proxies](/docs/connect/proxies/integrate) can also be -configured to run as a managed proxy. To configure custom proxies, specify -an alternate command to execute for the proxy: - -```json -{ - "service": { - "name": "web", - "port": 8080, - "connect": { - "proxy": { - "exec_mode": "daemon", - "command": ["/usr/bin/my-proxy", "-flag-example"], - "config": { - "foo": "bar" - } - } - } - } -} -``` - -The `exec_mode` value specifies how the proxy is executed. The only -supported value at this time is "daemon". The command is the binary and -any arguments to execute. -The "daemon" mode expects a proxy to run as a long-running, blocking -process. It should not double-fork into the background. The custom -proxy should retrieve its configuration (such as the port to run on) -via the [custom proxy integration APIs](/docs/connect/proxies/integrate). - -The default proxy command can be changed at an agent-global level -in the agent configuration. An example in HCL format is shown below. - -``` -connect { - proxy_defaults { - command = ["/usr/bin/my-proxy"] - } -} -``` - -With this configuration, all services registered without an explicit -proxy command will use `my-proxy` instead of the default built-in proxy. - -The `config` key is an optional opaque JSON object which will be passed through -to the proxy via the proxy configuration endpoint to allow any configuration -options the proxy needs to be specified. See the [built-in proxy -configuration reference](/docs/connect/configuration) -for details of config options that can be passed when using the built-in proxy. - -### Managed Proxy Logs - -Managed proxies have both stdout and stderr captured in log files in the agent's -`data_dir`. They can be found in -`/proxy/logs/-std{err,out}.log`. - -The built-in proxy will inherit its log level from the agent so if the agent is -configured with `log_level = DEBUG`, a proxy it starts will also output `DEBUG` -level logs showing service discovery, certificate and authorization information. - -~> **Note:** In `-dev` mode there is no `data_dir` unless one is explicitly -configured so logging is disabled. You can access logs by providing the -[`-data-dir`](/docs/agent/config/cli-flags#_data_dir) CLI option. If a data dir is -configured, this will also cause proxy processes to stay running when the agent -terminates as described in [Lifecycle](#lifecycle). diff --git a/website/content/docs/connect/registration/index.mdx b/website/content/docs/connect/registration/index.mdx index 379174e310c5..c3e3090b3b2f 100644 --- a/website/content/docs/connect/registration/index.mdx +++ b/website/content/docs/connect/registration/index.mdx @@ -7,14 +7,13 @@ description: >- # Service Mesh Proxy Overview -To make Connect aware of proxies you will need to register them in a [service -definition](/docs/discovery/services), just like you would register any other service with Consul. This section outlines your options for registering Connect proxies, either using independent registrations, or in nested sidecar registrations. +To enable service mesh proxies, you must define and register them with Consul. Proxies are a type of service in Consul that facilitate highly secure communication between services in a service mesh. The topics in the section outline your options for registering service mesh proxies. You can register proxies independently or nested inside a sidecar service registration. -## Proxy Service Registration +## Proxy service registration To register proxies with independent proxy service registrations, you can define them in either in config files or via the API just like any other service. Learn more about all of the options you can define when registering your proxy service in the [proxy registration documentation](/docs/connect/registration/service-registration). -## Sidecar Service Registration +## Sidecar service registration To reduce the amount of boilerplate needed for a sidecar proxy, application service definitions may define an inline sidecar service block. This is an opinionated diff --git a/website/content/docs/connect/registration/service-registration.mdx b/website/content/docs/connect/registration/service-registration.mdx index fcfecf0c0103..45922a8d3cc2 100644 --- a/website/content/docs/connect/registration/service-registration.mdx +++ b/website/content/docs/connect/registration/service-registration.mdx @@ -9,6 +9,7 @@ description: >- This topic describes how to declare a proxy as a `connect-proxy` in service definitions. The `kind` must be declared and information about the service they represent must be provided to function as a Consul service mesh proxy. + ## Configuration Configure a service mesh proxy using the following syntax: @@ -178,9 +179,7 @@ You can configure the service mesh proxy to create listeners for upstream servic ### Upstream Configuration Examples -Upstreams support multiple destination types. The following examples include information about each implementation. - --> **Snake case**: The examples in this topic use `snake_case` because the syntax is supported in configuration files and API registrations. See [Service Definition Parameter Case](/docs/discovery/services#service-definition-parameter-case) for additional information. +Upstreams support multiple destination types. The following examples include information about each implementation. Note that the examples in this topic use snake case, which is a convention that separates words with underscores, because the format is supported in configuration files and API registrations. @@ -300,10 +299,7 @@ The proxy will default to `direct` mode if a mode cannot be determined from the The following examples show additional configuration for transparent proxies. -Added in v1.10.0. - --> Note that `snake_case` is used here as it works in both [config file and API -registrations](/docs/discovery/services#service-definition-parameter-case). +Note that the examples in this topic use snake case, which is a convention that separates words with underscores, because the format is supported in configuration files and API registrations. #### Configure a proxy listener for outbound traffic on port 22500 @@ -328,8 +324,7 @@ registrations](/docs/discovery/services#service-definition-parameter-case). The following examples show all possible mesh gateway configurations. --> Note that `snake_case` is used here as it works in both [config file and API -registrations](/docs/discovery/services#service-definition-parameter-case). + Note that the examples in this topic use snake case, which is a convention that separates words with underscores, because the format is supported in configuration files and API registrations. #### Using a Local/Egress Gateway in the Local Datacenter @@ -385,9 +380,8 @@ The following examples show possible configurations to expose HTTP paths through Exposing paths through Envoy enables a service to protect itself by only listening on localhost, while still allowing non-Connect-enabled applications to contact an HTTP endpoint. Some examples include: exposing a `/metrics` path for Prometheus or `/healthz` for kubelet liveness checks. - --> Note that `snake_case` is used here as it works in both [config file and API -registrations](/docs/discovery/services#service-definition-parameter-case). + +Note that the examples in this topic use snake case, which is a convention that separates words with underscores, because the format is supported in configuration files and API registrations. #### Expose listeners in Envoy for HTTP and GRPC checks registered with the local Consul agent diff --git a/website/content/docs/connect/registration/sidecar-service.mdx b/website/content/docs/connect/registration/sidecar-service.mdx index 81f483e24b5c..57bfc8358227 100644 --- a/website/content/docs/connect/registration/sidecar-service.mdx +++ b/website/content/docs/connect/registration/sidecar-service.mdx @@ -7,20 +7,16 @@ description: >- # Register a Service Mesh Proxy in a Service Registration -Connect proxies are typically deployed as "sidecars" that run on the same node -as the single service instance that they handle traffic for. They might be on -the same VM or running as a separate container in the same network namespace. +This topic describes how to declare a proxy as a _sidecar_ proxy. +Sidecar proxies run on the same node as the single service instance that they handle traffic for. +They may be on the same VM or running as a separate container in the same network namespace. -To simplify the configuration experience when deploying a sidecar for a service -instance, Consul 1.3 introduced a new field in the Connect block of the [service -definition](/docs/discovery/services). +## Configuration -The `connect.sidecar_service` field is a complete nested service definition on -which almost any regular service definition field can be set. The exceptions are -[noted below](#limitations). If used, the service definition is treated -identically to another top-level service definition. The value of the nested -definition is that _all fields are optional_ with some opinionated defaults -applied that make setting up a sidecar proxy much simpler. +Add the `connect.sidecar_service` block to your service definition file and specify the parameters to configure sidecar proxy behavior. The `sidecar_service` block is a service definition that can contain most regular service definition fields. Refer to [Limitations](#limitations) for information about unsupported service definition fields for sidecar proxies. + +Consul treats sidecar proxy service definitions as a root-level service definition. All fields are optional in nested +definitions, which default to opinionated settings that are intended to reduce burden of setting up a sidecar proxy. ## Minimal Example @@ -134,7 +130,7 @@ proxy. - `kind` - Defaults to `connect-proxy`. This can't be overridden currently. - `check`, `checks` - By default we add a TCP check on the local address and port for the proxy, and a [service alias - check](/docs/discovery/checks#alias) for the parent service. If either + check](/consul/docs/services/usage/checks#alias-checks) for the parent service. If either `check` or `checks` fields are set, only the provided checks are registered. - `proxy.destination_service_name` - Defaults to the parent service name. - `proxy.destination_service_id` - Defaults to the parent service ID. @@ -143,8 +139,7 @@ proxy. ## Limitations -Almost all fields in a [service definition](/docs/discovery/services) may be -set on the `connect.sidecar_service` except for the following: +The following fields are not supported in the `connect.sidecar_service` block: - `id` - Sidecar services get an ID assigned and it is an error to override this. This ensures the agent can correctly deregister the sidecar service @@ -153,9 +148,6 @@ set on the `connect.sidecar_service` except for the following: unset this to make the registration be for a regular non-connect-proxy service. - `connect.sidecar_service` - Service definitions can't be nested recursively. -- `connect.proxy` - (Deprecated) [Managed - proxies](/docs/connect/proxies/managed-deprecated) can't be defined on a - sidecar. - `connect.native` - Currently the `kind` is fixed to `connect-proxy` and it's an error to register a `connect-proxy` that is also Connect-native. diff --git a/website/content/docs/consul-vs-other/dns-tools-compare.mdx b/website/content/docs/consul-vs-other/dns-tools-compare.mdx index f4fdf981d42a..c2b82fcf9ba7 100644 --- a/website/content/docs/consul-vs-other/dns-tools-compare.mdx +++ b/website/content/docs/consul-vs-other/dns-tools-compare.mdx @@ -10,7 +10,7 @@ description: >- **Examples**: NS1, AWS Route53, AzureDNS, Cloudflare DNS -Consul was originally designed as a centralized service registry for any cloud environment that dynamically tracks services as they are added, changed, or removed within a compute infrastructure. Consul maintains a catalog of these registered services and their attributes, such as IP addresses or service name. For more information, refer to [What is Service Discovery?(/docs/intro/usecases/what-is-service-discovery). +Consul was originally designed as a centralized service registry for any cloud environment that dynamically tracks services as they are added, changed, or removed within a compute infrastructure. Consul maintains a catalog of these registered services and their attributes, such as IP addresses or service name. For more information, refer to [What is Service Discovery?](/docs/concepts/service-discovery). -As a result, Consul can also provide basic DNS functionality, including [lookups, alternate domains, and access controls](/docs/discovery/dns). Since Consul is platform agnostic, you can retrieve service information across both cloud and on-premises data centers. Consul does not natively support some advanced DNS capabilities, such as filters or advanced routing logic. However, you can integrate Consul with existing DNS solutions, such as [NS1](https://help.ns1.com/hc/en-us/articles/360039417093-NS1-Consul-Integration-Overview) and [DNSimple](https://blog.dnsimple.com/2022/05/consul-integration/), to support these advanced capabilities. +As a result, Consul can also provide basic DNS functionality, including [lookups, alternate domains, and access controls](/consul/docs/services/discovery/dns-overview). Since Consul is platform agnostic, you can retrieve service information across both cloud and on-premises data centers. Consul does not natively support some advanced DNS capabilities, such as filters or advanced routing logic. However, you can integrate Consul with existing DNS solutions, such as [NS1](https://help.ns1.com/hc/en-us/articles/360039417093-NS1-Consul-Integration-Overview) and [DNSimple](https://blog.dnsimple.com/2022/05/consul-integration/), to support these advanced capabilities. diff --git a/website/content/docs/consul-vs-other/service-mesh-compare.mdx b/website/content/docs/consul-vs-other/service-mesh-compare.mdx index b0848d2b90bc..419f5679bae1 100644 --- a/website/content/docs/consul-vs-other/service-mesh-compare.mdx +++ b/website/content/docs/consul-vs-other/service-mesh-compare.mdx @@ -14,5 +14,5 @@ Consul’s service mesh allows organizations to securely connect and manage thei Consul is platform agnostic — it supports any runtime (Kubernetes, EKS, AKS, GKE, VMs, ECS, Lambda, Nomad) and any cloud provider (AWS, Microsoft Azure, GCP, private clouds). This makes it one of the most flexible service discovery and service mesh platforms. While other service mesh software provides support for multiple runtimes for the data plane, they require you to run the control plane solely on Kubernetes. With Consul, you can run both the control plane and data plane in different runtimes. Consul also has several unique integrations with Vault, an industry standard for secrets management. Operators have the option to use Consul’s built-in certificate authority, or leverage Vault’s PKI engine to generate and store TLS certificates for both the data plane and control plane. In addition, Consul can automatically rotate the TLS certificates on both the data plane and control plane without requiring any type of restarts. This lets you rotate the certificates more frequently without incurring additional management burden on operators. -When deploying Consul on Kubernetes, you can store sensitive data including licenses, ACL tokens, and TLS certificates centrally Vault instead of Kubernetes secrets. Vault is much more secure than Kubernetes secrets because it automatically encrypts all data, provides advanced access controls to secrets, and provides centralized governance for all secrets. +When deploying Consul on Kubernetes, you can store sensitive data including licenses, ACL tokens, and TLS certificates centrally in Vault instead of Kubernetes secrets. Vault is much more secure than Kubernetes secrets because it automatically encrypts all data, provides advanced access controls to secrets, and provides centralized governance for all secrets. diff --git a/website/content/docs/discovery/checks.mdx b/website/content/docs/discovery/checks.mdx deleted file mode 100644 index 7ee2d0fe30e8..000000000000 --- a/website/content/docs/discovery/checks.mdx +++ /dev/null @@ -1,976 +0,0 @@ ---- -layout: docs -page_title: Configure Health Checks -description: >- - Agents can be configured to periodically perform custom checks on the health of a service instance or node. Learn about the types of health checks and how to define them in agent and service configuration files. ---- - -# Health Checks - -One of the primary roles of the agent is management of system-level and application-level health -checks. A health check is considered to be application-level if it is associated with a -service. If not associated with a service, the check monitors the health of the entire node. -Review the [health checks tutorial](https://learn.hashicorp.com/tutorials/consul/service-registration-health-checks) -to get a more complete example on how to leverage health check capabilities in Consul. - -A check is defined in a configuration file or added at runtime over the HTTP interface. Checks -created via the HTTP interface persist with that node. - -There are several different kinds of checks: - -- Script + Interval - These checks depend on invoking an external application - that performs the health check, exits with an appropriate exit code, and potentially - generates some output. A script is paired with an invocation interval (e.g. - every 30 seconds). This is similar to the Nagios plugin system. The output of - a script check is limited to 4KB. Output larger than this will be truncated. - By default, Script checks will be configured with a timeout equal to 30 seconds. - It is possible to configure a custom Script check timeout value by specifying the - `timeout` field in the check definition. When the timeout is reached on Windows, - Consul will wait for any child processes spawned by the script to finish. For any - other system, Consul will attempt to force-kill the script and any child processes - it has spawned once the timeout has passed. - In Consul 0.9.0 and later, script checks are not enabled by default. To use them you - can either use : - - - [`enable_local_script_checks`](/docs/agent/config/cli-flags#_enable_local_script_checks): - enable script checks defined in local config files. Script checks defined via the HTTP - API will not be allowed. - - [`enable_script_checks`](/docs/agent/config/cli-flags#_enable_script_checks): enable - script checks regardless of how they are defined. - - ~> **Security Warning:** Enabling script checks in some configurations may - introduce a remote execution vulnerability which is known to be targeted by - malware. We strongly recommend `enable_local_script_checks` instead. See [this - blog post](https://www.hashicorp.com/blog/protecting-consul-from-rce-risk-in-specific-configurations) - for more details. - -- `HTTP + Interval` - These checks make an HTTP `GET` request to the specified URL, - waiting the specified `interval` amount of time between requests (eg. 30 seconds). - The status of the service depends on the HTTP response code: any `2xx` code is - considered passing, a `429 Too ManyRequests` is a warning, and anything else is - a failure. This type of check - should be preferred over a script that uses `curl` or another external process - to check a simple HTTP operation. By default, HTTP checks are `GET` requests - unless the `method` field specifies a different method. Additional header - fields can be set through the `header` field which is a map of lists of - strings, e.g. `{"x-foo": ["bar", "baz"]}`. By default, HTTP checks will be - configured with a request timeout equal to 10 seconds. - - It is possible to configure a custom HTTP check timeout value by - specifying the `timeout` field in the check definition. The output of the - check is limited to roughly 4KB. Responses larger than this will be truncated. - HTTP checks also support TLS. By default, a valid TLS certificate is expected. - Certificate verification can be turned off by setting the `tls_skip_verify` - field to `true` in the check definition. When using TLS, the SNI will be set - automatically from the URL if it uses a hostname (as opposed to an IP address); - the value can be overridden by setting `tls_server_name`. - - Consul follows HTTP redirects by default. Set the `disable_redirects` field to - `true` to disable redirects. - -- `TCP + Interval` - These checks make a TCP connection attempt to the specified - IP/hostname and port, waiting `interval` amount of time between attempts - (e.g. 30 seconds). If no hostname - is specified, it defaults to "localhost". The status of the service depends on - whether the connection attempt is successful (ie - the port is currently - accepting connections). If the connection is accepted, the status is - `success`, otherwise the status is `critical`. In the case of a hostname that - resolves to both IPv4 and IPv6 addresses, an attempt will be made to both - addresses, and the first successful connection attempt will result in a - successful check. This type of check should be preferred over a script that - uses `netcat` or another external process to check a simple socket operation. - By default, TCP checks will be configured with a request timeout of 10 seconds. - It is possible to configure a custom TCP check timeout value by specifying the - `timeout` field in the check definition. - -- `UDP + Interval` - These checks direct the client to periodically send UDP datagrams - to the specified IP/hostname and port. The duration specified in the `interval` field sets the amount of time - between attempts, such as `30s` to indicate 30 seconds. The check is logged as healthy if any response from the UDP server is received. Any other result sets the status to `critical`. - The default interval for, UDP checks is `10s`, but you can configure a custom UDP check timeout value by specifying the - `timeout` field in the check definition. If any timeout on read exists, the check is still considered healthy. - -- `Time to Live (TTL)` ((#ttl)) - These checks retain their last known state - for a given TTL. The state of the check must be updated periodically over the HTTP - interface. If an external system fails to update the status within a given TTL, - the check is set to the failed state. This mechanism, conceptually similar to a - dead man's switch, relies on the application to directly report its health. For - example, a healthy app can periodically `PUT` a status update to the HTTP endpoint; - if the app fails, the TTL will expire and the health check enters a critical state. - The endpoints used to update health information for a given check are: [pass](/api-docs/agent/check#ttl-check-pass), - [warn](/api-docs/agent/check#ttl-check-warn), [fail](/api-docs/agent/check#ttl-check-fail), - and [update](/api-docs/agent/check#ttl-check-update). TTL checks also persist their - last known status to disk. This allows the Consul agent to restore the last known - status of the check across restarts. Persisted check status is valid through the - end of the TTL from the time of the last check. - -- `Docker + Interval` - These checks depend on invoking an external application which - is packaged within a Docker Container. The application is triggered within the running - container via the Docker Exec API. We expect that the Consul agent user has access - to either the Docker HTTP API or the unix socket. Consul uses `$DOCKER_HOST` to - determine the Docker API endpoint. The application is expected to run, perform a health - check of the service running inside the container, and exit with an appropriate exit code. - The check should be paired with an invocation interval. The shell on which the check - has to be performed is configurable which makes it possible to run containers which - have different shells on the same host. Check output for Docker is limited to - 4KB. Any output larger than this will be truncated. In Consul 0.9.0 and later, the agent - must be configured with [`enable_script_checks`](/docs/agent/config/cli-flags#_enable_script_checks) - set to `true` in order to enable Docker health checks. - -- `gRPC + Interval` - These checks are intended for applications that support the standard - [gRPC health checking protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - The state of the check will be updated by probing the configured endpoint, waiting `interval` - amount of time between probes (eg. 30 seconds). By default, gRPC checks will be configured - with a default timeout of 10 seconds. - It is possible to configure a custom timeout value by specifying the `timeout` field in - the check definition. gRPC checks will default to not using TLS, but TLS can be enabled by - setting `grpc_use_tls` in the check definition. If TLS is enabled, then by default, a valid - TLS certificate is expected. Certificate verification can be turned off by setting the - `tls_skip_verify` field to `true` in the check definition. - To check on a specific service instead of the whole gRPC server, add the service identifier after the `gRPC` check's endpoint in the following format `/:service_identifier`. - -- `H2ping + Interval` - These checks test an endpoint that uses http2 - by connecting to the endpoint and sending a ping frame. TLS is assumed to be configured by default. - To disable TLS and use h2c, set `h2ping_use_tls` to `false`. If the ping is successful - within a specified timeout, then the check is updated as passing. - The timeout defaults to 10 seconds, but is configurable using the `timeout` field. If TLS is enabled a valid - certificate is required, unless `tls_skip_verify` is set to `true`. - The check will be run on the interval specified by the `interval` field. - -- `Alias` - These checks alias the health state of another registered - node or service. The state of the check will be updated asynchronously, but is - nearly instant. For aliased services on the same agent, the local state is monitored - and no additional network resources are consumed. For other services and nodes, - the check maintains a blocking query over the agent's connection with a current - server and allows stale requests. If there are any errors in watching the aliased - node or service, the check state will be critical. For the blocking query, the - check will use the ACL token set on the service or check definition or otherwise - will fall back to the default ACL token set with the agent (`acl_token`). - -## Check Definition - -A script check: -======= - -Review the [service health checks tutorial](https://learn.hashicorp.com/tutorials/consul/service-registration-health-checks) -to get a more complete example on how to leverage health check capabilities in Consul. - -## Registering a health check - -There are three ways to register a service with health checks: - -1. Start or reload a Consul agent with a service definition file in the - [agent's configuration directory](/docs/agent#configuring-consul-agents). -1. Call the - [`/agent/service/register`](/api-docs/agent/service#register-service) - HTTP API endpoint to register the service. -1. Use the - [`consul services register`](/commands/services/register) - CLI command to register the service. - -When a service is registered using the HTTP API endpoint or CLI command, -the checks persist in the Consul data folder across Consul agent restarts. - -## Types of checks - -This section describes the available types of health checks you can use to -automatically monitor the health of a service instance or node. - --> **To manually mark a service unhealthy:** Use the maintenance mode - [CLI command](/commands/maint) or - [HTTP API endpoint](/api-docs/agent#enable-maintenance-mode) - to temporarily remove one or all service instances on a node - from service discovery DNS and HTTP API query results. - -### Script check ((#script-interval)) - -Script checks periodically invoke an external application that performs the health check, -exits with an appropriate exit code, and potentially generates some output. -The specified `interval` determines the time between check invocations. -The output of a script check is limited to 4KB. -Larger outputs are truncated. - -By default, script checks are configured with a timeout equal to 30 seconds. -To configure a custom script check timeout value, -specify the `timeout` field in the check definition. -After reaching the timeout on a Windows system, -Consul waits for any child processes spawned by the script to finish. -After reaching the timeout on other systems, -Consul attempts to force-kill the script and any child processes it spawned. - -Script checks are not enabled by default. -To enable a Consul agent to perform script checks, -use one of the following agent configuration options: - -- [`enable_local_script_checks`](/docs/agent/config/cli-flags#_enable_local_script_checks): - Enable script checks defined in local config files. - Script checks registered using the HTTP API are not allowed. -- [`enable_script_checks`](/docs/agent/config/cli-flags#_enable_script_checks): - Enable script checks no matter how they are registered. - - ~> **Security Warning:** - Enabling non-local script checks in some configurations may introduce - a remote execution vulnerability known to be targeted by malware. - We strongly recommend `enable_local_script_checks` instead. - For more information, refer to - [this blog post](https://www.hashicorp.com/blog/protecting-consul-from-rce-risk-in-specific-configurations). - -The following service definition file snippet is an example -of a script check definition: - - - -```hcl -check = { - id = "mem-util" - name = "Memory utilization" - args = ["/usr/local/bin/check_mem.py", "-limit", "256MB"] - interval = "10s" - timeout = "1s" -} -``` - -```json -{ - "check": { - "id": "mem-util", - "name": "Memory utilization", - "args": ["/usr/local/bin/check_mem.py", "-limit", "256MB"], - "interval": "10s", - "timeout": "1s" - } -} -``` - - - -#### Check script conventions - -A check script's exit code is used to determine the health check status: - -- Exit code 0 - Check is passing -- Exit code 1 - Check is warning -- Any other code - Check is failing - -Any output of the script is captured and made available in the -`Output` field of checks included in HTTP API responses, -as in this example from the [local service health endpoint](/api-docs/agent/service#by-name-json). - -### HTTP check ((#http-interval)) - -HTTP checks periodically make an HTTP `GET` request to the specified URL, -waiting the specified `interval` amount of time between requests. -The status of the service depends on the HTTP response code: any `2xx` code is -considered passing, a `429 Too ManyRequests` is a warning, and anything else is -a failure. This type of check -should be preferred over a script that uses `curl` or another external process -to check a simple HTTP operation. By default, HTTP checks are `GET` requests -unless the `method` field specifies a different method. Additional request -headers can be set through the `header` field which is a map of lists of -strings, such as `{"x-foo": ["bar", "baz"]}`. - -By default, HTTP checks are configured with a request timeout equal to 10 seconds. -To configure a custom HTTP check timeout value, -specify the `timeout` field in the check definition. -The output of an HTTP check is limited to approximately 4KB. -Larger outputs are truncated. -HTTP checks also support TLS. By default, a valid TLS certificate is expected. -Certificate verification can be turned off by setting the `tls_skip_verify` -field to `true` in the check definition. When using TLS, the SNI is implicitly -determined from the URL if it uses a hostname instead of an IP address. -You can explicitly set the SNI value by setting `tls_server_name`. - -Consul follows HTTP redirects by default. -To disable redirects, set the `disable_redirects` field to `true`. - -The following service definition file snippet is an example -of an HTTP check definition: - - - -```hcl -check = { - id = "api" - name = "HTTP API on port 5000" - http = "https://localhost:5000/health" - tls_server_name = "" - tls_skip_verify = false - method = "POST" - header = { - Content-Type = ["application/json"] - } - body = "{\"method\":\"health\"}" - disable_redirects = true - interval = "10s" - timeout = "1s" -} -``` - -```json -{ - "check": { - "id": "api", - "name": "HTTP API on port 5000", - "http": "https://localhost:5000/health", - "tls_server_name": "", - "tls_skip_verify": false, - "method": "POST", - "header": { "Content-Type": ["application/json"] }, - "body": "{\"method\":\"health\"}", - "interval": "10s", - "timeout": "1s" - } -} -``` - - - -### TCP check ((#tcp-interval)) - -TCP checks periodically make a TCP connection attempt to the specified IP/hostname and port, waiting `interval` amount of time between attempts. -If no hostname is specified, it defaults to "localhost". -The health check status is `success` if the target host accepts the connection attempt, -otherwise the status is `critical`. In the case of a hostname that -resolves to both IPv4 and IPv6 addresses, an attempt is made to both -addresses, and the first successful connection attempt results in a -successful check. This type of check should be preferred over a script that -uses `netcat` or another external process to check a simple socket operation. - -By default, TCP checks are configured with a request timeout equal to 10 seconds. -To configure a custom TCP check timeout value, -specify the `timeout` field in the check definition. - -The following service definition file snippet is an example -of a TCP check definition: - - - -```hcl -check = { - id = "ssh" - name = "SSH TCP on port 22" - tcp = "localhost:22" - interval = "10s" - timeout = "1s" -} -``` - -```json -{ - "check": { - "id": "ssh", - "name": "SSH TCP on port 22", - "tcp": "localhost:22", - "interval": "10s", - "timeout": "1s" - } -} -``` - - - -### UDP check ((#udp-interval)) - -UDP checks periodically direct the Consul agent to send UDP datagrams -to the specified IP/hostname and port, -waiting `interval` amount of time between attempts. -The check status is set to `success` if any response is received from the targeted UDP server. -Any other result sets the status to `critical`. - -By default, UDP checks are configured with a request timeout equal to 10 seconds. -To configure a custom UDP check timeout value, -specify the `timeout` field in the check definition. -If any timeout on read exists, the check is still considered healthy. - -The following service definition file snippet is an example -of a UDP check definition: - - - -```hcl -check = { - id = "dns" - name = "DNS UDP on port 53" - udp = "localhost:53" - interval = "10s" - timeout = "1s" -} -``` - -```json -{ - "check": { - "id": "dns", - "name": "DNS UDP on port 53", - "udp": "localhost:53", - "interval": "10s", - "timeout": "1s" - } -} -``` - - - -### OSService check - -OSService checks periodically direct the Consul agent to monitor the health of a service running on -the host operating system as either a Windows service (Windows) or a SystemD service (Unix). -The check is logged as `healthy` if the service is running. -If it is stopped or not running, the status is `critical`. All other results set -the status to `warning`, which indicates that the check is not reliable because an issue is preventing the check from determining the health of the service. - -The following service definition file snippet is an example -of an OSService check definition: - - - -```hcl -check = { - id = "myco-svctype-svcname-001" - name = "svcname-001 Windows Service Health" - service_id = "flash_pnl_1" - os_service = "myco-svctype-svcname-001" - interval = "10s" -} -``` - -```json -{ - "check": { - "id": "myco-svctype-svcname-001", - "name": "svcname-001 Windows Service Health", - "service_id": "flash_pnl_1", - "os_service": "myco-svctype-svcname-001", - "interval": "10s" - } -} -``` - - - -### Time to live (TTL) check ((#ttl)) - -TTL checks retain their last known state for the specified `ttl` duration. -If the `ttl` duration elapses before a new check update -is provided over the HTTP interface, -the check is set to `critical` state. - -This mechanism relies on the application to directly report its health. -For example, a healthy app can periodically `PUT` a status update to the HTTP endpoint. -Then, if the app is disrupted and unable to perform this update -before the TTL expires, the health check enters the `critical` state. -The endpoints used to update health information for a given check are: [pass](/api-docs/agent/check#ttl-check-pass), -[warn](/api-docs/agent/check#ttl-check-warn), [fail](/api-docs/agent/check#ttl-check-fail), -and [update](/api-docs/agent/check#ttl-check-update). TTL checks also persist their -last known status to disk. This persistence allows the Consul agent to restore the last known -status of the check across agent restarts. Persisted check status is valid through the -end of the TTL from the time of the last check. - -To manually mark a service unhealthy, -it is far more convenient to use the maintenance mode -[CLI command](/commands/maint) or -[HTTP API endpoint](/api-docs/agent#enable-maintenance-mode) -rather than a TTL health check with arbitrarily high `ttl`. - -The following service definition file snippet is an example -of a TTL check definition: - - - -```hcl -check = { - id = "web-app" - name = "Web App Status" - notes = "Web app does a curl internally every 10 seconds" - ttl = "30s" -} -``` - -```json -{ - "check": { - "id": "web-app", - "name": "Web App Status", - "notes": "Web app does a curl internally every 10 seconds", - "ttl": "30s" - } -} -``` - - - -### Docker check ((#docker-interval)) - -These checks depend on periodically invoking an external application that -is packaged within a Docker Container. The application is triggered within the running -container through the Docker Exec API. We expect that the Consul agent user has access -to either the Docker HTTP API or the unix socket. Consul uses `$DOCKER_HOST` to -determine the Docker API endpoint. The application is expected to run, perform a health -check of the service running inside the container, and exit with an appropriate exit code. -The check should be paired with an invocation interval. The shell on which the check -has to be performed is configurable, making it possible to run containers which -have different shells on the same host. -The output of a Docker check is limited to 4KB. -Larger outputs are truncated. -The agent must be configured with [`enable_script_checks`](/docs/agent/config/cli-flags#_enable_script_checks) -set to `true` in order to enable Docker health checks. - -The following service definition file snippet is an example -of a Docker check definition: - - - -```hcl -check = { - id = "mem-util" - name = "Memory utilization" - docker_container_id = "f972c95ebf0e" - shell = "/bin/bash" - args = ["/usr/local/bin/check_mem.py"] - interval = "10s" -} -``` - -```json -{ - "check": { - "id": "mem-util", - "name": "Memory utilization", - "docker_container_id": "f972c95ebf0e", - "shell": "/bin/bash", - "args": ["/usr/local/bin/check_mem.py"], - "interval": "10s" - } -} -``` - - - -### gRPC check ((##grpc-interval)) - -gRPC checks are intended for applications that support the standard -[gRPC health checking protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md). -The state of the check will be updated by periodically probing the configured endpoint, -waiting `interval` amount of time between attempts. - -By default, gRPC checks are configured with a timeout equal to 10 seconds. -To configure a custom Docker check timeout value, -specify the `timeout` field in the check definition. - -gRPC checks default to not using TLS. -To enable TLS, set `grpc_use_tls` in the check definition. -If TLS is enabled, then by default, a valid TLS certificate is expected. -Certificate verification can be turned off by setting the -`tls_skip_verify` field to `true` in the check definition. -To check on a specific service instead of the whole gRPC server, add the service identifier after the `gRPC` check's endpoint in the following format `/:service_identifier`. - -The following service definition file snippet is an example -of a gRPC check for a whole application: - - - -```hcl -check = { - id = "mem-util" - name = "Service health status" - grpc = "127.0.0.1:12345" - grpc_use_tls = true - interval = "10s" -} -``` - -```json -{ - "check": { - "id": "mem-util", - "name": "Service health status", - "grpc": "127.0.0.1:12345", - "grpc_use_tls": true, - "interval": "10s" - } -} -``` - - - -The following service definition file snippet is an example -of a gRPC check for the specific `my_service` service - - - -```hcl -check = { - id = "mem-util" - name = "Service health status" - grpc = "127.0.0.1:12345/my_service" - grpc_use_tls = true - interval = "10s" -} -``` - -```json -{ - "check": { - "id": "mem-util", - "name": "Service health status", - "grpc": "127.0.0.1:12345/my_service", - "grpc_use_tls": true, - "interval": "10s" - } -} -``` - - - -### H2ping check ((#h2ping-interval)) - -H2ping checks test an endpoint that uses http2 by connecting to the endpoint -and sending a ping frame, waiting `interval` amount of time between attempts. -If the ping is successful within a specified timeout, -then the check status is set to `success`. - -By default, h2ping checks are configured with a request timeout equal to 10 seconds. -To configure a custom h2ping check timeout value, -specify the `timeout` field in the check definition. - -TLS is enabled by default. -To disable TLS and use h2c, set `h2ping_use_tls` to `false`. -If TLS is not disabled, a valid certificate is required unless `tls_skip_verify` is set to `true`. - -The following service definition file snippet is an example -of an h2ping check definition: - - - -```hcl -check = { - id = "h2ping-check" - name = "h2ping" - h2ping = "localhost:22222" - interval = "10s" - h2ping_use_tls = false -} -``` - -```json -{ - "check": { - "id": "h2ping-check", - "name": "h2ping", - "h2ping": "localhost:22222", - "interval": "10s", - "h2ping_use_tls": false - } -} -``` - - - -### Alias check - -These checks alias the health state of another registered -node or service. The state of the check updates asynchronously, but is -nearly instant. For aliased services on the same agent, the local state is monitored -and no additional network resources are consumed. For other services and nodes, -the check maintains a blocking query over the agent's connection with a current -server and allows stale requests. If there are any errors in watching the aliased -node or service, the check state is set to `critical`. -For the blocking query, the check uses the ACL token set on the service or check definition. -If no ACL token is set in the service or check definition, -the blocking query uses the agent's default ACL token -([`acl.tokens.default`](/docs/agent/config/config-files#acl_tokens_default)). - -~> **Configuration info**: The alias check configuration expects the alias to be -registered on the same agent as the one you are aliasing. If the service is -not registered with the same agent, `"alias_node": ""` must also be -specified. When using `alias_node`, if no service is specified, the check will -alias the health of the node. If a service is specified, the check will alias -the specified service on this particular node. - -The following service definition file snippet is an example -of an alias check for a local service: - - - -```hcl -check = { - id = "web-alias" - alias_service = "web" -} -``` - -```json -{ - "check": { - "id": "web-alias", - "alias_service": "web" - } -} -``` - - - -## Check definition - -This section covers some of the most common options for check definitions. -For a complete list of all check options, refer to the -[Register Check HTTP API endpoint documentation](/api-docs/agent/check#json-request-body-schema). - --> **Casing for check options:** - The correct casing for an option depends on whether the check is defined in - a service definition file or an HTTP API JSON request body. - For example, the option `deregister_critical_service_after` in a service - definition file is instead named `DeregisterCriticalServiceAfter` in an - HTTP API JSON request body. - -#### General options - -- `name` `(string: )` - Specifies the name of the check. - -- `id` `(string: "")` - Specifies a unique ID for this check on this node. - - If unspecified, Consul defines the check id by: - - If the check definition is embedded within a service definition file, - a unique check id is auto-generated. - - Otherwise, the `id` is set to the value of `name`. - If names might conflict, you must provide unique IDs to avoid - overwriting existing checks with the same id on this node. - -- `interval` `(string: )` - Specifies - the frequency at which to run this check. - Required for all check types except TTL and alias checks. - - The value is parsed by Go's `time` package, and has the following - [formatting specification](https://golang.org/pkg/time/#ParseDuration): - - > A duration string is a possibly signed sequence of decimal numbers, each with - > optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". - > Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - -- `service_id` `(string: )` - Specifies - the ID of a service instance to associate this check with. - That service instance must be on this node. - If not specified, this check is treated as a node-level check. - For more information, refer to the - [service-bound checks](#service-bound-checks) section. - -- `status` `(string: "")` - Specifies the initial status of the health check as - "critical" (default), "warning", or "passing". For more details, refer to - the [initial health check status](#initial-health-check-status) section. - - -> **Health defaults to critical:** If health status it not initially specified, - it defaults to "critical" to protect against including a service - in discovery results before it is ready. - -- `deregister_critical_service_after` `(string: "")` - If specified, - the associated service and all its checks are deregistered - after this check is in the critical state for more than the specified value. - The value has the same formatting specification as the [`interval`](#interval) field. - - The minimum timeout is 1 minute, - and the process that reaps critical services runs every 30 seconds, - so it may take slightly longer than the configured timeout to trigger the deregistration. - This field should generally be configured with a timeout that's significantly longer than - any expected recoverable outage for the given service. - -- `notes` `(string: "")` - Provides a human-readable description of the check. - This field is opaque to Consul and can be used however is useful to the user. - For example, it could be used to describe the current state of the check. - -- `token` `(string: "")` - Specifies an ACL token used for any interaction - with the catalog for the check, including - [anti-entropy syncs](/docs/architecture/anti-entropy) and deregistration. - - For alias checks, this token is used if a remote blocking query is necessary to watch the state of the aliased node or service. - -#### Success/failures before passing/warning/critical - -To prevent flapping health checks and limit the load they cause on the cluster, -a health check may be configured to become passing/warning/critical only after a -specified number of consecutive checks return as passing/critical. -The status does not transition states until the configured threshold is reached. - -- `success_before_passing` - Number of consecutive successful results required - before check status transitions to passing. Defaults to `0`. Added in Consul 1.7.0. - -- `failures_before_warning` - Number of consecutive unsuccessful results required - before check status transitions to warning. Defaults to the same value as that of - `failures_before_critical` to maintain the expected behavior of not changing the - status of service checks to `warning` before `critical` unless configured to do so. - Values higher than `failures_before_critical` are invalid. Added in Consul 1.11.0. - -- `failures_before_critical` - Number of consecutive unsuccessful results required - before check status transitions to critical. Defaults to `0`. Added in Consul 1.7.0. - -This feature is available for all check types except TTL and alias checks. -By default, both passing and critical thresholds are set to 0 so the check -status always reflects the last check result. - - - -```hcl -checks = [ - { - name = "HTTP TCP on port 80" - tcp = "localhost:80" - interval = "10s" - timeout = "1s" - success_before_passing = 3 - failures_before_warning = 1 - failures_before_critical = 3 - } -] -``` - -```json -{ - "checks": [ - { - "name": "HTTP TCP on port 80", - "tcp": "localhost:80", - "interval": "10s", - "timeout": "1s", - "success_before_passing": 3, - "failures_before_warning": 1, - "failures_before_critical": 3 - } - ] -} -``` - - - -## Initial health check status - -By default, when checks are registered against a Consul agent, the state is set -immediately to "critical". This is useful to prevent services from being -registered as "passing" and entering the service pool before they are confirmed -to be healthy. In certain cases, it may be desirable to specify the initial -state of a health check. This can be done by specifying the `status` field in a -health check definition, like so: - - - -```hcl -check = { - id = "mem" - args = ["/bin/check_mem", "-limit", "256MB"] - interval = "10s" - status = "passing" -} -``` - -```json -{ - "check": { - "id": "mem", - "args": ["/bin/check_mem", "-limit", "256MB"], - "interval": "10s", - "status": "passing" - } -} -``` - - - -The above service definition would cause the new "mem" check to be -registered with its initial state set to "passing". - -## Service-bound checks - -Health checks may optionally be bound to a specific service. This ensures -that the status of the health check will only affect the health status of the -given service instead of the entire node. Service-bound health checks may be -provided by adding a `service_id` field to a check configuration: - - - -```hcl -check = { - id = "web-app" - name = "Web App Status" - service_id = "web-app" - ttl = "30s" -} -``` - -```json -{ - "check": { - "id": "web-app", - "name": "Web App Status", - "service_id": "web-app", - "ttl": "30s" - } -} -``` - - - -In the above configuration, if the web-app health check begins failing, it will -only affect the availability of the web-app service. All other services -provided by the node will remain unchanged. - -## Agent certificates for TLS checks - -The [enable_agent_tls_for_checks](/docs/agent/config/config-files#enable_agent_tls_for_checks) -agent configuration option can be utilized to have HTTP or gRPC health checks -to use the agent's credentials when configured for TLS. - -## Multiple check definitions - -Multiple check definitions can be defined using the `checks` (plural) -key in your configuration file. - - - -```hcl -checks = [ - { - id = "chk1" - name = "mem" - args = ["/bin/check_mem", "-limit", "256MB"] - interval = "5s" - }, - { - id = "chk2" - name = "/health" - http = "http://localhost:5000/health" - interval = "15s" - }, - { - id = "chk3" - name = "cpu" - args = ["/bin/check_cpu"] - interval = "10s" - }, - ... -] -``` - -```json -{ - "checks": [ - { - "id": "chk1", - "name": "mem", - "args": ["/bin/check_mem", "-limit", "256MB"], - "interval": "5s" - }, - { - "id": "chk2", - "name": "/health", - "http": "http://localhost:5000/health", - "interval": "15s" - }, - { - "id": "chk3", - "name": "cpu", - "args": ["/bin/check_cpu"], - "interval": "10s" - }, - ... - ] -} -``` - - \ No newline at end of file diff --git a/website/content/docs/discovery/dns.mdx b/website/content/docs/discovery/dns.mdx deleted file mode 100644 index 29f3e9645ba8..000000000000 --- a/website/content/docs/discovery/dns.mdx +++ /dev/null @@ -1,586 +0,0 @@ ---- -layout: docs -page_title: Find services with DNS -description: >- - For service discovery use cases, Domain Name Service (DNS) is the main interface to look up, query, and address Consul nodes and services. Learn how a Consul DNS lookup can help you find services by tag, name, namespace, partition, datacenter, or domain. ---- - -# Query services with DNS - -One of the primary query interfaces for Consul is DNS. -The DNS interface allows applications to make use of service -discovery without any high-touch integration with Consul. - -For example, instead of making HTTP API requests to Consul, -a host can use the DNS server directly via name lookups -like `redis.service.us-east-1.consul`. This query automatically -translates to a lookup of nodes that provide the `redis` service, -are located in the `us-east-1` datacenter, and have no failing health checks. -It's that simple! - -There are a number of configuration options that are important for the DNS interface, -specifically [`client_addr`](/docs/agent/config/config-files#client_addr),[`ports.dns`](/docs/agent/config/config-files#dns_port), -[`recursors`](/docs/agent/config/config-files#recursors),[`domain`](/docs/agent/config/config-files#domain), -[`alt_domain`](/docs/agent/config/config-files#alt_domain), and [`dns_config`](/docs/agent/config/config-files#dns_config). -By default, Consul will listen on 127.0.0.1:8600 for DNS queries in the `consul.` -domain, without support for further DNS recursion. Please consult the -[documentation on configuration options](/docs/agent/config), -specifically the configuration items linked above, for more details. - -There are a few ways to use the DNS interface. One option is to use a custom -DNS resolver library and point it at Consul. Another option is to set Consul -as the DNS server for a node and provide a -[`recursors`](/docs/agent/config/config-files#recursors) configuration so that non-Consul queries -can also be resolved. The last method is to forward all queries for the "consul." -domain to a Consul agent from the existing DNS server. Review the -[DNS Forwarding tutorial](https://learn.hashicorp.com/tutorials/consul/dns-forwarding?utm_source=docs) for examples. - -You can experiment with Consul's DNS server on the command line using tools such as `dig`: - -```shell-session -$ dig @127.0.0.1 -p 8600 redis.service.dc1.consul. ANY -``` - --> **Note:** In DNS, all queries are case-insensitive. A lookup of `PostgreSQL.node.dc1.consul` will find all nodes named `postgresql`. - -## Node Lookups - -To resolve names, Consul relies on a very specific format for queries. -There are fundamentally two types of queries: node lookups and service lookups. -A node lookup, a simple query for the address of a named node, looks like this: - -```text -.node[.]. -``` - -For example, if we have a `foo` node with default settings, we could -look for `foo.node.dc1.consul.` The datacenter is an optional part of -the FQDN: if not provided, it defaults to the datacenter of the agent. -If we know `foo` is running in the same datacenter as our local agent, -we can instead use `foo.node.consul.` This convention allows for terse -syntax where appropriate while supporting queries of nodes in remote -datacenters as necessary. - -For a node lookup, the only records returned are A and AAAA records -containing the IP address, and TXT records containing the -`node_meta` values of the node. - -```shell-session -$ dig @127.0.0.1 -p 8600 foo.node.consul ANY - -; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 -p 8600 foo.node.consul ANY -; (1 server found) -;; global options: +cmd -;; Got answer: -;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24355 -;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0 -;; WARNING: recursion requested but not available - -;; QUESTION SECTION: -;foo.node.consul. IN ANY - -;; ANSWER SECTION: -foo.node.consul. 0 IN A 10.1.10.12 -foo.node.consul. 0 IN TXT "meta_key=meta_value" -foo.node.consul. 0 IN TXT "value only" - - -;; AUTHORITY SECTION: -consul. 0 IN SOA ns.consul. postmaster.consul. 1392836399 3600 600 86400 0 -``` - -By default the TXT records value will match the node's metadata key-value -pairs according to [RFC1464](https://www.ietf.org/rfc/rfc1464.txt). -Alternatively, the TXT record will only include the node's metadata value when the -node's metadata key starts with `rfc1035-`. - - -### Node Lookups for Consul Enterprise - -Consul nodes exist at the admin partition level within a datacenter. -By default, the partition and datacenter used in a [node lookup](#node-lookups) are -the partition and datacenter of the Consul agent that received the DNS query. - -Use the following query format to specify a partition for a node lookup: -```text -.node..ap..dc. -``` - -Consul server agents are in the `default` partition. -If DNS queries are addressed to Consul server agents, -node lookups to non-`default` partitions must explicitly specify -the partition of the target node. - -## Service Lookups - -A service lookup is used to query for service providers. Service queries support -two lookup methods: standard and strict [RFC 2782](https://tools.ietf.org/html/rfc2782). - -By default, SRV weights are all set at 1, but changing weights is supported using the -`Weights` attribute of the [service definition](/docs/discovery/services). - -Note that DNS is limited in size per request, even when performing DNS TCP -queries. - -For services having many instances (more than 500), it might not be possible to -retrieve the complete list of instances for the service. - -When DNS SRV response are sent, order is randomized, but weights are not -taken into account. In the case of truncation different clients using weighted SRV -responses will have partial and inconsistent views of instances weights so the -request distribution could be skewed from the intended weights. In that case, -it is recommended to use the HTTP API to retrieve the list of nodes. - -### Standard Lookup - -The format of a standard service lookup is: - -```text -[.].service[.]. -``` - -The `tag` is optional, and, as with node lookups, the `datacenter` is as -well. If no tag is provided, no filtering is done on tag. If no -datacenter is provided, the datacenter of this Consul agent is assumed. - -If we want to find any redis service providers in our local datacenter, -we could query `redis.service.consul.` If we want to find the PostgreSQL -primary in a particular datacenter, we could query -`primary.postgresql.service.dc2.consul.` - -The DNS query system makes use of health check information to prevent routing -to unhealthy nodes. When a service query is made, any services failing their health -check or failing a node system check will be omitted from the results. To allow -for simple load balancing, the set of nodes returned is also randomized each time. -These mechanisms make it easy to use DNS along with application-level retries -as the foundation for an auto-healing service oriented architecture. - -For standard services queries, both A and SRV records are supported. SRV records -provide the port that a service is registered on, enabling clients to avoid relying -on well-known ports. SRV records are only served if the client specifically requests -them, like so: - -```shell-session -$ dig @127.0.0.1 -p 8600 consul.service.consul SRV - -; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 -p 8600 consul.service.consul ANY -; (1 server found) -;; global options: +cmd -;; Got answer: -;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50483 -;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 1, ADDITIONAL: 1 -;; WARNING: recursion requested but not available - -;; QUESTION SECTION: -;consul.service.consul. IN SRV - -;; ANSWER SECTION: -consul.service.consul. 0 IN SRV 1 1 8300 foobar.node.dc1.consul. - -;; ADDITIONAL SECTION: -foobar.node.dc1.consul. 0 IN A 10.1.10.12 -``` - -### RFC 2782 Lookup - -Valid formats for RFC 2782 SRV lookups depend on -whether you want to filter results based on a service tag: - -- No filtering on service tag: - - ```text - _._tcp[.service][.]. - ``` - -- Filtering on service tag specified in the RFC 2782 protocol field: - - ```text - _._[.service][.]. - ``` - -Per [RFC 2782](https://tools.ietf.org/html/rfc2782), SRV queries must -prepend an underscore (`_`) to the `service` and `protocol` values in a query to -prevent DNS collisions. -To perform no tag-based filtering, specify `tcp` in the RFC 2782 protocol field. -To filter results on a service tag, specify the tag in the RFC 2782 protocol field. - -Other than the query format and default `tcp` protocol/tag value, the behavior -of the RFC style lookup is the same as the standard style of lookup. - -If you registered the service `rabbitmq` on port 5672 and tagged it with `amqp`, -you could make an RFC 2782 query for its SRV record as `_rabbitmq._amqp.service.consul`: - -```shell-session -$ dig @127.0.0.1 -p 8600 _rabbitmq._amqp.service.consul SRV - -; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 -p 8600 _rabbitmq._amqp.service.consul ANY -; (1 server found) -;; global options: +cmd -;; Got answer: -;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 52838 -;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 -;; WARNING: recursion requested but not available - -;; QUESTION SECTION: -;_rabbitmq._amqp.service.consul. IN SRV - -;; ANSWER SECTION: -_rabbitmq._amqp.service.consul. 0 IN SRV 1 1 5672 rabbitmq.node1.dc1.consul. - -;; ADDITIONAL SECTION: -rabbitmq.node1.dc1.consul. 0 IN A 10.1.11.20 -``` - -Again, note that the SRV record returns the port of the service as well as its IP. - -#### SRV response for hosts in the .addr subdomain - -If a service registered to Consul has an explicit IP [`address`](/api-docs/agent/service#address) -or tagged address(es) defined on the service registration, the hostname returned -in the target field of the answer section for the DNS SRV query for the service -will be in the format of `.addr..consul`. - - - - - -In the example below, the `rabbitmq` service has been registered with an explicit -IPv4 address of `192.0.2.10`. - - - -```hcl -node_name = "node1" - -services { - name = "rabbitmq" - address = "192.0.2.10" - port = 5672 -} -``` - -```json -{ - "node_name": "node1", - "services": [ - { - "name": "rabbitmq", - "address": "192.0.2.10", - "port": 5672 - } - ] -} -``` - - - -When performing an SRV query for this service, the SRV response contains a single -record with a hostname in the format of `.addr..consul`. - -```shell-session -$ dig @127.0.0.1 -p 8600 -t srv _rabbitmq._tcp.service.consul +short -1 1 5672 c000020a.addr.dc1.consul. -``` - -In this example, the hex-encoded IP from the returned hostname is `c000020a`. -Converting each hex octet to decimal reveals the IP address that was specified -in the service registration. - -```shell-session -$ echo -n "c000020a" | perl -ne 'printf("%vd\n", pack("H*", $_))' -192.0.2.10 -``` - - - - - -In the example below, the `rabbitmq` service has been registered with an explicit -IPv6 address of `2001:db8:1:2:cafe::1337`. - - - -```hcl -node_name = "node1" - -services { - name = "rabbitmq" - address = "2001:db8:1:2:cafe::1337" - port = 5672 -} -``` - -```json -{ - "node_name": "node1", - "services": [ - { - "name": "rabbitmq", - "address": "2001:db8:1:2:cafe::1337", - "port": 5672 - } - ] -} -``` - - - -When performing an SRV query for this service, the SRV response contains a single -record with a hostname in the format of `.addr..consul`. - -```shell-session -$ dig @127.0.0.1 -p 8600 -t srv _rabbitmq._tcp.service.consul +short -1 1 5672 20010db800010002cafe000000001337.addr.dc1.consul. -``` - -In this example, the hex-encoded IP from the returned hostname is -`20010db800010002cafe000000001337`. This is the fully expanded IPv6 address with -colon separators removed. - -The following command re-adds the colon separators to display the fully expanded -IPv6 address that was specified in the service registration. - -```shell-session -$ echo -n "20010db800010002cafe000000001337" | perl -ne 'printf join(":", unpack("(A4)*", $_))."\n"' -2001:0db8:0001:0002:cafe:0000:0000:1337 -``` - - - - - -### Service Lookups for Consul Enterprise - -By default, all service lookups use the `default` namespace -within the partition and datacenter of the Consul agent that received the DNS query. -To lookup services in another namespace, partition, and/or datacenter, -use the [canonical format](#canonical-format). - -Consul server agents are in the `default` partition. -If DNS queries are addressed to Consul server agents, -service lookups to non-`default` partitions must explicitly specify -the partition of the target service. - -To lookup services imported from a cluster peer, -refer to [service virtual IP lookups for Consul Enterprise](#service-virtual-ip-lookups-for-consul-enterprise) instead. - -#### Canonical format - -Use the following query format to specify namespace, partition, and/or datacenter -for `.service`, `.connect`, `.virtual`, and `.ingress` service lookup types. -All three fields (`namespace`, `partition`, `datacenter`) are optional. -```text -[.].service[..ns][..ap][..dc] -``` - -#### Alternative formats for specifying namespace - -Though the [canonical format](#canonical-format) is recommended for readability, -you can use the following query formats specify namespace but not partition: - -- Specify both namespace and datacenter: - - ```text - [.].service... - ``` - -- **Deprecated in Consul 1.11:** - Specify namespace without a datacenter, - which requires that DNS queries are addressed to a Consul agent with - [`dns_config.prefer_namespace`](/docs/agent/config/config-files#dns_prefer_namespace) - set to `true`: - - ```text - [.].service.. - ``` - -### Prepared Query Lookups - -The format of a prepared query lookup is: - -```text -.query[.]. -``` - -The `datacenter` is optional, and if not provided, the datacenter of this Consul -agent is assumed. - -The `query or name` is the ID or given name of an existing -[Prepared Query](/api-docs/query). These behave like standard service -queries but provide a much richer set of features, such as filtering by multiple -tags and automatically failing over to look for services in remote datacenters if -no healthy nodes are available in the local datacenter. Consul 0.6.4 and later also -added support for [prepared query templates](/api-docs/query#prepared-query-templates) -which can match names using a prefix match, allowing one template to apply to -potentially many services. - -To allow for simple load balancing, the set of nodes returned is randomized each time. -Both A and SRV records are supported. SRV records provide the port that a service is -registered on, enabling clients to avoid relying on well-known ports. SRV records are -only served if the client specifically requests them. - -### Connect-Capable Service Lookups - -To find Connect-capable services: - -```text -.connect. -``` - -This will find all [Connect-capable](/docs/connect) -endpoints for the given `service`. A Connect-capable endpoint may be -both a proxy for a service or a natively integrated Connect application. -The DNS interface does not differentiate the two. - -Most services will use a [proxy](/docs/connect/proxies) that handles -service discovery automatically and therefore won't use this DNS format. -This DNS format is primarily useful for [Connect-native](/docs/connect/native) -applications. - -This endpoint currently only finds services within the same datacenter -and doesn't support tags. This DNS interface will be expanded over time. -If you need more complex behavior, please use the -[catalog API](/api-docs/catalog). - -### Service Virtual IP Lookups - -To find the unique virtual IP allocated for a service: - -```text -.virtual[.]. -``` - -This will return the unique virtual IP for any [Connect-capable](/docs/connect) -service. Each Connect service has a virtual IP assigned to it by Consul - this is used -by sidecar proxies for the [Transparent Proxy](/docs/connect/transparent-proxy) feature. -The peer name is an optional part of the FQDN, and it is used to query for the virtual IP -of a service imported from that peer. - -The virtual IP is also added to the service's [Tagged Addresses](/docs/discovery/services#tagged-addresses) -under the `consul-virtual` tag. - -#### Service Virtual IP Lookups for Consul Enterprise - -By default, a service virtual IP lookup uses the `default` namespace -within the partition and datacenter of the Consul agent that received the DNS query. - -To lookup services imported from a cluster peered partition or open-source datacenter, -specify the namespace and peer name in the lookup: -```text -.virtual[.].. -``` - -To lookup services not imported from a cluster peer, -refer to [service lookups for Consul Enterprise](#service-lookups-for-consul-enterprise) instead. - -### Ingress Service Lookups - -To find ingress-enabled services: - -```text -.ingress. -``` - -This will find all [ingress gateway](/docs/connect/gateways/ingress-gateway) -endpoints for the given `service`. - -This endpoint currently only finds services within the same datacenter -and doesn't support tags. This DNS interface will be expanded over time. -If you need more complex behavior, please use the -[catalog API](/api-docs/catalog). - -### UDP Based DNS Queries - -When the DNS query is performed using UDP, Consul will truncate the results -without setting the truncate bit. This is to prevent a redundant lookup over -TCP that generates additional load. If the lookup is done over TCP, the results -are not truncated. - -## Alternative Domain - -By default, Consul responds to DNS queries in the `consul` domain, -but you can set a specific domain for responding to DNS queries by configuring the [`domain`](/docs/agent/config/config-files#domain) parameter. - -In some instances, Consul may need to respond to queries in more than one domain, -such as during a DNS migration or to distinguish between internal and external queries. - -Consul versions 1.5.2+ can be configured to respond to DNS queries on an alternative domain -through the [`alt_domain`](/docs/agent/config/config-files#alt_domain) agent configuration -option. As of Consul versions 1.11.0+, Consul's DNS response will use the same domain as was used in the query; -in prior versions, the response may use the primary [`domain`](/docs/agent/config/config-files#domain) no matter which -domain was used in the query. - -In the following example, the `alt_domain` parameter is set to `test-domain`: - -```hcl - alt_domain = "test-domain" -``` - -```shell-session -$ dig @127.0.0.1 -p 8600 consul.service.test-domain SRV -``` - -The following responses are returned: - -``` -;; QUESTION SECTION: -;consul.service.test-domain. IN SRV - -;; ANSWER SECTION: -consul.service.test-domain. 0 IN SRV 1 1 8300 machine.node.dc1.test-domain. - -;; ADDITIONAL SECTION: -machine.node.dc1.test-domain. 0 IN A 127.0.0.1 -machine.node.dc1.test-domain. 0 IN TXT "consul-network-segment=" -``` - --> **PTR queries:** Responses to PTR queries (`.in-addr.arpa.`) will always use the -[primary domain](/docs/agent/config/config-files#domain) (not the alternative domain), -as there is no way for the query to specify a domain. - -## Caching - -By default, all DNS results served by Consul set a 0 TTL value. This disables -caching of DNS results. However, there are many situations in which caching is -desirable for performance and scalability. This is discussed more in the tutorial -for [DNS caching](https://learn.hashicorp.com/tutorials/consul/dns-caching). - -## WAN Address Translation - -By default, Consul DNS queries will return a node's local address, even when -being queried from a remote datacenter. If you need to use a different address -to reach a node from outside its datacenter, you can configure this behavior -using the [`advertise-wan`](/docs/agent/config/cli-flags#_advertise-wan) and -[`translate_wan_addrs`](/docs/agent/config/config-files#translate_wan_addrs) configuration -options. - -## DNS with ACLs - -In order to use the DNS interface when -[Access Control Lists (ACLs)](/docs/security/acl) -are enabled, you must first create ACL tokens with the necessary policies. - -Consul agents resolve DNS requests using one of the preconfigured tokens below, -listed in order of precedence: - -1. The agent's [`default` token](/docs/agent/config/config-files#acl_tokens_default). -2. The built-in [`anonymous` token](/docs/security/acl/acl-tokens#built-in-tokens). - Because the anonymous token is used when any request is made to Consul without - explicitly specifying a token, production deployments should not apply policies - needed for DNS to this token. - -Consul will either accept or deny the request depending on whether the token -has the appropriate authorization. The following table describes the available -DNS lookups and required policies when ACLs are enabled: - -| Lookup | Type | Description | ACLs Required | -| ------------------------------------------------------------------------------ | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `*.node.consul` | [Node](#node-lookups) | Allow resolving DNS requests for the target node (i.e., `.node.consul`) | [`node:read`](/docs/security/acl/acl-rules#node-rules) | -| `*.service.consul`, `*.connect.consul`, `*.ingress.consul`, `*.virtual.consul` | [Service: standard](#service-lookups) | Allow resolving DNS requests for target service (e.g., `.service.consul`) instances running on ACL-authorized nodes | [`service:read`](/docs/security/acl/acl-rules#service-rules), [`node:read`](/docs/security/acl/acl-rules#node-rules) | -| `*.query.consul` | [Service: prepared query](#prepared-query-lookups) | Allow resolving DNS requests for [service instances specified](/api-docs/query#service-1) by the target prepared query (i.e., `.query.consul`) running on ACL-authorized nodes | [`query:read`](/docs/security/acl/acl-rules#prepared-query-rules), [`service:read`](/docs/security/acl/acl-rules#service-rules), [`node:read`](/docs/security/acl/acl-rules#node-rules) | - -For guidance on how to configure an appropriate token for DNS, refer to the -securing Consul with ACLs guides for: - -- [Production Environments](https://learn.hashicorp.com/tutorials/consul/access-control-setup-production#token-for-dns) -- [Development Environments](https://learn.hashicorp.com/tutorials/consul/access-control-setup?utm_source=docs#enable-acls-on-consul-clients) diff --git a/website/content/docs/discovery/services.mdx b/website/content/docs/discovery/services.mdx deleted file mode 100644 index 2a3df359ea7b..000000000000 --- a/website/content/docs/discovery/services.mdx +++ /dev/null @@ -1,701 +0,0 @@ ---- -layout: docs -page_title: Register Services with Service Definitions -description: >- - Define and register services and their health checks with Consul to make a service available for service discovery or service mesh access. Learn how to format service definitions with this reference page and sample code. ---- - -# Register Services with Service Definitions - -One of the main goals of service discovery is to provide a catalog of available -services. To that end, the agent provides a simple service definition format -to declare the availability of a service and to potentially associate it with -a health check. A health check associated with a service is considered to be an -application-level check. Define services in a configuration file or add it at -runtime using the HTTP interface. - -Complete the [Getting Started tutorials](https://learn.hashicorp.com/tutorials/consul/get-started-service-discovery?utm_source=docs) to get hands-on experience registering a simple service with a health check on your local machine. - -## Service Definition - -Configure a service by providing the service definition to the agent. You can -either specify the configuration file using the `-config-file` option, or specify -the directory containing the service definition file with the `-config-dir` option. -Consul can load service definitions saved as `.json` or `.hcl` files. - -Send a `SIGHUP` to the running agent or use [`consul reload`](/commands/reload) to check for new service definitions or to -update existing services. Alternatively, the service can be [registered dynamically](/api-docs/agent/service#register-service) -using the [HTTP API](/api-docs). - -A service definition contains a set of parameters that specify various aspects of the service, including how it is discovered by other services in the network. -All possible parameters are included in the following example, but only the top-level `service` parameter and its `name` parameter child are required by default. - - - -```hcl -service { - name = "redis" - id = "redis" - port = 80 - tags = ["primary"] - - meta = { - custom_meta_key = "custom_meta_value" - } - - tagged_addresses = { - lan = { - address = "192.168.0.55" - port = 8000 - } - - wan = { - address = "198.18.0.23" - port = 80 - } - } - - port = 8000 - socket_path = "/tmp/redis.sock" - enable_tag_override = false - - checks = [ - { - args = ["/usr/local/bin/check_redis.py"] - interval = "10s" - } - ] - - kind = "connect-proxy" - proxy_destination = "redis" - - proxy = { - destination_service_name = "redis" - destination_service_id = "redis1" - local_service_address = "127.0.0.1" - local_service_port = 9090 - local_service_socket_path = "/tmp/redis.sock" - mode = "transparent" - - transparent_proxy { - outbound_listener_port = 22500 - } - - mesh_gateway = { - mode = "local" - } - - expose = { - checks = true - - paths = [ - { - path = "/healthz" - local_path_port = 8080 - listener_port = 21500 - protocol = "http2" - } - ] - } - } - - connect = { - native = false - } - - weights = { - passing = 5 - warning = 1 - } - - token = "233b604b-b92e-48c8-a253-5f11514e4b50" - namespace = "foo" -} -``` - -```json -{ - "service": { - "id": "redis", - "name": "redis", - "tags": ["primary"], - "address": "", - "meta": { - "meta": "for my service" - }, - "tagged_addresses": { - "lan": { - "address": "192.168.0.55", - "port": 8000, - }, - "wan": { - "address": "198.18.0.23", - "port": 80 - } - }, - "port": 8000, - "socket_path": "/tmp/redis.sock", - "enable_tag_override": false, - "checks": [ - { - "args": ["/usr/local/bin/check_redis.py"], - "interval": "10s" - } - ], - "kind": "connect-proxy", - "proxy_destination": "redis", // Deprecated - "proxy": { - "destination_service_name": "redis", - "destination_service_id": "redis1", - "local_service_address": "127.0.0.1", - "local_service_port": 9090, - "local_service_socket_path": "/tmp/redis.sock", - "mode": "transparent", - "transparent_proxy": { - "outbound_listener_port": 22500 - }, - "config": {}, - "upstreams": [], - "mesh_gateway": { - "mode": "local" - }, - "expose": { - "checks": true, - "paths": [ - { - "path": "/healthz", - "local_path_port": 8080, - "listener_port": 21500, - "protocol": "http2" - } - ] - } - }, - "connect": { - "native": false, - "sidecar_service": {} - "proxy": { // Deprecated - "command": [], - "config": {} - } - }, - "weights": { - "passing": 5, - "warning": 1 - }, - "token": "233b604b-b92e-48c8-a253-5f11514e4b50", - "namespace": "foo" - } -} -``` - - - -The following table describes the available parameters for service definitions. - -### `service` - -This is the root-level parameter that defines the service. You can specify the parameters to configure the service. - -| Parameter | Description | Default | Required | -| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ---------------------------- | -| `id` | String value that specifies the service ID.

    If not specified, the value of the `name` field will be used.

    Services must have unique IDs per node, so you should specify unique values if the default `name` will conflict with other services.

    | Value of the `name` parameter | Optional | -| `name` | Specifies the name of the service.
    The value for this parameter is used as the ID if the `id` parameter is not specified.
    We recommend using valid DNS labels for service definition names for compatibility with external DNSs. | None | Required | -| `tags` | List of string values that can be used to add service-level labels.
    For example, you can define tags that distinguish between `primary` and `secondary` nodes or service versions.
    We recommend using valid DNS labels for service definition IDs for compatibility with external DNSs.
    Tag values are opaque to Consul.
    | None | Optional | -| `address` | String value that specifies a service-specific IP address or hostname.
    If no value is specified, the IP address of the agent node is used by default.
    There is no service-side validation of this parameter. | IP address of the agent node | Optional | -| `meta` | Object that defines a map of the max 64 key/value pairs.
    The meta object has the same limitations as the node meta object in the node definition.
    Meta data can be retrieved per individual instance of the service. All instances of a given service have their own copy of the meta data.
    See [Adding Meta Data](#adding-meta-data) for supported parameters.
    | None | Optional | -| `tagged_addresses` | Tagged addresses are additional addresses that may be defined for a node or service. See [Tagged Addresses](#tagged-addresses) for details. | None | Optional | -| `port` | Integer value that specifies a service-specific port number. The port number should be specified when the `address` parameter is defined to improve service discoverability. | Optional | -| `socket_path` | String value that specifies the path to the service socket.
    Specify this parameter to expose the service to the mesh if the service listens on a Unix Domain socket. | None | Optional | -| `enable_tag_override` | Boolean value that determines if the anti-entropy feature for the service is enabled.
    If set to `true`, then external agents can update this service in the catalog and modify the tags.
    Subsequent local sync operations by this agent will ignore the updated tags.
    This parameter only applies to the locally-registered service. If multiple nodes register the same service, the `enable_tag_override` configuration, and all other service configuration items, operate independently.
    Updating the tags for services registered on one node is independent from the same service (by name) registered on another node.
    See [anti-entropy syncs](/docs/architecture/anti-entropy) for additional information.
    | False | Optional | -| `checks` | Array of objects that define health checks for the service. See [Health Checks](#health-checks) for details. | None | Optional | -| `kind` | String value that identifies the service as a Connect proxy. See [Connect](#connect) for details. | None | Optional | -| `proxy_destination` | String value that specifies the _name_ of the destination service that the service currently being configured proxies to.
    This parameter is deprecated. Use `proxy.destination_service` instead.
    See [Connect](#connect) for additional information. | None | Optional | -| `proxy` | Object that defines the destination services that the service currently being configured proxies to. See [Proxy](#proxy) for additional information. | None | Optional | -| `connect` | Object that configures a Consul Connect service mesh connection. See [Connect](#connect) for details. | None | Optional | -| `weights` | Object that configures the weight of the service in terms of its DNS service (SRV) response. See [DNS SRV Weights](#dns-srv-weights) for details. | None | Optional | -| `token` | String value specifying the ACL token to be used to register the service (if the ACL system is enabled). The token is required for the service to interact with the service catalog. See [Security Configurations](#security-configurations) for details. | None | Required if ACLs are enabled | -| `namespace` | String value specifying the Consul Namespace where the service should be registered. See [Security Configurations](#security-configurations) for details. | None | Optional | - -### Adding Meta Data - -You can add semantic meta data to the service using the `meta` parameter. This parameter defines a map of max 64 key/value pairs. You can specify the following parameters to define meta data for the service. - -| Parameter | Description | Default | Required | -| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | -------- | -| `KEY` | String value that adds semantic metadata to the service.
    Keys can only have ASCII characters (`A` - `Z`, `a` - `z`, `0` - `9`, `_`, and `-`).
    Keys can not have special characters.
    Keys are limited to 128 characters.
    Values are limited to 512 characters. | None | Optional | - -### Security Configurations - -If the ACL system is enabled, specify a value for the `token` parameter to provide an ACL token. This token is -used for any interaction with the catalog for the service, including [anti-entropy syncs](/docs/architecture/anti-entropy) and deregistration. - -Services registered in Consul clusters where both [Consul Namespaces](/docs/enterprise/namespaces) -and the ACL system are enabled can be registered to specific namespaces that are associated with -ACL tokens scoped to the namespace. Services registered with a service definition -will not inherit the namespace associated with the ACL token specified in the `token` -field. The `namespace` _and_ the `token` parameters must be included in the service definition for the service to be registered to the -namespace that the ACL token is scoped to. - -### Health Checks - -You can add health checks to your service definition. Health checks perform several safety functions, such as allowing a web balancer to gracefully remove failing nodes and allowing a database -to replace a failed secondary. The health check functionality is strongly integrated into the DNS interface, as well. If a service is failing its health check or a node has any failing system-level check, the DNS interface will omit that -node from any service query. - -The health check name is automatically generated as `service:`. If there are multiple service checks -registered, the ID will be generated as `service::` where -`` is an incrementing number starting from `1`. - -Consul includes several check types with different options. Refer to the [health checks documentation](/docs/discovery/checks) for details. - -### Proxy - -Service definitions allow for an optional proxy registration. Proxies used with Connect -are registered as services in Consul's catalog. -See the [Proxy Service Registration](/docs/connect/registration/service-registration) reference -for the available configuration options. - -### Connect - -The `kind` parameter determines the service's role. Services can be configured to perform several roles, but you must omit the `kind` parameter for typical non-proxy instances. - -The following roles are supported for service entries: - -- `connect-proxy`: Defines the configuration for a connect proxy -- `ingress-gateway`: Defines the configuration for an [ingress gateway](/docs/connect/config-entries/ingress-gateway) -- `mesh-gateway`: Defines the configuration for a [mesh gateway](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters#mesh-gateway-configuration) -- `terminating-gateway`: Defines the configuration for a [terminating gateway](/docs/connect/config-entries/terminating-gateway#terminating-gateway) - -In the service definition example described above, the service is registered as a proxy because the `kind` property is set to `connect-proxy`. -The `proxy` parameter is also required for Connect proxy registrations and is only valid if `kind` is `connect-proxy`. -Refer to the [Proxy Service Registration](/docs/connect/registration/service-registration) documentation for details about this type. - -When the `kind` parameter is set to `connect-proxy`, the only required parameter for the `proxy` configuration is `destination_service_name`. -Refer to the [complete proxy configuration example](/docs/connect/registration/service-registration#complete-configuration-example) for additional information. - -The `connect` field can be specified to configure [Connect](/docs/connect) for a service. This field is available in Consul 1.2.0 and later. The following parameters are available. - -| Parameter | Description | Default | Required | -| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | -------- | -| `native` | Boolean value that advertises the service as [Connect-native](/docs/connect/native).
    If set to `true`, do not configure a `sidecar_service`. | `false` | Optional | -| `sidecar_service` | Object that defines a nested service definition.
    Do not configure if `native` is set to `true`. | See [Sidecar Service Registration](/docs/connect/registration/sidecar-service) for default configurations. | Optional | - --> **Non-service registration roles**: The `kind` values supported for configuration entries are different than what is supported for service registrations. Refer to the [Configuration Entries](/docs/connect/config-entries) documentation for information about non-service registration types. - -#### Deprecated parameters - -Different Consul Connect parameters are supported for different Consul versions. The following table describes changes applicable to service discovery. - -| Parameter | Description | Consul version | Status | -| ------------------- | ---------------------------------------------------------------------------------------------------- | ---------------------------- | --------------------------------------------------------------------------- | -| `proxy_destination` | Specified the proxy destination **in the root level** of the definition file. | 1.2.0 to 1.3.0 | Deprecated since 1.5.0.
    Use `proxy.destination_service_name` instead. | -| `connect.proxy` | Specified "managed" proxies, [which have been deprecated](/docs/connect/proxies/managed-deprecated). | 1.2.0 (beta) to 1.3.0 (beta) | Deprecated. | - -### DNS SRV Weights - -You can configure how the service responds to DNS SRV requests by specifying a set of states/weights in the `weights` field. - -#### `weights` - -When DNS SRV requests are made, the response will include the weights specified for the given state of the service. -This allows some instances to be given higher weight if they have more capacity. It also allows load reduction on -services with checks in `warning` status by giving passing instances a higher weight. - -| Parameter | Description | Default | Required | -| --------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | -------- | -| `STATE` | Integer value indicating its weight. A higher number indicates more weight. | If not specified, the following weights are used:
    `"passing" : 1`
    `"warning" : 1` | Optional | - -If a service is `critical`, it is excluded from DNS responses. -Services with warning checks are included in responses by default, but excluded if the optional param `only_passing = true` -is present in the agent DNS configuration or the `passing` query parameter is used via the API. - -### Enable Tag Override and Anti-Entropy - -Services may also contain a `token` field to provide an ACL token. This token is -used for any interaction with the catalog for the service, including -[anti-entropy syncs](/docs/architecture/anti-entropy) and deregistration. - -You can optionally disable the anti-entropy feature for this service using the -`enable_tag_override` flag. External agents can modify tags on services in the -catalog, so subsequent sync operations can either maintain tag modifications or -revert them. If `enable_tag_override` is set to `TRUE`, the next sync cycle may -revert some service properties, **but** the tags would maintain the updated value. -If `enable_tag_override` is set to `FALSE`, the next sync cycle will revert any -updated service properties, **including** tags, to their original value. - -It's important to note that this applies only to the locally registered -service. If you have multiple nodes all registering the same service -their `enable_tag_override` configuration and all other service -configuration items are independent of one another. Updating the tags -for the service registered on one node is independent of the same -service (by name) registered on another node. If `enable_tag_override` is -not specified the default value is false. See [anti-entropy -syncs](/docs/architecture/anti-entropy) for more info. - -For Consul 0.9.3 and earlier you need to use `enableTagOverride`. Consul 1.0 -supports both `enable_tag_override` and `enableTagOverride` but the latter is -deprecated and has been removed as of Consul 1.1. - -### Tagged Addresses - -Tagged addresses are additional addresses that may be defined for a node or -service. Tagged addresses can be used by remote agents and services as alternative -addresses for communicating with the given node or service. Multiple tagged -addresses may be configured on a node or service. - -The following example describes the syntax for defining a tagged address. - - - -```hcl -service { - name = "redis" - port = 80 - tagged_addresses { - = { - address = "
    " - port = port - } - } -} -``` - -```json -{ - "service": { - "name": "redis", - "port": 80, - "tagged_addresses": { - "": { - "address": "
    ", - "port": port - } - } - } -} -``` - - - -The following table provides an overview of the various tagged address types supported by Consul. - -| Type | Description | Tags | -| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------- | -| LAN | LAN addresses are intended to be directly accessible only from services within the same Consul data center. See [LAN tags](#lan-tags) for details. | `lan`
    `lan_ipv4`
    `lan_ipv6` | -| Virtual | Virtual tagged addresses are logical address types that can be configured on [Connect](/docs/connect)-enabled services. The virtual address provides a fixed IP address that can be used by downstream services when connecting to an upstream service. See [Virtual tags](#virtual-tags) for details. | `virtual` | -| WAN | Define a WAN address for the service or node when it should be accessed at an alternate address by services in a remote datacenter. See [WAN tags](#wan-tags) for details. | `wan`
    `wan_ipv4`
    `wan_ipv6` | - -#### LAN tags - -- `lan` - The IPv4 LAN address at which the node or service is accessible. -- `lan_ipv4` - The IPv4 LAN address at which the node or service is accessible. -- `lan_ipv6` - The IPv6 LAN address at which the node or service is accessible. - - - - - -```hcl -service { - name = "redis" - address = "192.0.2.10" - port = 80 - tagged_addresses { - lan = { - address = "192.0.2.10" - port = 80 - } - lan_ipv4 = { - address = "192.0.2.10" - port = 80 - } - lan_ipv6 = { - address = "2001:db8:1:2:cafe::1337" - port = 80 - } - } -} -``` - - - - - -```json -{ - "service": { - "name": "redis", - "address": "192.0.2.10", - "port": 80, - "tagged_addresses": { - "lan": { - "address": "192.0.2.10", - "port": 80 - }, - "lan_ipv4": { - "address": "192.0.2.10", - "port": 80 - }, - "lan_ipv6": { - "address": "2001:db8:1:2:cafe::1337", - "port": 80 - } - } - } -} -``` - - - - -#### Virtual tags - -Connections to virtual addresses are load balanced across available instances of a service, provided the following conditions are satisfied: - -1. [Transparent proxy](/docs/connect/transparent-proxy) is enabled for the - downstream and upstream services. -1. The upstream service is not configured for individual instances to be - [dialed directly](/docs/connect/config-entries/service-defaults#dialeddirectly). - -Virtual addresses are not required to be routable IPs within the -network. They are strictly a control plane construct used to provide a fixed -address for the instances of a given logical service. Egress connections from -the proxy to an upstream service will be destined to the IP address of an -individual service instance, not the virtual address of the logical service. - -Use the following address tag to specify the logical address at which the -service can be reached by other services in the mesh. - -- `virtual` - The virtual IP address at which a logical service is reachable. - - - - - -```hcl -service { - name = "redis" - address = "192.0.2.10" - port = 80 - tagged_addresses { - virtual = { - address = "203.0.113.50" - port = 80 - } - } -} -``` - - - - - -```json -{ - "service": { - "name": "redis", - "address": "192.0.2.10", - "port": 80, - "tagged_addresses": { - "virtual": { - "address": "203.0.113.50", - "port": 80 - } - } - } -} -``` - - - - -#### WAN tags - -One or more of the following address tags can be configured for a node or service -to advertise how it should be accessed over the WAN. - -- `wan` - The IPv4 WAN address at which the node or service is accessible when - being dialed from a remote data center. -- `wan_ipv4` - The IPv4 WAN address at which the node or service is accessible - when being dialed from a remote data center. -- `wan_ipv6` - The IPv6 WAN address at which the node or service is accessible - when being dialed from a remote data center. - - - - - -```hcl -service { - name = "redis" - address = "192.0.2.10" - port = 80 - tagged_addresses { - wan = { - address = "198.51.100.200" - port = 80 - } - wan_ipv4 = { - address = "198.51.100.200" - port = 80 - } - wan_ipv6 = { - address = "2001:db8:5:6:1337::1eaf" - port = 80 - } - } -} -``` - - - - - -```json -{ - "service": { - "name": "redis", - "address": "192.0.2.10", - "port": 80, - "tagged_addresses": { - "wan": { - "address": "198.51.100.200", - "port": 80 - }, - "wan_ipv4": { - "address": "198.51.100.200", - "port": 80 - }, - "wan_ipv6": { - "address": "2001:db8:5:6:1337::1eaf", - "port": 80 - } - } - } -} -``` - - - - -## Multiple Service Definitions - -Multiple services definitions can be provided at once when registering services -via the agent configuration by using the plural `services` key (registering -multiple services in this manner is not supported using the HTTP API). - - - - - -```hcl -services { - id = "red0" - name = "redis" - tags = [ - "primary" - ] - address = "" - port = 6000 - checks = [ - { - args = ["/bin/check_redis", "-p", "6000"] - interval = "5s" - timeout = "20s" - } - ] -} -services { - id = "red1" - name = "redis" - tags = [ - "delayed", - "secondary" - ] - address = "" - port = 7000 - checks = [ - { - args = ["/bin/check_redis", "-p", "7000"] - interval = "30s" - timeout = "60s" - } - ] -} - -``` - - - - - -```json -{ - "services": [ - { - "id": "red0", - "name": "redis", - "tags": [ - "primary" - ], - "address": "", - "port": 6000, - "checks": [ - { - "args": ["/bin/check_redis", "-p", "6000"], - "interval": "5s", - "timeout": "20s" - } - ] - }, - { - "id": "red1", - "name": "redis", - "tags": [ - "delayed", - "secondary" - ], - "address": "", - "port": 7000, - "checks": [ - { - "args": ["/bin/check_redis", "-p", "7000"], - "interval": "30s", - "timeout": "60s" - } - ] - }, - ... - ] -} -``` - - - - -## Service and Tag Names with DNS - -Consul exposes service definitions and tags over the [DNS](/docs/discovery/dns) -interface. DNS queries have a strict set of allowed characters and a -well-defined format that Consul cannot override. While it is possible to -register services or tags with names that don't match the conventions, those -services and tags will not be discoverable via the DNS interface. It is -recommended to always use DNS-compliant service and tag names. - -DNS-compliant service and tag names may contain any alpha-numeric characters, as -well as dashes. Dots are not supported because Consul internally uses them to -delimit service tags. - -## Service Definition Parameter Case - -For historical reasons Consul's API uses `CamelCased` parameter names in -responses, however its configuration file uses `snake_case` for both HCL and -JSON representations. For this reason the registration _HTTP APIs_ accept both -name styles for service definition parameters although APIs will return the -listings using `CamelCase`. - -Note though that **all config file formats require -`snake_case` fields**. We always document service definition examples using -`snake_case` and JSON since this format works in both config files and API -calls. diff --git a/website/content/docs/ecs/compatibility.mdx b/website/content/docs/ecs/compatibility.mdx index 76bb2b4beb84..2b6716cdb879 100644 --- a/website/content/docs/ecs/compatibility.mdx +++ b/website/content/docs/ecs/compatibility.mdx @@ -7,15 +7,17 @@ description: >- # Consul on AWS Elastic Container Service (ECS) Compatability Matrix -For every release of Consul on ECS, the `consul-ecs` binary and `consul-ecs` Terraform module are updated. The versions of the Terraform module and binary are tightly coupled. For example, `consul-ecs` 0.4.1 binary must use the `consul-ecs` 0.4.1 Terraform module. +For every release of Consul on ECS, the `consul-ecs` binary and `consul-ecs` Terraform module are updated. The versions of the Terraform module and binary are tightly coupled. For example, `consul-ecs` 0.5.2 binary must use the `consul-ecs` 0.5.2 Terraform module. ## Supported Consul versions | Consul Version | Compatible consul-ecs Versions | | -------------- | ------------------------------- | -| 1.12.x | 0.5.x | -| 1.11.x | 0.3.0, 0.4.x | -| 1.10.x | 0.2.x | +| 1.14.x | 0.5.2+ | +| 1.13.x | 0.5.2+ | +| 1.12.x | 0.5.x | +| 1.11.x | 0.3.0, 0.4.x | +| 1.10.x | 0.2.x | ## Supported Envoy versions diff --git a/website/content/docs/ecs/configuration-reference.mdx b/website/content/docs/ecs/configuration-reference.mdx index 4264fb8f9e45..fed887bc835d 100644 --- a/website/content/docs/ecs/configuration-reference.mdx +++ b/website/content/docs/ecs/configuration-reference.mdx @@ -185,7 +185,7 @@ Defines the Consul checks for the service. Each `check` object may contain the f | `method` | `string` | optional | Specifies the HTTP method to be used for an HTTP check. When no value is specified, `GET` is used. | | `name` | `string` | optional | The name of the check. | | `notes` | `string` | optional | Specifies arbitrary information for humans. This is not used by Consul internally. | -| `os_service` | `string` | optional | Specifies the name of a service on which to perform an [OS service check](/docs/discovery/checks#osservice-check). The check runs according the frequency specified in the `interval` parameter. | +| `os_service` | `string` | optional | Specifies the name of a service on which to perform an [OS service check](/consul/docs/services/usage/checks#osservice-check). The check runs according the frequency specified in the `interval` parameter. | | `status` | `string` | optional | Specifies the initial status the health check. Must be one of `passing`, `warning`, `critical`, `maintenance`, or `null`. | | `successBeforePassing` | `integer` | optional | Specifies the number of consecutive successful results required before check status transitions to passing. | | `tcp` | `string` | optional | Specifies this is a TCP check. Must be an IP/hostname plus port to which a TCP connection is made every `interval`. | diff --git a/website/content/docs/ecs/index.mdx b/website/content/docs/ecs/index.mdx index 8dc22fccca48..edf50846fcb8 100644 --- a/website/content/docs/ecs/index.mdx +++ b/website/content/docs/ecs/index.mdx @@ -30,8 +30,7 @@ For a detailed architecture overview, see the [Architecture](/docs/ecs/architect There are several ways to get started with Consul with ECS. -- The [Serverless Consul Service Mesh with ECS and HCP](https://learn.hashicorp.com/tutorials/cloud/consul-ecs-hcp?utm_source=docs) learn guide shows how to use Terraform to run Consul service mesh applications on ECS with managed Consul servers running in HashiCorp Cloud Platform (HCP). -- The [Service Mesh with ECS and Consul on EC2](https://learn.hashicorp.com/tutorials/consul/consul-ecs-ec2?utm_source=docs) learn guide shows how to use Terraform to run Consul service mesh applications on ECS with Consul servers running on EC2 instances. +- The [Integrate your AWS ECS services into Consul service mesh](/consul/tutorials/cloud-integrations/consul-ecs) tutorial shows how to use Terraform to run Consul service mesh applications on ECS with self-managed Consul or HCP-managed Consul. - The [Consul with Dev Server on Fargate](https://registry.terraform.io/modules/hashicorp/consul-ecs/aws/latest/examples/dev-server-fargate) example installation deploys a sample application in ECS using the Fargate launch type. - The [Consul with Dev Server on EC2](https://registry.terraform.io/modules/hashicorp/consul-ecs/aws/latest/examples/dev-server-ec2) example installation deploys a sample application in ECS using the EC2 launch type. diff --git a/website/content/docs/ecs/manual/install.mdx b/website/content/docs/ecs/manual/install.mdx index ffc4111fa2ab..5ce30be96511 100644 --- a/website/content/docs/ecs/manual/install.mdx +++ b/website/content/docs/ecs/manual/install.mdx @@ -373,11 +373,11 @@ configuration to a shared volume. ### `CONSUL_ECS_CONFIG_JSON` -Configuration is passed to the `consul-ecs` binary in JSON format using the `CONSUL_ECS_CONFIG_JSON` environment variable. +Consul uses the `CONSUL_ECS_CONFIG_JSON` environment variable to passed configurations to the `consul-ecs` binary in JSON format. -The following is an example of the configuration that might be used for a service named `example-client-app` with one upstream -service name `example-server-app`. The `proxy` and `service` blocks include information used by `consul-ecs-mesh-init` to perform -[service registration](/docs/discovery/services) with Consul during task startup. The same configuration format is used for +The following example configures a service named `example-client-app` with one upstream +service name `example-server-app`. The `proxy` and `service` blocks include information used by `consul-ecs-mesh-init` to register the service with Consul during task start up. +The same configuration format is used for the `consul-ecs-health-sync` container. ```json @@ -409,7 +409,7 @@ the `consul-ecs-health-sync` container. | `proxy.upstreams` | list | The upstream services that your application calls over the service mesh, if any. The `destinationName` and `localBindPort` fields are required. | | `service.name` | string | The name used to register this service into the Consul service catalog. | | `service.port` | integer | The port your application listens on. Set to `0` if your application does not listen on any port. | -| `service.checks` | list | Consul [checks](/docs/discovery/checks) to include so that Consul can run health checks against your application. | +| `service.checks` | list | Consul [checks](/consul/docs/services/usage/checks) to include so that Consul can run health checks against your application. | See the [Configuration Reference](/docs/ecs/configuration-reference) for a complete reference of fields. diff --git a/website/content/docs/ecs/terraform/install.mdx b/website/content/docs/ecs/terraform/install.mdx index cfb3e41d0f68..2c2c87e08fe3 100644 --- a/website/content/docs/ecs/terraform/install.mdx +++ b/website/content/docs/ecs/terraform/install.mdx @@ -138,7 +138,7 @@ in their [`network_configuration`](https://registry.terraform.io/providers/hashi Add the `gateway-task` to your Terraform configuration if you want to deploy a mesh gateway. Mesh gateways enable service to service communication across the WAN, as well as federate service mesh traffic across Consul admin partitions and Consul datacenters over the WAN. Refer to the following documentation to learn more about mesh gateways: * [WAN Federation via Mesh Gateways](/docs/connect/gateways/mesh-gateway/wan-federation-via-mesh-gateways) -* [Service-to-service Traffic Across Datacenters](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters). +* [Service-to-service Traffic Across Datacenters](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-wan-datacenters). You must add and configure a `gateway-task` for each Consul datacenter in your network. You must also enable TLS and gossip encryption on all server and client agents in all data centers per the [Requirements](#requirements). Mesh gateways operate by sniffing and extracting the server name indication (SNI) header from the service mesh session and routing the connection to the appropriate destination based on the server name requested. diff --git a/website/content/docs/ecs/terraform/secure-configuration.mdx b/website/content/docs/ecs/terraform/secure-configuration.mdx index 979f98edc30e..2aedb6a0e028 100644 --- a/website/content/docs/ecs/terraform/secure-configuration.mdx +++ b/website/content/docs/ecs/terraform/secure-configuration.mdx @@ -108,8 +108,9 @@ The following table describes the required input variables for the `acl-controll | `name_prefix` | string | AWS resources created by the `acl-controller` module will include this prefix in the resource name. | -If you are using Consul Enterprise, see Admin Partitions and Namespaces for -additional configuration required to support Consul Enterprise on ECS. + +If you are using Consul Enterprise, see the [Admin Partitions and Namespaces requirements documentation](/consul/docs/ecs/requirements) for additional configuration required to support Consul Enterprise on ECS. + ## Deploy your services diff --git a/website/content/docs/enterprise/admin-partitions.mdx b/website/content/docs/enterprise/admin-partitions.mdx index 9154faff3dc0..b54c3b0a4e9a 100644 --- a/website/content/docs/enterprise/admin-partitions.mdx +++ b/website/content/docs/enterprise/admin-partitions.mdx @@ -21,7 +21,9 @@ This topic provides and overview of admin partitions, which are entities that de Admin partitions exist a level above namespaces in the identity hierarchy. They contain one or more namespaces and allow multiple independent tenants to share a Consul server cluster. As a result, admin partitions enable you to define administrative and communication boundaries between services managed by separate teams or belonging to separate stakeholders. They can also segment production and non-production services within the Consul deployment. --> **Preexisting resource nodes and namespaces**: Admin partitions were introduced in Consul 1.11. Resource nodes were not namespaced prior to 1.11. After upgrading to Consul 1.11 or later, all resource nodes will be namespaced. +As of Consul v1.11, every _datacenter_ contains a single administrative partition named `default` when created. With Consul Enterprise, operators have the option of creating multiple partitions within a single datacenter. + +-> **Preexisting nodes**: Admin partitions were introduced in Consul 1.11. Nodes existed in global scope prior to 1.11. After upgrading to Consul 1.11 or later, all nodes will be scoped to an admin partition, which will be the `default` partition when initially upgrading an existing deployment or for OSS versions. There are tutorials available to help you get started with admin partitions. @@ -59,7 +61,13 @@ The partition in which [`proxy-defaults`](/docs/connect/config-entries/proxy-def ### Cross-partition Networking -You can configure services to be discoverable by downstream services in any partition within the datacenter. Specify the upstream services that you want to be available for discovery by configuring the `exported-services` configuration entry in the partition where the services are registered. Refer to the [`exported-services` documentation](/docs/connect/config-entries/exported-services) for details. Additionally, the requests made by downstream applications must have the correct DNS name for the Virtual IP Service lookup to occur. Service Virtual IP lookups allow for communications across Admin Partitions when using Transparent Proxy. Refer to the [Service Virtual IP Lookups for Consul Enterprise](/docs/discovery/dns#service-virtual-ip-lookups-for-consul-enterprise) for additional information. +You can configure services to be discoverable by downstream services in any partition within the datacenter. Specify the upstream services that you want to be available for discovery by configuring the `exported-services` configuration entry in the partition where the services are registered. Refer to the [`exported-services` documentation](/consul/docs/connect/config-entries/exported-services) for details. Additionally, the requests made by downstream applications must have the correct DNS name for the Virtual IP Service lookup to occur. Service Virtual IP lookups allow for communications across Admin Partitions when using Transparent Proxy. Refer to the [Service Virtual IP Lookups for Consul Enterprise](/consul/docs/services/discovery/dns-static-lookups#service-virtual-ip-lookups-for-consul-enterprise) for additional information. + +### Cluster Peering + +You can use [cluster peering](/docs/connect/cluster-peering/) between two admin partitions to connect clusters owned by different operators. Without Consul Enterprise, cluster peering is limited to the `default` partitions in each datacenter. Enterprise users can [create and manage cluster peering connections](/docs/connect/cluster-peering/create-manage-peering) between any two admin partitions as long as the partitions are in separate datacenters. It is not possible to establish cluster peering connections between two partitions in a single datacenter. + +To use mesh gateways with admin partitions and cluster peering, refer to [Mesh Gateways between Peered Clusters](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-peers). ## Requirements @@ -129,7 +137,7 @@ The following procedure will result in an admin partition in each Kubernetes clu Verify that your Consul deployment meets the [Kubernetes Requirements](#kubernetes-requirements) before proceeding. -1. Verify that your VPC is configured to enable connectivity between the pods running Consul clients and servers. Refer to your virtual cloud provider's documentation for instructions on configuring network connectivity. +1. Verify that your VPC is configured to enable connectivity between the pods running workloads and Consul servers. Refer to your virtual cloud provider's documentation for instructions on configuring network connectivity. 1. Set environment variables to use with shell commands. ```shell-session @@ -146,7 +154,7 @@ Verify that your Consul deployment meets the [Kubernetes Requirements](#kubernet $ kubectl create secret --context ${SERVER_CONTEXT} --namespace consul generic license --from-file=key=./path/to/license.hclic ``` -1. Create the license secret in the workload client cluster. This step must be repeated for every additional workload client cluster. +1. Create the license secret in the non-default partition cluster for your workloads. This step must be repeated for every additional non-default partition cluster. ```shell-session $ kubectl create --context ${CLIENT_CONTEXT} ns consul @@ -172,7 +180,7 @@ Verify that your Consul deployment meets the [Kubernetes Requirements](#kubernet enableConsulNamespaces: true tls: enabled: true - image: hashicorp/consul-enterprise:1.13.2-ent + image: hashicorp/consul-enterprise:1.14.0-ent adminPartitions: enabled: true acls: @@ -180,20 +188,8 @@ Verify that your Consul deployment meets the [Kubernetes Requirements](#kubernet enterpriseLicense: secretName: license secretKey: key - server: - exposeGossipAndRPCPorts: true - connectInject: - enabled: true - consulNamespaces: - mirroringK8S: true - controller: - enabled: true meshGateway: enabled: true - replicas: 1 - dns: - enabled: true - enableRedirection: true ``` @@ -204,66 +200,66 @@ Verify that your Consul deployment meets the [Kubernetes Requirements](#kubernet 1. Install the Consul server(s) using the values file created in the previous step: ```shell-session - $ helm install ${HELM_RELEASE_SERVER} hashicorp/consul --version "0.49.0" --create-namespace --namespace consul --values server.yaml + $ helm install ${HELM_RELEASE_SERVER} hashicorp/consul --version "1.0.0" --create-namespace --namespace consul --values server.yaml ``` -1. After the server starts, get the external IP address for partition service so that it can be added to the client configuration. The IP address is used to bootstrap connectivity between servers and clients. +1. After the server starts, get the external IP address for partition service so that it can be added to the client configuration. The IP address is used to bootstrap connectivity between servers and workload pods on the non-default partition cluster. ```shell-session $ kubectl get services --selector="app=consul,component=server" --namespace consul --output jsonpath="{range .items[*]}{@.status.loadBalancer.ingress[*].ip}{end}" 34.135.103.67 ``` -1. Get the Kubernetes authentication method URL for the workload cluster: +1. Get the Kubernetes authentication method URL for the non-default partition cluster running your workloads: ```shell-session $ kubectl config view --output "jsonpath={.clusters[?(@.name=='${CLIENT_CONTEXT}')].cluster.server}" ``` - Use the IP address printed to the console to configure the `k8sAuthMethodHost` parameter in the workload configuration file for your client nodes. + Use the IP address printed to the console to configure the `k8sAuthMethodHost` parameter in the workload configuration file for your non-default partition cluster running your workloads. -1. Copy the server certificate to the workload cluster. +1. Copy the server certificate to the non-default partition cluster running your workloads. ```shell-session $ kubectl get secret ${HELM_RELEASE_SERVER}-consul-ca-cert --context ${SERVER_CONTEXT} -n consul --output yaml | kubectl apply --namespace consul --context ${CLIENT_CONTEXT} --filename - ``` -1. Copy the server key to the workload cluster. +1. Copy the server key to the non-default partition cluster running your workloads. ```shell-session $ kubectl get secret ${HELM_RELEASE_SERVER}-consul-ca-key --context ${SERVER_CONTEXT} --namespace consul --output yaml | kubectl apply --namespace consul --context ${CLIENT_CONTEXT} --filename - ``` -1. If ACLs were enabled in the server configuration values file, copy the token to the workload cluster. +1. If ACLs were enabled in the server configuration values file, copy the token to the non-default partition cluster running your workloads. ```shell-session $ kubectl get secret ${HELM_RELEASE_SERVER}-consul-partitions-acl-token --context ${SERVER_CONTEXT} --namespace consul --output yaml | kubectl apply --namespace consul --context ${CLIENT_CONTEXT} --filename - ``` -#### Install the workload client cluster +#### Install on the non-default partition clusters running workloads -1. Switch to the workload client clusters: +1. Switch to the workload non-default partition clusters running your workloads: ```shell-session $ kubectl config use-context ${CLIENT_CONTEXT} ``` -1. Create the workload configuration for client nodes in your cluster. Create a configuration for each admin partition. +1. Create a configuration for each non-default admin partition. In the following example, the external IP address and the Kubernetes authentication method IP address from the previous steps have been applied. Also, ensure a unique `global.name` value is assigned. - + ```yaml global: - name: client + name: consul enabled: false enableConsulNamespaces: true - image: hashicorp/consul-enterprise:1.13.2-ent + image: hashicorp/consul-enterprise:1.14.0-ent adminPartitions: enabled: true - name: clients + name: partition-workload tls: enabled: true caCert: @@ -285,31 +281,17 @@ Verify that your Consul deployment meets the [Kubernetes Requirements](#kubernet hosts: [34.135.103.67] # See step 4 from `Install Consul server cluster` tlsServerName: server.dc1.consul k8sAuthMethodHost: https://104.154.156.146 # See step 5 from `Install Consul server cluster` - client: - enabled: true - exposeGossipPorts: true - join: [34.135.103.67] # See step 4 from `Install Consul server cluster` - connectInject: - enabled: true - consulNamespaces: - mirroringK8S: true - controller: - enabled: true meshGateway: enabled: true - replicas: 1 - dns: - enabled: true - enableRedirection: true ``` -1. Install the workload client clusters: +1. Install the non-default partition clusters running your workloads: ```shell-session - $ helm install ${HELM_RELEASE_CLIENT} hashicorp/consul --version "0.49.0" --create-namespace --namespace consul --values client.yaml + $ helm install ${HELM_RELEASE_CLIENT} hashicorp/consul --version "1.0.0" --create-namespace --namespace consul --values client.yaml ``` ### Verifying the Deployment diff --git a/website/content/docs/enterprise/audit-logging.mdx b/website/content/docs/enterprise/audit-logging.mdx index 0d7c37fd3138..d2ed6796931a 100644 --- a/website/content/docs/enterprise/audit-logging.mdx +++ b/website/content/docs/enterprise/audit-logging.mdx @@ -82,6 +82,21 @@ audit { } } ``` + +```yaml +server: + auditLogs: + enabled: true + sinks: + - name: My Sink + type: file + format: json + path: /tmp/audit.json + delivery_guarantee: best-effort + rotate_duration: 24h + rotate_max_files: 15 + rotate_bytes: 25165824 +``` @@ -122,6 +137,18 @@ audit { } ``` +```yaml +server: + auditLogs: + enabled: true + sinks: + - name: My Sink + type: file + format: json + path: /dev/stdout + delivery_guarantee: best-effort +``` + diff --git a/website/content/docs/enterprise/index.mdx b/website/content/docs/enterprise/index.mdx index f3ef52d61e6d..56008ce7d83c 100644 --- a/website/content/docs/enterprise/index.mdx +++ b/website/content/docs/enterprise/index.mdx @@ -33,7 +33,7 @@ The following features are [available in several forms of Consul Enterprise](#co ### Complex Network Topology Support - [Network Areas](/docs/enterprise/federation): Support complex network topologies between federated Consul datacenters with pairwise federation rather than full mesh federation -- [Network Segments](/docs/enterprise/network-segments): Support complex network topologies within a Consul datacenter by enforcing boundaries in Consul client gossip traffic +- [Network Segments](/docs/enterprise/network-segments/network-segments-overview): Support complex network topologies within a Consul datacenter by enforcing boundaries in Consul client gossip traffic ### Governance - [OIDC Auth Method](/docs/security/acl/auth-methods/oidc): Manage user access to Consul through an OIDC identity provider instead of Consul ACL tokens directly @@ -59,31 +59,92 @@ To access Consul Enterprise in a self-managed installation, [apply a purchased license](/docs/enterprise/license/overview) to the Consul Enterprise binary that grants access to the desired features. -You can also try out Consul Enterprise before purchasing by -[requesting a 30-day trial license](https://www.hashicorp.com/products/consul/trial). +Contact your [HashiCorp Support contact](https://support.hashicorp.com/) for a development license. ## Consul Enterprise Feature Availability -Consul Enterprise is offered in several forms that provide a different mix of enterprise features. -Choose the form that best suits the needs of your organization. +The Consul Enterprise features that are available depend on your license and the runtimes you use in your deployment. -Available enterprise features per Consul form and license include: +### Feature availability by license + +Available Enterprise features per Consul form and license include: | Feature | [HashiCorp Cloud Platform (HCP) Consul] | [Consul Enterprise] | Legacy Consul Enterprise (module-based) | | -------------------------------------------------------- | --------------------------------------- | ------------------- | ------------------------------------------------- | | Consul servers as a managed service | Yes | No (self-managed) | No (self-managed) | | [Admin Partitions](/docs/enterprise/admin-partitions) | All tiers | Yes | With Governance and Policy module | -| [Namespaces](/docs/enterprise/namespaces) | All tiers | Yes | With Governance and Policy module | -| [Automated Backups](/docs/enterprise/backups) | All tiers | Yes | Yes | -| [Redundancy Zones](/docs/enterprise/redundancy) | Not applicable | Yes | With Global Visibility, Routing, and Scale module | -| [Read Replicas](/docs/enterprise/read-scale) | No | Yes | With Global Visibility, Routing, and Scale module | -| [Automated Upgrades](/docs/enterprise/upgrades) | All tiers | Yes | Yes | +| [Audit Logging](/docs/enterprise/audit-logging) | Standard tier and above | Yes | With Governance and Policy module | +| [Automated Server Backups](/docs/enterprise/backups) | All tiers | Yes | Yes | +| [Automated Server Upgrades](/docs/enterprise/upgrades) | All tiers | Yes | Yes | | [Consul-Terraform-Sync Enterprise](/docs/nia/enterprise) | All tiers | Yes | Yes | +| [Enhanced Read Scalability](/docs/enterprise/read-scale) | No | Yes | With Global Visibility, Routing, and Scale module | +| [Namespaces](/docs/enterprise/namespaces) | All tiers | Yes | With Governance and Policy module | | [Network Areas](/docs/enterprise/federation) | No | Yes | With Global Visibility, Routing, and Scale module | -| [Network Segments](/docs/enterprise/network-segments) | No | Yes | With Global Visibility, Routing, and Scale module | -| [OIDC Auth Method](/docs/security/acl/auth-methods/oidc) | No | Yes | Yes | -| [Audit Logging](/docs/enterprise/audit-logging) | Standard tier and above | Yes | With Governance and Policy module | +| [Network Segments](/docs/enterprise/network-segments/network-segments-overview) | No | Yes | With Global Visibility, Routing, and Scale module | +| [OIDC Auth Method](/docs/security/acl/auth-methods/oidc) | No | Yes | Yes | +| [Redundancy Zones](/docs/enterprise/redundancy) | Not applicable | Yes | With Global Visibility, Routing, and Scale module | | [Sentinel for KV](/docs/enterprise/sentinel) | All tiers | Yes | With Governance and Policy module | [HashiCorp Cloud Platform (HCP) Consul]: https://cloud.hashicorp.com/products/consul [Consul Enterprise]: https://www.hashicorp.com/products/consul/ + +### Feature availability by runtime + +Consul Enterprise feature availability can change depending on your server and client agent runtimes. + + + + + +| Enterprise Feature | VM Client | K8s Client | ECS Client | +| ----------------------------------------------------------------------- | :-------: | :--------: | :--------: | +| [Admin Partitions](/consul/docs/enterprise/admin-partitions) | ✅ | ✅ | ✅ | +| [Audit Logging](/consul/docs/enterprise/audit-logging) | ✅ | ✅ | ✅ | +| [Automated Server Backups](/consul/docs/enterprise/backups) | ✅ | ✅ | ✅ | +| [Automated Server Upgrades](/consul/docs/enterprise/upgrades) | ✅ | ✅ | ✅ | +| [Enhanced Read Scalability](/consul/docs/enterprise/read-scale) | ✅ | ✅ | ✅ | +| [Namespaces](/consul/docs/enterprise/namespaces) | ✅ | ✅ | ✅ | +| [Network Areas](/consul/docs/enterprise/federation) | ✅ | ✅ | ✅ | +| [Network Segments](/consul/docs/enterprise/network-segments/network-segments-overview) | ✅ | ❌ | ❌ | +| [OIDC Auth Method](/consul/docs/security/acl/auth-methods/oidc) | ✅ | ✅ | ✅ | +| [Redundancy Zones](/consul/docs/enterprise/redundancy) | ✅ | ✅ | ✅ | +| [Sentinel ](/consul/docs/enterprise/sentinel) | ✅ | ✅ | ✅ | + + + + + +| Enterprise Feature | VM Client | K8s Client | ECS Client | +| ----------------------------------------------------------------------- | :-------: | :--------: | :--------: | +| [Admin Partitions](/consul/docs/enterprise/admin-partitions) | ✅ | ✅ | ✅ | +| [Audit Logging](/consul/docs/enterprise/audit-logging) | ✅ | ✅ | ✅ | +| [Automated Server Backups](/consul/docs/enterprise/backups) | ✅ | ✅ | ✅ | +| [Automated Server Upgrades](/consul/docs/enterprise/upgrades) | ❌ | ❌ | ❌ | +| [Enhanced Read Scalability](/consul/docs/enterprise/read-scale) | ❌ | ❌ | ❌ | +| [Namespaces](/consul/docs/enterprise/namespaces) | ✅ | ✅ | ✅ | +| [Network Areas](/consul/docs/enterprise/federation) | ✅ | ✅ | ✅ | +| [Network Segments](/consul/docs/enterprise/network-segments/network-segments-overview) | ❌ | ❌ | ❌ | +| [OIDC Auth Method](/consul/docs/security/acl/auth-methods/oidc) | ✅ | ✅ | ✅ | +| [Redundancy Zones](/consul/docs/enterprise/redundancy) | ❌ | ❌ | ❌ | +| [Sentinel ](/consul/docs/enterprise/sentinel) | ✅ | ✅ | ✅ | + + + + + +| Enterprise Feature | VM Client | K8s Client | ECS Client | +| ----------------------------------------------------------------------- | :-------: | :--------: | :--------: | +| [Admin Partitions](/consul/docs/enterprise/admin-partitions) | ✅ | ✅ | ✅ | +| [Audit Logging](/consul/docs/enterprise/audit-logging) | ✅ | ✅ | ✅ | +| [Automated Server Backups](/consul/docs/enterprise/backups) | ✅ | ✅ | ✅ | +| [Automated Server Upgrades](/consul/docs/enterprise/upgrades) | ✅ | ✅ | ✅ | +| [Enhanced Read Scalability](/consul/docs/enterprise/read-scale) | ❌ | ❌ | ❌ | +| [Namespaces](/consul/docs/enterprise/namespaces) | ✅ | ✅ | ✅ | +| [Network Areas](/consul/docs/enterprise/federation) | ❌ | ❌ | ❌ | +| [Network Segments](/consul/docs/enterprise/network-segments/network-segments-overview) | ❌ | ❌ | ❌ | +| [OIDC Auth Method](/consul/docs/security/acl/auth-methods/oidc) | ❌ | ❌ | ❌ | +| [Redundancy Zones](/consul/docs/enterprise/redundancy) | n/a | n/a | n/a | +| [Sentinel ](/consul/docs/enterprise/sentinel) | ✅ | ✅ | ✅ | + + + \ No newline at end of file diff --git a/website/content/docs/enterprise/license/faq.mdx b/website/content/docs/enterprise/license/faq.mdx index b0a0c004edd9..6bfd2b6e6733 100644 --- a/website/content/docs/enterprise/license/faq.mdx +++ b/website/content/docs/enterprise/license/faq.mdx @@ -72,14 +72,19 @@ Consul will only cease operation after license *termination*, which occurs 10 ye after license expiration and is defined in [`termination_time`](/api-docs/operator/license#getting-the-consul-license). +~> **Starting with Consul 1.14, and patch releases 1.13.3 and 1.12.6, Consul will support non-terminating licenses**: + Please contact your support representative for more details on non-terminating licenses. + An expired license will not allow Consul versions released after the expiration date to run. + It will not be possible to upgrade to a new version of Consul released after license expiration. + ## Q: Does this affect client agents? There are upgrade requirements that affect Consul Enterprise clients. -Please review the [upgrade requirements](faq#q-what-are-the-upgrade-requirements) documentation. +Please review the [upgrade requirements](#q-what-are-the-upgrade-requirements) documentation. ## Q: Does this affect snapshot agents? -Same behavior as Consul clients. See answer for [Does this affect client agents? ](faq#q-does-this-affect-client-agents) +Same behavior as Consul clients. See answer for [Does this affect client agents? ](#q-does-this-affect-client-agents) ## Q: What is the behavior if the license is missing? @@ -96,7 +101,7 @@ Consul snapshot agents will attempt to retrieve the license from servers if cert ## Q: Where can users get a trial license for Consul Enterprise? -Visit [consul.io/trial](https://www.hashicorp.com/products/consul/trial) for a free 30-day trial license. +Contact your [HashiCorp Support contact](https://support.hashicorp.com/) for a development license. ~> **Trial install will cease operation 24 hours after 30-day license expiration**: Trial licenses are not meant to be used in production. @@ -133,7 +138,7 @@ When a customer deploys new clusters to a 1.10.0+ent release, they need to have New Consul cluster deployments using 1.10.0+ent will need to have a valid license on servers to successfully deploy. This valid license must be on-disk (auto-loaded) or as an environment variable. -Please see the [upgrade requirements](faq#q-what-are-the-upgrade-requirements). +Please see the [upgrade requirements](/consul/docs/enterprise/license/faq#q-what-are-the-upgrade-requirements). ## Q: What is the migration path for customers who want to migrate from their existing license-as-applied-via-the-CLI flow to the license on disk flow? @@ -178,7 +183,7 @@ When downgrading to a version of Consul before 1.10.0+ent, customers will need t ## Q: Are there potential pitfalls when downgrading or upgrading Consul server instances? -~> Verify that you meet the [upgrade requirements](faq#q-what-are-the-upgrade-requirements). +~> Verify that you meet the [upgrade requirements](/consul/docs/enterprise/license/faq#q-what-are-the-upgrade-requirements). Assume a scenario where there are three Consul server nodes: diff --git a/website/content/docs/enterprise/license/overview.mdx b/website/content/docs/enterprise/license/overview.mdx index 76070dd888b0..2528c11c652b 100644 --- a/website/content/docs/enterprise/license/overview.mdx +++ b/website/content/docs/enterprise/license/overview.mdx @@ -20,6 +20,9 @@ agent's configuration or environment. Also, prior to 1.10.0, server agents would the license between themselves. This no longer occurs and the license must be present on each server agent when it is started. +Consul Enterprise 1.14.0, when running on Kubernetes, removed client agents and replaced these with virtual agents. +Virtual agents are nodes that Consul service mesh services run on. HashiCorp uses virtual agents to determine license entitlements for customers on per-node licensing and pricing agreements. + -> Visit the [Enterprise License Tutorial](https://learn.hashicorp.com/tutorials/nomad/hashicorp-enterprise-license?utm_source=docs) for detailed steps on how to install the license key. ### Applying a License @@ -41,6 +44,8 @@ may also be licensed in the very same manner. However, to avoid the need to configure the license on many client agents and snapshot agents, those agents have the capability to retrieve the license automatically under the conditions described below. +Virtual agents do not need the license to run. + Updating the license for an agent depends on the method you used to apply the license. - **If you used the `CONSUL_LICENSE` environment variable**: After updating the environment variable, restart the affected agents. diff --git a/website/content/docs/enterprise/license/utilization-reporting.mdx b/website/content/docs/enterprise/license/utilization-reporting.mdx new file mode 100644 index 000000000000..759d448e9720 --- /dev/null +++ b/website/content/docs/enterprise/license/utilization-reporting.mdx @@ -0,0 +1,173 @@ +--- +page_title: Automated license utilization reporting +description: >- + Learn what data HashiCorp collects to meter Enterprise license utilization. Enable or disable reporting. Review sample payloads and logs. +--- + +# Automated license utilization reporting + +This topic describes how to enable automated license utilization reporting in Consul Enterprise. This feature automatically sends license utilization data to HashiCorp so that you do not have to manually collect and report it. It also enables you to review your license usage with the monitoring solution you already use, such as Splunk and Datadog, as you optimize and manage your deployments. + +## Introduction + +You can use automated license utilization report to understand how much additional networking infrastructure you can deploy under your current contract. This feature helps you protect against overutilization and budget for predicted consumption. + +Automated reporting shares the minimum data required to validate license utilization as defined in our contracts. This data mostly consists of computed metrics, and it will never contain Personal Identifiable Information (PII) or other sensitive information. Automated reporting shares the data with HashiCorp using a secure unidirectional HTTPS API and makes an auditable record in the product logs each time it submits a report. This process is GDPR-compliant. + +## Requirements + +Automated license utilization reporting does not support _air-gapped installations_, which are systems with no network interfaces. + +The following versions of Consul Enterprise support automated license utilization reporting: + +- Patch releases of Consul Enterprise 1.14.8 and newer. +- Patch releases of Consul Enterprise 1.13.9 and newer. + +Download a supported release from the [Consul Versions](https://releases.hashicorp.com/consul/) page. + +## Enable automated reporting + +Before you enable automated reporting, make sure that outbound network traffic is configured correctly and upgrade your enterprise product to a version that supports it. If your installation is air-gapped or network settings are not in place, automated reporting will not work. + +To enable automated reporting, complete the following steps: + +1. [Allow outbound HTTPS traffic on port 443](#allow-outbound-https-traffic) +1. [Check product logs](#check-product-logs) + +### Allow outbound HTTPS traffic on port 443 + +Make sure that your network allows HTTPS egress on port 443 from `https://reporting.hashicorp.services` by adding the following IP adddresses to your allow-list: + +- `100.20.70.12` +- `35.166.5.222` +- `23.95.85.111` +- `44.215.244.1` + +### Check product logs + +Automatic license utilization reporting starts sending data within roughly 24 hours. Check the product logs for records that the data sent successfully. + + + +``` +[DEBUG] beginning snapshot export +[DEBUG] creating payload +[DEBUG] marshalling payload to json +[DEBUG] generating authentication headers +[DEBUG] creating request +[DEBUG] sending request +[DEBUG] performing request: method=POST url=https://census.license.hashicorp.services +[DEBUG] recording audit record +[INFO] reporting: Report sent: auditRecord={"payload":{"payload_version":"1","license_id":"d2cdd857-4202-5a45-70a6-e4b531050c34","product":"consul","product_version":"1.16.0-dev+ent","export_timestamp":"2023-05-26T20:09:13.753921087Z","snapshots":[{"snapshot_version":1,"snapshot_id":"0001J724F90F4XWQDSAA76ZQWA","process_id":"01H1CTJPC1S8H7Q45MKTJ689ZW","timestamp":"2023-05-26T20:09:13.753513962Z","schema_version":"1.0.0","service":"consul","metrics":{"consul.billable.nodes":{"key":"consul.billable.nodes","kind":"counter","mode":"write","value":2},"consul.billable.service_instances":{"key":"consul.billable.service_instances","kind":"counter","mode":"write","value":2}}}],"metadata":{}}} +[DEBUG] completed recording audit record +[DEBUG] export finished successfully" +``` + + + +If your installation is air-gapped or your network does not allow the correct egress, the logs show an error. + + + +``` +[DEBUG] reporting: beginning snapshot export +[DEBUG] reporting: creating payload +[DEBUG] reporting: marshalling payload to json +[DEBUG] reporting: generating authentication headers +[DEBUG] reporting: creating request +[DEBUG] reporting: sending request +[DEBUG] reporting: performing request: method=POST url=https://census.license.hashicorp.services +[DEBUG] reporting: error status code received: statusCode=403 +``` + + + +In this case, reconfigure your network to allow egress and check the logs again in roughly 24 hours to confirm that automated reporting works correctly. + +## Opt out + +If your installation is air-gapped or you want to manually collect and report on the same license utilization metrics, you can opt out of automated reporting. + +Manually reporting these metrics can be time consuming. Opting out of automated reporting does not mean that you also opt out from sending license utilization metrics. Customers who opt out of automated reporting are still required to manually collect and send license utilization metrics to HashiCorp. + +If you are considering opting out because you are worried about the data, we strongly recommend that you review the [example payloads](#example-payloads) before opting out. If you have concerns with any of the automatically reported data, raise these concerns with your account manager. + +There are two methods for opting out of automated reporting: + +- HCL configuration (recommended) +- Environment variable (requires restart) + +We recommend opting out in your product's configuration file because it does not require a system restart. Add the following block to your `configuration.hcl` or `configuration.json` file. + +```hcl +reporting { + license { + enabled = false + } +} +``` + +When opting out using an environment variable, the system provides a startup message confirming that you have disabled automated reporting. Set the following environment variable to disable automated reporting: + + + +```shell-session +$ export OPTOUT_LICENSE_REPORTING=true +``` + + + +After you set the environment variable, restart your system to complete the process for opting out. + +```shell-session +$ consul reload +``` + + +Check your product logs roughly 24 hours after opting out to make sure that the system is not trying to send reports. Keep in mind that if your configuration file and environment variable differ, the environment variable setting takes precedence. + +## Example payloads + +HashiCorp collects the following utilization data as JSON payloads: +`exporter_version` - The version of the licensing exporter + + + +```json +{ + "payload": { + "payload_version": "1", + "license_id": "d2cdd857-4202-5a45-70a6-e4b531050c34", + "product": "consul", + "product_version": "1.16.0-dev+ent", + "export_timestamp": "2023-05-26T20:09:13.753921087Z", + "snapshots": [ + { + "snapshot_version": 1, + "snapshot_id": "0001J724F90F4XWQDSAA76ZQWA", + "process_id": "01H1CTJPC1S8H7Q45MKTJ689ZW", + "timestamp": "2023-05-26T20:09:13.753513962Z", + "schema_version": "1.0.0", + "service": "consul", + "metrics": { + "consul.billable.nodes": { + "key": "consul.billable.nodes", + "kind": "counter", + "mode": "write", + "value": 2 + }, + "consul.billable.service_instances": { + "key": "consul.billable.service_instances", + "kind": "counter", + "mode": "write", + "value": 2 + } + } + } + ], + "metadata": {} + } +} +``` + + \ No newline at end of file diff --git a/website/content/docs/enterprise/network-segments.mdx b/website/content/docs/enterprise/network-segments.mdx deleted file mode 100644 index 0ae655549937..000000000000 --- a/website/content/docs/enterprise/network-segments.mdx +++ /dev/null @@ -1,236 +0,0 @@ ---- -layout: docs -page_title: Network Segments (Enterprise) -description: >- - Network segments enable LAN gossip in a datacenter when network rules or firewalls prevent specific sets of clients from communicating directly. Learn about configuring server and client agents to operate in segmented networks. ---- - -# Network Segments - - - -This feature requires version 0.9.3+ of -self-managed Consul Enterprise. -Refer to the [enterprise feature matrix](/docs/enterprise#consul-enterprise-feature-availability) for additional information. - - - -Consul requires full connectivity between all agents (servers and clients) in a -[datacenter](/docs/agent/config/cli-flags#_datacenter) within a given -LAN gossip pool. By default, all Consul agents will be a part of one shared Serf LAN -gossip pool known as the `` network segment, thus requiring full mesh -connectivity within the datacenter. - -![Consul datacenter default agent connectivity: one network segment](/img/network-segments/consul-network-segments-single.png) - -In some environments, full connectivity between all agents is not possible—known as a -"segmented network". This is usually the result of business policies enforced through -network rules or firewalls. To use Consul in a segmented network, you must break up -the LAN gossip pool along network communication boundaries into separate "network -segments". Network segments are isolated LAN gossip pools that only require full -connectivity between agent members on the same segment. - -![Consul datacenter agent connectivity with network segments](/img/network-segments/consul-network-segments-multiple.png) - -Complete the [Network Segments](https://learn.hashicorp.com/tutorials/consul/network-partition-datacenters) tutorial to learn more about network segments. - --> **Info:** Network segments enable you to operate a Consul datacenter without full -mesh (LAN) connectivity between agents. To federate multiple Consul datacenters -without full mesh (WAN) connectivity between all server agents in all datacenters, -use [Network Areas (Enterprise)](/docs/enterprise/federation). - -# Consul Networking Models - -To help set context for this feature, it is useful to understand the various -Consul networking models and their capabilities. - -**Cluster:** A set of Consul servers forming a Raft quorum along with a -collection of Consul clients, all set to the same -[datacenter](/docs/agent/config/cli-flags#_datacenter), and joined together to form -what we will call a "local cluster". Consul clients discover the Consul servers -in their local cluster through the gossip mechanism and make RPC requests to -them. LAN Gossip (OSS) is an open intra-cluster networking model, and Network -Segments (Enterprise) creates multiple segments within one cluster. - -**Federated Cluster:** A set of connected clusters, each representing a unique Consul “datacenter”. These Consul servers are federated together -over the WAN. Consul clients make use of resources in federated clusters by -forwarding RPCs through the Consul servers in their local cluster, but they -never interact with remote Consul servers directly. There are two tutorials that -will guide you through inter-cluster network models: - -1. [WAN gossip (OSS)](https://learn.hashicorp.com/consul/security-networking/datacenters) -1. [Network Areas (Enterprise)](https://learn.hashicorp.com/tutorials/consul/federation-network-areas). - -**LAN Gossip Pool**: A set of Consul agents that have full mesh connectivity -among themselves, and use Serf to maintain a shared view of the members of the -pool for different purposes, like finding a Consul server in a local cluster, -or finding servers in a remote cluster. A **segmented** LAN Gossip Pool limits a -group of agents to only connect with the agents in its segment. - -# Network Segments Configuration - -## Server Configuration - -Server agents are members of all segments. The datacenter includes a `` -segment, as well as additional segments defined in the -[`segments`](/docs/agent/config/config-files#segments) server agent configuration option. -Each additional segment is defined by: - -- a non-empty name -- a unique port -- optionally, a custom bind and advertise address for the additional segment's - Serf LAN listener on the server - -~> **Note:** Prior to Consul 1.7.3, a Consul server agent configured with too -many network segments may not be able to start due to [limitations](https://learn.hashicorp.com/tutorials/consul/network-partition-datacenters#network-segments-limitations) -in Serf. - -### Example Server Configuration - -The following server agent configuration will create two user-defined network -segments: `alpha` and `beta`. - - - -```hcl -segments = [ - { - name = "alpha" - bind = "{{GetPrivateIP}}" - advertise = "{{GetPrivateIP}}" - port = 8303 - }, - { - name = "beta" - bind = "{{GetPrivateIP}}" - advertise = "{{GetPrivateIP}}" - port = 8304 - } -] -``` - -```json -{ - "segments": [ - { - "name": "alpha", - "bind": "{{GetPrivateIP}}", - "advertise": "{{GetPrivateIP}}", - "port": 8303 - }, - { - "name": "beta", - "bind": "{{GetPrivateIP}}", - "advertise": "{{GetPrivateIP}}", - "port": 8304 - } - ] -} -``` - - - -The server [agent configuration](/docs/agent/config/config-files) options relevant to network -segments are: - -- [`ports.serf_lan`](/docs/agent/config/config-files#serf_lan_port): The Serf LAN port on this server - for the `` network segment's gossip pool. -- [`segments`](/docs/agent/config/config-files#segments): A list of user-defined network segments - on this server, including their names and Serf LAN ports. - -## Client Configuration - -Each client agent can only be a member of one segment at a time. This will be the -`` segment unless otherwise specified in the agent's -[`segment`](/docs/agent/config/cli-flags#_segment) agent configuration option. - -### Join a Client to a Segment ((#join_a_client_to_a_segment)) - -For a client agent to [join](/commands/join) the Consul -datacenter, it must connect to another agent (client or server) within its -configured segment. - - - - -Clients A and B specify the same segment S. Client B is already joined to the segment S -LAN gossip pool. Client A wants to join via Client B. In order to do so, Client A -must connect to Client B's configured [Serf LAN port](/docs/agent/config/config-files#serf_lan_port). - - - - -Client A specifies segment S and wants to join the segment S gossip pool via Server 1. -In order to do so, Client A must connect to Server 1's configured [Serf LAN port -for segment S](/docs/agent/config/config-files#segment_port). - - - - -There are several methods to specify the port used by the join operation, listed in order -of precedence: - -1. **Specify an explicit port in the join address**. This can be done at the CLI when starting - the agent (e.g., `consul agent -retry-join "client-b-address:8303"`), or in the agent's - configuration using the [retry-join option](/docs/agent/config/config-files#retry_join). This method - is not compatible with [cloud auto-join](/docs/install/cloud-auto-join#auto-join-with-network-segments). - -2. **Specify an alternate Serf LAN port for the agent**. This can be done at the CLI when starting - the agent (e.g., `consul agent -retry-join "client-b-address" -serf-lan-port 8303`), or in - the agent's configuration using the [serf_lan](/docs/agent/config/config-files#serf_lan_port) option. - When a Serf LAN port is not explicitly specified in the join address, the agent will attempt to - join the target host at the Serf LAN port specified in CLI or agent configuration. - -3. **Use the default Serf LAN port (8301)**. The agent will attempt to join the target host - on port 8301. - --> Agents within a segment can use different port numbers for their Serf LAN port. -For example, on the `` segment, Server S can use port 8301, Client A -can use 8303, and Client B can use 8304. However, if an agent wishes to join a -segment via an agent that uses a different port number, the target agent's Serf LAN -port must be specified in the join address (method 1 above). - -### Example Client Configuration - -The following client agent configuration will cause the agent to: - -- Open a Serf LAN listener port on 8303. -- Attempt to join the cluster via servers on port 8303 (since an alternate port is not - specified in the `retry_join` addresses). - - - -```hcl -node_name = "consul-client1" -retry_join = ["consul-server1", "consul-server2", "consul-server3"] -segment = "alpha" -ports = { - serf_lan = 8303 -} -``` - -```json -{ - "node_name": "consul-client1", - "retry_join": ["consul-server1", "consul-server2", "consul-server3"], - "segment": "alpha", - "ports": { - "serf_lan": 8303 - } -} -``` - - - -The client [agent configuration](/docs/agent/config/config-files) options relevant to network -segments are: - -- [`segment`](/docs/agent/config/config-files#segment-2): The name of the network segment this - client agent belongs to. -- [`ports.serf_lan`](/docs/agent/config/config-files#serf_lan_port): - Serf LAN port for the above segment on this client. This is not required - to match the configured Serf LAN port for other agents on this segment. -- [`retry_join`](/docs/agent/config/config-files#retry_join) or - [`start_join`](/docs/agent/config/config-files#start_join): A list of agent addresses to join - when starting. Ensure the correct Serf LAN port for this segment is used when joining - the LAN gossip pool using one of the [available configuration methods](#join_a_client_to_a_segment). diff --git a/website/content/docs/enterprise/network-segments/create-network-segment.mdx b/website/content/docs/enterprise/network-segments/create-network-segment.mdx new file mode 100644 index 000000000000..b7ef6b66b8ad --- /dev/null +++ b/website/content/docs/enterprise/network-segments/create-network-segment.mdx @@ -0,0 +1,194 @@ +--- +layout: docs +page_title: Create Network Segments +description: >- + Learn how to create Consul network segments to enable services in the LAN gossip pool to communicate across communication boundaries. +--- + +# Create Network Segments + +This topic describes how to create Consul network segments so that services can connect to other services in the LAN gossip pool that have been placed into separate communication boundaries. Refer to [Network Segments Overview](/consul/docs/enterprise/network-segments/network-segments-overview) for additional information. + + +## Requirements + +- Consul Enterprise 0.9.3+ + +## Define segments in the server configuration + +1. Add the `segments` block to your server configuration. Refer to the [`segments`](/consul/docs/agent/config/config-files#segments) documentation for details about how to define the configuration. + + In the following example, an `alpha` segment is configured to listen for traffic on port `8303` and a `beta` segment is configured to listen to traffic on port `8304`: + + + + ```hcl + segments = [ + { + name = "alpha" + bind = "10.0.0.1" + advertise = "10.0.0.1" + port = 8303 + }, + { + name = "beta" + bind = "10.0.0.1" + advertise = "10.0.0.1" + port = 8304 + } + ] + ``` + + ```json + { + "segments": [ + { + "name": "alpha", + "bind": "10.0.0.1", + "advertise": "10.0.0.1", + "port": 8303 + }, + { + "name": "beta", + "bind": "10.0.0.1", + "advertise": "10.0.0.1", + "port": 8304 + } + ] + } + ``` + + + +1. Start the server using the `consul agent` command. Copy the address for each segment listener so that you can [direct clients to join the segment](#configure-clients-to-join-segments) when you start them: + + ```shell-session + $ consul agent -config-file server.hcl + [INFO] serf: EventMemberJoin: server1.dc1 10.20.10.11 + [INFO] serf: EventMemberJoin: server1 10.20.10.11 + [INFO] consul: Started listener for LAN segment "alpha" on 10.20.10.11:8303 + [INFO] serf: EventMemberJoin: server1 10.20.10.11 + [INFO] consul: Started listener for LAN segment "beta" on 10.20.10.11:8304 + [INFO] serf: EventMemberJoin: server1 10.20.10.11 + ``` +1. Verfiy that the server is a member of all segments: + + ```shell-session + $ consul members + Node Address Status Type Build Protocol DC Segment + server1 10.20.10.11:8301 alive server 1.14+ent 2 dc1 + ``` + +## Configure clients to join segments + +Client agents can only be members of one segment at a time. You can direct clients to join a segment by specifying the address and name of the segment with the [`-join`](/consul/docs/agent/config/cli-flags#_join) and [`-segment`](/consul/docs/agent/config/cli-flags#_segment) command line flags when starting the agent. + +```shell-session +$ consul agent -config-file client.hcl -join 10.20.10.11:8303 -segment alpha +``` + +Alternatively, you can add the [`retry_join`](/consul/docs/agent/config/config-files#retry_join) and [`segment`](/consul/docs/agent/config/config-files#segment-1) parameters to your client agent configuration file: + +```hcl +node_name = "consul-client" +server = false +datacenter = "dc1" +data_dir = "consul/client-data" +log_level = "INFO" +retry_join = ["10.20.10.11:8303"] +segment = "alpha" +``` + +## Verify segments + +You can use the CLI, API, or GUI to verify which segments your agents have joined. + + + + + +Run the `consul members` command to verify that the client agents are joined to the correct segments: + + + +```shell-session +$ consul members +Node Address Status Type Build Protocol DC Partition Segment +server 192.168.4.159:8301 alive server 1.14+ent 2 dc1 default +client1 192.168.4.159:8447 alive client 1.14+ent 2 dc1 default alpha +``` + + + +You can also pass the name of a segment in the `-segment` flag to view agents in a specific segment. Note that server agents display their LAN listener port for the specified segment the segment filter applied. In the following example, the command returns port `8303` for alpha, rather than for the `` segment port: + + + +```shell-session +$ consul members -segment alpha +Node Address Status Type Build Protocol DC Segment +server1 10.20.10.11:8301 alive server 1.14+ent 2 dc1 alpha +client1 10.20.10.21:8303 alive client 1.14+ent 2 dc1 alpha +``` + + + +Refer to the [`members`](/consul/commands/members) documentation for additional information. + + + + + +Call the `/agent/members` API endpoint to view members that the agent sees in the cluster gossip pool. + + + +```shell-session +$ curl http://127.0.0.1:8500/v1/agent/members?segment=alpha + +{ + "Addr" : "192.168.4.163", + "DelegateCur" : 4, + "DelegateMax" : 5, + "DelegateMin" : 2, + "Name" : "consul-client", + "Port" : 8447, + "ProtocolCur" : 2, + "ProtocolMax" : 5, + "ProtocolMin" : 1, + "Status" : 1, + "Tags" : { + "build" : "1.13.1+ent:5bd604e6", + "dc" : "dc1", + "ft_admpart" : "1", + "ft_ns" : "1", + "id" : "aeaf70d7-57f7-7eaf-e246-6edfe8386e9c", + "role" : "node", + "segment" : "alpha", + "vsn" : "2", + "vsn_max" : "3", + "vsn_min" : "2" + } +} +``` + + + +Refer to the [`/agent/members` API endpoint documentation](/consul/api-docs/agent#list-members) for additional information. + + + + +If the UI is enabled in your agent configuration, the segment name appears in the node’s Metadata tab. + +1. Open the URL for the UI. By default, the UI is `localhost:8500`. +1. Click **Node** in the sidebar and click on the name of the client agent you want to check. +1. Click the **Metadata** tab. The network segment appears as a key-value pair. + + + + + +## Related resources + +You can also create and run a prepared query to query for additional information about the services registered to client nodes. Prepared queries are HTTP API endpoint features that enable you to run complex queries of Consul nodes. Refer [Prepared Query HTTP Endpoint](/consul/api-docs/query) for usage. \ No newline at end of file diff --git a/website/content/docs/enterprise/network-segments/network-segments-overview.mdx b/website/content/docs/enterprise/network-segments/network-segments-overview.mdx new file mode 100644 index 000000000000..b6d50338ecc4 --- /dev/null +++ b/website/content/docs/enterprise/network-segments/network-segments-overview.mdx @@ -0,0 +1,63 @@ +--- +layout: docs +page_title: Network Segments Overview +description: >- + Network segments enable LAN gossip traffic within a datacenter when network rules or firewalls prevent specific sets of clients from communicating directly. Learn about segmented network concepts. +--- + +# Network Segments Overview + +Network segmentation is the practice of dividing a network into multiple segments or subnets that act as independent networks. This topic provides an overview of concepts related to operating Consul in a segmented network. + + + +This feature requires Consul Enterprise version 0.9.3 or later. +Refer to the [enterprise feature matrix](/consul/docs/enterprise#consul-enterprise-feature-availability) for additional information. + + + +## Segmented networks + +Consul requires full connectivity between all agents in a datacenter within a LAN gossip pool. In some environments, however, business policies enforced through network rules or firewalls prevent full connectivity between all agents. These environments are called _segmented networks_. Network segments are isolated LAN gossip pools that only require full connectivity between agent members on the same segment. + +To use Consul in a segmented network, you must define the segments in your server agent configuration and direct client agents to join one of the segments. The Consul network segment configuration should match the LAN gossip pool boundaries. The following diagram shows how a network may be segmented: + +![Consul datacenter agent connectivity with network segments](/img/network-segments/consul-network-segments-multiple.png) + +## Default network segment + +By default, all Consul agents are part of a shared Serf LAN gossip pool, referred to as the `` network segment. Because all agents are within the same segment, full mesh connectivity within the datacenter is required. The following diagram shows the `` network segment: + +![Consul datacenter default agent connectivity: one network segment](/img/network-segments/consul-network-segments-single.png) + +## Segment membership + +Server agents are members of all segments. The datacenter includes the `` segment, as well as additional segments defined in the `segments` server agent configuration option. Refer to the [`segments`](/consul/docs/agent/config/config-files#segments) documentation for additional information. + +Each client agent can only be a member of one segment at a time. Client agents are members of the `` segment unless they are configured to join a different segment. +For a client agent to join the Consul datacenter, it must connect to another agent (client or server) within its configured segment. + + + +Complete the [Network Segments](https://learn.hashicorp.com/tutorials/consul/network-partition-datacenters) tutorial to learn more about network segments. + +-> **Info:** Network segments enable you to operate a Consul datacenter without full +mesh (LAN) connectivity between agents. To federate multiple Consul datacenters +without full mesh (WAN) connectivity between all server agents in all datacenters, +use [Network Areas (Enterprise)](/docs/enterprise/federation). + +## Consul networking models + +Network segments are a subset of other Consul networking models. Understanding the broader models will help you segment your network. Refer to [Architecture Overview](/consul/docs/architecture) for additional information about the following concepts. + +### Clusters + +You can segment networks within a Consul _cluster_. A cluster is one or more Consul servers that form a Raft quorum and one or more Consul clients that are members of the same [datacenter](/consul/docs/agent/config/cli-flags#_datacenter). The cluster is sometimes called the _local cluster_. Consul clients discover and make RPC requests to Consul servers in their local cluster through the gossip mechanism. Consul OSS uses LAN gossip for intra-cluster communication between agents. + +### LAN gossip pool + +A set of fully-connected Consul agents is a _LAN gossip pool_. LAN gossip pools use the Serf protocol to maintain a shared view of the members of the pool for different purposes, such as finding a Consul server in a local cluster or finding servers in a remote cluster. A segmented LAN gossip pool limits a group of agents to only connect with the agents in its segment. + +## Network segments versus network areas + +Network segments enable you to operate a Consul datacenter without full mesh connectivity between agents using a LAN gossip pool. To federate multiple Consul datacenters without full mesh connectivity between all server agents in all datacenters, use [network areas](/consul/docs/enterprise/federation). Network areas are a Consul Enterprise capability. \ No newline at end of file diff --git a/website/content/docs/install/cloud-auto-join.mdx b/website/content/docs/install/cloud-auto-join.mdx index 006e3114c304..ff7a139d721e 100644 --- a/website/content/docs/install/cloud-auto-join.mdx +++ b/website/content/docs/install/cloud-auto-join.mdx @@ -34,7 +34,7 @@ or via a configuration file: ## Auto-join with Network Segments -In order to use cloud auto-join with [Network Segments](/docs/enterprise/network-segments), +In order to use cloud auto-join with [Network Segments](/consul/docs/enterprise/network-segments/network-segments-overview), you must reconfigure the Consul agent's Serf LAN port to match that of the segment you wish to join. @@ -106,7 +106,7 @@ In order to use discovery behind a proxy, you will need to set The following sections give the options specific to each supported cloud provider. -### Amazon EC2 +### Amazon EC2 and ECS This returns the first private IP address of all servers in the given region which have the given `tag_key` and `tag_value`. @@ -128,6 +128,10 @@ $ consul agent -retry-join "provider=aws tag_key=... tag_value=..." - `addr_type` (optional) - the type of address to discover: `private_v4`, `public_v4`, `public_v6`. Default is `private_v4`. (>= 1.0) - `access_key_id` (optional) - the AWS access key for authentication (see below for more information about authenticating). - `secret_access_key` (optional) - the AWS secret access key for authentication (see below for more information about authenticating). +- `service` (optional) - String value that specifies which AWS service to filter. You can specify either `ec2` or `ecs`. Default is `ec2`. +- `ecs_cluster` (optional) - String value that limits searches to a specific AWS ECS cluster name or full ARN. By default, Consul searches all clusters with the specified tag values. +- `ecs_family` (optional) - String value limits searches to a AWS ECS task definition family. By default, Consul searches all task definition families with the specified tags. +- `endpoint` (optional) - String value that specifies the endpoint URL of the AWS service to use. If not set, the AWS client sets the value, which defaults to the public DNS name for the service in the specified region. #### Authentication & Precedence @@ -137,12 +141,19 @@ $ consul agent -retry-join "provider=aws tag_key=... tag_value=..." - ECS task role metadata (container-specific). - EC2 instance role metadata. -The only required IAM permission is `ec2:DescribeInstances`, and it is -recommended that you make a dedicated key used only to auto-join the datacenter. If the -region is omitted it will be discovered through the local instance's [EC2 -metadata +The only IAM permission required for discovering EC2 consul-servers is `ec2:DescribeInstances`. +We recommend that you make a dedicated key used only to auto-join the datacenter. +If the region is omitted it will be discovered through the local instance's [EC2 metadata endpoint](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html). +The AWS ECS task role associated with the service attempting to discover the `consul-server` must have the following IAM permissions: +- `ecs:ListClusters` (only used when `ecs_cluster` is not provided) +- `ecs:ListServices` (only used when `ecs_cluster` is not provided) +- `ecs:DescribeServices` (only used when `ecs_cluster` is not provided) +- `ecs:ListTasks` +- `ecs:DescribeTasks` +If the region is omitted from the configuration, Consul obtains it from the local instance's [ECS V4 metadata endpoint](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v4.html). + ### Microsoft Azure This returns the first private IP address of all servers in the given region diff --git a/website/content/docs/install/ports.mdx b/website/content/docs/install/ports.mdx index f40e1756add5..079674f0417f 100644 --- a/website/content/docs/install/ports.mdx +++ b/website/content/docs/install/ports.mdx @@ -21,6 +21,7 @@ Before running Consul, you should ensure the following bind ports are accessible | HTTP: The HTTP API (TCP Only) | 8500 | | HTTPS: The HTTPs API | disabled (8501)\* | | gRPC: The gRPC API | disabled (8502)\* | +| gRPC TLS: The gRPC API with TLS connections | disabled (8503)\* | | LAN Serf: The Serf LAN port (TCP and UDP) | 8301 | | Wan Serf: The Serf WAN port (TCP and UDP) | 8302 | | server: Server RPC address (TCP Only) | 8300 | diff --git a/website/content/docs/integrate/download-tools.mdx b/website/content/docs/integrate/download-tools.mdx index 4953f5f56ee6..7c503b78cdc1 100644 --- a/website/content/docs/integrate/download-tools.mdx +++ b/website/content/docs/integrate/download-tools.mdx @@ -15,7 +15,7 @@ These Consul tools are created and managed by the dedicated engineers at HashiCo - [Envconsul](https://github.com/hashicorp/envconsul) - Read and set environmental variables for processes from Consul. - [Consul API Gateway](https://github.com/hashicorp/consul-api-gateway/) - dedicated ingress solution for intelligently routing traffic to applications running on a Consul Service Mesh. -- [Consul ESM](https://github.com/hashicorp/consul-esm) - Provides external service monitoring for Consul. Complete the [tutorial]((https://learn.hashicorp.com/tutorials/consul/service-registration-external-services?utm_source=docs)) to learn more. +- [Consul ESM](https://github.com/hashicorp/consul-esm) - Provides external service monitoring for Consul. Complete the [tutorial](/consul/tutorials/developer-discovery/service-registration-external-services?utm_source=docs) to learn more. - [Consul Migrate](https://github.com/hashicorp/consul-migrate) - Data migration tool to handle Consul upgrades to 0.5.1+ - [Consul Replicate](https://github.com/hashicorp/consul-replicate) - Consul cross-DC KV replication daemon. - [Consul Template](https://github.com/hashicorp/consul-template) - Generic template rendering and notifications with Consul. Complete the [tutorial](https://learn.hashicorp.com/tutorials/consul/consul-template?utm_source=docs) to the learn more. @@ -54,7 +54,6 @@ These Consul tools are created and managed by the amazing members of the Consul - [gradle-consul-plugin](https://github.com/amirkibbar/red-apple) - A Consul Gradle plugin - [hashi-ui](https://github.com/jippi/hashi-ui) - A modern user interface for the Consul and Nomad - [HashiBox](https://github.com/nunchistudio/hashibox) - Vagrant environment to simulate highly-available cloud with Consul, Nomad, Vault, and optional support for Waypoint. OSS & Enterprise supported. -- [helios-consul](https://github.com/SVT/helios-consul) - Service registrar plugin for Helios - [Jenkins Consul Plugin](https://plugins.jenkins.io/consul) - Jenkins plugin for service discovery and K/V store - [marathon-consul](https://github.com/allegro/marathon-consul) - Service registry bridge for Marathon - [marathon-consul](https://github.com/CiscoCloud/marathon-consul) - Bridge from Marathon apps to the Consul K/V store diff --git a/website/content/docs/integrate/partnerships.mdx b/website/content/docs/integrate/partnerships.mdx index b8fbca9e98f5..69cef4999b7b 100644 --- a/website/content/docs/integrate/partnerships.mdx +++ b/website/content/docs/integrate/partnerships.mdx @@ -89,7 +89,7 @@ Here are links to resources, documentation, examples and best practices to guide - [Monitoring Consul with Datadog APM](https://www.datadoghq.com/blog/consul-datadog/) - [Monitor HCP Consul with New Relic Instant Observability](https://github.com/newrelic-experimental/hashicorp-quickstart-annex/blob/main/hcp-consul/README.md) - [HCP Consul and CloudFabrix AIOps Integration](https://bot-docs.cloudfabrix.io/Bots/consul/?h=consul) -- [Consul and SnappyFlow Full Stack Observability](https://docs.snappyflow.io/docs/integrations/hcp_consul) +- [Consul and SnappyFlow Full Stack Observability](https://docs.snappyflow.io/docs/Integrations/hcp_consul) **Network Performance Monitoring (NPM)** diff --git a/website/content/docs/internals/acl.mdx b/website/content/docs/internals/acl.mdx index 391ee450315a..87575627710a 100644 --- a/website/content/docs/internals/acl.mdx +++ b/website/content/docs/internals/acl.mdx @@ -10,7 +10,7 @@ description: >- # ACL System ((#version_8_acls)) -This content has been moved into the [ACL Guide](https://learn.hashicorp.com/tutorials/consul/access-control-setup-production). +This content has been moved into the [ACL Guide](/consul/tutorials/security/access-control-setup-production). -See [Complete ACL Coverage in Consul 0.8](/docs/security/acl/acl-legacy) for details -about ACL changes in Consul 0.8 and later. +Reference [Complete ACL Coverage in Consul 0.8](/docs/security/acl/acl-legacy) for details +about ACL changes in Consul 0.8 and later. \ No newline at end of file diff --git a/website/content/docs/intro/index.mdx b/website/content/docs/intro/index.mdx index 89d4f67a88d2..96b190d68337 100644 --- a/website/content/docs/intro/index.mdx +++ b/website/content/docs/intro/index.mdx @@ -24,7 +24,7 @@ Consul interacts with the _data plane_ through proxies. The data plane is the pa The core Consul workflow consists of the following stages: -- **Register**: Teams add services to the Consul catalog, which is a central registry that lets services automatically discover each other without requiring a human operator to modify application code, deploy additional load balancers, or hardcode IP addresses. It is the runtime source of truth for all services and their addresses. Teams can manually [define and register services](/docs/discovery/services) using the CLI or the API, or you can automate the process in Kubernetes with [service sync](/docs/k8s/service-sync). Services can also include health checks so that Consul can monitor for unhealthy services. +- **Register**: Teams add services to the Consul catalog, which is a central registry that lets services automatically discover each other without requiring a human operator to modify application code, deploy additional load balancers, or hardcode IP addresses. It is the runtime source of truth for all services and their addresses. Teams can manually [define](/consul/docs/services/usage/define-services) and [register](/consul/docs/services/usage/register-services-checks) using the CLI or the API, or you can automate the process in Kubernetes with [service sync](/consul/docs/k8s/service-sync). Services can also include health checks so that Consul can monitor for unhealthy services. - **Query**: Consul’s identity-based DNS lets you find healthy services in the Consul catalog. Services registered with Consul provide health information, access points, and other data that help you control the flow of data through your network. Your services only access other services through their local proxy according to the identity-based policies you define. - **Secure**: After services locate upstreams, Consul ensures that service-to-service communication is authenticated, authorized, and encrypted. Consul service mesh secures microservice architectures with mTLS and can allow or restrict access based on service identities, regardless of differences in compute environments and runtimes. diff --git a/website/content/docs/k8s/annotations-and-labels.mdx b/website/content/docs/k8s/annotations-and-labels.mdx index 63b407fb1552..cd0afce61273 100644 --- a/website/content/docs/k8s/annotations-and-labels.mdx +++ b/website/content/docs/k8s/annotations-and-labels.mdx @@ -9,13 +9,21 @@ description: >- ## Overview -Consul on Kubernetes provides a few options for customizing how connect-inject behavior should be configured. +Consul on Kubernetes provides a few options for customizing how connect-inject or service sync behavior should be configured. This allows the user to configure natively configure Consul on select Kubernetes resources (i.e. pods, services). -- [Annotations](#annotations) -- [Labels](#labels) +- [Consul Service Mesh](#consul-service-mesh) + - [Annotations](#annotations) + - [Labels](#labels) +- [Service Sync](#service-sync) + - [Annotations](#annotations-1) -## Annotations +The noun _connect_ is used throughout this documentation to refer to the connect +subsystem that provides Consul's service mesh capabilities. + +## Consul Service Mesh + +### Annotations The following Kubernetes resource annotations could be used on a pod to control connect-inject behavior: @@ -50,6 +58,10 @@ The following Kubernetes resource annotations could be used on a pod to control list of additional user IDs to exclude from traffic redirection when running in transparent proxy mode. +- `consul.hashicorp.com/use-proxy-health-check` - It this is set to `true`, it configures + a readiness endpoint on Consul sidecar proxy and queries the proxy instead of the proxy's inbound port which + forwards the request to the application. + - `consul.hashicorp.com/connect-service` - For pods that accept inbound connections, this specifies the name of the service that is being served. This defaults to the name of the Kubernetes service associated with the pod. @@ -67,83 +79,95 @@ The following Kubernetes resource annotations could be used on a pod to control - `consul.hashicorp.com/connect-service-upstreams` - The list of upstream services that this pod needs to connect to via Connect along with a static local port to listen for those connections. When transparent proxy is enabled, - this annotation is optional. There are a few formats this annotation can take: - - - Unlabeled: - Use the unlabeled annotation format to specify a service name, Consul Enterprise namespaces and partitions, and - datacenters. To use [cluster peering](/docs/connect/cluster-peering/k8s) with upstreams, use the following - labeled format. - - Service name: Place the service name at the beginning of the annotation to specify the upstream service. You can - also append the datacenter where the service is deployed (optional). - ```yaml - annotations: - "consul.hashicorp.com/connect-service-upstreams":"[service-name]:[port]:[optional datacenter]" - ``` + this annotation is optional. This annotation can be either _labeled_ or _unlabeled_. We recommend the labeled format because it has a more consistent syntax and can be used to reference cluster peers as upstreams. - - Namespace (requires Consul Enterprise 1.7+): Upstream services may be running in a different namespace. Place - the upstream namespace after the service name. For additional details about configuring the injector, refer to + - **Labeled**: - [Consul Enterprise Namespaces](#consul-enterprise-namespaces) . - ```yaml - annotations: - "consul.hashicorp.com/connect-service-upstreams":"[service-name].[service-namespace]:[port]:[optional datacenter]" - ``` - If the namespace is not specified, the annotation defaults to the namespace of the source service. - If you are not using Consul Enterprise 1.7+, Consul interprets the value placed in the namespace position as part of the service name. - - - Admin partitions (requires Consul Enterprise 1.11+): Upstream services may be running in a different - partition. You must specify the namespace when specifying a partition. Place the partition name after the namespace. If you specify the name of the datacenter (optional), it must be the local datacenter. Communicating across partitions using this method is only supported within a - datacenter. For cross partition communication across datacenters, refer to [cluster - peering](/docs/connect/cluster-peering/k8s). - ```yaml - annotations: - "consul.hashicorp.com/connect-service-upstreams":"[service-name].[service-namespace].[service-partition]:[port]:[optional datacenter]" - ``` - - [Prepared queries](/api-docs/query): Prepend the annotation - with `prepared_query` and place the name of the query at the beginning of the string. - ```yaml - annotations: - 'consul.hashicorp.com/connect-service-upstreams': 'prepared_query:[query name]:[port]' - ``` + The labeled annotation format allows you to reference any service as an upstream. You can specify a Consul Enterprise namespace. You can also specify an admin partition in the same datacenter, a cluster peer, or a WAN-federated datacenter. - - Labeled (requires Consul for Kubernetes v0.45.0+): - The labeled format is required when using the cluster peering feature and specifying an upstream in another - peer. You can specify a Consul Enterprise namespace, partition, or datacenter. The format supports only one peer, datacenter, or partition. - Service name: Place the service name at the beginning of the annotation followed by `.svc` to specify the upstream service. + ```yaml annotations: "consul.hashicorp.com/connect-service-upstreams":"[service-name].svc:[port]" ``` + - Peer or datacenter: Place the peer or datacenter after `svc.` followed by either `peer` or `dc` and the port number. + ```yaml annotations: "consul.hashicorp.com/connect-service-upstreams":"[service-name].svc.[service-peer].peer:[port]" ``` + ```yaml annotations: "consul.hashicorp.com/connect-service-upstreams":"[service-name].svc.[service-dc].dc:[port]" ``` - - Namespace (required Consul Enterprise): Place the namespace after `svc.` followed by `ns` and the port number. + + - Namespace (requires Consul Enterprise): Place the namespace after `svc.` followed by `ns` and the port number. + ```yaml annotations: "consul.hashicorp.com/connect-service-upstreams":"[service-name].svc.[service-namespace].ns:[port]" ``` - When specifying a peer, datacenter, or admin partition when namespaces are enabled, you must - provide the namespace . + + When namespaces are enabled, you must include the namespace in the annotation before specifying a cluster peer, WAN-federated datacenter, or admin partition in the same datacenter. + ```yaml annotations: "consul.hashicorp.com/connect-service-upstreams":"[service-name].svc.[service-namespace].ns.[service-peer].peer:[port]" ``` + ```yaml annotations: "consul.hashicorp.com/connect-service-upstreams":"[service-name].svc.[service-namespace].ns.[service-partition].ap:[port]" ``` + ```yaml annotations: "consul.hashicorp.com/connect-service-upstreams":"[service-name].svc.[service-namespace].ns.[service-dc].dc:[port]" ``` - - Multiple upstreams: Delimit multiple services or upstreams with commas. You can specify any of the unlabeled, labeled, or prepared query formats when using the supported versions for the formats. + - **Unlabeled**: + The unlabeled annotation format allows you to reference any service not in a cluster peer as an upstream. You can specify a Consul Enterprise namespace. You can also specify an admin partition in the same datacenter or a WAN-federated datacenter. Unlike the labeled annotation, you can also reference a prepared query as an upstream. + + - Service name: Place the service name at the beginning of the annotation to specify the upstream service. You also have the option to append the WAN federated datacenter where the service is deployed. + + ```yaml + annotations: + "consul.hashicorp.com/connect-service-upstreams":"[service-name]:[port]:[optional datacenter]" + ``` + + - Namespace: Upstream services may be running in a different namespace. Place + the upstream namespace after the service name. For additional details about configuring the injector, refer to [Consul Enterprise namespaces](#consul-enterprise-namespaces) . + + ```yaml + annotations: + "consul.hashicorp.com/connect-service-upstreams":"[service-name].[service-namespace]:[port]:[optional datacenter]" + ``` + + If the namespace is not specified, the annotation defaults to the namespace of the source service. + Consul Enterprise v1.7 and older interprets the value placed in the namespace position as part of the service name. + + - Admin partitions: Upstream services may be running in a different + partition. When specifying a partition, you must also specify a namespace. Place the partition name after the namespace. If you specify the name of the datacenter, it must be the local datacenter. Communicating across partitions using this method is only supported within a + datacenter. For cross partition communication across datacenters, [establish a cluster + peering connection](/consul/docs/k8s/connect/cluster-peering/usage/establish-peering) and set the upstream with a labeled annotation format. + + ```yaml + annotations: + "consul.hashicorp.com/connect-service-upstreams":"[service-name].[service-namespace].[service-partition]:[port]:[optional datacenter]" + ``` + + - Prepared queries: To reference a [prepared query](/consul/api-docs/query) in an upstream annotation, prepend the annotation + with `prepared_query` and then invoke the name of the query. + + ```yaml + annotations: + 'consul.hashicorp.com/connect-service-upstreams': 'prepared_query:[query name]:[port]' + ``` + + - **Multiple upstreams**: Delimit multiple services or upstreams with commas. You can specify any of the unlabeled, labeled, or prepared query formats when using the supported versions for the formats. ```yaml annotations: @@ -172,6 +196,13 @@ The following Kubernetes resource annotations could be used on a pod to control consul.hashicorp.com/kubernetes-service: 'service-name-to-use' ``` +- `consul.hashicorp.com/service-weight:` - Configure ability to support weighted loadbalancing by service annotation for Catalog Sync. The integer provided will be applied as a weight for the `passing` state for the health of the service. See [weights](/consul/docs/services/configuration/services-configuration-reference#weights) in service configuration for more information on how this is leveraged for services in the Catalog. + + ```yaml + annotations: + consul.hashicorp.com/service-weight: 10 + ``` + - `consul.hashicorp.com/service-tags` - A comma separated list of tags that will be applied to the Consul service and its sidecar. @@ -246,7 +277,7 @@ The following Kubernetes resource annotations could be used on a pod to control "consul.hashicorp.com/consul-sidecar-user-volume-mount": "[{\"name\": \"secrets-store-mount\", \"mountPath\": \"/mnt/secrets-store\"}]" ``` -## Labels +### Labels Resource labels could be used on a Kubernetes service to control connect-inject behavior. @@ -257,3 +288,45 @@ Resource labels could be used on a Kubernetes service to control connect-inject registration to ignore all services except for the one which should be used for routing requests using Consul. +## Service Sync + +### Annotations + +The following Kubernetes resource annotations could be used on a pod to [Service Sync](https://developer.hashicorp.com/consul/docs/k8s/service-sync) behavior: + +- `consul.hashicorp.com/service-sync`: If this is set to `true`, then the Kubernetes service is explicitly configured to be synced to Consul. + + ```yaml + annotations: + 'consul.hashicorp.com/service-sync': 'true' + ``` + +- `consul.hashicorp.com/service-port`: Configures the port to register to the Consul Catalog for the Kubernetes service. The annotation value may be a name of a port (recommended) or an exact port value. Refer to [service ports](https://developer.hashicorp.com/consul/docs/k8s/service-sync#service-ports) for more information. + + ```yaml + annotations: + 'consul.hashicorp.com/service-port': 'http' + ``` + +- `consul.hashicorp.com/service-tags`: A comma separated list of strings (without whitespace) to use for registering tags to the service registered to Consul. These custom tags automatically include the `k8s` tag which can't be disabled. + + ```yaml + annotations: + 'consul.hashicorp.com/service-tags': 'primary,foo' + ``` + +- `consul.hashicorp.com/service-meta-KEY`: A map for specifying service metadata for Consul services. The "KEY" below can be set to any key. This allows you to set multiple meta values. + + ```yaml + annotations: + 'consul.hashicorp.com/service-meta-KEY': 'value' + ``` + +- `consul.hashicorp.com/service-weight:` - Configures ability to support weighted loadbalancing by service annotation for Catalog Sync. The integer provided will be applied as a weight for the `passing` state for the health of the service. Refer to [weights](/consul/docs/services/configuration/services-configuration-reference#weights) in service configuration for more information on how this is leveraged for services in the Consul catalog. + + ```yaml + annotations: + consul.hashicorp.com/service-weight: 10 + ``` + + diff --git a/website/content/docs/k8s/architecture.mdx b/website/content/docs/k8s/architecture.mdx index 6c4da9b96b92..568bd4994c81 100644 --- a/website/content/docs/k8s/architecture.mdx +++ b/website/content/docs/k8s/architecture.mdx @@ -2,15 +2,17 @@ layout: docs page_title: Consul on Kubernetes Control Plane Architecture description: >- - When running on Kubernetes, Consul’s control plane architecture does not change significantly. Server agents are deployed as a StatefulSet with a persistent volume, while client agents run as a k8s DaemonSet with an exposed API port. + When running on Kubernetes, Consul’s control plane architecture does not change significantly. Server agents are deployed as a StatefulSet with a persistent volume, while client agents can run as a k8s DaemonSet with an exposed API port or be omitted with Consul Dataplanes. --- - # Architecture -This topic describes the architecture, components, and resources associated with Consul deployments to Kubernetes. Consul employs the same architectural design on Kubernetes as it does with other platforms (see [Architecture](/docs/architecture)), but Kubernetes provides additional benefits that make operating a Consul cluster easier. +This topic describes the architecture, components, and resources associated with Consul deployments to Kubernetes. Consul employs the same architectural design on Kubernetes as it does with other platforms, but Kubernetes provides additional benefits that make operating a Consul cluster easier. Refer to [Consul Architecture](/docs/architecture) for more general information on Consul's architecture. -Refer to the standard [production deployment guide](https://learn.hashicorp.com/consul/datacenter-deploy/deployment-guide) for important information, regardless of the deployment platform. +> **For more specific guidance:** +> - For guidance on datacenter design, refer to [Consul and Kubernetes Reference Architecture](/consul/tutorials/kubernetes-production/kubernetes-reference-architecture). +> - For step-by-step deployment guidance, refer to [Consul and Kubernetes Deployment Guide](/consul/tutorials/kubernetes-production/kubernetes-deployment-guide). +> - For non-Kubernetes guidance, refer to the standard [production deployment guide](/consul/tutorials/production-deploy/deployment-guide). ## Server Agents @@ -35,32 +37,12 @@ Volume Claims when a [StatefulSet is deleted](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-storage), so this must done manually when removing servers. -## Client Agents - -The client agents are run as a **DaemonSet**. This places one agent -(within its own pod) on each Kubernetes node. -The clients expose the Consul HTTP API via a static port (8500) -bound to the host port. This enables all other pods on the node to connect -to the node-local agent using the host IP that can be retrieved via the -Kubernetes downward API. See -[accessing the Consul HTTP API](/docs/k8s/installation/install#accessing-the-consul-http-api) -for an example. +## Consul Dataplane -We do not use a **NodePort** Kubernetes service because requests to node ports get randomly routed -to any pod in the service and we need to be able to route directly to the Consul -client running on our node. +By default, Consul on Kubernetes uses an alternate service mesh configuration that injects sidecars without client agents. _Consul Dataplane_ manages Envoy proxies and leaves responsibility for other functions to the orchestrator, which removes the need to run client agents on every node. --> **Note:** There is no way to bind to a local-only -host port. Therefore, any other node can connect to the agent. This should be -considered for security. For a properly production-secured agent with TLS -and ACLs, this is safe. +![Diagram of Consul Dataplanes in Kubernetes deployment](/img/k8s-dataplanes-architecture.png) -We run Consul clients as a **DaemonSet** instead of running a client in each -application pod as a sidecar because this would turn -a pod into a "node" in Consul and also causes an explosion of resource usage -since every pod needs a Consul agent. Service registration should be handled via the -catalog syncing feature with Services rather than pods. +Refer to [Simplified Service Mesh with Consul Dataplanes](/docs/connect/dataplane) for more information. --> **Note:** Due to a limitation of anti-affinity rules with DaemonSets, -a client-mode agent runs alongside server-mode agents in Kubernetes. This -duplication wastes some resources, but otherwise functions perfectly fine. +Consul Dataplane is the default proxy manager in Consul on Kubernetes 1.14 and later. If you are on Consul 1.13 or older, refer to [upgrading to Consul Dataplane](/docs/k8s/upgrade#upgrading-to-consul-dataplanes) for specific upgrade instructions. diff --git a/website/content/docs/k8s/compatibility.mdx b/website/content/docs/k8s/compatibility.mdx index 7938e57427bb..8698c8903fcd 100644 --- a/website/content/docs/k8s/compatibility.mdx +++ b/website/content/docs/k8s/compatibility.mdx @@ -9,19 +9,25 @@ description: >- For every release of Consul on Kubernetes, a Helm chart, `consul-k8s-control-plane` binary and a `consul-k8s` CLI binary is built and distributed through a single version. When deploying via Helm, the recommended best path for upgrading Consul on Kubernetes, is to upgrade using the same `consul-k8s-control-plane` version as the Helm Chart, as the Helm Chart and Control Plane binary are tightly coupled. -## Supported Consul versions +## Supported Consul and Kubernetes versions -Consul Kubernetes versions all of its components (`consul-k8s` CLI, `consul-k8s-control-plane`, and Helm chart) with a single semantic version. When installing or upgrading to a specific versions, ensure that you are using the correct Consul version with the compatible `consul-k8s` helm chart and/or CLI. +Consul Kubernetes versions all of its components (`consul-k8s` CLI, `consul-k8s-control-plane`, and Helm chart) with a single semantic version. When installing or upgrading to a specific versions, ensure that you are using the correct Consul version with the compatible Helm chart or `consul-k8s` CLI. -| Consul Version | Compatible consul-k8s Versions | -| -------------- | -------------------------------- | -| 1.13.x | 0.47.0 - latest | -| 1.12.x | 0.43.0 - latest | -| 1.11.x | 0.39.0 - 0.42.0, 0.44.0 - latest | +| Consul version | Compatible `consul-k8s` versions | Compatible Kubernetes versions | +| -------------- | -------------------------------- | -------------------------------| +| 1.14.x | 1.0.x | 1.22.x - 1.25.x | +| 1.13.x | 0.49.x | 1.21.x - 1.24.x | +| 1.12.x | 0.43.0 - 0.49.x | 1.19.x - 1.22.x | + +### Version-specific upgrade requirements + +As of Consul v1.14.0, Kubernetes deployments use [Consul Dataplane](/consul/docs/connect/dataplane) instead of client agents. If you upgrade Consul from a version that uses client agents to a version that uses dataplanes, you must follow specific steps to update your Helm chart and remove client agents from the existing deployment. Refer to [Upgrading to Consul Dataplane](/consul/docs/k8s/upgrade#upgrading-to-consul-dataplane) for more information. + +The v1.0.0 release of the Consul on Kubernetes Helm chart also introduced a change to the [`externalServers[].hosts` parameter](/consul/docs/k8s/helm#v-externalservers-hosts). Previously, you were able to enter a provider lookup as a string in this field. Now, you must include `exec=` at the start of a string containing a provider lookup. Otherwise, the string is treated as a DNS name. Refer to the [`go-netaddrs` library and command line tool](https://github.com/hashicorp/go-netaddrs) for more information. ## Supported Envoy versions -Supported versions of Envoy for Consul versions are also found in [Envoy - Supported Versions](/docs/connect/proxies/envoy#supported-versions). The recommended best practice is to use the default version of Envoy that is provided in the Helm values.yml file, as that is the version that has been tested with the default Consul and Consul Kubernetes binaries for a given Helm chart. +Supported versions of Envoy and `consul-dataplane` (for Consul K8s 1.0 and above) for Consul versions are also found in [Envoy - Supported Versions](/docs/connect/proxies/envoy#supported-versions). Starting with `consul-k8s` 1.0, `consul-dataplane` will include a bundled version of Envoy. The recommended best practice is to use the default version of Envoy or `consul-dataplane` that is provided in the Helm `values.yaml` file, as that is the version that has been tested with the default Consul and Consul Kubernetes binaries for a given Helm chart. ## Vault as a Secrets Backend compatibility @@ -33,7 +39,7 @@ Starting with Consul K8s 0.39.0 and Consul 1.11.x, Consul Kubernetes supports th ## Platform specific compatibility notes -### Red Hat OpenShift +### Red Hat OpenShift Consul Kubernetes delivered Red Hat OpenShift support starting with Consul Helm chart version 0.25.0 for Consul 1.8.4. Please note the following details regarding OpenShift support. @@ -45,6 +51,6 @@ Consul Kubernetes delivered Red Hat OpenShift support starting with Consul Helm Consul Kubernetes is [certified](https://marketplace.cloud.vmware.com/services/details/hashicorp-consul-1?slug=true) for both VMware Tanzu Kubernetes Grid, and VMware Tanzu Kubernetes Integrated Edition. - Tanzu Kubernetes Grid is certified for version 1.3.0 and above. Only Calico is supported as the CNI Plugin. -- Tanzu Kubernetes Grid Integrated Edition is supported for version 1.11.1 and above. [NSX-T CNI Plugin v3.1.2](https://docs.vmware.com/en/VMware-NSX-T-Data-Center/3.1/rn/NSX-Container-Plugin-312-Release-Notes.html) and greater should be used and configured with the `enable_hostport_snat` setting set to `true`. +- Tanzu Kubernetes Grid Integrated Edition is supported for version 1.11.1 and above. **NOTE:** When deploying Consul K8s 0.49.x and below, [NSX-T CNI Plugin v3.1.2](https://docs.vmware.com/en/VMware-NSX-T-Data-Center/3.1/rn/NSX-Container-Plugin-312-Release-Notes.html) and greater should be used and configured with the `enable_hostport_snat` setting set to `true`. diff --git a/website/content/docs/k8s/connect/cluster-peering/tech-specs.mdx b/website/content/docs/k8s/connect/cluster-peering/tech-specs.mdx new file mode 100644 index 000000000000..b984e9abde08 --- /dev/null +++ b/website/content/docs/k8s/connect/cluster-peering/tech-specs.mdx @@ -0,0 +1,180 @@ +--- +layout: docs +page_title: Cluster Peering on Kubernetes Technical Specifications +description: >- + In Kubernetes deployments, cluster peering connections interact with mesh gateways, sidecar proxies, exported services, and ACLs. Learn about requirements specific to k8s, including required Helm values and CRDs. +--- + +# Cluster peering on Kubernetes technical specifications + +This reference topic describes the technical specifications associated with using cluster peering in your Kubernetes deployments. These specifications include [required Helm values](#helm-requirements) and [required custom resource definitions (CRDs)](#crd-requirements), as well as required Consul components and their configurations. + +For cluster peering requirements in non-Kubernetes deployments, refer to [cluster peering technical specifications](/consul/docs/connect/cluster-peering/tech-specs). + +## General Requirements + +To use cluster peering features, make sure your Consul environment meets the following prerequisites: + +- Consul v1.14 or higher +- Consul on Kubernetes v1.0.0 or higher +- At least two Kubernetes clusters + +In addition, the following service mesh components are required in order to establish cluster peering connections: + +- [Helm](#helm-requirements) +- [Custom resource definitions (CRD)](#crd-requirements) +- [Mesh gateways](#mesh-gateway-requirements) +- [Exported services](#exported-service-requirements) +- [ACLs](#acl-requirements) + +## Helm requirements + + Mesh gateways are required when establishing cluster peering connections. The following values must be set in the Helm chart to enable mesh gateways: + +- [`global.tls.enabled = true`](/consul/docs/k8s/helm#v-global-tls-enabled) +- [`meshGateway.enabled = true`](/consul/docs/k8s/helm#v-meshgateway-enabled) + +Refer to the following example Helm configuration: + + + +```yaml +global: + name: consul + image: "hashicorp/consul:1.14.1" + peering: + enabled: true + tls: + enabled: true +meshGateway: + enabled: true +``` + + + +After mesh gateways are enabled in the Helm chart, you can separately [configure Mesh CRDs](#mesh-gateway-configuration-for-kubernetes). + +## CRD requirements + +You must create the following CRDs in order to establish a peering connection: + +- `PeeringAcceptor`: Generates a peering token and accepts an incoming peering connection. +- `PeeringDialer`: Uses a peering token to make an outbound peering connection with the cluster that generated the token. + +Refer to the following example CRDs: + + + + + +```yaml +apiVersion: consul.hashicorp.com/v1alpha1 +kind: PeeringAcceptor +metadata: + name: cluster-02 ## The name of the peer you want to connect to +spec: + peer: + secret: + name: "peering-token" + key: "data" + backend: "kubernetes" +``` + + + + + +```yaml +apiVersion: consul.hashicorp.com/v1alpha1 +kind: PeeringDialer +metadata: + name: cluster-01 ## The name of the peer you want to connect to +spec: + peer: + secret: + name: "peering-token" + key: "data" + backend: "kubernetes" +``` + + + + +## Mesh gateway requirements + +Mesh gateways are required for routing service mesh traffic between partitions with cluster peering connections. Consider the following general requirements for mesh gateways when using cluster peering: + +- A cluster requires a registered mesh gateway in order to export services to peers. +- For Enterprise, this mesh gateway must also be registered in the same partition as the exported services and their `exported-services` configuration entry. +- To use the `local` mesh gateway mode, you must register a mesh gateway in the importing cluster. + +In addition, you must define the `Proxy.Config` settings using opaque parameters compatible with your proxy. Refer to the [Gateway options](/consul/docs/connect/proxies/envoy#gateway-options) and [Escape-hatch Overrides](/consul/docs/connect/proxies/envoy#escape-hatch-overrides) documentation for additional Envoy proxy configuration information. + +### Mesh gateway modes + +By default, all cluster peering connections use mesh gateways in [remote mode](/consul/docs/connect/gateways/mesh-gateway/service-to-service-traffic-wan-datacenters#remote). Be aware of these additional requirements when changing a mesh gateway's mode. + +- For mesh gateways that connect peered clusters, you can set the `mode` as either `remote` or `local`. +- The `none` mode is invalid for mesh gateways with cluster peering connections. + +Refer to [mesh gateway modes](/consul/docs/connect/gateways/mesh-gateway#modes) for more information. + +### Mesh gateway configuration for Kubernetes + +Mesh gateways are required for cluster peering connections. Complete the following steps to add mesh gateways to your deployment so that you can establish cluster peering connections: + +1. In `cluster-01` create the `Mesh` custom resource with `peeringThroughMeshGateways` set to `true`. + + + + ```yaml + apiVersion: consul.hashicorp.com/v1alpha1 + kind: Mesh + metadata: + name: mesh + spec: + peering: + peerThroughMeshGateways: true + ``` + + + +1. Apply the mesh gateway to `cluster-01`. Replace `CLUSTER1_CONTEXT` to target the first Consul cluster. + + ```shell-session + $ kubectl --context $CLUSTER1_CONTEXT apply -f mesh.yaml + ``` + +1. Repeat the process to create and apply a mesh gateway with cluster peering enabled to `cluster-02`. Replace `CLUSTER2_CONTEXT` to target the second Consul cluster. + + + + ```yaml + apiVersion: consul.hashicorp.com/v1alpha1 + kind: Mesh + metadata: + name: mesh + spec: + peering: + peerThroughMeshGateways: true + ``` + + + + ```shell-session + $ kubectl --context $CLUSTER2_CONTEXT apply -f mesh.yaml + ``` + +## Exported service requirements + +The `exported-services` CRD is required in order for services to communicate across partitions with cluster peering connections. + +Refer to the [`exported-services` configuration entry](/consul/docs/connect/config-entries/exported-services) reference for more information. + +## ACL requirements + +If ACLs are enabled, you must add tokens to grant the following permissions: + +- Grant `service:write` permissions to services that define mesh gateways in their server definition. +- Grant `service:read` permissions for all services on the partition. +- Grant `mesh:write` permissions to the mesh gateways that participate in cluster peering connections. This permission allows a leaf certificate to be issued for mesh gateways to terminate TLS sessions for HTTP requests. \ No newline at end of file diff --git a/website/content/docs/k8s/connect/cluster-peering/usage/establish-peering.mdx b/website/content/docs/k8s/connect/cluster-peering/usage/establish-peering.mdx new file mode 100644 index 000000000000..19e504b95d68 --- /dev/null +++ b/website/content/docs/k8s/connect/cluster-peering/usage/establish-peering.mdx @@ -0,0 +1,453 @@ +--- +layout: docs +page_title: Establish Cluster Peering Connections on Kubernetes +description: >- + To establish a cluster peering connection on Kubernetes, generate a peering token to establish communication. Then export services and authorize requests with service intentions. +--- + +# Establish cluster peering connections on Kubernetes + +This page details the process for establishing a cluster peering connection between services in a Consul on Kubernetes deployment. + +The overall process for establishing a cluster peering connection consists of the following steps: + +1. Create a peering token in one cluster. +1. Use the peering token to establish peering with a second cluster. +1. Export services between clusters. +1. Create intentions to authorize services for peers. + +Cluster peering between services cannot be established until all four steps are complete. + +For general guidance for establishing cluster peering connections, refer to [Establish cluster peering connections](/consul/docs/connect/cluster-peering/usage/establish-cluster-peering). + +## Prerequisites + +You must meet the following requirements to use Consul's cluster peering features with Kubernetes: + +- Consul v1.14.1 or higher +- Consul on Kubernetes v1.0.0 or higher +- At least two Kubernetes clusters + +In Consul on Kubernetes, peers identify each other using the `metadata.name` values you establish when creating the `PeeringAcceptor` and `PeeringDialer` CRDs. For additional information about requirements for cluster peering on Kubernetes deployments, refer to [Cluster peering on Kubernetes technical specifications](/consul/docs/k8s/connect/cluster-peering/tech-specs). + +### Assign cluster IDs to environmental variables + +After you provision a Kubernetes cluster and set up your kubeconfig file to manage access to multiple Kubernetes clusters, you can assign your clusters to environmental variables for future use. + +1. Get the context names for your Kubernetes clusters using one of these methods: + + - Run the `kubectl config current-context` command to get the context for the cluster you are currently in. + - Run the `kubectl config get-contexts` command to get all configured contexts in your kubeconfig file. + +1. Use the `kubectl` command to export the Kubernetes context names and then set them to variables. For more information on how to use kubeconfig and contexts, refer to the [Kubernetes docs on configuring access to multiple clusters](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/). + + ```shell-session + $ export CLUSTER1_CONTEXT= + $ export CLUSTER2_CONTEXT= + ``` + +### Update the Helm chart + +To use cluster peering with Consul on Kubernetes deployments, update the Helm chart with [the required values](/consul/docs/k8s/connect/cluster-peering/tech-specs#helm-requirements). After updating the Helm chart, you can use the `consul-k8s` CLI to apply `values.yaml` to each cluster. + +1. In `cluster-01`, run the following commands: + + ```shell-session + $ export HELM_RELEASE_NAME1=cluster-01 + ``` + + ```shell-session + $ helm install ${HELM_RELEASE_NAME1} hashicorp/consul --create-namespace --namespace consul --version "1.0.1" --values values.yaml --set global.datacenter=dc1 --kube-context $CLUSTER1_CONTEXT + ``` + +1. In `cluster-02`, run the following commands: + + ```shell-session + $ export HELM_RELEASE_NAME2=cluster-02 + ``` + + ```shell-session + $ helm install ${HELM_RELEASE_NAME2} hashicorp/consul --create-namespace --namespace consul --version "1.0.1" --values values.yaml --set global.datacenter=dc2 --kube-context $CLUSTER2_CONTEXT + ``` + +### Configure the mesh gateway mode for traffic between services + +In Kubernetes deployments, you can configure mesh gateways to use `local` mode so that a service dialing a service in a remote peer dials the remote mesh gateway instead of the local mesh gateway. To configure the mesh gateway mode so that this traffic always leaves through the local mesh gateway, you can use the `ProxyDefaults` CRD. + +1. In `cluster-01` apply the following `ProxyDefaults` CRD to configure the mesh gateway mode. + + + + ```yaml + apiVersion: consul.hashicorp.com/v1alpha1 + kind: ProxyDefaults + metadata: + name: global + spec: + meshGateway: + mode: local + ``` + + + + ```shell-session + $ kubectl --context $CLUSTER1_CONTEXT apply -f proxy-defaults.yaml + ``` + +1. In `cluster-02` apply the following `ProxyDefaults` CRD to configure the mesh gateway mode. + + + + ```yaml + apiVersion: consul.hashicorp.com/v1alpha1 + kind: ProxyDefaults + metadata: + name: global + spec: + meshGateway: + mode: local + ``` + + + + ```shell-session + $ kubectl --context $CLUSTER2_CONTEXT apply -f proxy-defaults.yaml + ``` + +## Create a peering token + +To begin the cluster peering process, generate a peering token in one of your clusters. The other cluster uses this token to establish the peering connection. + +Every time you generate a peering token, a single-use secret for establishing the secret is embedded in the token. Because regenerating a peering token invalidates the previously generated secret, you must use the most recently created token to establish peering connections. + +1. In `cluster-01`, create the `PeeringAcceptor` custom resource. To ensure cluster peering connections are secure, the `metadata.name` field cannot be duplicated. Refer to the peer by a specific name. + + + + ```yaml + apiVersion: consul.hashicorp.com/v1alpha1 + kind: PeeringAcceptor + metadata: + name: cluster-02 ## The name of the peer you want to connect to + spec: + peer: + secret: + name: "peering-token" + key: "data" + backend: "kubernetes" + ``` + + + +1. Apply the `PeeringAcceptor` resource to the first cluster. + + ```shell-session + $ kubectl --context $CLUSTER1_CONTEXT apply --filename acceptor.yaml + ``` + +1. Save your peering token so that you can export it to the other cluster. + + ```shell-session + $ kubectl --context $CLUSTER1_CONTEXT get secret peering-token --output yaml > peering-token.yaml + ``` + +## Establish a connection between clusters + +Next, use the peering token to establish a secure connection between the clusters. + +1. Apply the peering token to the second cluster. + + ```shell-session + $ kubectl --context $CLUSTER2_CONTEXT apply --filename peering-token.yaml + ``` + +1. In `cluster-02`, create the `PeeringDialer` custom resource. To ensure cluster peering connections are secure, the `metadata.name` field cannot be duplicated. Refer to the peer by a specific name. + + + + ```yaml + apiVersion: consul.hashicorp.com/v1alpha1 + kind: PeeringDialer + metadata: + name: cluster-01 ## The name of the peer you want to connect to + spec: + peer: + secret: + name: "peering-token" + key: "data" + backend: "kubernetes" + ``` + + + +1. Apply the `PeeringDialer` resource to the second cluster. + + ```shell-session + $ kubectl --context $CLUSTER2_CONTEXT apply --filename dialer.yaml + ``` + +## Export services between clusters + +After you establish a connection between the clusters, you need to create an `exported-services` CRD that defines the services that are available to another admin partition. + +While the CRD can target admin partitions either locally or remotely, clusters peering always exports services to remote admin partitions. Refer to [exported service consumers](/consul/docs/connect/config-entries/exported-services#consumers-1) for more information. + + +1. For the service in `cluster-02` that you want to export, add the `"consul.hashicorp.com/connect-inject": "true"` annotation to your service's pods prior to deploying. The annotation allows the workload to join the mesh. It is highlighted in the following example: + + + + ```yaml + # Service to expose backend + apiVersion: v1 + kind: Service + metadata: + name: backend + spec: + selector: + app: backend + ports: + - name: http + protocol: TCP + port: 80 + targetPort: 9090 + --- + apiVersion: v1 + kind: ServiceAccount + metadata: + name: backend + --- + # Deployment for backend + apiVersion: apps/v1 + kind: Deployment + metadata: + name: backend + labels: + app: backend + spec: + replicas: 1 + selector: + matchLabels: + app: backend + template: + metadata: + labels: + app: backend + annotations: + "consul.hashicorp.com/connect-inject": "true" + spec: + serviceAccountName: backend + containers: + - name: backend + image: nicholasjackson/fake-service:v0.22.4 + ports: + - containerPort: 9090 + env: + - name: "LISTEN_ADDR" + value: "0.0.0.0:9090" + - name: "NAME" + value: "backend" + - name: "MESSAGE" + value: "Response from backend" + ``` + + + +1. Deploy the `backend` service to the second cluster. + + ```shell-session + $ kubectl --context $CLUSTER2_CONTEXT apply --filename backend.yaml + ``` + +1. In `cluster-02`, create an `ExportedServices` custom resource. The name of the peer that consumes the service should be identical to the name set in the `PeeringDialer` CRD. + + + + ```yaml + apiVersion: consul.hashicorp.com/v1alpha1 + kind: ExportedServices + metadata: + name: default ## The name of the partition containing the service + spec: + services: + - name: backend ## The name of the service you want to export + consumers: + - peer: cluster-01 ## The name of the peer that receives the service + ``` + + + +1. Apply the `ExportedServices` resource to the second cluster. + + ```shell-session + $ kubectl --context $CLUSTER2_CONTEXT apply --filename exported-service.yaml + ``` + +## Authorize services for peers + +Before you can call services from peered clusters, you must set service intentions that authorize those clusters to use specific services. Consul prevents services from being exported to unauthorized clusters. + +1. Create service intentions for the second cluster. The name of the peer should match the name set in the `PeeringDialer` CRD. + + + + ```yaml + apiVersion: consul.hashicorp.com/v1alpha1 + kind: ServiceIntentions + metadata: + name: backend-deny + spec: + destination: + name: backend + sources: + - name: "*" + action: deny + - name: frontend + action: allow + peer: cluster-01 ## The peer of the source service + ``` + + + +1. Apply the intentions to the second cluster. + + + + ```shell-session + $ kubectl --context $CLUSTER2_CONTEXT apply --filename intention.yaml + ``` + + + +1. Add the `"consul.hashicorp.com/connect-inject": "true"` annotation to your service's pods before deploying the workload so that the services in `cluster-01` can dial `backend` in `cluster-02`. To dial the upstream service from an application, configure the application so that that requests are sent to the correct DNS name as specified in [Service Virtual IP Lookups](/consul/docs/services/discovery/dns-static-lookups#service-virtual-ip-lookups). In the following example, the annotation that allows the workload to join the mesh and the configuration provided to the workload that enables the workload to dial the upstream service using the correct DNS name is highlighted. [Service Virtual IP Lookups for Consul Enterprise](/consul/docs/services/discovery/dns-static-lookups#service-virtual-ip-lookups-for-consul-enterprise) details how you would similarly format a DNS name including partitions and namespaces. + + + + ```yaml + # Service to expose frontend + apiVersion: v1 + kind: Service + metadata: + name: frontend + spec: + selector: + app: frontend + ports: + - name: http + protocol: TCP + port: 9090 + targetPort: 9090 + --- + apiVersion: v1 + kind: ServiceAccount + metadata: + name: frontend + --- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: frontend + labels: + app: frontend + spec: + replicas: 1 + selector: + matchLabels: + app: frontend + template: + metadata: + labels: + app: frontend + annotations: + "consul.hashicorp.com/connect-inject": "true" + spec: + serviceAccountName: frontend + containers: + - name: frontend + image: nicholasjackson/fake-service:v0.22.4 + securityContext: + capabilities: + add: ["NET_ADMIN"] + ports: + - containerPort: 9090 + env: + - name: "LISTEN_ADDR" + value: "0.0.0.0:9090" + - name: "UPSTREAM_URIS" + value: "http://backend.virtual.cluster-02.consul" + - name: "NAME" + value: "frontend" + - name: "MESSAGE" + value: "Hello World" + - name: "HTTP_CLIENT_KEEP_ALIVES" + value: "false" + ``` + + + +1. Apply the service file to the first cluster. + + ```shell-session + $ kubectl --context $CLUSTER1_CONTEXT apply --filename frontend.yaml + ``` + +1. Run the following command in `frontend` and then check the output to confirm that you peered your clusters successfully. + + ```shell-session + $ kubectl --context $CLUSTER1_CONTEXT exec -it $(kubectl --context $CLUSTER1_CONTEXT get pod -l app=frontend -o name) -- curl localhost:9090 + ``` + + + + ```json + { + "name": "frontend", + "uri": "/", + "type": "HTTP", + "ip_addresses": [ + "10.16.2.11" + ], + "start_time": "2022-08-26T23:40:01.167199", + "end_time": "2022-08-26T23:40:01.226951", + "duration": "59.752279ms", + "body": "Hello World", + "upstream_calls": { + "http://backend.virtual.cluster-02.consul": { + "name": "backend", + "uri": "http://backend.virtual.cluster-02.consul", + "type": "HTTP", + "ip_addresses": [ + "10.32.2.10" + ], + "start_time": "2022-08-26T23:40:01.223503", + "end_time": "2022-08-26T23:40:01.224653", + "duration": "1.149666ms", + "headers": { + "Content-Length": "266", + "Content-Type": "text/plain; charset=utf-8", + "Date": "Fri, 26 Aug 2022 23:40:01 GMT" + }, + "body": "Response from backend", + "code": 200 + } + }, + "code": 200 + } + ``` + + + +### Authorize service reads with ACLs + +If ACLs are enabled on a Consul cluster, sidecar proxies that access exported services as an upstream must have an ACL token that grants read access. + +Read access to all imported services is granted using either of the following rules associated with an ACL token: + +- `service:write` permissions for any service in the sidecar's partition. +- `service:read` and `node:read` for all services and nodes, respectively, in sidecar's namespace and partition. + +For Consul Enterprise, the permissions apply to all imported services in the service's partition. These permissions are satisfied when using a [service identity](/consul/docs/security/acl/acl-roles#service-identities). + +Refer to [Reading servers](/consul/docs/connect/config-entries/exported-services#reading-services) in the `exported-services` configuration entry documentation for example rules. + +For additional information about how to configure and use ACLs, refer to [ACLs system overview](/consul/docs/security/acl). \ No newline at end of file diff --git a/website/content/docs/k8s/connect/cluster-peering/usage/l7-traffic.mdx b/website/content/docs/k8s/connect/cluster-peering/usage/l7-traffic.mdx new file mode 100644 index 000000000000..956298fe3cd9 --- /dev/null +++ b/website/content/docs/k8s/connect/cluster-peering/usage/l7-traffic.mdx @@ -0,0 +1,75 @@ +--- +layout: docs +page_title: Manage L7 Traffic With Cluster Peering on Kubernetes +description: >- + Combine service resolver configurations with splitter and router configurations to manage L7 traffic in Consul on Kubernetes deployments with cluster peering connections. Learn how to define dynamic traffic rules to target peers for redirects in k8s. +--- + +# Manage L7 traffic with cluster peering on Kubernetes + +This usage topic describes how to configure the `service-resolver` custom resource definition (CRD) to set up and manage L7 traffic between services that have an existing cluster peering connection in Consul on Kubernetes deployments. + +For general guidance for managing L7 traffic with cluster peering, refer to [Manage L7 traffic with cluster peering](/consul/docs/connect/cluster-peering/usage/peering-traffic-management). + +## Service resolvers for redirects and failover + +When you use cluster peering to connect datacenters through their admin partitions, you can use [dynamic traffic management](/consul/docs/connect/l7-traffic) to configure your service mesh so that services automatically forward traffic to services hosted on peer clusters. + +However, the `service-splitter` and `service-router` CRDs do not natively support directly targeting a service instance hosted on a peer. Before you can split or route traffic to a service on a peer, you must define the service hosted on the peer as an upstream service by configuring a failover in a `service-resolver` CRD. Then, you can set up a redirect in a second service resolver to interact with the peer service by name. + +For more information about formatting, updating, and managing configuration entries in Consul, refer to [How to use configuration entries](/consul/docs/agent/config-entries). + +## Configure dynamic traffic between peers + +To configure L7 traffic management behavior in deployments with cluster peering connections, complete the following steps in order: + +1. Define the peer cluster as a failover target in the service resolver configuration. + + The following example updates the [`service-resolver` CRD](/consul/docs/connect/config-entries/) in `cluster-01` so that Consul redirects traffic intended for the `frontend` service to a backup instance in peer `cluster-02` when it detects multiple connection failures. + + ```yaml + apiVersion: consul.hashicorp.com/v1alpha1 + kind: ServiceResolver + metadata: + name: frontend + spec: + connectTimeout: 15s + failover: + '*': + targets: + - peer: 'cluster-02' + service: 'frontend' + namespace: 'default' + ``` + +1. Define the desired behavior in `service-splitter` or `service-router` CRD. + + The following example splits traffic evenly between `frontend` and `frontend-peer`: + + ```yaml + apiVersion: consul.hashicorp.com/v1alpha1 + kind: ServiceSplitter + metadata: + name: frontend + spec: + splits: + - weight: 50 + ## defaults to service with same name as configuration entry ("frontend") + - weight: 50 + service: frontend-peer + ``` + +1. Create a second `service-resolver` configuration entry on the local cluster that resolves the name of the peer service you used when splitting or routing the traffic. + + The following example uses the name `frontend-peer` to define a redirect targeting the `frontend` service on the peer `cluster-02`: + + ```yaml + apiVersion: consul.hashicorp.com/v1alpha1 + kind: ServiceResolver + metadata: + name: frontend-peer + spec: + redirect: + peer: 'cluster-02' + service: 'frontend' + ``` \ No newline at end of file diff --git a/website/content/docs/k8s/connect/cluster-peering/usage/manage-peering.mdx b/website/content/docs/k8s/connect/cluster-peering/usage/manage-peering.mdx new file mode 100644 index 000000000000..bc622fe15d38 --- /dev/null +++ b/website/content/docs/k8s/connect/cluster-peering/usage/manage-peering.mdx @@ -0,0 +1,121 @@ +--- +layout: docs +page_title: Manage Cluster Peering Connections on Kubernetes +description: >- + Learn how to list, read, and delete cluster peering connections using Consul on Kubernetes. You can also reset cluster peering connections on k8s deployments. +--- + +# Manage cluster peering connections on Kubernetes + +This usage topic describes how to manage cluster peering connections on Kubernetes deployments. + +After you establish a cluster peering connection, you can get a list of all active peering connections, read a specific peering connection's information, and delete peering connections. + +For general guidance for managing cluster peering connections, refer to [Manage L7 traffic with cluster peering](/consul/docs/connect/cluster-peering/usage/peering-traffic-management). + +## Reset a peering connection + +To reset the cluster peering connection, you need to generate a new peering token from the cluster where you created the `PeeringAcceptor` CRD. The only way to create or set a new peering token is to manually adjust the value of the annotation `consul.hashicorp.com/peering-version`. Creating a new token causes the previous token to expire. + +1. In the `PeeringAcceptor` CRD, add the annotation `consul.hashicorp.com/peering-version`. If the annotation already exists, update its value to a higher version. + + + + ```yaml + apiVersion: consul.hashicorp.com/v1alpha1 + kind: PeeringAcceptor + metadata: + name: cluster-02 + annotations: + consul.hashicorp.com/peering-version: "1" ## The peering version you want to set, must be in quotes + spec: + peer: + secret: + name: "peering-token" + key: "data" + backend: "kubernetes" + ``` + + + +1. After updating `PeeringAcceptor`, repeat all of the steps to [establish a new peering connection](/consul/docs/k8s/connect/cluster-peering/usage/establish-peering). + +## List all peering connections + +In Consul on Kubernetes deployments, you can list all active peering connections in a cluster using the Consul CLI. + +1. If necessary, [configure your CLI to interact with the Consul cluster](/consul/tutorials/get-started-kubernetes/kubernetes-gs-deploy#configure-your-cli-to-interact-with-consul-cluster). + +1. Run the [`consul peering list` CLI command](/consul/commands/peering/list). + + ```shell-session + $ consul peering list + Name State Imported Svcs Exported Svcs Meta + cluster-02 ACTIVE 0 2 env=production + cluster-03 PENDING 0 0 + ``` + +## Read a peering connection + +In Consul on Kubernetes deployments, you can get information about individual peering connections between clusters using the Consul CLI. + +1. If necessary, [configure your CLI to interact with the Consul cluster](/consul/tutorials/get-started-kubernetes/kubernetes-gs-deploy#configure-your-cli-to-interact-with-consul-cluster). + +1. Run the [`consul peering read` CLI command](/consul/commands/peering/read). + + ```shell-session + $ consul peering read -name cluster-02 + Name: cluster-02 + ID: 3b001063-8079-b1a6-764c-738af5a39a97 + State: ACTIVE + Meta: + env=production + + Peer ID: e83a315c-027e-bcb1-7c0c-a46650904a05 + Peer Server Name: server.dc1.consul + Peer CA Pems: 0 + Peer Server Addresses: + 10.0.0.1:8300 + + Imported Services: 0 + Exported Services: 2 + + Create Index: 89 + Modify Index: 89 + ``` + +## Delete peering connections + +To end a peering connection in Kubernetes deployments, delete both the `PeeringAcceptor` and `PeeringDialer` resources. + +1. Delete the `PeeringDialer` resource from the second cluster. + + ```shell-session + $ kubectl --context $CLUSTER2_CONTEXT delete --filename dialer.yaml + ``` + +1. Delete the `PeeringAcceptor` resource from the first cluster. + + ```shell-session + $ kubectl --context $CLUSTER1_CONTEXT delete --filename acceptor.yaml + ```` + +To confirm that you deleted your peering connection in `cluster-01`, query the the `/health` HTTP endpoint: + +1. Exec into the server pod for the first cluster. + + ```shell-session + $ kubectl exec -it consul-server-0 --context $CLUSTER1_CONTEXT -- /bin/sh + ``` + +1. If you've enabled ACLs, export an ACL token to access the `/health` HTP endpoint for services. The bootstrap token may be used if an ACL token is not already provisioned. + + ```shell-session + $ export CONSUL_HTTP_TOKEN= + ``` + +1. Query the the `/health` HTTP endpoint. Peered services with deleted connections should no longe appear. + + ```shell-session + $ curl "localhost:8500/v1/health/connect/backend?peer=cluster-02" + ``` \ No newline at end of file diff --git a/website/content/docs/k8s/connect/health.mdx b/website/content/docs/k8s/connect/health.mdx index 7f84608c548c..ca43e7ffa98a 100644 --- a/website/content/docs/k8s/connect/health.mdx +++ b/website/content/docs/k8s/connect/health.mdx @@ -2,7 +2,7 @@ layout: docs page_title: Configure Health Checks for Consul on Kubernetes description: >- - Kubernetes has built-in health probes you can sync with Consul's health checks to ensure service mesh traffic is routed to healthy pods. Learn how to register a TTL Health check and use mutating webhooks to redirect k8s liveness, readiness, and startup probes through Envoy proxies. + Kubernetes has built-in health probes you can sync with Consul's health checks to ensure service mesh traffic is routed to healthy pods. --- # Configure Health Checks for Consul on Kubernetes @@ -14,14 +14,17 @@ Health check synchronization with Consul is done automatically whenever `connect For each Kubernetes pod that is connect-injected the following will be configured: -1. A [TTL health check](/docs/discovery/checks#ttl) is registered within Consul. -The Consul health check's state will reflect the pod's readiness status, -which is the combination of all Kubernetes probes registered with the pod. +1. A [Consul health check](/consul/api-docs/catalog#register-entity) is registered within Consul catalog. +The Consul health check's state will reflect the pod's readiness status. -1. If the pod is utilizing [Transparent Proxy](/docs/connect/transparent-proxy) mode, the mutating webhook will mutate all `http` based Startup, Liveness, and Readiness probes in the pod to redirect through the Envoy proxy. -This is done with [`ExposePaths` configuration](/docs/connect/registration/service-registration#expose-paths-configuration-reference) for each probe so that kubelet can access the endpoint through the Envoy proxy. +1. If the pod is using [Transparent Proxy](/docs/connect/transparent-proxy) mode, +the mutating webhook will mutate all `http` based Startup, Liveness, and Readiness probes in the pod to redirect through the Envoy proxy. +This is done with +[`ExposePaths` configuration](/docs/connect/registration/service-registration#expose-paths-configuration-reference) +for each probe so that kubelet can access the endpoint through the Envoy proxy. -~> The mutation behavior can be disabled by either setting the `consul.hashicorp.com/transparent-proxy-overwrite-probes` pod annotation to `false` or the `connectInject.defaultOverwriteProbes` Helm value to `false`. +~> The mutation behavior can be disabled by either setting the `consul.hashicorp.com/transparent-proxy-overwrite-probes` +pod annotation to `false` or the `connectInject.defaultOverwriteProbes` Helm value to `false`. When readiness probes are set for a pod, the status of the pod will be reflected within Consul and will cause Consul to redirect service mesh traffic to the pod based on the pod's health. If the pod has failing health checks, Consul will no longer use diff --git a/website/content/docs/k8s/connect/index.mdx b/website/content/docs/k8s/connect/index.mdx index 1549cdf23f89..e75dca79c523 100644 --- a/website/content/docs/k8s/connect/index.mdx +++ b/website/content/docs/k8s/connect/index.mdx @@ -10,10 +10,9 @@ description: >- [Consul Service Mesh](/docs/connect) is a feature built into to Consul that enables automatic service-to-service authorization and connection encryption across your Consul services. Consul Service Mesh can be used with Kubernetes to secure pod -communication with other pods and external Kubernetes services. "Consul Connect" refers to the service mesh functionality within Consul and is used interchangeably with the name -"Consul Service Mesh." +communication with other pods and external Kubernetes services. _Consul Connect_ refers to the component in Consul that enables service mesh functionality. We sometimes use Connect to mean Consul service mesh throughout the documentation. -The Connect sidecar running Envoy can be automatically injected into pods in +Consul can automatically inject the sidecar running Envoy into pods in your cluster, making configuration for Kubernetes automatic. This functionality is provided by the [consul-k8s project](https://github.com/hashicorp/consul-k8s) and can be @@ -22,32 +21,37 @@ automatically installed and configured using the ## Usage -When the -[Connect injector is installed](/docs/k8s/connect#installation-and-configuration), -the Connect sidecar can be automatically added to all pods. This sidecar can both -accept and establish connections using Connect, enabling the pod to communicate -to clients and dependencies exclusively over authorized and encrypted -connections. +-> **Important:** As of consul-k8s `v0.26.0` and Consul Helm `v0.32.0`, a Kubernetes +service is required to run services on the Consul service mesh. --> **Note:** The examples in this section are valid and use -publicly available images. If you've installed the Connect injector, feel free -to run the examples in this section to try Connect with Kubernetes. -Please note the documentation below this section on how to properly install -and configure the Connect injector. +Installing Consul on Kubernetes with [`connect-inject` enabled](/docs/k8s/connect#installation-and-configuration) adds a sidecar to all pods. By default, it enables service mesh functionality with Consul Dataplane by injecting an Envoy proxy. You can also configure Consul to inject a client agent sidecar to connect to your service mesh. Refer to [Simplified Service Mesh with Consul Dataplane](/docs/connect/dataplane) for more information. -### Accepting Inbound Connections +### Service names -An example Deployment is shown below with Connect enabled to accept inbound -connections. Notice that the Deployment would still be fully functional without -Connect. Minimal to zero modifications are required to enable Connect in Kubernetes. -Notice also that even though we're using a Deployment here, the same configuration -would work on a Pod, a StatefulSet, or a DaemonSet. +When the service is onboarded, the name registered in Consul is set to the name of the Kubernetes Service associated with the Pod. You can use the [`consul.hashicorp.com/connect-service` annotation](/consul/docs/k8s/annotations-and-labels#consul-hashicorp-com-connect-service) to specify a custom name for the service, but if ACLs are enabled then the name of the service registered in Consul must match the Pod's `ServiceAccount` name. -This Deployment specification starts a server that responds to any -HTTP request with the static text "hello world". +### Transparent proxy mode --> **Note:** As of consul-k8s `v0.26.0` and Consul Helm `v0.32.0`, having a Kubernetes -service is **required** to run services on the Consul Service Mesh. +By default, the Consul service mesh runs in transparent proxy mode. This mode forces inbound and outbound traffic through the sidecar proxy even though the service binds to all interfaces. Transparent proxy infers the location of upstream services using Consul service intentions, and also allows you to use Kubernetes DNS as you normally would for your workloads. + +When transparent proxy mode is enabled, all service-to-service traffic is required to use mTLS. When onboarding new services to service mesh, your network may have mixed mTLS and non-mTLS traffic, which can result in broken service-to-service communication. You can temporarily enable permissive mTLS mode during the onboarding process so that existing mesh services can accept traffic from services that are not yet fully onboarded. Permissive mTLS enables sidecar proxies to access both mTLS and non-mTLS traffic. Refer to [Onboard mesh services in transparent proxy mode](/consul/docs/k8s/connect/onboarding-tproxy-mode) for additional information. + +### Kubernetes service mesh workload scenarios + +-> **Note:** A Kubernetes Service is required in order to register services on the Consul service mesh. Consul monitors the lifecyle of the Kubernetes Service and its service instances using the service object. In addition, the Kubernetes service is used to register and de-register the service from Consul's catalog. + +The following configurations are examples for registering workloads on Kubernetes into Consul's service mesh in different scenarios. Each scenario provides an example Kubernetes manifest to demonstrate how to use Consul's service mesh with a specific Kubernetes workload type. + +- [Kubernetes Pods running as a deployment](#kubernetes-pods-running-as-a-deployment) +- [Connecting to mesh-enabled Services](#connecting-to-mesh-enabled-services) +- [Kubernetes Jobs](#kubernetes-jobs) +- [Kubernetes Pods with multiple ports](#kubernetes-pods-with-multiple-ports) + +#### Kubernetes Pods running as a deployment + +The following example shows a Kubernetes configuration that specifically enables service mesh connections for the `static-server` service. Consul starts and registers a sidecar proxy that listens on port 20000 by default and proxies valid inbound connections to port 8080. + + ```yaml apiVersion: v1 @@ -98,7 +102,9 @@ spec: serviceAccountName: static-server ``` -The only change for Connect is the addition of the + + +The only change for Consul service mesh is the addition of the `consul.hashicorp.com/connect-inject` annotation. This enables injection for the Pod in this Deployment. The injector can also be [configured](/docs/k8s/connect#installation-and-configuration) @@ -130,15 +136,16 @@ The service name registered in Consul will be set to the name of the Kubernetes associated with the Pod. This can be customized with the `consul.hashicorp.com/connect-service` annotation. If using ACLs, this name must be the same as the Pod's `ServiceAccount` name. -### Connecting to Connect-Enabled Services +To establish a connection to the Pod using service mesh, a client must use another mesh proxy. The client mesh proxy will use Consul service discovery to find all available upstream proxies and their public ports. + +#### Connecting to mesh-enabled Services The example Deployment specification below configures a Deployment that is capable of establishing connections to our previous example "static-server" service. The connection to this static text service happens over an authorized and encrypted connection via Connect. --> **Note:** As of consul-k8s `v0.26.0` and Consul Helm `v0.32.0`, having a Kubernetes -Service is **required** to run services on the Consul Service Mesh. + ```yaml apiVersion: v1 @@ -184,6 +191,8 @@ spec: serviceAccountName: static-client ``` + + By default when ACLs are enabled or when ACLs default policy is `allow`, Consul will automatically configure proxies with all upstreams from the same datacenter. When ACLs are enabled with default `deny` policy, @@ -218,7 +227,95 @@ $ kubectl exec deploy/static-client -- curl --silent http://static-server/ command terminated with exit code 52 ``` -### Kubernetes Pods with Multiple ports +#### Kubernetes Jobs + +Kubernetes Jobs run pods that only make outbound requests to services on the mesh and successfully terminate when they are complete. In order to register a Kubernetes Job with the mesh, you must provide an integer value for the `consul.hashicorp.com/sidecar-proxy-lifecycle-shutdown-grace-period-seconds` annotation. Then, issue a request to the `http://127.0.0.1:20600/graceful_shutdown` API endpoint so that Kubernetes gracefully shuts down the `consul-dataplane` sidecar after the job is complete. + +Below is an example Kubernetes manifest that deploys a job correctly. + + + +```yaml +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: test-job + namespace: default +--- +apiVersion: v1 +kind: Service +metadata: + name: test-job + namespace: default +spec: + selector: + app: test-job + ports: + - port: 80 +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: test-job + namespace: default + labels: + app: test-job +spec: + template: + metadata: + annotations: + 'consul.hashicorp.com/connect-inject': 'true' + 'consul.hashicorp.com/sidecar-proxy-lifecycle-shutdown-grace-period-seconds': '5' + labels: + app: test-job + spec: + containers: + - name: test-job + image: alpine/curl:3.14 + ports: + - containerPort: 80 + command: + - /bin/sh + - -c + - | + echo "Started test job" + sleep 10 + echo "Killing proxy" + curl --max-time 2 -s -f -XPOST http://127.0.0.1:20600/graceful_shutdown + sleep 10 + echo "Ended test job" + serviceAccountName: test-job + restartPolicy: Never +``` + + + +Upon completing the job you should be able to verify that all containers are shut down within the pod. + +```shell-session +$ kubectl get pods +NAME READY STATUS RESTARTS AGE +test-job-49st7 0/2 Completed 0 3m55s +``` + +```shell-session +$ kubectl get job +NAME COMPLETIONS DURATION AGE +test-job 1/1 30s 4m31s +``` + +In addition, based on the logs emitted by the pod you can verify that the proxy was shut down before the Job completed. + +```shell-session +$ kubectl logs test-job-49st7 -c test-job +Started test job +Killing proxy +Ended test job +``` + +#### Kubernetes Pods with multiple ports + To configure a pod with multiple ports to be a part of the service mesh and receive and send service mesh traffic, you will need to add configuration so that a Consul service can be registered per port. This is because services in Consul currently support a single port per service instance. @@ -230,6 +327,9 @@ First, decide on the names for the two Consul services that will correspond to t chooses the names `web` for `8080` and `web-admin` for `9090`. Create two service accounts for `web` and `web-admin`: + + + ```yaml apiVersion: v1 kind: ServiceAccount @@ -241,7 +341,14 @@ kind: ServiceAccount metadata: name: web-admin ``` + + + + Create two Service objects for `web` and `web-admin`: + + + ```yaml apiVersion: v1 kind: Service @@ -267,12 +374,17 @@ spec: port: 80 targetPort: 9090 ``` + + + `web` will target `containerPort` `8080` and select pods labeled `app: web`. `web-admin` will target `containerPort` `9090` and will also select the same pods. ~> Kubernetes 1.24+ only In Kubernetes 1.24+ you need to [create a Kubernetes secret](https://kubernetes.io/docs/concepts/configuration/secret/#service-account-token-secrets) for each multi-port service that references the ServiceAccount, and the Kubernetes secret must have the same name as the ServiceAccount: + + ```yaml apiVersion: v1 kind: Secret @@ -291,12 +403,15 @@ metadata: type: kubernetes.io/service-account-token ``` + + Create a Deployment with any chosen name, and use the following annotations: ```yaml -consul.hashicorp.com/connect-inject: true -consul.hashicorp.com/transparent-proxy: false -consul.hashicorp.com/connect-service: web,web-admin -consul.hashicorp.com/connect-service-port: 8080,9090 +annotations: + 'consul.hashicorp.com/connect-inject': 'true' + 'consul.hashicorp.com/transparent-proxy': 'false' + 'consul.hashicorp.com/connect-service': 'web,web-admin' + 'consul.hashicorp.com/connect-service-port': '8080,9090' ``` Note that the order the ports are listed in the same order as the service names, i.e. the first service name `web` corresponds to the first port, `8080`, and the second service name `web-admin` corresponds to the second port, `9090`. @@ -306,7 +421,10 @@ The service account on the pod spec for the deployment should be set to the firs serviceAccountName: web ``` -For reference, the full deployment example could look something like the following: +The following deployment example demonstrates the required annotations for the manifest. In addition, the previous YAML manifests can also be combined into a single manifest for easier deployment. + + + ```yaml apiVersion: apps/v1 kind: Deployment @@ -348,13 +466,61 @@ spec: serviceAccountName: web ``` + + After deploying the `web` application, you can test service mesh connections by deploying the `static-client` -application with the configuration in the [previous section](#connecting-to-connect-enabled-services) and add the -following annotation to the pod template on `static-client`: +application with the configuration in the [previous section](#connecting-to-mesh-enabled-services) and add the +`consul.hashicorp.com/connect-service-upstreams: 'web:1234,web-admin:2234'` annotation to the pod template on `static-client`: + + + ```yaml -consul.hashicorp.com/connect-service-upstreams: "web:1234,web-admin:2234" +apiVersion: v1 +kind: Service +metadata: + # This name will be the service name in Consul. + name: static-client +spec: + selector: + app: static-client + ports: + - port: 80 +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: static-client +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: static-client +spec: + replicas: 1 + selector: + matchLabels: + app: static-client + template: + metadata: + name: static-client + labels: + app: static-client + annotations: + 'consul.hashicorp.com/connect-inject': 'true' + 'consul.hashicorp.com/connect-service-upstreams': 'web:1234,web-admin:2234' + spec: + containers: + - name: static-client + image: curlimages/curl:latest + # Just spin & wait forever, we'll use `kubectl exec` to demo + command: ['/bin/sh', '-c', '--'] + args: ['while true; do sleep 30; done;'] + # If ACLs are enabled, the serviceAccountName must match the Consul service name. + serviceAccountName: static-client ``` + + If you exec on to a static-client pod, using a command like: ```shell-session $ kubectl exec -it static-client-5bd667fbd6-kk6xs -- /bin/sh @@ -404,9 +570,6 @@ upgrade the installation using `helm upgrade` for existing installs or ```yaml connectInject: enabled: true - -controller: - enabled: true ``` This will configure the injector to inject when the diff --git a/website/content/docs/k8s/connect/ingress-controllers.mdx b/website/content/docs/k8s/connect/ingress-controllers.mdx index b630cde8aca4..e044bfee345a 100644 --- a/website/content/docs/k8s/connect/ingress-controllers.mdx +++ b/website/content/docs/k8s/connect/ingress-controllers.mdx @@ -90,5 +90,5 @@ above to your own uses cases. - [Traefik Consul example - kschoche](https://github.com/kschoche/traefik-consul) - [Kong and Traefik Ingress Controller examples - joatmon08](https://github.com/joatmon08/consul-k8s-ingress-controllers) -- [NGINX Ingress Controller example - dhiaayahci](https://github.com/dhiaayachi/eks-consul-ingressnginx) +- [NGINX Ingress Controller example](https://github.com/hashicorp-education/consul-k8s-nginx-ingress-controller) diff --git a/website/content/docs/k8s/connect/ingress-gateways.mdx b/website/content/docs/k8s/connect/ingress-gateways.mdx index 84aa5350da13..e0536a835e4b 100644 --- a/website/content/docs/k8s/connect/ingress-gateways.mdx +++ b/website/content/docs/k8s/connect/ingress-gateways.mdx @@ -34,8 +34,6 @@ global: name: consul connectInject: enabled: true -controller: - enabled: true ingressGateways: enabled: true gateways: @@ -268,8 +266,6 @@ global: name: consul connectInject: enabled: true -controller: - enabled: true ingressGateways: enabled: false # Set to false gateways: diff --git a/website/content/docs/k8s/connect/observability/metrics.mdx b/website/content/docs/k8s/connect/observability/metrics.mdx index a3b25e2223d9..8b80ed9e346a 100644 --- a/website/content/docs/k8s/connect/observability/metrics.mdx +++ b/website/content/docs/k8s/connect/observability/metrics.mdx @@ -7,20 +7,16 @@ description: >- # Configure Metrics for Consul on Kubernetes -Consul on Kubernetes integrates with Prometheus and Grafana to provide metrics for Consul Service Mesh. The metrics +Consul on Kubernetes integrates with Prometheus and Grafana to provide metrics for Consul service mesh. The metrics available are: -* Connect Service metrics -* Sidecar proxy metrics -* Consul agent metrics -* Ingress, Terminating and Mesh Gateway metrics +- Connect service metrics +- Sidecar proxy metrics +- Consul agent metrics +- Ingress, terminating, and mesh gateway metrics Specific sidecar proxy metrics can also be seen in the Consul UI Topology Visualization view. This section documents how to enable each of these. --> **Note:** Metrics will be supported in Consul-helm >= `0.31.0` and consul-k8s >= `0.25.0`. However, enabling the [metrics merging feature](#connect-service-and-sidecar-metrics-with-metrics-merging) with Helm value (`defaultEnableMerging`) or -annotation (`consul.hashicorp.com/enable-metrics-merging`) can only be used with Consul `1.10.0` and above. The -other metrics configuration can still be used before Consul `1.10.0`. - ## Connect Service and Sidecar Metrics with Metrics Merging Prometheus annotations are used to instruct Prometheus to scrape metrics from Pods. Prometheus annotations only support @@ -28,33 +24,40 @@ scraping from one endpoint on a Pod, so Consul on Kubernetes supports metrics me sidecar proxy metrics are merged into one endpoint. If there are no service metrics, it also supports just scraping the sidecar proxy metrics. + Connect service metrics can be configured with the Helm values nested under [`connectInject.metrics`](/docs/k8s/helm#v-connectinject-metrics). Metrics and metrics merging can be enabled by default for all connect-injected Pods with the following Helm values: + ```yaml connectInject: metrics: defaultEnabled: true # by default, this inherits from the value global.metrics.enabled defaultEnableMerging: true ``` + They can also be overridden on a per-Pod basis using the annotations `consul.hashicorp.com/enable-metrics` and `consul.hashicorp.com/enable-metrics-merging`. -~> In most cases, the default settings will be sufficient. If you are encountering issues with colliding ports or service +~> In most cases, the default settings are sufficient. If you encounter issues with colliding ports or service metrics not being merged, you may need to change the defaults. -The Prometheus annotations configure the endpoint to scrape the metrics from. As shown in the diagram, the annotations point to a listener on `0.0.0.0:20200` on the Envoy sidecar. This listener and the corresponding Prometheus annotations can be configured with the following Helm values (or overridden on a per-Pod basis with Consul annotations `consul.hashicorp.com/prometheus-scrape-port` and `consul.hashicorp.com/prometheus-scrape-path`): +The Prometheus annotations specify which endpoint to scrape the metrics from. The annotations point to a listener on `0.0.0.0:20200` on the Envoy sidecar. You can configure the listener and the corresponding Prometheus annotations using the following Helm values. Alternatively, you can specify the `consul.hashicorp.com/prometheus-scrape-port` and `consul.hashicorp.com/prometheus-scrape-path` Consul annotations to override them on a per-Pod basis: + ```yaml connectInject: metrics: defaultPrometheusScrapePort: 20200 defaultPrometheusScrapePath: "/metrics" ``` -Those Helm values will result in the following Prometheus annotations being automatically added to the Pod for scraping: + +The Helm values specified in the previous example result in the following Prometheus annotations being automatically added to the Pod for scraping: + ```yaml metadata: annotations: @@ -63,26 +66,24 @@ metadata: prometheus.io/port: "20200" ``` -When metrics alone are enabled, the listener in the diagram on `0.0.0.0:20200` would point directly at the sidecar -metrics endpoint, rather than the merged metrics endpoint. The Prometheus scraping annotations would stay the same. - -When metrics and metrics merging are *both* enabled, metrics are combined from the service and the sidecar proxy, and -exposed via a local server on the Consul sidecar for scraping. This endpoint is called the merged metrics endpoint and -defaults to `127.0.0.1:20100/stats/prometheus`. The listener will target the merged metrics endpoint in the above case. +When metrics and metrics merging are both enabled, metrics are combined from the service and the sidecar proxy, and +exposed through a local server on the Consul Dataplane sidecar for scraping. This endpoint is called the merged metrics endpoint and +defaults to `127.0.0.1:20100/stats/prometheus`. The listener targets the merged metrics endpoint in the above case. It can be configured with the following Helm values (or overridden on a per-Pod basis with -`consul.hashicorp.com/merged-metrics-port`): +`consul.hashicorp.com/merged-metrics-port`: + ```yaml connectInject: metrics: defaultMergedMetricsPort: 20100 ``` -The endpoint to scrape service metrics from can be configured only on a per-Pod basis via the Pod annotations `consul.hashicorp.com/service-metrics-port` and `consul.hashicorp.com/service-metrics-path`. If these are not configured, the service metrics port will default to the port used to register the service with Consul (`consul.hashicorp.com/connect-service-port`), which in turn defaults to the first port on the first container of the Pod. The service metrics path will default to `/metrics`. +The endpoint to scrape service metrics from can be configured only on a per-Pod basis with the Pod annotations `consul.hashicorp.com/service-metrics-port` and `consul.hashicorp.com/service-metrics-path`. If these are not configured, the service metrics port defaults to the port used to register the service with Consul (`consul.hashicorp.com/connect-service-port`), which in turn defaults to the first port on the first container of the Pod. The service metrics path defaults to `/metrics`. ## Consul Agent Metrics -Metrics from the Consul server and client Pods can be scraped via Prometheus by setting the field `global.metrics.enableAgentMetrics` to `true`. Additionally, one can configure the metrics retention time on the agents by configuring -the field `global.metrics.agentMetricsRetentionTime` which expects a duration and defaults to `"1m"`. This value must be greater than `"0m"` for the Consul servers and clients to emit metrics at all. As the Prometheus deployment currently does not support scraping TLS endpoints, agent metrics are currently *unsupported* when TLS is enabled. +Metrics from the Consul server Pods can be scraped with Prometheus by setting the field `global.metrics.enableAgentMetrics` to `true`. Additionally, one can configure the metrics retention time on the agents by configuring +the field `global.metrics.agentMetricsRetentionTime` which expects a duration and defaults to `"1m"`. This value must be greater than `"0m"` for the Consul servers to emit metrics at all. As the Prometheus deployment currently does not support scraping TLS endpoints, agent metrics are currently unsupported when TLS is enabled. ```yaml global: @@ -94,10 +95,10 @@ global: ## Gateway Metrics -Metrics from the Consul gateways, namely the Ingress Gateways, Terminating Gateways and the Mesh Gateways can be scraped -via Prometheus by setting the field `global.metrics.enableGatewayMetrics` to `true`. The gateways emit standard Envoy proxy -metrics. To ensure that the metrics are not exposed to the public internet (as Mesh and Ingress gateways can have public -IPs), their metrics endpoints are exposed on the Pod IP of the respective gateway instance, rather than on all +Metrics from the Consul ingress, terminating, and mesh gateways can be scraped +with Prometheus by setting the field `global.metrics.enableGatewayMetrics` to `true`. The gateways emit standard Envoy proxy +metrics. To ensure that the metrics are not exposed to the public internet, as mesh and ingress gateways can have public +IPs, their metrics endpoints are exposed on the Pod IP of the respective gateway instance, rather than on all interfaces on `0.0.0.0`. ```yaml @@ -109,16 +110,16 @@ global: ## Metrics in the UI Topology Visualization -Consul's built-in UI has a topology visualization for services part of the Consul Service Mesh. The topology visualization has the ability to fetch basic metrics from a metrics provider for each service and display those metrics as part of the [topology visualization](/docs/connect/observability/ui-visualization). +Consul's built-in UI has a topology visualization for services that are part of the Consul service mesh. The topology visualization has the ability to fetch basic metrics from a metrics provider for each service and display those metrics as part of the [topology visualization](/docs/connect/observability/ui-visualization). The diagram below illustrates how the UI displays service metrics for a sample application: ![UI Topology View](/img/ui-service-topology-view-hover.png) -The topology view is configured under `ui.metrics`. This will enable the Consul UI to query the provider specified by -`ui.metrics.provider` at the URL of the Prometheus server `ui.metrics.baseURL` to display sidecar proxy metrics for the -service. The UI will display some specific sidecar proxy Prometheus metrics when `ui.metrics.enabled` is `true` and -`ui.enabled` is true. The value of `ui.metrics.enabled` defaults to `"-"` which means it will inherit from the value of +The topology view is configured under `ui.metrics`. This configuration enables the Consul UI to query the provider specified by +`ui.metrics.provider` at the URL of the Prometheus server `ui.metrics.baseURL`, and then display sidecar proxy metrics for the +service. The UI displays some specific sidecar proxy Prometheus metrics when `ui.metrics.enabled` is `true` and +`ui.enabled` is true. The value of `ui.metrics.enabled` defaults to `"-"` which means it inherits from the value of `global.metrics.enabled.` ```yaml @@ -132,13 +133,13 @@ ui: ## Deploying Prometheus (_for demo and non-production use-cases only_) -The Helm chart contains demo manifests for deploying Prometheus. It can be installed with Helm via `prometheus.enabled`. This manifest is based on the community manifest for Prometheus. +The Helm chart contains demo manifests for deploying Prometheus. It can be installed with Helm with `prometheus.enabled`. This manifest is based on the community manifest for Prometheus. The Prometheus deployment is designed to allow quick bootstrapping for trial and demo use cases, and is not recommended for production use-cases. -Prometheus will be installed in the same namespace as Consul, and will be installed +Prometheus is be installed in the same namespace as Consul, and gets installed and uninstalled along with the Consul installation. -Grafana can optionally be utilized with Prometheus to display metrics. The installation and configuration of Grafana must be managed separately from the Consul Helm chart. The [Layer 7 Observability with Prometheus, Grafana, and Kubernetes](https://learn.hashicorp.com/tutorials/consul/kubernetes-layer7-observability?in=consul/kubernetes?in=consul/kubernetes)) tutorial provides an installation walkthrough using Helm. +Grafana can optionally be utilized with Prometheus to display metrics. The installation and configuration of Grafana must be managed separately from the Consul Helm chart. The [Layer 7 Observability with Prometheus, Grafana, and Kubernetes](/consul/tutorials/kubernetes/kubernetes-layer7-observability) tutorial provides an installation walkthrough using Helm. ```yaml prometheus: diff --git a/website/content/docs/k8s/connect/terminating-gateways.mdx b/website/content/docs/k8s/connect/terminating-gateways.mdx index b8b4e60c81df..e38556bdde34 100644 --- a/website/content/docs/k8s/connect/terminating-gateways.mdx +++ b/website/content/docs/k8s/connect/terminating-gateways.mdx @@ -9,18 +9,18 @@ description: >- Adding a terminating gateway is a multi-step process: -- Update the Helm chart with terminating gateway config options +- Update the Helm chart with terminating gateway configuration options - Deploy the Helm chart - Access the Consul agent - Register external services with Consul ## Requirements -- [Consul](https://www.consul.io/docs/install#install-consul) +- [Consul](/docs/install#install-consul) - [Consul on Kubernetes CLI](/docs/k8s/k8s-cli) - Familiarity with [Terminating Gateways](/docs/connect/gateways/terminating-gateway) -## Update the Helm chart with terminating gateway config options +## Update the Helm chart with terminating gateway configuration options Minimum required Helm options: @@ -29,10 +29,6 @@ Minimum required Helm options: ```yaml global: name: consul -connectInject: - enabled: true -controller: - enabled: true terminatingGateways: enabled: true ``` @@ -44,30 +40,32 @@ terminatingGateways: The Helm chart may be deployed using the [Consul on Kubernetes CLI](/docs/k8s/k8s-cli). ```shell-session -$ consul-k8s install -f values.yaml +$ consul-k8s install --config-file values.yaml ``` ## Accessing the Consul agent -You can access the Consul server directly from your host via `kubectl port-forward`. This is helpful for interacting with your Consul UI locally as well as for validating the connectivity of the application. +You can access the Consul server directly from your host by running `kubectl port-forward`. This is helpful for interacting with your Consul UI locally as well as for validating the connectivity of the application. + ```shell-session -$ kubectl port-forward consul-server-0 8500 & +$ kubectl port-forward service/consul-server 8500 & ``` ```shell-session $ export CONSUL_HTTP_ADDR=http://localhost:8500 ``` + If TLS is enabled use port 8501: ```shell-session -$ kubectl port-forward consul-server-0 8501 & +$ kubectl port-forward service/consul-server 8501 & ``` ```shell-session @@ -75,6 +73,7 @@ $ export CONSUL_HTTP_ADDR=https://localhost:8501 $ export CONSUL_HTTP_SSL_VERIFY=false ``` + If ACLs are enabled also set: @@ -103,6 +102,7 @@ you may register the service as a node in the Consul catalog. The [`destination`](/docs/connect/config-entries/service-defaults#terminating-gateway-destination) field of the `ServiceDefaults` Custom Resource Definition (CRD) allows clients to dial an external service directly. For this method to work, [`TransparentProxy`](/docs/connect/transparent-proxy) must be enabled. + The following table describes traffic behaviors when using the `destination` field to route traffic through a terminating gateway: | External Services Layer | Client dials | Client uses TLS | Allowed | Notes | @@ -116,7 +116,7 @@ The following table describes traffic behaviors when using the `destination` fie | L7 | Hostname | No | Allowed | A `Host` or `:authority` header is required. | | L7 | IP | No | Allowed | There are no limitations on dialing IPs without TLS. | -You can provide a `caFile` to secure traffic between unencrypted clients that connect to external services through the terminating gateway. +You can provide a `caFile` to secure traffic that connect to external services through the terminating gateway. Refer to [Create the configuration entry for the terminating gateway](#create-the-configuration-entry-for-the-terminating-gateway) for details. -> **Note:** Regardless of the `protocol` specified in the `ServiceDefaults`, [L7 intentions](/docs/connect/config-entries/service-intentions#permissions) are not currently supported with `ServiceDefaults` destinations. @@ -149,11 +149,12 @@ $ kubectl apply --filename service-defaults.yaml All other terminating gateway operations can use the name of the `ServiceDefaults` component, in this case "example-https", as a Consul service name. + -Normally, Consul services are registered with the Consul client on the node that -they're running on. Since this is an external service, there is no Consul node -to register it onto. Instead, we will make up a node name and register the +Normally, Consul services are registered on the node that +they're running on. Since this service is an external service, there is no Consul node +to register it onto. Instead, we must make up a node name and register the service to that node. Create a sample external service and register it with Consul. @@ -194,7 +195,7 @@ $ curl --request PUT --data @external.json --insecure $CONSUL_HTTP_ADDR/v1/catal true ``` -If ACLs and TLS are enabled : +If ACLs and TLS are enabled: ```shell-session $ curl --request PUT --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" --data @external.json --insecure $CONSUL_HTTP_ADDR/v1/catalog/register @@ -205,7 +206,7 @@ true ### Update terminating gateway ACL role if ACLs are enabled -If ACLs are enabled, update the terminating gateway acl role to have `service: write` permissions on all of the services +If ACLs are enabled, update the terminating gateway ACL role to have `service:write` permissions on all of the services being represented by the gateway. Create a new policy that includes the write permission for the service you created. @@ -232,15 +233,14 @@ service "example-https" { } ``` -Fetch the ID of the terminating gateway token. +Obtain the ID of the terminating gateway role. ```shell-session -consul acl role list | grep -B 6 -- "- RELEASE_NAME-terminating-gateway-policy" | grep ID - -ID: +$ consul acl role list -format=json | jq --raw-output '[.[] | select(.Name | endswith("-terminating-gateway-acl-role"))] | if (. | length) == 1 then (. | first | .ID) else "Unable to determine the role ID because there are multiple roles matching this name.\n" | halt_error end' + ``` -Update the terminating gateway ACL token with the new policy. +Update the terminating gateway ACL role with the new policy. ```shell-session $ consul acl role update -id -policy-name example-https-write-policy @@ -275,7 +275,7 @@ spec: If TLS is enabled for external services registered through the Consul catalog and you are not using [transparent proxy `destination`](#register-an-external-service-as-a-destination), you must include the [`caFile`](/docs/connect/config-entries/terminating-gateway#cafile) parameter that points to the system trust store of the terminating gateway container. By default, the trust store is located in the `/etc/ssl/certs/ca-certificates.crt` directory. -Configure the [`caFile`](https://www.consul.io/docs/connect/config-entries/terminating-gateway#cafile) parameter in the `TerminatingGateway` config entry to point to the `/etc/ssl/cert.pem` directory if TLS is enabled and you are using one of the following components: +Configure the [`caFile`](/docs/connect/config-entries/terminating-gateway#cafile) parameter in the `TerminatingGateway` config entry to point to the `/etc/ssl/cert.pem` directory if TLS is enabled and you are using one of the following components: - Consul Helm chart 0.43 or older - An Envoy image with an alpine base image @@ -379,7 +379,7 @@ deployment "static-client" successfully rolled out You can verify connectivity of the static-client and terminating gateway via a curl command. - + ```shell-session $ kubectl exec deploy/static-client -- curl -vvvs https://example.com/ diff --git a/website/content/docs/k8s/crds/index.mdx b/website/content/docs/k8s/crds/index.mdx index 4e15ef36d1c4..43387ae3123d 100644 --- a/website/content/docs/k8s/crds/index.mdx +++ b/website/content/docs/k8s/crds/index.mdx @@ -8,26 +8,22 @@ description: >- # Custom Resource Definitions (CRDs) for Consul on Kubernetes This topic describes how to manage Consul [configuration entries](/docs/agent/config-entries) -via Kubernetes Custom Resources. Configuration entries provide cluster-wide defaults for the service mesh. - -## Requirements - -* consul-helm 0.28.0 or later -* consul-k8s 0.22.0 or later -* consul 1.8.4 or later; some configuration entries require a newer version of Consul +with Kubernetes Custom Resources. Configuration entries provide cluster-wide defaults for the service mesh. ## Supported Configuration Entries You can specify the following values in the `kind` field. Click on a configuration entry to view its documentation: -- [`Mesh`](/docs/connect/config-entries/mesh) (requires Consul 1.10.0+) -- [`ExportedServices`](/docs/connect/config-entries/exported-services) +- [`Mesh`](/docs/connect/config-entries/mesh) +- [`ExportedServices`](/docs/connect/config-entries/exported-services) +- [`PeeringAcceptor`](/docs/connect/cluster-peering/k8s#peeringacceptor) +- [`PeeringDialer`](/docs/connect/cluster-peering/k8s#peeringdialer) - [`ProxyDefaults`](/docs/connect/config-entries/proxy-defaults) - [`ServiceDefaults`](/docs/connect/config-entries/service-defaults) - [`ServiceSplitter`](/docs/connect/config-entries/service-splitter) - [`ServiceRouter`](/docs/connect/config-entries/service-router) - [`ServiceResolver`](/docs/connect/config-entries/service-resolver) -- [`ServiceIntentions`](/docs/connect/config-entries/service-intentions) (requires Consul 1.9.0+) +- [`ServiceIntentions`](/docs/connect/config-entries/service-intentions) - [`IngressGateway`](/docs/connect/config-entries/ingress-gateway) - [`TerminatingGateway`](/docs/connect/config-entries/terminating-gateway) @@ -50,37 +46,15 @@ Hang tight while we grab the latest from your chart repositories... Update Complete. ⎈Happy Helming!⎈ ``` -Next, you must configure consul-helm via your `values.yaml` to install the custom resource definitions -and enable the controller that acts on them: - - - -```yaml -global: - name: consul - -controller: - enabled: true - -connectInject: - enabled: true -``` - - - -Note that: - -1. `controller.enabled: true` installs the CRDs and enables the controller. -1. Configuration entries are used to configure Consul service mesh so it's also - expected that `connectInject` will be enabled. - -See [Install with Helm Chart](/docs/k8s/installation/install) for further installation +Refer to [Install with Helm Chart](/docs/k8s/installation/install) for further installation instructions. +**Note**: Configuration entries require `connectInject` to be enabled, which is a default behavior in the official Helm Chart. If you disabled this setting, you must re-enable it to use CRDs. + ## Upgrading An Existing Cluster to CRDs If you have an existing Consul cluster running on Kubernetes you may need to perform -extra steps to migrate to CRDs. See [Upgrade An Existing Cluster to CRDs](/docs/k8s/crds/upgrade-to-crds) for full instructions. +extra steps to migrate to CRDs. Refer to [Upgrade An Existing Cluster to CRDs](/docs/k8s/crds/upgrade-to-crds) for full instructions. ## Usage @@ -88,7 +62,7 @@ Once installed, you can use `kubectl` to create and manage Consul's configuratio ### Create -You can create configuration entries via `kubectl apply`. +You can create configuration entries with `kubectl apply`. ```shell-session $ cat < protocol: tcp servicedefaults.consul.hashicorp.com/foo edited @@ -171,11 +145,11 @@ Error from server (NotFound): servicedefaults.consul.hashicorp.com "foo" not fou If running `kubectl delete` hangs without exiting, there may be a dependent configuration entry registered with Consul that prevents the target configuration entry from being -deleted. For example, if you set the protocol of your service to `http` via `ServiceDefaults` and then -create a `ServiceSplitter`, you won't be able to delete the `ServiceDefaults`. +deleted. For example, if you set the protocol of your service to `http` in `ServiceDefaults` and then +create a `ServiceSplitter`, you will not be able to delete `ServiceDefaults`. This is because by deleting the `ServiceDefaults` config, you are setting the -protocol back to the default which is `tcp`. Since `ServiceSplitter` requires +protocol back to the default which is `tcp`. Because `ServiceSplitter` requires that the service has an `http` protocol, Consul will not allow the `ServiceDefaults` to be deleted since that would put Consul into a broken state. @@ -188,7 +162,7 @@ the `ServiceSplitter`. Consul Open Source (Consul OSS) ignores Kubernetes namespaces and registers all services into the same global Consul registry based on their names. For example, service `web` in Kubernetes namespace -`web-ns` and service `admin` in Kubernetes namespace `admin-ns` will be registered into +`web-ns` and service `admin` in Kubernetes namespace `admin-ns` are registered into Consul as `web` and `admin` with the Kubernetes source namespace ignored. When creating custom resources to configure these services, the namespace of the @@ -213,8 +187,7 @@ metadata: spec: ... ``` -~> **NOTE:** If two custom resources of the same kind **and** the same name are attempted to -be created in different Kubernetes namespaces, the last one created will not be synced. +~> **Note:** If you create two custom resources with identical `kind` and `name` values in different Kubernetes namespaces, the last one you create is not able to sync. #### ServiceIntentions Special Case @@ -271,25 +244,24 @@ spec: -~> **NOTE:** If two `ServiceIntentions` resources set the same `spec.destination.name`, the -last one created will not be synced. +~> **Note:** If two `ServiceIntentions` resources set the same `spec.destination.name`, the +last one created is not synced. ### Consul Enterprise Consul Enterprise supports multiple configurations for how Kubernetes namespaces are mapped to Consul namespaces. The Consul namespace that the custom resource is registered into depends on the configuration being used but in general, you should create your -custom resources in the same Kubernetes namespace as the service they're configuring and -everything will work as expected. +custom resources in the same Kubernetes namespace as the service they configure. The details on each configuration are: -1. **Mirroring** - The Kubernetes namespace will be "mirrored" into Consul, i.e. - service `web` in Kubernetes namespace `web-ns` will be registered as service `web` +1. **Mirroring** - The Kubernetes namespace is mirrored into Consul. For example, the + service `web` in Kubernetes namespace `web-ns` is registered as service `web` in the Consul namespace `web-ns`. In the same vein, a `ServiceDefaults` custom resource with - name `web` in Kubernetes namespace `web-ns` will configure that same service. + name `web` in Kubernetes namespace `web-ns` configures that same service. - This is configured via [`connectInject.consulNamespaces`](/docs/k8s/helm#v-connectinject-consulnamespaces): + This is configured with [`connectInject.consulNamespaces`](/docs/k8s/helm#v-connectinject-consulnamespaces): @@ -305,13 +277,12 @@ The details on each configuration are: -1. **Mirroring with prefix** - The Kubernetes namespace will be "mirrored" into Consul - with a prefix added to the Consul namespace, i.e. - if the prefix is `k8s-` then service `web` in Kubernetes namespace `web-ns` will be registered as service `web` +1. **Mirroring with prefix** - The Kubernetes namespace is mirrored into Consul + with a prefix added to the Consul namespace. For example, if the prefix is `k8s-` then service `web` in Kubernetes namespace `web-ns` will be registered as service `web` in the Consul namespace `k8s-web-ns`. In the same vein, a `ServiceDefaults` custom resource with - name `web` in Kubernetes namespace `web-ns` will configure that same service. + name `web` in Kubernetes namespace `web-ns` configures that same service. - This is configured via [`connectInject.consulNamespaces`](/docs/k8s/helm#v-connectinject-consulnamespaces): + This is configured with [`connectInject.consulNamespaces`](/docs/k8s/helm#v-connectinject-consulnamespaces): @@ -329,17 +300,16 @@ The details on each configuration are: 1. **Single destination namespace** - The Kubernetes namespace is ignored and all services - will be registered into the same Consul namespace, i.e. if the destination Consul - namespace is `my-ns` then service `web` in Kubernetes namespace `web-ns` will - be registered as service `web` in Consul namespace `my-ns`. + are registered into the same Consul namespace. For example, if the destination Consul + namespace is `my-ns` then service `web` in Kubernetes namespace `web-ns` is registered as service `web` in Consul namespace `my-ns`. In this configuration, the Kubernetes namespace of the custom resource is ignored. For example, a `ServiceDefaults` custom resource with the name `web` in Kubernetes - namespace `admin-ns` will configure the service with name `web` even though that + namespace `admin-ns` configures the service with name `web` even though that service is running in Kubernetes namespace `web-ns` because the `ServiceDefaults` resource ends up registered into the same Consul namespace `my-ns`. - This is configured via [`connectInject.consulNamespaces`](/docs/k8s/helm#v-connectinject-consulnamespaces): + This is configured with [`connectInject.consulNamespaces`](/docs/k8s/helm#v-connectinject-consulnamespaces): @@ -355,13 +325,12 @@ The details on each configuration are: - ~> **NOTE:** In this configuration, if two custom resources of the same kind **and** the same name are attempted to - be created in two Kubernetes namespaces, the last one created will not be synced. + ~> **Note:** In this configuration, if two custom resources are created in two Kubernetes namespaces with identical `name` and `kind` values, the last one created is not synced. #### ServiceIntentions Special Case (Enterprise) `ServiceIntentions` are different from the other custom resources because the -name of the resource doesn't matter. For other resources, the name of the resource +name of the resource does not matter. For other resources, the name of the resource determines which service it configures. For example, this resource configures the service `web`: @@ -379,7 +348,7 @@ spec: For `ServiceIntentions`, because we need to support the ability to create -wildcard intentions (e.g. `foo => * (allow)` meaning that `foo` can talk to **any** service), +wildcard intentions (e.g. `foo => * (allow)` meaning that `foo` can talk to any service), and because `*` is not a valid Kubernetes resource name, we instead use the field `spec.destination.name` to configure the destination service for the intention: @@ -415,5 +384,5 @@ spec: In addition, we support the field `spec.destination.namespace` to configure the destination service's Consul namespace. If `spec.destination.namespace` -is empty, then the Consul namespace used will be the same as the other +is empty, then the Consul namespace used is the same as the other config entries as outlined above. diff --git a/website/content/docs/k8s/crds/upgrade-to-crds.mdx b/website/content/docs/k8s/crds/upgrade-to-crds.mdx index f8a393bd250e..e583f316970d 100644 --- a/website/content/docs/k8s/crds/upgrade-to-crds.mdx +++ b/website/content/docs/k8s/crds/upgrade-to-crds.mdx @@ -60,11 +60,6 @@ new and existing services: 1. Next, modify your Helm values: 1. Remove the `defaultProtocol` config. This won't affect existing services. - 1. Set: - ```yaml - controller: - enabled: true - ``` 1. Now you can upgrade your Helm chart to the latest version with the new Helm values. 1. From now on, any new service will require a [`ServiceDefaults`](/docs/connect/config-entries/service-defaults) resource to set its protocol: @@ -164,13 +159,6 @@ You will need to perform the following steps to upgrade: 1. Next, remove this annotation from existing deployments. This will have no effect on the deployments because the annotation was only used when the service was first created. -1. Modify your Helm values and add: - - ```yaml - controller: - enabled: true - ``` - 1. Now you can upgrade your Helm chart to the latest version. 1. From now on, any new service will require a [`ServiceDefaults`](/docs/connect/config-entries/service-defaults) resource to set its protocol: diff --git a/website/content/docs/k8s/deployment-configurations/clients-outside-kubernetes.mdx b/website/content/docs/k8s/deployment-configurations/clients-outside-kubernetes.mdx index c978da82e8b1..eebd2dd81d35 100644 --- a/website/content/docs/k8s/deployment-configurations/clients-outside-kubernetes.mdx +++ b/website/content/docs/k8s/deployment-configurations/clients-outside-kubernetes.mdx @@ -1,80 +1,65 @@ --- layout: docs -page_title: Join External Clients to Consul on Kubernetes +page_title: Join External Services to Consul on Kubernetes description: >- - Client agents running on VMs can join a Consul datacenter running on Kubernetes. Configure the Kubernetes installation to accept communication from external clients. + Services running on a virtual machine (VM) can join a Consul datacenter running on Kubernetes. Learn how to configure the Kubernetes installation to accept communication from external services. --- -# Join External Clients to Consul on Kubernetes +# Join External Services to Consul on Kubernetes -Consul clients running on non-Kubernetes nodes can join a Consul cluster running within Kubernetes. - -## Networking - -Within one datacenter, Consul typically requires a fully connected -[network](/docs/architecture). This means the IPs of every client and server -agent should be routable by every other client and server agent in the -datacenter. Clients need to be able to [gossip](/docs/architecture/gossip) with -every other agent and make RPC calls to servers. Servers need to be able to -gossip with every other agent. See [Architecture](/docs/architecture) for more details. - --> **Consul Enterprise customers** may use [network -segments](/docs/enterprise/network-segments) to enable non-fully-connected -topologies. However, out-of-cluster nodes must still be able to communicate -with the server pod or host IP addresses. +Services running on non-Kubernetes nodes can join a Consul cluster running within Kubernetes. ## Auto-join + The recommended way to join a cluster running within Kubernetes is to use the ["k8s" cloud auto-join provider](/docs/install/cloud-auto-join#kubernetes-k8s). The auto-join provider dynamically discovers IP addresses to join using the Kubernetes API. It authenticates with Kubernetes using a standard -`kubeconfig` file. This works with all major hosted Kubernetes offerings +`kubeconfig` file. Auto-join works with all major hosted Kubernetes offerings as well as self-hosted installations. The token in the `kubeconfig` file needs to have permissions to list pods in the namespace where Consul servers are deployed. -The auto-join string below will join a Consul server cluster that is -started using the [official Helm chart](/docs/k8s/helm): +The auto-join string below joins a Consul server agent to a cluster using the [official Helm chart](/docs/k8s/helm): ```shell-session $ consul agent -retry-join 'provider=k8s label_selector="app=consul,component=server"' ``` + -> **Note:** This auto-join command only connects on the default gossip port -8301, whether you are joining on the pod network or via host ports. Either a -consul server or client that is already a member of the datacenter should be -listening on this port for the external client agent to be able to use +8301, whether you are joining on the pod network or via host ports. A +Consul server that is already a member of the datacenter should be +listening on this port for the external service to connect through auto-join. ### Auto-join on the Pod network -In the default Consul Helm chart installation, Consul clients and servers are -routable only via their pod IPs for server RPCs and gossip (HTTP -API calls to Consul clients can also be made through host IPs). This means any -external client agents joining the Consul cluster running on Kubernetes would -need to be able to have connectivity to those pod IPs. -In many hosted Kubernetes environments, you will need to explicitly configure +In the default Consul Helm chart installation, Consul servers are +routable through their pod IPs for server RPCs. As a result, any +external agents joining the Consul cluster running on Kubernetes +need to be able to connect to those pod IPs. + +In many hosted Kubernetes environments, you need to explicitly configure your hosting provider to ensure that pod IPs are routable from external VMs. -See [Azure AKS -CNI](https://docs.microsoft.com/en-us/azure/aks/concepts-network#azure-cni-advanced-networking), -[AWS EKS -CNI](https://docs.aws.amazon.com/eks/latest/userguide/pod-networking.html) and -[GKE VPC-native -clusters](https://cloud.google.com/kubernetes-engine/docs/concepts/alias-ips). +For more information, refer to [Azure AKS CNI](https://docs.microsoft.com/en-us/azure/aks/concepts-network#azure-cni-advanced-networking), +[AWS EKS CNI](https://docs.aws.amazon.com/eks/latest/userguide/pod-networking.html) and +[GKE VPC-native clusters](https://cloud.google.com/kubernetes-engine/docs/concepts/alias-ips). -Given you have the [official Helm chart](/docs/k8s/helm) installed with the default values, do the following to join an external client agent. +To join external agents with Consul on Kubernetes deployments installed with default values through the [official Helm chart](/docs/k8s/helm): - 1. Make sure the pod IPs of the clients and servers in Kubernetes are + 1. Make sure the pod IPs of the servers in Kubernetes are routable from the VM and that the VM can access port 8301 (for gossip) and port 8300 (for server RPC) on those pod IPs. - 1. Make sure that the client and server pods running in Kubernetes can route + 1. Make sure that the server pods running in Kubernetes can route to the VM's advertise IP on its gossip port (default 8301). - 2. Make sure you have the `kubeconfig` file for the Kubernetes cluster in `$HOME/.kube/config` on the external VM. + 1. Make sure you have the `kubeconfig` file for the Kubernetes cluster in `$HOME/.kube/config` on the external VM. + + 1. On the external VM, run: - 2. On the external VM, run: - ```bash + ```shell-session consul agent \ -advertise="$ADVERTISE_IP" \ -retry-join='provider=k8s label_selector="app=consul,component=server"' \ @@ -86,7 +71,8 @@ Given you have the [official Helm chart](/docs/k8s/helm) installed with the defa -data-dir=$DATA_DIR \ ``` - 3. Check if the join was successful by running `consul members`. Sample output: + 1. Run `consul members` to check if the join was successful. + ```shell-session / $ consul members Node Address Status Type Build Protocol DC Segment @@ -97,10 +83,10 @@ Given you have the [official Helm chart](/docs/k8s/helm) installed with the defa gke-external-agent-default-pool-32d15192-vo7k 10.138.0.42:8301 alive client 1.9.1 2 dc1 ``` -### Auto-join via host ports -If your external VMs can't connect to Kubernetes pod IPs, but they can connect -to the internal host IPs of the nodes in the Kubernetes cluster, you have the -option to expose the clients and server ports on the host IP instead. +### Auto-join through host ports + +If your external VMs cannot connect to Kubernetes pod IPs but they can connect +to the internal host IPs of the nodes in the Kubernetes cluster, you can join the two by exposing ports on the host IP instead. 1. Install the [official Helm chart](/docs/k8s/helm) with the following values: ```yaml @@ -114,19 +100,20 @@ option to expose the clients and server ports on the host IP instead. # Note that this needs to be different than 8301, to avoid conflicting with the client gossip hostPort port: 9301 ``` - This will expose the client gossip ports, the server gossip ports and the server RPC port at `hostIP:hostPort`. Note that `hostIP` is the **internal** IP of the VM that the client/server pods are deployed on. + This installation exposes the client gossip ports, the server gossip ports and the server RPC port at `hostIP:hostPort`. Note that `hostIP` is the **internal** IP of the VM that the client/server pods are deployed on. 1. Make sure the IPs of the Kubernetes nodes are routable from the VM and that the VM can access ports 8301 and 9301 (for gossip) and port 8300 (for server RPC) on those node IPs. - 1. Make sure the client and server pods running in Kubernetes can route to + 1. Make sure the server pods running in Kubernetes can route to the VM's advertise IP on its gossip port (default 8301). - 3. Make sure you have the `kubeconfig` file for the Kubernetes cluster in `$HOME/.kube/config` on the external VM. + 1. Make sure you have the `kubeconfig` file for the Kubernetes cluster in `$HOME/.kube/config` on the external VM. - 4. On the external VM, run (note the addition of `host_network=true` in the retry-join argument): - ```bash + 1. On the external VM, run: + + ```shell-session consul agent \ -advertise="$ADVERTISE_IP" \ -retry-join='provider=k8s host_network=true label_selector="app=consul,component=server"' @@ -137,7 +124,11 @@ option to expose the clients and server ports on the host IP instead. -datacenter=$DATACENTER \ -data-dir=$DATA_DIR \ ``` - 3. Check if the join was successful by running `consul members`. Sample output: + + Note the addition of `host_network=true` in the retry-join argument. + + 1. Run `consul members` to check if the join was successful. + ```shell-session / $ consul members Node Address Status Type Build Protocol DC Segment @@ -149,13 +140,12 @@ option to expose the clients and server ports on the host IP instead. ``` ## Manual join -If you are unable to use auto-join, you can also follow the instructions in -either of the auto-join sections but instead of using a `provider` key in the -`-retry-join` flag, you would need to pass the address of at least one -consul server, e.g: `-retry-join=$CONSUL_SERVER_IP:$SERVER_SERFLAN_PORT`. A -`kubeconfig` file is not required when using manual join. -However, rather than hardcoding the IP, it's recommended to set up a DNS entry -that would resolve to the consul servers' pod IPs (if using the pod network) or -host IPs that the server pods are running on (if using host ports). +If you are unable to use auto-join, try following the instructions in +either of the auto-join sections, but instead of using a `provider` key in the +`-retry-join` flag, pass the address of at least one Consul server. Example: `-retry-join=$CONSUL_SERVER_IP:$SERVER_SERFLAN_PORT`. + +A `kubeconfig` file is not required when using manual join. +Instead of hardcoding an IP address, we recommend you set up a DNS entry +that resolves to the pod IPs or host IPs that the Consul server pods are running on. \ No newline at end of file diff --git a/website/content/docs/k8s/deployment-configurations/consul-enterprise.mdx b/website/content/docs/k8s/deployment-configurations/consul-enterprise.mdx index 75f65c58d781..cacc0ab485f7 100644 --- a/website/content/docs/k8s/deployment-configurations/consul-enterprise.mdx +++ b/website/content/docs/k8s/deployment-configurations/consul-enterprise.mdx @@ -11,7 +11,7 @@ You can use this Helm chart to deploy Consul Enterprise by following a few extra Find the license file that you received in your welcome email. It should have a `.hclic` extension. You will use the contents of this file to create a Kubernetes secret before installing the Helm chart. --> **Note:** This guide assumes you are storing your license as a Kubernetes Secret. If you would like to store the enterprise license in Vault, please reference [Storing the Enterprise License in Vault](/docs/k8s/deployment-configuration/vault/data-integration/enterprise-license). +~> **Note:** This guide assumes you are storing your license as a Kubernetes Secret. If you would like to store the enterprise license in Vault, please reference [Storing the Enterprise License in Vault](/consul/docs/k8s/deployment-configurations/vault/data-integration/enterprise-license). You can use the following commands to create the secret with name `consul-ent-license` and key `key`: diff --git a/website/content/docs/k8s/deployment-configurations/multi-cluster/kubernetes.mdx b/website/content/docs/k8s/deployment-configurations/multi-cluster/kubernetes.mdx index 5103a3d55208..ac4fa3dcbf2b 100644 --- a/website/content/docs/k8s/deployment-configurations/multi-cluster/kubernetes.mdx +++ b/website/content/docs/k8s/deployment-configurations/multi-cluster/kubernetes.mdx @@ -9,7 +9,7 @@ description: >- -> **1.8.0+:** This feature is available in Consul versions 1.8.0 and higher -~> This topic requires familiarity with [Mesh Gateways](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters) and [WAN Federation Via Mesh Gateways](/docs/connect/gateways/mesh-gateway/wan-federation-via-mesh-gateways). +~> This topic requires familiarity with [Mesh Gateways](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-wan-datacenters) and [WAN Federation Via Mesh Gateways](/docs/connect/gateways/mesh-gateway/wan-federation-via-mesh-gateways). -> Looking for a step-by-step guide? Complete the [Secure and Route Service Mesh Communication Across Kubernetes](https://learn.hashicorp.com/tutorials/consul/kubernetes-mesh-gateways?utm_source=docs) tutorial to learn more. @@ -68,9 +68,6 @@ connectInject: # Consul Connect service mesh must be enabled for federation. enabled: true -controller: - enabled: true - meshGateway: # Mesh gateways are gateways between datacenters. They must be enabled # for federation in Kubernetes since the communication between datacenters @@ -358,8 +355,6 @@ global: secretKey: gossipEncryptionKey connectInject: enabled: true -controller: - enabled: true meshGateway: enabled: true server: diff --git a/website/content/docs/k8s/deployment-configurations/multi-cluster/vms-and-kubernetes.mdx b/website/content/docs/k8s/deployment-configurations/multi-cluster/vms-and-kubernetes.mdx index a0530d8e14d5..4e56e8b015d8 100644 --- a/website/content/docs/k8s/deployment-configurations/multi-cluster/vms-and-kubernetes.mdx +++ b/website/content/docs/k8s/deployment-configurations/multi-cluster/vms-and-kubernetes.mdx @@ -9,7 +9,7 @@ description: >- -> **1.8.0+:** This feature is available in Consul versions 1.8.0 and higher -~> This topic requires familiarity with [Mesh Gateways](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters) and [WAN Federation Via Mesh Gateways](/docs/connect/gateways/mesh-gateway/wan-federation-via-mesh-gateways). +~> This topic requires familiarity with [Mesh Gateways](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-wan-datacenters) and [WAN Federation Via Mesh Gateways](/docs/connect/gateways/mesh-gateway/wan-federation-via-mesh-gateways). Consul datacenters running on non-kubernetes platforms like VMs or bare metal can be federated with Kubernetes datacenters. Just like with Kubernetes, one datacenter @@ -258,6 +258,51 @@ You'll need: } } ``` +1. If ACLs are enabled you'll also need to modify the [anonymous token](/consul/docs/security/acl/acl-tokens#anonymous-token) policy to have the following permissions: + + ```hcl + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } + ``` + + With Consul Enterprise, use: + + ```hcl + partition_prefix "" { + namespace_prefix "" { + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } + } + } + ``` + + These permissions are needed to allow cross-datacenter requests. To make a cross-dc request the sidecar proxy in the originating DC needs to know about the + services running in the remote DC. To do so, it needs an ACL token that allows it to look up the services in the remote DC. The way tokens are created in + Kubernetes, the sidecar proxies have local ACL tokens–i.e tokens that are only valid in the local DC. When a request goes from one DC to another, if the + request has a local token, it is stripped from the request because the remote DC won't be able to validate it. When the request lands in the other DC, + it has no ACL token and so will be subject to the anonymous token policy. This is why the anonymous token policy must be configured to allow read access + to all services. When the Kubernetes DC is the primary, this is handled automatically, but when the primary DC is on VMs, this must be configured manually. + + To configure the anonymous token policy, first create a policy with the above rules, then attach it to the anonymous token. For example using the CLI: + + ```sh + echo 'node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + }' | consul acl policy create -name anonymous -rules - + + consul acl token update -id 00000000-0000-0000-0000-000000000002 -policy-name anonymous + ``` 1. If gossip encryption is enabled, you'll need the key. @@ -329,8 +374,6 @@ global: connectInject: enabled: true -controller: - enabled: true meshGateway: enabled: true server: diff --git a/website/content/docs/k8s/deployment-configurations/servers-outside-kubernetes.mdx b/website/content/docs/k8s/deployment-configurations/servers-outside-kubernetes.mdx index b82d9b563e15..9c67c5bf64e3 100644 --- a/website/content/docs/k8s/deployment-configurations/servers-outside-kubernetes.mdx +++ b/website/content/docs/k8s/deployment-configurations/servers-outside-kubernetes.mdx @@ -8,25 +8,22 @@ description: >- # Join External Servers to Consul on Kubernetes If you have a Consul cluster already running, you can configure your -Consul clients inside Kubernetes to join this existing cluster. +Consul on Kubernetes installation to join this existing cluster. The below `values.yaml` file shows how to configure the Helm chart to install -Consul clients that will join an existing cluster. +Consul that will join an existing Consul server cluster. The `global.enabled` value first disables all chart components by default so that each component is opt-in. This allows us to _only_ setup the client agents. We then opt-in to the client agents by setting `client.enabled` to `true`. -Next, `client.exposeGossipPorts` can be set to `true` or `false` depending on if -you want the clients to be exposed on the Kubernetes internal node IPs (`true`) or -their pod IPs (`false`). - -Finally, `client.join` is set to an array of valid -[`-retry-join` values](/docs/agent/config/cli-flags#retry-join). In the -example above, a fake [cloud auto-join](/docs/install/cloud-auto-join) -value is specified. This should be set to resolve to the proper addresses of -your existing Consul cluster. +Next, configure `externalServers` to point it to Consul servers. +The `externalServers.hosts` value must be provided and should be set to a DNS, an IP, +or an `exec=` string with a command returning Consul IPs. Please see [this documentation](https://github.com/hashicorp/go-netaddrs) +on how the `exec=` string works.externalServers +Other values in the `externalServers` section are optional. Please refer to +[Helm Chart configuration](https://developer.hashicorp.com/consul/docs/k8s/helm#h-externalservers) for more details. @@ -34,26 +31,16 @@ your existing Consul cluster. global: enabled: false -client: - enabled: true - # Set this to true to expose the Consul clients using the Kubernetes node - # IPs. If false, the pod IPs must be routable from the external servers. - exposeGossipPorts: true - join: - - 'provider=my-cloud config=val ...' +externalServers: + hosts: [] ``` --> **Networking:** Note that for the Kubernetes nodes to join an existing -cluster, the nodes (and specifically the agent pods) must be able to connect -to all other server and client agents inside and _outside_ of Kubernetes over [LAN](/docs/install/glossary#lan-gossip). -If this isn't possible, consider running a separate Consul cluster inside Kubernetes -and federating it with your cluster outside Kubernetes. -You may also consider adopting Consul Enterprise for -[network segments](/docs/enterprise/network-segments). +-> **Note:** If you are looking to join Consul clients to an existing Consul server cluster, +please see [this documentation](https://developer.hashicorp.com/consul/docs/v1.13.x/k8s/deployment-configurations/servers-outside-kubernetes). -## Configuring TLS with Auto-encrypt +## Configuring TLS -> **Note:** Consul on Kubernetes currently does not support external servers that require mutual authentication for the HTTPS clients of the Consul servers, that is when servers have either @@ -62,10 +49,9 @@ As noted in the [Security Model](/docs/security#secure-configuration), that setting isn't strictly necessary to support Consul's threat model as it is recommended that all requests contain a valid ACL token. -Consul's auto-encrypt feature allows clients to automatically provision their certificates by making a request to the servers at startup. -If you would like to use this feature with external Consul servers, you need to configure the Helm chart with information about the servers -so that it can retrieve the clients' CA to use for securing the rest of the cluster. -To do that, you must add the following values, in addition to the values mentioned above: +If the Consul server has TLS enabled, you would also need to provide the CA certificate that Consul on Kubernetes will +need to talk to the server. First save this certificate in a Kubernetes secret and then provide it in your Helm values below, +in addition to the values mentioned above: @@ -73,19 +59,17 @@ To do that, you must add the following values, in addition to the values mention global: tls: enabled: true - enableAutoEncrypt: true + caCert: + secretName: + secretKey: externalServers: enabled: true - hosts: - - 'provider=my-cloud config=val ...' + hosts: [] ``` -In most cases, `externalServers.hosts` will be the same as `client.join`, however, both keys must be set because -they are used for different purposes: one for Serf LAN and the other for HTTPS connections. -Please see the [reference documentation](/docs/k8s/helm#v-externalservers-hosts) -for more info. If your HTTPS port is different from Consul's default `8501`, you must also set +If your HTTPS port is different from Consul's default `8501`, you must also set `externalServers.httpsPort`. ## Configuring ACLs @@ -132,13 +116,16 @@ to create policies, tokens, and an auth method. If you are [enabling Consul Conn so that the Consul servers can validate a Kubernetes service account token when using the [Kubernetes auth method](/docs/security/acl/auth-methods/kubernetes) with `consul login`. +-> **Note:** If `externalServers.k8sAuthMethodHost` is set and you are also using WAN federation +(`global.federation.enabled` is set to `true`), ensure that `global.federation.k8sAuthMethodHost` is set to the same +value as `externalServers.k8sAuthMethodHost`. + ```yaml externalServers: enabled: true - hosts: - - 'provider=my-cloud config=val ...' + hosts: [] k8sAuthMethodHost: 'https://kubernetes.example.com:443' ``` @@ -156,17 +143,9 @@ global: bootstrapToken: secretName: bootstrap-token secretKey: token -client: - enabled: true - # Set this to true to expose the Consul clients using the Kubernetes node - # IPs. If false, the pod IPs must be routable from the external servers. - exposeGossipPorts: true - join: - - 'provider=my-cloud config=val ...' externalServers: enabled: true - hosts: - - 'provider=my-cloud config=val ...' + hosts: [] k8sAuthMethodHost: 'https://kubernetes.example.com:443' ``` @@ -184,17 +163,9 @@ global: enabled: false acls: manageSystemACLs: true -client: - enabled: true - # Set this to true to expose the Consul clients using the Kubernetes node - # IPs. If false, the pod IPs must be routable from the external servers. - exposeGossipPorts: true - join: - - 'provider=my-cloud config=val ...' externalServers: enabled: true - hosts: - - 'provider=my-cloud config=val ...' + hosts: [] k8sAuthMethodHost: 'https://kubernetes.example.com:443' ``` diff --git a/website/content/docs/k8s/deployment-configurations/single-dc-multi-k8s.mdx b/website/content/docs/k8s/deployment-configurations/single-dc-multi-k8s.mdx index 67bc4f15b326..42adbb14cf56 100644 --- a/website/content/docs/k8s/deployment-configurations/single-dc-multi-k8s.mdx +++ b/website/content/docs/k8s/deployment-configurations/single-dc-multi-k8s.mdx @@ -10,18 +10,13 @@ description: >- ~> **Note:** When running Consul across multiple Kubernetes clusters, we recommend using [admin partitions](/docs/enterprise/admin-partitions) for production environments. This Consul Enterprise feature allows you to accommodate multiple tenants without resource collisions when administering a cluster at scale. Admin partitions also enable you to run Consul on Kubernetes clusters across a non-flat network. This page describes deploying a single Consul datacenter in multiple Kubernetes clusters, -with servers and clients running in one cluster and only clients in the rest of the clusters. +with servers running in one cluster and only Consul on Kubernetes components in the rest of the clusters. This example uses two Kubernetes clusters, but this approach could be extended to using more than two. ## Requirements -* Consul-Helm version `v0.32.1` or higher -* This deployment topology requires that the Kubernetes clusters have a flat network -for both pods and nodes so that pods or nodes from one cluster can connect -to pods or nodes in another. In many hosted Kubernetes environments, this may have to be explicitly configured based on the hosting provider's network. Refer to the following documentation for instructions: - * [Azure AKS CNI](https://docs.microsoft.com/en-us/azure/aks/concepts-network#azure-cni-advanced-networking) - * [AWS EKS CNI](https://docs.aws.amazon.com/eks/latest/userguide/pod-networking.html) - * [GKE VPC-native clusters](https://cloud.google.com/kubernetes-engine/docs/concepts/alias-ips). +* `consul-k8s` v1.0.x or higher, and Consul 1.14.x or higher +* Kubernetes clusters must be able to communicate over LAN on a flat network. * Either the Helm release name for each Kubernetes cluster must be unique, or `global.name` for each Kubernetes cluster must be unique to prevent collisions of ACL resources with the same prefix. ## Prepare Helm release name ahead of installs @@ -34,14 +29,14 @@ Before proceeding with installation, prepare the Helm release names as environme ```shell-session $ export HELM_RELEASE_SERVER=server - $ export HELM_RELEASE_CLIENT=client + $ export HELM_RELEASE_CONSUL=consul ... - $ export HELM_RELEASE_CLIENT2=client2 + $ export HELM_RELEASE_CONSUL2=consul2 ``` -## Deploying Consul servers and clients in the first cluster +## Deploying Consul servers in the first cluster -First, deploy the first cluster with Consul Servers and Clients with the example Helm configuration below. +First, deploy the first cluster with Consul servers with the example Helm configuration below. @@ -56,10 +51,6 @@ global: gossipEncryption: secretName: consul-gossip-encryption-key secretKey: key -connectInject: - enabled: true -controller: - enabled: true ui: service: type: NodePort @@ -86,17 +77,15 @@ Now install Consul cluster with Helm: $ helm install ${HELM_RELEASE_SERVER} --values cluster1-values.yaml hashicorp/consul ``` - Once the installation finishes and all components are running and ready, the following information needs to be extracted (using the below command) and applied to the second Kubernetes cluster. - * The Gossip encryption key created * The CA certificate generated during installation * The ACL bootstrap token generated during installation ```shell-session -$ kubectl get secret consul-gossip-encryption-key ${HELM_RELEASE_SERVER}-consul-ca-cert ${HELM_RELEASE_SERVER}-consul-bootstrap-acl-token --output yaml > cluster1-credentials.yaml +$ kubectl get secret ${HELM_RELEASE_SERVER}-consul-ca-cert ${HELM_RELEASE_SERVER}-consul-bootstrap-acl-token --output yaml > cluster1-credentials.yaml ``` -## Deploying Consul clients in the second cluster +## Deploying Consul Kubernetes in the second cluster ~> **Note:** If multiple Kubernetes clusters will be joined to the Consul Datacenter, then the following instructions will need to be repeated for each additional Kubernetes cluster. Switch to the second Kubernetes cluster where Consul clients will be deployed @@ -124,38 +113,27 @@ global: bootstrapToken: secretName: cluster1-consul-bootstrap-acl-token secretKey: token - gossipEncryption: - secretName: consul-gossip-encryption-key - secretKey: key tls: enabled: true - enableAutoEncrypt: true caCert: secretName: cluster1-consul-ca-cert secretKey: tls.crt externalServers: enabled: true - # This should be any node IP of the first k8s cluster + # This should be any node IP of the first k8s cluster or the load balancer IP if using LoadBalancer service type for the UI. hosts: ["10.0.0.4"] - # The node port of the UI's NodePort service + # The node port of the UI's NodePort service or the load balancer port. httpsPort: 31557 tlsServerName: server.dc1.consul # The address of the kube API server of this Kubernetes cluster k8sAuthMethodHost: https://kubernetes.example.com:443 -client: - enabled: true - join: ["provider=k8s kubeconfig=/consul/userconfig/cluster1-kubeconfig/kubeconfig label_selector=\"app=consul,component=server\""] - extraVolumes: - - type: secret - name: cluster1-kubeconfig - load: false connectInject: enabled: true ``` -Note the references to the secrets extracted and applied from the first cluster in ACL, gossip, and TLS configuration. +Note the references to the secrets extracted and applied from the first cluster in ACL and TLS configuration. The `externalServers.hosts` and `externalServers.httpsPort` refer to the IP and port of the UI's NodePort service deployed in the first cluster. @@ -187,23 +165,10 @@ reach the Kubernetes API in that cluster. The easiest way to get it is from the `kubeconfig` by running `kubectl config view` and grabbing the value of `cluster.server` for the second cluster. -Lastly, set up the clients so that they can discover the servers in the first cluster. -For this, Consul's cloud auto-join feature -for the [Kubernetes provider](/docs/install/cloud-auto-join#kubernetes-k8s) can be used. - -This can be configured by saving the `kubeconfig` for the first cluster as a Kubernetes secret in the second cluster -and referencing it in the `clients.join` value. Note that the secret is made available to the client pods -by setting it in `client.extraVolumes`. - -~> **Note:** The kubeconfig provided to the client should have minimal permissions. -The cloud auto-join provider will only need permission to read pods. -Please see [Kubernetes Cloud auto-join](/docs/install/cloud-auto-join#kubernetes-k8s) -for more details. - Now, proceed with the installation of the second cluster. ```shell-session -$ helm install ${HELM_RELEASE_CLIENT} --values cluster2-values.yaml hashicorp/consul +$ helm install ${HELM_RELEASE_CONSUL} --values cluster2-values.yaml hashicorp/consul ``` ## Verifying the Consul Service Mesh works diff --git a/website/content/docs/k8s/deployment-configurations/vault/data-integration/gossip.mdx b/website/content/docs/k8s/deployment-configurations/vault/data-integration/gossip.mdx index 187064d9f09a..dd2915ba52dd 100644 --- a/website/content/docs/k8s/deployment-configurations/vault/data-integration/gossip.mdx +++ b/website/content/docs/k8s/deployment-configurations/vault/data-integration/gossip.mdx @@ -7,7 +7,7 @@ description: >- # Storing Gossip Encryption Key in Vault -This topic describes how to configure the Consul Helm chart to use TLS certificates issued by Vault in the Consul controller and connect inject webhooks. +This topic describes how to configure the Consul Helm chart to use a gossip encryption key stored in Vault. ## Overview Complete the steps outlined in the [Data Integration](/docs/k8s/deployment-configurations/vault/data-integration) section to use a gossip encryption key stored in Vault. diff --git a/website/content/docs/k8s/deployment-configurations/vault/data-integration/index.mdx b/website/content/docs/k8s/deployment-configurations/vault/data-integration/index.mdx index 735b7d12fa86..86cc9e81f0cc 100644 --- a/website/content/docs/k8s/deployment-configurations/vault/data-integration/index.mdx +++ b/website/content/docs/k8s/deployment-configurations/vault/data-integration/index.mdx @@ -7,54 +7,34 @@ description: >- # Vault as the Secrets Backend - Data Integration -## Overview - -This topic describes an overview of how to configure Vault and Consul in order to share secrets for use within Consul. - -### General Integration Steps - -You must complete two general procedures for each secret you wish to store in Vault. - -Complete the following steps once: - 1. Store the secret in Vault. - 1. Create a Vault policy that authorizes the desired level of access to the secret. - -Repeat the following steps for each datacenter in the cluster: - 1. Create Vault Kubernetes auth roles that link the policy to each Consul on Kubernetes service account that requires access. - 1. Update the Consul on Kubernetes helm chart. +This topic describes how to configure Vault and Consul in order to share secrets for use within Consul. ## Prerequisites -Prior to setting up the data integration between Vault and Consul on Kubernetes, you will need to have read and completed the steps in the [Systems Integration](/docs/k8s/deployment-configurations/vault/systems-integration) section of [Vault as a Secrets Backend](/docs/k8s/deployment-configurations/vault). -### Example - Gossip Encryption Key Integration +Before you set up the data integration between Vault and Consul on Kubernetes, read and complete the steps in the [Systems Integration](/docs/k8s/deployment-configurations/vault/systems-integration) section of [Vault as a Secrets Backend](/docs/k8s/deployment-configurations/vault). -Following the general integration steps, a more detailed workflow for integration of the [Gossip encryption key](/docs/k8s/deployment-configurations/vault/data-integration/gossip) with the Vault Secrets backend would like the following: +## General integration steps +For each secret you want to store in Vault, you must complete two multi-step procedures. Complete the following steps once: 1. Store the secret in Vault. - - Save the gossip encryption key in Vault at the path `secret/consul/gossip`. 1. Create a Vault policy that authorizes the desired level of access to the secret. - - Create a Vault policy that you name `gossip-policy` which allows `read` access to the path `secret/consul/gossip`. Repeat the following steps for each datacenter in the cluster: 1. Create Vault Kubernetes auth roles that link the policy to each Consul on Kubernetes service account that requires access. - - Both Consul servers and Consul clients need access to the gossip encryption key, so you create two Vault Kubernetes: - - A role called `consul-server` that maps the Kubernetes namespace and service account name for your consul servers to the `gossip-policy` created in [step 2](#one-time-setup-in-vault) of One time setup in Vault. - - A role called `consul-client` that maps the Kubernetes namespace and service account name for your consul clients to the `gossip-policy` created in [step 2](#one-time-setup-in-vault) of One time setup in Vault.. - 1. Update the Consul on Kubernetes helm chart. - - Configure the Vault Kubernetes auth roles created for the gossip encryption key: - - [`global.secretsBackend.vault.consulServerRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulserverrole) is set to the `consul-server` Vault Kubernetes auth role created previously. - - [`global.secretsBackend.vault.consulClientRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulclientrole) is set to the `consul-client` Vault Kubernetes auth role created previously. - -## Secrets to Service Account Mapping - -At the most basic level, the goal of this configuration is to authorize a Consul on Kubernetes service account to access a secret in Vault. -Below is a mapping of Vault secrets and the Consul on Kubernetes service accounts that need to access them. -(NOTE: `Consul components` refers to all other services and jobs that are not Consul servers or clients. + 1. Update the Consul on Kubernetes Helm chart. + +## Secrets-to-service account mapping + +At the most basic level, the goal of this configuration is to authorize a Consul on Kubernetes service account to access a secret in Vault. + +The following table associates Vault secrets and the Consul on Kubernetes service accounts that require access. +(NOTE: `Consul components` refers to all other services and jobs that are not Consul servers or clients. It includes things like terminating gateways, ingress gateways, etc.) -### Primary Datacenter +### Primary datacenter + | Secret | Service Account For | Configurable Role in Consul k8s Helm | | ------ | ------------------- | ------------------------------------ | |[ACL Bootstrap token](/docs/k8s/deployment-configurations/vault/data-integration/bootstrap-token) | Consul server-acl-init job | [`global.secretsBackend.vault.manageSystemACLsRole`](/docs/k8s/helm#v-global-secretsbackend-vault-managesystemaclsrole)| @@ -62,13 +42,15 @@ It includes things like terminating gateways, ingress gateways, etc.) |[ACL Replication token](/docs/k8s/deployment-configurations/vault/data-integration/replication-token) | Consul server-acl-init job | [`global.secretsBackend.vault.manageSystemACLsRole`](/docs/k8s/helm#v-global-secretsbackend-vault-managesystemaclsrole)| |[Enterprise license](/docs/k8s/deployment-configurations/vault/data-integration/enterprise-license) | Consul servers
    Consul clients | [`global.secretsBackend.vault.consulServerRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulserverrole)
    [`global.secretsBackend.vault.consulClientRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulclientrole)| |[Gossip encryption key](/docs/k8s/deployment-configurations/vault/data-integration/gossip) | Consul servers
    Consul clients | [`global.secretsBackend.vault.consulServerRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulserverrole)
    [`global.secretsBackend.vault.consulClientRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulclientrole)| -|[Snapshot Agent config](/docs/k8s/deployment-configurations/vault/data-integration/snapshot-agent-config) | Consul snapshot agent | [`global.secretsBackend.vault.consulSnapshotAgentRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulsnapshotagentrole)| +|[Snapshot Agent config](/docs/k8s/deployment-configurations/vault/data-integration/snapshot-agent-config) | Consul servers | [`global.secretsBackend.vault.consulServerRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulserverrole)| |[Server TLS credentials](/docs/k8s/deployment-configurations/vault/data-integration/server-tls) | Consul servers
    Consul clients
    Consul components | [`global.secretsBackend.vault.consulServerRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulserverrole)
    [`global.secretsBackend.vault.consulClientRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulclientrole)
    [`global.secretsBackend.vault.consulCARole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulcarole)| |[Service Mesh and Consul client TLS credentials](/docs/k8s/deployment-configurations/vault/data-integration/connect-ca) | Consul servers | [`global.secretsBackend.vault.consulServerRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulserverrole)| |[Webhook TLS certificates for controller and connect inject](/docs/k8s/deployment-configurations/vault/data-integration/connect-ca) | Consul controllers
    Consul connect inject | [`global.secretsBackend.vault.controllerRole`](/docs/k8s/helm#v-global-secretsbackend-vault-controllerrole)
    [`global.secretsBackend.vault.connectInjectRole`](/docs/k8s/helm#v-global-secretsbackend-vault-controllerrole)| -### Secondary Datacenters +### Secondary datacenters + The mapping for secondary data centers is similar with the following differences: + - There is no use of bootstrap token because ACLs would have been bootstrapped in the primary datacenter. - ACL Partition token is mapped to both the `server-acl-init` job and the `partition-init` job service accounts. - ACL Replication token is mapped to both the `server-acl-init` job and Consul service accounts. @@ -79,30 +61,18 @@ The mapping for secondary data centers is similar with the following differences |[ACL Replication token](/docs/k8s/deployment-configurations/vault/data-integration/replication-token) | Consul server-acl-init job
    Consul servers | [`global.secretsBackend.vault.manageSystemACLsRole`](/docs/k8s/helm#v-global-secretsbackend-vault-managesystemaclsrole)
    [`global.secretsBackend.vault.consulServerRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulserverrole)| |[Enterprise license](/docs/k8s/deployment-configurations/vault/data-integration/enterprise-license) | Consul servers
    Consul clients | [`global.secretsBackend.vault.consulServerRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulserverrole)
    [`global.secretsBackend.vault.consulClientRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulclientrole)| |[Gossip encryption key](/docs/k8s/deployment-configurations/vault/data-integration/gossip) | Consul servers
    Consul clients | [`global.secretsBackend.vault.consulServerRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulserverrole)
    [`global.secretsBackend.vault.consulClientRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulclientrole)| -|[Snapshot Agent config](/docs/k8s/deployment-configurations/vault/data-integration/snapshot-agent-config) | Consul snapshot agent | [`global.secretsBackend.vault.consulSnapshotAgentRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulsnapshotagentrole)| +|[Snapshot Agent config](/docs/k8s/deployment-configurations/vault/data-integration/snapshot-agent-config) | Consul servers | [`global.secretsBackend.vault.consulServerRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulserverrole)| |[Server TLS credentials](/docs/k8s/deployment-configurations/vault/data-integration/server-tls) | Consul servers
    Consul clients
    Consul components | [`global.secretsBackend.vault.consulServerRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulserverrole)
    [`global.secretsBackend.vault.consulClientRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulclientrole)
    [`global.secretsBackend.vault.consulCARole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulcarole)| |[Service Mesh and Consul client TLS credentials](/docs/k8s/deployment-configurations/vault/data-integration/connect-ca) | Consul servers | [`global.secretsBackend.vault.consulServerRole`](/docs/k8s/helm#v-global-secretsbackend-vault-consulserverrole)| |[Webhook TLS certificates for controller and connect inject](/docs/k8s/deployment-configurations/vault/data-integration/connect-ca) | Consul controllers
    Consul connect inject | [`global.secretsBackend.vault.controllerRole`](/docs/k8s/helm#v-global-secretsbackend-vault-controllerrole)
    [`global.secretsBackend.vault.connectInjectRole`](/docs/k8s/helm#v-global-secretsbackend-vault-controllerrole)| -### Combining policies within roles -As you can see in the table above, depending upon your needs, a Consul on Kubernetes service account could have the need to request more than one secret. In these cases, you will want to create one role for the Consul on Kubernetes service account that is mapped to multiple policies, each of which allows it access to a given secret. -For example, if your Consul on Kubernetes servers need access to [Gossip encryption key](/docs/k8s/deployment-configurations/vault/data-integration/gossip), [Consul Server TLS credentials](/docs/k8s/deployment-configurations/vault/data-integration/server-tls), and [Enterprise license](/docs/k8s/deployment-configurations/vault/data-integration/enterprise-license), assuming you have already saved the secrets in vault, you would: -1. Create a policy for each secret. - 1. Gossip encryption key - - +### Combining policies within roles - ```HCL - path "secret/data/consul/gossip" { - capabilities = ["read"] - } - ``` +As you can see in the table above, depending upon your needs, a Consul on Kubernetes service account could have the need to request more than one secret. In these cases, you will want to create one role for the Consul on Kubernetes service account that is mapped to multiple policies, each of which allows it access to a given secret. - +For example, if your Consul on Kubernetes servers need access to [Consul Server TLS credentials](/docs/k8s/deployment-configurations/vault/data-integration/server-tls) and an [Enterprise license](/docs/k8s/deployment-configurations/vault/data-integration/enterprise-license): - ```shell-session - $ vault policy write gossip-policy gossip-policy.hcl - ``` +1. Create a policy for each secret. 1. Consul Server TLS credentials @@ -141,12 +111,14 @@ For example, if your Consul on Kubernetes servers need access to [Gossip encrypt $ vault write auth/kubernetes/role/consul-server \ bound_service_account_names= \ bound_service_account_namespaces= \ - policies=gossip-policy,ca-policy,license-policy \ + policies=ca-policy,license-policy \ ttl=1h ``` ## Detailed data integration guides + The following secrets can be stored in Vault KV secrets engine, which is meant to handle arbitrary secrets: + - [ACL Bootstrap token](/docs/k8s/deployment-configurations/vault/data-integration/bootstrap-token) - [ACL Partition token](/docs/k8s/deployment-configurations/vault/data-integration/partition-token) - [ACL Replication token](/docs/k8s/deployment-configurations/vault/data-integration/replication-token) @@ -155,9 +127,11 @@ The following secrets can be stored in Vault KV secrets engine, which is meant t - [Snapshot Agent config](/docs/k8s/deployment-configurations/vault/data-integration/snapshot-agent-config) The following TLS certificates and keys can generated and managed by Vault the Vault PKI Engine, which is meant to handle things like certificate expiration and rotation: + - [Server TLS credentials](/docs/k8s/deployment-configurations/vault/data-integration/server-tls) - [Service Mesh and Consul client TLS credentials](/docs/k8s/deployment-configurations/vault/data-integration/connect-ca) - [Vault as the Webhook Certificate Provider for Consul Controller and Connect Inject on Kubernetes](/docs/k8s/deployment-configurations/vault/data-integration/webhook-certs) -## Secrets to Service Account Mapping +## Secrets-to-service account mapping + Read through the [detailed data integration guides](#detailed-data-integration-guides) that are pertinent to your environment. diff --git a/website/content/docs/k8s/deployment-configurations/vault/data-integration/server-tls.mdx b/website/content/docs/k8s/deployment-configurations/vault/data-integration/server-tls.mdx index 02074c48c9d5..86ab3a6bd078 100644 --- a/website/content/docs/k8s/deployment-configurations/vault/data-integration/server-tls.mdx +++ b/website/content/docs/k8s/deployment-configurations/vault/data-integration/server-tls.mdx @@ -104,7 +104,6 @@ this is required for the Consul components to communicate with the Consul server allow_subdomains=true \ allow_bare_domains=true \ allow_localhost=true \ - generate_lease=true \ max_ttl="720h" ``` diff --git a/website/content/docs/k8s/deployment-configurations/vault/data-integration/snapshot-agent-config.mdx b/website/content/docs/k8s/deployment-configurations/vault/data-integration/snapshot-agent-config.mdx index f6328410228d..4bb99d2a6906 100644 --- a/website/content/docs/k8s/deployment-configurations/vault/data-integration/snapshot-agent-config.mdx +++ b/website/content/docs/k8s/deployment-configurations/vault/data-integration/snapshot-agent-config.mdx @@ -20,7 +20,7 @@ Repeat the following steps for each datacenter in the cluster: 1. Update the Consul on Kubernetes helm chart. ## Prerequisites -Prior to setting up the data integration between Vault and Consul on Kubernetes, you will need to have: +Prior to setting up the data integration between Vault and Consul on Kubernetes, you will need to have: 1. Read and completed the steps in the [Systems Integration](/docs/k8s/deployment-configurations/vault/systems-integration) section of [Vault as a Secrets Backend](/docs/k8s/deployment-configurations/vault). 2. Read the [Data Integration Overview](/docs/k8s/deployment-configurations/vault/data-integration) section of [Vault as a Secrets Backend](/docs/k8s/deployment-configurations/vault). @@ -56,21 +56,23 @@ $ vault policy write snapshot-agent-config-policy snapshot-agent-config-policy.h ## Create Vault Authorization Roles for Consul -Next, you will create a Kubernetes auth role for the Consul snapshot agent: +Next, you will add this policy to your Consul server Kubernetes auth role: ```shell-session $ vault write auth/kubernetes/role/consul-server \ - bound_service_account_names= \ + bound_service_account_names= \ bound_service_account_namespaces= \ policies=snapshot-agent-config-policy \ ttl=1h ``` +Note that if you have other policies associated +with the Consul server service account, you will need to make to include those as well. To find out the service account name of the Consul snapshot agent, you can run the following `helm template` command with your Consul on Kubernetes values file: ```shell-session -$ helm template --release-name ${RELEASE_NAME} -s templates/client-snapshot-agent-serviceaccount.yaml hashicorp/consul -f values.yaml +$ helm template --release-name ${RELEASE_NAME} -s templates/server-serviceaccount.yaml hashicorp/consul -f values.yaml ``` ## Update Consul on Kubernetes Helm chart @@ -85,7 +87,7 @@ global: secretsBackend: vault: enabled: true - consulSnapshotAgentRole: snapshot-agent + consulServerRole: consul-server client: snapshotAgent: configSecret: diff --git a/website/content/docs/k8s/deployment-configurations/vault/data-integration/webhook-certs.mdx b/website/content/docs/k8s/deployment-configurations/vault/data-integration/webhook-certs.mdx index 867779769acc..a2076909dc2e 100644 --- a/website/content/docs/k8s/deployment-configurations/vault/data-integration/webhook-certs.mdx +++ b/website/content/docs/k8s/deployment-configurations/vault/data-integration/webhook-certs.mdx @@ -10,28 +10,28 @@ description: >- This topic describes how to configure the Consul Helm chart to use TLS certificates issued by Vault in the Consul controller and connect inject webhooks. ## Overview -In a Consul Helm chart configuration that does not use Vault, webhook-cert-manager normally fulfills the role of ensuring that a valid certificate is updated to the `mutatingwebhookconfiguration` of either controller or connect inject to ensure that Kubernetes can communicate with each of these services. +In a Consul Helm chart configuration that does not use Vault, webhook-cert-manager normally fulfills the role of ensuring that a valid certificate is updated to the `mutatingwebhookconfiguration` of either controller or connect inject to ensure that Kubernetes can communicate with each of these services. -When Vault is configured as the controller and connect inject Webhook Certificate Provider on Kubernetes: +When Vault is configured as the controller and connect inject Webhook Certificate Provider on Kubernetes: - `webhook-cert-manager` is no longer deployed to the cluster. - - controller and connect inject each get their webhook certificates from its own Vault PKI mount via the injected Vault Agent. - - controller and connect inject each need to be configured with its own Vault Role that has necessary permissions to receive certificates from its respective PKI mount. - - controller and connect inject each locally update its own `mutatingwebhookconfiguration` so that Kubernetes can relay events. + - Controller and connect inject each get their webhook certificates from its own Vault PKI mount via the injected Vault Agent. + - Controller and connect inject each need to be configured with its own Vault Role that has necessary permissions to receive certificates from its respective PKI mount. + - Controller and connect inject each locally update its own `mutatingwebhookconfiguration` so that Kubernetes can relay events. - Vault manages certificate rotation and rotates certificates to each webhook. To use Vault as the controller and connect inject Webhook Certificate Provider, we will need to modify the steps outlined in the [Data Integration](/docs/k8s/deployment-configurations/vault/data-integration) section: These following steps will be repeated for each datacenter: 1. Create a Vault policy that authorizes the desired level of access to the secret. - 1. (Added) Create Vault PKI roles for controller and connect inject each that establish the domains that each is allowed to issue certificates for. + 1. (Added) Create Vault PKI roles for controller and connect inject that each establish the domains that each is allowed to issue certificates for. 1. Create Vault Kubernetes auth roles that link the policy to each Consul on Kubernetes service account that requires access. 1. Configure the Vault Kubernetes auth roles in the Consul on Kubernetes helm chart. ## Prerequisites -Complete the following prerequisites prior to implementing the integration described in this topic: +Complete the following prerequisites prior to implementing the integration described in this topic: 1. Verify that you have completed the steps described in [Systems Integration](/docs/k8s/deployment-configurations/vault/systems-integration) section of [Vault as a Secrets Backend](/docs/k8s/deployment-configurations/vault). 1. You should be familiar with the [Data Integration Overview](/docs/k8s/deployment-configurations/vault/data-integration) section of [Vault as a Secrets Backend](/docs/k8s/deployment-configurations/vault). -1. Configure [Vault as the Server TLS Certificate Provider on Kubernetes](/docs/k8s/deployment-configurations/vault/data-integration/server-tls) +1. Configure [Vault as the Server TLS Certificate Provider on Kubernetes](/docs/k8s/deployment-configurations/vault/data-integration/server-tls) 1. Configure [Vault as the Service Mesh Certificate Provider on Kubernetes](/docs/k8s/deployment-configurations/vault/data-integration/connect-ca) ## Bootstrapping the PKI Engines @@ -74,44 +74,45 @@ Issue the following commands to enable and configure the PKI Secrets Engine to s 1. Create a policy that allows `["create", "update"]` access to the [certificate issuing URL](https://www.vaultproject.io/api-docs/secret/pki) so Consul controller and connect inject can fetch a new certificate/key pair and provide it to the Kubernetes `mutatingwebhookconfiguration`. - The path to the secret referenced in the `path` resource is the same value that you will configure in the `global.secretsBackend.vault.controller.tlsCert.secretName` and `global.secretsBackend.vault.connectInject.tlsCert.secretName` Helm configuration (refer to [Update Consul on Kubernetes Helm chart](#update-consul-on-kubernetes-helm-chart)). + The path to the secret referenced in the `path` resource is the same value that you will configure in the `global.secretsBackend.vault.controller.tlsCert.secretName` and `global.secretsBackend.vault.connectInject.tlsCert.secretName` Helm configuration (refer to [Update Consul on Kubernetes Helm chart](#update-consul-on-kubernetes-helm-chart)). - ```shell-session - $ vault policy write controller-tls-policy - < \ @@ -204,11 +205,6 @@ global: consulCARole: "consul-ca" controllerRole: "controller-role" connectInjectRole: "connect-inject-role" - controller: - caCert: - secretName: "controller/cert/ca" - tlsCert: - secretName: "controller/issue/controller-role" connectInject: caCert: secretName: "connect-inject/cert/ca" @@ -228,8 +224,6 @@ server: load: "false" connectInject: enabled: true -controller: - enabled: true ```
    diff --git a/website/content/docs/k8s/deployment-configurations/vault/wan-federation.mdx b/website/content/docs/k8s/deployment-configurations/vault/wan-federation.mdx index 92f1f2557b5c..6e84eb973804 100644 --- a/website/content/docs/k8s/deployment-configurations/vault/wan-federation.mdx +++ b/website/content/docs/k8s/deployment-configurations/vault/wan-federation.mdx @@ -7,7 +7,7 @@ description: >- # Federation Between Kubernetes Clusters with Vault as Secrets Backend -~> **Note**: This topic requires familiarity with [Mesh Gateways](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters), [WAN Federation Via Mesh Gateways](/docs/connect/gateways/mesh-gateway/wan-federation-via-mesh-gateways). +~> **Note**: This topic requires familiarity with [Mesh Gateways](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-wan-datacenters), [WAN Federation Via Mesh Gateways](/docs/connect/gateways/mesh-gateway/wan-federation-via-mesh-gateways). This page describes how you can federate multiple Kubernetes clusters using Vault as the secrets backend. See the [Multi-Cluster Overview](/docs/k8s/deployment-configurations/multi-cluster) for more information on use cases and how it works. @@ -16,7 +16,7 @@ The [Federation Between Kubernetes Clusters](/docs/k8s/deployment-configurations ## Usage -The expected use case is to create WAN Federation on Kubernetes clusters. The following procedure will result in a WAN Federation with Vault as the secrets backend between two clusters, dc1 and dc2. dc1 will act as the primary Consul cluster and will also contain the Vault server installation. dc2 will be the secondary Consul cluster. +The expected use case is to create WAN Federation on Kubernetes clusters. The following procedure will result in a WAN Federation with Vault as the secrets backend between two clusters, dc1 and dc2. dc1 will act as the primary Consul cluster and will also contain the Vault server installation. dc2 will be the secondary Consul cluster. ![Consul on Kubernetes with Vault as the Secrets Backend](/img/k8s/consul-vault-wan-federation-topology.svg 'Consul on Kubernetes with Vault as the Secrets Backend') @@ -36,7 +36,7 @@ The two data centers will federated using mesh gateways. This communication top In this setup, you will deploy Vault server in the primary datacenter (dc1) Kubernetes cluster, which is also the primary Consul datacenter. You will configure your Vault Helm installation in the secondary datacenter (dc2) Kubernetes cluster to use it as an external server. This way there will be a single vault server cluster that will be used by both Consul datacenters. -~> **Note**: For demonstration purposes, you will deploy a Vault server in dev mode. For production installations, this is not recommended. Please visit the [Vault Deployment Guide](https://learn.hashicorp.com/tutorials/vault/raft-deployment-guide) for guidance on how to install Vault in a production setting. +~> **Note**: For demonstration purposes, you will deploy a Vault server in dev mode. For production installations, this is not recommended. Please visit the [Vault Deployment Guide](https://learn.hashicorp.com/tutorials/vault/raft-deployment-guide) for guidance on how to install Vault in a production setting. 1. Change your current Kubernetes context to target the primary datacenter (dc1). @@ -143,8 +143,8 @@ Repeat the following steps for each datacenter in the cluster: ``` ### Primary Datacenter (dc1) -1. Install the Vault Injector in your Consul Kubernetes cluster (dc1), which is used for accessing secrets from Vault. - +1. Install the Vault Injector in your Consul Kubernetes cluster (dc1), which is used for accessing secrets from Vault. + -> **Note**: In the primary datacenter (dc1), you will not have to configure `injector.externalvaultaddr` value because the Vault server is in the same primary datacenter (dc1) cluster. @@ -165,7 +165,7 @@ Repeat the following steps for each datacenter in the cluster: Next, install Vault in the Kubernetes cluster. - + ```shell-session $ helm upgrade vault-dc1 --values vault-dc1.yaml hashicorp/vault --wait ``` @@ -202,7 +202,7 @@ Repeat the following steps for each datacenter in the cluster: 1. Install the Vault Injector in the secondary datacenter (dc2). In the secondary datacenter (dc2), you will configure the `externalvaultaddr` value point to the external address of the Vault server in the primary datacenter (dc1). - + Change your Kubernetes context to target the secondary datacenter (dc2): ```shell-session @@ -210,7 +210,7 @@ Repeat the following steps for each datacenter in the cluster: ``` - + ```yaml server: enabled: false @@ -219,9 +219,9 @@ Repeat the following steps for each datacenter in the cluster: externalVaultAddr: ${VAULT_ADDR} authPath: auth/kubernetes-dc2 ``` - + - + Next, install Vault in the Kubernetes cluster. ```shell-session $ helm install vault-dc2 --values vault-dc2.yaml hashicorp/vault --wait @@ -273,7 +273,7 @@ Repeat the following steps for each datacenter in the cluster: $ export K8S_DC2_JWT_TOKEN="$(kubectl get secret `kubectl get serviceaccounts vault-dc2-auth-method --output jsonpath='{.secrets[0].name}'` --output jsonpath='{.data.token}' | base64 --decode)" ``` -1. Configure Auth Method with the JWT token of service account. You will have to get the externally reachable address of the secondary Consul datacenter (dc2) in the secondary Kubernetes cluster and set `kubernetes_host` within the Auth Method configuration. +1. Configure Auth Method with the JWT token of service account. You will have to get the externally reachable address of the secondary Consul datacenter (dc2) in the secondary Kubernetes cluster and set `kubernetes_host` within the Auth Method configuration. ```shell-session $ export KUBE_API_URL_DC2=$(kubectl config view --output jsonpath="{.clusters[?(@.name == \"$(kubectl config current-context)\")].cluster.server}") @@ -297,7 +297,7 @@ Repeat the following steps for each datacenter in the cluster: enabled: true ``` - + ## Data Integration There are two main procedures for using Vault as the service mesh certificate provider in Kubernetes. @@ -319,10 +319,10 @@ Repeat the following steps for each datacenter in the cluster: ```shell-session $ vault kv put consul/secret/replication token="$(uuidgen | tr '[:upper:]' '[:lower:]')" - ``` + ``` ```shell-session $ vault write pki/root/generate/internal common_name="Consul CA" ttl=87600h - ``` + ``` 1. Create Vault policies that authorize the desired level of access to the secrets. @@ -475,8 +475,6 @@ Repeat the following steps for each datacenter in the cluster: connectInject: replicas: 1 enabled: true - controller: - enabled: true meshGateway: enabled: true replicas: 1 @@ -490,7 +488,7 @@ Repeat the following steps for each datacenter in the cluster: ``` ### Pre-installation for Secondary Datacenter (dc2) -1. Update the Consul on Kubernetes helm chart. For secondary datacenter (dc2), you will need to get the address of the mesh gateway from the **primary datacenter (dc1)** cluster. +1. Update the Consul on Kubernetes helm chart. For secondary datacenter (dc2), you will need to get the address of the mesh gateway from the **primary datacenter (dc1)** cluster. Keep your Kubernetes context targeting dc1 and set the `MESH_GW_HOST` environment variable that you will use in the Consul Helm chart for secondary datacenter (dc2). @@ -610,7 +608,7 @@ Repeat the following steps for each datacenter in the cluster: ``` 1. Configure and install Consul in the secondary datacenter (dc2). - + -> **Note**: To configure Vault as the Connect CA in secondary datacenters, you need to make sure that the Root CA path is the same. The intermediate path is different for each datacenter. In the `connectCA` Helm configuration for a secondary datacenter, you can specify a `intermediatePKIPath` that is, for example, prefixed with the datacenter for which this configuration is intended (e.g. `dc2/connect-intermediate`). diff --git a/website/content/docs/k8s/dns.mdx b/website/content/docs/k8s/dns.mdx index c5c89c8347b6..24a1ecdb95d4 100644 --- a/website/content/docs/k8s/dns.mdx +++ b/website/content/docs/k8s/dns.mdx @@ -8,10 +8,10 @@ description: >- # Resolve Consul DNS Requests in Kubernetes One of the primary query interfaces to Consul is the -[DNS interface](/docs/discovery/dns). You can configure Consul DNS in +[DNS interface](/consul/docs/services/discovery/dns-overview). You can configure Consul DNS in Kubernetes using a [stub-domain configuration](https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/#configure-stub-domain-and-upstream-dns-servers) -if using KubeDNS or a [proxy configuration](https://coredns.io/plugins/proxy/) if using CoreDNS. +if using KubeDNS or a [proxy configuration](https://coredns.io/plugins/forward/) if using CoreDNS. Once configured, DNS requests in the form `.service.consul` will resolve for services in Consul. This will work from all Kubernetes namespaces. diff --git a/website/content/docs/k8s/helm.mdx b/website/content/docs/k8s/helm.mdx index 4a5206e54824..36a96e8c59e6 100644 --- a/website/content/docs/k8s/helm.mdx +++ b/website/content/docs/k8s/helm.mdx @@ -28,7 +28,6 @@ Use these links to navigate to a particular top-level stanza. - [`ui`](#h-ui) - [`syncCatalog`](#h-synccatalog) - [`connectInject`](#h-connectinject) -- [`controller`](#h-controller) - [`meshGateway`](#h-meshgateway) - [`ingressGateways`](#h-ingressgateways) - [`terminatingGateways`](#h-terminatinggateways) @@ -59,31 +58,14 @@ Use these links to navigate to a particular top-level stanza. the prefix will be `-consul`. - `domain` ((#v-global-domain)) (`string: consul`) - The domain Consul will answer DNS queries for - (see `-domain` (https://www.consul.io/docs/agent/config/cli-flags#_domain)) and the domain services synced from + (Refer to [`-domain`](https://developer.hashicorp.com/consul/docs/agent/config/cli-flags#_domain)) and the domain services synced from Consul into Kubernetes will have, e.g. `service-name.service.consul`. - - `peering` ((#v-global-peering)) - [Experimental] Configures the Cluster Peering feature. Requires Consul v1.13+ and Consul-K8s v0.45+. + - `peering` ((#v-global-peering)) - Configures the Cluster Peering feature. Requires Consul v1.14+ and Consul-K8s v1.0.0+. - `enabled` ((#v-global-peering-enabled)) (`boolean: false`) - If true, the Helm chart enables Cluster Peering for the cluster. This option enables peering controllers and allows use of the PeeringAcceptor and PeeringDialer CRDs for establishing service mesh peerings. - - `tokenGeneration` ((#v-global-peering-tokengeneration)) - - - `serverAddresses` ((#v-global-peering-tokengeneration-serveraddresses)) - - - `source` ((#v-global-peering-tokengeneration-serveraddresses-source)) (`string: ""`) - Source can be set to "","consul" or "static". - - "" is the default source. If servers are enabled, it will check if `server.exposeService` is enabled, and read - the addresses from that service to use as the peering token server addresses. If using admin partitions and - only Consul client agents are enabled, the addresses in `externalServers.hosts` and `externalServers.grpcPort` - will be used. - - "consul" will use the Consul advertise addresses in the peering token. - - "static" will use the addresses specified in `global.peering.tokenGeneration.serverAddresses.static`. - - - `static` ((#v-global-peering-tokengeneration-serveraddresses-static)) (`array: []`) - Static addresses must be formatted "hostname|ip:port" where the port is the Consul server(s)' grpc port. - - `adminPartitions` ((#v-global-adminpartitions)) - Enabling `adminPartitions` allows creation of Admin Partitions in Kubernetes clusters. It additionally indicates that you are running Consul Enterprise v1.11+ with a valid Consul Enterprise license. Admin partitions enables deploying services across partitions, while sharing @@ -97,27 +79,6 @@ Use these links to navigate to a particular top-level stanza. Changing the partition name would require an un-install and a re-install with the updated name. Must be "default" in the server cluster ie the Kubernetes cluster that the Consul server pods are deployed onto. - - `service` ((#v-global-adminpartitions-service)) - Partition service properties. - - - `type` ((#v-global-adminpartitions-service-type)) (`string: LoadBalancer`) - - - `nodePort` ((#v-global-adminpartitions-service-nodeport)) - Optionally set the nodePort value of the partition service if using a NodePort service. - If not set and using a NodePort service, Kubernetes will automatically assign - a port. - - - `rpc` ((#v-global-adminpartitions-service-nodeport-rpc)) (`integer: null`) - RPC node port - - - `serf` ((#v-global-adminpartitions-service-nodeport-serf)) (`integer: null`) - Serf node port - - - `https` ((#v-global-adminpartitions-service-nodeport-https)) (`integer: null`) - HTTPS node port - - - `annotations` ((#v-global-adminpartitions-service-annotations)) (`string: null`) - Annotations to apply to the partition service. - - ```yaml - annotations: | - "annotation-key": "annotation-value" - ``` - - `image` ((#v-global-image)) (`string: hashicorp/consul:`) - The name (and tag) of the Consul Docker image for clients and servers. This can be overridden per component. This should be pinned to a specific version tag, otherwise you may inadvertently upgrade your Consul version. @@ -133,7 +94,7 @@ Use these links to navigate to a particular top-level stanza. - `imagePullSecrets` ((#v-global-imagepullsecrets)) (`array`) - Array of objects containing image pull secret names that will be applied to each service account. This can be used to reference image pull secrets if using a custom consul or consul-k8s-control-plane Docker image. - See https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry for reference. + Refer to https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry. Example: @@ -153,12 +114,13 @@ Use these links to navigate to a particular top-level stanza. https://github.com/hashicorp/consul/issues/1858. - `enablePodSecurityPolicies` ((#v-global-enablepodsecuritypolicies)) (`boolean: false`) - Controls whether pod security policies are created for the Consul components - created by this chart. See https://kubernetes.io/docs/concepts/policy/pod-security-policy/. + created by this chart. Refer to https://kubernetes.io/docs/concepts/policy/pod-security-policy/. - `secretsBackend` ((#v-global-secretsbackend)) - secretsBackend is used to configure Vault as the secrets backend for the Consul on Kubernetes installation. The Vault cluster needs to have the Kubernetes Auth Method, KV2 and PKI secrets engines enabled and have necessary secrets, policies and roles created prior to installing Consul. - See https://www.consul.io/docs/k8s/installation/vault for full instructions. + Refer to [Vault as the Secrets Backend](https://developer.hashicorp.com/consul/docs/k8s/deployment-configurations/vault) + documentation for full instructions. The Vault cluster _must_ not have the Consul cluster installed by this Helm chart as its storage backend as that would cause a circular dependency. @@ -196,16 +158,6 @@ Use these links to navigate to a particular top-level stanza. ``` and check the name of `metadata.name`. - - `consulSnapshotAgentRole` ((#v-global-secretsbackend-vault-consulsnapshotagentrole)) (`string: ""`) - The Vault role for the Consul client snapshot agent. - The role must be connected to the Consul client snapshot agent's service account. - The role must also have a policy with read capabilities for the snapshot agent config - defined by the `client.snapshotAgent.configSecret.secretName` value. - To discover the service account name of the Consul client, run - ```shell-session - $ helm template --show-only templates/client-snapshot-agent-serviceaccount.yaml --set client.snapshotAgent.enabled=true hashicorp/consul - ``` - and check the name of `metadata.name`. - - `manageSystemACLsRole` ((#v-global-secretsbackend-vault-managesystemaclsrole)) (`string: ""`) - A Vault role for the Consul `server-acl-init` job, which manages setting ACLs so that clients and components can obtain ACL tokens. The role must be connected to the `server-acl-init` job's service account. The role must also have a policy with read and write capabilities for the bootstrap, replication or partition tokens @@ -226,14 +178,14 @@ Use these links to navigate to a particular top-level stanza. ``` and check the name of `metadata.name`. - - `controllerRole` ((#v-global-secretsbackend-vault-controllerrole)) (`string: ""`) - The Vault role to read Consul controller's webhook's + - `controllerRole` ((#v-global-secretsbackend-vault-controllerrole)) (`string: ""`) - The Vault role to read Consul controller's webhook's CA and issue a certificate and private key. - A Vault policy must be created which grants issue capabilities to + A Vault policy must be created which grants issue capabilities to `global.secretsBackend.vault.controller.tlsCert.secretName`. - `connectInjectRole` ((#v-global-secretsbackend-vault-connectinjectrole)) (`string: ""`) - The Vault role to read Consul connect-injector webhook's CA and issue a certificate and private key. - A Vault policy must be created which grants issue capabilities to + A Vault policy must be created which grants issue capabilities to `global.secretsBackend.vault.connectInject.tlsCert.secretName`. - `consulCARole` ((#v-global-secretsbackend-vault-consulcarole)) (`string: ""`) - The Vault role for all Consul components to read the Consul's server's CA Certificate (unauthenticated). @@ -263,21 +215,21 @@ Use these links to navigate to a particular top-level stanza. The provider will be configured to use the Vault Kubernetes auth method and therefore requires the role provided by `global.secretsBackend.vault.consulServerRole` to have permissions to the root and intermediate PKI paths. - Please see https://www.consul.io/docs/connect/ca/vault#vault-acl-policies - for information on how to configure the Vault policies. + Please refer to [Vault ACL policies](https://developer.hashicorp.com/consul/docs/connect/ca/vault#vault-acl-policies) + documentation for information on how to configure the Vault policies. - `address` ((#v-global-secretsbackend-vault-connectca-address)) (`string: ""`) - The address of the Vault server. - `authMethodPath` ((#v-global-secretsbackend-vault-connectca-authmethodpath)) (`string: kubernetes`) - The mount path of the Kubernetes auth method in Vault. - `rootPKIPath` ((#v-global-secretsbackend-vault-connectca-rootpkipath)) (`string: ""`) - The path to a PKI secrets engine for the root certificate. - For more details, please refer to [Vault Connect CA configuration](https://www.consul.io/docs/connect/ca/vault#rootpkipath). + For more details, please refer to [Vault Connect CA configuration](https://developer.hashicorp.com/consul/docs/connect/ca/vault#rootpkipath). - `intermediatePKIPath` ((#v-global-secretsbackend-vault-connectca-intermediatepkipath)) (`string: ""`) - The path to a PKI secrets engine for the generated intermediate certificate. - For more details, please refer to [Vault Connect CA configuration](https://www.consul.io/docs/connect/ca/vault#intermediatepkipath). + For more details, please refer to [Vault Connect CA configuration](https://developer.hashicorp.com/consul/docs/connect/ca/vault#intermediatepkipath). - `additionalConfig` ((#v-global-secretsbackend-vault-connectca-additionalconfig)) (`string: {}`) - Additional Connect CA configuration in JSON format. - Please refer to [Vault Connect CA configuration](https://www.consul.io/docs/connect/ca/vault#configuration) + Please refer to [Vault Connect CA configuration](https://developer.hashicorp.com/consul/docs/connect/ca/vault#configuration) for all configuration options available for that provider. Example: @@ -296,14 +248,14 @@ Use these links to navigate to a particular top-level stanza. - `controller` ((#v-global-secretsbackend-vault-controller)) - - `tlsCert` ((#v-global-secretsbackend-vault-controller-tlscert)) - Configuration to the Vault Secret that Kubernetes will use on + - `tlsCert` ((#v-global-secretsbackend-vault-controller-tlscert)) - Configuration to the Vault Secret that Kubernetes will use on Kubernetes CRD creation, deletion, and update, to get TLS certificates used issued from vault to send webhooks to the controller. - `secretName` ((#v-global-secretsbackend-vault-controller-tlscert-secretname)) (`string: null`) - The Vault secret path that issues TLS certificates for controller webhooks. - - `caCert` ((#v-global-secretsbackend-vault-controller-cacert)) - Configuration to the Vault Secret that Kubernetes will use on + - `caCert` ((#v-global-secretsbackend-vault-controller-cacert)) - Configuration to the Vault Secret that Kubernetes will use on Kubernetes CRD creation, deletion, and update, to get CA certificates used issued from vault to send webhooks to the controller. @@ -312,14 +264,14 @@ Use these links to navigate to a particular top-level stanza. - `connectInject` ((#v-global-secretsbackend-vault-connectinject)) - - `caCert` ((#v-global-secretsbackend-vault-connectinject-cacert)) - Configuration to the Vault Secret that Kubernetes will use on + - `caCert` ((#v-global-secretsbackend-vault-connectinject-cacert)) - Configuration to the Vault Secret that Kubernetes uses on Kubernetes pod creation, deletion, and update, to get CA certificates used issued from vault to send webhooks to the ConnectInject. - `secretName` ((#v-global-secretsbackend-vault-connectinject-cacert-secretname)) (`string: null`) - The Vault secret path that contains the CA certificate for Connect Inject webhooks. - - `tlsCert` ((#v-global-secretsbackend-vault-connectinject-tlscert)) - Configuration to the Vault Secret that Kubernetes will use on + - `tlsCert` ((#v-global-secretsbackend-vault-connectinject-tlscert)) - Configuration to the Vault Secret that Kubernetes uses on Kubernetes pod creation, deletion, and update, to get TLS certificates used issued from vault to send webhooks to the ConnectInject. @@ -327,7 +279,7 @@ Use these links to navigate to a particular top-level stanza. inject webhooks. - `gossipEncryption` ((#v-global-gossipencryption)) - Configures Consul's gossip encryption key. - (see `-encrypt` (https://www.consul.io/docs/agent/config/cli-flags#_encrypt)). + (Refer to [`-encrypt`](https://developer.hashicorp.com/consul/docs/agent/config/cli-flags#_encrypt)). By default, gossip encryption is not enabled. The gossip encryption key may be set automatically or manually. The recommended method is to automatically generate the key. To automatically generate and set a gossip encryption key, set autoGenerate to true. @@ -335,7 +287,7 @@ Use these links to navigate to a particular top-level stanza. To manually generate a gossip encryption key, set secretName and secretKey and use Consul to generate a key, saving this as a Kubernetes secret or Vault secret path and key. If `global.secretsBackend.vault.enabled=true`, be sure to add the "data" component of the secretName path as required by - the Vault KV-2 secrets engine [see example]. + the Vault KV-2 secrets engine [refer to example]. ```shell-session $ kubectl create secret generic consul-gossip-encryption-key --from-literal=key=$(consul keygen) @@ -356,18 +308,23 @@ Use these links to navigate to a particular top-level stanza. - `secretKey` ((#v-global-gossipencryption-secretkey)) (`string: ""`) - The key within the Kubernetes secret or Vault secret key that holds the gossip encryption key. + - `logLevel` ((#v-global-gossipencryption-loglevel)) (`string: ""`) - Override global log verbosity level for `gossip-encryption-autogenerate-job` pods. One of "trace", "debug", "info", "warn", or "error". + - `recursors` ((#v-global-recursors)) (`array: []`) - A list of addresses of upstream DNS servers that are used to recursively resolve DNS queries. These values are given as `-recursor` flags to Consul servers and clients. - See https://www.consul.io/docs/agent/config/cli-flags#_recursor for more details. + Refer to [`-recursor`](https://developer.hashicorp.com/consul/docs/agent/config/cli-flags#_recursor) for more details. If this is an empty array (the default), then Consul DNS will only resolve queries for the Consul top level domain (by default `.consul`). - - `tls` ((#v-global-tls)) - Enables TLS (https://learn.hashicorp.com/tutorials/consul/tls-encryption-secure) + - `tls` ((#v-global-tls)) - Enables [TLS](https://developer.hashicorp.com/consul/tutorials/security/tls-encryption-secure) across the cluster to verify authenticity of the Consul servers and clients. Requires Consul v1.4.1+. - `enabled` ((#v-global-tls-enabled)) (`boolean: false`) - If true, the Helm chart will enable TLS for Consul servers and clients and all consul-k8s-control-plane components, as well as generate certificate authority (optional) and server and client certificates. + This setting is required for [Cluster Peering](https://developer.hashicorp.com/consul/docs/connect/cluster-peering/k8s). + + - `logLevel` ((#v-global-tls-loglevel)) (`string: ""`) - Override global log verbosity level. One of "trace", "debug", "info", "warn", or "error". - `enableAutoEncrypt` ((#v-global-tls-enableautoencrypt)) (`boolean: false`) - If true, turns on the auto-encrypt feature on clients and servers. It also switches consul-k8s-control-plane components to retrieve the CA from the servers @@ -384,7 +341,7 @@ Use these links to navigate to a particular top-level stanza. - `verify` ((#v-global-tls-verify)) (`boolean: true`) - If true, `verify_outgoing`, `verify_server_hostname`, and `verify_incoming` for internal RPC communication will be set to `true` for Consul servers and clients. Set this to false to incrementally roll out TLS on an existing Consul cluster. - Please see https://consul.io/docs/k8s/operations/tls-on-existing-cluster + Please refer to [TLS on existing clusters](https://developer.hashicorp.com/consul/docs/k8s/operations/tls-on-existing-cluster) for more details. - `httpsOnly` ((#v-global-tls-httpsonly)) (`boolean: true`) - If true, the Helm chart will configure Consul to disable the HTTP port on @@ -420,13 +377,23 @@ Use these links to navigate to a particular top-level stanza. Note that we need the CA key so that we can generate server and client certificates. It is particularly important for the client certificates since they need to have host IPs - as Subject Alternative Names. In the future, we may support bringing your own server - certificates. + as Subject Alternative Names. If you are setting server certs yourself via `server.serverCert` + and you are not enabling clients (or clients are enabled with autoEncrypt) then you do not + need to provide the CA key. - `secretName` ((#v-global-tls-cakey-secretname)) (`string: null`) - The name of the Kubernetes or Vault secret that holds the CA key. - `secretKey` ((#v-global-tls-cakey-secretkey)) (`string: null`) - The key within the Kubernetes or Vault secret that holds the CA key. + - `annotations` ((#v-global-tls-annotations)) (`string: null`) - This value defines additional annotations for + tls init jobs. Format this value as a multi-line string. + + ```yaml + annotations: | + "sample/annotation1": "foo" + "sample/annotation2": "bar" + ``` + - `enableConsulNamespaces` ((#v-global-enableconsulnamespaces)) (`boolean: false`) - `enableConsulNamespaces` indicates that you are running Consul Enterprise v1.7+ with a valid Consul Enterprise license and would like to make use of configuration beyond registering everything into @@ -440,6 +407,8 @@ Use these links to navigate to a particular top-level stanza. for all Consul and consul-k8s-control-plane components. This requires Consul >= 1.4. + - `logLevel` ((#v-global-acls-loglevel)) (`string: ""`) - Override global log verbosity level. One of "trace", "debug", "info", "warn", or "error". + - `bootstrapToken` ((#v-global-acls-bootstraptoken)) - A Kubernetes or Vault secret containing the bootstrap token to use for creating policies and tokens for all Consul and consul-k8s-control-plane components. If set, we will skip ACL bootstrapping of the servers and will only @@ -465,6 +434,23 @@ Use these links to navigate to a particular top-level stanza. - `secretKey` ((#v-global-acls-replicationtoken-secretkey)) (`string: null`) - The key within the Kubernetes or Vault secret that holds the replication token. + - `resources` ((#v-global-acls-resources)) (`map`) - The resource requests (CPU, memory, etc.) for the server-acl-init and server-acl-init-cleanup pods. + This should be a YAML map corresponding to a Kubernetes + [`ResourceRequirements``](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#resourcerequirements-v1-core) + object. + + Example: + + ```yaml + resources: + requests: + memory: '200Mi' + cpu: '100m' + limits: + memory: '200Mi' + cpu: '100m' + ``` + - `partitionToken` ((#v-global-acls-partitiontoken)) - partitionToken references a Vault secret containing the ACL token to be used in non-default partitions. This value should only be provided in the default partition and only when setting the `global.secretsBackend.vault.enabled` value to true. @@ -476,6 +462,29 @@ Use these links to navigate to a particular top-level stanza. - `secretKey` ((#v-global-acls-partitiontoken-secretkey)) (`string: null`) - The key within the Vault secret that holds the parition token. + - `tolerations` ((#v-global-acls-tolerations)) (`string: ""`) - tolerations configures the taints and tolerations for the server-acl-init + and server-acl-init-cleanup jobs. This should be a multi-line string matching the + [Tolerations](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/) array in a Pod spec. + + - `nodeSelector` ((#v-global-acls-nodeselector)) (`string: null`) - This value defines [`nodeSelector`](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) + labels for the server-acl-init and server-acl-init-cleanup jobs pod assignment, formatted as a multi-line string. + + Example: + + ```yaml + nodeSelector: | + beta.kubernetes.io/arch: amd64 + ``` + + - `annotations` ((#v-global-acls-annotations)) (`string: null`) - This value defines additional annotations for + acl init jobs. Format this value as a multi-line string. + + ```yaml + annotations: | + "sample/annotation1": "foo" + "sample/annotation2": "bar" + ``` + - `enterpriseLicense` ((#v-global-enterpriselicense)) - This value refers to a Kubernetes or Vault secret that you have created that contains your enterprise license. It is required if you are using an enterprise binary. Defining it here applies it to your cluster once a leader @@ -495,8 +504,9 @@ Use these links to navigate to a particular top-level stanza. - `enabled` ((#v-global-federation-enabled)) (`boolean: false`) - If enabled, this datacenter will be federation-capable. Only federation via mesh gateways is supported. Mesh gateways and servers will be configured to allow federation. - Requires `global.tls.enabled`, `meshGateway.enabled` and `connectInject.enabled` - to be true. Requires Consul 1.8+. + Requires `global.tls.enabled`, `connectInject.enabled`, and one of + `meshGateway.enabled` or `externalServers.enabled` to be true. + Requires Consul 1.8+. - `createFederationSecret` ((#v-global-federation-createfederationsecret)) (`boolean: false`) - If true, the chart will create a Kubernetes secret that can be imported into secondary datacenters so they can federate with this datacenter. The @@ -508,15 +518,18 @@ Use these links to navigate to a particular top-level stanza. - `primaryDatacenter` ((#v-global-federation-primarydatacenter)) (`string: null`) - The name of the primary datacenter. - - `primaryGateways` ((#v-global-federation-primarygateways)) (`array: []`) - A list of addresses of the primary mesh gateways in the form `:`. - (e.g. ["1.1.1.1:443", "2.3.4.5:443"] + - `primaryGateways` ((#v-global-federation-primarygateways)) (`array: []`) - A list of addresses of the primary mesh gateways in the form `:` + (e.g. `["1.1.1.1:443", "2.3.4.5:443"]`). - `k8sAuthMethodHost` ((#v-global-federation-k8sauthmethodhost)) (`string: null`) - If you are setting `global.federation.enabled` to true and are in a secondary datacenter, set `k8sAuthMethodHost` to the address of the Kubernetes API server of the secondary datacenter. This address must be reachable from the Consul servers in the primary datacenter. This auth method will be used to provision ACL tokens for Consul components and is different from the one used by the Consul Service Mesh. - Please see the [Kubernetes Auth Method documentation](/docs/security/acl/auth-methods/kubernetes). + Please refer to the [Kubernetes Auth Method documentation](https://developer.hashicorp.com/consul/docs/security/acl/auth-methods/kubernetes). + + If `externalServers.enabled` is set to true, `global.federation.k8sAuthMethodHost` and + `externalServers.k8sAuthMethodHost` should be set to the same value. You can retrieve this value from your `kubeconfig` by running: @@ -525,6 +538,8 @@ Use these links to navigate to a particular top-level stanza. -o jsonpath="{.clusters[?(@.name=='')].cluster.server}" ``` + - `logLevel` ((#v-global-federation-loglevel)) (`string: ""`) - Override global log verbosity level for the `create-federation-secret-job` pods. One of "trace", "debug", "info", "warn", or "error". + - `metrics` ((#v-global-metrics)) - Configures metrics for Consul service mesh - `enabled` ((#v-global-metrics-enabled)) (`boolean: false`) - Configures the Helm chart’s components @@ -543,22 +558,6 @@ Use these links to navigate to a particular top-level stanza. Envoy metrics on port `20200` at the `/metrics` path and all gateway pods will have Prometheus scrape annotations. Only applicable if `global.metrics.enabled` is true. - - `consulSidecarContainer` ((#v-global-consulsidecarcontainer)) (`map`) - For connect-injected pods, the consul sidecar is responsible for metrics merging. For ingress/mesh/terminating - gateways, it additionally ensures the Consul services are always registered with their local Consul client. - - - `resources` ((#v-global-consulsidecarcontainer-resources)) (`map`) - Set default resources for consul sidecar. If null, that resource won't - be set. - These settings can be overridden on a per-pod basis via these annotations: - - - `consul.hashicorp.com/consul-sidecar-cpu-limit` - - `consul.hashicorp.com/consul-sidecar-cpu-request` - - `consul.hashicorp.com/consul-sidecar-memory-limit` - - `consul.hashicorp.com/consul-sidecar-memory-request` - - - `imageEnvoy` ((#v-global-imageenvoy)) (`string: envoyproxy/envoy-alpine:`) - The name (and tag) of the Envoy Docker image used for the - connect-injected sidecar proxies and mesh, terminating, and ingress gateways. - See https://www.consul.io/docs/connect/proxies/envoy for full compatibility matrix between Consul and Envoy. - - `imageConsulDataplane` ((#v-global-imageconsuldataplane)) (`string: hashicorp/consul-dataplane:`) - The name (and tag) of the consul-dataplane Docker image used for the connect-injected sidecar proxies and mesh, terminating, and ingress gateways. @@ -568,7 +567,7 @@ Use these links to navigate to a particular top-level stanza. - `enabled` ((#v-global-openshift-enabled)) (`boolean: false`) - If true, the Helm chart will create necessary configuration for running its components on OpenShift. - - `consulAPITimeout` ((#v-global-consulapitimeout)) (`string: 5s`) - The time in seconds that the consul API client will wait for a response from + - `consulAPITimeout` ((#v-global-consulapitimeout)) (`string: 5s`) - The time in seconds that the consul API client will wait for a response from the API before cancelling the request. - `cloud` ((#v-global-cloud)) - Enables installing an HCP Consul self-managed cluster. @@ -577,9 +576,57 @@ Use these links to navigate to a particular top-level stanza. - `enabled` ((#v-global-cloud-enabled)) (`boolean: false`) - If true, the Helm chart will enable the installation of an HCP Consul self-managed cluster. - - `secretName` ((#v-global-cloud-secretname)) (`string: null`) - The name of the Kubernetes secret that holds the HCP cloud configuration. - It contains the HCP service principal client_id and client_secret as well - as the HCP resource_id. + - `resourceId` ((#v-global-cloud-resourceid)) - The name of the Kubernetes secret that holds the HCP resource id. + This is required when global.cloud.enabled is true. + + - `secretName` ((#v-global-cloud-resourceid-secretname)) (`string: null`) - The name of the Kubernetes secret that holds the resource id. + + - `secretKey` ((#v-global-cloud-resourceid-secretkey)) (`string: null`) - The key within the Kubernetes secret that holds the resource id. + + - `clientId` ((#v-global-cloud-clientid)) - The name of the Kubernetes secret that holds the HCP cloud client id. + This is required when global.cloud.enabled is true. + + - `secretName` ((#v-global-cloud-clientid-secretname)) (`string: null`) - The name of the Kubernetes secret that holds the client id. + + - `secretKey` ((#v-global-cloud-clientid-secretkey)) (`string: null`) - The key within the Kubernetes secret that holds the client id. + + - `clientSecret` ((#v-global-cloud-clientsecret)) - The name of the Kubernetes secret that holds the HCP cloud client secret. + This is required when global.cloud.enabled is true. + + - `secretName` ((#v-global-cloud-clientsecret-secretname)) (`string: null`) - The name of the Kubernetes secret that holds the client secret. + + - `secretKey` ((#v-global-cloud-clientsecret-secretkey)) (`string: null`) - The key within the Kubernetes secret that holds the client secret. + + - `apiHost` ((#v-global-cloud-apihost)) - The name of the Kubernetes secret that holds the HCP cloud client id. + This is optional when global.cloud.enabled is true. + + - `secretName` ((#v-global-cloud-apihost-secretname)) (`string: null`) - The name of the Kubernetes secret that holds the api hostname. + + - `secretKey` ((#v-global-cloud-apihost-secretkey)) (`string: null`) - The key within the Kubernetes secret that holds the api hostname. + + - `authUrl` ((#v-global-cloud-authurl)) - The name of the Kubernetes secret that holds the HCP cloud authorization url. + This is optional when global.cloud.enabled is true. + + - `secretName` ((#v-global-cloud-authurl-secretname)) (`string: null`) - The name of the Kubernetes secret that holds the authorization url. + + - `secretKey` ((#v-global-cloud-authurl-secretkey)) (`string: null`) - The key within the Kubernetes secret that holds the authorization url. + + - `scadaAddress` ((#v-global-cloud-scadaaddress)) - The name of the Kubernetes secret that holds the HCP cloud scada address. + This is optional when global.cloud.enabled is true. + + - `secretName` ((#v-global-cloud-scadaaddress-secretname)) (`string: null`) - The name of the Kubernetes secret that holds the scada address. + + - `secretKey` ((#v-global-cloud-scadaaddress-secretkey)) (`string: null`) - The key within the Kubernetes secret that holds the scada address. + + - `extraLabels` ((#v-global-extralabels)) (`map`) - Extra labels to attach to all pods, deployments, daemonsets, statefulsets, and jobs. This should be a YAML map. + + Example: + + ```yaml + extraLabels: + labelKey: label-value + anotherLabelKey: another-label-value + ``` ### server ((#h-server)) @@ -591,11 +638,13 @@ Use these links to navigate to a particular top-level stanza. Consul server cluster. If you're running Consul externally and want agents within Kubernetes to join that cluster, this should probably be false. + - `logLevel` ((#v-server-loglevel)) (`string: ""`) - Override global log verbosity level. One of "trace", "debug", "info", "warn", or "error". + - `image` ((#v-server-image)) (`string: null`) - The name of the Docker image (including any tag) for the containers running Consul server agents. - `replicas` ((#v-server-replicas)) (`integer: 1`) - The number of server agents to run. This determines the fault tolerance of - the cluster. Please see the deployment table (https://consul.io/docs/internals/consensus#deployment-table) + the cluster. Please refer to the [deployment table](https://developer.hashicorp.com/consul/docs/architecture/consensus#deployment-table) for more information. - `bootstrapExpect` ((#v-server-bootstrapexpect)) (`int: null`) - The number of servers that are expected to be running. @@ -633,9 +682,9 @@ Use these links to navigate to a particular top-level stanza. Vault Secrets backend: If you are using Vault as a secrets backend, a Vault Policy must be created which allows `["create", "update"]` - capabilities on the PKI issuing endpoint, which is usually of the form `pki/issue/consul-server`. - Please see the following guide for steps to generate a compatible certificate: - https://learn.hashicorp.com/tutorials/consul/vault-pki-consul-secure-tls + capabilities on the PKI issuing endpoint, which is usually of the form `pki/issue/consul-server`. + Complete [this tutorial](https://developer.hashicorp.com/consul/tutorials/vault-secure/vault-pki-consul-secure-tls) + to learn how to generate a compatible certificate. Note: when using TLS, both the `server.serverCert` and `global.tls.caCert` which points to the CA endpoint of this PKI engine must be provided. @@ -669,24 +718,24 @@ Use these links to navigate to a particular top-level stanza. - `storageClass` ((#v-server-storageclass)) (`string: null`) - The StorageClass to use for the servers' StatefulSet storage. It must be able to be dynamically provisioned if you want the storage - to be automatically created. For example, to use + to be automatically created. For example, to use local(https://kubernetes.io/docs/concepts/storage/storage-classes/#local) storage classes, the PersistentVolumeClaims would need to be manually created. A `null` value will use the Kubernetes cluster's default StorageClass. If a default StorageClass does not exist, you will need to create one. - Refer to the [Read/Write Tuning](https://www.consul.io/docs/install/performance#read-write-tuning) - section of the Server Performance Requirements documentation for considerations + Refer to the [Read/Write Tuning](https://developer.hashicorp.com/consul/docs/install/performance#read-write-tuning) + section of the Server Performance Requirements documentation for considerations around choosing a performant storage class. - ~> **Note:** The [Reference Architecture](https://learn.hashicorp.com/tutorials/consul/reference-architecture#hardware-sizing-for-consul-servers) + ~> **Note:** The [Reference Architecture](https://developer.hashicorp.com/consul/tutorials/production-deploy/reference-architecture#hardware-sizing-for-consul-servers) contains best practices and recommendations for selecting suitable hardware sizes for your Consul servers. - - `connect` ((#v-server-connect)) (`boolean: true`) - This will enable/disable Connect (https://consul.io/docs/connect). Setting this to true + - `connect` ((#v-server-connect)) (`boolean: true`) - This will enable/disable [service mesh](https://developer.hashicorp.com/consul/docs/connect). Setting this to true _will not_ automatically secure pod communication, this setting will only enable usage of the feature. Consul will automatically initialize - a new CA and set of certificates. Additional Connect settings can be configured - by setting the `server.extraConfig` value. + a new CA and set of certificates. Additional service mesh settings can be configured + by setting the `server.extraConfig` value or by applying [configuration entries](https://developer.hashicorp.com/consul/docs/connect/config-entries). - `serviceAccount` ((#v-server-serviceaccount)) @@ -701,7 +750,7 @@ Use these links to navigate to a particular top-level stanza. - `resources` ((#v-server-resources)) (`map`) - The resource requests (CPU, memory, etc.) for each of the server agents. This should be a YAML map corresponding to a Kubernetes - ResourceRequirements (https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#resourcerequirements-v1-core) + [`ResourceRequirements``](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#resourcerequirements-v1-core) object. NOTE: The use of a YAML string is deprecated. Example: @@ -709,10 +758,10 @@ Use these links to navigate to a particular top-level stanza. ```yaml resources: requests: - memory: '100Mi' + memory: '200Mi' cpu: '100m' limits: - memory: '100Mi' + memory: '200Mi' cpu: '100m' ``` @@ -730,18 +779,23 @@ Use these links to navigate to a particular top-level stanza. - `server` ((#v-server-containersecuritycontext-server)) (`map`) - The consul server agent container + - `aclInit` ((#v-server-containersecuritycontext-aclinit)) (`map`) - The acl-init job + + - `tlsInit` ((#v-server-containersecuritycontext-tlsinit)) (`map`) - The tls-init job + - `updatePartition` ((#v-server-updatepartition)) (`integer: 0`) - This value is used to carefully control a rolling update of Consul server agents. This value specifies the - partition (https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#partitions) - for performing a rolling update. Please read the linked Kubernetes documentation - and https://www.consul.io/docs/k8s/upgrade#upgrading-consul-servers for more information. + [partition](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#partitions) + for performing a rolling update. Please read the linked Kubernetes + and [Upgrade Consul](https://developer.hashicorp.com/consul/docs/k8s/upgrade#upgrading-consul-servers) + documentation for more information. - - `disruptionBudget` ((#v-server-disruptionbudget)) - This configures the PodDisruptionBudget (https://kubernetes.io/docs/tasks/run-application/configure-pdb/) + - `disruptionBudget` ((#v-server-disruptionbudget)) - This configures the [`PodDisruptionBudget`](https://kubernetes.io/docs/tasks/run-application/configure-pdb/) for the server cluster. - - `enabled` ((#v-server-disruptionbudget-enabled)) (`boolean: true`) - This will enable/disable registering a PodDisruptionBudget for the server - cluster. If this is enabled, it will only register the budget so long as - the server cluster is enabled. + - `enabled` ((#v-server-disruptionbudget-enabled)) (`boolean: true`) - Enables registering a PodDisruptionBudget for the server + cluster. If enabled, it only registers the budget so long as + the server cluster is enabled. To disable, set to `false`. - `maxUnavailable` ((#v-server-disruptionbudget-maxunavailable)) (`integer: null`) - The maximum number of unavailable pods. By default, this will be automatically computed based on the `server.replicas` value to be `(n/2)-1`. @@ -749,7 +803,7 @@ Use these links to navigate to a particular top-level stanza. --set 'server.disruptionBudget.maxUnavailable=0'` flag to the helm chart installation command because of a limitation in the Helm templating language. - - `extraConfig` ((#v-server-extraconfig)) (`string: {}`) - A raw string of extra JSON configuration (https://consul.io/docs/agent/config/config-files) for Consul + - `extraConfig` ((#v-server-extraconfig)) (`string: {}`) - A raw string of extra [JSON configuration](https://developer.hashicorp.com/consul/docs/agent/config/config-files) for Consul servers. This will be saved as-is into a ConfigMap that is read by the Consul server agents. This can be used to add additional configuration that isn't directly exposed by the chart. @@ -805,7 +859,7 @@ Use these links to navigate to a particular top-level stanza. - ... ``` - - `affinity` ((#v-server-affinity)) (`string`) - This value defines the affinity (https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity) + - `affinity` ((#v-server-affinity)) (`string`) - This value defines the [affinity](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity) for server pods. It defaults to allowing only a single server pod on each node, which minimizes risk of the cluster becoming unusable if a node is lost. If you need to run more pods per node (for example, testing on Minikube), set this value @@ -826,12 +880,14 @@ Use these links to navigate to a particular top-level stanza. ``` - `tolerations` ((#v-server-tolerations)) (`string: ""`) - Toleration settings for server pods. This - should be a multi-line string matching the Tolerations - (https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/) array in a Pod spec. + should be a multi-line string matching the + [Tolerations](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/) + array in a Pod spec. - `topologySpreadConstraints` ((#v-server-topologyspreadconstraints)) (`string: ""`) - Pod topology spread constraints for server pods. - This should be a multi-line YAML string matching the `topologySpreadConstraints` array - (https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/) in a Pod Spec. + This should be a multi-line YAML string matching the + [`topologySpreadConstraints`](https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/) + array in a Pod Spec. This requires K8S >= 1.18 (beta) or 1.19 (stable). @@ -849,7 +905,7 @@ Use these links to navigate to a particular top-level stanza. component: server ``` - - `nodeSelector` ((#v-server-nodeselector)) (`string: null`) - This value defines `nodeSelector` (https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) + - `nodeSelector` ((#v-server-nodeselector)) (`string: null`) - This value defines [`nodeSelector`](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) labels for server pod assignment, formatted as a multi-line string. Example: @@ -860,7 +916,7 @@ Use these links to navigate to a particular top-level stanza. ``` - `priorityClassName` ((#v-server-priorityclassname)) (`string: ""`) - This value references an existing - Kubernetes `priorityClassName` (https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#pod-priority) + Kubernetes [`priorityClassName`](https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#pod-priority) that can be assigned to server pods. - `extraLabels` ((#v-server-extralabels)) (`map`) - Extra labels to attach to the server pods. This should be a YAML map. @@ -923,6 +979,89 @@ Use these links to navigate to a particular top-level stanza. feature, in case kubernetes cluster is behind egress http proxies. Additionally, it could be used to configure custom consul parameters. + - `snapshotAgent` ((#v-server-snapshotagent)) - Values for setting up and running + [snapshot agents](https://developer.hashicorp.com/consul/commands/snapshot/agent) + within the Consul clusters. They run as a sidecar with Consul servers. + + - `enabled` ((#v-server-snapshotagent-enabled)) (`boolean: false`) - If true, the chart will install resources necessary to run the snapshot agent. + + - `interval` ((#v-server-snapshotagent-interval)) (`string: 1h`) - Interval at which to perform snapshots. + Refer to [`interval`](https://developer.hashicorp.com/consul/commands/snapshot/agent#interval) + + - `configSecret` ((#v-server-snapshotagent-configsecret)) - A Kubernetes or Vault secret that should be manually created to contain the entire + config to be used on the snapshot agent. + This is the preferred method of configuration since there are usually storage + credentials present. Please refer to the [Snapshot agent config](https://developer.hashicorp.com/consul/commands/snapshot/agent#config-file-options) + for details. + + - `secretName` ((#v-server-snapshotagent-configsecret-secretname)) (`string: null`) - The name of the Kubernetes secret or Vault secret path that holds the snapshot agent config. + + - `secretKey` ((#v-server-snapshotagent-configsecret-secretkey)) (`string: null`) - The key within the Kubernetes secret or Vault secret key that holds the snapshot agent config. + + - `resources` ((#v-server-snapshotagent-resources)) (`map`) - The resource settings for snapshot agent pods. + + - `caCert` ((#v-server-snapshotagent-cacert)) (`string: null`) - Optional PEM-encoded CA certificate that will be added to the trusted system CAs. + Useful if using an S3-compatible storage exposing a self-signed certificate. + + Example: + + ```yaml + caCert: | + -----BEGIN CERTIFICATE----- + MIIC7jCCApSgAwIBAgIRAIq2zQEVexqxvtxP6J0bXAwwCgYIKoZIzj0EAwIwgbkx + ... + ``` + + - `auditLogs` ((#v-server-auditlogs)) - Added in Consul 1.8, the audit object allow users to enable auditing + and configure a sink and filters for their audit logs. Please refer to + [audit logs](https://developer.hashicorp.com/consul/docs/enterprise/audit-logging) documentation + for further information. + + - `enabled` ((#v-server-auditlogs-enabled)) (`boolean: false`) - Controls whether Consul logs out each time a user performs an operation. + global.acls.manageSystemACLs must be enabled to use this feature. + + - `sinks` ((#v-server-auditlogs-sinks)) (`array`) - A single entry of the sink object provides configuration for the destination to which Consul + will log auditing events. + + Example: + + ```yaml + sinks: + - name: My Sink + type: file + format: json + path: /tmp/audit.json + delivery_guarantee: best-effort + rotate_duration: 24h + rotate_max_files: 15 + rotate_bytes: 25165824 + + ``` + + The sink object supports the following keys: + + - `name` - Name of the sink. + + - `type` - Type specifies what kind of sink this is. Currently only file sinks are available + + - `format` - Format specifies what format the events will be emitted with. Currently only `json` + events are emitted. + + - `path` - The directory and filename to write audit events to. + + - `delivery_guarantee` - Specifies the rules governing how audit events are written. Consul + only supports `best-effort` event delivery. + + - `mode` - The permissions to set on the audit log files. + + - `rotate_duration` - Specifies the interval by which the system rotates to a new log file. + At least one of `rotate_duration` or `rotate_bytes` must be configured to enable audit logging. + + - `rotate_bytes` - Specifies how large an individual log file can grow before Consul rotates to a new file. + At least one of rotate_bytes or rotate_duration must be configured to enable audit logging. + + - `rotate_max_files` - Defines the limit that Consul should follow before it deletes old log files. + ### externalServers ((#h-externalservers)) - `externalServers` ((#v-externalservers)) - Configuration for Consul servers when the servers are running outside of Kubernetes. @@ -935,9 +1074,10 @@ Use these links to navigate to a particular top-level stanza. - `hosts` ((#v-externalservers-hosts)) (`array: []`) - An array of external Consul server hosts that are used to make HTTPS connections from the components in this Helm chart. - Valid values include IPs, DNS names, or Cloud auto-join string. + Valid values include an IP, a DNS name, or an [exec=](https://github.com/hashicorp/go-netaddrs) string. The port must be provided separately below. - Note: `client.join` must also be set to the hosts that should be + Note: This slice can only contain a single element. + Note: If enabling clients, `client.join` must also be set to the hosts that should be used to join the cluster. In most cases, the `client.join` values should be the same, however, they may be different if you wish to use separate hosts for the HTTPS connections. @@ -959,7 +1099,10 @@ Use these links to navigate to a particular top-level stanza. - `k8sAuthMethodHost` ((#v-externalservers-k8sauthmethodhost)) (`string: null`) - If you are setting `global.acls.manageSystemACLs` and `connectInject.enabled` to true, set `k8sAuthMethodHost` to the address of the Kubernetes API server. This address must be reachable from the Consul servers. - Please see the Kubernetes Auth Method documentation (https://consul.io/docs/acl/auth-methods/kubernetes). + Please refer to the [Kubernetes Auth Method documentation](https://developer.hashicorp.com/consul/docs/security/acl/auth-methods/kubernetes). + + If `global.federation.enabled` is set to true, `global.federation.k8sAuthMethodHost` and + `externalServers.k8sAuthMethodHost` should be set to the same value. You could retrieve this value from your `kubeconfig` by running: @@ -968,6 +1111,9 @@ Use these links to navigate to a particular top-level stanza. -o jsonpath="{.clusters[?(@.name=='')].cluster.server}" ``` + - `skipServerWatch` ((#v-externalservers-skipserverwatch)) (`boolean: false`) - If true, setting this prevents the consul-dataplane and consul-k8s components from watching the Consul servers for changes. This is + useful for situations where Consul servers are behind a load balancer. + ### client ((#h-client)) - `client` ((#v-client)) - Values that configure running a Consul client on Kubernetes nodes. @@ -976,10 +1122,12 @@ Use these links to navigate to a particular top-level stanza. the resources necessary for a Consul client on every Kubernetes node. This _does not_ require `server.enabled`, since the agents can be configured to join an external cluster. + - `logLevel` ((#v-client-loglevel)) (`string: ""`) - Override global log verbosity level. One of "trace", "debug", "info", "warn", or "error". + - `image` ((#v-client-image)) (`string: null`) - The name of the Docker image (including any tag) for the containers running Consul client agents. - - `join` ((#v-client-join)) (`array: null`) - A list of valid `-retry-join` values (https://www.consul.io/docs/agent/config/cli-flags#_retry_join). + - `join` ((#v-client-join)) (`array: null`) - A list of valid [`-retry-join` values](https://developer.hashicorp.com/consul/docs/agent/config/cli-flags#_retry_join). If this is `null` (default), then the clients will attempt to automatically join the server cluster running within Kubernetes. This means that with `server.enabled` set to true, clients will automatically @@ -1000,7 +1148,7 @@ Use these links to navigate to a particular top-level stanza. required for Connect. - `nodeMeta` ((#v-client-nodemeta)) - nodeMeta specifies an arbitrary metadata key/value pair to associate with the node - (see https://www.consul.io/docs/agent/config/cli-flags#_node_meta) + (refer to [`-node-meta`](https://developer.hashicorp.com/consul/docs/agent/config/cli-flags#_node_meta)) - `pod-name` ((#v-client-nodemeta-pod-name)) (`string: ${HOSTNAME}`) @@ -1044,7 +1192,7 @@ Use these links to navigate to a particular top-level stanza. - `tlsInit` ((#v-client-containersecuritycontext-tlsinit)) (`map`) - The tls-init initContainer - - `extraConfig` ((#v-client-extraconfig)) (`string: {}`) - A raw string of extra JSON configuration (https://consul.io/docs/agent/config/config-files) for Consul + - `extraConfig` ((#v-client-extraconfig)) (`string: {}`) - A raw string of extra [JSON configuration](https://developer.hashicorp.com/consul/docs/agent/config/config-files) for Consul clients. This will be saved as-is into a ConfigMap that is read by the Consul client agents. This can be used to add additional configuration that isn't directly exposed by the chart. @@ -1137,7 +1285,7 @@ Use these links to navigate to a particular top-level stanza. ``` - `priorityClassName` ((#v-client-priorityclassname)) (`string: ""`) - This value references an existing - Kubernetes `priorityClassName` (https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#pod-priority) + Kubernetes [`priorityClassName`](https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#pod-priority) that can be assigned to client pods. - `annotations` ((#v-client-annotations)) (`string: null`) - This value defines additional annotations for @@ -1164,7 +1312,7 @@ Use these links to navigate to a particular top-level stanza. feature, in case kubernetes cluster is behind egress http proxies. Additionally, it could be used to configure custom consul parameters. - - `dnsPolicy` ((#v-client-dnspolicy)) (`string: null`) - This value defines the Pod DNS policy (https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy) + - `dnsPolicy` ((#v-client-dnspolicy)) (`string: null`) - This value defines the [Pod DNS policy](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy) for client pods to use. - `hostNetwork` ((#v-client-hostnetwork)) (`boolean: false`) - hostNetwork defines whether or not we use host networking instead of hostPort in the event @@ -1174,7 +1322,8 @@ Use these links to navigate to a particular top-level stanza. combined with `dnsPolicy: ClusterFirstWithHostNet` - `updateStrategy` ((#v-client-updatestrategy)) (`string: null`) - updateStrategy for the DaemonSet. - See https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/#daemonset-update-strategy. + Refer to the Kubernetes [Daemonset upgrade strategy](https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/#daemonset-update-strategy) + documentation. This should be a multi-line string mapping directly to the updateStrategy Example: @@ -1186,53 +1335,6 @@ Use these links to navigate to a particular top-level stanza. type: RollingUpdate ``` - - `snapshotAgent` ((#v-client-snapshotagent)) - Values for setting up and running snapshot agents - (https://consul.io/commands/snapshot/agent) - within the Consul clusters. They are required to be co-located with Consul clients, - so will inherit the clients' nodeSelector, tolerations and affinity. - - - `enabled` ((#v-client-snapshotagent-enabled)) (`boolean: false`) - If true, the chart will install resources necessary to run the snapshot agent. - - - `replicas` ((#v-client-snapshotagent-replicas)) (`integer: 2`) - The number of snapshot agents to run. - - - `interval` ((#v-client-snapshotagent-interval)) (`string: 1h`) - Interval at which to perform snapshots. - See https://www.consul.io/commands/snapshot/agent#interval - - - `configSecret` ((#v-client-snapshotagent-configsecret)) - A Kubernetes or Vault secret that should be manually created to contain the entire - config to be used on the snapshot agent. - This is the preferred method of configuration since there are usually storage - credentials present. Please see Snapshot agent config (https://consul.io/commands/snapshot/agent#config-file-options) - for details. - - - `secretName` ((#v-client-snapshotagent-configsecret-secretname)) (`string: null`) - The name of the Kubernetes secret or Vault secret path that holds the snapshot agent config. - - - `secretKey` ((#v-client-snapshotagent-configsecret-secretkey)) (`string: null`) - The key within the Kubernetes secret or Vault secret key that holds the snapshot agent config. - - - `serviceAccount` ((#v-client-snapshotagent-serviceaccount)) - - - `annotations` ((#v-client-snapshotagent-serviceaccount-annotations)) (`string: null`) - This value defines additional annotations for the snapshot agent service account. This should be formatted as a - multi-line string. - - ```yaml - annotations: | - "sample/annotation1": "foo" - "sample/annotation2": "bar" - ``` - - - `resources` ((#v-client-snapshotagent-resources)) (`map`) - The resource settings for snapshot agent pods. - - - `caCert` ((#v-client-snapshotagent-cacert)) (`string: null`) - Optional PEM-encoded CA certificate that will be added to the trusted system CAs. - Useful if using an S3-compatible storage exposing a self-signed certificate. - - Example: - - ```yaml - caCert: | - -----BEGIN CERTIFICATE----- - MIIC7jCCApSgAwIBAgIRAIq2zQEVexqxvtxP6J0bXAwwCgYIKoZIzj0EAwIwgbkx - ... - ``` - ### dns ((#h-dns)) - `dns` ((#v-dns)) - Configuration for DNS configuration within the Kubernetes cluster. @@ -1244,7 +1346,7 @@ Use these links to navigate to a particular top-level stanza. - `enabled` ((#v-dns-enabled)) (`boolean: -`) - - `enableRedirection` ((#v-dns-enableredirection)) (`boolean: false`) - If true, services using Consul Connect will use Consul DNS + - `enableRedirection` ((#v-dns-enableredirection)) (`boolean: -`) - If true, services using Consul service mesh will use Consul DNS for default DNS resolution. The DNS lookups fall back to the nameserver IPs listed in /etc/resolv.conf if not found in Consul. @@ -1319,7 +1421,7 @@ Use these links to navigate to a particular top-level stanza. - `ingressClassName` ((#v-ui-ingress-ingressclassname)) (`string: ""`) - Optionally set the ingressClassName. - - `pathType` ((#v-ui-ingress-pathtype)) (`string: Prefix`) - pathType override - see: https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types + - `pathType` ((#v-ui-ingress-pathtype)) (`string: Prefix`) - pathType override - refer to: https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types - `hosts` ((#v-ui-ingress-hosts)) (`array`) - hosts is a list of host name to create Ingress rules. @@ -1355,16 +1457,17 @@ Use these links to navigate to a particular top-level stanza. - `enabled` ((#v-ui-metrics-enabled)) (`boolean: global.metrics.enabled`) - Enable displaying metrics in the UI. The default value of "-" will inherit from `global.metrics.enabled` value. - - `provider` ((#v-ui-metrics-provider)) (`string: prometheus`) - Provider for metrics. See - https://www.consul.io/docs/agent/config/config-files#ui_config_metrics_provider + - `provider` ((#v-ui-metrics-provider)) (`string: prometheus`) - Provider for metrics. Refer to + [`metrics_provider`](https://developer.hashicorp.com/consul/docs/agent/config/config-files#ui_config_metrics_provider) This value is only used if `ui.enabled` is set to true. - `baseURL` ((#v-ui-metrics-baseurl)) (`string: http://prometheus-server`) - baseURL is the URL of the prometheus server, usually the service URL. This value is only used if `ui.enabled` is set to true. - - `dashboardURLTemplates` ((#v-ui-dashboardurltemplates)) - Corresponds to https://www.consul.io/docs/agent/config/config-files#ui_config_dashboard_url_templates configuration. + - `dashboardURLTemplates` ((#v-ui-dashboardurltemplates)) - Corresponds to [`dashboard_url_templates`](https://developer.hashicorp.com/consul/docs/agent/config/config-files#ui_config_dashboard_url_templates) + configuration. - - `service` ((#v-ui-dashboardurltemplates-service)) (`string: ""`) - Sets https://www.consul.io/docs/agent/config/config-files#ui_config_dashboard_url_templates_service. + - `service` ((#v-ui-dashboardurltemplates-service)) (`string: ""`) - Sets [`dashboardURLTemplates.service`](https://developer.hashicorp.com/consul/docs/agent/config/config-files#ui_config_dashboard_url_templates_service). ### syncCatalog ((#h-synccatalog)) @@ -1384,8 +1487,8 @@ Use these links to navigate to a particular top-level stanza. to run the sync program. - `default` ((#v-synccatalog-default)) (`boolean: true`) - If true, all valid services in K8S are - synced by default. If false, the service must be annotated - (https://consul.io/docs/k8s/service-sync#sync-enable-disable) properly to sync. + synced by default. If false, the service must be [annotated](https://developer.hashicorp.com/consul/docs/k8s/service-sync#enable-and-disable-sync) + properly to sync. In either case an annotation can override the default. - `priorityClassName` ((#v-synccatalog-priorityclassname)) (`string: ""`) - Optional priorityClassName. @@ -1436,14 +1539,14 @@ Use these links to navigate to a particular top-level stanza. k8s services into. If the Consul namespace does not already exist, it will be created. This will be ignored if `mirroringK8S` is true. - - `mirroringK8S` ((#v-synccatalog-consulnamespaces-mirroringk8s)) (`boolean: false`) - If true, k8s services will be registered into a Consul namespace + - `mirroringK8S` ((#v-synccatalog-consulnamespaces-mirroringk8s)) (`boolean: true`) - If true, k8s services will be registered into a Consul namespace of the same name as their k8s namespace, optionally prefixed if `mirroringK8SPrefix` is set below. If the Consul namespace does not already exist, it will be created. Turning this on overrides the `consulDestinationNamespace` setting. `addK8SNamespaceSuffix` may no longer be needed if enabling this option. - If mirroring is enabled, avoid creating any Consul resources in the following - Kubernetes namespaces, as Consul currently reserves these namespaces for + If mirroring is enabled, avoid creating any Consul resources in the following + Kubernetes namespaces, as Consul currently reserves these namespaces for system use: "system", "universal", "operator", "root". - `mirroringK8SPrefix` ((#v-synccatalog-consulnamespaces-mirroringk8sprefix)) (`string: ""`) - If `mirroringK8S` is set to true, `mirroringK8SPrefix` allows each Consul namespace @@ -1482,6 +1585,19 @@ Use these links to navigate to a particular top-level stanza. or may not be broadly accessible depending on your Kubernetes cluster. Set this to false to skip syncing ClusterIP services. + - `ingress` ((#v-synccatalog-ingress)) + + - `enabled` ((#v-synccatalog-ingress-enabled)) (`boolean: false`) - Syncs the hostname from a Kubernetes Ingress resource to service registrations + when a rule matched a service. Currently only supports host based routing and + not path based routing. The only supported path on an ingress rule is "/". + Set this to false to skip syncing Ingress services. + + Currently, port 80 is synced if there is not TLS entry for the hostname. Syncs the port + 443 if there is a TLS entry that matches the hostname. + + - `loadBalancerIPs` ((#v-synccatalog-ingress-loadbalancerips)) (`boolean: false`) - Requires syncIngress to be `true`. syncs the LoadBalancer IP from a Kubernetes Ingress + resource instead of the hostname to service registrations when a rule matched a service. + - `nodePortSyncType` ((#v-synccatalog-nodeportsynctype)) (`string: ExternalFirst`) - Configures the type of syncing that happens for NodePort services. The valid options are: ExternalOnly, InternalOnly, ExternalFirst. @@ -1498,7 +1614,7 @@ Use these links to navigate to a particular top-level stanza. - `secretKey` ((#v-synccatalog-aclsynctoken-secretkey)) (`string: null`) - The key within the Kubernetes secret that holds the acl sync token. - - `nodeSelector` ((#v-synccatalog-nodeselector)) (`string: null`) - This value defines `nodeSelector` (https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) + - `nodeSelector` ((#v-synccatalog-nodeselector)) (`string: null`) - This value defines [`nodeSelector`](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) labels for catalog sync pod assignment, formatted as a multi-line string. Example: @@ -1558,13 +1674,13 @@ Use these links to navigate to a particular top-level stanza. - `enabled` ((#v-connectinject-enabled)) (`boolean: true`) - True if you want to enable connect injection. Set to "-" to inherit from global.enabled. - - `replicas` ((#v-connectinject-replicas)) (`integer: 2`) - The number of deployment replicas. + - `replicas` ((#v-connectinject-replicas)) (`integer: 1`) - The number of deployment replicas. - `image` ((#v-connectinject-image)) (`string: null`) - Image for consul-k8s-control-plane that contains the injector. - `default` ((#v-connectinject-default)) (`boolean: false`) - If true, the injector will inject the Connect sidecar into all pods by default. Otherwise, pods must specify the - injection annotation (https://consul.io/docs/k8s/connect#consul-hashicorp-com-connect-inject) + [injection annotation](https://developer.hashicorp.com/consul/docs/k8s/connect#consul-hashicorp-com-connect-inject) to opt-in to Connect injection. If this is true, pods can use the same annotation to explicitly opt-out of injection. @@ -1582,10 +1698,10 @@ Use these links to navigate to a particular top-level stanza. This value is also overridable via the "consul.hashicorp.com/transparent-proxy-overwrite-probes" annotation. Note: This value has no effect if transparent proxy is disabled on the pod. - - `disruptionBudget` ((#v-connectinject-disruptionbudget)) - This configures the PodDisruptionBudget (https://kubernetes.io/docs/tasks/run-application/configure-pdb/) + - `disruptionBudget` ((#v-connectinject-disruptionbudget)) - This configures the [`PodDisruptionBudget`](https://kubernetes.io/docs/tasks/run-application/configure-pdb/) for the service mesh sidecar injector. - - `enabled` ((#v-connectinject-disruptionbudget-enabled)) (`boolean: true`) - This will enable/disable registering a PodDisruptionBudget for the + - `enabled` ((#v-connectinject-disruptionbudget-enabled)) (`boolean: true`) - This will enable/disable registering a PodDisruptionBudget for the service mesh sidecar injector. If this is enabled, it will only register the budget so long as the service mesh is enabled. @@ -1595,13 +1711,19 @@ Use these links to navigate to a particular top-level stanza. --set 'connectInject.disruptionBudget.maxUnavailable=0'` flag to the helm chart installation command because of a limitation in the Helm templating language. + - `minAvailable` ((#v-connectinject-disruptionbudget-minavailable)) (`integer: null`) - The minimum number of available pods. + Takes precedence over maxUnavailable if set. + - `cni` ((#v-connectinject-cni)) - Configures consul-cni plugin for Consul Service mesh services - - `enabled` ((#v-connectinject-cni-enabled)) (`boolean: false`) - If true, then all traffic redirection setup will use the consul-cni plugin. + - `enabled` ((#v-connectinject-cni-enabled)) (`boolean: false`) - If true, then all traffic redirection setup uses the consul-cni plugin. Requires connectInject.enabled to also be true. - `logLevel` ((#v-connectinject-cni-loglevel)) (`string: null`) - Log level for the installer and plugin. Overrides global.logLevel + - `namespace` ((#v-connectinject-cni-namespace)) (`string: null`) - Set the namespace to install the CNI plugin into. Overrides global namespace settings for CNI resources. + Ex: "kube-system" + - `cniBinDir` ((#v-connectinject-cni-cnibindir)) (`string: /opt/cni/bin`) - Location on the kubernetes node where the CNI plugin is installed. Shoud be the absolute path and start with a '/' Example on GKE: @@ -1614,7 +1736,7 @@ Use these links to navigate to a particular top-level stanza. - `multus` ((#v-connectinject-cni-multus)) (`string: false`) - If multus CNI plugin is enabled with consul-cni. When enabled, consul-cni will not be installed as a chained CNI plugin. Instead, a NetworkAttachementDefinition CustomResourceDefinition (CRD) will be created in the helm release namespace. Following multus plugin standards, an annotation is required in order for the consul-cni plugin - to be executed and for your service to be added to the Consul Service Mesh. + to be executed and for your service to be added to the Consul Service Mesh. Add the annotation `'k8s.v1.cni.cncf.io/networks': '[{ "name":"consul-cni","namespace": "consul" }]'` to your pod to use the default installed NetworkAttachementDefinition CRD. @@ -1635,7 +1757,8 @@ Use these links to navigate to a particular top-level stanza. by the OpenShift platform. - `updateStrategy` ((#v-connectinject-cni-updatestrategy)) (`string: null`) - updateStrategy for the CNI installer DaemonSet. - See https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/#daemonset-update-strategy. + Refer to the Kubernetes [Daemonset upgrade strategy](https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/#daemonset-update-strategy) + documentation. This should be a multi-line string mapping directly to the updateStrategy Example: @@ -1647,7 +1770,19 @@ Use these links to navigate to a particular top-level stanza. type: RollingUpdate ``` - - `metrics` ((#v-connectinject-metrics)) - Configures metrics for Consul Connect services. All values are overridable + - `consulNode` ((#v-connectinject-consulnode)) + + - `meta` ((#v-connectinject-consulnode-meta)) (`map`) - meta specifies an arbitrary metadata key/value pair to associate with the node. + + Example: + + ```yaml + meta: + cluster: test-cluster + persistent: true + ``` + + - `metrics` ((#v-connectinject-metrics)) - Configures metrics for Consul service mesh services. All values are overridable via annotations on a per-pod basis. - `defaultEnabled` ((#v-connectinject-metrics-defaultenabled)) (`string: -`) - If true, the connect-injector will automatically @@ -1655,18 +1790,18 @@ Use these links to navigate to a particular top-level stanza. add a listener on the Envoy sidecar to expose metrics. The exposed metrics will depend on whether metrics merging is enabled: - If metrics merging is enabled: - the Consul sidecar will run a merged metrics server + the consul-dataplane will run a merged metrics server combining Envoy sidecar and Connect service metrics, i.e. if your service exposes its own Prometheus metrics. - If metrics merging is disabled: the listener will just expose Envoy sidecar metrics. This will inherit from `global.metrics.enabled`. - - `defaultEnableMerging` ((#v-connectinject-metrics-defaultenablemerging)) (`boolean: false`) - Configures the Consul sidecar to run a merged metrics server + - `defaultEnableMerging` ((#v-connectinject-metrics-defaultenablemerging)) (`boolean: false`) - Configures the consul-dataplane to run a merged metrics server to combine and serve both Envoy and Connect service metrics. This feature is available only in Consul v1.10.0 or greater. - - `defaultMergedMetricsPort` ((#v-connectinject-metrics-defaultmergedmetricsport)) (`integer: 20100`) - Configures the port at which the Consul sidecar will listen on to return + - `defaultMergedMetricsPort` ((#v-connectinject-metrics-defaultmergedmetricsport)) (`integer: 20100`) - Configures the port at which the consul-dataplane will listen on to return combined metrics. This port only needs to be changed if it conflicts with the application's ports. @@ -1690,6 +1825,16 @@ Use these links to navigate to a particular top-level stanza. - `priorityClassName` ((#v-connectinject-priorityclassname)) (`string: ""`) - Optional priorityClassName. + - `extraLabels` ((#v-connectinject-extralabels)) (`map`) - Extra labels to attach to the connect inject pods. This should be a YAML map. + + Example: + + ```yaml + extraLabels: + labelKey: label-value + anotherLabelKey: another-label-value + ``` + - `annotations` ((#v-connectinject-annotations)) (`string: null`) - This value defines additional annotations for connect inject pods. This should be formatted as a multi-line string. @@ -1715,7 +1860,19 @@ Use these links to navigate to a particular top-level stanza. "sample/annotation2": "bar" ``` - - `resources` ((#v-connectinject-resources)) (`map`) - The resource settings for connect inject pods. + - `resources` ((#v-connectinject-resources)) (`map`) - The resource settings for connect inject pods. The defaults, are optimized for getting started worklows on developer deployments. The settings should be tweaked for production deployments. + + - `requests` ((#v-connectinject-resources-requests)) + + - `memory` ((#v-connectinject-resources-requests-memory)) (`string: 200Mi`) - Recommended production default: 500Mi + + - `cpu` ((#v-connectinject-resources-requests-cpu)) (`string: 50m`) - Recommended production default: 250m + + - `limits` ((#v-connectinject-resources-limits)) + + - `memory` ((#v-connectinject-resources-limits-memory)) (`string: 200Mi`) - Recommended production default: 500Mi + + - `cpu` ((#v-connectinject-resources-limits-cpu)) (`string: 50m`) - Recommended production default: 250m - `failurePolicy` ((#v-connectinject-failurepolicy)) (`string: Fail`) - Sets the failurePolicy for the mutating webhook. By default this will cause pods not part of the consul installation to fail scheduling while the webhook is offline. This prevents a pod from skipping mutation if the webhook were to be momentarily offline. @@ -1724,14 +1881,14 @@ Use these links to navigate to a particular top-level stanza. which can lead to hangs. In these environments it is recommend to use "Ignore" instead. This setting can be safely disabled by setting to "Ignore". - - `namespaceSelector` ((#v-connectinject-namespaceselector)) (`string`) - Selector for restricting the webhook to only specific namespaces. + - `namespaceSelector` ((#v-connectinject-namespaceselector)) (`string`) - Selector for restricting the webhook to only specific namespaces. Use with `connectInject.default: true` to automatically inject all pods in namespaces that match the selector. This should be set to a multiline string. - See https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#matching-requests-namespaceselector + Refer to https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#matching-requests-namespaceselector for more details. - By default, we exclude the kube-system namespace since usually users won't - want those pods injected and also the local-path-storage namespace so that - Kind (Kubernetes In Docker) can provision Pods used to create PVCs. + By default, we exclude kube-system since usually users won't + want those pods injected and local-path-storage and openebs so that + Kind (Kubernetes In Docker) and [OpenEBS](https://openebs.io/) respectively can provision Pods used to create PVCs. Note that this exclusion is only supported in Kubernetes v1.21.1+. Example: @@ -1748,7 +1905,7 @@ Use these links to navigate to a particular top-level stanza. annotated. Use `["*"]` to automatically allow all k8s namespaces. For example, `["namespace1", "namespace2"]` will only allow pods in the k8s - namespaces `namespace1` and `namespace2` to have Connect sidecars injected + namespaces `namespace1` and `namespace2` to have Consul service mesh sidecars injected and registered with Consul. All other k8s namespaces will be ignored. To deny all namespaces, set this to `[]`. @@ -1776,12 +1933,12 @@ Use these links to navigate to a particular top-level stanza. k8s pods into. If the Consul namespace does not already exist, it will be created. This will be ignored if `mirroringK8S` is true. - - `mirroringK8S` ((#v-connectinject-consulnamespaces-mirroringk8s)) (`boolean: false`) - Causes k8s pods to be registered into a Consul namespace + - `mirroringK8S` ((#v-connectinject-consulnamespaces-mirroringk8s)) (`boolean: true`) - Causes k8s pods to be registered into a Consul namespace of the same name as their k8s namespace, optionally prefixed if `mirroringK8SPrefix` is set below. If the Consul namespace does not already exist, it will be created. Turning this on overrides the - `consulDestinationNamespace` setting. If mirroring is enabled, avoid creating any Consul - resources in the following Kubernetes namespaces, as Consul currently reserves these + `consulDestinationNamespace` setting. If mirroring is enabled, avoid creating any Consul + resources in the following Kubernetes namespaces, as Consul currently reserves these namespaces for system use: "system", "universal", "operator", "root". - `mirroringK8SPrefix` ((#v-connectinject-consulnamespaces-mirroringk8sprefix)) (`string: ""`) - If `mirroringK8S` is set to true, `mirroringK8SPrefix` allows each Consul namespace @@ -1813,8 +1970,8 @@ Use these links to navigate to a particular top-level stanza. If set to an empty string all service accounts can log in. This only has effect if ACLs are enabled. - See https://www.consul.io/docs/acl/acl-auth-methods.html#binding-rules - and https://www.consul.io/docs/acl/auth-methods/kubernetes.html#trusted-identity-attributes + Refer to Auth methods [Binding rules](https://developer.hashicorp.com/consul/docs/security/acl/auth-methods#binding-rules) + and [Trusted identiy attributes](https://developer.hashicorp.com/consul/docs/security/acl/auth-methods/kubernetes#trusted-identity-attributes) for more details. Requires Consul >= v1.5. @@ -1840,7 +1997,7 @@ Use these links to navigate to a particular top-level stanza. leads to unnecessary thread and memory usage and leaves unnecessary idle connections open. It is advised to keep this number low for sidecars and high for edge proxies. This will control the `--concurrency` flag to Envoy. - For additional information see also: https://blog.envoyproxy.io/envoy-threading-model-a8d44b922310 + For additional information, refer to https://blog.envoyproxy.io/envoy-threading-model-a8d44b922310 This setting can be overridden on a per-pod basis via this annotation: - `consul.hashicorp.com/consul-envoy-proxy-concurrency` @@ -1856,82 +2013,65 @@ Use these links to navigate to a particular top-level stanza. - `requests` ((#v-connectinject-sidecarproxy-resources-requests)) - - `memory` ((#v-connectinject-sidecarproxy-resources-requests-memory)) (`string: null`) - Recommended default: 100Mi + - `memory` ((#v-connectinject-sidecarproxy-resources-requests-memory)) (`string: null`) - Recommended production default: 100Mi - - `cpu` ((#v-connectinject-sidecarproxy-resources-requests-cpu)) (`string: null`) - Recommended default: 100m + - `cpu` ((#v-connectinject-sidecarproxy-resources-requests-cpu)) (`string: null`) - Recommended production default: 100m - `limits` ((#v-connectinject-sidecarproxy-resources-limits)) - - `memory` ((#v-connectinject-sidecarproxy-resources-limits-memory)) (`string: null`) - Recommended default: 100Mi + - `memory` ((#v-connectinject-sidecarproxy-resources-limits-memory)) (`string: null`) - Recommended production default: 100Mi - - `cpu` ((#v-connectinject-sidecarproxy-resources-limits-cpu)) (`string: null`) - Recommended default: 100m + - `cpu` ((#v-connectinject-sidecarproxy-resources-limits-cpu)) (`string: null`) - Recommended production default: 100m - - `initContainer` ((#v-connectinject-initcontainer)) (`map`) - The resource settings for the Connect injected init container. + - `lifecycle` ((#v-connectinject-sidecarproxy-lifecycle)) (`map`) - Set default lifecycle management configuration for sidecar proxy. + These settings can be overridden on a per-pod basis via these annotations: -### controller ((#h-controller)) + - `consul.hashicorp.com/enable-sidecar-proxy-lifecycle` + - `consul.hashicorp.com/enable-sidecar-proxy-shutdown-drain-listeners` + - `consul.hashicorp.com/sidecar-proxy-lifecycle-shutdown-grace-period-seconds` + - `consul.hashicorp.com/sidecar-proxy-lifecycle-graceful-port` + - `consul.hashicorp.com/sidecar-proxy-lifecycle-graceful-shutdown-path` -- `controller` ((#v-controller)) - Controller handles config entry custom resources. - Requires consul >= 1.8.4. - ServiceIntentions require consul 1.9+. + - `defaultEnabled` ((#v-connectinject-sidecarproxy-lifecycle-defaultenabled)) (`boolean: true`) - - `enabled` ((#v-controller-enabled)) (`boolean: true`) - Enables the controller for managing custom resources. + - `defaultEnableShutdownDrainListeners` ((#v-connectinject-sidecarproxy-lifecycle-defaultenableshutdowndrainlisteners)) (`boolean: true`) - - `replicas` ((#v-controller-replicas)) (`integer: 1`) - The number of deployment replicas. + - `defaultShutdownGracePeriodSeconds` ((#v-connectinject-sidecarproxy-lifecycle-defaultshutdowngraceperiodseconds)) (`integer: 30`) - - `logLevel` ((#v-controller-loglevel)) (`string: ""`) - Log verbosity level. One of "debug", "info", "warn", or "error". + - `defaultGracefulPort` ((#v-connectinject-sidecarproxy-lifecycle-defaultgracefulport)) (`integer: 20600`) - - `serviceAccount` ((#v-controller-serviceaccount)) + - `defaultGracefulShutdownPath` ((#v-connectinject-sidecarproxy-lifecycle-defaultgracefulshutdownpath)) (`string: /graceful_shutdown`) - - `annotations` ((#v-controller-serviceaccount-annotations)) (`string: null`) - This value defines additional annotations for the controller service account. This should be formatted as a - multi-line string. + - `initContainer` ((#v-connectinject-initcontainer)) (`map`) - The resource settings for the Connect injected init container. If null, the resources + won't be set for the initContainer. The defaults are optimized for developer instances of + Kubernetes, however they should be tweaked with the recommended defaults as shown below to speed up service registration times. - ```yaml - annotations: | - "sample/annotation1": "foo" - "sample/annotation2": "bar" - ``` - - - `resources` ((#v-controller-resources)) (`map`) - The resource settings for controller pods. + - `resources` ((#v-connectinject-initcontainer-resources)) - - `nodeSelector` ((#v-controller-nodeselector)) (`string: null`) - Optional YAML string to specify a nodeSelector config. + - `requests` ((#v-connectinject-initcontainer-resources-requests)) - - `tolerations` ((#v-controller-tolerations)) (`string: null`) - Optional YAML string to specify tolerations. + - `memory` ((#v-connectinject-initcontainer-resources-requests-memory)) (`string: 25Mi`) - Recommended production default: 150Mi - - `affinity` ((#v-controller-affinity)) (`string: null`) - Affinity Settings - This should be a multi-line string matching the affinity object + - `cpu` ((#v-connectinject-initcontainer-resources-requests-cpu)) (`string: 50m`) - Recommended production default: 250m - - `priorityClassName` ((#v-controller-priorityclassname)) (`string: ""`) - Optional priorityClassName. + - `limits` ((#v-connectinject-initcontainer-resources-limits)) - - `aclToken` ((#v-controller-acltoken)) - Refers to a Kubernetes secret that you have created that contains - an ACL token for your Consul cluster which grants the controller process the correct - permissions. This is only needed if you are managing ACLs yourself (i.e. not using - `global.acls.manageSystemACLs`). + - `memory` ((#v-connectinject-initcontainer-resources-limits-memory)) (`string: 150Mi`) - Recommended production default: 150Mi - If running Consul OSS, requires permissions: - ```hcl - operator = "write" - service_prefix "" { - policy = "write" - intentions = "write" - } - ``` - If running Consul Enterprise, talk to your account manager for assistance. - - - `secretName` ((#v-controller-acltoken-secretname)) (`string: null`) - The name of the Vault secret that holds the ACL token. - - - `secretKey` ((#v-controller-acltoken-secretkey)) (`string: null`) - The key within the Vault secret that holds the ACL token. + - `cpu` ((#v-connectinject-initcontainer-resources-limits-cpu)) (`string: null`) - Recommended production default: 500m ### meshGateway ((#h-meshgateway)) -- `meshGateway` ((#v-meshgateway)) - Mesh Gateways enable Consul Connect to work across Consul datacenters. +- `meshGateway` ((#v-meshgateway)) - [Mesh Gateways](https://developer.hashicorp.com/consul/docs/connect/gateways/mesh-gateway) enable Consul Connect to work across Consul datacenters. + + - `enabled` ((#v-meshgateway-enabled)) (`boolean: false`) - If [mesh gateways](https://developer.hashicorp.com/consul/docs/connect/gateways/mesh-gateway) are enabled, a Deployment will be created that runs + gateways and Consul service mesh will be configured to use gateways. + This setting is required for [Cluster Peering](https://developer.hashicorp.com/consul/docs/connect/cluster-peering/k8s). + Requirements: consul 1.6.0+ if using `global.acls.manageSystemACLs``. - - `enabled` ((#v-meshgateway-enabled)) (`boolean: false`) - If mesh gateways are enabled, a Deployment will be created that runs - gateways and Consul Connect will be configured to use gateways. - See https://www.consul.io/docs/connect/mesh_gateway.html - Requirements: consul 1.6.0+ if using - global.acls.manageSystemACLs. + - `logLevel` ((#v-meshgateway-loglevel)) (`string: ""`) - Override global log verbosity level for `mesh-gateway-deployment` pods. One of "trace", "debug", "info", "warn", or "error". - - `replicas` ((#v-meshgateway-replicas)) (`integer: 2`) - Number of replicas for the Deployment. + - `replicas` ((#v-meshgateway-replicas)) (`integer: 1`) - Number of replicas for the Deployment. - `wanAddress` ((#v-meshgateway-wanaddress)) - What gets registered as WAN address for the gateway. @@ -1962,7 +2102,7 @@ Use these links to navigate to a particular top-level stanza. - `port` ((#v-meshgateway-wanaddress-port)) (`integer: 443`) - Port that gets registered for WAN traffic. If source is set to "Service" then this setting will have no effect. - See the documentation for source as to which port will be used in that + Refer to the documentation for source as to which port will be used in that case. - `static` ((#v-meshgateway-wanaddress-static)) (`string: ""`) - If source is set to "Static" then this value will be used as the WAN @@ -2027,15 +2167,31 @@ Use these links to navigate to a particular top-level stanza. - `initServiceInitContainer` ((#v-meshgateway-initserviceinitcontainer)) (`map`) - The resource settings for the `service-init` init container. - - `affinity` ((#v-meshgateway-affinity)) (`string`) - By default, we set an anti-affinity so that two gateway pods won't be - on the same node. NOTE: Gateways require that Consul client agents are - also running on the nodes alongside each gateway pod. + - `affinity` ((#v-meshgateway-affinity)) (`string: null`) - This value defines the [affinity](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity) + for mesh gateway pods. It defaults to `null` thereby allowing multiple gateway pods on each node. But if one would prefer + a mode which minimizes risk of the cluster becoming unusable if a node is lost, set this value + to the value in the example below. + + Example: + + ```yaml + affinity: | + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + app: {{ template "consul.name" . }} + release: "{{ .Release.Name }}" + component: mesh-gateway + topologyKey: kubernetes.io/hostname + ``` - `tolerations` ((#v-meshgateway-tolerations)) (`string: null`) - Optional YAML string to specify tolerations. - `topologySpreadConstraints` ((#v-meshgateway-topologyspreadconstraints)) (`string: ""`) - Pod topology spread constraints for mesh gateway pods. - This should be a multi-line YAML string matching the `topologySpreadConstraints` array - (https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/) in a Pod Spec. + This should be a multi-line YAML string matching the + [`topologySpreadConstraints`](https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/) + array in a Pod Spec. This requires K8S >= 1.18 (beta) or 1.19 (stable). @@ -2079,13 +2235,15 @@ Use these links to navigate to a particular top-level stanza. - `enabled` ((#v-ingressgateways-enabled)) (`boolean: false`) - Enable ingress gateway deployment. Requires `connectInject.enabled=true` and `client.enabled=true`. + - `logLevel` ((#v-ingressgateways-loglevel)) (`string: ""`) - Override global log verbosity level for `ingress-gateways-deployment` pods. One of "trace", "debug", "info", "warn", or "error". + - `defaults` ((#v-ingressgateways-defaults)) - Defaults sets default values for all gateway fields. With the exception of annotations, defining any of these values in the `gateways` list will override the default values provided here. Annotations will include both the default annotations and any additional ones defined for a specific gateway. - - `replicas` ((#v-ingressgateways-defaults-replicas)) (`integer: 2`) - Number of replicas for each ingress gateway defined. + - `replicas` ((#v-ingressgateways-defaults-replicas)) (`integer: 1`) - Number of replicas for each ingress gateway defined. - `service` ((#v-ingressgateways-defaults-service)) - The service options configure the Service that fronts the gateway Deployment. @@ -2125,15 +2283,31 @@ Use these links to navigate to a particular top-level stanza. - `resources` ((#v-ingressgateways-defaults-resources)) (`map`) - Resource limits for all ingress gateway pods - - `affinity` ((#v-ingressgateways-defaults-affinity)) (`string`) - By default, we set an anti-affinity so that two of the same gateway pods - won't be on the same node. NOTE: Gateways require that Consul client agents are - also running on the nodes alongside each gateway pod. + - `affinity` ((#v-ingressgateways-defaults-affinity)) (`string: null`) - This value defines the [affinity](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity) + for ingress gateway pods. It defaults to `null` thereby allowing multiple gateway pods on each node. But if one would prefer + a mode which minimizes risk of the cluster becoming unusable if a node is lost, set this value + to the value in the example below. + + Example: + + ```yaml + affinity: | + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + app: {{ template "consul.name" . }} + release: "{{ .Release.Name }}" + component: ingress-gateway + topologyKey: kubernetes.io/hostname + ``` - `tolerations` ((#v-ingressgateways-defaults-tolerations)) (`string: null`) - Optional YAML string to specify tolerations. - `topologySpreadConstraints` ((#v-ingressgateways-defaults-topologyspreadconstraints)) (`string: ""`) - Pod topology spread constraints for ingress gateway pods. - This should be a multi-line YAML string matching the `topologySpreadConstraints` array - (https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/) in a Pod Spec. + This should be a multi-line YAML string matching the + [`topologySpreadConstraints`](https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/) + array in a Pod Spec. This requires K8S >= 1.18 (beta) or 1.19 (stable). @@ -2193,13 +2367,15 @@ Use these links to navigate to a particular top-level stanza. - `enabled` ((#v-terminatinggateways-enabled)) (`boolean: false`) - Enable terminating gateway deployment. Requires `connectInject.enabled=true` and `client.enabled=true`. + - `logLevel` ((#v-terminatinggateways-loglevel)) (`string: ""`) - Override global log verbosity level. One of "trace", "debug", "info", "warn", or "error". + - `defaults` ((#v-terminatinggateways-defaults)) - Defaults sets default values for all gateway fields. With the exception of annotations, defining any of these values in the `gateways` list will override the default values provided here. Annotations will include both the default annotations and any additional ones defined for a specific gateway. - - `replicas` ((#v-terminatinggateways-defaults-replicas)) (`integer: 2`) - Number of replicas for each terminating gateway defined. + - `replicas` ((#v-terminatinggateways-defaults-replicas)) (`integer: 1`) - Number of replicas for each terminating gateway defined. - `extraVolumes` ((#v-terminatinggateways-defaults-extravolumes)) (`array`) - A list of extra volumes to mount. These will be exposed to Consul in the path `/consul/userconfig//`. @@ -2216,15 +2392,31 @@ Use these links to navigate to a particular top-level stanza. - `resources` ((#v-terminatinggateways-defaults-resources)) (`map`) - Resource limits for all terminating gateway pods - - `affinity` ((#v-terminatinggateways-defaults-affinity)) (`string`) - By default, we set an anti-affinity so that two of the same gateway pods - won't be on the same node. NOTE: Gateways require that Consul client agents are - also running on the nodes alongside each gateway pod. + - `affinity` ((#v-terminatinggateways-defaults-affinity)) (`string: null`) - This value defines the [affinity](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity) + for terminating gateway pods. It defaults to `null` thereby allowing multiple gateway pods on each node. But if one would prefer + a mode which minimizes risk of the cluster becoming unusable if a node is lost, set this value + to the value in the example below. + + Example: + + ```yaml + affinity: | + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + app: {{ template "consul.name" . }} + release: "{{ .Release.Name }}" + component: terminating-gateway + topologyKey: kubernetes.io/hostname + ``` - `tolerations` ((#v-terminatinggateways-defaults-tolerations)) (`string: null`) - Optional YAML string to specify tolerations. - `topologySpreadConstraints` ((#v-terminatinggateways-defaults-topologyspreadconstraints)) (`string: ""`) - Pod topology spread constraints for terminating gateway pods. - This should be a multi-line YAML string matching the `topologySpreadConstraints` array - (https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/) in a Pod Spec. + This should be a multi-line YAML string matching the + [`topologySpreadConstraints`](https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/) + array in a Pod Spec. This requires K8S >= 1.18 (beta) or 1.19 (stable). @@ -2288,13 +2480,18 @@ Use these links to navigate to a particular top-level stanza. - `image` ((#v-apigateway-image)) (`string: null`) - Image to use for the api-gateway-controller pods and gateway instances + ~> **Note:** Using API Gateway <= 0.4 with external servers requires setting `client.enabled: true`. + + - `imageEnvoy` ((#v-apigateway-imageenvoy)) (`string: envoyproxy/envoy:`) - The name (and tag) of the Envoy Docker image used for the + apiGateway. For other Consul compoenents, imageEnvoy has been replaced with Consul Dataplane. + - `logLevel` ((#v-apigateway-loglevel)) (`string: info`) - Override global log verbosity level for api-gateway-controller pods. One of "debug", "info", "warn", or "error". - `managedGatewayClass` ((#v-apigateway-managedgatewayclass)) - Configuration settings for the optional GatewayClass installed by consul-k8s (enabled by default) - `enabled` ((#v-apigateway-managedgatewayclass-enabled)) (`boolean: true`) - When true a GatewayClass is configured to automatically work with Consul as installed by helm. - - `nodeSelector` ((#v-apigateway-managedgatewayclass-nodeselector)) (`string: null`) - This value defines `nodeSelector` (https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) + - `nodeSelector` ((#v-apigateway-managedgatewayclass-nodeselector)) (`string: null`) - This value defines [`nodeSelector`](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) labels for gateway pod assignment, formatted as a multi-line string. Example: @@ -2304,6 +2501,10 @@ Use these links to navigate to a particular top-level stanza. beta.kubernetes.io/arch: amd64 ``` + - `tolerations` ((#v-apigateway-managedgatewayclass-tolerations)) (`string: null`) - Toleration settings for gateway pods created with the managed gateway class. + This should be a multi-line string matching the + [Tolerations](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/) array in a Pod spec. + - `serviceType` ((#v-apigateway-managedgatewayclass-servicetype)) (`string: LoadBalancer`) - This value defines the type of service created for gateways (e.g. LoadBalancer, ClusterIP) - `useHostPorts` ((#v-apigateway-managedgatewayclass-usehostports)) (`boolean: false`) - This value toggles if the gateway ports should be mapped to host ports @@ -2315,8 +2516,9 @@ Use these links to navigate to a particular top-level stanza. Example: ```yaml - service: | - - external-dns.alpha.kubernetes.io/hostname + service: + annotations: | + - external-dns.alpha.kubernetes.io/hostname ``` - `deployment` ((#v-apigateway-managedgatewayclass-deployment)) (`map`) - This value defines the number of pods to deploy for each Gateway as well as a min and max number of pods for all Gateways @@ -2353,10 +2555,10 @@ Use these links to navigate to a particular top-level stanza. ``` - `priorityClassName` ((#v-apigateway-controller-priorityclassname)) (`string: ""`) - This value references an existing - Kubernetes `priorityClassName` (https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#pod-priority) + Kubernetes [`priorityClassName`](https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#pod-priority) that can be assigned to api-gateway-controller pods. - - `nodeSelector` ((#v-apigateway-controller-nodeselector)) (`string: null`) - This value defines `nodeSelector` (https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) + - `nodeSelector` ((#v-apigateway-controller-nodeselector)) (`string: null`) - This value defines [`nodeSelector`](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) labels for api-gateway-controller pod assignment, formatted as a multi-line string. Example: @@ -2366,6 +2568,9 @@ Use these links to navigate to a particular top-level stanza. beta.kubernetes.io/arch: amd64 ``` + - `tolerations` ((#v-apigateway-controller-tolerations)) (`string: null`) - This value defines the tolerations for api-gateway-controller pod, this should be a multi-line string matching the + [Tolerations](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/) array in a Pod spec. + - `service` ((#v-apigateway-controller-service)) - Configuration for the Service created for the api-gateway-controller - `annotations` ((#v-apigateway-controller-service-annotations)) (`string: null`) - Annotations to apply to the api-gateway-controller service. @@ -2388,6 +2593,16 @@ Use these links to navigate to a particular top-level stanza. This should be a multi-line string matching the Toleration array in a PodSpec. + - `nodeSelector` ((#v-webhookcertmanager-nodeselector)) (`string: null`) - This value defines [`nodeSelector`](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) + labels for the webhook-cert-manager pod assignment, formatted as a multi-line string. + + Example: + + ```yaml + nodeSelector: | + beta.kubernetes.io/arch: amd64 + ``` + ### prometheus ((#h-prometheus)) - `prometheus` ((#v-prometheus)) - Configures a demo Prometheus installation. diff --git a/website/content/docs/k8s/index.mdx b/website/content/docs/k8s/index.mdx index 2c3554a044ea..b6fae1110bd5 100644 --- a/website/content/docs/k8s/index.mdx +++ b/website/content/docs/k8s/index.mdx @@ -14,59 +14,58 @@ This section documents the official integrations between Consul and Kubernetes. ## Use Cases -**Consul Service Mesh:** +**Consul Service Mesh**: Consul can automatically inject the [Consul Service Mesh](/docs/connect) sidecar into pods so that they can accept and establish encrypted -and authorized network connections via mutual TLS. And because Consul Service Mesh -can run anywhere, pods can also communicate with external services (and -vice versa) over a fully encrypted connection. +and authorized network connections with mutual TLS. And because Consul Service Mesh +can run anywhere, pods and external services can communicate with each other over a fully encrypted connection. -**Service sync to enable Kubernetes and non-Kubernetes services to communicate:** -Consul can sync Kubernetes services with its own service registry. This allows -Kubernetes services to use native Kubernetes service discovery to discover +**Service sync to enable Kubernetes and non-Kubernetes services to communicate**: +Consul can sync Kubernetes services with its own service registry. This service sync allows +Kubernetes services to use Kubernetes' native service discovery capabilities to discover and connect to external services registered in Consul, and for external services to use Consul service discovery to discover and connect to Kubernetes services. -**And more!** Consul can run directly on Kubernetes, so in addition to the +**Additional integrations**: Consul can run directly on Kubernetes, so in addition to the native integrations provided by Consul itself, any other tool built for -Kubernetes can choose to leverage Consul. +Kubernetes can leverage Consul. ## Getting Started With Consul and Kubernetes There are several ways to try Consul with Kubernetes in different environments. -**Tutorials** +### Tutorials -- The [Getting Started with Consul Service Mesh track](https://learn.hashicorp.com/tutorials/consul/service-mesh-deploy?in=consul/gs-consul-service-mesh?utm_source=docs) +- The [Service Mesh on Kubernetes collection](/consul/tutorials/kubernetes?utm_source=docs) provides guidance for installing Consul as service mesh for Kubernetes using the Helm chart, deploying services in the service mesh, and using intentions to secure service communications. -- The [Migrate to Microservices with Consul Service Mesh on Kubernetes](https://learn.hashicorp.com/collections/consul/microservices?utm_source=docs) +- The [Migrate to Microservices with Consul Service Mesh on Kubernetes](/consul/tutorials/microservices?utm_source=docs) collection uses an example application written by a fictional company to illustrate why and how organizations can migrate from monolith to microservices using Consul service mesh on Kubernetes. The case study in this collection should provide information valuable for understanding how to develop services that leverage Consul during any stage of your microservices journey. -- The [Consul and Minikube guide](https://learn.hashicorp.com/tutorials/consul/kubernetes-minikube?utm_source=docs) is a quick step-by-step guide for deploying Consul with the official Helm chart on a local instance of Minikube. +- The [Consul and Minikube guide](/consul/tutorials/kubernetes/kubernetes-minikube?utm_source=docs) is a quick step-by-step guide for deploying Consul with the official Helm chart on a local instance of Minikube. - Review production best practices and cloud-specific configurations for deploying Consul on managed Kubernetes runtimes. - - The [Consul on Azure Kubernetes Service (AKS) tutorial](https://learn.hashicorp.com/tutorials/consul/kubernetes-aks-azure?utm_source=docs) is a complete step-by-step guide on how to deploy Consul on AKS. The guide also allows you to practice deploying two microservices. - - The [Consul on Amazon Elastic Kubernetes Service (EKS) tutorial](https://learn.hashicorp.com/tutorials/consul/kubernetes-eks-aws?utm_source=docs) is a complete step-by-step guide on how to deploy Consul on EKS. Additionally, it provides guidance on interacting with your datacenter with the Consul UI, CLI, and API. - - The [Consul on Google Kubernetes Engine (GKE) tutorial](https://learn.hashicorp.com/tutorials/consul/kubernetes-gke-google?utm_source=docs) is a complete step-by-step guide on how to deploy Consul on GKE. Additionally, it provides guidance on interacting with your datacenter with the Consul UI, CLI, and API. + - The [Consul on Azure Kubernetes Service (AKS) tutorial](/consul/tutorials/kubernetes/kubernetes-aks-azure?utm_source=docs) is a complete step-by-step guide on how to deploy Consul on AKS. The guide also allows you to practice deploying two microservices. + - The [Consul on Amazon Elastic Kubernetes Service (EKS) tutorial](/consul/tutorials/kubernetes/kubernetes-eks-aws?utm_source=docs) is a complete step-by-step guide on how to deploy Consul on EKS. Additionally, it provides guidance on interacting with your datacenter with the Consul UI, CLI, and API. + - The [Consul on Google Kubernetes Engine (GKE) tutorial](/consul/tutorials/kubernetes/kubernetes-gke-google?utm_source=docs) is a complete step-by-step guide on how to deploy Consul on GKE. Additionally, it provides guidance on interacting with your datacenter with the Consul UI, CLI, and API. -- The [Consul and Kubernetes Reference Architecture](https://learn.hashicorp.com/tutorials/consul/kubernetes-reference-architecture?utm_source=docs) guide provides recommended practices for production. +- The [Consul and Kubernetes Reference Architecture](/consul/tutorials/kubernetes/kubernetes-reference-architecture?utm_source=docs) guide provides recommended practices for production. -- The [Consul and Kubernetes Deployment](https://learn.hashicorp.com/tutorials/consul/kubernetes-deployment-guide?utm_source=docs) tutorial covers the necessary steps to install and configure a new Consul cluster on Kubernetes in production. +- The [Consul and Kubernetes Deployment](/consul/tutorials/kubernetes/kubernetes-deployment-guide?utm_source=docs) tutorial covers the necessary steps to install and configure a new Consul cluster on Kubernetes in production. -- The [Secure Consul and Registered Services on Kubernetes](https://learn.hashicorp.com/tutorials/consul/kubernetes-secure-agents?utm_source=docs) tutorial covers +- The [Secure Consul and Registered Services on Kubernetes](/consul/tutorials/kubernetes/kubernetes-secure-agents?utm_source=docs) tutorial covers the necessary steps to secure a Consul cluster running on Kubernetes in production. -- The [Layer 7 Observability with Consul Service Mesh](https://learn.hashicorp.com/tutorials/consul/kubernetes-layer7-observability?in=consul/kubernetes) tutorial covers monitoring a +- The [Layer 7 Observability with Consul Service Mesh](/consul/tutorials/kubernetes/kubernetes-layer7-observability) tutorial covers monitoring a Consul service mesh running on Kubernetes with Prometheus and Grafana. -**Documentation** +### Documentation - [Installing Consul](/docs/k8s/installation/install) covers how to install Consul using the Helm chart. - [Helm Chart Reference](/docs/k8s/helm) describes the different options for configuring the Helm chart. diff --git a/website/content/docs/k8s/installation/install-cli.mdx b/website/content/docs/k8s/installation/install-cli.mdx index f195784c0aca..48804fe440ab 100644 --- a/website/content/docs/k8s/installation/install-cli.mdx +++ b/website/content/docs/k8s/installation/install-cli.mdx @@ -5,13 +5,10 @@ description: >- You can use the Consul K8s CLI tool to schedule Kubernetes deployments instead of using Helm. Learn how to download and install the tool to interact with Consul on Kubernetes using the `consul-k8s` command. --- -# Install Consul on K8s CLI - -# Install Consul on Kubernetes from Consul K8s CLI +# Install Consul on Kubernetes from Consul K8s CLI This topic describes how to install Consul on Kubernetes using the Consul K8s CLI tool. The Consul K8s CLI tool enables you to quickly install and interact with Consul on Kubernetes. Use the Consul K8s CLI tool to install Consul on Kubernetes if you are deploying a single cluster. We recommend using the [Helm chart installation method](/docs/k8s/installation/install) if you are installing Consul on Kubernetes for multi-cluster deployments that involve cross-partition or cross datacenter communication. - ## Introduction If it is your first time installing Consul on Kubernetes, then you must first install the Consul K8s CLI tool. You can install Consul on Kubernetes using the Consul K8s tool after installing the CLI. @@ -20,50 +17,44 @@ If it is your first time installing Consul on Kubernetes, then you must first in - The `kubectl` client must already be configured to authenticate to the Kubernetes cluster using a valid `kubeconfig` file. - Install one of the following package managers so that you can install the Consul K8s CLI tool. The installation instructions also provide commands for installing and using the package managers: - - MacOS: [Homebrew](https://brew.sh) - - Ubuntu/Debian: apt + - MacOS: [Homebrew](https://brew.sh) + - Ubuntu/Debian: apt - CentOS/RHEL: yum You must install the correct version of the CLI for your Consul on Kubernetes deployment. To deploy a previous version of Consul on Kubernetes, download the specific version of the CLI that matches the version of the control plane that you would like to deploy. Refer to the [compatibility matrix](/docs/k8s/compatibility) for details. -## Install the CLI +## Install the CLI The following instructions describe how to install the latest version of the Consul K8s CLI tool, as well as earlier versions, so that you can install an appropriate version of tool for your control plane. ### Install the latest version -Complete the following instructions for a fresh installation of Consul on Kubernetes. +Complete the following instructions for a fresh installation of Consul on Kubernetes. -The [Homebrew](https://brew.sh) package manager is required to complete the following installation instructions. The Homebrew formulae always installs the latest version of a binary. +The [Homebrew](https://brew.sh) package manager is required to complete the following installation instructions. The Homebrew formulae always installs the latest version of a binary. 1. Install the HashiCorp `tap`, which is a repository of all Homebrew packages for HashiCorp: ```shell-session $ brew tap hashicorp/tap ``` - -1. Install the Consul K8s CLI with `hashicorp/tap/consul` formula. - ```shell-session - $ brew install hashicorp/tap/consul-k8s - ``` - -1. If you have already provisioned a Kubernetes cluster and have already configured access to the cluster via a `kubeconfig` file, you are ready to install Consul K8s. Issue the `install` subcommand to install Consul on Kubernetes: +1. Install the Consul K8s CLI with `hashicorp/tap/consul` formula. ```shell-session - $ consul-k8s install + $ brew install hashicorp/tap/consul-k8s ``` 1. (Optional) Issue the `consul-k8s version` command to verify the installation: ```shell-session $ consul-k8s version - consul-k8s 0.39.0 + consul-k8s 1.0 ``` - + @@ -73,24 +64,24 @@ The [Homebrew](https://brew.sh) package manager is required to complete the foll ```shell-session $ curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add - ``` - -1. Add the HashiCorp apt repository. - + +1. Add the HashiCorp apt repository. + ```shell-session $ sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" ``` - + 1. Run apt-get install to install the `consul-k8s` CLI. ```shell-session $ sudo apt-get update && sudo apt-get install consul-k8s ``` - + 1. (Optional) Issue the `consul-k8s version` command to verify the installation. ```shell-session $ consul-k8s version - consul-k8s 0.39.0 + consul-k8s 1.0 ``` @@ -109,26 +100,26 @@ The [Homebrew](https://brew.sh) package manager is required to complete the foll $ sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo ``` -1. Install the `consul-k8s` CLI. +1. Install the `consul-k8s` CLI. ```shell-session $ sudo yum -y install consul-k8s ``` - + 1. (Optional) Issue the `consul-k8s version` command to verify the installation. ```shell-session $ consul-k8s version - consul-k8s 0.39.0 + consul-k8s 1.0 ``` - +
    ### Install a previous version -Complete the following instructions to install a specific version of the CLI so that your tool is compatible with your Consul on Kubernetes control plane. Refer to the [compatibility matrix](/docs/k8s/compatibility) for additional information. +Complete the following instructions to install a specific version of the CLI so that your tool is compatible with your Consul on Kubernetes control plane. Refer to the [compatibility matrix](/docs/k8s/compatibility) for additional information. @@ -137,27 +128,27 @@ Complete the following instructions to install a specific version of the CLI so 1. Download the appropriate version of Consul K8s CLI using the following `curl` command. Set the `$VERSION` environment variable to the appropriate version for your deployment. ```shell-session - $ export VERSION=0.39.0 && \ + $ export VERSION=1.1.1 && \ curl --location "https://releases.hashicorp.com/consul-k8s/${VERSION}/consul-k8s_${VERSION}_darwin_amd64.zip" --output consul-k8s-cli.zip ``` 1. Unzip the zip file output to extract the `consul-k8s` CLI binary. This overwrites existing files and also creates a `.consul-k8s` subdirectory in your `$HOME` folder. ```shell-session - $ unzip -o consul-k8s-cli.zip -d ~/.consul-k8s + $ unzip -o consul-k8s-cli.zip -d ~/consul-k8s ``` - -1. Add the path to your directory. In order to persist the `$PATH` across sessions, you will need to add this to your shellrc (i.e. shell run commands) file for the shell used by your terminal. + +1. Add the path to your directory. In order to persist the `$PATH` across sessions, you will need to add this to your shellrc (i.e. shell run commands) file for the shell used by your terminal. ```shell-session - $ export PATH=$PATH:$HOME/.consul-k8s/ + $ export PATH=$PATH:$HOME/consul-k8s ``` - + 1. (Optional) Issue the `consul-k8s version` command to verify the installation. ```shell-session $ consul-k8s version - consul-k8s 0.39.0 + consul-k8s 1.0 ```
    @@ -169,25 +160,25 @@ Complete the following instructions to install a specific version of the CLI so ```shell-session $ curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add - ``` - -1. Add the HashiCorp apt repository. - + +1. Add the HashiCorp apt repository. + ```shell-session $ sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" ``` - + 1. Run apt-get install to install the `consul-k8s` CLI. ```shell-session $ export VERSION=0.39.0 && \ sudo apt-get update && sudo apt-get install consul-k8s=${VERSION} ``` - + 1. (Optional) Issue the `consul-k8s version` command to verify the installation. ```shell-session $ consul-k8s version - consul-k8s 0.39.0 + consul-k8s 1.0 ``` @@ -206,30 +197,30 @@ Complete the following instructions to install a specific version of the CLI so $ sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo ``` -1. Install the `consul-k8s` CLI. +1. Install the `consul-k8s` CLI. ```shell-session - $ export VERSION=-0.39.0 && \ + $ export VERSION=-1.0 && \ sudo yum -y install consul-k8s-${VERSION}-1 ``` - -1. (Optional) Issue the `consul-k8s version` command to verify the installation. + +2. (Optional) Issue the `consul-k8s version` command to verify the installation. ```shell-session $ consul-k8s version - consul-k8s 0.39.0 + consul-k8s 1.0 ``` - + ## Install Consul on Kubernetes -After installing the Consul K8s CLI tool (`consul-k8s`), issue the `install` subcommand and any additional options to install Consul on Kubernetes. Refer to the [Consul K8s CLI reference](/docs/k8s/k8s-cli) for details about all commands and available options. If you do not include any additional options, the `consul-k8s` CLI installs Consul on Kubernetes using the default settings form the Consul Helm chart values. The following example installs Consul on Kubernetes with service mesh and CRDs enabled. +After installing the Consul K8s CLI tool (`consul-k8s`), issue the `install` subcommand and any additional options to install Consul on your existing Kubernetes cluster. Refer to the [Consul K8s CLI reference](/docs/k8s/k8s-cli) for details about all commands and available options. If you do not include any additional options, the `consul-k8s` CLI installs Consul on Kubernetes using the default settings form the Consul Helm chart values. The following example installs Consul on Kubernetes with service mesh and CRDs enabled. ```shell-session -$ consul-k8s install -set connectInject.enabled=true -set controller.enabled=true +$ consul-k8s install ==> Pre-Install Checks No existing installations found. @@ -241,11 +232,9 @@ No existing installations found. Overrides: connectInject: enabled: true - controller: - enabled: true Proceed with installation? (y/N) y - + ==> Running Installation ✓ Downloaded charts --> creating 1 resource(s) @@ -260,7 +249,7 @@ The pre-install checks may fail if existing `PersistentVolumeClaims` (PVC) are d ## Check the Consul cluster status -Issue the `consul-k8s status` command to view the status of the installed Consul cluster. +Issue the `consul-k8s status` command to view the status of the installed Consul cluster. ```shell-session $ consul-k8s status @@ -268,16 +257,8 @@ $ consul-k8s status ==> Consul-K8s Status Summary NAME | NAMESPACE | STATUS | CHARTVERSION | APPVERSION | REVISION | LAST UPDATED ---------+-----------+----------+--------------+------------+----------+-------------------------- - consul | consul | deployed | 0.40.0 | 1.11.2 | 1 | 2022/01/31 16:58:51 PST - -==> Config: - connectInject: - enabled: true - controller: - enabled: true - global: - name: consul + consul | consul | deployed | 0.40.0 | 1.14.0 | 1 | 2022/01/31 16:58:51 PST ✓ Consul servers healthy (3/3) ✓ Consul clients healthy (3/3) -``` \ No newline at end of file +``` diff --git a/website/content/docs/k8s/installation/install.mdx b/website/content/docs/k8s/installation/install.mdx index 54c67c05817a..d6181101876d 100644 --- a/website/content/docs/k8s/installation/install.mdx +++ b/website/content/docs/k8s/installation/install.mdx @@ -9,28 +9,23 @@ description: >- This topic describes how to install Consul on Kubernetes using the official Consul Helm chart. For instruction on how to install Consul on Kubernetes using the Consul K8s CLI, refer to [Installing the Consul K8s CLI](/docs/k8s/installation/install-cli). - ## Introduction -We recommend using the Consul Helm chart to install Consul on Kubernetes for multi-cluster installations that involve cross-partition or cross datacenter communication. The Helm chart installs and configures all necessary components to run Consul. The configuration enables you to run a server cluster, a client cluster, or both. +We recommend using the Consul Helm chart to install Consul on Kubernetes for multi-cluster installations that involve cross-partition or cross datacenter communication. The Helm chart installs and configures all necessary components to run Consul. -Consul can run directly on Kubernetes in server or client mode so that you can leverage Consul functionality if your workloads are fully deployed to Kubernetes. For heterogeneous workloads, Consul agents can join a server running inside or outside of Kubernetes. Refer to the [architecture section](/docs/k8s/architecture) to learn more about the general architecture of Consul on Kubernetes. +Consul can run directly on Kubernetes so that you can leverage Consul functionality if your workloads are fully deployed to Kubernetes. For heterogeneous workloads, Consul agents can join a server running inside or outside of Kubernetes. Refer to the [Consul on Kubernetes architecture](/docs/k8s/architecture) to learn more about its general architecture. The Helm chart exposes several useful configurations and automatically sets up complex resources, but it does not automatically operate Consul. You must still become familiar with how to monitor, backup, and upgrade the Consul cluster. -The Helm chart has no required configuration, so it installs a Consul cluster with default configurations. We strongly recommend that you [learn about the configuration options](/docs/k8s/helm#configuration-values) prior to going to production. +The Helm chart has no required configuration, so it installs a Consul cluster with default configurations. We strongly recommend that you [learn about the configuration options](/docs/k8s/helm#configuration-values) before going to production. -> **Security warning**: By default, Helm installs Consul with security configurations disabled so that the out-of-box experience is optimized for new users. We strongly recommend using a properly-secured Kubernetes cluster or making sure that you understand and enable [Consul’s security features](/docs/security) before going into production. Some security features are not supported in the Helm chart and require additional manual configuration. -Refer to the [architecture](/docs/k8s/installation/install#architecture) section to learn more about the general architecture of Consul on Kubernetes. - -For a hands-on experience with Consul as a service mesh -for Kubernetes, follow the [Getting Started with Consul service -mesh](https://learn.hashicorp.com/tutorials/consul/service-mesh-deploy?in=consul/gs-consul-service-mesh?utm_source=docs) tutorial. +> For a hands-on experience with Consul as a service mesh for Kubernetes, follow the [Getting Started with Consul service mesh tutorial](/consul/tutorials/kubernetes-features/service-mesh-deploy?utm_source=docs). ## Requirements -- Helm version 3.2+. Visit the [Helm website](https://helm.sh/docs/intro/install/) to download the latest version. +Using the Helm Chart requires Helm version 3.6+. Visit the [Helm website](https://helm.sh/docs/intro/install/) to download the latest version. ## Install Consul @@ -46,11 +41,10 @@ mesh](https://learn.hashicorp.com/tutorials/consul/service-mesh-deploy?in=consul ```shell-session $ helm search repo hashicorp/consul NAME CHART VERSION APP VERSION DESCRIPTION - hashicorp/consul 0.39.0 1.11.1 Official HashiCorp Consul Chart + hashicorp/consul 1.0.1 1.14.1 Official HashiCorp Consul Chart ``` -1. Prior to installing via Helm, ensure that the `consul` Kubernetes namespace does not exist, as installing on a dedicated namespace - is recommended. +1. Before you install Consul on Kubernetes with Helm, ensure that the `consul` Kubernetes namespace does not exist. We recommend installing Consul on a dedicated namespace. ```shell-session $ kubectl get namespace @@ -61,46 +55,44 @@ mesh](https://learn.hashicorp.com/tutorials/consul/service-mesh-deploy?in=consul kube-system Active 18h ``` -1. Install Consul on Kubernetes using Helm. The Helm chart does everything to set up a recommended Consul-on-Kubernetes deployment. After installation, a Consul cluster will be formed, a leader will be elected, and every node will have a running Consul agent. - 1. To install the latest version of Consul on Kubernetes, issue the following command to install Consul with the default configuration using Helm. You could also install Consul on a dedicated namespace of your choosing by modifying the value of the `-n` flag for the Helm install. +1. Install Consul on Kubernetes using Helm. The Helm chart does everything to set up your deployment: after installation, agents automatically form clusters, elect leaders, and run the necessary agents. + + - Run the following command to install the latest version of Consul on Kubernetes with its default configuration. - ```shell-session - $ helm install consul hashicorp/consul --set global.name=consul --create-namespace --namespace consul - ``` + ```shell-session + $ helm install consul hashicorp/consul --set global.name=consul --create-namespace --namespace consul + ``` - 1. To install a specific version of Consul on Kubernetes, issue the following command with `--version` flag to install the specified version with the default configuration using Helm. + You can also install Consul on a dedicated namespace of your choosing by modifying the value of the `-n` flag for the Helm install. - ```shell-session - $ export VERSION=0.43.0 - $ helm install consul hashicorp/consul --set global.name=consul --version ${VERSION} --create-namespace --namespace consul - ``` + - To install a specific version of Consul on Kubernetes, issue the following command with `--version` flag: + ```shell-session + $ export VERSION=1.0.1 + $ helm install consul hashicorp/consul --set global.name=consul --version ${VERSION} --create-namespace --namespace consul + ``` ## Custom installation If you want to customize your installation, create a `values.yaml` file to override the default settings. -You can learn what settings are available by running `helm inspect values hashicorp/consul` -or by reading the [Helm Chart Reference](/docs/k8s/helm). +To learn what settings are available, run `helm inspect values hashicorp/consul` +or read the [Helm Chart Reference](/docs/k8s/helm). ### Minimal `values.yaml` for Consul service mesh -The minimal settings to enable [Consul Service Mesh]((/docs/k8s/connect)) would be captured in the following `values.yaml` config file: +The following `values.yaml` config file contains the minimum required settings to enable [Consul Service Mesh](/consul/docs/k8s/connect): ```yaml global: name: consul -connectInject: - enabled: true -controller: - enabled: true -``` + ``` -Once you've created your `values.yaml` file, run `helm install` with the `--values` flag: +After you create your `values.yaml` file, run `helm install` with the `--values` flag: ```shell-session $ helm install consul hashicorp/consul --create-namespace --namespace consul --values values.yaml @@ -120,108 +112,119 @@ Because the plugin is executed by the local Kubernetes kubelet, the plugin alrea The Consul Helm Chart is responsible for installing the Consul CNI plugin. To configure the plugin to be installed, add the following configuration to your `values.yaml` file: - + + + -```yaml -global: - name: consul -connectInject: - enabled: true - cni: + ```yaml + global: + name: consul + connectInject: enabled: true - logLevel: info - cniBinDir: "/opt/cni/bin" - cniNetDir: "/etc/cni/net.d" + cni: + enabled: true + logLevel: info + cniBinDir: "/opt/cni/bin" + cniNetDir: "/etc/cni/net.d" ``` + + + + -```yaml -global: - name: consul -connectInject: - enabled: true - cni: + ```yaml + global: + name: consul + connectInject: enabled: true - logLevel: info - cniBinDir: "/home/kubernetes/bin" - cniNetDir: "/etc/cni/net.d" + cni: + enabled: true + logLevel: info + cniBinDir: "/home/kubernetes/bin" + cniNetDir: "/etc/cni/net.d" ``` + + + + -```yaml -global: - name: consul - openshift: - enabled: true -connectInject: - enabled: true - cni: + ```yaml + global: + name: consul + openshift: + enabled: true + connectInject: enabled: true - logLevel: info - multus: true - cniBinDir: "/var/lib/cni/bin" - cniNetDir: "/etc/kubernetes/cni/net.d" + cni: + enabled: true + logLevel: info + multus: true + cniBinDir: "/var/lib/cni/bin" + cniNetDir: "/etc/kubernetes/cni/net.d" ``` + - - + The following table describes the available CNI plugin options: -| Option | Description | Default | -| --- | --- | --- | +| Option | Description | Default | +| ---------- | ----------- | ------------- | | `cni.enabled` | Boolean value that enables or disables the CNI plugin. If `true`, the plugin is responsible for redirecting traffic in the service mesh. If `false`, redirection is handled by the `connect-inject init` container. | `false` | | `cni.logLevel` | String value that specifies the log level for the installer and plugin. You can specify the following values: `info`, `debug`, `error`. | `info` | +| `cni.namespace` | Set the namespace to install the CNI plugin into. Overrides global namespace settings for CNI resources, for example `kube-system` | namespace used for `consul-k8s` install, for example `consul` | | `cni.multus` | Boolean value that enables multus CNI plugin support. If `true`, multus will be enabled. If `false`, Consul CNI will operate as a chained plugin. | `false` | | `cni.cniBinDir` | String value that specifies the location on the Kubernetes node where the CNI plugin is installed. | `/opt/cni/bin` | | `cni.cniNetDir` | String value that specifies the location on the Kubernetes node for storing the CNI configuration. | `/etc/cni/net.d` | ### Enable Consul service mesh on select namespaces -By default, Consul Service Mesh is enabled on almost all namespaces (with the exception of `kube-system` and `local-path-storage`) within a Kubernetes cluster. You can restrict this to a subset of namespaces by specifying a `namespaceSelector` that matches a label attached to each namespace denoting whether to enable Consul service mesh. In order to default to enabling service mesh on select namespaces by label, the `connectInject.default` value must be set to `true`. +By default, Consul Service Mesh is enabled on almost all namespaces within a Kubernetes cluster, with the exception of `kube-system` and `local-path-storage`. To restrict the service mesh to a subset of namespaces: + +1. specify a `namespaceSelector` that matches a label attached to each namespace where you want to deploy the service mesh. In order to default to enabling service mesh on select namespaces by label, the `connectInject.default` value must be set to `true`. -```yaml -global: - name: consul -connectInject: - enabled: true - default: true - namespaceSelector: | - matchLabels: - connect-inject : enabled -controller: - enabled: true + ```yaml + global: + name: consul + connectInject: + enabled: true + default: true + namespaceSelector: | + matchLabels: + connect-inject : enabled ``` -Label the namespace(s), where you would like to enable Consul Service Mesh. +1. Label the namespaces where you would like to enable Consul Service Mesh. -```shell-session -$ kubectl create ns foo -$ kubectl label namespace foo connect-inject=enabled -``` + ```shell-session + $ kubectl create ns foo + $ kubectl label namespace foo connect-inject=enabled + ``` -Next, run `helm install` with the `--values` flag: +1. Run `helm install` with the `--values` flag: -```shell-session -$ helm install consul hashicorp/consul --create-namespace --namespace consul --values values.yaml -NAME: consul -``` + ```shell-session + $ helm install consul hashicorp/consul --create-namespace --namespace consul --values values.yaml + NAME: consul + ``` ### Update your Consul on Kubernetes configuration -If you've already installed Consul and want to make changes, you'll need to run -`helm upgrade`. See [Upgrading](/docs/k8s/upgrade) for more details. +If you already installed Consul and want to make changes, you need to run +`helm upgrade`. Refer to [Upgrading](/docs/k8s/upgrade) for more details. ## Usage @@ -230,38 +233,38 @@ You can view the Consul UI and access the Consul HTTP API after installation. ### Viewing the Consul UI The Consul UI is enabled by default when using the Helm chart. -For security reasons, it isn't exposed via a `LoadBalancer` Service by default so you must -use `kubectl port-forward` to visit the UI. -#### TLS Disabled +For security reasons, it is not exposed through a `LoadBalancer` service by default. To visit the UI, you must +use `kubectl port-forward`. + +#### Port forward with TLS disabled -If running with TLS disabled, the Consul UI will be accessible via http on port 8500: +If running with TLS disabled, the Consul UI is accessible through http on port 8500: ```shell-session $ kubectl port-forward service/consul-server --namespace consul 8500:8500 ... ``` -Once the port is forwarded navigate to [http://localhost:8500](http://localhost:8500). +After you set up the port forward, navigate to [http://localhost:8500](http://localhost:8500). -#### TLS Enabled +#### Port forward with TLS enabled -If running with TLS enabled, the Consul UI will be accessible via https on port 8501: +If running with TLS enabled, the Consul UI is accessible through https on port 8501: ```shell-session $ kubectl port-forward service/consul-server --namespace consul 8501:8501 ... ``` -Once the port is forwarded navigate to [https://localhost:8501](https://localhost:8501). +After you set up the port forward, navigate to [https://localhost:8501](https://localhost:8501). -~> You'll need to click through an SSL warning from your browser because the +~> You need to click through an SSL warning from your browser because the Consul certificate authority is self-signed and not in the browser's trust store. #### ACLs Enabled -If ACLs are enabled, you will need to input an ACL token into the UI in order -to see all resources and make modifications. +If ACLs are enabled, you need to input an ACL token to display all resources and make modifications in the UI. To retrieve the bootstrap token that has full permissions, run: @@ -276,25 +279,18 @@ Then paste the token into the UI under the ACLs tab (without the `%`). to retrieve the bootstrap token since secondary datacenters use a separate token with less permissions. -#### Exposing the UI via a service +#### Exposing the UI through a service If you want to expose the UI via a Kubernetes Service, configure the [`ui.service` chart values](/docs/k8s/helm#v-ui-service). -This service will allow requests to the Consul servers so it should +Because this service allows requests to the Consul servers, it should not be open to the world. ### Accessing the Consul HTTP API -The Consul HTTP API should be accessed by communicating to the local agent -running on the same node. While technically any listening agent (client or -server) can respond to the HTTP API, communicating with the local agent -has important caching behavior, and allows you to use the simpler -[`/agent` endpoints for services and checks](/api-docs/agent). +While technically any listening agent can respond to the HTTP API, communicating with the local Consul node has important caching behavior and allows you to use the simpler [`/agent` endpoints for services and checks](/api-docs/agent). -For Consul installed via the Helm chart, a client agent is installed on -each Kubernetes node. This is explained in the [architecture](/docs/k8s/installation/install#client-agents) -section. To access the agent, you may use the -[downward API](https://kubernetes.io/docs/tasks/inject-data-application/downward-api-volume-expose-pod-information/). +To find information about a node, you can use the [downward API](https://kubernetes.io/docs/tasks/inject-data-application/downward-api-volume-expose-pod-information/). An example pod specification is shown below. In addition to pods, anything with a pod template can also access the downward API and can therefore also @@ -308,7 +304,7 @@ metadata: spec: containers: - name: example - image: 'consul:latest' + image: 'hashicorp/consul:latest' env: - name: HOST_IP valueFrom: @@ -345,7 +341,7 @@ spec: spec: containers: - name: example - image: 'consul:latest' + image: 'hashicorp/consul:latest' env: - name: HOST_IP valueFrom: diff --git a/website/content/docs/k8s/k8s-cli.mdx b/website/content/docs/k8s/k8s-cli.mdx index 3b3c65959ec1..2e96017bd877 100644 --- a/website/content/docs/k8s/k8s-cli.mdx +++ b/website/content/docs/k8s/k8s-cli.mdx @@ -472,8 +472,6 @@ $ consul-k8s status defaultEnableMerging: true defaultEnabled: true enableGatewayMetrics: true - controller: - enabled: true global: metrics: enableAgentMetrics: true diff --git a/website/content/docs/k8s/operations/tls-on-existing-cluster.mdx b/website/content/docs/k8s/operations/tls-on-existing-cluster.mdx index ad43186c0361..96c20e27dbf8 100644 --- a/website/content/docs/k8s/operations/tls-on-existing-cluster.mdx +++ b/website/content/docs/k8s/operations/tls-on-existing-cluster.mdx @@ -15,7 +15,7 @@ However, depending on your Kubernetes use case, your upgrade procedure may be di ## Gradual TLS Rollout without Consul Connect -If you're **not using Consul Connect**, follow this process. +If you do not use a service mesh, follow this process. 1. Run a Helm upgrade with the following config: @@ -31,8 +31,7 @@ If you're **not using Consul Connect**, follow this process. updatePartition: ``` -This upgrade will trigger a rolling update of the clients, as well as any -other `consul-k8s` components, such as sync catalog or client snapshot deployments. + This upgrade trigger a rolling update of `consul-k8s` components. 1. Perform a rolling upgrade of the servers, as described in [Upgrade Consul Servers](/docs/k8s/upgrade#upgrading-consul-servers). @@ -50,9 +49,9 @@ applications to it. 1. Add a new identical node pool. -1. Cordon all nodes in the **old** pool by running `kubectl cordon` - to ensure Kubernetes doesn't schedule any new workloads on those nodes - and instead schedules onto the new nodes, which shortly will be TLS-enabled. +1. Cordon all nodes in the old pool by running `kubectl cordon`. + This command ensures Kubernetes does not schedule any new workloads on those nodes, + and instead schedules onto the new TLS-enabled nodes. 1. Create the following Helm config file for the upgrade: @@ -72,26 +71,16 @@ applications to it. ``` In this configuration, we're setting `server.updatePartition` to the number of - server replicas as described in [Upgrade Consul Servers](/docs/k8s/upgrade#upgrading-consul-servers) - and `client.updateStrategy` to `OnDelete` to manually trigger an upgrade of the clients. + server replicas as described in [Upgrade Consul Servers](/docs/k8s/upgrade#upgrading-consul-servers). -1. Run `helm upgrade` with the above config file. The upgrade will trigger an update of all - components except clients and servers, such as the Consul Connect webhook deployment - or the sync catalog deployment. Note that the sync catalog and the client - snapshot deployments will not be in the `ready` state until the clients on their - nodes are upgraded. It is OK to proceed to the next step without them being ready - because Kubernetes will keep the old deployment pod around, and so there will be no - downtime. - -1. Gradually perform an upgrade of the clients by deleting client pods on the **new** node - pool. +1. Run `helm upgrade` with the above config file. 1. At this point, all components (e.g., Consul Connect webhook and sync catalog) should be running on the new node pool. 1. Redeploy all your Connect-enabled applications. One way to trigger a redeploy is to run `kubectl drain` on the nodes in the old pool. - Now that the Connect webhook is TLS-aware, it will add TLS configuration to + Now that the Connect webhook is TLS-aware, it adds TLS configuration to the sidecar proxy. Also, Kubernetes should schedule these applications on the new node pool. 1. Perform a rolling upgrade of the servers described in diff --git a/website/content/docs/k8s/service-sync.mdx b/website/content/docs/k8s/service-sync.mdx index 577aaccff88f..56ad75b0b5ee 100644 --- a/website/content/docs/k8s/service-sync.mdx +++ b/website/content/docs/k8s/service-sync.mdx @@ -12,7 +12,7 @@ services are available to Consul agents and services in Consul can be available as first-class Kubernetes services. This functionality is provided by the [consul-k8s project](https://github.com/hashicorp/consul-k8s) and can be automatically installed and configured using the -[Consul Helm chart](/docs/k8s/installation/install). +[Consul K8s Helm chart](/consul/docs/k8s/installation/install). ![screenshot of a Kubernetes service in the UI](/img/k8s-service.png) @@ -20,23 +20,18 @@ automatically installed and configured using the Consul catalog enable Kubernetes services to be accessed by any node that is part of the Consul cluster, including other distinct Kubernetes clusters. For non-Kubernetes nodes, they can access services using the standard -[Consul DNS](/docs/discovery/dns) or HTTP API. +[Consul DNS](/consul/docs/services/discovery/dns-overview) or HTTP API. **Why sync Consul services to Kubernetes?** Syncing Consul services to -Kubernetes services enables non-Kubernetes services (such as external to -the cluster) to be accessed in a native Kubernetes way: using kube-dns, -environment variables, etc. This makes it very easy to automate external +Kubernetes services enables non-Kubernetes services to be accessed using kube-dns and Kubernetes-specific +environment variables. This integration makes it very easy to automate external service discovery, including hosted services like databases. -## Installation and Configuration +## Installation and configuration -~> Enabling both Service Mesh and Service Sync on the same Kubernetes services is not supported, as Service Mesh also registers Kubernetes service instances to Consul. Please ensure that Service Sync is only enabled for namespaces and services that are not injected with the Consul sidecar for Service Mesh as described in [Sync Enable/Disable](/docs/k8s/service-sync#sync-enable-disable). +~> Enabling both Service Mesh and Service Sync on the same Kubernetes services is not supported, as Service Mesh also registers Kubernetes service instances to Consul. Ensure that Service Sync is only enabled for namespaces and services that are not injected with the Consul sidecar for Service Mesh as described in [Sync Enable/Disable](/docs/k8s/service-sync#sync-enable-disable). -The service sync is done using an external long-running process in the -[consul-k8s project](https://github.com/hashicorp/consul-k8s). This process -can run either in or out of a Kubernetes cluster. However, running this within -the Kubernetes cluster is generally easier since it is automated using the -[Helm chart](/docs/k8s/helm). +The service sync feature deploys a long-running process which can run either inside or outside of a Kubernetes cluster. However, running this process within the Kubernetes cluster is generally easier since it is automated using the [Helm chart](/consul/docs/k8s/helm). The Consul server cluster can run either in or out of a Kubernetes cluster. The Consul server cluster does not need to be running on the same machine @@ -54,8 +49,7 @@ syncCatalog: enabled: true ``` -This will enable services to sync _in both directions_. You can also choose -to only sync Kubernetes services to Consul or vice versa by disabling a direction. +This value enables service syncing in both direction. You can also disable a direction so that only Kubernetes services sync to Consul, or only Consul services sync to Kubernetes. To only enable syncing Consul services to Kubernetes use the config: @@ -75,7 +69,7 @@ syncCatalog: toK8S: false ``` -See the [Helm configuration](/docs/k8s/helm#v-synccatalog) +Refer to the [Helm configuration](/docs/k8s/helm#v-synccatalog) for more information. ### Authentication @@ -83,16 +77,15 @@ for more information. The sync process must authenticate to both Kubernetes and Consul to read and write services. -If running `consul-k8s` using the Helm chart then this authentication is handled for you. +If running `consul-k8s` using the Helm chart, then this authentication is handled for you. If running `consul-k8s` outside of Kubernetes, a valid kubeconfig file must be provided with cluster -and authentication information. The sync process will look into the default locations +and authentication information. The sync process looks into the default locations for both in-cluster and out-of-cluster authentication. If `kubectl` works, then the sync program should work. -For Consul, if ACLs are configured on the cluster, a Consul -[ACL token](https://learn.hashicorp.com/tutorials/consul/access-control-setup-production) -will need to be provided. Review the [ACL rules](/docs/security/acl/acl-rules) +If ACLs are configured on the Consul cluster, you need to provide a Consul +[ACL token](/consul/tutorials/security/access-control-setup-production). Review the [ACL rules](/docs/security/acl/acl-rules) when creating this token so that it only allows the necessary privileges. The catalog sync process accepts this token by using the [`CONSUL_HTTP_TOKEN`](/commands#consul_http_token) environment variable. This token should be set as a @@ -103,22 +96,21 @@ and referenced in the Helm chart. This sync registers Kubernetes services to the Consul catalog automatically. -This enables discovery and connection to Kubernetes services using native -Consul service discovery such as DNS or HTTP. This is particularly useful for +This sync enables discovery and connection to Kubernetes services using native +Consul service discovery protocols such as DNS or HTTP. This is particularly useful for non-Kubernetes nodes. This also causes all discoverable services to be part of a central service catalog in Consul for further syncing into alternate Kubernetes clusters or other platforms. -Each synced service will be registered onto a Consul node called `k8s-sync`. This -is not a real node because there is no Consul client registering and monitoring -the services. Instead, the catalog sync process is monitoring Kubernetes +Each synced service is registered onto a Consul node called `k8s-sync`. This node +is not a real node. Instead, the catalog sync process is monitoring Kubernetes and syncing the services to Consul. -### Kubernetes Service Types +### Kubernetes service types Not all Kubernetes services are externally accessible. The sync program by -default will only sync services of the following types or configurations. -If a service type is not listed below, then the sync program will ignore that +default only syncs services of the following types or configurations. +If a service type is not listed below, then the sync program ignores that service type. #### NodePort @@ -126,59 +118,60 @@ service type. [NodePort services](https://kubernetes.io/docs/concepts/services-networking/service/#nodeport) register a static port that every node in the K8S cluster listens on. -For NodePort services, a Consul service instance will be created for each +For NodePort services, a Consul service instance is created for each node that has the representative pod running. While Kubernetes configures a static port on all nodes in the cluster, this limits the number of service instances to be equal to the nodes running the target pods. -By default it will use the external IP of the node but this can be configured via +By default it uses the external IP of the node but this can be configured through the [`nodePortSyncType` helm option](/docs/k8s/helm#v-synccatalog-nodeportsynctype). -The service instance's port will be set to the _first_ defined node port of the service unless -set specifically via the `consul.hashicorp.com/service-port` annotation (see [Service Ports](/docs/k8s/service-sync#service-ports)). +The service instance's port is set to the first defined node port of the service unless +set specifically in the `consul.hashicorp.com/service-port` annotation. Refer to [Service Ports](/docs/k8s/service-sync#service-ports) for more information. #### LoadBalancer -For LoadBalancer services, a single service instance will be registered with +For LoadBalancer services, a single service instance is registered with the external IP of the created load balancer. Because this is already a load -balancer, only one service instance will be registered with Consul rather +balancer, only one service instance is registered with Consul rather than registering each individual pod endpoint. -The service instance's port will be set to the _first_ defined port of the -service unless set specifically via the `consul.hashicorp.com/service-port` annotation (see [Service Ports](/docs/k8s/service-sync#service-ports)). +The service instance's port is set to the first defined port of the +service unless set specifically in the `consul.hashicorp.com/service-port` annotation. Refer to [Service Ports](/docs/k8s/service-sync#service-ports) for more information. #### External IPs Any service type may specify an "[external IP](https://kubernetes.io/docs/concepts/services-networking/service/#external-ips)" configuration. The external IP must be configured by some other system, but -any service discovery will resolve to this set of IP addresses rather than a +any service discovery resolves to this set of IP addresses rather than a virtual IP. -If an external IP list is present, a service instance in Consul will be created +If an external IP list is present, a service instance in Consul is created for each external IP. It is assumed that if an external IP is present that it is routable and configured by some other system. -The service instance's port will be set to the _first_ defined port of the -service unless set specifically via the `consul.hashicorp.com/service-port` annotation (see [Service Ports](/docs/k8s/service-sync#service-ports)). +The service instance's port is set to the _first_ defined port of the +service unless set specifically with the `consul.hashicorp.com/service-port` annotation. Refer to [Service Ports](/docs/k8s/service-sync#service-ports) for more information. #### ClusterIP ClusterIP services are synced by default as of `consul-k8s` version 0.3.0. -Each pod that is an endpoint for the service will be synced as a Consul service +Each pod that is an endpoint for the service is synced as a Consul service instance with its IP set to the pod IP and its port set to the `targetPort`. -The service instance's port can be overridden via the `consul.hashicorp.com/service-port` annotation (see [Service Ports](/docs/k8s/service-sync#service-ports)). +The service instance's port can be overridden with the `consul.hashicorp.com/service-port` annotation. Refer to [Service Ports](/docs/k8s/service-sync#service-ports) for more information. -> In Kubernetes clusters where pod IPs are not accessible outside the cluster, the services registered in Consul may not be routable. To skip syncing ClusterIP services, set [`syncClusterIPServices`](/docs/k8s/helm#v-synccatalog-syncclusteripservices) to `false` in the Helm chart values file. -### Sync Enable/Disable +### Enable and disable sync -By default, all valid service types (as explained above) are synced from every Kubernetes -namespace (except for `kube-system` and `kube-public`). -If you wish to only sync specific services via annotation, set the default to `false`: +By default, all valid service types are synced from every Kubernetes +namespace except for `kube-system` and `kube-public`. + +To only sync specific services, first modify the annotation to set the default to `false`: ```yaml syncCatalog: @@ -186,7 +179,7 @@ syncCatalog: default: false ``` -And explicitly enable syncing specific services via the `consul.hashicorp.com/service-sync` annotation: +Then, explicitly enable syncing specific services with the `consul.hashicorp.com/service-sync` annotation: ```yaml kind: Service @@ -197,7 +190,7 @@ metadata: 'consul.hashicorp.com/service-sync': 'true' ``` --> **NOTE:** If the annotation is set to `false` when the default sync is `true`, the service will **not** be synced. +-> **Note:** If the annotation is set to `false` when the default sync is `true`, the service does not sync. You can allow or deny syncing from specific Kubernetes namespaces by setting the `k8sAllowNamespaces` and `k8sDenyNamespaces` keys: @@ -210,10 +203,10 @@ syncCatalog: k8sDenyNamespaces: ['kube-system', 'kube-public'] ``` -In the default configuration (shown above), services from all namespaces except for -`kube-system` and `kube-public` will be synced. +In the default configuration, services from all namespaces except for +`kube-system` and `kube-public` are synced. -If you wish to only sync from specific namespaces, you can list only those +To only sync from specific namespaces, you can list only those namespaces in the `k8sAllowNamespaces` key: ```yaml @@ -224,8 +217,7 @@ syncCatalog: k8sDenyNamespaces: [] ``` -If you wish to sync from every namespace _except_ specific namespaces, you can -use `*` in the allow list and then specify the non-syncing namespaces in the deny list: +To sync from every namespace except specific namespaces, use `*` in the allow list and then specify the non-syncing namespaces in the deny list: ```yaml syncCatalog: @@ -235,15 +227,15 @@ syncCatalog: k8sDenyNamespaces: ['no-sync-ns-1', 'no-sync-ns-2'] ``` --> **NOTE:** The deny list takes precedence over the allow list. If a namespace -is listed in both lists, it will **not** be synced. +-> **Note:** The deny list takes precedence over the allow list. If a namespace +is listed in both lists, it does not sync. -### Service Name +### Service name When a Kubernetes service is synced to Consul, the name of the service in Consul -by default will be the value of the "name" metadata on that Kubernetes service. +by default is the value of the `name` metadata on that Kubernetes service. This makes it so that service sync works with zero configuration changes. -This can be overridden using an annotation to specify the Consul service name: +This setting can be overridden using an annotation to specify the Consul service name: ```yaml kind: Service @@ -254,17 +246,15 @@ metadata: 'consul.hashicorp.com/service-name': my-consul-service ``` -**If a conflicting service name exists in Consul,** the sync program will -register additional instances to that same service. Therefore, services inside +**If a conflicting service name exists in Consul,** the sync program +registers additional instances to that same service. Therefore, services inside and outside of Kubernetes should have different names unless you want either side to potentially connect. This default behavior also enables gracefully -transitioning a service from outside of K8S to inside, and vice versa. +transitioning a service between deployments inside and outside of Kubernetes. -### Service Ports +### Service ports -When syncing the Kubernetes service to Consul, the Consul service port will be -the first defined port in the service. Additionally, all ports will be -registered in the service instance metadata with the key "port-X" where X is +When syncing the Kubernetes service to Consul, the Consul service port is the first defined port in the service. Additionally, all ports become registered in the service instance metadata with the key "port-X," where X is the name of the port and the value is the externally accessible port. The default service port can be overridden using an annotation: @@ -280,13 +270,10 @@ metadata: The annotation value may be a name of a port (recommended) or an exact port value. -### Service Tags +### Service tags -A service registered in Consul from Kubernetes will always have the tag "k8s" added -to it. Additional tags can be specified with a comma-separated annotation value -as shown below. This will also automatically include the "k8s" tag which can't -be disabled. The values should be specified comma-separated without any -additional whitespace. +A service registered in Consul from Kubernetes always has the tag "k8s" added +to it. Additional tags can be specified with a comma-separated annotation value. These custom tags automatically include the "k8s" tag, which can't be disabled. When specifying values, use commas without whitespace. ```yaml kind: Service @@ -297,16 +284,15 @@ metadata: 'consul.hashicorp.com/service-tags': 'primary,foo' ``` -### Service Meta +### Service meta -A service registered in Consul from Kubernetes will set the `external-source` key to -"kubernetes". This can be used by API consumers, the UI, CLI, etc. to filter -service instances that are set in k8s. The Consul UI (in Consul 1.2.3 and later) -will read this value to show a Kubernetes icon next to all externally +A service registered in Consul from Kubernetes sets the `external-source` key to +`kubernetes`. This can be used from the APLI, CLI and UI to filter +service instances that are set in k8s. The Consul UI displays a Kubernetes icon next to all externally registered services from Kubernetes. Additional metadata can be specified using annotations. The "KEY" below can be -set to any key. This allows setting multiple meta values: +set to any key. This allows setting multiple meta values. ```yaml kind: Service @@ -320,15 +306,13 @@ metadata: ### Consul Enterprise Namespaces Consul Enterprise supports Consul namespaces. These can be used when syncing -from Kubernetes to Consul (although not vice-versa). +from Kubernetes to Consul. However, namespaces are not supported when syncing from Consul to Kubernetes. There are three options available: 1. **Single Destination Namespace** – Sync all Kubernetes services, regardless of namespace, into the same Consul namespace. - This can be configured with: - ```yaml global: enableConsulNamespaces: true @@ -339,13 +323,11 @@ There are three options available: consulDestinationNamespace: 'my-consul-ns' ``` -1. **Mirror Namespaces** - Each Kubernetes service will be synced to a Consul namespace with the same +1. **Mirror Namespaces** - Each Kubernetes service is synced to a Consul namespace with the same name as its Kubernetes namespace. - For example, service `foo` in Kubernetes namespace `ns-1` will be synced to the Consul namespace `ns-1`. - If a mirrored namespace does not exist in Consul, it will be created. - - This can be configured with: + For example, service `foo` in Kubernetes namespace `ns-1` is synced to the Consul namespace `ns-1`. + If a mirrored namespace does not exist in Consul, it is created automatically. ```yaml global: @@ -359,13 +341,11 @@ There are three options available: addK8SNamespaceSuffix: false ``` -1. **Mirror Namespaces With Prefix** - Each Kubernetes service will be synced to a Consul namespace - with the same name as its Kubernetes namespace **with a prefix**. For example, given a prefix - `k8s-`, service `foo` in Kubernetes namespace `ns-1` will be synced to the Consul namespace +1. **Mirror Namespaces With Prefix** - Each Kubernetes service is synced to a Consul namespace + with the same name as its Kubernetes namespace with a prefix. For example, given a prefix + `k8s-`, service `foo` in Kubernetes namespace `ns-1` syncs to the Consul namespace `k8s-ns-1`. - This can be configured with: - ```yaml global: enableConsulNamespaces: true @@ -379,24 +359,20 @@ There are three options available: addK8SNamespaceSuffix: false ``` --> Note that in both mirroring examples we're setting `addK8SNamespaceSuffix: false`. If set to `true` -(the default), the Kubernetes namespace will be added as a suffix to each +-> Note that in both mirroring examples, `addK8SNamespaceSuffix` is set to `false`. If set to its default value, `true`, the Kubernetes namespace is added as a suffix to each Consul service name. For example Kubernetes service `foo` in namespace `k8s-ns` would be registered into Consul with the name `foo-k8s-ns`. This is useful when syncing from multiple Kubernetes namespaces to -a single consul namespace but is likely something you'll want turned off -when mirroring namespaces since services won't overlap with services from +a single Consul namespace. However, you may want to disable this behavior +when mirroring namespaces so that services do not overlap with services from other namespaces. ## Consul to Kubernetes This syncs Consul services into first-class Kubernetes services. -The sync service will create an [`ExternalName`](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) -`Service` for each Consul service. The "external name" will be -the Consul DNS name. +The sync creates an [`ExternalName`](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) for each Consul service. The "external name" is the Consul DNS name. -For example, given a Consul service `foo`, a Kubernetes Service will be created -as follows: +For example, given a Consul service `foo`: ```yaml apiVersion: v1 @@ -410,22 +386,22 @@ spec: ``` With Consul To Kubernetes syncing enabled, DNS requests of the form `` -will be serviced by Consul DNS. From a different Kubernetes namespace than where Consul +are serviced by Consul DNS. From a different Kubernetes namespace than where Consul is deployed, the DNS request would need to be `.`. --> **Note:** Consul to Kubernetes syncing **isn't required** if you've enabled [Consul DNS on Kubernetes](/docs/k8s/dns) -_and_ all you need to do is address services in the form `.service.consul`, i.e. you don't need Kubernetes `Service` objects created. +-> **Note:** Consul to Kubernetes syncing is not required if you enabled [Consul DNS on Kubernetes](/docs/k8s/dns). +All you need to do is address services in the form `.service.consul`, so you do not need Kubernetes `Service` objects created. ~> **Requires Consul DNS via CoreDNS in Kubernetes:** This feature requires that [Consul DNS](/docs/k8s/dns) is configured within Kubernetes. -Additionally, **[CoreDNS](https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/#config-coredns) -is required (instead of kube-dns)** to resolve an +Additionally, [CoreDNS](https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/#config-coredns) +is required instead of kube-dns to resolve an issue with resolving `externalName` services pointing to custom domains. -### Sync Enable/Disable +### Enable and disable sync All Consul services visible to the sync process based on its given ACL token -will be synced to Kubernetes. +are synced to Kubernetes. There is no way to change this behavior per service. For the opposite sync direction (Kubernetes to Consul), you can use Kubernetes annotations to disable @@ -437,24 +413,24 @@ In the future, we hope to support per-service configuration. ### Service Name When a Consul service is synced to Kubernetes, the name of the Kubernetes -service will exactly match the name of the Consul service. +service matches the name of the Consul service exactly. To change this default exact match behavior, it is possible to specify a prefix to be added to service names within Kubernetes by using the `-k8s-service-prefix` flag. This can also be specified in the Helm configuration. -**If a conflicting service is found,** the service will not be synced. This +**If a conflicting service is found**: the service is not synced. This does not match the Kubernetes to Consul behavior, but given the current -implementation we must do this because Kubernetes can't mix both CNAME and +implementation we must do this because Kubernetes cannott mix both CNAME and Endpoint-based services. -### Kubernetes Service Labels and Annotations +### Kubernetes service labels and annotations -Any Consul services synced to Kubernetes will be labeled and annotated. -An annotation `consul.hashicorp.com/synced` will be set to "true" to note +Any Consul services synced to Kubernetes are labeled and annotated. +An annotation `consul.hashicorp.com/synced` is set to `true` to note that this is a synced service from Consul. -Additionally, a label `consul=true` will be specified so that label selectors +Additionally, a label `consul=true` is specified so that label selectors can be used with `kubectl` and other tooling to easily filter all Consul-synced services. diff --git a/website/content/docs/k8s/upgrade/index.mdx b/website/content/docs/k8s/upgrade/index.mdx index 0e41d2cf7c76..f944efc668d2 100644 --- a/website/content/docs/k8s/upgrade/index.mdx +++ b/website/content/docs/k8s/upgrade/index.mdx @@ -5,42 +5,30 @@ description: >- Consul on Kubernetes relies on packages and binaries that have individual upgrade requirements. Learn how to update Helm configurations, Helm versions, Consul versions, and Consul agents, as well as how to determine what will change and its impact on your service mesh. --- -# Upgrading Consul on Kubernetes Components +# Upgrading Consul on Kubernetes components -## Upgrade Types +This topic describes considerations and strategies for upgrading Consul deployments running on Kubernetes clusters. In addition to upgrading the version of Consul, you may need to update your Helm chart or the release version of the Helm chart. -Consul on Kubernetes will need to be upgraded/updated if you change your Helm configuration, -if a new Helm chart is released, or if you wish to upgrade your Consul version. +## Version-specific upgrade requirements -### Helm Configuration Changes +As of Consul v1.14.0, Kubernetes deployments use [Consul Dataplane](/consul/docs/connect/dataplane) instead of client agents. If you upgrade Consul from a version that uses client agents to a version that uses dataplanes, you must follow specific steps to update your Helm chart and remove client agents from the existing deployment. Refer to [Upgrading to Consul Dataplane](/consul/docs/k8s/upgrade#upgrading-to-consul-dataplane) for more information. -If you make a change to your Helm values file, you will need to perform a `helm upgrade` -for those changes to take effect. - -For example, if you've installed Consul with the following: +The v1.0.0 release of the Consul on Kubernetes Helm chart also introduced a change to the [`externalServers[].hosts` parameter](/consul/docs/k8s/helm#v-externalservers-hosts). Previously, you were able to enter a provider lookup as a string in this field. Now, you must include `exec=` at the start of a string containing a provider lookup. Otherwise, the string is treated as a DNS name. Refer to the [`go-netaddrs` library and command line tool](https://github.com/hashicorp/go-netaddrs) for more information. - +## Upgrade types -```yaml -global: - name: consul -connectInject: - enabled: false -``` +We recommend updating Consul on Kubernetes when: - + - You change your Helm configuration + - A new Helm chart is released + - You want to upgrade your Consul version -And you wish to set `connectInject.enabled` to `true`: +### Helm configuration changes -```diff -global: - name: consul -connectInject: -- enabled: false -+ enabled: true -``` +If you make a change to your Helm values file, you need to perform a `helm upgrade` +for those changes to take effect. -To update your deployment configuration using Helm, perform the following steps. +For example, if you installed Consul with `connectInject.enabled: false` and you want to change its value to `true`: 1. Determine your current installed chart version. @@ -58,17 +46,15 @@ To update your deployment configuration using Helm, perform the following steps. $ helm upgrade consul hashicorp/consul --namespace consul --version 0.40.0 --values /path/to/my/values.yaml ``` - **Before performing the upgrade, be sure you've read the other sections on this page, + **Before performing the upgrade, be sure you read the other sections on this page, continuing at [Determining What Will Change](#determining-what-will-change).** -~> NOTE: It's important to always set the `--version` flag, because otherwise Helm -will use the most up-to-date version in its local cache, which may result in an -unintended upgrade. +~> Note: You should always set the `--version` flag when upgrading Helm. Otherwise Helm uses the most up-to-date version in its local cache, which may result in an unintended upgrade. -### Helm Chart Version Upgrade +### Upgrade Helm chart version -You may wish to upgrade your Helm chart version to take advantage of new features, -bugfixes, or because you want to upgrade your Consul version, and it requires a +You may wish to upgrade your Helm chart version to take advantage of new features and +bug fixes, or because you want to upgrade your Consul version and it requires a certain Helm chart version. 1. Update your local Helm repository cache: @@ -98,7 +84,8 @@ certain Helm chart version. ``` In this example, version `0.39.0` (from `consul-k8s:0.39.0`) is being used. - If you want to upgrade to the latest `0.40.0` version, use the following procedure: + +If you want to upgrade to the latest `0.40.0` version, use the following procedure: 1. Check the changelog for any breaking changes from that version and any versions in between: [CHANGELOG.md](https://github.com/hashicorp/consul-k8s/blob/main/CHANGELOG.md). @@ -111,14 +98,14 @@ certain Helm chart version. **Before performing the upgrade, be sure you've read the other sections on this page, continuing at [Determining What Will Change](#determining-what-will-change).** -### Consul Version Upgrade +### Upgrade Consul version -If a new version of Consul is released, you will need to perform a Helm upgrade -to update to the new version. +If a new version of Consul is released, you need to perform a Helm upgrade +to update to the new version. Before you upgrade to a new version: -1. Ensure you've read the [Upgrading Consul](/docs/upgrading) documentation. -1. Ensure you've read any [specific instructions](/docs/upgrading/upgrade-specific) for the version you're upgrading - to and the Consul [changelog](https://github.com/hashicorp/consul/blob/main/CHANGELOG.md) for that version. +1. Read the [Upgrading Consul](/docs/upgrading) documentation. +1. Read any [specific instructions](/docs/upgrading/upgrade-specific) for the version you want to upgrade + to, as well as the Consul [changelog](https://github.com/hashicorp/consul/blob/main/CHANGELOG.md) for that version. 1. Read our [Compatibility Matrix](/docs/k8s/compatibility) to ensure your current Helm chart version supports this Consul version. If it does not, you may need to also upgrade your Helm chart version at the same time. @@ -133,7 +120,7 @@ to update to the new version. -1. Determine your current installed chart version. In this example, version `0.39.0` (from `consul-k8s:0.39.0`) is being used. +2. Determine the version of your exisiting Helm installation. In this example, version `0.39.0` (from `consul-k8s:0.39.0`) is being used. ```shell-session $ helm list --filter consul --namespace consul @@ -150,18 +137,16 @@ to update to the new version. **Before performing the upgrade, be sure you have read the other sections on this page, continuing at [Determining What Will Change](#determining-what-will-change).** -~> NOTE: It's important to always set the `--version` flag, because otherwise Helm -will use the most up-to-date version in its local cache, which may result in an -unintended upgrade. +~> Note: You should always set the `--version` flag when upgrading Helm. Otherwise Helm uses the most up-to-date version in its local cache, which may result in an unintended upgrade. -## Determining What Will Change +## Determine scope of changes -Before upgrading, it's important to understand what changes will be made to your -cluster. For example, you will need to take more care if your upgrade will result +Before upgrading, it is important to understand the changes that affect your +cluster. For example, you need to take more care if your upgrade results in the Consul server StatefulSet being redeployed. -There is no built-in functionality in Helm that shows what a helm upgrade will -change. There is, however, a Helm plugin [helm-diff](https://github.com/databus23/helm-diff) +There is no built-in functionality in Helm that shows what a helm upgrade +changes. There is, however, a Helm plugin [helm-diff](https://github.com/databus23/helm-diff) that can be used. 1. Install `helm-diff` with: @@ -177,80 +162,30 @@ that can be used. $ helm diff upgrade consul hashicorp/consul --namespace consul --version 0.40.0 --values /path/to/your/values.yaml ``` - This will print out the manifests that will be updated and their diffs. + This command prints out the manifests that will be updated and their diffs. -1. To see only the objects that will be updated, add `| grep "has changed"`: +1. To see only updated objects, add `| grep "has changed"`: ```shell-session $ helm diff upgrade consul hashicorp/consul --namespace consul --version 0.40.0 --values /path/to/your/values.yaml | grep "has changed" ``` -1. Take specific note if `consul-client, DaemonSet` or `consul-server, StatefulSet` are listed. - This means that your Consul client daemonset or Consul server statefulset (or both) will be redeployed. - - If either is being redeployed, we will follow the same pattern for upgrades as - on other platforms: the servers will be redeployed one-by-one, and then the - clients will be redeployed in batches. Read [Upgrading Consul](/docs/upgrading) and then continue - reading below. - - If neither the client daemonset nor the server statefulset is being redeployed, - then you can continue with the helm upgrade without any specific sequence to follow. - -## Service Mesh +1. Take specific note if `consul-server, StatefulSet` is listed, as it means your Consul server statefulset will be redeployed. -If you are using Consul's service mesh features, as opposed to the [service sync](/docs/k8s/service-sync) -functionality, you must be aware of the behavior of the service mesh during upgrades. + If your Consul server statefulset needs to be redeployed, follow the same pattern for upgrades as + on other platforms by redploying servers one by one. Refer tp [Upgrading Consul](/docs/upgrading) for more information. -Consul clients operate as a daemonset across all Kubernetes nodes. During an upgrade, -if the Consul client daemonset has changed, the client pods will need to be restarted -because their spec has changed. + If neither the server statefulset is not being redeployed, + then you can continue with the Helm upgrade without any specific sequence to follow. -When a Consul client pod is restarted, it will deregister itself from Consul when it stops. -When the pod restarts, it will re-register itself with Consul. -Thus, during the period between the Consul client on a node stopping and restarting, -the following will occur: +## Upgrade Consul servers -1. The node will be deregistered from Consul. It will not show up in the Consul UI - nor in API requests. -1. Because the node is deregistered, all service pods that were on that node will - also be deregistered. This means they will not receive service mesh traffic - until the Consul client pod restarts. -1. Service pods on that node can continue to make requests through the service - mesh because each Envoy proxy maintains a cache of the locations of upstream - services. However, if the upstream services change IPs, Envoy will not be able - to refresh its cluster information until its local Consul client is restarted. - So services can continue to make requests without downtime for a short period - of time, however, it's important for the local Consul client to be restarted - as quickly as possible. +Initiate the server upgrade: -Once the local Consul client pod restarts, each service pod needs to be re-registered -with its local Consul client. This is done automatically by the connect inject controller. - -Because service mesh pods are briefly deregistered during a Consul client restart, -it's **important that you do not restart all Consul clients at once**. Otherwise -you may experience downtime because no replicas of a specific service will be in the mesh. - -In addition, it's **important that you have multiple replicas** for each service. -If you only have one replica, then during restart of the Consul client on the -node hosting that replica, it will be briefly deregistered from the mesh. Since -it's the only replica, other services will not be able to make calls to that -service. (NOTE: This can also be avoided by stopping that replica so it is rescheduled to -a node whose Consul client has already been updated.) - -Given the above, we recommend that after Consul servers are upgraded, the Consul -client daemonset is set to use the `OnDelete` update strategy and Consul clients -are deleted one by one or in batches. See [Upgrading Consul Servers](#upgrading-consul-server) -and [Upgrading Consul Clients](#upgrading-consul-clients) for more details. - -## Upgrading Consul Servers - -To initiate the upgrade: - -1. Change the `global.image` value to the desired Consul version -1. Set the `server.updatePartition` value _equal to the number of server replicas_. - By default there are 3 servers, so you would set this value to `3` -1. Set the `updateStrategy` for clients to `OnDelete` +1. Change the `global.image` value to the desired Consul version. +1. Set the `server.updatePartition` value to the number of server replicas. By default there are 3 servers, so you would set this value to `3`. +1. Set the `updateStrategy` for clients to `OnDelete`. @@ -259,9 +194,6 @@ To initiate the upgrade: image: 'consul:123.456' server: updatePartition: 3 - client: - updateStrategy: | - type: OnDelete ``` @@ -269,13 +201,7 @@ To initiate the upgrade: The `updatePartition` value controls how many instances of the server cluster are updated. Only instances with an index _greater than_ the `updatePartition` value are updated (zero-indexed). Therefore, by setting - it equal to replicas, none should update yet. - - The `updateStrategy` controls how Kubernetes rolls out changes to the client daemonset. - By setting it to `OnDelete`, no clients will be restarted until their pods are deleted. - Without this, they would be redeployed alongside the servers because their Docker - image versions have changed. This is not desirable because we want the Consul - servers to be upgraded _before_ the clients. + it equal to replicas, updates should not occur immediately. 1. Next, perform the upgrade: @@ -283,8 +209,8 @@ To initiate the upgrade: $ helm upgrade consul hashicorp/consul --namespace consul --version --values /path/to/your/values.yaml ``` - This will not cause the servers to redeploy (although the resource will be updated). If - everything is stable, begin by decreasing the `updatePartition` value by one, + This command does not cause the servers to redeploy, although the resource is updated. If + everything is stable, decrease the `updatePartition` value by one and performing `helm upgrade` again. This will cause the first Consul server to be stopped and restarted with the new image. @@ -296,38 +222,48 @@ To initiate the upgrade: `updatePartition` is `0`. At this point, you may remove the `updatePartition` configuration. Your server upgrade is complete. -## Upgrading Consul Clients +## Upgrading to Consul Dataplane -With the servers upgraded, it is time to upgrade the clients. -If you are using Consul's service mesh features, you will want to be careful -restarting the clients as outlined in [Service Mesh](#service-mesh). +In earlier versions, Consul on Kubernetes used client agents in its deployments. As of v1.14.0, Consul uses [Consul Dataplane](/docs/connect/dataplane/) in Kubernetes deployments instead of client agents. -You can either: +If you upgrade Consul from a version that uses client agents to a version the uses dataplanes, complete the following steps to upgrade your deployment safely and without downtime. -1. Manually issue `kubectl delete pod ` for each consul daemonset pod -1. Set the updateStrategy to rolling update with a small number: +1. If ACLs are enabled, you must first upgrade to consul-k8s 0.49.8 or above. These versions expose the setting `connectInject.prepareDataplanesUpgrade` + which is required for no-downtime upgrades when ACLs are enabled. - ```yaml + Set `connectInject.prepareDataplanesUpgrade` to `true` and then perform the upgrade to 0.49.8 or above (whichever is the latest in the 0.49.x series) + + ```yaml filename="values.yaml" + connectInject: + prepareDataplanesUpgrade: true + ``` + +1. Consul dataplanes disables Consul clients by default, but during an upgrade you need to ensure Consul clients continue to run. Edit your Helm chart configuration and set the [`client.enabled`](/consul/docs/k8s/helm#v-client-enabled) field to `true` and specify an action for Consul to take during the upgrade process in the [`client.updateStrategy`](/consul/docs/k8s/helm#v-client-updatestrategy) field: + + ```yaml filename="values.yaml" client: + enabled: true updateStrategy: | - rollingUpdate: - maxUnavailable: 2 - type: RollingUpdate + type: OnDelete ``` - Then, run `helm upgrade`. This will upgrade the clients in batches, waiting - until the clients come up healthy before continuing. +1. Follow our [recommended procedures to upgrade servers](#upgrade-consul-servers) on Kubernetes deployments to upgrade Helm values for the new version of Consul. The latest version of consul-k8s components may be in a CrashLoopBackoff state during the performance of the server upgrade from versions <1.14.x until all Consul servers are on versions >=1.14.x. Components in CrashLoopBackoff will not negatively affect the cluster because older versioned components will still be operating. Once all servers have been fully upgraded, the latest consul-k8s components will automatically restore from CrashLoopBackoff and older component versions will be spun down. + +1. Run `kubectl rollout restart` to restart your service mesh applications. Restarting service mesh application causes Kubernetes to re-inject them with the webhook for dataplanes. + +1. Restart all gateways in your service mesh. + +1. Now that all services and gateways are using Consul dataplanes, disable client agents in your Helm chart by deleting the `client` stanza or setting `client.enabled` to `false` and running a `consul-k8s` or Helm upgrade. + +1. If ACLs are enabled, outdated ACL tokens will persist a result of the upgrade. You can manually delete the tokens to declutter your Consul environment. -1. Cordon and drain each node to ensure there are no connect pods active on it, and then delete the - consul client pod on that node. + Outdated connect-injector tokens have the following description: `token created via login: {"component":"connect-injector"}`. Do not delete + the tokens that have a description where `pod` is a key, for example `token created via login: {"component":"connect-injector","pod":"default/consul-connect-injector-576b65747c-9547x"}`). The dataplane-enabled connect inject pods use these tokens. --> NOTE: If you are using only the Service Sync functionality, you can perform an upgrade without -following a specific sequence since that component is more resilient to brief restarts of -Consul clients. + You can also review the creation date for the tokens and only delete the injector tokens created before your upgrade, but do not delete all old tokens without considering if they are still in use. Some tokens, such as the server tokens, are still necessary. -## Configuring TLS on an Existing Cluster +## Configuring TLS on an existing cluster If you already have a Consul cluster deployed on Kubernetes and would like to turn on TLS for internal Consul communication, -please see -[Configuring TLS on an Existing Cluster](/docs/k8s/operations/tls-on-existing-cluster). +refer to [Configuring TLS on an Existing Cluster](/docs/k8s/operations/tls-on-existing-cluster). diff --git a/website/content/docs/lambda/index.mdx b/website/content/docs/lambda/index.mdx index 552b6f41f35f..1a765478f5a7 100644 --- a/website/content/docs/lambda/index.mdx +++ b/website/content/docs/lambda/index.mdx @@ -31,6 +31,6 @@ You can also add the `consul-lambda-extension` plugin as a layer in your Lambda Refer to [Invoke Services from Lambda Functions](/docs/lambda/invoke-from-lambda) for additional information about registering Lambda functions into Consul. -Consul mesh gateways are required to send requests from Lambda functions to mesh services. Refer to [Mesh Gateways between Datacenters](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters) for additional information. +Consul mesh gateways are required to send requests from Lambda functions to mesh services. Refer to [Mesh Gateways](/docs/connect/gateways/mesh-gateway) for additional information. -Note that L7 traffic management features are not supported. As a result, requests from Lambda functions ignore service routes and splitters. \ No newline at end of file +Note that L7 traffic management features are not supported. As a result, requests from Lambda functions ignore service routes and splitters. diff --git a/website/content/docs/lambda/invoke-from-lambda.mdx b/website/content/docs/lambda/invoke-from-lambda.mdx index 495e7e92a9b6..e84fe9a3b87a 100644 --- a/website/content/docs/lambda/invoke-from-lambda.mdx +++ b/website/content/docs/lambda/invoke-from-lambda.mdx @@ -86,7 +86,7 @@ spec: The mesh gateway must be running and registered to the Lambda function’s Consul datacenter. Refer to the following documentation and tutorials for instructions: -- [Mesh Gateways between Datacenters](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters) +- [Mesh Gateways between WAN-Federated Datacenters](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-wan-datacenters) - [Mesh Gateways between Admin Partitions](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-partitions) - [Mesh Gateways between Peered Clusters](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-peers) - [Connect Services Across Datacenters with Mesh Gateways](https://developer.hashicorp.com/consul/tutorials/developer-mesh/service-mesh-gateways) diff --git a/website/content/docs/nia/configuration.mdx b/website/content/docs/nia/configuration.mdx index 78110b736f39..ddea01b5790c 100644 --- a/website/content/docs/nia/configuration.mdx +++ b/website/content/docs/nia/configuration.mdx @@ -197,7 +197,7 @@ Service registration requires that the [Consul token](/docs/nia/configuration#co | `default_check.enabled` | Optional | boolean | Enables CTS to create the default health check. | `true` | | `default_check.address` | Optional | string | The address to use for the default HTTP health check. Needs to include the scheme (`http`/`https`) and the port, if applicable. | `http://localhost:` or `https://localhost:`. Determined from the [port configuration](/docs/nia/configuration#port) and whether [TLS is enabled](/docs/nia/configuration#enabled-2) on the CTS API. | -The default health check is an [HTTP check](/docs/discovery/checks#http-interval) that calls the [Health API](/docs/nia/api/health). The following table describes the values CTS sets for this default check, corresponding to the [Consul register check API](/api-docs/agent/check#register-check). If an option is not listed in this table, then CTS is using the default value. +The default health check is an [HTTP check](/consul/docs/services/usage/checks#http-checks) that calls the [Health API](/consul/docs/nia/api/health). The following table describes the values CTS sets for this default check, corresponding to the [Consul register check API](/consul/api-docs/agent/check#register-check). If an option is not listed in this table, then CTS is using the default value. | Parameter | Value | | --------- | ----- | diff --git a/website/content/docs/nia/index.mdx b/website/content/docs/nia/index.mdx index 86443faad943..e244872dc87c 100644 --- a/website/content/docs/nia/index.mdx +++ b/website/content/docs/nia/index.mdx @@ -11,7 +11,7 @@ Network Infrastructure Automation (NIA) enables dynamic updates to network infra CTS executes one or more automation tasks with the most recent service variable values from the Consul service catalog. Each task consists of a runbook automation written as a CTS compatible Terraform module using resources and data sources for the underlying network infrastructure. The `consul-terraform-sync` daemon runs on the same node as a Consul agent. -CTS is available as an open source and enterprise distribution. Follow the [Network Infrastructure Automation introduction tutorial](https://learn.hashicorp.com/tutorials/consul/consul-terraform-sync-intro?utm_source=docs) to get started with CTS OSS or read more about [CTS Enterprise](/docs/nia/enterprise). +CTS is available as an open source and enterprise distribution. Follow the [Automate your network configuration with Consul-Terraform-Sync tutorial](/consul/tutorials/network-infrastructure-automation/consul-terraform-sync-intro?utm_source=docs) to get started with CTS OSS or read more about [CTS Enterprise](/consul/docs/nia/enterprise). ## Use Cases diff --git a/website/content/docs/release-notes/consul-api-gateway/v0_4_x.mdx b/website/content/docs/release-notes/consul-api-gateway/v0_4_x.mdx index b0c336af72a9..4ea9ec0dade8 100644 --- a/website/content/docs/release-notes/consul-api-gateway/v0_4_x.mdx +++ b/website/content/docs/release-notes/consul-api-gateway/v0_4_x.mdx @@ -30,8 +30,8 @@ description: >- `URLRewrite` filter to an `HTTPRoute` configuration. This enables the gateway to rewrite the URL path in a client's HTTP request before sending the request to a service. For example, you could configure the gateway to change the path - from `//store/checkout` to `//cart/checkout`. Refer to the [usage - documentation](/docs/api-gateway/usage) for additional information. + from `/store/checkout` to `/cart/checkout`. Refer to the [usage + documentation](/consul/docs/api-gateway/usage/reroute-http-requests) for additional information. ## What has Changed diff --git a/website/content/docs/release-notes/consul-k8s/v0_49_x.mdx b/website/content/docs/release-notes/consul-k8s/v0_49_x.mdx index 5f9725cd2a26..c7a37691385f 100644 --- a/website/content/docs/release-notes/consul-k8s/v0_49_x.mdx +++ b/website/content/docs/release-notes/consul-k8s/v0_49_x.mdx @@ -22,7 +22,7 @@ description: >- ## Supported Software - Consul 1.11.x, Consul 1.12.x and Consul 1.13.1+ -- Kubernetes 1.19-1.24 +- Kubernetes 1.19.x - 1.24.x - Kubectl 1.19+ - Helm 3.2+ - Envoy proxy support is determined by the Consul version deployed. Refer to @@ -35,7 +35,7 @@ For detailed information on upgrading, please refer to the [Upgrades page](/docs ## Known Issues The following issues are know to exist in the v0.49.0 release: -- Kubernetes 1.25 is not supported as the [Pod Security Admission controller](https://kubernetes.io/blog/2022/08/25/pod-security-admission-stable/) is currently not supported by Consul K8s. +- Kubernetes 1.25.x is not supported as the [Pod Security Admission controller](https://kubernetes.io/blog/2022/08/25/pod-security-admission-stable/) is currently not supported by Consul K8s. ## Changelogs diff --git a/website/content/docs/release-notes/consul-k8s/v1_0_x.mdx b/website/content/docs/release-notes/consul-k8s/v1_0_x.mdx new file mode 100644 index 000000000000..1de13f87683f --- /dev/null +++ b/website/content/docs/release-notes/consul-k8s/v1_0_x.mdx @@ -0,0 +1,64 @@ +--- +layout: docs +page_title: 1.0.x +description: >- + Consul on Kubernetes release notes for version 1.0.x +--- + +# Consul on Kubernetes 1.0 + +## Release Highlights + +- **Simplified Service Mesh Deployments with Consul Dataplane:** Consul client agents are no longer deployed by default, and Consul service mesh no longer uses Consul clients to operate. A new component `consul-dataplane` is now injected as a sidecar-proxy instead of plain Envoy. `consul-dataplane` manages the Envoy proxy process and proxies xDS requests from Envoy to Consul servers. All service mesh consul-k8s components are configured to talk directly to Consul servers. + +- **Cluster Peering GA with Peering over Mesh Gateways:** This version promotes Cluster Peering, a new model to federate Consul clusters for both service mesh and traditional service discovery, to General Availability. Cluster peering allows for service interconnectivity with looser coupling than the existing WAN federation. Cluster Peering on Consul K8s now enables [Cluster Peering with Control Plane traffic routed via Mesh Gateways](/docs/connect/gateways/mesh-gateway/peering-via-mesh-gateways) by default instead of provisioning load balancers using the `servers.exposeServers` stanza. In addtion, failover for service to service traffic over Cluster Peering can be configured through the `failover.targets` field in the [ServiceResolver](https://developer.hashicorp.com/consul/docs/connect/config-entries/service-resolver#targets) CRD. + +- **Consul API Gateway 0.5.0 Support:** Support to run Consul API Gateway without clients and allow Consul API Gateway to directly connect to Consul servers. + +## What's Changed + +- `client.enabled` now defaults to `false`. Setting it to true will deploy client agents, however, none of the consul-k8s components will use clients for their operation. For Vault on Kubernetes using Consul deployed on Kubernetes as a storage backend, `client.enabled` should be set to `true` prior to upgrading. +- `externalServers.grpcPort` default is now 8502 instead of 8503. +- `externalServers.hosts` no longer supports [cloud auto-join](/consul/docs/install/cloud-auto-join) strings directly. Instead, include an [`exec=`](https://github.com/hashicorp/go-netaddrs#command-line-tool-usage) string in the `externalServers.hosts` list to invoke the `discover` CLI. For example, the following string invokes the `discover` CLI with a cloud auto-join string: `exec=discover -q addrs provider=aws region=us-west-2 tag_key=consul-server tag_value=true`. The `discover` CLI is included in the official `hashicorp/consul-dataplane` images by default. +- `sync-catalog` now communicates directly to Consul servers. When communicating to servers outside of Kubernetes, use the `externalServers.hosts` stanza as described in [Join External Servers to Consul on Kubernetes](/consul/docs/k8s/deployment-configurations/servers-outside-kubernetes). +- Consul snapshot agent runs as a sidecar to Consul servers. + - `client.snapshotAgent` values are moved to `server.snapshotAgent`, with the exception of the following values: `client.snaphostAgent.replicas`, `client.snaphostAgent.serviceAccount` + - `global.secretsBackend.vault.consulSnapshotAgentRole` value is now removed. You should now use the `global.secretsBackend.vault.consulServerRole` for access to any Vault secrets. +- Support simplified default deployment values to allow for easier quick starts and testing: + * Set `server.replicas` to `1`. Formerly, this defaulted to `3`. + * `connectInject.enabled` now defaults to true. + * `dns.enabled` and `dns.enableRedirection` will now default to the value of `connectInject.transparentProxy.defaultEnabled`. Previously, `dns.enabled` defaulted to the value of `global.enabled` and `dns.enableRedirection` defaulted to the value to `false`. + * Set `connectInject.replicas` to 1 + * Set `meshGateway.affinity` to null and `meshGateway.replicas` to 1 + * Set `ingressGateways.defaults.affinity` to null and `ingressGateways.defaults.replicas` to 1 + * Set `terminatingGateways.defaults.affinity` to null and `terminatingGateways.defaults.replicas` to 1 + * `syncCatalog.consulNamespaces.mirroringK8S` now defaults to `true`. + * `connectInject.consulNamespaces.mirroringK8S` now defaults to `true`. +- `global.imageEnvoy` is now replaced with `global.imageConsulDataplane` for running the sidecar proxy. apiGateway.imageEnvoy` is now available for configuring the version of Envoy that the API Gateway uses. + +## Supported Software + +~> **Note:** Consul 1.13.x and 1.12.x is not supported. Please use Consul K8s 0.49.x if you want to use Consul 1.13.x or 1.12.x. +- Consul 1.14.x. +- Consul Dataplane v1.0.x. Refer to [Envoy and Consul Dataplane](/docs/connect/proxies/envoy#envoy-and-consul-dataplane) for details about Consul Dataplane versions and the available packaged Envoy version. +- Kubernetes 1.22.x - 1.25.x +- `kubectl` 1.22.x - 1.25.x +- Helm 3.6+ + +## Upgrading + +For detailed information on upgrading, please refer to the [Upgrades page](/docs/k8s/upgrade) + +## Known Issues + +The following issues are known to exist in the v1.0.0 release: + +- Pod Security Standards that are configured for the [Pod Security Admission controller](https://kubernetes.io/blog/2022/08/25/pod-security-admission-stable/) are currently not supported by Consul K8s. OpenShift 4.11.x enables Pod Security Standards on Kubernetes 1.25 [by default](https://connect.redhat.com/en/blog/important-openshift-changes-pod-security-standards) and is also not supported. Support will be added in a future Consul K8s 1.0.x patch release. + +## Changelogs + +The changelogs for this major release version and any maintenance versions are listed below. + +~> **Note:** The following link takes you to the changelogs on the GitHub website. + +- [1.0.0](https://github.com/hashicorp/consul-k8s/releases/tag/v1.0.0) diff --git a/website/content/docs/release-notes/consul/v1_12_x.mdx b/website/content/docs/release-notes/consul/v1_12_x.mdx index dd354d60b448..bc495dcb63d6 100644 --- a/website/content/docs/release-notes/consul/v1_12_x.mdx +++ b/website/content/docs/release-notes/consul/v1_12_x.mdx @@ -13,7 +13,7 @@ description: >- - **Per listener TLS Config**: It is now possible to configure TLS differently for each of Consul's listeners, such as HTTPS, gRPC, and the internal multiplexed RPC listener, using the `tls` stanza. Refer to [TLS Configuration Reference](/docs/agent/config/config-files#tls-configuration-reference) for more details. -- **AWS Lambda**: Adds the ability to invoke AWS Lambdas through terminating gateways, which allows for cross-datacenter communication, transparent proxy, and intentions with Consul Service Mesh. Refer to [AWS Lambda](/docs]/lambda) and [Invoke Lambda Functions](/docs/lambda/invocation) for more details. +- **AWS Lambda**: Adds the ability to invoke AWS Lambdas through terminating gateways, which allows for cross-datacenter communication, transparent proxy, and intentions with Consul Service Mesh. Refer to [AWS Lambda](/consul/docs/lambda) and [Invoke Lambda Functions](/consul/docs/lambda/invocation) for more details. - **Mesh-wide TLS min/max versions and cipher suites**: Using the [Mesh](/docs/connect/config-entries/mesh#tls) Config Entry or CRD, it is now possible to set TLS min/max versions and cipher suites for both inbound and outbound mTLS connections. diff --git a/website/content/docs/release-notes/consul/v1_13_x.mdx b/website/content/docs/release-notes/consul/v1_13_x.mdx index 03a08c57be8d..5d337e7d589e 100644 --- a/website/content/docs/release-notes/consul/v1_13_x.mdx +++ b/website/content/docs/release-notes/consul/v1_13_x.mdx @@ -15,7 +15,7 @@ description: >- - **Enables TLS on the Envoy Prometheus endpoint**: The Envoy prometheus endpoint can be enabled when `envoy_prometheus_bind_addr` is set and then secured over TLS using new CLI flags for the `consul connect envoy` command. These commands are: `-prometheus-ca-file`, `-prometheus-ca-path`, `-prometheus-cert-file` and `-prometheus-key-file`. The CA, cert, and key can be provided to Envoy by a Kubernetes mounted volume so that Envoy can watch the files and dynamically reload the certs when the volume is updated. -- **UDP Health Checks**: Adds the ability to register service discovery health checks that periodically send UDP datagrams to the specified IP/hostname and port. Refer to [UDP checks](/docs/discovery/checks#udp-interval). +- **UDP Health Checks**: Adds the ability to register service discovery health checks that periodically send UDP datagrams to the specified IP/hostname and port. Refer to [UDP checks](/consul/docs//services/usage/checks#udp-checks). ## What's Changed diff --git a/website/content/docs/release-notes/consul/v1_14_x.mdx b/website/content/docs/release-notes/consul/v1_14_x.mdx new file mode 100644 index 000000000000..e7ad18c853b4 --- /dev/null +++ b/website/content/docs/release-notes/consul/v1_14_x.mdx @@ -0,0 +1,50 @@ +--- +layout: docs +page_title: 1.14.x +description: >- + Consul release notes for version 1.14.x +--- + +# Consul 1.14.0 + +## Release Highlights + +- **Cluster Peering (GA):** This version promotes Cluster Peering, a new model to federate Consul clusters for both service mesh and traditional service discovery, to General Availability. Cluster peering allows for service interconnectivity with looser coupling than the existing WAN federation. For more information, refer to the [cluster peering](/docs/connect/cluster-peering) documentation. Some notable improvements to Cluster Peering include: + + - **Cluster Peering Failover:** Cluster Peering now supports the ability to redirect to services running on cluster peers with service resolvers. More details for configuring failover across peers is provided in the Service Resolver [failover](/docs/connect/config-entries/service-resolver#failover) stanza. + + - **Control Plane traffic over Mesh Gateways:** Cluster Peering now supports the establishing peering through Mesh Gateways. More detail on using Mesh Gateways for Cluster Peering are found in [Enabling Peering Control Plane Traffic](/docs/connect/gateways/mesh-gateway/peering-via-mesh-gateways). Mesh Gateways are used by default for [Cluster Peering on Kubernetes](/docs/connect/cluster-peering/k8s). + +- **Simplified Service Mesh with Consul Dataplane:** Support for a new `consul-dataplane`, a lightweight process for managing Envoy proxies introduced in Consul v1.14.0. Consul Dataplane removes the need to run client agents on every node in a cluster for service discovery and service mesh. Instead, Consul deploys sidecar proxies that provide lower latency, support additional runtimes, and integrate with cloud infrastructure providers. Read more in [Simplified Service Mesh with Consul Dataplane](/docs/connect/dataplane). + + ~> **Note:** Currently `consul-dataplane` is only supported on clusters running on Consul on Kubernetes 1.0+. + +## What's Changed + +- 1.14 adds a new `ports.grpc_tls` configuration option. This introduces a new port to better separate TLS config from the existing `ports.grpc` config. The new `ports.grpc_tls` only supports TLS encrypted communication. The existing `ports.grpc` now only supports plain-text communication. +- `peering` and `connect` are default. +- The gRPC TLS port default value to 8503 +- Removes support for Envoy 1.20.x and adds Envoy 1.24.0 to support matrix. +- Renames `PeerName` to `Peer` on prepared queries and exported services. +- Converts service mesh failover to use Envoy's aggregate clusters. This +changes the names of some [Envoy dynamic HTTP metrics](https://www.envoyproxy.io/docs/envoy/latest/configuration/upstream/cluster_manager/cluster_stats#dynamic-http-statistics). + +## Upgrading + +For more detailed information, please refer to the [upgrade details page](/docs/upgrading/upgrade-specific#consul-1-14-0) and the changelogs. + +## Known Issues + +The following issues are known to exist in the 1.14.0 release: + +- Prior to Consul 1.14, cluster peering and Consul service mesh were disabled by default. A breaking change was made in Consul 1.14 that enabled cluster peering and Consul service mesh by default. To disable both, set `peering.enabled` and `connect.enabled` to false. The changes to Consul service mesh in version 1.14 are incompatible with Nomad 1.4.2 and earlier. If you operate Consul service mesh using Nomad 1.4.2 or earlier, do not upgrade to Consul 1.14 until hashicorp/nomad#15266 is fixed. + +- For 1.14.0, there is a known issue with the `consul connect envoy` CLI command. If the command is configured to use TLS for contacting the HTTP API, it will also incorrectly enable TLS for gRPC. Users should not upgrade to 1.14.0 if they are using plaintext gRPC connections in conjunction with TLS-encrypted HTTP APIs. + +## Changelogs + +The changelogs for this major release version and any maintenance versions are listed below. + +-> **Note**: These links take you to the changelogs on the GitHub website. + +- [1.14.0](https://github.com/hashicorp/consul/releases/tag/v1.14.0) diff --git a/website/content/docs/security/acl/acl-policies.mdx b/website/content/docs/security/acl/acl-policies.mdx index 22f5dac8b209..bf860a74f51c 100644 --- a/website/content/docs/security/acl/acl-policies.mdx +++ b/website/content/docs/security/acl/acl-policies.mdx @@ -389,7 +389,11 @@ New installations of Consul ship with the following built-in policies. ### Global Management -The `global-management` policy grants unrestricted privileges to any token linked to it. The policy is assigned the reserved ID of `00000000-0000-0000-0000-000000000001`. You can rename the global management policy, but Consul will prevent you from modifying any other attributes, including the rule set and datacenter scope. +The `global-management` policy grants unrestricted privileges to any token linked to it. The policy is assigned the reserved ID of `00000000-0000-0000-0000-000000000001`. You can rename the global management policy, but Consul prevents you from modifying any other attributes, including the rule set and datacenter scope. + +### Global Read-Only + +The `builtin/global-read-only` policy grants unrestricted _read-only_ privileges to any token linked to it. The policy is assigned the reserved ID of `00000000-0000-0000-0000-000000000002`. You can rename the global read-only policy, but Consul prevents you from modifying any other attributes, including the rule set and datacenter scope. ### Namespace Management diff --git a/website/content/docs/security/acl/acl-rules.mdx b/website/content/docs/security/acl/acl-rules.mdx index b24ca71e2fbf..81a173ded847 100644 --- a/website/content/docs/security/acl/acl-rules.mdx +++ b/website/content/docs/security/acl/acl-rules.mdx @@ -22,7 +22,7 @@ The following table provides an overview of the resources you can use to create | `key`
    `key_prefix`   | Controls access to key/value store operations in the [KV API](/api-docs/kv).
    Can also use the `list` access level when setting the policy disposition.
    Has additional value options in Consul Enterprise for integrating with [Sentinel](https://docs.hashicorp.com/sentinel/consul).
    See [Key/Value Rules](#key-value-rules) for details. | Yes | | `keyring`       | Controls access to keyring operations in the [Keyring API](/api-docs/operator/keyring).
    See [Keyring Rules](#keyring-rules) for details. | No | | `mesh`       | Provides operator-level permissions for resources in the admin partition, such as ingress gateways or mesh proxy defaults. See [Mesh Rules](#mesh-rules) for details. | No | -| `peering`       | Controls access to cluster peerings in the [Cluster Peering API](/api-docs/peering). For more details, refer to [Peering Rules](#peering-rules). | No | +| `peering`       | Controls access to cluster peerings in the [Cluster Peering API](/api-docs/peering). For more details, refer to [Peering Rules](#peering-rules). | No | | `namespace`
    `namespace_prefix` | Controls access to one or more namespaces.
    See [Namespace Rules](#namespace-rules) for details. | Yes | | `node`
    `node_prefix`   | Controls access to node-level operations in the [Catalog API](/api-docs/catalog), [Health API](/api-docs/health), [Prepared Query API](/api-docs/query), [Network Coordinate API](/api-docs/coordinate), and [Agent API](/api-docs/agent)
    See [Node Rules](#node-rules) for details. | Yes | | `operator`       | Controls access to cluster-level operations available in the [Operator API](/api-docs/operator) excluding keyring API endpoints.
    See [Operator Rules](#operator-rules) for details. | No | @@ -586,8 +586,21 @@ These actions may required an ACL token to complete. Use the following methods t This allows a single token to be used during all check registration operations. * Provide an ACL token with `service` and `check` definitions at registration time. This allows for greater flexibility and enables the use of multiple tokens on the same agent. - Refer to the [services](/docs/discovery/services) and [checks](/docs/discovery/checks) documentation for examples. - Tokens may also be passed to the [HTTP API](/api-docs) for operations that require them. + Refer to the [services](/consul/docs/services/usage/define-services) and [checks](/consul/docs/services/usage/checks) documentation for examples. You can also pass tokens to the [HTTP API](/consul/api-docs) for operations that require them. + +### Reading Imported Nodes + +Nodes rules affect read access to nodes with services exported by [`exported-services` configuration entries](/docs/connect/config-entries/exported-services#reading-services), including nodes imported from [cluster peerings](/docs/connect/cluster-peering) or [admin partitions](/docs/enterprise/admin-partitions) (Enterprise-only). +Read access to all imported nodes is granted when either of the following rule sets are attached to a token: +- `service:write` is granted to any service. +- `node:read` is granted to all nodes. + +For Consul Enterprise, either set of rules must be scoped to the requesting services's partition and at least one namespace. + +You may need similarly scoped [Service Rules](#reading-imported-services) to read Consul data, depending on the endpoint (e.g. `/v1/health/service/:name`). +These permissions are satisfied when using a [service identity](/docs/security/acl/acl-roles#service-identities). + +Refer to [Reading Services](/docs/connect/config-entries/exported-services#reading-services) for example ACL policies used to read imported services using the health endpoint. ## Operator Rules @@ -801,12 +814,12 @@ to use for registration events: 2. Providing an ACL token with service and check definitions at registration time. This allows for greater flexibility and enables the use of multiple tokens on the same agent. Examples of what this looks like are available for - both [services](/docs/discovery/services) and - [checks](/docs/discovery/checks). Tokens may also be passed to the [HTTP - API](/api-docs) for operations that require them. **Note:** all tokens + both [services](/consul/docs/services/usage/define-services) and + [checks](/consul/docs/services/usage/checks). Tokens may also be passed to the [HTTP + API](/consul/api-docs) for operations that require them. Note that all tokens passed to an agent are persisted on local disk to allow recovery from - restarts. See [`-data-dir` flag - documentation](/docs/agent/config/cli-flags#_data_dir) for notes on securing + restarts. Refer to [`-data-dir` flag + documentation](/consul/docs/agent/config/cli-flags#_data_dir) for information about securing access. In addition to ACLs, in Consul 0.9.0 and later, the agent must be configured with @@ -814,6 +827,22 @@ In addition to ACLs, in Consul 0.9.0 and later, the agent must be configured wit [`enable_local_script_checks`](/docs/agent/config/config-files#enable_local_script_checks) set to `true` in order to enable script checks. +### Reading Imported Services + +Service rules affect read access to services exported by [`exported-services` configuration entries](/docs/connect/config-entries/exported-services#reading-services), including services exported between [cluster peerings](/docs/connect/cluster-peering) or [admin partitions](/docs/enterprise/admin-partitions) (Enterprise-only). +Read access to all imported services is granted when either of the following rule sets are attached to a token: +- `service:write` is granted to any service. +- `service:read` is granted to all services. + +For Consul Enterprise, either set of rules must be scoped to the requesting services's partition and at least one namespace. + +You may need similarly scoped [Node Rules](#reading-imported-nodes) to read Consul data, depending on the endpoint (e.g. `/v1/health/service/:name`). +These permissions are satisfied when using a [service identity](/docs/security/acl/acl-roles#service-identities). + +Refer to [Reading Services](/docs/connect/config-entries/exported-services#reading-services) for example ACL policies used to read imported services using the health endpoint. + +### Intentions + Service rules are also used to grant read or write access to intentions. The following policy provides read-write access to the "app" service, and explicitly grants `intentions:read` access to view intentions associated with the "app" service. diff --git a/website/content/docs/security/acl/auth-methods/aws-iam.mdx b/website/content/docs/security/acl/auth-methods/aws-iam.mdx index 954b05ef25f5..c2a85ac29f10 100644 --- a/website/content/docs/security/acl/auth-methods/aws-iam.mdx +++ b/website/content/docs/security/acl/auth-methods/aws-iam.mdx @@ -106,13 +106,13 @@ The authentication step returns the following trusted identity attributes for us selectors and bind name interpolation. All of these attributes are strings that can be interpolated and support the following selector operations: `Equal, Not Equal, In, Not In, Matches, Not Matches` -| Attribute | Description | Requirement | -| -------------------- | ----------------------------------- | ---------------------------------------------------------------- | -| `entity_name` | Name of IAM role or user | | -| `entity_id` | Unique ID of IAM role or user | | -| `account_id` | AWS account id of IAM role or user | | -| `entity_path` | The path of the IAM role or user | `EnableIAMEntityDetails=true` | -| `entity_tags.` | AWS account id of IAM role or user | `EnableIAMEntityDetails=true` and `IAMEntityTags` contains `` | +| Attribute | Description | Requirement | +| -------------------- | --------------------------------------- | ------------------------------------------------------------------ | +| `entity_name` | Name of IAM role or user | | +| `entity_id` | Unique ID of IAM role or user | | +| `account_id` | AWS account id of IAM role or user | | +| `entity_path` | The path of the IAM role or user | `EnableIAMEntityDetails=true` | +| `entity_tags.` | Value of a tag on the IAM role or user | `EnableIAMEntityDetails=true` and `IAMEntityTags` contains `` | ## IAM Policies diff --git a/website/content/docs/security/acl/auth-methods/kubernetes.mdx b/website/content/docs/security/acl/auth-methods/kubernetes.mdx index a842d92cbe46..734e94c99682 100644 --- a/website/content/docs/security/acl/auth-methods/kubernetes.mdx +++ b/website/content/docs/security/acl/auth-methods/kubernetes.mdx @@ -76,14 +76,13 @@ The Kubernetes service account corresponding to the configured [`ServiceAccountJWT`](/docs/security/acl/auth-methods/kubernetes#serviceaccountjwt) needs to have access to two Kubernetes APIs: -- [**TokenReview**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#create-tokenreview-v1-authentication-k8s-io) +- [**TokenReview**](https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/token-review-v1/) -> Kubernetes should be running with `--service-account-lookup`. This is defaulted to true in Kubernetes 1.7, but any versions prior should ensure the Kubernetes API server is started with this setting. -- [**ServiceAccount**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#read-serviceaccount-v1-core) - (`get`) +- [**ServiceAccount**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#service-account-tokens) The following is an example [RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) diff --git a/website/content/docs/security/acl/auth-methods/oidc.mdx b/website/content/docs/security/acl/auth-methods/oidc.mdx index e64292773399..edc136bd7042 100644 --- a/website/content/docs/security/acl/auth-methods/oidc.mdx +++ b/website/content/docs/security/acl/auth-methods/oidc.mdx @@ -73,7 +73,7 @@ parameters are required to properly configure an auth method of type - `JWTSupportedAlgs` `(array)` - JWTSupportedAlgs is a list of supported signing algorithms. Defaults to `RS256`. ([Available - algorithms](https://github.com/hashicorp/consul/blob/main/vendor/github.com/coreos/go-oidc/jose.go#L7)) + algorithms](https://github.com/hashicorp/consul/blob/main/internal/go-sso/oidcauth/jwt.go)) - `BoundAudiences` `(array)` - List of `aud` claims that are valid for login; any match is sufficient. diff --git a/website/content/docs/security/acl/tokens/create/create-a-consul-esm-token.mdx b/website/content/docs/security/acl/tokens/create/create-a-consul-esm-token.mdx new file mode 100644 index 000000000000..cf33e95248f9 --- /dev/null +++ b/website/content/docs/security/acl/tokens/create/create-a-consul-esm-token.mdx @@ -0,0 +1,382 @@ +--- +layout: docs +page_title: Create tokens for for Consul external service monitor +description: >- + Learn how to create ACL tokens for the Consul external service monitor +--- + +# Create a Consul ESM token + +This topic describes how to create a token for the Consul external service monitor. + +## Introduction + +Consul external service monitor (ESM) can monitor third-party or external services in contexts where you are unable to run a Consul agent. To learn more about Consul ESM, refer to the [Register External Services with Consul Service Discovery](/consul/tutorials/developer-discovery/service-registration-external-services) tutorial. + + +## Requirements + +Core ACL functionality is available in all versions of Consul. + +Consul ESM must present a token linked to policies that grant the following permissions: + +* `agent:read`: Enables checking version compatibility and calculating network coordinates +* `key:write`: Enables storing state in the Consul KV store +* `node:read`: Enables discovering Consul nodes to monitor +* `node:write`: Enables updating status for the nodes that Consul ESM monitors +* `service:write`: Enables Consul ESM to register as a service in the catalog +* `session:write`: Enables Consul ESM is registered to acquire a leader lock +* `acl:read`: (Enterprise-only) Enables Consul ESM to scan namespaces for nodes and health checks to monitor + +Consul ESM only supports `default` admin partitions. + +@include 'create-token-requirements.mdx' + +## Consul ESM token in Consul OSS + +To create a token for Consul ESM, you must define a policy, register the policy with Consul, and link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The policy grants the appropriate permissions for Consul ESM running on an agent with the node name `agent1` to monitor two nodes named `node1` and `node2`. It allows Consul ESM to register into the catalog as the `consul-esm` service and write keys with the prefix `consul-esm/` in the Consul KV store. + + + +```hcl +agent "agent1" { + policy = "read" +} +key_prefix "consul-esm/" { + policy = "write" +} +node_prefix "" { + policy = "read" +} +service "consul-esm" { + policy = "write" +} +session "agent1" { + policy = "write" +} +node "node1" { + policy = "write" +} +node "node2" { + policy = "write" +} +``` + +```json +{ + "agent": { + "agent1": [{ + "policy": "read" + }] + }, + "key_prefix": { + "consul-esm/": [{ + "policy": "write" + }] + }, + "node": { + "node1": [{ + "policy": "write" + }], + "node2": [{ + "policy": "write" + }] + }, + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "service": { + "consul-esm": [{ + "policy": "write" + }] + }, + "session": { + "agent1": [{ + "policy": "write" + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policy, you can register the policy with Consul using the command line or API endpoint. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + +The following example registers a policy defined in `esm-policy.hcl`. + +```shell-session +$ consul acl policy create \ + -name "esm-policy" -rules @esm-policy.hcl \ + -description "Policy for Consul ESM" +``` + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + +The following example registers the policy defined in `esm-policy.hcl`. You must embed policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "esm-policy", + "Description": "Policy for Consul ESM", + "Rules": "agent \"agent1\" {\n policy = \"read\"\n}\nkey_prefix \"consul-esm/\" {\n policy = \"write\"\n}\nnode_prefix \"\" {\n policy = \"read\"\n}\nservice \"consul-esm\" {\n policy = \"write\"\n}\nsession \"agent1\" {\n policy = \"write\"\n}\nnode \"node1\" {\n policy = \"write\"\n}\nnode \"node2\" {\n policy = \"write\"\n}\n" +}' +``` + + + + + +### Link the policy to a token + +After registering the policy into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +The following example creates an ACL token linked to the policy `esm-policy`. + +```shell-session +$ consul acl token create \ + -description "Token for Consul ESM" \ + -policy-name "esm-policy" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +The following example creates an ACL token linked to the policy `esm-policy`. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "esm-policy" + } + ] +}' +``` + + + + + + +## Consul ESM token in Consul Enterprise + +To create a token for Consul ESM, you must define a policy, register the policy with Consul, and link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The policy grants the appropriate permissions for Consul ESM running on an agent named `agent1` to monitor two nodes named `node1` and `node2`. It allows Consul ESM to register into the catalog as the `consul-esm` service, to write keys with the prefix `consul-esm/` in the Consul KV store, and to scan the `default` and `ns1` namespaces for nodes and health checks to monitor. + + + +```hcl +partition "default" { + agent "agent1" { + policy = "read" + } + key_prefix "consul-esm/" { + policy = "write" + } + node_prefix "" { + policy = "read" + } + service "consul-esm" { + policy = "write" + } + session "agent1" { + policy = "write" + } + + node "node1" { + policy = "write" + } + node "node1" { + policy = "write" + } + + namespace "default" { + acl = "read" + } + namespace "ns1" { + acl = "read" + } +} +``` + +```json +{ + "partition": { + "default": [{ + "agent": { + "agent1": [{ + "policy": "read" + }] + }, + "key_prefix": { + "consul-esm/": [{ + "policy": "write" + }] + }, + "namespace": { + "default": [{ + "acl": "read" + }], + "ns1": [{ + "acl": "read" + }] + }, + "node": { + "node1": [{ + "policy": "write" + }, + { + "policy": "write" + }] + }, + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "service": { + "consul-esm": [{ + "policy": "write" + }] + }, + "session": { + "agent1": [{ + "policy": "write" + }] + } + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policy, you can register the policy with Consul using the command line or API endpoint. + +You can specify an admin partition and namespace when creating policies in Consul Enterprise. The policy is only valid in the specified scopes. The example policy contains permissions for multiple namespaces in multiple partitions. You must create ACL policies that grant permissions for multiple namespaces in multiple partitions in the `default` namespace and the `default` partition. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + +The following command registers a policy defined in `esm-policy.hcl`. + +```shell-session +$ consul acl policy create -partition "default" -namespace "default" \ + -name "esm-policy" -rules @esm-policy.hcl \ + -description "Policy for Consul ESM" +``` + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + +The following example registers the policy defined in `esm-policy.hcl`. You must embed policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "esm-policy", + "Description": "Policy for Consul ESM", + "Partition": "default", + "Namespace": "default", + "Rules": "partition \"default\" {\n agent \"agent1\" {\n policy = \"read\"\n }\n key_prefix \"consul-esm/\" {\n policy = \"write\"\n }\n node_prefix \"\" {\n policy = \"read\"\n }\n service \"consul-esm\" {\n policy = \"write\"\n }\n session \"agent1\" {\n policy = \"write\"\n }\n\n node \"node1\" {\n policy = \"write\"\n }\n node \"node1\" {\n policy = \"write\"\n }\n\n namespace \"default\" {\n acl = \"read\"\n }\n namespace \"ns1\" {\n acl = \"read\"\n }\n}\n" +}' +``` + + + + + + +### Link the policy to a token + +After registering the policy into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + +You can specify an admin partition and namespace when creating tokens in Consul Enterprise. The token must be created in the partition and namespace where the policy was created. The following example creates an ACL token in the `default` namespace in the `default` partition. + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + + +The following command creates the ACL token linked to the policy `esm-policy`. + +```shell-session +$ consul acl token create -partition "default" -namespace "default" \ + -description "Token for Consul ESM" \ + -policy-name "esm-policy" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +The following example creates an ACL token linked to the policy `esm-policy`. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "esm-policy" + } + ], + "Partition": "default", + "Namespace": "default" +}' +``` + + + + diff --git a/website/content/docs/security/acl/tokens/create/create-a-dns-token.mdx b/website/content/docs/security/acl/tokens/create/create-a-dns-token.mdx new file mode 100644 index 000000000000..f4d87b7724bf --- /dev/null +++ b/website/content/docs/security/acl/tokens/create/create-a-dns-token.mdx @@ -0,0 +1,331 @@ +--- +layout: docs +page_title: Create tokens for service registration +description: >- + Learn how to create ACL tokens to enable Consul DNS. +--- + +# Create a DNS token + +This topic describes how to create a token that enables the Consul DNS to query services in the network when ACLs are enabled. + +## Introduction + +The Consul binary ships with a DNS server that you can use for service discovery in your network. The agent that fulfills DNS lookups requires appropriate ACL permissions to discover services, nodes, and prepared queries registered in Consul. + +A Consul agent must be configured with a token linked to policies that grant the appropriate set of permissions. + +Specify the [`default`](/consul/docs/agent/config/config-files#acl_tokens_default) token to the Consul agent to authorize the agent to respond to DNS queries. Refer to [DNS usage overview](/consul/docs/services/discovery/dns-overview) for details on configuring and using Consul DNS. + +## Requirements + +Core ACL functionality is available in all versions of Consul. + +The DNS token must be linked to policies that grant the following permissions: + +* `service:read`: Enables the agent to perform service lookups for DNS +* `node:read`: Enables node lookups over DNS +* `query:read`: Enables the agent to perform prepared query lookups for DNS + +@include 'create-token-requirements.mdx' + +## DNS token in Consul OSS + +To create a token for DNS, you must define a policy, register the policy with Consul, and link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The policy grants the appropriate permissions to enable a Consul agent to respond to DNS queries. + + + +```hcl +node_prefix "" { + policy = "read" +} +service_prefix "" { + policy = "read" +} +query_prefix "" { + policy = "read" +} +``` + +```json +{ + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "query_prefix": { + "": [{ + "policy": "read" + }] + }, + "service_prefix": { + "": [{ + "policy": "read" + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policy, you can register the policy with Consul using the command line or API endpoint. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + +The following example registers a policy defined in `dns-access.hcl`. + +```shell-session +$ consul acl policy create \ + -name "dns-access" -rules @dns-access.hcl \ + -description "DNS Policy" +``` + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + +The following example registers the policy defined in `dns-access.hcl`. You must embed policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "dns-access", + "Description": "DNS Policy", + "Rules": "node_prefix \"\" {\n policy = \"read\"\n}\nservice_prefix \"\" {\n policy = \"read\"\n}\nquery_prefix \"\" {\n policy = \"read\"\n}\n" +}' +``` + + + + + +### Link the policy to a token + +After registering the policy into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +The following command creates the ACL token linked to the policy `dns-access`. + +```shell-session +$ consul acl token create \ + -description "DNS token" \ + -policy-name "dns-access" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +The following example creates the ACL token linked to the policy `dns-access`. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "dns-access" + } + ] +}' +``` + + + + + +## DNS token in Consul Enterprise + +To create a token for DNS, you must define a policy, register the policy with Consul, and link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The policy grants the appropriate permissions to enable a Consul agent to respond to DNS queries for resources in any namespace in any partition. + + + +```hcl +partition_prefix "" { + namespace_prefix "" { + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } + query_prefix "" { + policy = "read" + } + } +} +``` + +```json +{ + "partition_prefix": { + "": [{ + "namespace_prefix": { + "": [{ + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "query_prefix": { + "": [{ + "policy": "read" + }] + }, + "service_prefix": { + "": [{ + "policy": "read" + }] + } + }] + } + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policy, you can register the policy with Consul using the command line or API endpoint. + +You can specify an admin partition when creating policies in Consul Enterprise. The policy is only valid in the specified admin partition. The example policy contains permissions for multiple namespaces in multiple partitions. You must create ACL policies that grant permissions for multiple namespaces in multiple partitions in the `default` namespace and the `default` partition. + + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + +```shell-session +consul acl policy create -partition "default" -namespace "default" \ + -name dns-access -rules @dns-access.hcl \ + -description "DNS Policy" +``` + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + +The following example registers the policy defined in `dns-access.hcl`. You must embed policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "dns-access", + "Description": "DNS Policy", + "Partition": "default", + "Namespace": "default", + "Rules": "partition_prefix \"\" {\n namespace_prefix \"\" {\n node_prefix \"\" {\n policy = \"read\"\n }\n service_prefix \"\" {\n policy = \"read\"\n }\n query_prefix \"\" {\n policy = \"read\"\n }\n }\n}\n" +}' +``` + + + + + +### Link the policy to a token + +After registering the policy into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +The following command creates the ACL token linked to the policy `dns-access`. + +```shell-session +$ consul acl token create -partition "default" -namespace "default" \ + -description "DNS token" \ + -policy-name "dns-access" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +The following example creates the ACL token linked to the policy `dns-access`. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "dns-access" + } + ], + "Partition": "default", + "Namespace": "default" +}' +``` + + + + + +## Apply the token + +Configure the Consul agent with the token by either specifying the token in the agent configuration file or by using the `consul set-agent-token` command. + +### Apply the token in a file + +Specify the token in the [`default`](/consul/docs/agent/config/config-files#acl_tokens_default) field of the agent configuration file so that the agent can present it and register into the catalog on startup. + +```hcl +acl = { + enabled = true + tokens = { + default = "" + ... + } + ... +} +``` + +### Apply the token with a command + +Set the `default` token using the [`acl.token.default`](/consul/docs/agent/config/config-files#acl_tokens_default) command. The following command configures a running Consul agent token with the specified token. + +```shell-session +$ consul set-agent-token default +``` + diff --git a/website/content/docs/security/acl/tokens/create/create-a-mesh-gateway-token.mdx b/website/content/docs/security/acl/tokens/create/create-a-mesh-gateway-token.mdx new file mode 100644 index 000000000000..6e94395d31dd --- /dev/null +++ b/website/content/docs/security/acl/tokens/create/create-a-mesh-gateway-token.mdx @@ -0,0 +1,508 @@ +--- +layout: docs +page_title: Create a token for mesh gateway registration +description: >- + Learn how to create ACL tokens that your mesh gateway can present to Consul servers so that they + can register with the Consul catalog. +--- + +# Create a mesh gateway token + +This topic describes how to create a token for a mesh gateway. + +## Introduction + +Mesh gateways enable service-to-service traffic between Consul datacenters or between Consul admin +partitions. They also enable datacenters to be federated across wide area networks. Refer to [Mesh +Gateways](/consul/docs/connect/gateways#mesh-gateways) for additional information. + +Gateways must present a token linked to policies that grant the appropriate set of permissions in +order to be discoverable and to route to other services in a mesh. + +## Requirements + +Core ACL functionality is available in all versions of Consul. + +The mesh gateway must present a token linked to a policy that grants the following permissions: + +* `mesh:write` to obtain leaf certificates for terminating TLS connections +* `peering:read` for Consul cluster peering through mesh gateways. If you are not using cluster + peering or if the mesh gateway is not in the `default` partition, then you can omit the + `peering:read` permission. +* `service:write` to allow the mesh gateway to register into the catalog +* `service:read` for all services and `node:read` for all nodes in order to discover and route to services +* `agent:read` to enable the `consul connect envoy` CLI command to automatically discover gRPC + settings from the Consul agent. If this command is not used to start the gateway or if the Consul + agent uses the default gRPC settings, then you can omit the `agent:read` permission. + +@include 'create-token-requirements.mdx' + +## Consul OSS + +To create a token for the mesh gateway, you must define a policy, register the policy with Consul, and link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The policy grants the appropriate permissions to register as a service named `mesh-gateway` and to operate as a mesh gateway. + + + +```hcl +mesh = "write" +peering = "read" +service "mesh-gateway" { + policy = "write" +} +service_prefix "" { + policy = "read" +} +node_prefix "" { + policy = "read" +} +agent_prefix "" { + policy = "read" +} +``` + +```json +{ + "mesh": "write", + "peering": "read", + "service": { + "mesh-gateway": [{ + "policy": "write" + }] + }, + "service_prefix": { + "": [{ + "policy": "read" + }] + }, + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "agent_prefix": { + "": [{ + "policy": "read" + }] + } +} +``` + + + + +### Register the policy with Consul + +After defining the policy, you can register the policy with Consul using the command line or API endpoint. + +The following commands create the ACL policy and token. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. The following example registers a policy defined in `mgw-register.hcl`: + +```shell-session +$ consul acl policy create \ + -name "mgw-register" -rules @mgw-register.hcl \ + -description "Mesh gateway policy" +``` + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. The following example registers the policy defined in `mgw-register.hcl`. You must embed policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + –-header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "mgw-register", + "Description": "Mesh gateway policy", + "Rules": "mesh = \"write\"\npeering = \"read\"\nservice \"mesh-gateway\" {\n policy = \"write\"\n}\nservice_prefix \"\" {\n policy = \"read\"\n}\nnode_prefix \"\" {\n policy = \"read\"\n}\nagent_prefix \"\" {\n policy = \"read\"\n}\n" +}' +``` + +Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + + + + + +### Link the policy to a token + +After registering the policy into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +The following command creates the ACL token linked to the policy `mgw-register`. + +```shell-session +$ consul acl token create \ + -description "Mesh gateway token" \ + -policy-name "mgw-register" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + –-header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "mgw-register" + } + ] +}' +``` + + + + + +## Consul Enterprise in default partition + +To create a token for the mesh gateway, you must define a policy, register the policy with Consul, and link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +You can specify an admin partition and namespace when using Consul Enterprise. Mesh gateways must register into the `default` namespace. + +The following example policy is defined in a file. The policy grants the appropriate permissions to register as a service named `mesh-gateway` and to operate as a mesh gateway in the default partition. + + + +```hcl +mesh = "write" +partition_prefix "" { + peering = "read" +} +partition "default" { + namespace "default" { + service "mesh-gateway" { + policy = "write" + } + agent_prefix "" { + policy = "read" + } + } + namespace_prefix "" { + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } + } +} +``` + +```json +{ + "mesh": "write", + "partition": { + "default": [{ + "namespace": { + "default": [{ + "service": { + "mesh-gateway": [{ + "policy": "write" + }] + }, + "agent_prefix": { + "": [{ + "policy": "read" + }] + } + }] + }, + "namespace_prefix": { + "": [{ + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "service_prefix": { + "": [{ + "policy": "read" + }] + } + }] + } + }] + }, + "partition_prefix": { + "": [{ + "peering": "read" + }] + } +} +``` + + + + +### Register the policy with Consul + +After defining the policy, you can register the policy with Consul using the command line or API endpoint. + +The following commands create the ACL policy and token. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. The following example registers a policy defined in `mgw-register.hcl`: + +You can specify an admin partition when creating policies in Consul Enterprise. The policy is only valid in the specified admin partition. You must create the policy in the partition where the mesh gateway registers. The following example creates the policy in the `default` partition. + +```shell-session +$ consul acl policy create -partition "default" \ + -name mgw-register -rules @mgw-register.hcl \ + -description "Mesh gateway policy" +``` + +Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. The following example registers the policy defined in `mgw-register.hcl`. You must embed policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + –-header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "mgw-register", + "Description": "Mesh gateway policy", + "Partition": "default", + "Rules": "mesh = \"write\"\npeering = \"read\"\npartition_prefix \"\" {\n peering = \"read\"\n}\nnamespace \"default\" {\n service \"mesh-gateway\" {\n policy = \"write\"\n }\n agent_prefix \"\" {\n policy = \"read\"\n }\n}\nnamespace_prefix \"\" {\n node_prefix \"\" {\n \tpolicy = \"read\"\n }\n service_prefix \"\" {\n policy = \"read\"\n }\n}\n" +}' +``` + +Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + + + + + +### Link the policy to a token + +After registering the policy into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +You can specify an admin partition when creating tokens in Consul Enterprise. The token is only valid in the specified admin partition. The token must be created in the partition where the mesh gateway registers. The following example creates the token in the partition `ptn1`. + +```shell-session +$ consul acl token create -partition "default" \ + -description "Mesh gateway token" \ + -policy-name "mgw-register" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +You can specify an admin partition when creating tokens in Consul Enterprise. The token is only valid in the specified admin partition. The token must be created in the partition where the mesh gateway registers. The following example creates the token in the partition `ptn1`. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + –-header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "mgw-register" + } + ], + "Partition": "default" +}' +``` + + + + + +## Consul Enterprise in non-default partition + +To create a token for the mesh gateway, you must define a policy, register the policy with Consul, and link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +You can specify an admin partition and namespace when using Consul Enterprise. Mesh gateways must register into the `default` namespace. To register a mesh gateway in a non-default partition, create the ACL policy and token in the partition where the mesh gateway registers. + +The following example policy is defined in a file. The policy grants the appropriate permissions to register as a service named `mesh-gateway` and to operate as a mesh gateway in a non-default partition. + + + +```hcl +mesh = "write" +namespace "default" { + service "mesh-gateway" { + policy = "write" + } + agent_prefix "" { + policy = "read" + } +} +namespace_prefix "" { + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } +} +``` + +```json +{ + "mesh": "write", + "namespace": { + "default": [{ + "service": { + "mesh-gateway": [{ + "policy": "write" + }] + }, + "agent_prefix": { + "": [{ + "policy": "read" + }] + } + }] + }, + "namespace_prefix": { + "": [{ + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "service_prefix": { + "": [{ + "policy": "read" + }] + } + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policy, you can register the policy with Consul using the command line or API endpoint. + +The following commands create the ACL policy and token. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. The following example registers a policy defined in `mgw-register.hcl`: + +You can specify an admin partition when creating policies in Consul Enterprise. The policy is only valid in the specified admin partition. You must create the policy in the partition where the mesh gateway registers. The following example creates the policy in the partition `ptn1`. + +```shell-session +$ consul acl policy create -partition "ptn1" \ + -name mgw-register -rules @mgw-register.hcl \ + -description "Mesh gateway policy" +``` + +Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. The following example registers the policy defined in `mgw-register.hcl`. You must embed policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + –-header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "mgw-register", + "Description": "Mesh gateway policy", + "Partition": "ptn1", + "Rules": "mesh = \"write\"\npeering = \"read\"\nnamespace \"default\" {\n service \"mesh-gateway\" {\n policy = \"write\"\n }\n agent_prefix \"\" {\n policy = \"read\"\n }\n}\nnamespace_prefix \"\" {\n node_prefix \"\" {\n \tpolicy = \"read\"\n }\n service_prefix \"\" {\n policy = \"read\"\n }\n}\n" +}' +``` + +Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + + + + + +### Link the policy to a token + +After registering the policy into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +You can specify an admin partition when creating tokens in Consul Enterprise. The token is only valid in the specified admin partition. The token must be created in the partition where the mesh gateway registers. The following example creates the token in the partition `ptn1`. + +```shell-session +$ consul acl token create -partition "ptn1" \ + -description "Mesh gateway token" \ + -policy-name "mgw-register" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +You can specify an admin partition when creating tokens in Consul Enterprise. The token is only valid in the specified admin partition. The token must be created in the partition where the mesh gateway registers. The following example creates the token in the partition `ptn1`. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + –-header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "mgw-register" + } + ], + "Partition": "ptn1" +}' +``` + + + + diff --git a/website/content/docs/security/acl/tokens/create/create-a-replication-token.mdx b/website/content/docs/security/acl/tokens/create/create-a-replication-token.mdx new file mode 100644 index 000000000000..f38f4682fcc2 --- /dev/null +++ b/website/content/docs/security/acl/tokens/create/create-a-replication-token.mdx @@ -0,0 +1,312 @@ +--- +layout: docs +page_title: Create tokens for service registration +description: >- + Learn how to create ACL tokens that a server agent in a secondary datacenter can use for ACL token replication between WAN-federated datacenters. +--- + +# Create a replication token + +This topic describes how to configure an ACL token for ACL replication between WAN-federated datacenters. If your Consul clusters are connected through peer connections, ACL replication is not required. To learn more about cluster peering, refer to the [comparison between WAN federation and cluster peering](/consul/docs/connect/cluster-peering#compared-with-wan-federation). + +## Introduction + +Consul agents must present a token linked to policies that grant the appropriate set of permissions. +Specify the [`replication`](/consul/docs/agent/config/config-files#acl_tokens_replication) token on each server in a non-primary datacenter. For hands-on instructions on how to configure ACL replication across datacenters, refer to the [ACL Replication for Multiple Datacenters](/consul/tutorials/security-operations/access-control-replication-multiple-datacenters) tutorial. + + +## Requirements + +Core ACL functionality is available in all versions of Consul. + +For a Consul server agent with ACL replication enabled in a secondary datacenter, the token must be linked to a policy that grants the following permissions: + +* `acl:write`: Enables replication of ACL resources +* `operator:write`: Enables replication of the proxy-defaults configuration entry and enables CA certification signing in the secondary datacenter +* `service:read` and `intention:read`: Enables replication of the service-defaults and intentions configuration entries + +@include 'create-token-requirements.mdx' + +## Replication token in Consul OSS + +To create a token for ACL replication, you must define a policy, register the policy with Consul, and link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The policy grants the appropriate permissions for ACL replication. + + + +```hcl +acl = "write" +operator = "write" +service_prefix "" { + policy = "read" + intentions = "read" +} +``` + +```json +{ + "acl": "write", + "operator": "write", + "service_prefix": { + "": [{ + "intentions": "read", + "policy": "read" + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policy, you can register the policy with Consul using the command line or API endpoint. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + +The following example registers a policy defined in `acl-replication.hcl`. + +```shell-session +$ consul acl policy create \ + -name "acl-replication" -rules @acl-replication.hcl \ + -description "ACL replication token" +``` + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + +The following example registers the policy defined in `acl-replication.hcl`. You must embed policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "acl-replication", + "Description": "ACL replication", + "Rules": "acl = \"write\"\noperator = \"write\"\nservice_prefix \"\" {\n policy = \"read\"\n intentions = \"read\"\n}\n" +}' +``` + + + + + +### Link the policy to a token + +After registering the policy into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an auth method. + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +The following command creates the ACL token linked to the policy `acl-replication`. + +```shell-session +$ consul acl token create \ + -description "ACL replication" \ + -policy-name "acl-replication" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +The following example creates the ACL token linked to the policy `acl-replication`. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "acl-replication" + } + ] +}' +``` + + + + + +## Replication token in Consul Enterprise + +To create a token for ACL replication, you must define a policy, register the policy with Consul, and link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The following example policy grants the appropriate permissions for ACL replication. + + + +```hcl +operator = "write" +service_prefix "" { + policy = "read" + intentions = "read" +} +namespace_prefix "" { + acl = "write" + service_prefix "" { + policy = "read" + intentions = "read" + } +} +``` + +```json +{ + "namespace_prefix": { + "": [{ + "acl": "write", + "service_prefix": { + "": [{ + "intentions": "read", + "policy": "read" + }] + } + }] + }, + "operator": "write", + "service_prefix": { + "": [{ + "intentions": "read", + "policy": "read" + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policy, you can register the policy with Consul using the command line or API endpoint. + +You can specify an admin partition, namespace, or both when registering policies in Consul Enterprise. Policies are only valid in the specified scopes. The policy for replication must be created in the `default` namespace and `default` partition. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + +The following example registers a policy defined in `acl-replication.hcl`. + +```shell-session +$ consul acl policy create -partition "default" -namespace "default" \ + -name "acl-replication" -rules @acl-replication.hcl \ + -description "ACL replication token" +``` + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + +The following example registers the policy defined in `acl-replication.hcl`. You must embed policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "acl-replication", + "Description": "ACL replication", + "Partition": "default", + "Namespace": "default", + "Rules": "operator = \"write\"\nservice_prefix \"\" {\n policy = \"read\"\n intentions = \"read\"\n}\nnamespace_prefix \"\" {\n acl = \"write\"\n service_prefix \"\" {\n policy = \"read\"\n intentions = \"read\"\n }\n}\n" +}' +``` + + + + + +### Link the policy to a token + +After registering the policy into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +```shell-session +$ consul acl token create -partition "default" -namespace "default" \ + -description "ACL replication" \ + -policy-name "acl-replication" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +The following example creates the ACL token linked to the policy `acl-replication`. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "acl-replication" + } + ], + "Partition": "default", + "Namespace": "default" +}' +``` + + + + + +## Apply the token + +Configure the Consul agent with the token by either specifying the token in the agent configuration file or by using the `consul set-agent-token` command. + +### Apply the token in a file + +Specify the token in the [`replication`](/consul/docs/agent/config/config-files#acl_tokens_replication) field of the agent configuration file so that the agent can present it and register into the catalog on startup. + +```hcl +acl = { + enabled = true + tokens = { + replication = "" + ... + } + ... +} +``` + +### Apply the token with a command + +Set the `replication` token using the [`consul set-agent-token`](/consul/commands/acl/set-agent-token) command. The following command configures a running Consul agent token with the specified token. + +```shell-session +$ consul set-agent-token replication +``` + diff --git a/website/content/docs/security/acl/tokens/create/create-a-service-token.mdx b/website/content/docs/security/acl/tokens/create/create-a-service-token.mdx new file mode 100644 index 000000000000..125390b39830 --- /dev/null +++ b/website/content/docs/security/acl/tokens/create/create-a-service-token.mdx @@ -0,0 +1,416 @@ +--- +layout: docs +page_title: Create tokens for service registration +description: >- + Learn how to create ACL tokens that your services can present to Consul servers so that they can register with the Consul catalog. +--- + +# Create a service token + +This topic describes how to create a token that you can use to register a service and discover services in the Consul catalog. If you are using Consul service mesh, a sidecar proxy can use the token to discover and route traffic to other services. + +## Introduction + +Services must present a token linked to policies that grant the appropriate set of permissions in order to be discoverable or to interact with other services in a mesh. + +### Service identities versus custom policies + +You can create tokens linked to custom policies or to service identities. [Service identities](/consul/docs/security/acl#service-identities) are constructs in Consul that enable you to quickly grant permissions for a group of services, rather than creating similar policies for each service. + +We recommend using a service identity to grant permissions for service discovery and service mesh use cases rather than creating a custom policy. This is because service identities automatically grant the service and its sidecar proxy `service:write`, `service:read`, and `node:read`. + +Your organization may have requirements or processes for deploying services in a way that is inconsistent with service and node identities. In these cases, you can create custom policies and link them to tokens. + +## Requirements + +Core ACL functionality is available in all versions of Consul. + +The service token must be linked to policies that grant the following permissions: + +* `service:write`: Enables the service to update the catalog. If service mesh is enabled, the service's sidecar proxy can also update the catalog. Note that this permission implicitly grants `intention:read` permission to sidecar proxies so that they can read and enforce intentions. Refer to [Intention Management Permissions](/consul/docs/connect/intentions#intention-management-permissions) for details. +* `service:read`: Enables the service to learn about other services in the network. If service mesh is enabled, the service's sidecar proxy can also learn about other services in the network. +* `node:read`: Enables the sidecar proxy to discover and route traffic to other services in the catalog if service mesh is enabled. + +@include 'create-token-requirements.mdx' + +## Service identity in Consul OSS + +Refer to [Service identities](/consul/docs/security/acl#service-identities) for information about creating service identities that you can link to tokens. + +You can manually create tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy or service identity to link to create a token. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +The following example creates an ACL token linked to a service identity for a service named `svc1`. + +```shell-session +$ consul acl token create \ + -description "Service token for svc1" \ + -service-identity "svc1" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify a service identity in the request body to create a token linked to the service identity. An ACL token linked to a policy with permissions to use the API endpoint is required. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +The following example creates a token linked to a service identity named `svc1`: + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "ServiceIdentities": [ + { + "ServiceName": "svc1" + } + ] +}' +``` + + + + + +## Service identity in Consul Enterprise + +Refer to [Service identities](/consul/docs/security/acl#service-identities) for information about creating service identities that you can link to tokens. + +You can manually create tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy or service identity to link to create a token. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +You can specify an admin partition, namespace, or both when creating tokens in Consul Enterprise. The token can only include permissions in the specified scope, if any. The following example creates an ACL token that the service can use to register in the `ns1` namespace of partition `ptn1`: + +```shell-session +$ consul acl token create -partition "ptn1" -namespace "ns1" \ + -description "Service token for svc1" \ + -service-identity "svc1" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify a service identity in the request body to create a token linked to the service identity. An ACL token linked to a policy with permissions to use the API endpoint is required. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +You can specify an admin partition and namespace when creating tokens in Consul Enterprise. The token is only valid in the specified scopes. The following example creates an ACL token that the service can use to register in the `ns1` namespace of partition `ptn1`: + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "ServiceIdentities": [ + { + "ServiceName": "svc1" + } + ], + "Namespace": "ns1", + "Partition": "ptn1" +}' +``` + + + + + +## Custom policy in Consul OSS + +When you are unable to link tokens to a service identity, you can define policies, register them with Consul, and link the policies to tokens that enable services to register into the Consul catalog. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The policy grants the `svc1` service `write` permissions so that it can register into the catalog. For service mesh, the policy grants the `svc1-sidecar-proxy` service `write` permissions so that the sidecar proxy can register into the catalog. It grants service and node `read` permissions to discover and route to other services. + + + +```hcl +service "svc1" { + policy = "write" +} +service "svc1-sidecar-proxy" { + policy = "write" +} +service_prefix "" { + policy = "read" +} +node_prefix "" { + policy = "read" +} +``` + +```json +{ + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "service": { + "svc1": [{ + "policy": "write" + }], + "svc1-sidecar-proxy": [{ + "policy": "write" + }] + }, + "service_prefix": { + "": [{ + "policy": "read" + }] + } +} +``` + + + + +### Register the policy with Consul + +After defining the policies, you can register them with Consul using the command line or API endpoint. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. The following example registers a policy defined in `svc1-register.hcl`: + + +```shell-session +$ consul acl policy create \ + -name "svc1-register" -rules @svc1-register.hcl \ + -description "Allow svc1 to register into the catalog" +``` + +Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl token create` command. + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. The following example registers the policy defined in `svc1-register.hcl`. You must embed policy rules in the `Rules` field of the request body + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "svc1-register", + "Description": "Allow svc1 to register into the catalog", + "Rules": "service \"svc1\" {\n policy = \"write\"\n}\nservice \"svc1-sidecar-proxy\" {\n policy = \"write\"\n}\nservice_prefix \"\" {\n policy = \"read\"\n}\nnode_prefix \"\" {\n policy = \"read\"\n}\n" +}' +``` + +Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + + + + + +### Link the policy to a token + +After registering the policies into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +The following commands create the ACL token linked to the policy `svc1-register`. + +```shell-session +$ consul acl token create \ + -description "Service token for svc1" \ + -policy-name "svc1-register" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +The following example creates an ACL token that the `svc1` service can use to register in the `ns1` namespaces of partition `ptn1`: + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "svc1-register" + } + ] +}' +``` + + + + + +## Custom policy in Consul Enterprise + +When you are unable to link tokens to a service identity, you can define policies, register them with Consul, and link the policies to tokens that enable services to register into the Consul catalog. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +You can specify an admin partition and namespace when creating policies in Consul Enterprise. The policy is only valid in the specified scopes. + +The following example policy is defined in a file. The policy allows the `svc1` service to register in the `ns1` namespace of partition `ptn1`. For service mesh, the policy grants the `svc1-sidecar-proxy` service `write` permissions so that the sidecar proxy can register into the catalog. It grants service and node `read` permissions to discover and route to other services. + + + +```hcl +partition "ptn1" { + namespace "ns1" { + service "svc1" { + policy = "write" + } + service "svc1-sidecar-proxy" { + policy = "write" + } + service_prefix "" { + policy = "read" + } + node_prefix "" { + policy = "read" + } + } +} +``` + +```json +{ + "partition": { + "ptn1": [{ + "namespace": { + "ns1": [{ + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "service": { + "svc1": [{ + "policy": "write" + }], + "svc1-sidecar-proxy": [{ + "policy": "write" + }] + }, + "service_prefix": { + "": [{ + "policy": "read" + }] + } + }] + } + }] + } +} +``` + + + + +### Register the policy with Consul + +After defining the policies, you can register them with Consul using the command line or API endpoint. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. The following example registers a policy defined in `svc1-register.hcl`: + + +```shell-session +$ consul acl policy create -partition "ptn1" -namespace "ns1" \ + -name "svc1-register" -rules @svc1-register.hcl \ + -description "Custom policy for service svc1" +``` + +Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl token create` command. + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. The following example registers the policy defined in `svc1-register.hcl`. You must embed policy rules in the `Rules` field of the request body + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "svc1-register", + "Description": "Allow svc1 to register into the catalog", + "Namespace": "ns1", + "Partition": "ptn1", + "Rules": "partition \"ptn1\" {\n namespace \"ns1\" {\n service \"svc1\" {\n policy = \"write\"\n }\n service \"svc1-sidecar-proxy\" {\n policy = \"write\"\n }\n service_prefix \"\" {\n policy = \"read\"\n }\n node_prefix \"\" {\n policy = \"read\"\n }\n }\n}\n" +}' +``` + +Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + + + + + +### Link the policy to a token + +After registering the policies into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +You can specify an admin partition and namespace when creating tokens in Consul Enterprise. The token is only valid in the specified scopes. The following example creates an ACL token that the service can use to register in the `ns1` namespace of partition `ptn1`: + +The following commands create the ACL token linked to the policy `svc1-register`. + +```shell-session +$ consul acl token create -partition "ptn1" -namespace "ns1" \ + -description "Service token for svc1" \ + -policy-name "svc1-register" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +You can specify an admin partition and namespace when creating tokens in Consul Enterprise. The token is only valid in the specified scopes. The following example creates an ACL token that the service can use to register in the `ns1` namespace of partition `ptn1`: + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "svc1-register" + } + ], + "Namespace": "ns1", + "Partition": "ptn1" +}' +``` + + + + diff --git a/website/content/docs/security/acl/tokens/create/create-a-snapshot-agent-token.mdx b/website/content/docs/security/acl/tokens/create/create-a-snapshot-agent-token.mdx new file mode 100644 index 000000000000..374498a93d75 --- /dev/null +++ b/website/content/docs/security/acl/tokens/create/create-a-snapshot-agent-token.mdx @@ -0,0 +1,173 @@ +--- +layout: docs +page_title: Create tokens for snapshot agents +description: >- + Learn how to create an ACL token for the Consul snapshot agent. +--- + +# Create a snapshot agent token + +This topic describes how to create a token for the Consul snapshot agent. + + + +## Introduction + +The `consul snapshot agent` command starts a process that takes snapshots of the state of the Consul +servers and either saves them locally or pushes them to a remote storage service. Refer to [Consul Snapshot Agent](/consul/commands/snapshot/agent) for additional information. + +## Requirements + +Core ACL functionality is available in all versions of Consul. + +### Requirements for the `agent` command + +The [`agent`](/consul/commands/snapshot/agent) subcommand requires [Consul Enterprise](https://www.hashicorp.com/products/consul/). All other [`snapshot` subcommands](/consul/commands/snapshot) are available in the open source version of Consul. + +### Snapshot agent ACL requirements + +The Consul snapshot agent must present a token linked to policies that grant the following set of permissions. + +* `acl:write`: Enables the agent read and snapshot ACL data +* `key:write`: Enables the agent to create a key in the Consul KV store that serves as a leader election lock when multiple snapshot agents are running in an environment +* `session:write`: Enables the agent to create sessions for the specified Consul node where it is running +* `service:write`: Enables the agent to register into the catalog + +@include 'create-token-requirements.mdx' + +## Create a token + +To create a token for the snapshot agent, you must define a policy, register the policy with Consul, and link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The policy grants the appropriate permissions for a snapshot agent running on a node named `server-1234` to register into the catalog as the `consul-snapshot` service. It uses the key `consul-snapshot/lock` for a leader election lock. + + + +```hcl +acl = "write" +key "consul-snapshot/lock" { + policy = "write" +} +session "server-1234" { + policy = "write" +} +service "consul-snapshot" { + policy = "write" +} +``` + +```json +{ + "acl": "write", + "key": { + "consul-snapshot/lock": [{ + "policy": "write" + }] + }, + "service": { + "consul-snapshot": [{ + "policy": "write" + }] + }, + "session": { + "server-1234": [{ + "policy": "write" + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policy, you can register the policy with Consul using the command line or API endpoint. + +You can specify an admin partition and namespace when creating policies in Consul Enterprise. Policies are only valid in the specified scopes. You must create the policy for the snapshot agent in the `default` namespace in the `default` partition. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + +The following example registers a policy defined in `snapshot-agent.hcl`: + +```shell-session +$ consul acl policy create -partition "default" -namespace "default" \ + -name snapshot-agent -rules @snapshot-agent.hcl \ + -description "Snapshot agent policy" +``` + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + +The following example registers the policy defined in `snapshot-agent.hcl`. You must embed policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "snapshot-agent", + "Description": "Snapshot agent policy", + "Partition": "default", + "Namespace": "default", + "Rules": "acl = \"write\"\nkey \"consul-snapshot/lock\" {\n policy = \"write\"\n}\nsession \"server-1234\" {\n policy = \"write\"\n}\nservice \"consul-snapshot\" {\n policy = \"write\"\n}\n" +}' +``` + + + + + +### Link the policy to a token + +After registering the policies into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + +You can specify an admin partition and namespace when creating tokens in Consul Enterprise. Tokens are only valid in the specified scopes. The snapshot agent token must be created in the `default` namespace in the `default` partition. + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +The following command creates the ACL token linked to the policy `snapshot-agent`. + +```shell-session +$ consul acl token create -partition "default" -namespace "default" \ + -description "Snapshot agent token" \ + -policy-name "snapshot-agent" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "snapshot-agent" + } + ], + "Partition": "default", + "Namespace": "default" +}' +``` + + + + + diff --git a/website/content/docs/security/acl/tokens/create/create-a-terminating-gateway-token.mdx b/website/content/docs/security/acl/tokens/create/create-a-terminating-gateway-token.mdx new file mode 100644 index 000000000000..5ba304a9f84b --- /dev/null +++ b/website/content/docs/security/acl/tokens/create/create-a-terminating-gateway-token.mdx @@ -0,0 +1,352 @@ +--- +layout: docs +page_title: Create a token for terminating gateway registration +description: >- + Learn how to create ACL tokens that your terminating gateway can present to Consul servers so that they can register with the Consul catalog. +--- + +# Create a terminating gateway token + +This topic describes how to create an ACL token that enables a terminating gateway to register with Consul. + +## Introduction + +Terminating gateways enable connectivity within your organizational network from services in the Consul service mesh to services and destinations outside the mesh. + +To learn how to configure terminating gateways, refer to the [Terminating Gateways](/consul/docs/connect/gateways/terminating-gateway#terminating-gateway-configuration) documentation and the [Understand Terminating Gateways](/consul/tutorials/developer-mesh/service-mesh-terminating-gateways) tutorial. + +## Requirements + +Core ACL functionality is available in all versions of Consul. + +The terminating gateway token must be linked to policies that grant the appropriate set of permissions in order to be discoverable and to forward traffic out of the mesh. The following permissions are required: + +* `service:write` to allow the terminating gateway to register into the catalog +* `service:write` for each service that it forwards traffic for +* `node:read` for the nodes of each service that it forwards traffic for +* `service:read` for all services and `node:read` for all nodes in order to discover and route to services +* `agent:read` to enable the `consul connect envoy` CLI command to automatically discover gRPC settings from the Consul agent. If this command is not used to start the gateway or if the Consul agent uses the default gRPC settings, then you can omit the `agent:read` permission. + +@include 'create-token-requirements.mdx' + +## Consul OSS + +To create a token for the terminating gateway, you must define a policy, register the policy with Consul, and link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The policy grants the appropriate permissions to register as a service named `terminating-gateway` and to operate as a terminating gateway. For this example, the terminating gateway forwards traffic for two services named `external-service-1` and `external-service-2`. The policy examples include `service:write` permissions for these services. If you have additional services, your policy must include `service:write` permissions for the additional services to be included in the policy rules. + + + +```hcl +service "terminating-gateway" { + policy = "write" +} +service "external-service-1" { + policy = "write" +} +service "external-service-2" { + policy = "write" +} +node_prefix "" { + policy = "read" +} +agent_prefix "" { + policy = "read" +} +``` + +```json +{ + "service": { + "terminating-gateway": [{ + "policy": "write" + }], + "external-service-1": [{ + "policy": "write" + }], + "external-service-2": [{ + "policy": "write" + }] + }, + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "agent_prefix": { + "": [{ + "policy": "read" + }] + } +} +``` + + + + +### Register the policy with Consul + +After defining the policy, you can register the policy with Consul using the command line or API endpoint. + +The following commands create the ACL policy and token. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. The following example registers a policy defined in `tgw-register.hcl`: + +```shell-session +$ consul acl policy create \ + -name "tgw-register" -rules @tgw-register.hcl \ + -description "Terminating gateway policy" +``` + +Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. The following example registers the policy defined in `tgw-register.hcl`. You must embed policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "tgw-register", + "Description": "Terminating gateway policy", + "Rules": "service \"terminating-gateway\" {\n policy = \"write\"\n}\nservice \"external-service-1\" {\n policy = \"write\"\n}\nservice \"external-service-2\" {\n policy = \"write\"\n}\nnode_prefix \"\" {\n policy = \"read\"\n}\nagent_prefix \"\" {\n policy = \"read\"\n}\n" +}' +``` + +Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + + + + + +### Link the policy to a token + +After registering the policy into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +The following command creates the ACL token linked to the policy `tgw-register`. + +```shell-session +$ consul acl token create \ + -description "Terminating gateway token" \ + -policy-name "tgw-register" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "tgw-register" + } + ] +}' +``` + + + + + +## Consul Enterprise + +To create a token for the terminating gateway, you must define a policy, register the policy with Consul, and link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +You can specify an admin partition and namespace when creating policies in Consul Enterprise. The policy is only valid in the specified scopes. + +The following example policy is defined in a file. The policy grants the appropriate permissions for a terminating gateway to register as a service named `terminating-gateway` in namespace `ns1` in partition `ptn1`. + +For this example, the terminating gateway forwards traffic for the following two services: + +* `external-service-1` in the `default` namespace +* `external-service-2` in the `ns1` namespace + +The policy examples include `service:write` permissions for these services. If you have additional services, your policy must include `service:write` permissions for the additional services to be included in the policy rules. + +The policy contains permissions for resources in multiple namespaces. You must create ACL policies that grant permissions for multiple namespaces in the `default` namespace. + + + +```hcl +partition "ptn1" { + namespace "ns1" { + service "terminating-gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } + service "external-service-2" { + policy = "write" + } + } + namespace "default" { + service "external-service-1" { + policy = "write" + } + node_prefix "" { + policy = "read" + } + agent_prefix "" { + policy = "read" + } + } +} +``` + +```json +{ + "partition": { + "ptn1": [{ + "namespace": { + "default": [{ + "agent_prefix": { + "": [{ + "policy": "read" + }] + }, + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "service": { + "external-service-1": [{ + "policy": "write" + }] + } + }], + "ns1": [{ + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "service": { + "external-service-2": [{ + "policy": "write" + }], + "terminating-gateway": [{ + "policy": "write" + }] + } + }] + } + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policy, you can register the policy with Consul using the command line or API endpoint. + +You can specify an admin partition and namespace when creating policies in Consul Enterprise. The policy is only valid in the specified admin partition and namespace. You must create the policy in the same partition where the terminating gateway is registered. If the terminating gateway requires permissions for multiple namespaces, then the policy must be created in the `default` namespace. The following example creates the policy in the partition `ptn1` and `default` namespace because the example policy contains permissions for multiple namespaces. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. The following example registers a policy defined in `tgw-register.hcl`: + +```shell-session +$ consul acl policy create -partition "ptn1" -namespace "default" \ + -name "tgw-register" -rules @tgw-register.hcl \ + -description "Terminating gateway policy" +``` + +Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. The following example registers the policy defined in `tgw-register.hcl`. You must embed policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "tgw-register", + "Description": "Terminating gateway policy", + "Partition": "ptn1", + "Namespace": "default", + "Rules": "partition \"ptn1\" {\n namespace \"ns1\" {\n service \"terminating-gateway\" {\n policy = \"write\"\n }\n node_prefix \"\" {\n policy = \"read\"\n }\n service \"external-service-2\" {\n policy = \"write\"\n }\n }\n namespace \"default\" {\n service \"external-service-1\" {\n policy = \"write\"\n }\n node_prefix \"\" {\n policy = \"read\"\n }\n agent_prefix \"\" {\n policy = \"read\"\n }\n }\n}\n" +}' +``` + +Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + + + + + +### Link the policy to a token + +After registering the policy into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + +You can specify an admin partition when creating tokens in Consul Enterprise. The token is only valid in the specified admin partition. You must create the token in the partition where the terminating gateway is registered. If the terminating gateway requires permissions for multiple namespaces, then the token must be created in the `default` namespace. The following example creates the token in the `default` namespace in the `ptn1` partition because the example policy contains permissions for multiple namespaces. + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +```shell-session +$ consul acl token create -partition "ptn1" -namespace "default" \ + -description "Terminating gateway token" \ + -policy-name "tgw-register" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "tgw-register" + } + ], + "Partition": "ptn1", + "Namespace": "default" +}' +``` + + + + diff --git a/website/content/docs/security/acl/tokens/create/create-a-token-for-vault-consul-storage.mdx b/website/content/docs/security/acl/tokens/create/create-a-token-for-vault-consul-storage.mdx new file mode 100644 index 000000000000..ab2c04061499 --- /dev/null +++ b/website/content/docs/security/acl/tokens/create/create-a-token-for-vault-consul-storage.mdx @@ -0,0 +1,164 @@ +--- +layout: docs +page_title: Create tokens for service registration +description: Learn how to create an ACL token for Vault’s Consul storage backend. +--- + +# Create a token for Vault with Consul storage backend + +This topic describes how to create a token for Vault’s Consul storage backend. + +## Introduction + +If you are using Vault to manage secrets in your infrastructure, you can configure Vault to use Consul's key/value (KV) store as backend storage to persist Vault's data. Refer to the [Consul KV documentation](/consul/docs/dynamic-app-config/kv) and the [Vault storage documentation](/vault/docs/configuration/storage) for additional information. + +## Requirements + +Core ACL functionality is available in all versions of Consul. + +The Vault Consul storage backend must present a token linked to policies that grant the following permissions: + +* `agent:read`: Provides KV visibility to all agents +* `key:write`: Enables writing to the KV store +* `service:write`: Enables the Vault service to register into the catalog +* `session:write`: Enables the agent to initialize a new session + +@include 'create-token-requirements.mdx' + +## Create a token linked to a policy + +To create a token for Vault’s Consul storage backend, you must define a policy, register the policy with Consul, and link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The policy grants the appropriate permissions to enable Vault to register as a service named `vault` and provides access to the `vault/` path in Consul's KV store. + + + +```hcl +agent_prefix "" { + policy = "read" +} +key_prefix "vault/" { + policy = "write" +} +service "vault" { + policy = "write" +} +session_prefix "" { + policy = "write" +} +``` + +```json +{ + "agent_prefix": { + "": [{ + "policy": "read" + }] + }, + "key_prefix": { + "vault/": [{ + "policy": "write" + }] + }, + "service": { + "vault": [{ + "policy": "write" + }] + }, + "session_prefix": { + "": [{ + "policy": "write" + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policy, you can register the policy with Consul using the command line or API endpoint. + + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + +The following example registers a policy defined in `vault-storage-backend.hcl`. + +```shell-session +$ consul acl policy create -partition "default" -namespace "default" \ + -name vault-storage-backend -rules @vault-storage-backend.hcl \ + -description "Policy for the Vault Consul storage backend" +``` + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + +The following example registers the policy defined in `vault-storage-backend.hcl`. You must embed policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "vault-storage-backend", + "Description": "Policy for the Vault Consul storage backend", + "Rules": "agent_prefix \"\" {\n policy = \"read\"\n}\nkey_prefix \"vault/\" {\n policy = \"write\"\n}\nservice \"vault\" {\n policy = \"write\"\n}\nsession_prefix \"\" {\n policy = \"write\"\n}\n" +}' +``` + + + + + +### Link the policy to a token + +After registering the policy into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +The following command creates the ACL token linked to the policy `vault-storage-backend`. + +```shell-session +$ consul acl token create \ + -description "Token for the Vault Consul storage backend" \ + -policy-name "vault-storage-backend" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +The following example creates the ACL token linked to the policy `vault-storage-backend`. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "vault-storage-backend" + } + ] +}' +``` + + + + + diff --git a/website/content/docs/security/acl/tokens/create/create-a-ui-token.mdx b/website/content/docs/security/acl/tokens/create/create-a-ui-token.mdx new file mode 100644 index 000000000000..9c1e9019b5e7 --- /dev/null +++ b/website/content/docs/security/acl/tokens/create/create-a-ui-token.mdx @@ -0,0 +1,557 @@ +--- +layout: docs +page_title: Create tokens for agent registration +description: >- + Learn how to create ACL tokens that your Consul agents can present to Consul servers so that they can join the Consul cluster. +--- + +# Create a UI token + +This topic describes how to create a token that you can use to view resources in the Consul UI. + +## Introduction + +To navigate the Consul UI when ACLs are enabled, log into the UI with a token linked to policies that grant an appropriate set of permissions. The UI is unable to display resources that the token does not have permission to access. + +## Requirements + +Core ACL functionality is available in all versions of Consul. + +@include 'create-token-requirements.mdx' + +## View catalog in Consul OSS + +This section describes how to create a token that grants read-only access to the catalog. This token allows users to view the catalog without the ability to make changes. To create the ACL token, define a policy, create the policy, and then link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The policy allows users that login with the token to view all services and nodes in the catalog. + + + +```hcl +service_prefix "" { + policy = "read" +} +node_prefix "" { + policy = "read" +} +``` + +```json +{ + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "service_prefix": { + "": [{ + "policy": "read" + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policies, you can register them with Consul using the command line or API endpoint. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. The following example registers a policy defined in `ui-view-catalog.hcl`. + +```shell-session +$ consul acl policy create \ + -name "ui-view-catalog" -rules @ui-view-catalog.hcl \ + -description "Allow viewing the catalog" +``` + +Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. The following example registers the policy defined in `view-catalog.hcl`. You must embed the policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "ui-view-catalog", + "Description": "Allow viewing the catalog", + "Rules": "service_prefix \"\" {\n policy = \"read\"\n}\nnode_prefix \"\" {\n policy = \"read\"\n}\n" +}' +``` + + + + + +### Link the policy to a token + +After registering the policies into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +The following command creates the ACL token linked to the policy `ui-view-catalog`. + +```shell-session +$ consul acl token create \ + -description "UI token to view the catalog" \ + -policy-name "ui-view-catalog" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +The following example creates an ACL token that you can use to login to the UI and view the catalog. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "ui-view-catalog" + } + ] +}' +``` + + + + + +## View catalog in Consul Enterprise + +This section describes how to create a token that grants read-only access to the catalog. This token allows users to view the catalog without the ability to make changes. To create the ACL token, define a policy, create the policy, and then link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The following policy allows users that log in with the token to view services and nodes in the catalog in any partition and in any namespace. The `operator:read` permission is needed to list partitions. Without this permission, you can still view resources within a partition but cannot easily navigate to other partitions in the Consul UI. + + + +```hcl +operator = "read" +partition_prefix "" { + namespace_prefix "" { + service_prefix "" { + policy = "read" + } + node_prefix "" { + policy = "read" + } + } +} +``` + +```json +{ + "partition_prefix": { + "": [{ + "namespace_prefix": { + "": [{ + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "service_prefix": { + "": [{ + "policy": "read" + }] + } + }] + } + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policies, you can register them with Consul using the command line or API endpoint. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. The following example registers a policy defined in `ui-view-catalog.hcl`. + +You can specify an admin partition and namespace when registering policies in Consul Enterprise. Policies are only valid in the scopes specified during registration, but you can grant tokens registered in the `default` partition permission to access resources in a different partition than where the token was registered. Refer to the [admin partition documentation](/consul/docs/enterprise/admin-partitions#default-admin-partition) for additional information. + +The following example registers the policy in the `default` partition and the `default` namespace because the policy grants cross-partition and cross-namespace access. + +```shell-session +$ consul acl policy create -partition "default" -namespace "default" \ + -name "ui-view-catalog" -rules @ui-view-catalog.hcl \ + -description "Allow viewing the catalog" +``` + +Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. The following example registers the policy defined in `view-catalog.hcl`. You must embed the policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "ui-view-catalog", + "Description": "Allow viewing the catalog", + "Partition": "default", + "Namespace": "default", + "Rules": "partition_prefix \"\" {\n namespace_prefix \"\" {\n service_prefix \"\" {\n policy = \"read\"\n }\n node_prefix \"\" {\n policy = \"read\"\n }\n }\n}\n" +}' +``` + + + + + +### Link the policy to a token + +After registering the policies into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +```shell-session +$ consul acl token create -partition "default" -namespace "default" \ + -description "UI token to view the catalog" \ + -policy-name "ui-view-catalog" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +You can specify an admin partition and namespace when registering policies in Consul Enterprise. Policies are only valid in the scopes specified during registration, but you can grant tokens registered in the `default` partition permission to access resources in a different partition than where the token was registered. Refer to the [admin partition documentation](/consul/docs/enterprise/admin-partitions#default-admin-partition) for additional information. + +The following example registers the policy in the `default` partition and the `default` namespace because the policy grants cross-partition and cross-namespace access. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "ui-view-catalog" + } + ], + "Partition": "default", + "Namespace": "default" +}' +``` + + + + + +## View all resources in Consul OSS + +This section describes how to create a token with read-only access to all resources in the Consul UI. This token allows users to view any resources without the ability to make changes. To create the ACL token, define a policy, create the policy, and then link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The policy allows users that log in with the token to view all services and nodes in the catalog, all objects in the key/value store, all intentions, and all ACL resources. The `acl:read` permission does not allow viewing the token secret ids. + + + +```hcl +acl = "read" +key_prefix "" { + policy = "read" +} +node_prefix "" { + policy = "read" +} +operator = "read" +service_prefix "" { + policy = "read" + intentions = "read" +} +``` + +```json +{ + "acl": "read", + "key_prefix": { + "": [{ + "policy": "read" + }] + }, + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "operator": "read", + "service_prefix": { + "": [{ + "intentions": "read", + "policy": "read" + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policies, you can register them with Consul using the command line or API endpoint. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. The following example registers a policy defined in `ui-view-all.hcl`. + +```shell-session +$ consul acl policy create \ + -name "ui-view-all" -rules @ui-view-all.hcl \ + -description "Allow viewing all resources" +``` + +Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. The following example registers the policy defined in `ui-view-all.hcl`. You must embed the policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "ui-view-all", + "Description": "Allow viewing all resources", + "Rules": "acl = \"read\"\nkey_prefix \"\" {\n policy = \"read\"\n}\nnode_prefix \"\" {\n policy = \"read\"\n}\noperator = \"read\"\nservice_prefix \"\" {\n policy = \"read\"\n intentions = \"read\"\n}\n" +}' +``` + + + + + +### Link the policy to a token + +After registering the policies into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +The following command creates the ACL token linked to the policy `ui-view-all`. + +```shell-session +$ consul acl token create \ + -description "UI token to view all resources" \ + -policy-name "ui-view-all" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +The following example creates an ACL token that you can use to login to the UI and view the catalog. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "ui-view-all" + } + ] +}' +``` + + + + + +## View all resources in Consul Enterprise + +This section describes how to create a token with read-only access to all resources in the Consul UI. This token allows users to view any resources without the ability to make changes. To create the ACL token, define a policy, create the policy, and then link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The policy allows users that log in with the token to view all services and nodes in the catalog, all objects in the key-value store, all intentions, and all ACL resources in any namespace and any partition. The `acl:read` permission does not allow viewing the token secret ids. + + + +```hcl +operator = "read" +partition_prefix "" { + namespace_prefix "" { + acl = "read" + key_prefix "" { + policy = "read" + } + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + intentions = "read" + } + } +} +``` + +```json +{ + "operator": "read", + "partition_prefix": { + "": [{ + "namespace_prefix": { + "": [{ + "acl": "read", + "key_prefix": { + "": [{ + "policy": "read" + }] + }, + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "service_prefix": { + "": [{ + "intentions": "read", + "policy": "read" + }] + } + }] + } + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policies, you can register them with Consul using the command line or API endpoint. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. The following example registers a policy defined in `ui-view-all.hcl`. + +You can specify an admin partition and namespace when creating policies in Consul Enterprise. The policy is only valid in the specified scopes. Because the policy grants cross-partition and cross-namespace access, the policy must be created in the `default` partition and the `default` namespace. + +```shell-session +$ consul acl policy create -partition "default" -namespace "default" \ + -name "ui-view-all" -rules @ui-view-all.hcl \ + -description "Allow viewing all resources" +``` + +Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. The following example registers the policy defined in `ui-view-all.hcl`. You must embed the policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "ui-view-all", + "Description": "Allow viewing all resources", + "Partition": "default", + "Namespace": "default", + "Rules": "operator = \"read\"\npartition_prefix \"\" {\n namespace_prefix \"\" {\n acl = \"read\"\n key_prefix \"\" {\n policy = \"read\"\n }\n node_prefix \"\" {\n policy = \"read\"\n }\n service_prefix \"\" {\n policy = \"read\"\n intentions = \"read\"\n }\n }\n}\n" +}' +``` + + + + + +### Link the policy to a token + +After registering the policies into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +```shell-session +$ consul acl token create -partition "default" -namespace "default" \ + -description "UI token to view all resources" \ + -policy-name "ui-view-all" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +You can specify an admin partition and namespace when creating tokens in Consul Enterprise. The token is only valid in the specified scopes. Because the policy was created in the `default` partition and `default` namespace, the token must also be created in the `default` partition and `default` namespace. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "ui-view-all" + } + ], + "Partition": "default", + "Namespace": "default" +}' +``` + + + + diff --git a/website/content/docs/security/acl/tokens/create/create-an-agent-token.mdx b/website/content/docs/security/acl/tokens/create/create-an-agent-token.mdx new file mode 100644 index 000000000000..1fa06d7c4d3d --- /dev/null +++ b/website/content/docs/security/acl/tokens/create/create-an-agent-token.mdx @@ -0,0 +1,407 @@ +--- +layout: docs +page_title: Create tokens for agent registration +description: >- + Learn how to create ACL tokens that your Consul agents can present to Consul servers so that they can join the Consul cluster. +--- + +# Create an agent token + +This topic describes how to create a token that you can use to register an agent into the catalog. + +## Introduction + +Consul agents must present a token linked to policies that grant the appropriate set of permissions in order to register into the catalog and to discover services and nodes in the catalog. + +Specify the [`agent`](/consul/docs/agent/config/config-files#acl_tokens_agent) token to the Consul agent so that it can present the token when it registers into the catalog. + +### Node identities versus custom policies + +You can create tokens linked to custom policies or to node identities. [Node identities](/consul/docs/security/acl#node-identities) are constructs in Consul that enable you to quickly grant permissions for a group of agents, rather than create similar policies for each agent. + +We recommend using a node identity to grant permissions to the agent rather than creating a custom policy. This is because node identities automatically grant the node `node:write` and `service:read` permission. + +Your organization may have requirements or processes for deploying services in a way that is inconsistent with service and node identities. In these cases, you can create custom policies and link them to tokens. + +## Requirements + +Core ACL functionality is available in all versions of Consul. + +The agent token must be linked to policies that grant the following permissions: + +* `node:write`: Enables the agent to update the catalog. +* `service:read`: Enables the agent to discover other services in the catalog + +@include 'create-token-requirements.mdx' + +## Node identity in Consul OSS + +Refer to [Node identities](/consul/docs/security/acl#node-identities) for information about node identities that you can link to tokens. + +You can manually create tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy or node identity to link to create a token. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +The following command creates an ACL token linked to a node identity for a node named `node1` in the datacenter `dc1`. + +```shell-session +$ consul acl token create \ + -description "Agent token for node1" \ + -node-identity "node1:dc1" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify a node identity in the request body to create a token linked to the node identity. An ACL token linked to a policy with permissions to use the API endpoint is required. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +The following example creates a token linked to a node identity named `node1`: + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "NodeIdentities": [ + { + "NodeName": "node1", + "Datacenter": "dc1" + } + ] +}' +``` + + + + + +## Node identity in Consul Enterprise + +Refer to [Node identities](/consul/docs/security/acl#node-identities) for information about node identities that you can link to tokens. + +You can manually create tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy or node identity to link to create a token. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +You can specify an admin partition when creating tokens in Consul Enterprise. The token is only valid in the specified admin partition. The following example creates an ACL token that the agent can use to register in partition `ptn1` in datacenter `dc1`: + +```shell-session +$ consul acl token create -partition "ptn1" \ + -description "Agent token for node1" \ + -node-identity "node1:dc1" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify a node identity in the request body to create a token linked to the node identity. An ACL token linked to a policy with permissions to use the API endpoint is required. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +You can specify an admin partition when creating a token in Consul Enterprise. The token is only valid in the specified admin partition. The following example creates an ACL token that the agent can use to register in the partition `ptn1` in datacenter `dc1`: + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "NodeIdentities": [ + { + "NodeName": "node1", + "Datacenter": "dc1" + } + ], + "Partition": "ptn1" +}' +``` + + + + + +## Custom policy in Consul OSS + +When you are unable to link tokens to a node identity, you can define policies, register them with Consul, and link the policies to tokens that enable nodes to register into the Consul catalog. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The policy grants `write` permission for node `node1` so that the Consul agent can register into the catalog. It grants `read` permissions to discover services in the catalog. + + + +```hcl +node "node1" { + policy = "write" +} +service_prefix "" { + policy = "read" +} +``` + +```json +{ + "node": { + "node1": [{ + "policy": "write" + }] + }, + "service_prefix": { + "": [{ + "policy": "read" + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policy, you can register the policy with Consul using the command line or API endpoint. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. The following example registers a policy defined in `node1-register.hcl`: + +```shell-session +$ consul acl policy create \ + -name "node1-register" -rules @node1-register.hcl \ + -description "Custom policy for node1" \ +``` + +Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. The following example registers the policy defined in `node1-register.hcl`. You must embed policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "node1-register", + "Description": "Allow node1 to register into the catalog", + "Rules": "node \"node1\" {\n policy = \"write\"\n}\nservice_prefix \"\" {\n policy = \"read\"\n}\n" +}' +``` + +Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + + + + + +### Link the policy to a token + +After registering the policies into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +The following command creates the ACL token linked to the policy `node1-register`. + +```shell-session +$ consul acl token create \ + -description "Agent token for node1" \ + -policy-name "node1-register" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +The following example creates an ACL token that the agent can use to register as node `node1` in the catalog: + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "node1-register" + } + ] +}' +``` + + + + + + + +## Custom policy in Consul Enterprise + +When you are unable to link tokens to a node identity, you can define policies, register them with Consul, and link the policies to tokens that enable nodes to register into the Consul catalog. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The policy grants the `write` permission for node `node1` in partition `ptn1` so that the Consul agent can register into the catalog. It grants `read` permissions to discover services in any namespace in the `ptn1` partition. + + + +```hcl +partition "ptn1" { + node "node1" { + policy = "write" + } + namespace_prefix "" { + service_prefix "" { + policy = "read" + } + } +} +``` + +```json +{ + "partition": { + "ptn1": [{ + "namespace_prefix": { + "": [{ + "service_prefix": { + "": [{ + "policy": "read" + }] + } + }] + }, + "node": { + "node1": [{ + "policy": "write" + }] + } + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policy, you can register the policy with Consul using the command line or API endpoint. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. The following example registers a policy defined in `node1-register.hcl`: + +```shell-session +$ consul acl policy create -partition "ptn1" \ + -name "node1-register" -rules @node1-register.hcl \ + -description "Custom policy for node1" +``` + +Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. The following example registers the policy defined in `node1-register.hcl`. You must embed policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "node1-register", + "Description": "Allow node1 to register into the catalog", + "Partition": "ptn1", + "Rules": "partition \"ptn1\" {\n node \"node1\" {\n policy = \"write\"\n }\n namespace_prefix \"\" {\n service_prefix \"\" {\n policy = \"read\"\n }\n }\n}\n" +}' +``` + +Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + + + + + +### Link the policy to a token + +After registering the policy into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +```shell-session +$ consul acl token create -partition "ptn1" \ + -description "Agent token for node1" \ + -policy-name "node1-register" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +You can specify an admin partition when creating tokens in Consul Enterprise. The token is only valid in the specified admin partition. The following example creates an ACL token that the agent can use to register as the node `node1` in the partition `ptn1`: + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "node1-register" + } + ], + "Partition": "ptn1" +}' +``` + + + + + +## Apply the token + +Configure the Consul agent to present the token by either specifying the token in the agent configuration file or by using the `consul set-agent-token` command. + +### Apply the token in a file + +Specify the token in the [`acl.token.agent`](/consul/docs/agent/config/config-files#acl_tokens_agent) field of the agent configuration file so that the agent can present it and register into the catalog on startup. + +```hcl +acl = { + enabled = true + tokens = { + agent = "" + ... + } + ... +} +``` + +### Apply the token with a command + +Set the `agent` token using the [`consul set-agent-token`](/consul/commands/acl/set-agent-token) command. The following command configures a running Consul agent token with the specified token. + +```shell-session +consul acl set-agent-token agent +``` diff --git a/website/content/docs/security/acl/tokens/create/create-an-ingress-gateway-token.mdx b/website/content/docs/security/acl/tokens/create/create-an-ingress-gateway-token.mdx new file mode 100644 index 000000000000..65e01369966a --- /dev/null +++ b/website/content/docs/security/acl/tokens/create/create-an-ingress-gateway-token.mdx @@ -0,0 +1,326 @@ +--- +layout: docs +page_title: Create a token for ingress gateway registration +description: >- + Learn how to create ACL tokens that your ingress gateway can present to Consul servers so that they can register with the Consul catalog. +--- + +# Create an ingress gateway token + +This topic describes how to create a token to enable an ingress gateway to register. + +## Introduction + +Gateways must present a token linked to policies that grant the appropriate set of permissions in order to register into the catalog and to route to other services in a mesh. + +## Requirements + +Core ACL functionality is available in all versions of Consul. + +The ingress gateway token must be linked to policies that grant the following permissions: + +* `service:write` to allow the ingress gateway to register into the catalog +* `service:read` for all services and `node:read` for all nodes in order to discover and route to services +* `agent:read` to enable the `consul connect envoy` CLI command to automatically discover gRPC settings from the Consul agent. If this command is not used to start the gateway or if the Consul agent uses the default gRPC settings, then you can omit the `agent:read` permission. + +@include 'create-token-requirements.mdx' + +## Consul OSS + +To create a token for the ingress gateway, you must define a policy, register the policy with Consul, and link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +The following example policy is defined in a file. The policy grants the ingress gateway the appropriate permissions to register as a service named `ingress-gateway` and to operate as an ingress gateway. + + + +```hcl +service "ingress-gateway" { + policy = "write" +} +node_prefix "" { + policy = "read" +} +service_prefix "" { + policy = "read" +} +agent_prefix "" { + policy = "read" +} +``` + +```json +{ + "agent_prefix": { + "": [{ + "policy": "read" + }] + }, + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "service": { + "ingress-gateway": [{ + "policy": "write" + }] + }, + "service_prefix": { + "": [{ + "policy": "read" + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policy, you can register the policy with Consul using the command line or API endpoint. + +The following commands create the ACL policy and token. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. The following example registers a policy defined in `igw-register.hcl`: + +```shell-session +$ consul acl policy create \ + -name "igw-register" -rules @igw-register.hcl \ + -description "Ingress gateway policy" +``` + +Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. The following example registers the policy defined in `igw-register.hcl`. You must embed policy rules in the `Rules` field of the request body. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "igw-register", + "Description": "Ingress gateway policy", + "Rules": "service \"ingress-gateway\" {\n policy = \"write\"\n}\nnode_prefix \"\" {\n policy = \"read\"\n}\nservice_prefix \"\" {\n policy = \"read\"\n}\nagent_prefix \"\" {\n policy = \"read\"\n}\n" +}' +``` + +Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + + + + + +### Link the policy to a token + +After registering the policy into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +The following command creates the ACL token linked to the policy `igw-register`. + +```shell-session +$ consul acl token create \ + -description "Ingress gateway token" \ + -policy-name "igw-register" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "igw-register" + } + ] +}' +``` + + + + + +## Consul Enterprise + +To create a token for the ingress gateway, you must define a policy, register the policy with Consul, and link the policy to a token. + +### Define a policy + +You can send policy definitions as command line or API arguments or define them in an external HCL or JSON file. Refer to [ACL Rules](/consul/docs/security/acl/acl-rules) for details about all of the rules you can use in your policies. + +You can specify an admin partition and namespace when creating policies in Consul Enterprise. The policy is only valid in the specified scopes. + +The following example policy is defined in a file. The policy allows an ingress gateway to register as a service named `ingress-gateway` in the `ptn1` partition and `ns1` namespace. The policy contains permissions for resources in multiple namespaces. You must create ACL policies that grant permissions for multiple namespaces in the `default` namespace. + + + +```hcl +partition "ptn1" { + namespace "ns1" { + service "ingress-gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } + } + namespace "default" { + agent_prefix "" { + policy = "read" + } + } +} +``` + +```json +{ + "partition": { + "ptn1": [{ + "namespace": { + "default": [{ + "agent_prefix": { + "": [{ + "policy": "read" + }] + } + }], + "ns1": [{ + "node_prefix": { + "": [{ + "policy": "read" + }] + }, + "service": { + "ingress-gateway": [{ + "policy": "write" + }] + }, + "service_prefix": { + "": [{ + "policy": "read" + }] + } + }] + } + }] + } +} +``` + + + +### Register the policy with Consul + +After defining the policy, you can register the policy with Consul using the command line or API endpoint. + +The following commands create the ACL policy and token. + + + + + +Run the `consul acl policy create` command and specify the policy rules to create a policy. The following example registers a policy defined in `igw-register.hcl`: + +You can specify an admin partition and namespace when creating policies in Consul Enterprise. The policy is only valid in the specified admin partition and namespace. The following example creates the policy in the `default` namespace in the `ptn1` partition. The example policy contains permissions for resources in multiple namespaces. You must create ACL policies that grant permissions for multiple namespaces in the `default` namespace. + +```shell-session +$ consul acl policy create -partition "ptn1" -namespace "default" \ + -name "igw-register" -rules @igw-register.hcl \ + -description "Ingress gateway policy" +``` + +Refer to [Consul ACL Policy Create](/consul/commands/acl/policy/create) for details about the `consul acl policy create` command. + + + + + +Send a PUT request to the `/acl/policy` endpoint and specify the policy rules in the request body to create a policy. The following example registers the policy defined in `igw-register.hcl`. You must embed policy rules in the `Rules` field of the request body. + +You can specify an admin partition and namespace when creating tokens in Consul Enterprise. The token is only valid in the specified admin partition and namespace. The following example creates the token in the partition `ptn1` and namespace `ns1`. The example policy contains permissions for resources in multiple namespaces. You must create ACL policies that grant permissions for multiple namespaces in the `default` namespace. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/policy \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Name": "igw-register", + "Description": "Ingress gateway policy", + "Partition": "ptn1", + "Namespace": "default", + "Rules": "partition \"ptn1\" {\n namespace \"ns1\" {\n service \"ingress-gateway\" {\n policy = \"write\"\n }\n node_prefix \"\" {\n policy = \"read\"\n }\n service_prefix \"\" {\n policy = \"read\"\n }\n }\n namespace \"default\" {\n agent_prefix \"\" {\n policy = \"read\"\n }\n }\n}\n" +}' +``` + +Refer to [ACL Policy HTTP API](/consul/api-docs/acl/policies) for additional information about using the API endpoint. + + + + + +### Link the policy to a token + +After registering the policy into Consul, you can create and link tokens using the Consul command line or API endpoint. You can also enable Consul to dynamically create tokens from trusted external systems using an [auth method](/consul/docs/security/acl/auth-methods). + + + + + +Run the `consul acl token create` command and specify the policy name or ID to create a token linked to the policy. Refer to [Consul ACL Token Create](/consul/commands/acl/token/create) for details about the `consul acl token create` command. + +You can specify an admin partition and namespace when creating tokens in Consul Enterprise. The token is only valid in the specified admin partition and namespace. The following example creates the token in the partition `ptn1` and namespace `default`. The example policy contains permissions for resources in multiple namespaces. You must create ACL tokens linked to policies that grant permissions for multiple namespaces in the `default` namespace. + +```shell-session +$ consul acl token create -partition "ptn1" -namespace "default" \ + -description "Ingress gateway token" \ + -policy-name "igw-register" +``` + + + + + +Send a PUT request to the `/acl/token` endpoint and specify the policy name or ID in the request to create an ACL token linked to the policy. Refer to [ACL Token HTTP API](/consul/api-docs/acl/tokens) for additional information about using the API endpoint. + +You can specify an admin partition when creating tokens in Consul Enterprise. The token is only valid in the specified admin partition. You must create the token in the partition where the ingress gateway is registered. The following example creates the token in the partition `ptn1` and namespace `default`. + +```shell-session +$ curl --request PUT http://127.0.0.1:8500/v1/acl/token \ + --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ + --data '{ + "Policies": [ + { + "Name": "igw-register" + } + ], + "Partition": "ptn1", + "Namespace": "default" +}' +``` + + + + diff --git a/website/content/docs/security/acl/acl-tokens.mdx b/website/content/docs/security/acl/tokens/index.mdx similarity index 97% rename from website/content/docs/security/acl/acl-tokens.mdx rename to website/content/docs/security/acl/tokens/index.mdx index 7ad23571c8b5..ccbcab66468b 100644 --- a/website/content/docs/security/acl/acl-tokens.mdx +++ b/website/content/docs/security/acl/tokens/index.mdx @@ -66,7 +66,7 @@ service = { -Refer to the [service definitions documentation](/docs/discovery/services#service-definition) for additional information. +Refer to [Services Configuration Reference](/consul/docs/services/configuration/services-configuration-reference) for additional information. ### Agent Requests @@ -145,6 +145,7 @@ Refer to the [API](/api-docs/acl/tokens) or [command line](/commands/acl/token) | `NodeIdentities` | Specifies a list of node identities to apply to the token. See [Node Identities](/docs/security/acl/acl-roles#node-identities) in the "Roles" topic for additional information. | Array | none | | `Legacy` | Indicates if the token was created using the the legacy ACL system. | Boolean | `false` | | `Policies` | List of policies linked to the token, including the policy ID and name. | String | none | +| `Roles` | List of roles linked to the token, including the role ID and name. | String | none | ## Special-purpose Tokens diff --git a/website/content/docs/services/configuration/checks-configuration-reference.mdx b/website/content/docs/services/configuration/checks-configuration-reference.mdx new file mode 100644 index 000000000000..fee071de51b0 --- /dev/null +++ b/website/content/docs/services/configuration/checks-configuration-reference.mdx @@ -0,0 +1,55 @@ +--- +layout: docs +page_title: Health check configuration reference +description: -> + Use the health checks to direct safety functions, such as removing failing nodes and replacing secondary services. Learn how to configure health checks. +--- + +# Health check configuration reference + +This topic provides configuration reference information for health checks. For information about the different kinds of health checks and guidance on defining them, refer to [Define Health Checks]. + +## Introduction +Health checks perform several safety functions, such as allowing a web balancer to gracefully remove failing nodes and allowing a database to replace a failed secondary. You can configure health checks to monitor the health of the entire node. Refer to [Define Health Checks](/consul/docs/services/usage/checks) for information about how to define the differnet types of health checks available in Consul. + +## Check block +Specify health check options in the `check` block. To register two or more heath checks in the same configuration, use the [`checks` block](#checks-block). The following table describes the configuration options contained in the `check` block. + +| Parameter | Description | Check types | +| --- | --- | --- | +| `name` | Required string value that specifies the name of the check. Default is `service:`. If multiple service checks are registered, the autogenerated default is appended with colon and incrementing number starting with `1`. |
  • Script
  • HTTP
  • TCP
  • UDP
  • OSService
  • TTL
  • Docker
  • gRPC
  • H2ping
  • Alias
  • | +| `id` | A unique string value that specifies an ID for the check. Default to the `name` value. If `name` values conflict, specify a unique ID to avoid overwriting existing checks with same ID on the same node. Consul auto-generates an ID if the check is defined in a service definition file. |
  • Script
  • HTTP
  • TCP
  • UDP
  • OSService
  • TTL
  • Docker
  • gRPC
  • H2ping
  • Alias
  • | +| `notes` | String value that provides a human-readabiole description of the check. The contents are not visible to Consul. |
  • Script
  • HTTP
  • TCP
  • UDP
  • OSService
  • TTL
  • Docker
  • gRPC
  • H2ping
  • Alias
  • | +| `interval` | Required string value that specifies how frequently to run the check. The `interval` parameter is required for supported check types. The value is parsed by the golang [time package formatting specification](https://golang.org/pkg/time/#ParseDuration). |
  • Script
  • HTTP
  • TCP
  • UDP
  • OSService
  • Docker
  • gRPC
  • H2ping
  • | +| `timeout` | String value that specifies how long unsuccessful requests take to end with a timeout. The `timeout` is optional for the supported check types and has the following defaults:
  • Script: `30s`
  • HTTP: `10s`
  • TCP: `10s`
  • UDP: `10s`
  • gRPC: `10s`
  • H2ping: `10s`
  • |
  • Script
  • HTTP
  • TCP
  • UDP
  • gRPC
  • H2ping
  • | +| `status` | Optional string value that specifies the initial status of the health check. You can specify the following values:
  • `critical` (default)
  • `warning`
  • `passing`
  • |
  • Script
  • HTTP
  • TCP
  • UDP
  • OSService
  • TTL
  • Docker
  • gRPC
  • H2ping
  • Alias
  • | +| `deregister_critical_service_after` | String value that specifies how long a service and its associated checks are allowed to be in a `critical` state. Consul deregisters services if they are `critical` for the specified amount of time. The value is parsed by the golang [time package formatting specification](https://golang.org/pkg/time/#ParseDuration) |
  • Script
  • HTTP
  • TCP
  • UDP
  • OSService
  • TTL
  • Docker
  • gRPC
  • H2ping
  • Alias
  • | +| `success_before_passing` | Integer value that specifies how many consecutive times the check must pass before Consul marks the service or node as `passing`. Default is `0`. |
  • Script
  • HTTP
  • TCP
  • UDP
  • OSService
  • TTL
  • Docker
  • gRPC
  • H2ping
  • Alias
  • | +| `failures_before_warning` | Integer value that specifies how many consecutive times the check must fail before Consul marks the service or node as `warning`. The value cannot be more than `failures_before_critical`. Defaults to the value specified for `failures_before_critical`. |
  • Script
  • HTTP
  • TCP
  • UDP
  • OSService
  • TTL
  • Docker
  • gRPC
  • H2ping
  • Alias
  • | +| `failures_before_critical` | Integer value that specifies how many consecutive times the check must fail before Consul marks the service or node as `critical`. Default is `0`. |
  • Script
  • HTTP
  • TCP
  • UDP
  • OSService
  • TTL
  • Docker
  • gRPC
  • H2ping
  • Alias
  • | +| `args` | Specifies a list of arguments strings to pass to the command line. The list of values includes the path to a script file or external application to invoke and any additional parameters for running the script or application. |
  • Script
  • Docker
  • | +| `docker_container_id` | Specifies the Docker container ID in which to run an external health check application. Specify the external application with the `args` parameter. |
  • Docker
  • | +| `shell` | String value that specifies the type of command line shell to use for running the health check application. Specify the external application with the `args` parameter. |
  • Docker
  • | +| `grpc` | String value that specifies the gRPC endpoint, including port number, to send requests to. Append the endpoint with `:/` and a service identifier to check a specific service. The endpoint must support the [gRPC health checking protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md). |
  • gRPC
  • | +| `grpc_use_tls` | Boolean value that enables TLS for gRPC checks when set to `true`. |
  • gRPC
  • | +| `h2ping` | String value that specifies the HTTP2 endpoint, including port number, to send HTTP2 requests to. |
  • H2ping
  • | +| `h2ping_use_tls` | Boolean value that enables TLS for H2ping checks when set to `true`. |
  • H2ping
  • | +| `http` | String value that specifies an HTTP endpoint to send requests to. |
  • HTTP
  • | +| `tls_server_name` | String value that specifies the name of the TLS server that issues certificates. Defaults to the SNI determined by the address specified in the `http` field. Set the `tls_skip_verify` to `false` to disable this field. |
  • HTTP
  • | +| `tls_skip_verify` | Boolean value that disbles TLS for HTTP checks when set to `true`. Default is `false`. |
  • HTTP
  • | +| `method` | String value that specifies the request method to send during HTTP checks. Default is `GET`. |
  • HTTP
  • | +| `header` | Object that specifies header fields to send in HTTP check requests. Each header specified in `header` object contains a list of string values. |
  • HTTP
  • | +| `body` | String value that contains JSON attributes to send in HTTP check requests. You must escap the quotation marks around the keys and values for each attribute. |
  • HTTP
  • | +| `disable_redirects` | Boolean value that prevents HTTP checks from following redirects if set to `true`. Default is `false`. |
  • HTTP
  • | +| `os_service` | String value that specifies the name of the name of a service to check during an OSService check. |
  • OSService
  • | +| `service_id` | String value that specifies the ID of a service instance to associate with an OSService check. That service instance must be on the same node as the check. If not specified, the check verifies the health of the node. |
  • OSService
  • | +| `tcp` | String value that specifies an IP address or host and port number for the check establish a TCP connection with. |
  • TCP
  • | +| `udp` | String value that specifies an IP address or host and port number for the check to send UDP datagrams to. |
  • UDP
  • | +| `ttl` | String value that specifies how long to wait for an update from an external process during a TTL check. |
  • TTL
  • | +| `alias_service` | String value that specifies a service or node that the service associated with the health check aliases. |
  • Alias
  • | + + + +## Checks block +You can define multiple health checks in a single `checks` block. The `checks` block is an array of objects that contain the configuration options described in the [`check` block configuration reference](#check-block). + diff --git a/website/content/docs/services/configuration/services-configuration-overview.mdx b/website/content/docs/services/configuration/services-configuration-overview.mdx new file mode 100644 index 000000000000..3c01f05ae7ca --- /dev/null +++ b/website/content/docs/services/configuration/services-configuration-overview.mdx @@ -0,0 +1,29 @@ +--- +layout: docs +page_title: Services configuration overview +description: -> + This topic provides introduces the configuration items that enable you to register services with Consul so that they can connect to other services and nodes registered with Consul. +--- + +# Services configuration overview + +This topic provides introduces the configuration items that enable you to register services with Consul so that they can connect to other services and nodes registered with Consul. + +## Service definitions +A service definition contains a set of parameters that specify various aspects of the service, including how it is discovered by other services in the network. The service definition may also contain health check configurations. Refer to [Health Check Configuration Reference](/consul/docs/services/configuration/checks-configuration-reference) for configuration details about health checks. + +Configure individual services and health checks by specifying parameters in the `service` block of a service definition file. Refer to [Define Services](/consul/docs/services/usage/define-services) for information about defining services. + +To register a service, provide the service definition to the Consul agent. Refer to [Register Services and Health Checks](/consul/docs/services/usage/register-services-checks) for information about registering services. + +Consul supports service definitions written in JSON and HCL. + +## Service defaults +Use the `service-defaults` configuration entry to define the default parameters for service definitions. This enables you to configure common settings, such as namespace or partition for Consul Enterprise deployments, in a single definition. + +You can use `service-defaults` configuration entries on virtual machines and in Kubernetes environments. + +## ACLs +Services registered in Consul clusters where both Consul Namespaces and the ACL system are enabled can be registered to specific namespaces that are associated with ACL tokens scoped to the namespace. Services registered with a service definition will not inherit the namespace associated with the ACL token specified in the token field. The namespace and the token parameters must be included in the service definition for the service to be registered to the namespace that the ACL token is scoped to. + + diff --git a/website/content/docs/services/configuration/services-configuration-reference.mdx b/website/content/docs/services/configuration/services-configuration-reference.mdx new file mode 100644 index 000000000000..4614a4b26808 --- /dev/null +++ b/website/content/docs/services/configuration/services-configuration-reference.mdx @@ -0,0 +1,655 @@ +--- +layout: docs +page_title: Service configuration reference +description: Use the service definition to configure and register services to the Consul catalog, including services used as proxies in a Consul service mesh +--- + +# Services configuration reference + +This topic describes the options you can use to define services for registering them with Consul. Refer to the following topics for usage information: + +- [Define Services](/consul/docs/services/usage/define-services) +- [Register Services and Health Checks](/consul/docs/services/usage/register-services-checks) + +## Configuration model +The following outline shows how to format the configurations in the root `service` block. Click on a property name to view details about the configuration. + +- [`name`](#name): string | required +- [`id`](#id): string | optional +- [`address`](#address): string | optional +- [`port`](#port): integer | optional +- [`tags`](#tags): list of strings | optional +- [`meta`](#meta): object | optional + - [_`custom_meta_key`_](#meta): string | optional +- [`tagged_addresses`](#tagged_addresses): object | optional + - [`lan`](#tagged_addresses-lan): object | optional + - [`address`](#tagged_addresses-lan): string | optional + - [`port`](#tagged_addresses-lan): integer | optional + - [`wan`](#tagged_addresses-wan): object | optional + - [`address`](#tagged_addresses-wan): string | optional + - [`port`](#tagged_addresses-wan): integer | optional +- [`socket_path`](#socket_path): string | optional +- [`enable_tag_override`](#enable_tag_override): boolean | optional +- [`checks`](#checks) : list of objects | optional +- [`kind`](#kind): string | optional +- [`proxy`](#proxy): object | optional +- [`connect`](#connect): object | optional + - [`native`](#connect): boolean | optional + - [`sidecar_service`](#connect): object | optional +- [`weights`](#weights): object | optional + - [`passing`](#weights): integer | optional + - [`warning`](#weights): integer | optional +- [`token`](#token): string | required if ACLs are enabled +- [`namespace`](#namespace): string | optional | + +## Specification +This topic provides details about the configuration parameters. + +### name +Required value that specifies a name for the service. We recommend using valid DNS labels for service definition names for compatibility with external DNSs. The value for this parameter is used as the ID if the `id` parameter is not specified. + +- Type: string +- Default: none + +### id +Specifies an ID for the service. Services on the same node must have unique IDs. We recommend specifying unique values if the default name conflicts with other services. + +- Type: string +- Default: Value of the `name` field. + +### address +String value that specifies a service-specific IP address or hostname. +If no value is specified, the IP address of the agent node is used by default. +There is no service-side validation of this parameter. + +- Type: string +- Default: IP address of the agent node + +### port +Specifies a port number for the service. To improve service discoverability, we recommend specifying the port number, as well as an address in the [`tagged_addresses`](#tagged_addresses) parameter. + +- Type: integer +- Default: Port number of the agent + +### tags +Specifies a list of string values that add service-level labels. Tag values are opaque to Consul. We recommend using valid DNS labels for service definition IDs for compatibility with external DNSs. In the following example, the service is tagged as `v2` and `primary`: + +```hcl +tags = ["v2", "primary"] +``` + +Consul uses tags as an anti-entropy mechanism to maintain the state of the cluster. You can disable the anti-entropy feature for a service using the [`enable_tag_override`](#enable_tag_override) setting, which enables external agents to modify tags on services in the catalog. Refer to [Modify anti-entropy synchronization](/consul/docs/services/usage/define-services#modify-anti-entropy-synchronization) for additional usage information. + +### meta +The `meta` field contains custom key-value pairs that associate semantic metadata with the service. You can specify up to 64 pairs that meet the following requirements: + +- Keys and values must be strings. +- Keys can only contain ASCII characters (`A` -` Z`, `a`- `z`, `0` - `9`, `_`, and `-`). +- Keys can not have special characters. +- Keys are limited to 128 characters. +- Values are limited to 512 characters. + +In the following example, the `env` key is set to `prod`: + + + +```hcl +meta = { + env = "prod" +} +``` + +```json +"meta" : { + "env" : "prod" +} +``` + + + +### tagged_addresses +The `tagged_address` field is an object that configures additional addresses for a node or service. Remote agents and services can communicate with the service using a tagged address as an alternative to the address specified in the [`address`](#address) field. You can configure multiple addresses for a node or service. The following tags are supported: + +- [`lan`](#tagged_addresses-lan): IPv4 LAN address where the node or service is accessible. +- [`lan_ipv4`](#tagged_addresses-lan): IPv4 LAN address where the node or service is accessible. +- [`lan_ipv6`](#tagged_addresses-lan): IPv6 LAN address where the node or service is accessible. +- [`virtual`](#tagged_addresses-virtual): A fixed address for the instances of a given logical service. +- [`wan`](#tagged_addresses-wan): IPv4 WAN address where the node or service is accessible when dialed from a remote data center. +- [`wan_ipv4`](#tagged_addresses-wan): IPv4 WAN address where the node or service is accessible when dialed from a remote data center. +- [`wan_ipv6`](#tagged_addresses-lan): IPv6 WAN address at which the node or service is accessible when being dialed from a remote data center. + +### tagged_addresses.lan +Object that specifies either an IPv4 or IPv6 LAN address and port number where the service or node is accessible. You can specify one or more of the following fields: + +- `lan` +- `lan_ipv4` +- `lan_ipv6` + +The field contains the following parameters: + +- `address` +- `port` + +In the following example, the `redis` service has an IPv4 LAN address of `192.0.2.10:80` and IPv6 LAN address of `[2001:db8:1:2:cafe::1337]:80`: + + + +```hcl +service { + name = "redis" + address = "192.0.2.10" + port = 80 + tagged_addresses { + lan = { + address = "192.0.2.10" + port = 80 + } + lan_ipv4 = { + address = "192.0.2.10" + port = 80 + } + lan_ipv6 = { + address = "2001:db8:1:2:cafe::1337" + port = 80 + } + } +} +``` + +```json +{ + "service": { + "name": "redis", + "address": "192.0.2.10", + "port": 80, + "tagged_addresses": { + "lan": { + "address": "192.0.2.10", + "port": 80 + }, + "lan_ipv4": { + "address": "192.0.2.10", + "port": 80 + }, + "lan_ipv6": { + "address": "2001:db8:1:2:cafe::1337", + "port": 80 + } + } + } +} +``` + + + +### tagged_addresses.virtual +Object that specifies a fixed IP address and port number that downstream services in a service mesh can use to connect to the service. The `virtual` field contains the following parameters: + +- `address` +- `port` + +Virtual addresses are not required to be routable IPs within the network. They are strictly a control plane construct used to provide a fixed address for the instances of a logical service. Egress connections from the proxy to an upstream service go to the IP address of an individual service instance and not the virtual address of the logical service. + +If the following conditions are met, connections to virtual addresses are load balanced across available instances of a service, provided the following conditions are satisfied: + +1. [Transparent proxy](/consul/docs/connect/transparent-proxy) is enabled for the downstream and upstream services. +1. The upstream service is not configured for individual instances to be [dialed directly](/consul/docs/connect/config-entries/service-defaults#dialeddirectly). + +In the following example, the downstream services in the mesh can connect to the `redis` service at `203.0.113.50` on port `80`: + + + +```hcl +service { + name = "redis" + address = "192.0.2.10" + port = 80 + tagged_addresses { + virtual = { + address = "203.0.113.50" + port = 80 + } + } +} +``` + +```json +{ + "service": { + "name": "redis", + "address": "192.0.2.10", + "port": 80, + "tagged_addresses": { + "virtual": { + "address": "203.0.113.50", + "port": 80 + } + } + } +} +``` + + + +### tagged_addresses.wan +Object that specifies either an IPv4 or IPv6 WAN address and port number where the service or node is accessible from a remote datacenter. You can specify one or more of the following fields: + +- `wan` +- `wan_ipv4` +- `wan_ipv6` + +The field contains the following parameters: + +- `address` +- `port` + +In the following example, services or nodes in remote datacenters can reach the `redis` service at `198.51.100.200:80` and `[2001:db8:5:6:1337::1eaf]:80`: + + + +```hcl +service { + name = "redis" + address = "192.0.2.10" + port = 80 + tagged_addresses { + wan = { + address = "198.51.100.200" + port = 80 + } + wan_ipv4 = { + address = "198.51.100.200" + port = 80 + } + wan_ipv6 = { + address = "2001:db8:5:6:1337::1eaf" + port = 80 + } + } +} +``` + +```json +{ + "service": { + "name": "redis", + "address": "192.0.2.10", + "port": 80, + "tagged_addresses": { + "wan": { + "address": "198.51.100.200", + "port": 80 + }, + "wan_ipv4": { + "address": "198.51.100.200", + "port": 80 + }, + "wan_ipv6": { + "address": "2001:db8:5:6:1337::1eaf", + "port": 80 + } + } + } +} +``` + + + +### socket_path +String value that specifies the path to the service socket. Specify this parameter to expose the service to the mesh if the service listens on a Unix Domain socket. + +- Type: string +- Default: none + +### enable_tag_override +Boolean value that determines if the anti-entropy feature for the service is enabled. +Set to `true` to allow external Consul agents modify tags on the services in the Consul catalog. The local Consul agent ignores updated tags during subsequent sync operations. + +This parameter only applies to the locally-registered service. If multiple nodes register a service with the same `name`, the `enable_tag_override` configuration, and all other service configuration items, operate independently. + +Refer to [Modify anti-entropy synchronization](/consul/docs/services/usage/define-services#modify-anti-entropy-synchronization) for additional usage information. + +- Type: boolean +- Default: `false` + +### checks +The `checks` block contains an array of objects that define health checks for the service. Health checks perform several safety functions, such as allowing a web balancer to gracefully remove failing nodes and allowing a database to replace a failed secondary. Refer to [Health Check Configuration Reference](/consul/docs/services/configuration/checks-configuration-reference) for information about configuring health checks. + +### kind +String value that identifies the service as a proxy and determines its role in the service mesh. Do not configure the `kind` parameter for non-proxy service instances. Refer to [Consul Service Mesh](/consul/docs/connect) for additional information. + +You can specify the following values: + +- `connect-proxy`: Defines the configuration for a service mesh proxy. Refer to [Register a Service Mesh Proxy Outside of a Service Registration](/consul/docs/connect/registration/service-registration) for details about registering a service as a service mesh proxy. +- `ingress-gateway`: Defines the configuration for an [ingress gateway](/consul/docs/connect/config-entries/ingress-gateway) +- `mesh-gateway`: Defines the configuration for a [mesh gateway](/consul/docs/connect/gateways/mesh-gateway) +- `terminating-gateway`: Defines the configuration for a [terminating gateway](/consul/docs/connect/gateways/terminating-gateway) + +For non-service registration roles, the `kind` field has a different context when used to define configuration entries, such as `service-defaults`. Refer to the documentation for the configuration entry you want to implement for additional information. + +### proxy +Object that specifies proxy configurations when the service is configured to operate as a proxy in a service mesh. Do not configure the `proxy` parameter for non-proxy service instances. Refer to [Register a Service Mesh Proxy Outside of a Service Registration](/consul/docs/connect/registration/service-registration) for details about registering your service as a service mesh proxy. Refer to [`kind`](#kind) for information about the types of proxies you can define. Services that you assign proxy roles to are registered as services in the catalog. + +### connect +Object that configures a Consul service mesh connection. You should only configure the `connect` block of parameters if you are using Consul service mesh. Refer to [Consul Service Mesh](/consul/docs/connect) for additional information. + +The following table describes the parameters that you can place in the `connect` block: + +| Parameter | Description | Default | +| --- | --- | --- | +| `native` | Boolean value that advertises the service as a native service mesh proxy. Use this parameter to integrate your application with the `connect` API. Refer to [Service Mesh Native App Integration Overview](/consul/docs/connect/native) for additional information. If set to `true`, do not configure a `sidecar_service`. | `false` | +| `sidecar_service` | Object that defines a sidecar proxy for the service. Do not configure if `native` is set to `true`. Refer to [Register a Service Mesh Proxy in a Service Registration](/consul/docs/connect/registration/sidecar-service) for usage and configuration details. | Refer to [Register a Service Mesh Proxy in a Service Registration](/consul/docs/connect/registration/sidecar-service) for default configurations. | + +### weights +Object that configures how the service responds to DNS SRV requests based on the service's health status. Configuring allows service instances with more capacity to respond to DNS SRV requests. It also reduces the load on services with checks in `warning` status by giving passing instances a higher weight. + +You can specify one or more of the following states and configure an integer value indicating its weight: + +- `passing` +- `warning` +- `critical` + +Larger integer values increase the weight state. Services have the following default weights: + +- `"passing" : 1` +- `"warning" : 1` + +Services in a `critical` state are excluded from DNS responses by default. Services with `warning` checks are included in responses by default. Refer to [Perform Static DNS Queries](/consul/docs/services/discovery/dns-static-lookups) for additional information. + +In the following example, service instances in a `passing` state respond to DNS SRV requests, while instances in a `critical` instance can still respond at a lower frequency: + + + +```hcl +service { + ## ... + weights = { + passing = 3 + warning = 2 + critical = 1 + } + ## ... +} +``` + +```json +"service": { + ## ... + "weights": { + "passing": 3, + "warning": 2, + "critical": 1 + }, + ## ... +} +``` + + + +### token +String value that specifies the ACL token to present when registering the service if ACLs are enabled. The token is required for the service to interact with the service catalog. + +If [ACLs](/consul/docs/security/acl) and [namespaces](/consul/docs/enterprise/namespaces) are enabled, you can register services scoped to the specific [`namespace`](#namespace) associated with the ACL token in a Consul cluster. + +Services registered with a service definition do not inherit the namespace associated with the ACL token specified in the token field. The `namespace` and `token` parameters must be included in the service definition for the service to be registered to the namespace that the ACL token is scoped to. + +- Type: string +- Default: none + +### namespace +String value that specifies the namespace in which to register the service. Refer [Namespaces](/consul/docs/enterprise/namespaces) for additional information. + +- Type: string +- Default: none + +## Multiple service definitions + +You can define multiple services in a single definition file in the `services` block. This enables you register multiple services in a single command. Note that the HTTP API does not support the `services` block. + + + +```hcl +services { + id = "red0" + name = "redis" + tags = [ + "primary" + ] + address = "" + port = 6000 + checks = [ + { + args = ["/bin/check_redis", "-p", "6000"] + interval = "5s" + timeout = "20s" + } + ] +} +services { + id = "red1" + name = "redis" + tags = [ + "delayed", + "secondary" + ] + address = "" + port = 7000 + checks = [ + { + args = ["/bin/check_redis", "-p", "7000"] + interval = "30s" + timeout = "60s" + } + ] +} +``` + +```json +{ + "services": [ + { + "id": "red0", + "name": "redis", + "tags": [ + "primary" + ], + "address": "", + "port": 6000, + "checks": [ + { + "args": ["/bin/check_redis", "-p", "6000"], + "interval": "5s", + "timeout": "20s" + } + ] + }, + { + "id": "red1", + "name": "redis", + "tags": [ + "delayed", + "secondary" + ], + "address": "", + "port": 7000, + "checks": [ + { + "args": ["/bin/check_redis", "-p", "7000"], + "interval": "30s", + "timeout": "60s" + } + ] + } + ] +} +``` + + + +## Example definition +The following example includes all possible parameters, but only the top-level `service` parameter and its `name` parameter are required by default. + + + +```hcl +service { + name = "redis" + id = "redis" + port = 80 + tags = ["primary"] + + meta = { + custom_meta_key = "custom_meta_value" + } + + tagged_addresses = { + lan = { + address = "192.168.0.55" + port = 8000 + } + + wan = { + address = "198.18.0.23" + port = 80 + } + } + + port = 8000 + socket_path = "/tmp/redis.sock" + enable_tag_override = false + + checks = [ + { + args = ["/usr/local/bin/check_redis.py"] + interval = "10s" + } + ] + + kind = "connect-proxy" + proxy_destination = "redis" + + proxy = { + destination_service_name = "redis" + destination_service_id = "redis1" + local_service_address = "127.0.0.1" + local_service_port = 9090 + local_service_socket_path = "/tmp/redis.sock" + mode = "transparent" + + transparent_proxy { + outbound_listener_port = 22500 + } + + mesh_gateway = { + mode = "local" + } + + expose = { + checks = true + + paths = [ + { + path = "/healthz" + local_path_port = 8080 + listener_port = 21500 + protocol = "http2" + } + ] + } + } + + connect = { + native = false + } + + weights = { + passing = 5 + warning = 1 + } + + token = "233b604b-b92e-48c8-a253-5f11514e4b50" + namespace = "foo" +} +``` + +```json +{ + "service": { + "id": "redis", + "name": "redis", + "tags": ["primary"], + "address": "", + "meta": { + "meta": "for my service" + }, + "tagged_addresses": { + "lan": { + "address": "192.168.0.55", + "port": 8000, + }, + "wan": { + "address": "198.18.0.23", + "port": 80 + } + }, + "port": 8000, + "socket_path": "/tmp/redis.sock", + "enable_tag_override": false, + "checks": [ + { + "args": ["/usr/local/bin/check_redis.py"], + "interval": "10s" + } + ], + "kind": "connect-proxy", + "proxy_destination": "redis", // Deprecated + "proxy": { + "destination_service_name": "redis", + "destination_service_id": "redis1", + "local_service_address": "127.0.0.1", + "local_service_port": 9090, + "local_service_socket_path": "/tmp/redis.sock", + "mode": "transparent", + "transparent_proxy": { + "outbound_listener_port": 22500 + }, + "config": {}, + "upstreams": [], + "mesh_gateway": { + "mode": "local" + }, + "expose": { + "checks": true, + "paths": [ + { + "path": "/healthz", + "local_path_port": 8080, + "listener_port": 21500, + "protocol": "http2" + } + ] + } + }, + "connect": { + "native": false, + "sidecar_service": {} + "proxy": { // Deprecated + "command": [], + "config": {} + } + }, + "weights": { + "passing": 5, + "warning": 1 + }, + "token": "233b604b-b92e-48c8-a253-5f11514e4b50", + "namespace": "foo" + } +} +``` + + + + + + diff --git a/website/content/docs/services/discovery/dns-configuration.mdx b/website/content/docs/services/discovery/dns-configuration.mdx new file mode 100644 index 000000000000..794be43a206a --- /dev/null +++ b/website/content/docs/services/discovery/dns-configuration.mdx @@ -0,0 +1,76 @@ +--- +layout: docs +page_title: Configure Consul DNS behavior +description: -> + Learn how to modify the default DNS behavior so that services and nodes can easily discover other services and nodes in your network. +--- + +# Configure Consul DNS behavior + +This topic describes the default behavior of the Consul DNS functionality and how to customize how Consul performs queries. + +## Introduction +The Consul DNS is the primary interface for querying records when Consul service mesh is disabled and your network runs in a non-Kubernetes environment. The DNS enables you to look up services and nodes registered with Consul using terminal commands instead of making HTTP API requests to Consul. Refer to the [Discover Consul Nodes and Services Overview](/consul/docs/services/discovery/dns-overview) for additional information. + +## Configure DNS behaviors +By default, the Consul DNS listens for queries at `127.0.0.1:8600` and uses the `consul` domain. Specify the following parameters in the agent configuration to determine DNS behavior when querying services: + +- [`client_addr`](/consul/docs/agent/config/config-files#client_addr) +- [`ports.dns`](/consul/docs/agent/config/config-files#dns_port) +- [`recursors`](/consul/docs/agent/config/config-files#recursors) +- [`domain`](/consul/docs/agent/config/config-files#domain) +- [`alt_domain`](/consul/docs/agent/config/config-files#alt_domain) +- [`dns_config`](/consul/docs/agent/config/config-files#dns_config) + +### Configure WAN address translation +By default, Consul DNS queries return a node's local address, even when being queried from a remote datacenter. You can configure the DNS to reach a node from outside its datacenter by specifying the address in the following configuration fields in the Consul agent: + +- [advertise-wan](/consul/docs/agent/config/cli-flags#_advertise-wan) +- [translate_wan_addrs](/consul//docs/agent/config/config-files#translate_wan_addrs) + +### Use a custom DNS resolver library +You can specify a list of addresses in the agent's [`recursors`](/consul/docs/agent/config/config-files#recursors) field to provide upstream DNS servers that recursively resolve queries that are outside the service domain for Consul. + +Nodes that query records outside the `consul.` domain resolve to an upstream DNS. You can specify IP addresses or use `go-sockaddr` templates. Consul resolves IP addresses in the specified order and ignores duplicates. + +### Enable non-Consul queries +You enable non-Consul queries to be resolved by setting Consul as the DNS server for a node and providing a [`recursors`](/consul/docs/agent/config/config-files#recursors) configuration. + +### Forward queries to an agent +You can forward all queries sent to the `consul.` domain from the existing DNS server to a Consul agent. Refer to [Forward DNS for Consul Service Discovery](/consul/tutorials/networking/dns-forwarding) for instructions. + +### Query an alternate domain +By default, Consul responds to DNS queries in the `consul` domain, but you can set a specific domain for responding to DNS queries by configuring the [`domain`](/consul/docs/agent/config/config-files#domain) parameter. + +You can also specify an additional domain in the [`alt_domain`](/consul/docs/agent/config/config-files#alt_domain) agent configuration option, which configures Consul to respond to queries in a secondary domain. Configuring an alternate domain may be useful during a DNS migration or to distinguish between internal and external queries, for example. + +Consul's DNS response uses the same domain as the query. + +In the following example, the `alt_domain` parameter in the agent configuration is set to `test-domain`, which enables operators to query the domain: + +```shell-session +$ dig @127.0.0.1 -p 8600 consul.service.test-domain SRV + +;; QUESTION SECTION: +;consul.service.test-domain. IN SRV + +;; ANSWER SECTION: +consul.service.test-domain. 0 IN SRV 1 1 8300 machine.node.dc1.test-domain. + +;; ADDITIONAL SECTION: +machine.node.dc1.test-domain. 0 IN A 127.0.0.1 +machine.node.dc1.test-domain. 0 IN TXT "consul-network-segment=" +``` +#### PTR queries +Responses to pointer record (PTR) queries, such as `.in-addr.arpa.`, always use the [primary domain](/consul/docs/agent/config/config-files#domain) and not the alternative domain. + +### Caching +By default, DNS results served by Consul are not cached. Refer to the [DNS Caching tutorial](/consul/tutorials/networking/dns-caching) for instructions on how to enable caching. + + + + + + + + diff --git a/website/content/docs/services/discovery/dns-dynamic-lookups.mdx b/website/content/docs/services/discovery/dns-dynamic-lookups.mdx new file mode 100644 index 000000000000..d0fb8f14bea3 --- /dev/null +++ b/website/content/docs/services/discovery/dns-dynamic-lookups.mdx @@ -0,0 +1,110 @@ +--- +layout: docs +page_title: Enable dynamic DNS queries +description: -> + Learn how to dynamically query the Consul DNS using prepared queries, which enable robust service and node lookups. +--- + +# Enable dynamic DNS queries + +This topic describes how to dynamically query the Consul catalog using prepared queries. Prepared queries are configurations that enable you to register a complex service query and execute it on demand. For information about how to perform standard node and service lookups, refer to [Perform Static DNS Queries](/consul/docs/services/discovery/dns-static-lookups). + +## Introduction + +Prepared queries provide a rich set of lookup features, such as filtering by multiple tags and automatically failing over to look for services in remote datacenters if no healthy nodes are available in the local datacenter. You can also create prepared query templates that match names using a prefix match, allowing a single template to apply to potentially many services. Refer to [Query Consul Nodes and Services Overview](/consul/docs/services/discovery/dns-overview) for additional information about DNS query behaviors. + +## Requirements + +Consul 0.6.4 or later is required to create prepared query templates. + +### ACLs + +If ACLs are enabled, the querying service must present a token linked to permissions that enable read access for query, service, and node resources. Refer to the following documentation for information about creating policies to enable read access to the necessary resources: + +- [Prepared query rules](/consul/docs/security/acl/acl-rules#prepared-query-rules) +- [Service rules](/consul/docs/security/acl/acl-rules#service-rules) +- [Node rules](/consul/docs/security/acl/acl-rules#node-rules) + +## Create prepared queries + +Refer to the [prepared query reference](/consul/api-docs/query#create-prepared-query) for usage information. + +1. Specify the prepared query options in JSON format. The following prepared query targets all instances of the `redis` service in `dc1` and `dc2`: + + ```json + { + "Name": "my-query", + "Session": "adf4238a-882b-9ddc-4a9d-5b6758e4159e", + "Token": "", + "Service": { + "Service": "redis", + "Failover": { + "NearestN": 3, + "Datacenters": ["dc1", "dc2"] + }, + "Near": "node1", + "OnlyPassing": false, + "Tags": ["primary", "!experimental"], + "NodeMeta": { + "instance_type": "m3.large" + }, + "ServiceMeta": { + "environment": "production" + } + }, + "DNS": { + "TTL": "10s" + } + } + ``` + + Refer to the [prepared query configuration reference](/consul/api-docs/query#create-prepared-query) for information about all available options. + +1. Send the query in a POST request to the [`/query` API endpoint](/consul/api-docs/query). If the request is successful, Consul prints an ID for the prepared query. + + In the following example, the prepared query configuration is stored in the `payload.json` file: + + ```shell-session + $ curl --request POST --data @payload.json http://127.0.0.1:8500/v1/query + {"ID":"014af5ff-29e6-e972-dcf8-6ee602137127"}% + ``` + +1. To run the query, send a GET request to the endpoint and specify the ID returned from the POST call. + + ```shell-session + $ curl http://127.0.0.1:8500/v1/query/14af5ff-29e6-e972-dcf8-6ee602137127/execute\?near\=_agent + ``` + +## Execute prepared queries + +You can execute a prepared query using the standard lookup format or the strict RFC 2782 SRV lookup. + +### Standard lookup + +Use the following format to execute a prepared query using the standard lookup format: + +``` +.query[.]. +``` + +Refer [Standard lookups](/consul/docs/services/discovery/dns-static-lookups#standard-lookups) for additional information about the standard lookup format in Consul. + +### RFC 2782 SRV lookup + +Use the following format to execute a prepared query using the RFC 2782 lookup format: + +``` +_._tcp.query[.]. +``` + +For additional information about following the RFC 2782 SRV lookup format in Consul, refer to [RFC 2782 Lookup](/consul/docs/services/discovery/dns-static-lookups#rfc-2782-lookup). For general information about the RFC 2782 specification, refer to [A DNS RR for specifying the location of services \(DNS SRV\)](https://tools.ietf.org/html/rfc2782). + +### Lookup options + +The `datacenter` subdomain is optional. By default, the lookup queries the datacenter of this Consul agent. + +The `query name` or `id` subdomain is the name or ID of an existing prepared query. + +## Results + +To allow for simple load balancing, Consul returns the set of nodes in random order for each query. Prepared queries support A and SRV records. SRV records provide the port that a service is registered. Consul only serves SRV records if the client specifically requests them. diff --git a/website/content/docs/services/discovery/dns-overview.mdx b/website/content/docs/services/discovery/dns-overview.mdx new file mode 100644 index 000000000000..37eda715de25 --- /dev/null +++ b/website/content/docs/services/discovery/dns-overview.mdx @@ -0,0 +1,41 @@ +--- +layout: docs +page_title: DNS usage overview +description: >- + For service discovery use cases, Domain Name Service (DNS) is the main interface to look up, query, and address Consul nodes and services. Learn how a Consul DNS lookup can help you find services by tag, name, namespace, partition, datacenter, or domain. +--- + +# DNS usage overview + +This topic provides overview information about how to look up Consul nodes and services using the Consul DNS. + +## Consul DNS +The Consul DNS is the primary interface for discovering services registered in the Consul catalog. The DNS enables you to look up services and nodes registered with Consul using terminal commands instead of making HTTP API requests to Consul. + +We recommend using the DNS for service discovery in virtual machine (VM) environments because it removes the need to modify native applications so that they can consume the Consul service discovery APIs. + +The DNS has several default configurations, but you can customize how the server processes lookups. Refer to [Configure DNS Behaviors](/consul/docs/services/discovery/dns-configuration) for additional information. + +### DNS versus native app integration +You can use DNS to reach services registered with Consul or modify your application to natively consume the Consul service discovery HTTP APIs. + +We recommend using the DNS because it is less invasive. You do not have to modify your application with Consul to retrieve the service’s connection information. Instead, you can use a DNS fully qualified domain (FQDN) that conforms to Consul's lookup format to retreive the relevant information. + +Refer to [ Native App Integration](/consul/docs/connect/native) and its [Go package](/consul/docs/connect/native/go) for additional information. + +### DNS versus upstreams +If you are using Consul for service discovery and have not enabled service mesh features, then use the DNS to discover services and nodes in the Consul catalog. + +If you are using Consul for service mesh on VMs, you can use upstreams or DNS. We recommend using upstreams because you can query services and nodes without modifying the application code or environment variables. Refer to [Upstream Configuration Reference](/consul/docs/connect/registration/service-registration#upstream-configuration-reference) for additional information. + +If you are using Consul on Kubernetes, refer to [the upstreams annotation documentation](/consul/docs/k8s/annotations-and-labels#consul-hashicorp-com-connect-service-upstreams) for additional information. + +## Static queries +Node lookups and service lookups are the fundamental types of static queries. Depending on your use case, you may need to use different query methods and syntaxes to query the DNS for services and nodes. + +Consul relies on a very specific format for queries to resolve names. Note that all queries are case-sensitive. + +Refer to [Perform Static DNS Lookups](/consul/docs/services/discovery/dns-static-lookups) for details about how to perform node and service lookups. + +## Prepared queries +Prepared queries are configurations that enable you to register complex DNS queries. They provide lookup features that extend Consul's service discovery capabilities, such as filtering by multiple tags and automatically querying remote datacenters for services if no healthy nodes are available in the local datacenter. You can also create prepared query templates that match names using a prefix match, allowing a single template to apply to potentially many services. Refer to [Enable Dynamic DNS Queries](/consul/docs/services/discovery/dns-dynamic-lookups) for additional information. diff --git a/website/content/docs/services/discovery/dns-static-lookups.mdx b/website/content/docs/services/discovery/dns-static-lookups.mdx new file mode 100644 index 000000000000..6f2db4108c37 --- /dev/null +++ b/website/content/docs/services/discovery/dns-static-lookups.mdx @@ -0,0 +1,357 @@ +--- +layout: docs +page_title: Perform static DNS queries +description: -> + Learn how to use standard Consul DNS lookup formats to enable service discovery for services and nodes. +--- + +# Perform static DNS queries +This topic describes how to query the Consul DNS to look up nodes and services registered with Consul. Refer to [Enable Dynamic DNS Queries](/consul/docs/services/discovery/dns-dynamic-lookups) for information about using prepared queries. + +## Introduction +Node lookups and service lookups are the fundamental types of queries you can perform using the Consul DNS. Node lookups interrogate the catalog for named Consul agents. Service lookups interrogate the catalog for services registered with Consul. Refer to [DNS Usage Overivew](/consul/docs/services/discovery/dns-overview) for additional background information. + +## Requirements +All versions of Consul support DNS lookup features. + +### ACLs +If ACLs are enabled, you must present a token linked with the necessary policies. We recommend using a separate token in production deployments for querying the DNS. By default, Consul agents resolve DNS requests using the preconfigured tokens in order of precedence: + +The agent's [`default` token](/consul/docs/agent/config/config-files#acl_tokens_default) +The built-in [`anonymous` token](/consul/docs/security/acl/acl-tokens#built-in-tokens). + + +The following table describes the available DNS lookups and required policies when ACLs are enabled: + +| Lookup | Type | Description | ACLs Required | +| --- | --- | --- | --- | +| `*.node.consul` | Node | Allows Consul to resolve DNS requests for the target node. Example: `.node.consul` | `node:read` | +| `*.service.consul`
    `*.connect.consul`
    `*.ingress.consul`
    `*.virtual.consul` |Service: standard | Allows Consul to resolve DNS requests for target service instances running on ACL-authorized nodes. Example: `.service.consul` | `service:read`
    `node:read` | + +> **Tutorials**: For hands-on guidance on how to configure an appropriate token for DNS, refer to the tutorial for [Production Environments](/consul/tutorials/security/access-control-setup-production#token-for-dns) and [Development Environments](/consul/tutorials/day-0/access-control-setup#enable-acls-on-consul-clients). + +## Node lookups +Specify the name of the node, datacenter, and domain using the following FQDN syntax: + +```text +.node[..dc]. +``` + +The `datacenter` subdomain is optional. By default, the lookup queries the datacenter of the agent. + +By default, the domain is `consul`. Refer to [Configure DNS Behaviors](/consul/docs/services/discovery/dns-configuration) for information about using alternate domains. + +### Node lookup results + +Node lookups return A and AAAA records that contain the IP address and TXT records containing the `node_meta` values of the node. + +By default, TXT record values match the node's metadata key-value pairs according to [RFC1464](https://www.ietf.org/rfc/rfc1464.txt). If the metadata key starts with `rfc1035-`, the TXT record only includes the node's metadata value. + +The following example lookup queries the `foo` node in the `default` datacenter: + +```shell-session +$ dig @127.0.0.1 -p 8600 foo.node.consul ANY + +; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 -p 8600 foo.node.consul ANY +; (1 server found) +;; global options: +cmd +;; Got answer: +;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24355 +;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0 +;; WARNING: recursion requested but not available + +;; QUESTION SECTION: +;foo.node.consul. IN ANY + +;; ANSWER SECTION: +foo.node.consul. 0 IN A 10.1.10.12 +foo.node.consul. 0 IN TXT "meta_key=meta_value" +foo.node.consul. 0 IN TXT "value only" + + +;; AUTHORITY SECTION: +consul. 0 IN SOA ns.consul. postmaster.consul. 1392836399 3600 600 86400 0 +``` + +### Node lookups for Consul Enterprise + +Consul Enterprise includes the admin partition concept, which is an abstraction that lets you define isolated administrative network areas. Refer to [Admin Partitions](/consul/docs/enterprise/admin-partitions) for additional information. + +Consul nodes reside in admin partitions within a datacenter. By default, node lookups query the same partition and datacenter of the Consul agent that received the DNS query. + +Use the following query format to specify a partition for a node lookup: + +``` +.node[..ap][..dc]. +``` + +Consul server agents are in the `default` partition. If you send a DNS query to Consul server agents, you must explicitly specify the partition of the target node if it is not `default`. + +## Service lookups +You can query the network for service providers using either the [standard lookup](#standard-lookup) method or [strict RFC 2782 lookup](#rfc-2782-lookup) method. + +By default, all SRV records are weighted equally in service lookup responses, but you can configure the weights using the [`Weights`](/consul/docs/services/configuration/services-configuration-reference#weights) attribute of the service definition. Refer to [Define Services](/consul/docs/services/usage/define-services) for additional information. + +The DNS protocol limits the size of requests, even when performing DNS TCP queries, which may affect your experience querying for services. For services with more than 500 instances, you may not be able to retrieve the complete list of instances for the service. Refer to [RFC 1035, Domain Names - Implementation and Specification](https://datatracker.ietf.org/doc/html/rfc1035#section-2.3.4) for additional information. + +Consul randomizes DNS SRV records and ignores weights specified in service configurations when printing responses. If records are truncated, each client using weighted SRV responses may have partial and inconsistent views of instance weights. As a result, the request distribution may be skewed from the intended weights. We recommend calling the [`/catalog/nodes` API endpoint](/consul/api-docs/catalog#list-nodes) to retrieve the complete list of nodes. You can apply query parameters to API calls to sort and filter the results. + +### Standard lookups +To perform standard service lookups, specify tags, the name of the service, datacenter, and domain using the following syntax to query for service providers: + +```text +[.].service[.].dc. +``` + +The `tag` subdomain is optional. It filters responses so that only service providers containing the tag appear. + +The `datacenter` subdomain is optional. By default, Consul interrogates the querying agent's datacenter. + +By default, the lookups query in the `consul` domain. Refer to [Configure DNS Behaviors](/consul/docs/services/discovery/dns-configuration) for information about using alternate domains. + +#### Standard lookup results +Standard services queries return A and SRV records. SRV records include the port that the service is registered on. SRV records are only served if the client specifically requests them. + +Services that fail their health check or that fail a node system check are omitted from the results. As a load balancing measure, Consul randomizes the set of nodes returned in the response. These mechanisms help you use DNS with application-level retries as the foundation for a self-healing service-oriented architecture. + +The following example retrieves the SRV records for any `redis` service registered in Consul. + +```shell-session +$ dig @127.0.0.1 -p 8600 consul.service.consul SRV + +; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 -p 8600 consul.service.consul ANY +; (1 server found) +;; global options: +cmd +;; Got answer: +;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50483 +;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 1, ADDITIONAL: 1 +;; WARNING: recursion requested but not available + +;; QUESTION SECTION: +;consul.service.consul. IN SRV + +;; ANSWER SECTION: +consul.service.consul. 0 IN SRV 1 1 8300 foobar.node.dc1.consul. + +;; ADDITIONAL SECTION: +foobar.node.dc1.consul. 0 IN A 10.1.10.12 +``` + +The following example command and FQDN retrieves the SRV records for the primary Postgres service in the secondary datacenter: + +```shell-session hideClipboard +$ dig @127.0.0.1 -p 8600 primary.postgresql.service.dc2.consul SRV + +; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 -p 8600 primary.postgresql.service.dc2.consul ANY +; (1 server found) +;; global options: +cmd +;; Got answer: +;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50483 +;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 1, ADDITIONAL: 1 +;; WARNING: recursion requested but not available + +;; QUESTION SECTION: +;consul.service.consul. IN SRV + +;; ANSWER SECTION: +consul.service.consul. 0 IN SRV 1 1 5432 primary.postgresql.service.dc2.consul. + +;; ADDITIONAL SECTION: +primary.postgresql.service.dc2.consul. 0 IN A 10.1.10.12 +``` + +### RFC 2782 lookup +Per [RFC 2782](https://tools.ietf.org/html/rfc2782), SRV queries must prepend `service` and `protocol` values with an underscore (`_`) to prevent DNS collisions. Use the following syntax to perform RFC 2782 lookups: + +```text +_._[.service][.]. +``` + +You can create lookups that filter results by placing service tags in the `protocol` field. Use the following syntax to create RFC 2782 lookups that filter results based on service tags: + +```text +_._[.service][.]. +``` + +The following example queries the `rabbitmq` service tagged with `amqp`, which returns an instance at `rabbitmq.node1.dc1.consul` on port `5672`: + +```shell-session +$ dig @127.0.0.1 -p 8600 _rabbitmq._amqp.service.consul SRV + +; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 -p 8600 _rabbitmq._amqp.service.consul ANY +; (1 server found) +;; global options: +cmd +;; Got answer: +;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 52838 +;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 +;; WARNING: recursion requested but not available + +;; QUESTION SECTION: +;_rabbitmq._amqp.service.consul. IN SRV + +;; ANSWER SECTION: +_rabbitmq._amqp.service.consul. 0 IN SRV 1 1 5672 rabbitmq.node1.dc1.consul. + +;; ADDITIONAL SECTION: +rabbitmq.node1.dc1.consul. 0 IN A 10.1.11.20 +``` +#### SRV responses for hosts in the .addr subdomain + +If a service registered with Consul is configured with an explicit IP address or addresses in the [`address`](/consul/docs/services/configuration/services-configuration-reference#address) or [`tagged_address`](/consul/docs/services/configuration/services-configuration-reference#tagged_address) parameter, then Consul returns the hostname in the target field of the answer section for the DNS SRV query according to the following format: + +```text +.addr..consul`. +``` + +In the following example, the `rabbitmq` service is registered with an explicit IPv4 address of `192.0.2.10`. + +```hcl +node_name = "node1" + +services { + name = "rabbitmq" + address = "192.0.2.10" + port = 5672 +} +{ + "node_name": "node1", + "services": [ + { + "name": "rabbitmq", + "address": "192.0.2.10", + "port": 5672 + } + ] +} +``` + +The following example SRV query response contains a single record with a hostname written as a hexadecimal value: + +```shell-session +$ dig @127.0.0.1 -p 8600 -t srv _rabbitmq._tcp.service.consul +short +1 1 5672 c000020a.addr.dc1.consul. +``` + +You can convert hex octets to decimals to reveal the IP address. The following example command converts the hostname expressed as `c000020a` into the IPv4 address specified in the service registration. + +``` +$ echo -n "c000020a" | perl -ne 'printf("%vd\n", pack("H*", $_))' +192.0.2.10 +``` + +In the following example, the `rabbitmq` service is registered with an explicit IPv6 address of `2001:db8:1:2:cafe::1337`. + +```hcl +node_name = "node1" + +services { + name = "rabbitmq" + address = "2001:db8:1:2:cafe::1337" + port = 5672 +} +{ + "node_name": "node1", + "services": [ + { + "name": "rabbitmq", + "address": "2001:db8:1:2:cafe::1337", + "port": 5672 + } + ] +} +``` + +The following example SRV query response contains a single record with a hostname written as a hexadecimal value: + +```shell-session +$ dig @127.0.0.1 -p 8600 -t SRV _rabbitmq._tcp.service.consul +short +1 1 5672 20010db800010002cafe000000001337.addr.dc1.consul. +``` + +The response contains the fully-expanded IPv6 address with colon separators removed. The following command re-adds the colon separators to display the fully expanded IPv6 address that was specified in the service registration. + +```shell-session +$ echo -n "20010db800010002cafe000000001337" | perl -ne 'printf join(":", unpack("(A4)*", $_))."\n"' +2001:0db8:0001:0002:cafe:0000:0000:1337 +``` + +### Service lookups for Consul Enterprise +You can perform the following types of service lookups to query for services in another namespace, partition, and datacenter: + +- `.service` +- `.connect` +- `.virtual` +- `.ingress` + +Use the following query format to specify namespace, partition, or datacenter: +``` +[.].service[..ns][..ap][..dc] +``` + +The `namespace`, `partition`, and `datacenter` are optional. By default, all service lookups use the `default` namespace within the partition and datacenter of the Consul agent that received the DNS query. + +Consul server agents reside in the `default` partition. If DNS queries are addressed to Consul server agents, you must explicitly specify the partition of the target service when querying for services in partitions other than `default`. + +To lookup services imported from a cluster peer, refer to [Service virtual IP lookups for Consul Enterprise](#service-virtual-ip-lookups-for-consul-enterprise). + +#### Alternative formats for specifying namespace + +Although we recommend using the format described in [Service lookups for Consul Enterprise](#service-lookups-for-consul-enterprise) for readability, you can use the alternate query format to specify namespaces but not partitions: + +``` +[.].service... +``` + +### Service mesh-enabled service lookups + +Add the `.connect` subdomain to query for service mesh-enabled services: + +```text +.connect. +``` + +This finds all service mesh-capable endpoints for the service. A service mesh-capable endpoint may be a proxy for a service or a natively integrated service mesh application. The DNS interface does not differentiate the two. + +Many services use a proxy that handles service discovery automatically. As a result, they may not use the DNS format, which is primarily for service mesh-native applications. +This endpoint only finds services within the same datacenter and does not support tags. Refer to the [`catalog` API endpoint](/consul/api-docs/catalog) for more complex behaviors. + +### Service virtual IP lookups + +Add the `.virtual` subdomain to queries to find the unique virtual IP allocated for a service: + +```text +.virtual[.]. +``` + +This returns the unique virtual IP for any service mesh-capable service. Each service mesh service has a virtual IP assigned to it by Consul. Sidecar proxies use the virtual IP to enable the [transparent proxy](/consul/docs/connect/transparent-proxy) feature. + +The peer name is an optional. The DNS uses it to query for the virtual IP of a service imported from the specified peer. + +Consul adds virtual IPs to the [`tagged_addresses`](/consul/docs/services/configuration/services-configuration-reference#tagged_addresses) field in the service definition under the `consul-virtual` tag. + +#### Service virtual IP lookups for Consul Enterprise + +By default, a service virtual IP lookup checks the `default` namespace within the partition and datacenter of the Consul agent that received the DNS query. +To lookup services imported from a partition in another cluster peered to the querying cluster or open-source datacenter, specify the namespace and peer name in the lookup: + +```text +.virtual[.].. +``` + +To lookup services in a cluster peer that have not been imported, refer to [Service lookups for Consul Enterprise](#service-lookups-for-consul-enterprise). + +### Ingress Service Lookups + +Add the `.ingress` subdomain to your DNS FQDN to find ingress-enabled services: + +```text +.ingress. +``` + +This finds all ingress gateway endpoints for the service. + +This endpoint finds services within the same datacenter and does not support tags. Refer to the [`catalog` API endpoint](/consul/api-docs/catalog) for more complex behaviors. + +### UDP-based DNS queries + +When the DNS query is performed using UDP, Consul truncateß the results without setting the truncate bit. This prevents a redundant lookup over TCP that generates additional load. If the lookup is done over TCP, the results are not truncated. \ No newline at end of file diff --git a/website/content/docs/services/services.mdx b/website/content/docs/services/services.mdx new file mode 100644 index 000000000000..7300b9d1aa80 --- /dev/null +++ b/website/content/docs/services/services.mdx @@ -0,0 +1,49 @@ +--- +layout: docs +page_title: Services overview +description: >- + Learn about services and service discovery workflows and concepts for virtual machine environments. +--- + +# Services overview + +This topic provides overview information about services and how to make them discoverable in Consul when your network operates on virtual machines. If service mesh is enabled in your network, refer to the following articles for additional information about connecting services in a mesh: + +- [How Service Mesh Works](/consul/docs/connect/connect-internals) +- [How Consul Service Mesh Works on Kubernetes](/consul/docs/k8s/connect) + +## Introduction + +A _service_ is an entity in your network that performs a specialized operation or set of related operations. In many contexts, a service is software that you want to make available to users or other programs with access to your network. Services can also refer to native Consul functionality, such as _service mesh proxies_ and _gateways_, that enable you to establish connections between different parts of your network. + +You can define and register services with Consul, which makes them discoverable to other services in the network. You can also define various types of health checks that perform several safety functions, such as allowing a web balancer to gracefully remove failing nodes and allowing a database to replace a failed secondary. + +## Workflow + +For service discovery, the core Consul workflow for services consists of three stages: + +1. **Define services and health checks**: A service definition lets you define various aspects of the service, including how it is discovered by other services in the network. You can define health checks in the service definitions to verify the health of the service. Refer to [Define Services](/consul/docs/services/usage/define-services) and [Define Health Checks](/consul/docs/services/usage/checks) for additional information. + +1. **Register services and health checks**: After defining your services and health checks, you must register them with a Consul agent. Refer to [Register Services and Health Checks](/consul/docs/services/usage/register-services-checks) for additional information. + +1. **Query for services**: After registering your services and health checks, other services in your network can use the DNS to perform static or dynamic lookups to access your service. Refer to [DNS Usage Overview](/consul/docs/services/discovery/dns-overview) for additional information about the different ways to discover services in your datacenters. + + +## Service mesh use cases + +Consul redirects service traffic through sidecar proxies if you use Consul service mesh. As a result, you must specify upstream configurations in service definitions. The service mesh experience is different for virtual machine (VM) and Kubernetes environments. + +### Virtual machines + +You must define upstream services in the service definition. Consul uses the upstream configuration to bind the service with its upstreams. After registering the service, you must start a sidecar proxy on the VM to enable mesh connectivity. Refer to [Register a Service Mesh Proxy in a Service Registration](/consul/docs/connect/registration/sidecar-service) for details. + +### Kubernetes + +If you use Consul on Kubernetes, enable the service mesh injector in your Consul Helm chart and Consul automatically adds a sidecar to each of your pods using the Kubernetes `Service` definition as a reference. You can specify upstream annotations in the `Deployment` definition to bind upstream services to the pods. +Refer to [`connectInject`](/consul/docs/k8s/connect#installation-and-configuration) and [the upstreams annotation documentation](/consul/docs/k8s/annotations-and-labels#consul-hashicorp-com-connect-service-upstreams) for additional information. + +### Multiple services + +You can define common characteristics for services in your mesh, such as the admin partition, namespace, or upstreams, by creating and applying a `service-defaults` configuration entry. You can also define override configurations for specific upstreams or service instances. To use `service-defaults` configuraiton entries, you must enable Consul service mesh in your network. + +Refer to [Define Service Defaults](/consul/docs/services/usage/define-services#define-service-defaults) for additional information. \ No newline at end of file diff --git a/website/content/docs/services/usage/checks.mdx b/website/content/docs/services/usage/checks.mdx new file mode 100644 index 000000000000..afbf53dcc99b --- /dev/null +++ b/website/content/docs/services/usage/checks.mdx @@ -0,0 +1,592 @@ +--- +layout: docs +page_title: Define health checks +description: -> + Learn how to configure different types of health checks for services you register with Consul. +--- + +# Define health checks +This topic describes how to create different types of health checks for your services. + + +## Overview +Health checks are configurations that verifies the health of a service or node. Health checks configurations are nested in the `service` block. Refer to [Define Services](/consul/docs/services/usage/define-services) for information about specifying other service parameters. + +You can define individual health checks for your service in separate `check` blocks or define multiple checks in a `checks` block. Refer to [Define multiple checks](#define-multiple-checks) for additional information. + +You can create several different kinds of checks: + +- _Script_ checks invoke an external application that performs the health check, exits with an appropriate exit code, and potentially generates output. Script checks are one of the most common types of checks. +- _HTTP_ checks make an HTTP GET request to the specified URL and wait for the specified amount of time. HTTP checks are one of the most common types of checks. +- _TCP_ checks attempt to connect to an IP or hostname and port over TCP and wait for the specified amount of time. +- _UDP_ checks send UDP datagrams to the specified IP or hostname and port and wait for the specified amount of time. +- _Time-to-live (TTL)_ checks are passive checks that await updates from the service. If the check does not receive a status update before the specified duration, the health check enters a `critical`state. +- _Docker_ checks are dependent on external applications packaged with a Docker container that are triggered by calls to the Docker `exec` API endpoint. +- _gRPC_ checks probe applications that support the standard gRPC health checking protocol. +- _H2ping_ checks test an endpoint that uses http2. The check connects to the endpoint and sends a ping frame. +- _Alias_ checks represent the health state of another registered node or service. + +If your network runs in a Kubernetes environment, you can sync service health information with Kubernetes health checks. Refer to [Configure Health Checks for Consul on Kubernetes](/consul/docs/k8s/connect/health) for details. + +### Registration + +After defining health checks, you must register the service containing the checks with Consul. Refer to [Register Services and Health Checks](/consul/docs/services/usage/register-services-checks) for additional information. If the service is already registered, you can reload the service configuration file to implement your health check. Refer to [Reload](/consul/commands/reload) for additional information. + +## Define multiple checks + +You can define multiple checks for a service in a single `checks` block. The `checks` block contains an array of objects. The objects contain the configuration for each health check you want to implement. The following example includes two script checks named `mem` and `cpu` and an HTTP check that calls the `/health` API endpoint. + + + +```hcl +checks = [ + { + id = "chk1" + name = "mem" + args = ["/bin/check_mem", "-limit", "256MB"] + interval = "5s" + }, + { + id = "chk2" + name = "/health" + http = "http://localhost:5000/health" + interval = "15s" + }, + { + id = "chk3" + name = "cpu" + args = ["/bin/check_cpu"] + interval = "10s" + }, + ... +] +``` + +```json +{ + "checks": [ + { + "id": "chk1", + "name": "mem", + "args": ["/bin/check_mem", "-limit", "256MB"], + "interval": "5s" + }, + { + "id": "chk2", + "name": "/health", + "http": "http://localhost:5000/health", + "interval": "15s" + }, + { + "id": "chk3", + "name": "cpu", + "args": ["/bin/check_cpu"], + "interval": "10s" + }, + ... + ] +} +``` + + + +## Define initial health check status +When checks are registered against a Consul agent, they are assigned a `critical` status by default. This prevents services from registering as `passing` and entering the service pool before their health is verified. You can add the `status` parameter to the check definition to specify the initial state. In the following example, the check registers in a `passing` state: + + + +```hcl +check = { + id = "mem" + args = ["/bin/check_mem", "-limit", "256MB"] + interval = "10s" + status = "passing" +} +``` + +```json +{ + "check": [ + { + "args": [ + "/bin/check_mem", + "-limit", + "256MB" + ], + "id": "mem", + "interval": "10s", + "status": "passing" + } + ] +} +``` + + + +## Script checks +Script checks invoke an external application that performs the health check, exits with an appropriate exit code, and potentially generates output data. The output of a script check is limited to 4KB. Outputs that exceed the limit are truncated. + +Script checks timeout after 30 seconds by default, but you can configure a custom script check timeout value by specifying the `timeout` field in the check definition. When the timeout is reached on Windows, Consul waits for any child processes spawned by the script to finish. For any other system, Consul attempts to force-kill the script and any child processes it has spawned once the timeout has passed. + +### Script check configuration +To enable script checks, you must first enable the agent to send external requests, then configure the health check settings in the service definition: + +1. Add one of the following configurations to your agent configuration file to enable a script check: + - [`enable_local_script_checks`](/consul/docs/agent/config/cli-flags#enable_local_script_checks): Enable script checks defined in local configuration files. Script checks registered using the HTTP API are not allowed. + - [`enable_script_checks`](/consul/docs/agent/config/cli-flags#enable_script_checks): Enable script checks no matter how they are registered. + + !> **Security warning:** Enabling non-local script checks in some configurations may introduce a known remote execution vulnerability targeted by malware. We strongly recommend `enable_local_script_checks` instead. + +1. Specify the script to run in the `args` of the `check` block in your service configuration file. In the following example, a check named `Memory utilization` invokes the `check_mem.py` script every 10 seconds and times out if a response takes longer than one second: + + + + ```hcl + service { + ## ... + check = { + id = "mem-util" + name = "Memory utilization" + args = ["/usr/local/bin/check_mem.py", "-limit", "256MB"] + interval = "10s" + timeout = "1s" + } + } + ``` + + ```json + { + "service": [ + { + "check": { + "id": "mem-util", + "name": "Memory utilization", + "args": ["/usr/local/bin/check_mem.py", "-limit", "256MB"], + "interval": "10s", + "timeout": "1s" + } + } ] + } + ``` + + +Refer to [Health Checks Configuration Reference](/consul/docs/services/configuration/checks-configuration-reference) for information about all health check configurations. + +### Script check exit codes +The following exit codes returned by the script check determine the health check status: + +- Exit code 0 - Check is passing +- Exit code 1 - Check is warning +- Any other code - Check is failing + +Any output of the script is captured and made available in the `Output` field of checks included in HTTP API responses. Refer to the example described in the [local service health endpoint](/consul/api-docs/agent/service#by-name-json). + +## HTTP checks +_HTTP_ checks send an HTTP request to the specified URL and report the service health based on the [HTTP response code](#http-check-response-codes). We recommend using HTTP checks over [script checks](#script-checks) that use cURL or another external process to check an HTTP operation. + +### HTTP check configuration +Add an `http` field to the `check` block in your service definition file and specify the HTTP address, including port number, for the check to call. All other fields are optional. Refer to [Health Checks Configuration Reference](/consul/docs/services/configuration/checks-configuration-reference) for information about all health check configurations. + +In the following example, an HTTP check named `HTTP API on port 5000` sends a `POST` request to the `health` endpoint every 10 seconds: + + + +```hcl +check = { + id = "api" + name = "HTTP API on port 5000" + http = "https://localhost:5000/health" + tls_server_name = "" + tls_skip_verify = false + method = "POST" + header = { + Content-Type = ["application/json"] + } + body = "{\"method\":\"health\"}" + disable_redirects = true + interval = "10s" + timeout = "1s" +} +``` + +```json +{ + "check": { + "id": "api", + "name": "HTTP API on port 5000", + "http": "https://localhost:5000/health", + "tls_server_name": "", + "tls_skip_verify": false, + "method": "POST", + "header": { "Content-Type": ["application/json"] }, + "body": "{\"method\":\"health\"}", + "interval": "10s", + "timeout": "1s" + } +} +``` + + +HTTP checks send GET requests by default, but you can specify another request method in the `method` field. You can send additional headers in the `header` block. The `header` block contains a key and an array of strings, such as `{"x-foo": ["bar", "baz"]}`. By default, HTTP checks timeout at 10 seconds, but you can specify a custom timeout value in the `timeout` field. + +HTTP checks expect a valid TLS certificate by default. You can disable certificate verification by setting the `tls_skip_verify` field to `true`. When using TLS and a host name is specified in the `http` field, the check automatically determines the SNI from the URL. If the `http` field is configured with an IP address or if you want to explicitly set the SNI, specify the name in the `tls_server_name` field. + +The check follows HTTP redirects configured in the network by default. Set the `disable_redirects` field to `true` to disable redirects. + +### HTTP check response codes +Responses larger than 4KB are truncated. The HTTP response determines the status of the service: + +- A `200`-`299` response code is healthy. +- A `429` response code indicating too many requests is a warning. +- All other response codes indicate a failure. + + +## TCP checks +TCP checks establish connections to the specified IPs or hosts. If the check successfully establishes a connection, the service status is reported as `success`. If the IP or host does not accept the connection, the service status is reported as `critical`. We recommend TCP checks over [script checks](#script-checks) that use netcat or another external process to check a socket operation. + +### TCP check configuration +Add a `tcp` field to the `check` block in your service definition file and specify the address, including port number, for the check to call. All other fields are optional. Refer to [Health Checks Configuration Reference](/consul/docs/services/configuration/checks-configuration-reference) for information about all health check configurations. + +In the following example, a TCP check named `SSH TCP on port 22` attempts to connect to `localhost:22` every 10 seconds: + + + + +```hcl +check = { + id = "ssh" + name = "SSH TCP on port 22" + tcp = "localhost:22" + interval = "10s" + timeout = "1s" +} +``` + +```json +{ + "check": { + "id": "ssh", + "name": "SSH TCP on port 22", + "tcp": "localhost:22", + "interval": "10s", + "timeout": "1s" + } +} +``` + + + +If a hostname resolves to an IPv4 and an IPv6 address, Consul attempts to connect to both addresses. The first successful connection attempt results in a successful check. + +By default, TCP check requests timeout at 10 seconds, but you can specify a custom timeout in the `timeout` field. + +## UDP checks +UDP checks direct the Consul agent to send UDP datagrams to the specified IP or hostname and port. The check status is set to `success` if any response is received from the targeted UDP server. Any other result sets the status to `critical`. + +### UDP check configuration +Add a `udp` field to the `check` block in your service definition file and specify the address, including port number, for sending datagrams. All other fields are optional. Refer to [Health Checks Configuration Reference](/consul/docs/services/configuration/checks-configuration-reference) for information about all health check configurations. + +In the following example, a UDP check named `DNS UDP on port 53` sends datagrams to `localhost:53` every 10 seconds: + + + +```hcl +check = { + id = "dns" + name = "DNS UDP on port 53" + udp = "localhost:53" + interval = "10s" + timeout = "1s" +} +``` + +```json +{ + "check": { + "id": "dns", + "name": "DNS UDP on port 53", + "udp": "localhost:53", + "interval": "10s", + "timeout": "1s" + } +} +``` + + + +By default, UDP checks timeout at 10 seconds, but you can specify a custom timeout in the `timeout` field. If any timeout on read exists, the check is still considered healthy. + +## OSService check +OSService checks if an OS service is running on the host. OSService checks support Windows services on Windows hosts or SystemD services on Unix hosts. The check logs the service as `healthy` if it is running. If the service is not running, the status is logged as `critical`. All other results are logged with `warning`. A `warning` status indicates that the check is not reliable because an issue is preventing it from determining the health of the service. + +### OSService check configurations +Add an `os_service` field to the `check` block in your service definition file and specify the name of the service to check. All other fields are optional. Refer to [Health Checks Configuration Reference](/consul/docs/services/configuration/checks-configuration-reference] for information about all health check configurations. + +In the following example, an OSService check named `svcname-001 Windows Service Health` verifies that the `myco-svctype-svcname-001` service is running every 10 seconds: + + + +```hcl +check = { + id = "myco-svctype-svcname-001" + name = "svcname-001 Windows Service Health" + service_id = "flash_pnl_1" + os_service = "myco-svctype-svcname-001" + interval = "10s" +} +``` + +```json +{ + "check": { + "id": "myco-svctype-svcname-001", + "name": "svcname-001 Windows Service Health", + "service_id": "flash_pnl_1", + "os_service": "myco-svctype-svcname-001", + "interval": "10s" + } +} +``` + + + +## TTL checks +Time-to-live (TTL) checks wait for an external process to report the service's state to a Consul [`/agent/check` HTTP endpoint](/consul/api-docs/agent/check). If the check does not receive an update before the specified `ttl` duration, the check logs the service as `critical`. For example, if a healthy application is configured to periodically send a `PUT` request a status update to the HTTP endpoint, then the health check logs a `critical` state if the application is unable to send the update before the TTL expires. The check uses the following endpoints to update health information: + +- [pass](/consul/api-docs/agent/check#ttl-check-pass) +- [warn] (/consul/api-docs/agent/check#ttl-check-warn) +- [fail](/consul/api-docs/agent/check#ttl-check-fail) +- [update](/consul/api-docs/agent/check#ttl-check-update) + +TTL checks also persist their last known status to disk so that the Consul agent can restore the last known status of the check across restarts. Persisted check status is valid through the end of the TTL from the time of the last check. + +You can manually mark a service as unhealthy using the [`consul maint` CLI command](/consul/commands/maint) or [`agent/maintenance` HTTP API endpoint](/consul/api-docs/agent#enable-maintenance-mode), rather than waiting for a TTL health check if the `ttl` duration is high. + +### TTL check configuration +Add a `ttl` field to the `check` block in your service definition file and specify how long to wait for an update from the external process. All other fields are optional. Refer to [Health Checks Configuration Reference](/consul/docs/services/configuration/checks-configuration-reference] for information about all health check configurations. + +In the following example, a TTL check named `Web App Status` logs the application as `critical` if a status update is not received every 30 seconds: + + + + +```hcl +check = { + id = "web-app" + name = "Web App Status" + notes = "Web app does a curl internally every 10 seconds" + ttl = "30s" +} +``` + +```json +{ + "check": { + "id": "web-app", + "name": "Web App Status", + "notes": "Web app does a curl internally every 10 seconds", + "ttl": "30s" + } +} +``` + + + +## Docker checks +Docker checks invoke an application packaged within a Docker container. The application should perform a health check and exit with an appropriate exit code. + +The application is triggered within the running container through the Docker `exec` API. You should have access to either the Docker HTTP API or the Unix socket. Consul uses the `$DOCKER_HOST` environment variable to determine the Docker API endpoint. + +The output of a Docker check is limited to 4KB. Larger outputs are truncated. + +### Docker check configuration +To enable Docker checks, you must first enable the agent to send external requests, then configure the health check settings in the service definition: + +1. Add one of the following configurations to your agent configuration file to enable a Docker check: + + - [`enable_local_script_checks`](/consul/docs/agent/config/cli-flags#enable_local_script_checks): Enable script checks defined in local config files. Script checks registered using the HTTP API are not allowed. + + - [`enable_script_checks`](/consul/docs/agent/config/cli-flags#enable_script_checks): Enable script checks no matter how they are registered. + + !> **Security warning**: Enabling non-local script checks in some configurations may introduce a known remote execution vulnerability targeted by malware. We strongly recommend `enable_local_script_checks` instead. +1. Configure the following fields in the `check` block in your service definition file: + - `docker_container_id`: The `docker ps` command is a common way to get the ID. + - `shell`: Specifies the shell to use for performing the check. Different containers can run different shells on the same host. + - `args`: Specifies the external application to invoke. + - `interval`: Specifies the interval for running the check. + +In the following example, a Docker check named `Memory utilization` invokes the `check_mem.py` application in container `f972c95ebf0e` every 10 seconds: + + + + +```hcl +check = { + id = "mem-util" + name = "Memory utilization" + docker_container_id = "f972c95ebf0e" + shell = "/bin/bash" + args = ["/usr/local/bin/check_mem.py"] + interval = "10s" +} +``` + +```json +{ + "check": { + "id": "mem-util", + "name": "Memory utilization", + "docker_container_id": "f972c95ebf0e", + "shell": "/bin/bash", + "args": ["/usr/local/bin/check_mem.py"], + "interval": "10s" + } +} +``` + + + +## gRPC checks +gRPC checks send a request to the specified endpoint. These checks are intended for applications that support the standard [gRPC health checking protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + +### gRPC check configuration +Add a `grpc` field to the `check` block in your service definition file and specify the endpoint, including port number, for sending requests. All other fields are optional. Refer to [Health Checks Configuration Reference](/consul/docs/services/configuration/checks-configuration-reference] for information about all health check configurations. + +In the following example, a gRPC check named `Service health status` probes the entire application by sending requests to `127.0.0.1:12345` every 10 seconds: + + + +```hcl +check = { + id = "mem-util" + name = "Service health status" + grpc = "127.0.0.1:12345" + grpc_use_tls = true + interval = "10s" +} +``` + +```json +{ + "check": { + "id": "mem-util", + "name": "Service health status", + "grpc": "127.0.0.1:12345", + "grpc_use_tls": true, + "interval": "10s" + } +} +``` + + + +gRPC checks probe the entire gRPC server, but you can check on a specific service by adding the service identifier after the gRPC check's endpoint using the following format: `/:service_identifier`. + +In the following example, a gRPC check probes `my_service` in the application at `127.0.0.1:12345` every 10 seconds: + + + + +```hcl +check = { + id = "mem-util" + name = "Service health status" + grpc = "127.0.0.1:12345/my_service" + grpc_use_tls = true + interval = "10s" +} +``` + +```json +{ + "check": { + "id": "mem-util", + "name": "Service health status", + "grpc": "127.0.0.1:12345/my_service", + "grpc_use_tls": true, + "interval": "10s" + } +} +``` + + + +TLS is disabled for gRPC checks by default. You can enable TLS by setting `grpc_use_tls` to `true`. If TLS is enabled, you must either provide a valid TLS certificate or disable certificate verification by setting the `tls_skip_verify` field to `true`. + +By default, gRPC checks timeout after 10 seconds, but you can specify a custom duration in the `timeout` field. + +## H2ping checks +H2ping checks test an endpoint that uses HTTP2 by connecting to the endpoint and sending a ping frame. If the endpoint sends a response within the specified interval, the check status is set to `success`. + +### H2ping check configuration +Add an `h2ping` field to the `check` block in your service definition file and specify the HTTP2 endpoint, including port number, for the check to ping. All other fields are optional. Refer to [Health Checks Configuration Reference](/consul/docs/services/configuration/checks-configuration-reference) for information about all health check configurations. + +In the following example, an H2ping check named `h2ping` pings the endpoint at `localhost:22222` every 10 seconds: + + + + +```hcl +check = { + id = "h2ping-check" + name = "h2ping" + h2ping = "localhost:22222" + interval = "10s" + h2ping_use_tls = false +} +``` + +```json +{ + "check": { + "id": "h2ping-check", + "name": "h2ping", + "h2ping": "localhost:22222", + "interval": "10s", + "h2ping_use_tls": false + } +} +``` + + + +TLS is enabled by default, but you can disable TLS by setting `h2ping_use_tls` to `false`. When TLS is disabled, the Consul sends pings over h2c. When TLS is enabled, a valid certificate is required unless `tls_skip_verify` is set to `true`. + +By default, H2ping checks timeout at 10 seconds, but you can specify a custom duration in the `timeout` field. + + +## Alias checks +Alias checks continuously report the health state of another registered node or service. If the alias experiences errors while watching the actual node or service, the check reports a`critical` state. Consul updates the alias and actual node or service state asynchronously but nearly instantaneously. + +For aliased services on the same agent, the check monitors the local state without consuming additional network resources. For services and nodes on different agents, the check maintains a blocking query over the agent's connection with a current server and allows stale requests. + +### ACLs +For the blocking query, the alias check presents the ACL token set on the actual service or the token configured in the check definition. If neither are available, the alias check falls back to the default ACL token set for the agent. Refer to [`acl.tokens.default`](/consul/docs/agent/config/config-files#acl_tokens_default) for additional information about the default ACL token. + +### Alias checks configuration +Add an `alias_service` field to the `check` block in your service definition file and specify the name of the service or node to alias. All other fields are optional. Refer to [Health Checks Configuration Reference](/consul/docs/services/configuration/checks-configuration-reference] for information about all health check configurations. + +In the following example, an alias check with the ID `web-alias` reports the health state of the `web` service: + + + + +```hcl +check = { + id = "web-alias" + alias_service = "web" +} +``` + +```json +{ + "check": { + "id": "web-alias", + "alias_service": "web" + } +} +``` + + + +By default, the alias must be registered with the same Consul agent as the alias check. If the service is not registered with the same agent, you must specify `"alias_node": ""` in the `check` configuration. If no service is specified and the `alias_node` field is enabled, the check aliases the health of the node. If a service is specified, the check will alias the specified service on this particular node. \ No newline at end of file diff --git a/website/content/docs/services/usage/define-services.mdx b/website/content/docs/services/usage/define-services.mdx new file mode 100644 index 000000000000..a3801ec8af59 --- /dev/null +++ b/website/content/docs/services/usage/define-services.mdx @@ -0,0 +1,453 @@ +--- +layout: docs +page_title: Define services +description: >- + Learn how to define services so that they are discoverable in your network. +--- + +# Define services + +This topic describes how to define services so that they can be discovered by other services. Refer to [Services Overview](/consul/docs/services/services) for additional information. + +## Overview + +You must tell Consul about the services deployed to your network if you want them to be discoverable. You can define services in a configuration file or send the service definition parameters as a payload to the `/agent/service/register` API endpoint. Refer to [Register Services and Health Checks](/consul/docs/services/usage/register-services-checks) for details about how to register services with Consul. + +You can define multiple services individually using `service` blocks or group multiple services into the same `services` configuration block. Refer to [Define multiple services in a single file](#define-multiple-services-in-a-single-file) for additional information. + +If Consul service mesh is enabled in your network, you can use the [service defaults configuration entry](/consul/docs/connect/config-entries/service-defaults) to specify default global values for services. The configuration entry lets you define common service parameter, such as upstreams, namespaces, and partitions. Refer to [Define service defaults](#define-service-defaults) for additional information. + +## Requirements + +The core service discovery features are available in all versions of Consul. + +### Service defaults +To use the [service defaults configuration entry](#define-service-defaults), verify that your installation meets the following requirements: + +- Consul 1.5.0+ +- Consul 1.8.4+ is required to use the `ServiceDefaults` custom resource on Kubernetes + +### ACLs +If ACLs are enabled, resources in your network must present a token with `service:read` access to read a service defaults configuration entry. + +You must also present a token with `service:write` access to create, update, or delete a service defaults configuration entry. + +Service configurations must also contain and present an ACL token to perform anti-entropy syncs and deregistration operations. Refer to [Modify anti-entropy synchronozation](#modify-anti-entropy-synchronization) for additional information. + +On Consul Enterprise, you can register services with specific namespaces if the services' ACL tokens are scoped to the namespace. Services registered with a service definition do not inherit the namespace associated with the ACL token specified in the `token` field. The `namespace` and the `token` parameters must be included in the service definition for the service to be registered to the namespace that the ACL token is scoped to. + +## Define a service +Create a file for your service configurations and add a `service` block. The `service` block contains the parameters that configure various aspects of the service, including how it is discovered by other services in the network. The only required parameter is `name`. Refer to [Service Definition Reference](/consul/docs/services/configuration/services-configuration-reference) for details about the configuration options. + +For Kubernetes environments, you can enable the [`connectInject`](/consul/docs/k8s/connect#installation-and-configuration) configuration in your Consul Helm chart so that Consul automatically adds a sidecar to each of your pods. Consul uses the Kubernetes `Service` definition as a reference. + +The following example defines a service named `redis` that is available on port `80`. By default, the service has the IP address of the agent node. + + + + +```hcl +service { + name = "redis" + id = "redis" + port = 80 + tags = ["primary"] + + meta = { + custom_meta_key = "custom_meta_value" + } + + tagged_addresses = { + lan = { + address = "192.168.0.55" + port = 8000 + } + + wan = { + address = "198.18.0.23" + port = 80 + } + } +} +``` + + + + +```json +{ + "service": [ + { + "id": "redis", + "meta": [ + { + "custom_meta_key": "custom_meta_value" + } + ], + "name": "redis", + "port": 80, + "tagged_addresses": [ + { + "lan": [ + { + "address": "192.168.0.55", + "port": 8000 + } + ], + "wan": [ + { + "address": "198.18.0.23", + "port": 80 + } + ] + } + ], + "tags": [ + "primary" + ] + } + ] +} +``` + + + +```yaml +service: +- id: redis + meta: + - custom_meta_key: custom_meta_value + name: redis + port: 80 + tagged_addresses: + - lan: + - address: 192.168.0.55 + port: 8000 + wan: + - address: 198.18.0.23 + port: 80 + tags: + - primary +``` + + + +### Health checks + +You can add a `check` or `checks` block to your service configuration to define one or more health checks that monitor the health of your services. Refer to [Define Health Checks](/consul/docs/services/usage/checks) for additional information. + +### Register a service + +You can register your service using the [`consul services` command](/consul/commands/services) or by calling the [`/agent/services` API endpoint](/consul/api-docs/agent/service). Refer to [Register Services and Health Checks](/consul/docs/services/usage/register-services-checks) for details. + +## Define service defaults +If Consul service mesh is enabled in your network, you can define default values for services in your mesh by creating and applying a `service-defaults` configuration entry containing. Refer to [Service Mesh Configuration Overview](/consul/docs/connect/configuration) for additional information. + +Create a file for the configuration entry and specify the required fields. If you are authoring `service-defaults` in HCL or JSON, the `Kind` and `Name` fields are required. On Kubernetes, the `apiVersion`, `kind`, and `metadata.name` fields are required. Refer to [Service Defaults Reference](/consul/docs/connect/config-entries/service-defaults) for details about the configuration options. + + +If you use Consul Enterprise, you can also specify the `Namespace` and `Partition` fields to apply the configuration to services in a specific namespace or partition. For Kubernetes environments, the configuration entry is always created in the same partition as the Kubernetes cluster. + +### Consul OSS example + +The following example instructs services named `counting` to send up to `512` concurrent requests to a mesh gateway: + + + +```hcl +Kind = "service-defaults" +Name = "counting" + +UpstreamConfig = { + Defaults = { + MeshGateway = { + Mode = "local" + } + Limits = { + MaxConnections = 512 + MaxPendingRequests = 512 + MaxConcurrentRequests = 512 + } + } + + Overrides = [ + { + Name = "dashboard" + MeshGateway = { + Mode = "remote" + } + } + ] +} +``` +```yaml +apiVersion: consul.hashicorp.com/v1alpha1 +kind: ServiceDefaults +metadata: + name: counting +spec: + upstreamConfig: + defaults: + meshGateway: + mode: local + limits: + maxConnections: 512 + maxPendingRequests: 512 + maxConcurrentRequests: 512 + overrides: + - name: dashboard + meshGateway: + mode: remote +``` +```json +{ + "Kind": "service-defaults", + "Name": "counting", + "UpstreamConfig": { + "Defaults": { + "MeshGateway": { + "Mode": "local" + }, + "Limits": { + "MaxConnections": 512, + "MaxPendingRequests": 512, + "MaxConcurrentRequests": 512 + } + }, + "Overrides": [ + { + "Name": "dashboard", + "MeshGateway": { + "Mode": "remote" + } + } + ] + } +} +``` + + +### Consul Enterprise example + +The following example instructs services named `counting` in the `prod` namespace to send up to `512` concurrent requests to a mesh gateway: + + + +```hcl +Kind = "service-defaults" +Name = "counting" +Namespace = "prod" + +UpstreamConfig = { + Defaults = { + MeshGateway = { + Mode = "local" + } + Limits = { + MaxConnections = 512 + MaxPendingRequests = 512 + MaxConcurrentRequests = 512 + } + } + + Overrides = [ + { + Name = "dashboard" + MeshGateway = { + Mode = "remote" + } + } + ] +} +``` +```yaml +apiVersion: consul.hashicorp.com/v1alpha1 +kind: ServiceDefaults +metadata: + name: counting + namespace: prod +spec: + upstreamConfig: + defaults: + meshGateway: + mode: local + limits: + maxConnections: 512 + maxPendingRequests: 512 + maxConcurrentRequests: 512 + overrides: + - name: dashboard + meshGateway: + mode: remote +``` +```json +{ + "Kind": "service-defaults", + "Name": "counting", + "Namespace" : "prod", + "UpstreamConfig": { + "Defaults": { + "MeshGateway": { + "Mode": "local" + }, + "Limits": { + "MaxConnections": 512, + "MaxPendingRequests": 512, + "MaxConcurrentRequests": 512 + } + }, + "Overrides": [ + { + "Name": "dashboard", + "MeshGateway": { + "Mode": "remote" + } + } + ] + } +} +``` + + +### Apply service defaults + +You can apply your `service-defaults` configuration entry using the [`consul config` command](/consul/commands/config) or by calling the [`/config` API endpoint](/consul/api-docs/config). In Kubernetes environments, apply the `service-defaults` custom resource definitions (CRD) to implement and manage Consul configuration entries. + +Refer to the following topics for details about applying configuration entries: +- [How to Use Configuration Entries](/consul/docs/agent/config-entries) +- [Custom Resource Definitions for Consul on Kubernetes](/consul/docs/k8s/crds) + +## Define multiple services in a single file + +The `services` block contains an array of `service` objects. It is a wrapper that enables you to define multiple services in the service definition and instruct Consul to expect more than just a single service configuration. As a result, you can register multiple services in a single `consul services register` command. Note that the `/agent/service/register` API endpoint does not support the `services` parameter. + +In the following example, the service definition configures an instance of the `redis` service tagged as `primary` running on port `6000`. It also configures an instance of the service tagged as `secondary` running on port `7000`. + + + + + +```hcl +services { + id = "red0" + name = "redis" + tags = [ + "primary" + ] + address = "" + port = 6000 + checks = [ + { + args = ["/bin/check_redis", "-p", "6000"] + interval = "5s" + timeout = "20s" + } + ] +} +services { + id = "red1" + name = "redis" + tags = [ + "delayed", + "secondary" + ] + address = "" + port = 7000 + checks = [ + { + args = ["/bin/check_redis", "-p", "7000"] + interval = "30s" + timeout = "60s" + } + ] +} + +``` + + + + + +```json +{ + "services": [ + { + "id": "red0", + "name": "redis", + "tags": [ + "primary" + ], + "address": "", + "port": 6000, + "checks": [ + { + "args": ["/bin/check_redis", "-p", "6000"], + "interval": "5s", + "timeout": "20s" + } + ] + }, + { + "id": "red1", + "name": "redis", + "tags": [ + "delayed", + "secondary" + ], + "address": "", + "port": 7000, + "checks": [ + { + "args": ["/bin/check_redis", "-p", "7000"], + "interval": "30s", + "timeout": "60s" + } + ] + }, + ... + ] +} +``` + + + + +## Modify anti-entropy synchronization + +By default, the Consul agent uses anti-entropy mechanisms to maintain information about services and service health, and synchronize local states with the Consul catalog. You can enable the `enable_tag_override` option in the service configuration, which lets external agents change the tags for a service. This can be useful in situations where an external monitoring service needs to be the source of truth for tag information. Refer [Anti-entropy](/consul/docs/architecture/anti-entropy) for details. + +Add the `enable_tag_override` option to the `service` block and set the value to `true`: + + + + +```hcl +service { + ## ... + enable_tag_override = true + ## ... +} +``` + +```json +"service": { + ## ... + "enable_tag_override": true, + ## ... +} +``` + + + +This configuration only applies to the locally registered service. Nodes that register the same service apply the `enable_tag_override` and other service configurations independently. The tags for a service registered on one node update are not affected by operations performed on services with the same name registered on other nodes. + +Refer to [`enable_tag_override`](/consul/docs/services/configuration/services-configuration-reference#enable_tag_override) for additional configuration information. + +## Services in service mesh environments +Defining services for service mesh environments on virtual machines and in Kubernetes requires a different workflow. + +### Define service mesh proxies +You can register services to function as service mesh or sidecar proxies so that they can facilitate communication between other services across your network. Refer to [Service Mesh Proxy Overview](/consul/docs/connect/registration) for additional information. + +### Define services in Kubernetes +You can enable the services running in Kubernetes and Consul to sync automatically. Doing so ensures that Kubernetes services are available to Consul agents and services in Consul can be available as first-class Kubernetes services. Refer to [Service Sync for Consul on Kubernetes](/consul/docs/k8s/service-sync) for details. \ No newline at end of file diff --git a/website/content/docs/services/usage/register-services-checks.mdx b/website/content/docs/services/usage/register-services-checks.mdx new file mode 100644 index 000000000000..07a3f20ad9c0 --- /dev/null +++ b/website/content/docs/services/usage/register-services-checks.mdx @@ -0,0 +1,68 @@ +--- +layout: docs +page_title: Register services and health checks +description: -> + Learn how to register services and health checks with Consul agents. +--- + +# Register services and health checks + +This topic describes how to register services and health checks with Consul in networks running on virtual machines (VM). Refer to [Define Services](/consul/docs/services/usage/define-services) and [Define Health Checks](/consul/docs/services/usage/checks) for information about how to define services and health checks. + +## Overview +Register services and health checks in VM environments by providing the service definition to a Consul agent. You can use several different methods to register services and health checks. + +- Start a Consul agent and pass the service definition in the [agent's configuration directory](/consul/docs/agent#configuring-consul-agents). +- Reload the a running Consul agent and pass the service definition in the [agent's configuration directory](/consul/docs/agent#configuring-consul-agents). Use this method when implementing changes to an existing service or health check definition. +- Use the [`consul services register` command](/consul/commands/services/register) to register new service and health checks with a running Consul agent. +- Call the [`/agent/service/register`](/consul/api-docs/agent/service#register-service) HTTP API endpoint to to register new service and health checks with a running Consul agent. +- Call the [`/agent/check/register`](/consul/api-docs/agent/check#register-check) HTTP API endpoint to register a health check independent from the service. + +When a service is registered using the HTTP API endpoint or CLI command, the checks persist in the Consul data folder. If the agent restarts, Consul uses the service and check configurations in the configuration directory to start the services. + +Note that health checks associated with a service are application-level checks. + +## Start an agent +We recommend registering services on startup because the service persists if the agent fails. Specify the directory containing the service definition with the `-config-dir` option on startup. When the Consul agent starts, it processes all configurations in the directory and registers any services contained in the configurations. In the following example, the Consul agent starts and loads the configurations contained in the `configs` directory: + +```shell-session +$ consul agent -config-dir configs +``` + +Refer to [Starting the Consul Agent](/consul/docs/agent#starting-the-consul-agent) for additional information. + +## Reload an agent +Store your service definition file in the directory containing your Consul configuration files and either send a `SIGHUP` signal to the Consul agent service or run the `consul reload` command. Refer to [Consul Reload](/consul/commands/reload) for additional information. + +## Register using the CLI +Run the `consul services register` command and specify the service definition file to register the services and health checks defined in the file. In the following example, a service named `web` is registered: + +```shell-session +$ consul services register -name=web services.hcl +``` + +Refer to [Consul Agent Service Registration](/consul/commands/services/register) for additional information about using the command. + +## Register using the API + +Use the following methods to register services and health checks using the HTTP API. + +### Register services +Send a `PUT` request to the `/agent/service/register` API endpoint to dynamically register a service and its associated health checks. To register health checks independently, [call the checks API endpoint](#call-the-checks-http-api-endpoint). + +The following example request registers the service defined in the `service.json` file. + +```shell-session +$ curl --request PUT --data @service.json http://localhost:8500/v1/agent/service/register +``` + +Refer to [Service - Agent HTTP API](/consul/api-docs/agent/service) for additional information about the `services` endpoint. + +### Register health checks +Send a `PUT` request to the `/agent/check/register` API endpoint to dynamically register a health check to the local Consul agent. The following example request registers a health check defined in a `payload.json` file. + +```shell-session +$ curl --request PUT --data @payload.json http://localhost:8500/v1/agent/check/register +``` + +Refer to [Check - Agent HTTP API](/consul/api-docs/agent/check) for additional information about the `check` endpoint. diff --git a/website/content/docs/troubleshoot/common-errors.mdx b/website/content/docs/troubleshoot/common-errors.mdx index 985c0346b310..0d733022564d 100644 --- a/website/content/docs/troubleshoot/common-errors.mdx +++ b/website/content/docs/troubleshoot/common-errors.mdx @@ -199,10 +199,60 @@ as doing so gives the Consul client unnecessary access to all network traffic on We recommend raising an issue with the CNI you're using to add support for `hostPort` and switching back to `hostPort` eventually. -[troubleshooting]: https://learn.hashicorp.com/consul/day-2-operations/advanced-operations/troubleshooting -[node_name]: /docs/agent/config/config-files#node_name -[retry_join]: /docs/agent/config/cli-flags#retry-join -[license]: /commands/license +### consul-server-connection-manager: ACL auth method login failed: error="rpc error: code = PermissionDenied desc = Permission denied" + +If you see this error in the init container logs of service mesh pods, check that the pod has a service account name that matches its Service. +For example, this deployment: + +``` +apiVersion: v1 +kind: Service +metadata: + # This name will be the service name in Consul. + name: static-server +spec: + selector: + app: static-server + ports: + - protocol: TCP + port: 80 + targetPort: 8080 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: static-server +spec: + replicas: 1 + selector: + matchLabels: + app: static-server + template: + metadata: + name: static-server + labels: + app: static-server + annotations: + 'consul.hashicorp.com/connect-inject': 'true' + spec: + containers: + - name: static-server + image: hashicorp/http-echo:latest + args: + - -text="hello world" + - -listen=:8080 + ports: + - containerPort: 8080 + name: http + serviceAccountName: does-not-match +``` + +Will fail because the `serviceAccountName` is `does-not-match` instead of `static-server`. + +[troubleshooting]: /consul/tutorials/datacenter-operations/troubleshooting +[node_name]: /consul/docs/agent/config/config-files#node_name +[retry_join]: /consul/docs/agent/config/cli-flags#retry-join +[license]: /consul/commands/license [releases]: https://releases.hashicorp.com/consul/ [files]: https://easyengine.io/tutorials/linux/increase-open-files-limit [certificates]: https://learn.hashicorp.com/consul/advanced/day-1-operations/certificates diff --git a/website/content/docs/upgrading/index.mdx b/website/content/docs/upgrading/index.mdx index e9a2a892c990..c1641ff672e1 100644 --- a/website/content/docs/upgrading/index.mdx +++ b/website/content/docs/upgrading/index.mdx @@ -36,7 +36,8 @@ Consul is A, and version B is released. 2. On each Consul server agent, install version B of Consul. -3. One Consul server agent at a time, shut down version A via `consul leave` and restart with version B. Wait until +3. One Consul server agent at a time, use a service management system + (e.g., systemd, upstart, etc.) to restart the Consul service with version B. Wait until the server agent is healthy and has rejoined the cluster before moving on to the next server agent. diff --git a/website/content/docs/upgrading/instructions/general-process.mdx b/website/content/docs/upgrading/instructions/general-process.mdx index f3339b5d0e53..d51d21013a49 100644 --- a/website/content/docs/upgrading/instructions/general-process.mdx +++ b/website/content/docs/upgrading/instructions/general-process.mdx @@ -107,13 +107,7 @@ Take note of which agent is the leader. binary with the new one. **3.** The following steps must be done in order on the server agents, leaving the leader -agent for last. First force the server agent to leave the cluster with the following command: - -``` -consul leave -``` - -Then, use a service management system (e.g., systemd, upstart, etc.) to restart the Consul service. If +agent for last. First, use a service management system (e.g., systemd, upstart, etc.) to restart the Consul service. If you are not using a service management system, you must restart the agent manually. To validate that the agent has rejoined the cluster and is in sync with the leader, issue the @@ -173,7 +167,7 @@ all of your servers attempting to kick off leadership elections endlessly withou reaching a quorum and electing a leader. Most of these problems can be solved by following the steps outlined in our -[Outage Recovery](https://learn.hashicorp.com/tutorials/consul/recovery-outage) document. +[Disaster recovery for Consul clusters](/consul/tutorials/datacenter-operations/recovery-outage) document. If you are still having trouble after trying the recovery steps outlined there, then the following options for further assistance are available: diff --git a/website/content/docs/upgrading/instructions/index.mdx b/website/content/docs/upgrading/instructions/index.mdx index 4ddc86b07c51..c0d869ba3885 100644 --- a/website/content/docs/upgrading/instructions/index.mdx +++ b/website/content/docs/upgrading/instructions/index.mdx @@ -18,9 +18,10 @@ Our recommended upgrade path is to move through the following sequence of versio - 1.2.4 (final 1.2.x) - 1.6.10 (final 1.6.x) - 1.8.19 (final 1.8.x) -- Latest 1.10.x +- 1.10.12 (final 1.10.x) - Latest 1.12.x - Latest 1.13.x ([at least 1.13.1](/docs/upgrading/upgrade-specific#service-mesh-compatibility)) +- Latest 1.14.x ## Getting Started @@ -31,6 +32,7 @@ we recommend reviewing the changelog for versions between the one you are on and one you are upgrading to at each step to familiarize yourself with changes. Select your _currently installed_ release series: +- 1.13.x: work upwards from [1.14 upgrade notes](/docs/upgrading/upgrade-specific#consul-1-14-x) - 1.12.x: work upwards from [1.13 upgrade notes](/docs/upgrading/upgrade-specific#consul-1-13-x) - 1.11.x: work upwards from [1.12 upgrade notes](/docs/upgrading/upgrade-specific#consul-1-12-0) - 1.10.x: work upwards from [1.11 upgrade notes](/docs/upgrading/upgrade-specific#consul-1-11-0) diff --git a/website/content/docs/upgrading/instructions/upgrade-to-1-10-x.mdx b/website/content/docs/upgrading/instructions/upgrade-to-1-10-x.mdx index 7c5690ac3bf4..8fef8ab259dd 100644 --- a/website/content/docs/upgrading/instructions/upgrade-to-1-10-x.mdx +++ b/website/content/docs/upgrading/instructions/upgrade-to-1-10-x.mdx @@ -8,8 +8,6 @@ description: >- # Upgrading to Latest 1.10.x - - ## Introduction This guide explains how to best upgrade a single Consul Enterprise datacenter to latest v1.10.x diff --git a/website/content/docs/upgrading/instructions/upgrade-to-1-6-x.mdx b/website/content/docs/upgrading/instructions/upgrade-to-1-6-x.mdx index a86c1df5e972..19ff46d945e1 100644 --- a/website/content/docs/upgrading/instructions/upgrade-to-1-6-x.mdx +++ b/website/content/docs/upgrading/instructions/upgrade-to-1-6-x.mdx @@ -18,9 +18,9 @@ as part of this upgrade. The 1.6.x series is the last series that had support fo ACL tokens, so this migration _must_ happen before upgrading past the 1.6.x release series. Here is some documentation that may prove useful for reference during this upgrade process: -- [ACL System in Legacy Mode](/docs/security/acl/acl-legacy) - You can find - information about legacy configuration options and differences between modes here. -- [Configuration](/docs/agent/config) - You can find more details +- [Upgrading Legacy ACL tokens](/consul/tutorials/security-operations/access-control-token-migration) - You can find + information about upgrading legacy ACL tokens and differences between modes here. +- [Configuration](/consul/docs/agent/config) - You can find more details around legacy ACL and new ACL configuration options here. Legacy ACL config options will be listed as deprecates as of 1.4.0. diff --git a/website/content/docs/upgrading/upgrade-specific.mdx b/website/content/docs/upgrading/upgrade-specific.mdx index ed1b482c5879..7fce96adcd3d 100644 --- a/website/content/docs/upgrading/upgrade-specific.mdx +++ b/website/content/docs/upgrading/upgrade-specific.mdx @@ -17,24 +17,57 @@ upgrade flow. ## Consul 1.14.x ### Service Mesh Compatibility +Prior to Consul 1.14, cluster peering or Consul connect were disabled by default. +A breaking change was made in Consul 1.14 that: +- [Cluster Peering is enabled by default.](/docs/connect/cluster-peering) + Cluster peering and WAN federation can coexist, + so there is no need to disable cluster peering to upgrade existing WAN federated datacenters. + To disable cluster peering nonetheless, set [`peering.enabled`](/docs/agent/config/config-files#peering_enabled) to `false`. +- [Consul Connect is enabled by default.](/docs/connect) + To disable, set [`connect.enabled`](/docs/agent/config/config-files#connect_enabled) to `false`. + +The changes to Consul service mesh in version 1.14 are incompatible with Nomad 1.4.3 and +earlier. If you operate Consul service mesh using Nomad 1.4.3 or earlier, do not upgrade to +Consul 1.14 until [hashicorp/nomad#15266](https://github.com/hashicorp/nomad/issues/15266) and +[hashicorp/nomad#15360](https://github.com/hashicorp/nomad/issues/15360) have been fixed. + +For 1.14.0, there is a known issue with `consul connect envoy`. If the command is configured +to use TLS for contacting the HTTP API, it will also incorrectly enable TLS for gRPC. +Users should not upgrade to 1.14.0 if they are using plaintext gRPC connections in +conjunction with TLS-encrypted HTTP APIs. + + +#### Changes to gRPC TLS configuration + +**Make configuration changes** if using [`ports.grpc`](/docs/agent/config/config-files#grpc_port) in conjunction with any of the following settings that enables encryption: +1. [`tls.grpc`](/docs/agent/config/config-files#tls_grpc) +1. [`tls.defaults`](/docs/agent/config/config-files#tls_defaults) +1. [`auto_encrypt`](/docs/agent/config/config-files#auto_encrypt) +1. [`auto_config`](/docs/agent/config/config-files#auto_config) -##### Changes to gRPC TLS configuration +Prior to Consul 1.14, it was possible to encrypt communication between Consul and Envoy over `ports.grpc` using these settings. -**Make configuration changes** if using sidecar proxies or gateways that include any of the following configuration file values: -1. [`ports.https`](/docs/agent/config/config-files#https_port) - Encrypts gRPC in Consul 1.12 and prior -1. [`auto_encrypt`](/docs/agent/config/config-files#auto_encrypt) - Encrypts gRPC in Consul 1.13 and prior -1. [`auto_config`](/docs/agent/config/config-files#auto_config) - Encrypts gRPC in Consul 1.13 and prior +Consul 1.14 introduces [`ports.grpc_tls`](/docs/agent/config/config-files#grpc_tls_port), a new configuration +for encrypting communication over gRPC. The existing [`ports.grpc`](/docs/agent/config/config-files#grpc_port) configuration **no longer supports encryption**. As of version 1.14, +[`ports.grpc_tls`](/docs/agent/config/config-files#grpc_tls_port) is the only port that serves encrypted gRPC traffic. +The default value for the gRPC TLS port is 8503 for Consul servers. To disable the gRPC TLS port, use value -1. -Prior to Consul 1.14, it was possible to encrypt communication between Consul and Envoy over `ports.grpc` using these settings. +If you already use gRPC encryption, change the following fields to ensure compatibility: -Consul 1.14 introduces [`ports.grpc_tls`](/docs/agent/config/config-files#grpc_tls_port), a new configuration -for encrypting communication over gRPC. The existing [`ports.grpc`](/docs/agent/config/config- -files#grpc_port) configuration **will stop supporting encryption in a future release**. As of version 1.14, -`ports.grpc_tls` is the recommended configuration to encrypt gRPC traffic. ++ Change `ports.grpc` to `ports.grpc_tls`. Refer to the [`grpc_tls_port` documentation](/docs/agent/config/config-files#grpc_tls_port) for details. ++ Change `addresses.grpc` to `addresses.grpc_tls`. Refer to the [`grpc_tls` documentation](/docs/agent/config/config-files#grpc_tls) for details. ++ Update `consul connect envoy` command invocations to specify gRPC CA certificates with one of the new configuration options: +[`-grpc-ca-file`](/commands/connect/envoy#grpc-ca-file) or +[`-grpc-ca-path`](/commands/connect/envoy#grpc-ca-path) +(or their corresponding environment variables). -For most environments, the Envoy communication to Consul is loop-back only and does not benefit from encryption. +#### Changes to peering -If you already use gRPC encryption, change the existing `ports.grpc` to `ports.grpc_tls` in your configuration to ensure compatibility with future releases. +[Cluster peering](/docs/connect/cluster-peering) was released in Consul 1.13 as an experimental feature. +In Consul 1.14, cluster peering has been improved and is now considered stable. All experimental peering +connections created by 1.13 should be +[deleted](/docs/connect/cluster-peering/create-manage-peering#delete-peering-connections) +prior to upgrading, as they will no longer be compatible with 1.14. ## Consul 1.13.x @@ -51,7 +84,7 @@ review the following guidances relevant to your deployment: Upgrade to **Consul version 1.13.1 or later**. -Consul 1.13.0 contains a bug that prevents Consul server agents from restoring +Consul 1.13.0 contains a bug that prevents Consul server agents from restoring saved state on startup if the state 1. was generated before Consul 1.13 (such as during an upgrade), and @@ -61,25 +94,22 @@ This bug is fixed in Consul versions 1.13.1 and newer. #### Service mesh deployments using auto-encrypt or auto-config -**Do not upgrade to Consul 1.13 yet** if using +Upgrade to **Consul version 1.13.2 or later** if using [auto-encrypt](/docs/agent/config/config-files#auto_encrypt) or [auto-config](/docs/agent/config/config-files#auto_config). -In Consul 1.13, auto-encrypt and auto-config both cause Consul +In Consul 1.13.0 - 1.13.1, auto-encrypt and auto-config both cause Consul to require TLS for gRPC communication with Envoy proxies. In environments where Envoy proxies are not already configured -to use TLS for gRPC, upgrading Consul 1.13 will cause +to use TLS for gRPC, upgrading to Consul 1.13.0 - 1.13.1 will cause Envoy proxies to disconnect from the control plane (Consul agents). -The underlying cause is the same as discussed in -[deployments without the HTTPS port enabled on Consul agents](#service-mesh-deployments-without-the-https-port-enabled-on-consul-agents). -However, when using auto-encrypt or auto-config, -the problem **cannot** currently be avoided by -[modifying the agent's TLS configuration](#modify-the-consul-agent-s-tls-configuration) -because auto-encrypt and auto-config automatically set -interface-generic TLS configuration in a manner similar to -[`tls.defaults`](/docs/agent/config/config-files#tls_defaults). -We are working to address this problem in an upcoming 1.13 patch release. +If upgrading to version 1.13.2 or later, you must enable +[tls.grpc.use_auto_cert](/docs/agent/config/config-files#use_auto_cert) +if you currently rely on Consul agents presenting the auto-encrypt or +auto-config certs as the TLS server certs on the gRPC port. +The new `use_auto_cert` flag enables TLS for gRPC based on the presence +of auto-encrypt certs. #### Service mesh deployments without the HTTPS port enabled on Consul agents ((#grpc-tls)) @@ -174,8 +204,8 @@ such as with flags or environment variables like #### Modify Vault policy for Vault CA provider If using the Vault CA provider, -you must modify the Vault policy used by Consul to interact with Vault -so that certificates required for service mesh operation can still be generated. +modify the Vault policy used by Consul to interact with Vault +to ensure that certificates required for service mesh operation can still be generated. The policy must include the `update` capability on the intermediate PKI's tune mount configuration endpoint at path `/sys/mounts//tune`. Refer to the [Vault CA provider documentation](/docs/connect/ca/vault#vault-acl-policies) @@ -185,23 +215,25 @@ You are using the Vault CA provider if either of the following configurations ex - The Consul server agent configuration option [`connect.ca_provider`](/docs/agent/config/config-files#connect_ca_provider) is set to `vault`, or - The Consul on Kubernetes Helm Chart [`global.secretsBackend.vault.connectCA`](/docs/k8s/helm#v-global-secretsbackend-vault-connectca) value is configured. -Though this guidance is listed in the 1.13.x section, it applies to all of the following release series: -- Consul 1.13.x: applies to 1.13.2+ -- Consul 1.12.x: applies to 1.12.5+ -- Consul 1.11.x: applies to 1.11.9+ - -Those affected Consul versions contain a +Though this guidance is listed in the 1.13.x section, it applies to several release series. +Affected Consul versions contain a [bugfix that allows the intermediate CA's TTL configuration to be modified](https://github.com/hashicorp/consul/pull/14516). The bugfix requires the `update` capability to tune that configuration. -Without the `update` capability, those affected Consul versions +Without the `update` capability, the Consul versions listed in the _breaking change_ column cannot provide services with the certificates they need to participate in the mesh. -In an upcoming patch for each of those release series, -we will restore the intermediate CA's ability to provide certificates even without the `update` capability on the tune configuration endpoint, +The Consul versions in the _recommended versions_ column restore the intermediate CA's ability +to provide certificates even without the `update` capability on the tune configuration endpoint, though the `update` capability will still be needed to modify the CA's TTL configuration. -We recommend modifying the Vault policy before upgrading to Consul 1.11 or later -to ensure your organization does not accidentally miss this guidance when performing subsequent upgrades, -such as to the latest patch within a release series. +| Release Series | Versions with breaking change | Recommended versions | +| -------------- | ----------------------------- | -------------------- | +| Consul 1.13.x | 1.13.2 | 1.13.3 or later | +| Consul 1.12.x | 1.12.5 | 1.12.6 or later | +| Consul 1.11.x | 1.11.9 - 1.11.10 | 1.11.11 or later | + +As a precaution, we recommend both modifying the Vault policy +and upgrading to a recommended version as a double protection +to ensure the operation of your service mesh and to enable CA TTL modification. ### 1.9 Telemetry Compatibility @@ -215,6 +247,16 @@ If you were using this flag, you must remove it before upgrading. Follow the same guidance as provided in the [1.13 upgrade section for modifying the Vault policy if using the Vault CA provider](#modify-vault-policy-for-vault-ca-provider). +A breaking change was made in Consul 1.13.2 that impacts service mesh operation +if the Vault policy is not modified as described. +As a precaution, we recommend both modifying the Vault policy and upgrading +to Consul 1.13.3 or later to avoid the breaking nature of that change. + +### Nomad Incompatibility + +Nomad users should not upgrade to Consul 1.13.8 as an API change in Consul +prevents Nomad from correctly detecting the Consul agent version, resulting in +allocations not being placed in those clients. ## Consul 1.12.x ((#consul-1-12-0)) @@ -222,6 +264,10 @@ Follow the same guidance as provided in the Follow the same guidance as provided in the [1.13 upgrade section for modifying the Vault policy if using the Vault CA provider](#modify-vault-policy-for-vault-ca-provider). +A breaking change was made in Consul 1.12.5 that impacts service mesh operation +if the Vault policy is not modified as described. +As a precaution, we recommend both modifying the Vault policy and upgrading +to Consul 1.12.6 or later to avoid the breaking nature of that change. ### 1.9 Telemetry Compatibility @@ -264,9 +310,10 @@ be replaced with the new [`tls` stanza](/docs/agent/config/config-files#tls-conf ### 1.10 Compatibility Consul Enterprise versions 1.10.0 through 1.10.4 contain a latent bug that causes those client or server agents to deregister their own services or health -checks when some of the servers have been upgraded to 1.11. Before upgrading Consul Enterprise servers to 1.11, all Consul agents should first -be upgraded to 1.10.7 or higher to ensure forward compatibility and prevent -flapping of catalog registrations. +checks when some of the servers have been upgraded to 1.11 or later. +Before upgrading Consul Enterprise servers to 1.11 or later, +you should first upgrade all Consul client and server agents to 1.10.7 or higher +to ensure forward compatibility and prevent flapping of catalog registrations. ### Deprecated Agent Config Options @@ -338,6 +385,10 @@ ensures your sidecars are supported by Consul 1.11. Follow the same guidance as provided in the [1.13 upgrade section for modifying the Vault policy if using the Vault CA provider](#modify-vault-policy-for-vault-ca-provider). +A breaking change was made in Consul 1.11.9 that impacts service mesh operation +if the Vault policy is not modified as described. +As a precaution, we recommend both modifying the Vault policy and upgrading +to Consul 1.11.11 or later to avoid the breaking nature of that change. ## Consul 1.10.0 @@ -836,11 +887,9 @@ config files loaded by Consul, even when using the [`-config-file`](/docs/agent/config/cli-flags#_config_file) argument to specify a file directly. -#### Service Definition Parameter Case changed +#### Use Snake Case for Service Definition Parameters -All config file formats now require snake_case fields, so all CamelCased parameter -names should be changed before upgrading. -See [Service Definition Parameter Case](/docs/discovery/services#service-definition-parameter-case) documentation for details. +Snake case, which is a convention that uses underscores between words in a configuration key, is required for all configuration file formats. Change any camel cased parameter to snake case equivalents before upgrading. #### Deprecated Options Have Been Removed @@ -1232,7 +1281,7 @@ the file. Consul 0.7 also uses a new, automatically-created raft/peers.info file to avoid ingesting the `peers.json` file on the first start after upgrading (the `peers.json` file is simply deleted on the first start after upgrading). -Please be sure to review the [Outage Recovery tutorial](https://learn.hashicorp.com/tutorials/consul/recovery-outage) +Please be sure to review the [Disaster recovery for Consul clusters tutorial](/consul/tutorials/datacenter-operations/recovery-outage) before upgrading for more details. ## Consul 0.6.4 diff --git a/website/content/partials/create-token-auth-methods.mdx b/website/content/partials/create-token-auth-methods.mdx new file mode 100644 index 000000000000..912870728503 --- /dev/null +++ b/website/content/partials/create-token-auth-methods.mdx @@ -0,0 +1,3 @@ +### Auth methods + +Auth methods are components that perform authentication against a trusted external party to authorize the creation of ACL tokens for use within the local datacenter. Refer to the [auth methods documentation](/consul/docs/security/acl/auth-methods) for details about how to leverage auth methods in your network. diff --git a/website/content/partials/create-token-requirements.mdx b/website/content/partials/create-token-requirements.mdx new file mode 100644 index 000000000000..bf4742719e8d --- /dev/null +++ b/website/content/partials/create-token-requirements.mdx @@ -0,0 +1,22 @@ +### Authentication + +You must provide an ACL token linked to a policy with `acl:write` permissions to create and modify ACL tokens and policies using the CLI or API. + +You can provide the token manually using the `-token` option on the command line, but we recommend setting the `CONSUL_HTTP_TOKEN` environment variable to simplify your workflow: + +```shell-session +$ export CONSUL_HTTP_TOKEN= +``` + +The Consul CLI automatically reads the `CONSUL_HTTP_TOKEN` environment variable so that you do not have to pass the token to every Consul CLI command. + +To authenticate calls to the Consul HTTP API, you must provide the token in the `X-Consul-Token` header for each call: + +```shell-session +$ curl --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" ... +``` + +To learn about alternative ways to authenticate, refer to the following documentation: + +* [CLI Authentication](/consul/commands#authentication) +* [API Authentication](/consul/api-docs/api-structure#authentication) diff --git a/website/data/docs-nav-data.json b/website/data/docs-nav-data.json index 1a06f9cd9615..f8a02678bd7a 100644 --- a/website/data/docs-nav-data.json +++ b/website/data/docs-nav-data.json @@ -125,6 +125,10 @@ { "title": "Network Coordinates", "path": "architecture/coordinates" + }, + { + "title": "Consul at Scale", + "path": "architecture/scale" } ] }, @@ -141,6 +145,10 @@ { "title": "Consul", "routes": [ + { + "title": "v1.14.x", + "path": "release-notes/consul/v1_14_x" + }, { "title": "v1.13.x", "path": "release-notes/consul/v1_13_x" @@ -166,6 +174,10 @@ { "title": "Consul K8s", "routes": [ + { + "title": "v1.0.x", + "path": "release-notes/consul-k8s/v1_0_x" + }, { "title": "v0.49.x", "path": "release-notes/consul-k8s/v0_49_x" @@ -287,19 +299,70 @@ "divider": true }, { - "title": "Service Discovery", + "title": "Services", "routes": [ { - "title": "Register Services - Service Definitions", - "path": "discovery/services" + "title": "Overview", + "path": "services/services" + }, + { + "title": "Usage", + "routes": [ + { + "title": "Define services", + "path": "services/usage/define-services" + }, + { + "title": "Define health checks", + "path": "services/usage/checks" + }, + { + "title": "Register services and health checks", + "path": "services/usage/register-services-checks" + } + ] }, { - "title": "Find Services - DNS Interface", - "path": "discovery/dns" + "title": "Discover services with DNS", + "routes": [ + { + "title": "Overview", + "path": "services/discovery/dns-overview" + }, + { + "title": "Configure DNS behavior", + "path": "services/discovery/dns-configuration" + }, + { + "title": "Perform static DNS lookups", + "path": "services/discovery/dns-static-lookups" + }, + { + "title": "Enable dynamic DNS lookups", + "path": "services/discovery/dns-dynamic-lookups" + } + ] }, { - "title": "Monitor Services - Check Definitions", - "path": "discovery/checks" + "title": "Configuration", + "routes": [ + { + "title": "Overview", + "path": "services/configuration/services-configuration-overview" + }, + { + "title": "Services", + "path": "services/configuration/services-configuration-reference" + }, + { + "title": "Health checks", + "path": "services/configuration/checks-configuration-reference" + }, + { + "title": "Service defaults", + "href": "connect/config-entries/service-defaults" + } + ] } ] }, @@ -385,11 +448,6 @@ { "title": "Proxy Integration", "path": "connect/proxies/integrate" - }, - { - "title": "Managed (Deprecated)", - "path": "connect/proxies/managed-deprecated", - "hidden": true } ] }, @@ -467,20 +525,24 @@ "title": "Mesh Gateways", "routes": [ { - "title": "WAN Federation", + "title": "Overview", + "path": "connect/gateways/mesh-gateway" + }, + { + "title": "Enabling WAN Federation Control Plane Traffic", "path": "connect/gateways/mesh-gateway/wan-federation-via-mesh-gateways" }, { - "title": "Enabling Service-to-service Traffic Across Datacenters", - "path": "connect/gateways/mesh-gateway/service-to-service-traffic-datacenters" + "title": "Enabling Service-to-service Traffic Across WAN Federated Datacenters", + "path": "connect/gateways/mesh-gateway/service-to-service-traffic-wan-datacenters" }, { "title": "Enabling Service-to-service Traffic Across Admin Partitions", "path": "connect/gateways/mesh-gateway/service-to-service-traffic-partitions" }, { - "title": "Enabling Service-to-service Traffic Across Peered Clusters", - "path": "connect/gateways/mesh-gateway/service-to-service-traffic-peers" + "title": "Enabling Peering Control Plane Traffic", + "path": "connect/gateways/mesh-gateway/peering-via-mesh-gateways" } ] }, @@ -498,16 +560,29 @@ "title": "Cluster Peering", "routes": [ { - "title": "What is Cluster Peering?", + "title": "Overview", "path": "connect/cluster-peering" }, { - "title": "Create and Manage Peering Connections", - "path": "connect/cluster-peering/create-manage-peering" + "title": "Technical Specifications", + "path": "connect/cluster-peering/tech-specs" }, { - "title": "Cluster Peering on Kubernetes", - "path": "connect/cluster-peering/k8s" + "title": "Usage", + "routes": [ + { + "title": "Establish Cluster Peering Connections", + "path": "connect/cluster-peering/usage/establish-cluster-peering" + }, + { + "title": "Manage Cluster Peering Connections", + "path": "connect/cluster-peering/usage/manage-connections" + }, + { + "title": "Manage L7 Traffic With Cluster Peering", + "path": "connect/cluster-peering/usage/peering-traffic-management" + } + ] } ] }, @@ -572,6 +647,10 @@ { "title": "CLI Reference", "path": "connect/dataplane/consul-dataplane" + }, + { + "title": "Telemetry", + "path": "connect/dataplane/telemetry" } ] } @@ -610,7 +689,61 @@ }, { "title": "Tokens", - "path": "security/acl/acl-tokens" + "routes": [ + { + "title": "Overview", + "path": "security/acl/tokens" + }, + { + "title": "Create ACL Tokens", + "routes": [ + { + "title": "Create a service token", + "path": "security/acl/tokens/create/create-a-service-token" + }, + { + "title": "Create an agent token", + "path": "security/acl/tokens/create/create-an-agent-token" + }, + { + "title": "Create a UI token", + "path": "security/acl/tokens/create/create-a-ui-token" + }, + { + "title": "Create a mesh gateway token", + "path": "security/acl/tokens/create/create-a-mesh-gateway-token" + }, + { + "title": "Create an ingress gateway token", + "path": "security/acl/tokens/create/create-an-ingress-gateway-token" + }, + { + "title": "Create a terminating gateway token", + "path": "security/acl/tokens/create/create-a-terminating-gateway-token" + }, + { + "title": "Create a DNS token", + "path": "security/acl/tokens/create/create-a-dns-token" + }, + { + "title": "Create a replication token", + "path": "security/acl/tokens/create/create-a-replication-token" + }, + { + "title": "Create a snapshot agent token", + "path": "security/acl/tokens/create/create-a-snapshot-agent-token" + }, + { + "title": "Create a token for Vault's Consul storage backend", + "path": "security/acl/tokens/create/create-a-token-for-vault-consul-storage" + }, + { + "title": "Create a Consul ESM token", + "path": "security/acl/tokens/create/create-a-consul-esm-token" + } + ] + } + ] }, { "title": "Policies", @@ -935,6 +1068,36 @@ "title": "Overview", "path": "k8s/connect" }, + { + "title": "Admin Partitions", + "href": "/docs/enterprise/admin-partitions" + }, + { + "title": "Cluster Peering", + "routes": [ + { + "title": "Technical Specifications", + "path": "k8s/connect/cluster-peering/tech-specs" + }, + { + "title": "Usage", + "routes": [ + { + "title": "Establish Cluster Peering Connections", + "path": "k8s/connect/cluster-peering/usage/establish-peering" + }, + { + "title": "Manage Cluster Peering Connections", + "path": "k8s/connect/cluster-peering/usage/manage-peering" + }, + { + "title": "Manage L7 Traffic With Cluster Peering", + "path": "k8s/connect/cluster-peering/usage/l7-traffic" + } + ] + } + ] + }, { "title": "Transparent Proxy", "href": "/docs/connect/transparent-proxy" @@ -1145,7 +1308,7 @@ }, { "title": "Register Lambda Functions", - "routes":[ + "routes": [ { "title": "Requirements", "path": "lambda/registration" @@ -1171,7 +1334,7 @@ "text": "BETA", "type": "outlined", "color": "neutral" - } + } } ] }, @@ -1223,7 +1386,16 @@ }, { "title": "Network Segments", - "path": "enterprise/network-segments" + "routes": [ + { + "title": "Network Segments Overview", + "path": "enterprise/network-segments/network-segments-overview" + }, + { + "title": "Create a Network Segment", + "path": "enterprise/network-segments/create-network-segment" + } + ] }, { "title": "Namespaces", @@ -1244,6 +1416,10 @@ "title": "Overview", "path": "enterprise/license/overview" }, + { + "title": "Automated License Utilization Reporting", + "path": "enterprise/license/utilization-reporting" + }, { "title": "FAQ", "path": "enterprise/license/faq" @@ -1276,7 +1452,24 @@ }, { "title": "Usage", - "path": "api-gateway/usage" + "routes": [ + { + "title": "Basic Usage", + "path": "api-gateway/usage/usage" + }, + { + "title": "Reroute HTTP Requests", + "path": "api-gateway/usage/reroute-http-requests" + }, + { + "title": "Route Traffic to Peered Services", + "path": "api-gateway/usage/route-to-peered-services" + }, + { + "title": "Error Messages", + "path": "api-gateway/usage/errors" + } + ] }, { "title": "Configuration", diff --git a/website/public/img/cluster-peering-diagram.png b/website/public/img/cluster-peering-diagram.png new file mode 100644 index 000000000000..d00aa3eb0f3b Binary files /dev/null and b/website/public/img/cluster-peering-diagram.png differ diff --git a/website/public/img/consul-connect/mesh-gateway/cluster-peering-connectivity-with-mesh-gateways.png b/website/public/img/consul-connect/mesh-gateway/cluster-peering-connectivity-with-mesh-gateways.png new file mode 100755 index 000000000000..6a4649bdc000 Binary files /dev/null and b/website/public/img/consul-connect/mesh-gateway/cluster-peering-connectivity-with-mesh-gateways.png differ diff --git a/website/public/img/consul-connect/mesh-gateway/cluster-peering-connectivity-with-mesh-gateways.svg b/website/public/img/consul-connect/mesh-gateway/cluster-peering-connectivity-with-mesh-gateways.svg new file mode 100755 index 000000000000..a8078443a328 --- /dev/null +++ b/website/public/img/consul-connect/mesh-gateway/cluster-peering-connectivity-with-mesh-gateways.svg @@ -0,0 +1,1872 @@ + + + + + + + + + + + + + + + + + + + + + + + + DC1 + + + + + | ON PREMISES + + + + DC2 + + + + + | CLOUD US-EAST-1 + + + + + + + + + + + + + + + + + + + + 8300/tcp + + + + + + + + + + + + + + 8300/tcp + Remote listener-wan-address=ip:port + Local listener-address=ip:port + + + + + + + + + + + + + + + + + + + + + + 8503/tcp + + + + LEADER + + + + + + + + + + + + + + + 8503/tcp + + LEADER + + + + + + + + + + + + + + + 8503/tcp + + + + + + + + + + + + + + + 8503/tcp + + + + + + + + + + + + + + + 8503/tcp + + + + + + + + + + + + + + + + + 8443/tcp + + + + + + + + + + + + + + + + + + 8443/tcp + + + + + With Mesh Gateways + CROSS-DC CONTROL PLANE COMMUNICATION (CLUSTER PEERING) + + consul connect envoy \ -gateway=mesh -register \ -service "dc1-mesh-gw" \ -address "ip1:443" \ -wan-address "ip2:8443" \ -expose-servers \ -token=<used by gateway> + $ + 8503/tcp + gRPC API with TLS + ####/tcp + GW Local Listener + see "-address" config optionwhen launching gateway + EXAMPLE GATEWAY CONFIG + ####/tcp + GW Remote Listener + see "-wan-address" config optionwhen launching gateway + not shown: the Consul client agent deployedwith each gateway to manage its configuration + + + + + + + + + + + + + + + Mesh Gateway + + paths through gateways can differ forDC1 DC2 versus DC2 DC1 because agateway's local listener (for internal traffic) typicallydiffers from its remote listener (for external traffic) + + + + + Control Plane + + + + + + LEADER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Consul Server Agent + System Components + Communication Paths + Ports + Requires config entry of type "mesh" with Peering.PeerThroughMeshGateways=true + Not shown: Consul client agents and their LAN Serf Gossip traffic on ports 8301/{udp,tcp} are not shown because they are not involved in cross-DC communication. + + + + + + + + + + + + + + + + 8503/tcp + + + diff --git a/website/public/img/consul-connect/mesh-gateway/cluster-peering-connectivity-without-mesh-gateways.png b/website/public/img/consul-connect/mesh-gateway/cluster-peering-connectivity-without-mesh-gateways.png new file mode 100755 index 000000000000..37223efb47b8 Binary files /dev/null and b/website/public/img/consul-connect/mesh-gateway/cluster-peering-connectivity-without-mesh-gateways.png differ diff --git a/website/public/img/consul-connect/mesh-gateway/cluster-peering-connectivity-without-mesh-gateways.svg b/website/public/img/consul-connect/mesh-gateway/cluster-peering-connectivity-without-mesh-gateways.svg new file mode 100755 index 000000000000..c8f6bb45c5b8 --- /dev/null +++ b/website/public/img/consul-connect/mesh-gateway/cluster-peering-connectivity-without-mesh-gateways.svg @@ -0,0 +1,1185 @@ + + + + + + + + + + + DC1 + + + + + | ON PREMISES + + + + DC2 + + + + + | CLOUD US-EAST-1 + + + + Without Mesh Gateways + CROSS-DC CONTROL PLANE COMMUNICATION (CLUSTER PEERING) + 8503/tcp + gRPC API with TLS + all servers are connected in DCswith a cluster peering relationship + Control Plane + + + + + + LEADER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Consul Server Agent + System Components + Communication Paths + Ports + + Not shown: Consul client agents and their LAN Serf Gossip traffic on ports 8301/{udp,tcp} are not shown because they are not involved in cross-DC communication. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 8503/tcp + + + + + + + + + + + + + + + + + 8503/tcp + + LEADER + + + + + + + + + + + + + + + + + 8503/tcp + + + + + + + + + + + + + + + + + 8503/tcp + + + + + + + + + + + + + + + + + 8503/tcp + + + + LEADER + + + + + + + + + + + + + + + + + 8503/tcp + + + diff --git a/website/public/img/k8s-dataplanes-architecture.png b/website/public/img/k8s-dataplanes-architecture.png new file mode 100644 index 000000000000..3bf092a9598b Binary files /dev/null and b/website/public/img/k8s-dataplanes-architecture.png differ diff --git a/website/redirects.js b/website/redirects.js index 8e31b56f3401..e182a29c78d1 100644 --- a/website/redirects.js +++ b/website/redirects.js @@ -4,4 +4,23 @@ // modify or delete existing redirects without first verifying internally. // Next.js redirect documentation: https://nextjs.org/docs/api-reference/next.config.js/redirects -module.exports = [] +module.exports = [ + { + source: '/consul/docs/connect/cluster-peering/create-manage-peering', + destination: + '/consul/docs/connect/cluster-peering/usage/establish-cluster-peering', + permanent: true, + }, + { + source: '/consul/docs/connect/cluster-peering/k8s', + destination: '/consul/docs/k8s/connect/cluster-peering/k8s-tech-specs', + permanent: true, + }, + { + source: + '/consul/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters', + destination: + '/consul/docs/k8s/deployment-configurations/multi-cluster', + permanent: true, + } +]