github.com/hernad/nomad@v1.6.112/command/agent/consul/connect_proxies.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package consul
     5  
     6  import (
     7  	"errors"
     8  )
     9  
    10  // ConnectProxies implements SupportedProxiesAPI by using the Consul Agent API.
    11  type ConnectProxies struct {
    12  	agentAPI AgentAPI
    13  }
    14  
    15  func NewConnectProxiesClient(agentAPI AgentAPI) *ConnectProxies {
    16  	return &ConnectProxies{
    17  		agentAPI: agentAPI,
    18  	}
    19  }
    20  
    21  // Proxies returns a map of the supported proxies. The proxies are sorted from
    22  // Consul with the most preferred version as the 0th element.
    23  //
    24  // If Consul is of a version that does not support the API, a nil map is returned
    25  // with no error.
    26  //
    27  // If Consul cannot be reached an error is returned.
    28  func (c *ConnectProxies) Proxies() (map[string][]string, error) {
    29  	// Based on the Consul query:
    30  	// $ curl -s localhost:8500/v1/agent/self | jq .xDS
    31  	// {
    32  	//  "SupportedProxies": {
    33  	//    "envoy": [
    34  	//      "1.15.0",
    35  	//      "1.14.4",
    36  	//      "1.13.4",
    37  	//      "1.12.6"
    38  	//    ]
    39  	//  }
    40  	// }
    41  
    42  	self, err := c.agentAPI.Self()
    43  	if err != nil {
    44  		// this should not fail as long as we can reach consul
    45  		return nil, err
    46  	}
    47  
    48  	// If consul does not return a map of the supported consul proxies, it
    49  	// must be a version from before when the API was added in versions
    50  	// 1.9.0, 1.8.3, 1.7.7. Earlier versions in the same point release as well
    51  	// as all of 1.6.X support Connect, but not the supported proxies API.
    52  	// For these cases, we can simply fallback to the old version of Envoy
    53  	// that Nomad defaulted to back then - but not in this logic. Instead,
    54  	// return nil so we can choose what to do at the caller.
    55  
    56  	xds, xdsExists := self["xDS"]
    57  	if !xdsExists {
    58  		return nil, nil
    59  	}
    60  
    61  	proxies, proxiesExists := xds["SupportedProxies"]
    62  	if !proxiesExists {
    63  		return nil, nil
    64  	}
    65  
    66  	// convert interface{} to map[string]interface{}
    67  
    68  	intermediate, ok := proxies.(map[string]interface{})
    69  	if !ok {
    70  		return nil, errors.New("unexpected SupportedProxies response format from Consul")
    71  	}
    72  
    73  	// convert map[string]interface{} to map[string][]string
    74  
    75  	result := make(map[string][]string, len(intermediate))
    76  	for k, v := range intermediate {
    77  
    78  		// convert interface{} to []interface{}
    79  
    80  		if si, ok := v.([]interface{}); ok {
    81  			ss := make([]string, 0, len(si))
    82  			for _, z := range si {
    83  
    84  				// convert interface{} to string
    85  
    86  				if s, ok := z.(string); ok {
    87  					ss = append(ss, s)
    88  				}
    89  			}
    90  			result[k] = ss
    91  		}
    92  	}
    93  
    94  	return result, nil
    95  }