mirror of https://github.com/hashicorp/consul
Browse Source
* get upstream IPs * separate test data * fix lint issue * fix lint issuepull/14186/head
malizz
2 years ago
committed by
GitHub
5 changed files with 277 additions and 40 deletions
@ -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": {} |
||||
} |
||||
} |
||||
} |
||||
] |
||||
} |
||||
] |
||||
} |
@ -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