Skip to content

Commit

Permalink
got first destination working.
Browse files Browse the repository at this point in the history
  • Loading branch information
jmurret committed Oct 24, 2023
1 parent de5a7c0 commit 2185dd6
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 193 deletions.
144 changes: 118 additions & 26 deletions agent/xdsv2/resources_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
package xdsv2

import (
"fmt"
envoy_endpoint_v3 "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
envoy_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
envoy_tls_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
"os"
"path/filepath"
"sort"
Expand All @@ -23,25 +27,114 @@ import (
"google.golang.org/protobuf/proto"
)

func TestResources_ImplicitDestinations(t *testing.T) {
var testTypeUrlToPrettyName = map[string]string{
xdscommon.ListenerType: "listeners",
xdscommon.RouteType: "routes",
xdscommon.ClusterType: "clusters",
xdscommon.EndpointType: "endpoints",
xdscommon.SecretType: "secrets",
}

cases := map[string]struct {
}{
"l4-single-implicit-destination-tproxy": {},
// TestReconcile_SidecarProxyGoldenFileInputs tests the Reconcile() by using
// the golden test output/expected files from the sidecar proxy tests as inputs
// to the XDS controller reconciliation.
// XDS controller reconciles the full ProxyStateTemplate object. The fields
// that things that it focuses on are leaf certs, endpoints, and trust bundles,
// which is just a subset of the ProxyStateTemplate struct. Prior to XDS controller
// reconciliation, the sidecar proxy controller will have reconciled the other parts
// of the ProxyStateTemplate.
// Since the XDS controller does act on the ProxyStateTemplate, the tests
// utilize that entire object rather than just the parts that XDS controller
// internals reconciles. Namely, by using checking the full ProxyStateTemplate
// rather than just endpoints, leaf certs, and trust bundles, the test also ensures
// side effects or change in scope to XDS controller are not introduce mistakenly.
func TestAllResourcesFromIR_XDSGoldenFileInputs(t *testing.T) {
inputPath := "../../internal/mesh/internal/controllers/xds"

cases := []string{
// destinations - please add in alphabetical order
//"destination/l4-single-destination-ip-port-bind-address",
//"destination/l4-single-destination-unix-socket-bind-address",
"destination/l4-single-implicit-destination-tproxy",
//"destination/l4-multi-destination",
//"destination/l4-multiple-implicit-destinations-tproxy",
//"destination/l4-implicit-and-explicit-destinations-tproxy",
//"destination/mixed-multi-destination",
//"destination/multiport-l4-and-l7-multiple-implicit-destinations-tproxy",
//"destination/multiport-l4-and-l7-single-implicit-destination-tproxy",
//"destination/multiport-l4-and-l7-single-implicit-destination-with-multiple-workloads-tproxy",

//sources - please add in alphabetical order
//"source/l4-multiple-workload-addresses-with-specific-ports",
//"source/l4-multiple-workload-addresses-without-ports",
//"source/l4-single-workload-address-without-ports",
//"source/l7-expose-paths",
//"source/local-and-inbound-connections",
//"source/multiport-l4-multiple-workload-addresses-with-specific-ports",
//"source/multiport-l4-multiple-workload-addresses-without-ports",
//"source/multiport-l4-workload-with-only-mesh-port",
//"source/multiport-l7-multiple-workload-addresses-with-specific-ports",
//"source/multiport-l7-multiple-workload-addresses-without-ports",
//"source/multiport-l7-multiple-workload-addresses-without-ports",
}

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)

for _, name := range cases {
t.Run(name, func(t *testing.T) {
testFile := fmt.Sprintf("%s.golden", name)
inputFilePath := fmt.Sprintf("%s/testdata/%s", inputPath, testFile)
inputValueInput := goldenValueJSON(t, inputFilePath)

ps := jsonToProxyState(t, inputValueInput)
generator := NewResourceGenerator(testutil.Logger(t))

resources, err := generator.AllResourcesFromIR(&proxytracker.ProxyState{ProxyState: ps})
require.NoError(t, err)

require.NoError(t, err)

typeUrls := []string{
xdscommon.ListenerType,
xdscommon.RouteType,
xdscommon.ClusterType,
xdscommon.EndpointType,
// TODO(proxystate): add in future
//xdscommon.SecretType,
}
require.Len(t, resources, len(typeUrls))

for _, typeUrl := range typeUrls {
prettyName := testTypeUrlToPrettyName[typeUrl]
t.Run(prettyName, func(t *testing.T) {
items, ok := resources[typeUrl]
require.True(t, ok)

sort.Slice(items, func(i, j int) bool {
switch typeUrl {
case xdscommon.ListenerType:
return items[i].(*envoy_listener_v3.Listener).Name < items[j].(*envoy_listener_v3.Listener).Name
case xdscommon.RouteType:
return items[i].(*envoy_route_v3.RouteConfiguration).Name < items[j].(*envoy_route_v3.RouteConfiguration).Name
case xdscommon.ClusterType:
return items[i].(*envoy_cluster_v3.Cluster).Name < items[j].(*envoy_cluster_v3.Cluster).Name
case xdscommon.EndpointType:
return items[i].(*envoy_endpoint_v3.ClusterLoadAssignment).ClusterName < items[j].(*envoy_endpoint_v3.ClusterLoadAssignment).ClusterName
case xdscommon.SecretType:
return items[i].(*envoy_tls_v3.Secret).Name < items[j].(*envoy_tls_v3.Secret).Name
default:
panic("not possible")
}
})

resp, err := response.CreateResponse(typeUrl, "00000001", "00000001", items)
require.NoError(t, err)

gotJSON := protoToJSON(t, resp)

expectedJSON := goldenValue(t, fmt.Sprintf("testdata/%s/%s", prettyName, testFile))
require.JSONEq(t, expectedJSON, gotJSON)
})
}
})
}
}

Expand All @@ -58,7 +151,7 @@ func verifyClusterResourcesToGolden(t *testing.T, resources map[string][]proto.M
require.NoError(t, err)
gotJSON := protoToJSON(t, resp)

expectedJSON := goldenValue(t, filepath.Join("clusters", testName), "output")
expectedJSON := goldenValue(t, filepath.Join("testdata/clusters", testName))
require.JSONEq(t, expectedJSON, gotJSON)
}

Expand All @@ -75,7 +168,7 @@ func verifyListenerResourcesToGolden(t *testing.T, resources map[string][]proto.
require.NoError(t, err)
gotJSON := protoToJSON(t, resp)

expectedJSON := goldenValue(t, filepath.Join("listeners", testName), "output")
expectedJSON := goldenValue(t, filepath.Join("testdata/listeners", testName))
require.JSONEq(t, expectedJSON, gotJSON)
}

Expand All @@ -89,25 +182,24 @@ func protoToJSON(t *testing.T, pb proto.Message) string {
return string(gotJSON)
}

func jsonToProxyTemplate(t *testing.T, json []byte) *meshv2beta1.ProxyStateTemplate {
func jsonToProxyState(t *testing.T, json []byte) *meshv2beta1.ProxyState {
t.Helper()
um := protojson.UnmarshalOptions{}
proxyTemplate := &meshv2beta1.ProxyStateTemplate{}
err := um.Unmarshal(json, proxyTemplate)
ps := &meshv2beta1.ProxyState{}
err := um.Unmarshal(json, ps)
require.NoError(t, err)
return proxyTemplate
return ps
}

func goldenValueJSON(t *testing.T, goldenFile, inputOutput string) []byte {
func goldenValueJSON(t *testing.T, goldenPath 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 {
func goldenValue(t *testing.T, filePath string) string {
t.Helper()
return string(goldenValueJSON(t, goldenFile, inputOutput))
return string(goldenValueJSON(t, filePath))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"versionInfo": "00000001",
"resources": [
{
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
"connectTimeout": "5s",
"lbPolicy": "CLUSTER_PROVIDED",
"name": "original-destination",
"type": "ORIGINAL_DST"
},
{
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
"name": "tcp.api-1.default.dc1.internal.foo.consul",
"type": "EDS",
"connectTimeout": "5s",
"edsClusterConfig": {
"edsConfig": {
"ads": {},
"resourceApiVersion": "V3"
}
},
"commonLbConfig": {
"healthyPanicThreshold": {}
},
"name": "tcp.api-1.default.dc1.internal.foo.consul",
"transportSocket": {
"name": "tls",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
"commonTlsContext": {
"alpnProtocols": [
"consul~tcp"
],
"tlsCertificates": [
{
"certificateChain": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICDjCCAbWgAwIBAgIBAjAKBggqhkjOPQQDAjAUMRIwEAYDVQQDEwlUZXN0IENB\nIDEwHhcNMjMxMDE2MTYxMzI5WhcNMjMxMDE2MTYyMzI5WjAAMFkwEwYHKoZIzj0C\nAQYIKoZIzj0DAQcDQgAErErAIosDPheZQGbxFQ4hYC/e9Fi4MG9z/zjfCnCq/oK9\nta/bGT+5orZqTmdN/ICsKQDhykxZ2u/Xr6845zhcJaOCAQowggEGMA4GA1UdDwEB\n/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwDAYDVR0TAQH/\nBAIwADApBgNVHQ4EIgQg3ogXVz9cqaK2B6xdiJYMa5NtT0KkYv7BA2dR7h9EcwUw\nKwYDVR0jBCQwIoAgq+C1mPlPoGa4lt7sSft1goN5qPGyBIB/3mUHJZKSFY8wbwYD\nVR0RAQH/BGUwY4Zhc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9hcC9kZWZhdWx0L25zL2RlZmF1bHQvaWRlbnRpdHkv\ndGVzdC1pZGVudGl0eTAKBggqhkjOPQQDAgNHADBEAiB6L+t5bzRrBPhiQYNeA7fF\nUCuLWrdjW4Xbv3SLg0IKMgIgfRC5hEx+DqzQxTCP4sexX3hVWMjKoWmHdwiUcg+K\n/IE=\n-----END CERTIFICATE-----\n"
},
"privateKey": {
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIFIFkTIL1iUV4O/RpveVHzHs7ZzhSkvYIzbdXDttz9EooAoGCCqGSM49\nAwEHoUQDQgAErErAIosDPheZQGbxFQ4hYC/e9Fi4MG9z/zjfCnCq/oK9ta/bGT+5\norZqTmdN/ICsKQDhykxZ2u/Xr6845zhcJQ==\n-----END EC PRIVATE KEY-----\n"
}
}
],
"tlsParams": {},
"validationContext": {
"matchSubjectAltNames": [
{
"exact": "spiffe://foo.consul/ap/default/ns/default/identity/api1-identity"
}
],
"trustedCa": {
"inlineString": "some-root\nsome-other-root\n"
}
}
},
"sni": "api-1.default.dc1.internal.foo.consul"
}
},
"type": "EDS"
}
],
"typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
"nonce": "00000001"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"versionInfo": "00000001",
"resources": [
{
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
"clusterName": "tcp.api-1.default.dc1.internal.foo.consul",
"endpoints": [
{
"lbEndpoints": [
{
"endpoint": {
"address": {
"socketAddress": {
"address": "10.1.1.1",
"portValue": 20000
}
}
},
"healthStatus": "HEALTHY"
}
]
}
]
}
],
"typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
"nonce": "00000001"
}
Loading

0 comments on commit 2185dd6

Please sign in to comment.