From 68a224f1342213bc90a951fbb95ed1e5aed509bb Mon Sep 17 00:00:00 2001 From: Leonard Cohnen Date: Tue, 21 Jan 2025 04:54:16 +0100 Subject: [PATCH] service-mesh: introduce config generation tests With increasing envoy config complexity it gets more difficult to parse the final envoy config. Therefore we introduce tests which compare the envoy config for specific scenarios with golden JSON representations of the expected output. --- packages/by-name/service-mesh/package.nix | 3 +- service-mesh/config_test.go | 44 +++++ service-mesh/go.mod | 6 + service-mesh/go.sum | 18 ++ service-mesh/golden/defaultEnvoy.json | 223 ++++++++++++++++++++++ 5 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 service-mesh/config_test.go create mode 100644 service-mesh/golden/defaultEnvoy.json diff --git a/packages/by-name/service-mesh/package.nix b/packages/by-name/service-mesh/package.nix index cf26f31c30..89a4c7c386 100644 --- a/packages/by-name/service-mesh/package.nix +++ b/packages/by-name/service-mesh/package.nix @@ -19,12 +19,13 @@ buildGoModule rec { fileset = fileset.unions [ (path.append root "go.mod") (path.append root "go.sum") + (path.append root "golden/defaultEnvoy.json") (fileset.fileFilter (file: hasSuffix ".go" file.name) root) ]; }; proxyVendor = true; - vendorHash = "sha256-SlRxqvHfvWVtDABLnWiF8Sm8dedx2AX/rAU0cU8zHM4="; + vendorHash = "sha256-mFOLNHyUAc8eFzBXpdtnFHthJXQM5do6hTAA1K/XCfg="; subPackages = [ "." ]; diff --git a/service-mesh/config_test.go b/service-mesh/config_test.go new file mode 100644 index 0000000000..821ef92968 --- /dev/null +++ b/service-mesh/config_test.go @@ -0,0 +1,44 @@ +// Copyright 2024 Edgeless Systems GmbH +// SPDX-License-Identifier: AGPL-3.0-only + +package main + +import ( + _ "embed" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/goleak" +) + +//go:embed golden/defaultEnvoy.json +var defaultEnvoyConfig []byte + +func TestCompareEnvoyConfigToGolden(t *testing.T) { + require := require.New(t) + + config, err := ParseProxyConfig("", "", "") + require.NoError(err) + + testCases := map[string]struct { + pConfig ProxyConfig + }{ + "success": { + pConfig: config, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + configJSON, err := tc.pConfig.ToEnvoyConfig() + require.NoError(err) + assert.JSONEq(string(defaultEnvoyConfig), string(configJSON)) + }) + } +} + +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} diff --git a/service-mesh/go.mod b/service-mesh/go.mod index c849a6d1b9..df4d498c27 100644 --- a/service-mesh/go.mod +++ b/service-mesh/go.mod @@ -6,16 +6,22 @@ require ( github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 github.com/coreos/go-iptables v0.8.0 github.com/envoyproxy/go-control-plane/envoy v1.32.2 + github.com/stretchr/testify v1.8.4 + go.uber.org/goleak v1.3.0 google.golang.org/protobuf v1.36.1 ) require ( cel.dev/expr v0.16.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect github.com/google/go-cmp v0.6.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) // A refactoring of the go-control-plane library let's Go detect ambiguous imports: diff --git a/service-mesh/go.sum b/service-mesh/go.sum index 3d431d6329..b8733ae7db 100644 --- a/service-mesh/go.sum +++ b/service-mesh/go.sum @@ -4,17 +4,35 @@ github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 h1:N+3sFI5GUjRKBi+i0Tx github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/coreos/go-iptables v0.8.0 h1:MPc2P89IhuVpLI7ETL/2tx3XZ61VeICZjYqDEgNsPRc= github.com/coreos/go-iptables v0.8.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane/envoy v1.32.2 h1:zidqwmijfcbyKqVxjQDFx042PgX+p9U+/fu/f9VtSk8= github.com/envoyproxy/go-control-plane/envoy v1.32.2/go.mod h1:eR2SOX2IedqlPvmiKjUH7Wu//S602JKI7HPC/L3SRq8= github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/service-mesh/golden/defaultEnvoy.json b/service-mesh/golden/defaultEnvoy.json new file mode 100644 index 0000000000..a50d4d26a9 --- /dev/null +++ b/service-mesh/golden/defaultEnvoy.json @@ -0,0 +1,223 @@ +{ + "staticResources": { + "listeners": [ + { + "name": "ingress", + "address": { + "socketAddress": { + "address": "0.0.0.0", + "portValue": 15006 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "ingress", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "ingress", + "cluster": "IngressCluster" + } + } + ], + "transportSocket": { + "name": "envoy.transport_sockets.tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "commonTlsContext": { + "tlsCertificates": [ + { + "certificateChain": { + "filename": "/contrast/tls-config/certChain.pem" + }, + "privateKey": { + "filename": "/contrast/tls-config/key.pem" + } + } + ], + "validationContext": { + "trustedCa": { + "filename": "/contrast/tls-config/mesh-ca.pem" + } + } + }, + "requireClientCertificate": true + } + }, + "name": "ingress" + }, + { + "filters": [ + { + "name": "BlackHoleFilter", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "BlackHoleCluster", + "cluster": "BlackHoleCluster" + } + } + ], + "name": "BlackHoleFilter" + } + ], + "filterChainMatcher": { + "matcherTree": { + "input": { + "name": "port", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput" + } + }, + "exactMatchMap": { + "map": { + "15006": { + "action": { + "name": "forwardToBlackHoleFilter", + "typedConfig": { + "@type": "type.googleapis.com/google.protobuf.StringValue", + "value": "BlackHoleFilter" + } + } + } + } + } + }, + "onNoMatch": { + "action": { + "name": "forwardToIngress", + "typedConfig": { + "@type": "type.googleapis.com/google.protobuf.StringValue", + "value": "ingress" + } + } + } + }, + "listenerFilters": [ + { + "name": "tcpListener", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.listener.original_dst.v3.OriginalDst" + } + } + ], + "transparent": true + }, + { + "name": "ingressWithoutClientAuth", + "address": { + "socketAddress": { + "address": "0.0.0.0", + "portValue": 15007 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "ingress", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "ingressWithoutClientAuth", + "cluster": "IngressCluster" + } + } + ], + "transportSocket": { + "name": "envoy.transport_sockets.tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "commonTlsContext": { + "tlsCertificates": [ + { + "certificateChain": { + "filename": "/contrast/tls-config/certChain.pem" + }, + "privateKey": { + "filename": "/contrast/tls-config/key.pem" + } + } + ], + "validationContext": { + "trustedCa": { + "filename": "/contrast/tls-config/mesh-ca.pem" + } + } + }, + "requireClientCertificate": false + } + }, + "name": "ingressWithoutClientAuth" + }, + { + "filters": [ + { + "name": "BlackHoleFilter", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "BlackHoleCluster", + "cluster": "BlackHoleCluster" + } + } + ], + "name": "BlackHoleFilter" + } + ], + "filterChainMatcher": { + "matcherTree": { + "input": { + "name": "port", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput" + } + }, + "exactMatchMap": { + "map": { + "15007": { + "action": { + "name": "forwardToBlackHoleFilter", + "typedConfig": { + "@type": "type.googleapis.com/google.protobuf.StringValue", + "value": "BlackHoleFilter" + } + } + } + } + } + }, + "onNoMatch": { + "action": { + "name": "forwardToIngress", + "typedConfig": { + "@type": "type.googleapis.com/google.protobuf.StringValue", + "value": "ingressWithoutClientAuth" + } + } + } + }, + "listenerFilters": [ + { + "name": "tcpListener", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.listener.original_dst.v3.OriginalDst" + } + } + ], + "transparent": true + } + ], + "clusters": [ + { + "name": "IngressCluster", + "type": "ORIGINAL_DST", + "lbPolicy": "CLUSTER_PROVIDED", + "dnsLookupFamily": "V4_ONLY" + }, + { + "name": "BlackHoleCluster", + "type": "STATIC", + "connectTimeout": "10s" + } + ] + } +}