-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NET-5132 - Configure multiport routing for connect proxies in TProxy mode #18606
Changes from all commits
f4239e2
ab6ce72
93631aa
f65f474
7839d58
0b85a4b
a281bdc
1d5f30a
4844da9
b1df340
cf81b48
7945918
2a1f01b
2d486d8
eae4bf6
32928bc
f95b1b0
3727bd4
28e00f6
df7b6cd
22bbfca
867f2a0
151d470
840483f
47b9dbd
4456a60
2841214
71d5b13
dcf54e6
8ad8daf
6f5850a
e1392e0
b6d84f5
bb771ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// Copyright (c) HashiCorp, Inc. | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
|
||
package xdsv2 | ||
|
||
import ( | ||
envoy_cluster_v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" | ||
envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" | ||
"github.com/hashicorp/consul/agent/xds/response" | ||
"github.com/hashicorp/consul/envoyextensions/xdscommon" | ||
proxytracker "github.com/hashicorp/consul/internal/mesh/proxy-tracker" | ||
meshv1alpha1 "github.com/hashicorp/consul/proto-public/pbmesh/v1alpha1" | ||
"github.com/hashicorp/consul/sdk/testutil" | ||
"os" | ||
"path/filepath" | ||
"sort" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
"google.golang.org/protobuf/encoding/protojson" | ||
"google.golang.org/protobuf/proto" | ||
) | ||
|
||
func TestResources_ImplicitDestinations(t *testing.T) { | ||
|
||
cases := map[string]struct { | ||
}{ | ||
"l4-single-implicit-destination-tproxy": {}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does it only have one test case? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see my comment below. when I implemented the AlpnProtocol router match, I totally missed adding in logic for the proxyState -> xds conversion. so no tests failed and it was not until there was generated xds that you can verify it. There is no other place to put this kind of test so I added it here. I did not think we need to recreate all scenarios here since there should be less logic in this step of the conversion. I don't think we need many tests here, but we need something to able to assert that IR proto changes we make then properly get converted to XDS. Happy to entertain other ideas! |
||
} | ||
|
||
for name := range cases { | ||
goldenValueInput := goldenValueJSON(t, name, "input") | ||
|
||
proxyTemplate := jsonToProxyTemplate(t, goldenValueInput) | ||
generator := NewResourceGenerator(testutil.Logger(t)) | ||
|
||
resources, err := generator.AllResourcesFromIR(&proxytracker.ProxyState{ProxyState: proxyTemplate.ProxyState}) | ||
require.NoError(t, err) | ||
|
||
verifyClusterResourcesToGolden(t, resources, name) | ||
verifyListenerResourcesToGolden(t, resources, name) | ||
|
||
} | ||
} | ||
|
||
func verifyClusterResourcesToGolden(t *testing.T, resources map[string][]proto.Message, testName string) { | ||
clusters := resources[xdscommon.ClusterType] | ||
|
||
// The order of clusters returned via CDS isn't relevant, so it's safe | ||
// to sort these for the purposes of test comparisons. | ||
sort.Slice(clusters, func(i, j int) bool { | ||
return clusters[i].(*envoy_cluster_v3.Cluster).Name < clusters[j].(*envoy_cluster_v3.Cluster).Name | ||
}) | ||
|
||
resp, err := response.CreateResponse(xdscommon.ClusterType, "00000001", "00000001", clusters) | ||
require.NoError(t, err) | ||
gotJSON := protoToJSON(t, resp) | ||
|
||
expectedJSON := goldenValue(t, filepath.Join("clusters", testName), "output") | ||
require.JSONEq(t, expectedJSON, gotJSON) | ||
} | ||
|
||
func verifyListenerResourcesToGolden(t *testing.T, resources map[string][]proto.Message, testName string) { | ||
listeners := resources[xdscommon.ListenerType] | ||
|
||
// The order of clusters returned via CDS isn't relevant, so it's safe | ||
// to sort these for the purposes of test comparisons. | ||
sort.Slice(listeners, func(i, j int) bool { | ||
return listeners[i].(*envoy_listener_v3.Listener).Name < listeners[j].(*envoy_listener_v3.Listener).Name | ||
}) | ||
|
||
resp, err := response.CreateResponse(xdscommon.ListenerType, "00000001", "00000001", listeners) | ||
require.NoError(t, err) | ||
gotJSON := protoToJSON(t, resp) | ||
|
||
expectedJSON := goldenValue(t, filepath.Join("listeners", testName), "output") | ||
require.JSONEq(t, expectedJSON, gotJSON) | ||
} | ||
|
||
func protoToJSON(t *testing.T, pb proto.Message) string { | ||
t.Helper() | ||
m := protojson.MarshalOptions{ | ||
Indent: " ", | ||
} | ||
gotJSON, err := m.Marshal(pb) | ||
require.NoError(t, err) | ||
return string(gotJSON) | ||
} | ||
|
||
func jsonToProxyTemplate(t *testing.T, json []byte) *meshv1alpha1.ProxyStateTemplate { | ||
t.Helper() | ||
um := protojson.UnmarshalOptions{} | ||
proxyTemplate := &meshv1alpha1.ProxyStateTemplate{} | ||
err := um.Unmarshal(json, proxyTemplate) | ||
require.NoError(t, err) | ||
return proxyTemplate | ||
} | ||
|
||
func goldenValueJSON(t *testing.T, goldenFile, inputOutput string) []byte { | ||
t.Helper() | ||
goldenPath := filepath.Join("testdata", inputOutput, goldenFile) + ".golden" | ||
|
||
content, err := os.ReadFile(goldenPath) | ||
require.NoError(t, err) | ||
return content | ||
} | ||
|
||
func goldenValue(t *testing.T, goldenFile, inputOutput string) string { | ||
jmurret marked this conversation as resolved.
Show resolved
Hide resolved
|
||
t.Helper() | ||
return string(goldenValueJSON(t, goldenFile, inputOutput)) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
{ | ||
"proxyState": { | ||
"identity": { | ||
"tenancy": { | ||
"partition": "default", | ||
"namespace": "default", | ||
"peerName": "local" | ||
}, | ||
"name": "test-identity" | ||
}, | ||
"listeners": [ | ||
{ | ||
"name": "outbound_listener", | ||
"direction": "DIRECTION_OUTBOUND", | ||
"hostPort": { | ||
"host": "127.0.0.1", | ||
"port": 15001 | ||
}, | ||
"routers": [ | ||
{ | ||
"match": { | ||
"prefixRanges": [ | ||
{ | ||
"addressPrefix": "1.1.1.1", | ||
"prefixLen": 32 | ||
} | ||
], | ||
"destinationPort": 8080 | ||
}, | ||
"l4": { | ||
"name": "tcp.api-1.default.dc1.internal.foo.consul", | ||
"statPrefix": "upstream.tcp.api-1.default.default.dc1" | ||
} | ||
} | ||
], | ||
"capabilities": [ | ||
"CAPABILITY_TRANSPARENT" | ||
] | ||
} | ||
], | ||
"clusters": { | ||
"tcp.api-1.default.dc1.internal.foo.consul": { | ||
"endpointGroup": { | ||
"dynamic": { | ||
"config": { | ||
"disablePanicThreshold": true | ||
}, | ||
"outboundTls": { | ||
"outboundMesh": { | ||
"identityKey": "test-identity", | ||
"validationContext": { | ||
"spiffeIds": [ | ||
"spiffe://foo.consul/ap/default/ns/default/identity/api1-identity" | ||
] | ||
}, | ||
"sni": "api-1.default.dc1.internal.foo.consul" | ||
}, | ||
"alpnProtocols": [ | ||
"consul~tcp" | ||
] | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
"requiredEndpoints": { | ||
"api-1.default.dc1.internal.foo.consul": { | ||
"id": { | ||
"name": "api-1", | ||
"type": { | ||
"group": "catalog", | ||
"groupVersion": "v1alpha1", | ||
"kind": "ServiceEndpoints" | ||
}, | ||
"tenancy": { | ||
"partition": "default", | ||
"namespace": "default", | ||
"peerName": "local" | ||
} | ||
}, | ||
"port": "mesh" | ||
} | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this a copy-paste of the existing tests? If so, how were you thinking we'd keep these from diverging? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The other tests are golden files of proxyState, testing . This is a golden files for catalog/mesh vs -> proxy State. This test and file is for testing proxyState -> xds conversion. We have xds golden file tests that test proxyState -> xds, but they are proxy state converter tests, so adding those there did not seem appropriate. I added there was nothing testing that an ALPN router actually got converted to XDS. No tests failed and it was not until running an integration test that I noticed this it was even missing. So I added this to ensure that it happened. This type of testing will continue to be needed as we expand the types of Matches we support as we add more functionality. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"versionInfo": "00000001", | ||
"resources": [ | ||
{ | ||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", | ||
"name": "tcp.api-1.default.dc1.internal.foo.consul", | ||
"type": "EDS", | ||
"edsClusterConfig": { | ||
"edsConfig": { | ||
"ads": {}, | ||
"resourceApiVersion": "V3" | ||
} | ||
} | ||
} | ||
], | ||
"typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster", | ||
"nonce": "00000001" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
{ | ||
"versionInfo": "00000001", | ||
"resources": [ | ||
{ | ||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener", | ||
"name": "outbound_listener", | ||
"address": { | ||
"socketAddress": { | ||
"address": "127.0.0.1", | ||
"portValue": 15001 | ||
} | ||
}, | ||
"filterChains": [ | ||
{ | ||
"filterChainMatch": { | ||
"destinationPort": 8080, | ||
"prefixRanges": [ | ||
{ | ||
"addressPrefix": "1.1.1.1", | ||
"prefixLen": 32 | ||
} | ||
] | ||
}, | ||
"filters": [ | ||
{ | ||
"name": "envoy.filters.network.tcp_proxy", | ||
"typedConfig": { | ||
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", | ||
"statPrefix": "upstream.tcp.api-1.default.default.dc1", | ||
"cluster": "tcp.api-1.default.dc1.internal.foo.consul" | ||
} | ||
} | ||
] | ||
} | ||
], | ||
"listenerFilters": [ | ||
{ | ||
"name": "envoy.filters.listener.original_dst", | ||
"typedConfig": { | ||
"@type": "type.googleapis.com/envoy.extensions.filters.listener.original_dst.v3.OriginalDst" | ||
} | ||
} | ||
], | ||
"trafficDirection": "OUTBOUND" | ||
} | ||
], | ||
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", | ||
"nonce": "00000001" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this was found in testing that v2 wiring up was still using configSource with proxy tracker as the local cache.