diff --git a/.changelog/8545.txt b/.changelog/8545.txt new file mode 100644 index 000000000..a7d84ab1d --- /dev/null +++ b/.changelog/8545.txt @@ -0,0 +1,3 @@ +```release-note:feature +agent: expose the list of supported envoy versions on /v1/agent/self +``` diff --git a/agent/agent_endpoint.go b/agent/agent_endpoint.go index ffde07aa7..32f26b02e 100644 --- a/agent/agent_endpoint.go +++ b/agent/agent_endpoint.go @@ -17,6 +17,7 @@ import ( "github.com/hashicorp/consul/agent/debug" "github.com/hashicorp/consul/agent/structs" token_store "github.com/hashicorp/consul/agent/token" + "github.com/hashicorp/consul/agent/xds/proxysupport" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/ipaddr" "github.com/hashicorp/consul/lib" @@ -38,6 +39,11 @@ type Self struct { Member serf.Member Stats map[string]map[string]string Meta map[string]string + XDS *xdsSelf `json:"xDS,omitempty"` +} + +type xdsSelf struct { + SupportedProxies map[string][]string } func (s *HTTPServer) AgentSelf(resp http.ResponseWriter, req *http.Request) (interface{}, error) { @@ -60,6 +66,15 @@ func (s *HTTPServer) AgentSelf(resp http.ResponseWriter, req *http.Request) (int } } + var xds *xdsSelf + if s.agent.grpcServer != nil { + xds = &xdsSelf{ + SupportedProxies: map[string][]string{ + "envoy": proxysupport.EnvoyVersions, + }, + } + } + config := struct { Datacenter string NodeName string @@ -82,6 +97,7 @@ func (s *HTTPServer) AgentSelf(resp http.ResponseWriter, req *http.Request) (int Member: s.agent.LocalMember(), Stats: s.agent.Stats(), Meta: s.agent.State.Metadata(), + XDS: xds, }, nil } diff --git a/agent/agent_endpoint_test.go b/agent/agent_endpoint_test.go index 6f2b9f7bf..505835ce8 100644 --- a/agent/agent_endpoint_test.go +++ b/agent/agent_endpoint_test.go @@ -13,7 +13,6 @@ import ( "net/http/httptest" "net/url" "os" - "reflect" "strconv" "strings" "testing" @@ -27,6 +26,7 @@ import ( "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/token" tokenStore "github.com/hashicorp/consul/agent/token" + "github.com/hashicorp/consul/agent/xds/proxysupport" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/sdk/testutil" @@ -1209,39 +1209,65 @@ func TestAgent_Checks_ACLFilter(t *testing.T) { func TestAgent_Self(t *testing.T) { t.Parallel() - a := NewTestAgent(t, ` - node_meta { - somekey = "somevalue" - } - `) - defer a.Shutdown() - testrpc.WaitForTestAgent(t, a.RPC, "dc1") - req, _ := http.NewRequest("GET", "/v1/agent/self", nil) - obj, err := a.srv.AgentSelf(nil, req) - if err != nil { - t.Fatalf("err: %v", err) + cases := map[string]struct { + hcl string + expectXDS bool + }{ + "normal": { + hcl: ` + node_meta { + somekey = "somevalue" + } + `, + expectXDS: true, + }, + "no grpc": { + hcl: ` + node_meta { + somekey = "somevalue" + } + ports = { + grpc = -1 + } + `, + expectXDS: false, + }, } - val := obj.(Self) - if int(val.Member.Port) != a.Config.SerfPortLAN { - t.Fatalf("incorrect port: %v", obj) - } + for name, tc := range cases { + tc := tc + t.Run(name, func(t *testing.T) { + a := NewTestAgent(t, tc.hcl) + defer a.Shutdown() - if val.DebugConfig["SerfPortLAN"].(int) != a.Config.SerfPortLAN { - t.Fatalf("incorrect port: %v", obj) - } + testrpc.WaitForTestAgent(t, a.RPC, "dc1") + req, _ := http.NewRequest("GET", "/v1/agent/self", nil) + obj, err := a.srv.AgentSelf(nil, req) + require.NoError(t, err) - cs, err := a.GetLANCoordinate() - if err != nil { - t.Fatalf("err: %v", err) - } - if c := cs[a.config.SegmentName]; !reflect.DeepEqual(c, val.Coord) { - t.Fatalf("coordinates are not equal: %v != %v", c, val.Coord) - } - delete(val.Meta, structs.MetaSegmentKey) // Added later, not in config. - if !reflect.DeepEqual(a.config.NodeMeta, val.Meta) { - t.Fatalf("meta fields are not equal: %v != %v", a.config.NodeMeta, val.Meta) + val := obj.(Self) + require.Equal(t, a.Config.SerfPortLAN, int(val.Member.Port)) + require.Equal(t, a.Config.SerfPortLAN, val.DebugConfig["SerfPortLAN"].(int)) + + cs, err := a.GetLANCoordinate() + require.NoError(t, err) + require.Equal(t, cs[a.config.SegmentName], val.Coord) + + delete(val.Meta, structs.MetaSegmentKey) // Added later, not in config. + require.Equal(t, a.config.NodeMeta, val.Meta) + + if tc.expectXDS { + require.NotNil(t, val.XDS, "xds component missing when gRPC is enabled") + require.Equal(t, + map[string][]string{"envoy": proxysupport.EnvoyVersions}, + val.XDS.SupportedProxies, + ) + + } else { + require.Nil(t, val.XDS, "xds component should be missing when gRPC is disabled") + } + }) } } diff --git a/agent/xds/proxysupport/proxysupport.go b/agent/xds/proxysupport/proxysupport.go index 98296309c..ed4be6048 100644 --- a/agent/xds/proxysupport/proxysupport.go +++ b/agent/xds/proxysupport/proxysupport.go @@ -2,6 +2,9 @@ package proxysupport // EnvoyVersions lists the latest officially supported versions of envoy. // +// This list must be sorted by semver descending. Only one point release for +// each major release should be present. +// // see: https://www.consul.io/docs/connect/proxies/envoy#supported-versions var EnvoyVersions = []string{ "1.15.0",