open-nomad/command/agent/consul/connect_proxies.go
Seth Hoenig ed13e5723f consul/connect: dynamically select envoy sidecar at runtime
As newer versions of Consul are released, the minimum version of Envoy
it supports as a sidecar proxy also gets bumped. Starting with the upcoming
Consul v1.9.X series, Envoy v1.11.X will no longer be supported. Current
versions of Nomad hardcode a version of Envoy v1.11.2 to be used as the
default implementation of Connect sidecar proxy.

This PR introduces a change such that each Nomad Client will query its
local Consul for a list of Envoy proxies that it supports (https://github.com/hashicorp/consul/pull/8545)
and then launch the Connect sidecar proxy task using the latest supported version
of Envoy. If the `SupportedProxies` API component is not available from
Consul, Nomad will fallback to the old version of Envoy supported by old
versions of Consul.

Setting the meta configuration option `meta.connect.sidecar_image` or
setting the `connect.sidecar_task` stanza will take precedence as is
the current behavior for sidecar proxies.

Setting the meta configuration option `meta.connect.gateway_image`
will take precedence as is the current behavior for connect gateways.

`meta.connect.sidecar_image` and `meta.connect.gateway_image` may make
use of the special `${NOMAD_envoy_version}` variable interpolation, which
resolves to the newest version of Envoy supported by the Consul agent.

Addresses #8585 #7665
2020-10-13 09:14:12 -05:00

93 lines
2.3 KiB
Go

package consul
import (
"errors"
)
// ConnectProxies implements SupportedProxiesAPI by using the Consul Agent API.
type ConnectProxies struct {
agentAPI AgentAPI
}
func NewConnectProxiesClient(agentAPI AgentAPI) *ConnectProxies {
return &ConnectProxies{
agentAPI: agentAPI,
}
}
// Proxies returns a map of the supported proxies. The proxies are sorted from
// Consul with the most preferred version as the 0th element.
//
// If Consul is of a version that does not support the API, a nil map is returned
// with no error.
//
// If Consul cannot be reached an error is returned.
func (c *ConnectProxies) Proxies() (map[string][]string, error) {
// Based on the Consul query:
// $ curl -s localhost:8500/v1/agent/self | jq .xDS
// {
// "SupportedProxies": {
// "envoy": [
// "1.15.0",
// "1.14.4",
// "1.13.4",
// "1.12.6"
// ]
// }
// }
self, err := c.agentAPI.Self()
if err != nil {
// this should not fail as long as we can reach consul
return nil, err
}
// If consul does not return a map of the supported consul proxies, it
// must be a version from before when the API was added in versions
// 1.9.0, 1.8.3, 1.7.7. Earlier versions in the same point release as well
// as all of 1.6.X support Connect, but not the supported proxies API.
// For these cases, we can simply fallback to the old version of Envoy
// that Nomad defaulted to back then - but not in this logic. Instead,
// return nil so we can choose what to do at the caller.
xds, xdsExists := self["xDS"]
if !xdsExists {
return nil, nil
}
proxies, proxiesExists := xds["SupportedProxies"]
if !proxiesExists {
return nil, nil
}
// convert interface{} to map[string]interface{}
intermediate, ok := proxies.(map[string]interface{})
if !ok {
return nil, errors.New("unexpected SupportedProxies response format from Consul")
}
// convert map[string]interface{} to map[string][]string
result := make(map[string][]string, len(intermediate))
for k, v := range intermediate {
// convert interface{} to []interface{}
if si, ok := v.([]interface{}); ok {
ss := make([]string, 0, len(si))
for _, z := range si {
// convert interface{} to string
if s, ok := z.(string); ok {
ss = append(ss, s)
}
}
result[k] = ss
}
}
return result, nil
}