mirror of https://github.com/status-im/consul.git
get upstream IPs (#16197)
* get upstream IPs * separate test data * fix lint issue * fix lint issue
This commit is contained in:
parent
ed7367b6f4
commit
0a544809c9
|
@ -68,15 +68,20 @@ func (c *cmd) Run(args []string) int {
|
||||||
c.UI.Error("error generating troubleshoot client: " + err.Error())
|
c.UI.Error("error generating troubleshoot client: " + err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
upstreams, err := t.GetUpstreams()
|
envoyIDs, upstreamIPs, err := t.GetUpstreams()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.UI.Error("error calling GetUpstreams: " + err.Error())
|
c.UI.Error("error calling GetUpstreams: " + err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, u := range upstreams {
|
for _, u := range envoyIDs {
|
||||||
c.UI.Output(u)
|
c.UI.Output(u)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, u := range upstreamIPs {
|
||||||
|
c.UI.Output(fmt.Sprintf("%+v %v %+v", u.IPs, u.IsVirtual, u.ClusterNames))
|
||||||
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
{
|
||||||
|
"name": "outbound_listener:127.0.0.1:15001",
|
||||||
|
"address": {
|
||||||
|
"socket_address": {
|
||||||
|
"address": "127.0.0.1",
|
||||||
|
"port_value": 15001
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filter_chains": [
|
||||||
|
{
|
||||||
|
"filter_chain_match": {
|
||||||
|
"prefix_ranges": [
|
||||||
|
{
|
||||||
|
"address_prefix": "10.244.0.63",
|
||||||
|
"prefix_len": 32
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address_prefix": "10.244.0.64",
|
||||||
|
"prefix_len": 32
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.tcp_proxy",
|
||||||
|
"typed_config": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||||
|
"stat_prefix": "upstream.foo.default.default.dc1",
|
||||||
|
"cluster": "passthrough~foo.default.dc1.internal.dc1.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filter_chain_match": {
|
||||||
|
"prefix_ranges": [
|
||||||
|
{
|
||||||
|
"address_prefix": "10.96.5.96",
|
||||||
|
"prefix_len": 32
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address_prefix": "240.0.0.1",
|
||||||
|
"prefix_len": 32
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.http_connection_manager",
|
||||||
|
"typed_config": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||||
|
"stat_prefix": "upstream.foo.default.default.dc1",
|
||||||
|
"route_config": {
|
||||||
|
"name": "foo",
|
||||||
|
"virtual_hosts": [
|
||||||
|
{
|
||||||
|
"name": "foo.default.default.dc1",
|
||||||
|
"domains": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": {
|
||||||
|
"prefix": "/"
|
||||||
|
},
|
||||||
|
"route": {
|
||||||
|
"cluster": "foo.default.dc1.internal.dc1.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"http_filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.http.router",
|
||||||
|
"typed_config": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tracing": {
|
||||||
|
"random_sampling": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -5,17 +5,18 @@ import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
envoy_admin_v3 "github.com/envoyproxy/go-control-plane/envoy/admin/v3"
|
envoy_admin_v3 "github.com/envoyproxy/go-control-plane/envoy/admin/v3"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
"google.golang.org/protobuf/proto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
listeners string = "type.googleapis.com/envoy.admin.v3.ListenersConfigDump"
|
listeners string = "type.googleapis.com/envoy.admin.v3.ListenersConfigDump"
|
||||||
clusters string = "type.googleapis.com/envoy.admin.v3.ClustersConfigDump"
|
clusters string = "type.googleapis.com/envoy.admin.v3.ClustersConfigDump"
|
||||||
routes string = "type.googleapis.com/envoy.admin.v3.RoutesConfigDump"
|
routes string = "type.googleapis.com/envoy.admin.v3.RoutesConfigDump"
|
||||||
endpoints string = "type.googleapis.com/envoy.admin.v3.EndpointsConfigDump"
|
endpoints string = "type.googleapis.com/envoy.admin.v3.EndpointsConfigDump"
|
||||||
bootstrap string = "type.googleapis.com/envoy.admin.v3.BootstrapConfigDump"
|
bootstrap string = "type.googleapis.com/envoy.admin.v3.BootstrapConfigDump"
|
||||||
|
httpConnManager string = "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Troubleshoot struct {
|
type Troubleshoot struct {
|
||||||
|
@ -95,35 +96,3 @@ func (t *Troubleshoot) RunAllTests(envoyID string) ([]string, error) {
|
||||||
}
|
}
|
||||||
return output, resultErr
|
return output, resultErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Troubleshoot) GetUpstreams() ([]string, error) {
|
|
||||||
|
|
||||||
upstreams := []string{}
|
|
||||||
|
|
||||||
err := t.GetEnvoyConfigDump()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, cfg := range t.envoyConfigDump.Configs {
|
|
||||||
switch cfg.TypeUrl {
|
|
||||||
case listeners:
|
|
||||||
lcd := &envoy_admin_v3.ListenersConfigDump{}
|
|
||||||
|
|
||||||
err := proto.Unmarshal(cfg.GetValue(), lcd)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, listener := range lcd.GetDynamicListeners() {
|
|
||||||
upstream := envoyID(listener.Name)
|
|
||||||
if upstream != "" && upstream != "public_listener" &&
|
|
||||||
upstream != "outbound_listener" &&
|
|
||||||
upstream != "inbound_listener" {
|
|
||||||
upstreams = append(upstreams, upstream)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return upstreams, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
package troubleshoot
|
||||||
|
|
||||||
|
import (
|
||||||
|
envoy_admin_v3 "github.com/envoyproxy/go-control-plane/envoy/admin/v3"
|
||||||
|
envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
||||||
|
envoy_resource_v3 "github.com/envoyproxy/go-control-plane/pkg/resource/v3"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/envoyextensions/extensioncommon"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpstreamIP struct {
|
||||||
|
IPs []string
|
||||||
|
IsVirtual bool
|
||||||
|
ClusterNames map[string]struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Troubleshoot) GetUpstreams() ([]string, []UpstreamIP, error) {
|
||||||
|
|
||||||
|
upstream_envoy_ids := []string{}
|
||||||
|
upstream_ips := []UpstreamIP{}
|
||||||
|
|
||||||
|
err := t.GetEnvoyConfigDump()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cfg := range t.envoyConfigDump.Configs {
|
||||||
|
switch cfg.TypeUrl {
|
||||||
|
case listeners:
|
||||||
|
lcd := &envoy_admin_v3.ListenersConfigDump{}
|
||||||
|
|
||||||
|
err := proto.Unmarshal(cfg.GetValue(), lcd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, listener := range lcd.GetDynamicListeners() {
|
||||||
|
|
||||||
|
eid := envoyID(listener.Name)
|
||||||
|
|
||||||
|
if eid != "" && eid != "public_listener" &&
|
||||||
|
eid != "outbound_listener" && eid != "inbound_listener" {
|
||||||
|
upstream_envoy_ids = append(upstream_envoy_ids, eid)
|
||||||
|
} else if eid == "outbound_listener" {
|
||||||
|
l := &envoy_listener_v3.Listener{}
|
||||||
|
err = proto.Unmarshal(listener.GetActiveState().GetListener().GetValue(), l)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream_ips, err = getUpstreamIPsFromFilterChain(l.GetFilterChains())
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return upstream_envoy_ids, upstream_ips, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUpstreamIPsFromFilterChain(filterChains []*envoy_listener_v3.FilterChain) ([]UpstreamIP, error) {
|
||||||
|
if filterChains == nil {
|
||||||
|
return []UpstreamIP{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
upstreamIPs := []UpstreamIP{}
|
||||||
|
for _, fc := range filterChains {
|
||||||
|
|
||||||
|
if fc.GetFilters() == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if fc.GetFilterChainMatch() == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if fc.GetFilterChainMatch().GetPrefixRanges() == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
cidrs := fc.GetFilterChainMatch().GetPrefixRanges()
|
||||||
|
ips := []string{}
|
||||||
|
|
||||||
|
for _, cidr := range cidrs {
|
||||||
|
ips = append(ips, cidr.AddressPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, filter := range fc.GetFilters() {
|
||||||
|
isVirtual := false
|
||||||
|
|
||||||
|
if filter.GetTypedConfig() == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
clusterNames := map[string]struct{}{}
|
||||||
|
|
||||||
|
if config := envoy_resource_v3.GetHTTPConnectionManager(filter); config != nil {
|
||||||
|
isVirtual = true
|
||||||
|
|
||||||
|
cfg := config.GetRouteConfig()
|
||||||
|
|
||||||
|
clusterNames = extensioncommon.RouteClusterNames(cfg)
|
||||||
|
}
|
||||||
|
if config := extensioncommon.GetTCPProxy(filter); config != nil {
|
||||||
|
if config.GetCluster() != "" {
|
||||||
|
clusterNames[config.GetCluster()] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
upstreamIPs = append(upstreamIPs, UpstreamIP{
|
||||||
|
IPs: ips,
|
||||||
|
IsVirtual: isVirtual,
|
||||||
|
ClusterNames: clusterNames,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return upstreamIPs, nil
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package troubleshoot
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetUpstreamIPsFromFilterChain(t *testing.T) {
|
||||||
|
file, err := os.Open("testdata/listeners.json")
|
||||||
|
require.NoError(t, err)
|
||||||
|
jsonBytes, err := io.ReadAll(file)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
expected := []UpstreamIP{
|
||||||
|
{
|
||||||
|
IPs: []string{
|
||||||
|
"10.244.0.63",
|
||||||
|
"10.244.0.64",
|
||||||
|
},
|
||||||
|
IsVirtual: false,
|
||||||
|
ClusterNames: map[string]struct{}{
|
||||||
|
"passthrough~foo.default.dc1.internal.dc1.consul": {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
IPs: []string{
|
||||||
|
"10.96.5.96",
|
||||||
|
"240.0.0.1",
|
||||||
|
},
|
||||||
|
IsVirtual: true,
|
||||||
|
ClusterNames: map[string]struct{}{
|
||||||
|
"foo.default.dc1.internal.dc1.consul": {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var listener envoy_listener_v3.Listener
|
||||||
|
unmarshal := &protojson.UnmarshalOptions{
|
||||||
|
DiscardUnknown: true,
|
||||||
|
}
|
||||||
|
err = unmarshal.Unmarshal(jsonBytes, &listener)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
upstream_ips, err := getUpstreamIPsFromFilterChain(listener.GetFilterChains())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, expected, upstream_ips)
|
||||||
|
}
|
Loading…
Reference in New Issue