open-nomad/command/agent/consul/connect_proxies.go

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
}