Skip to content

Commit

Permalink
Merge pull request #5437 from emissary-ingress/tenshinhigashi/route-s…
Browse files Browse the repository at this point in the history
…hift-3.9

Pull in route shift to 3.9
  • Loading branch information
tenshinhigashi authored Nov 16, 2023
2 parents ad25a61 + 3df8aef commit d725060
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 4 deletions.
25 changes: 21 additions & 4 deletions pkg/ambex/transforms.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package ambex
import (
// standard library
"context"
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"

// third-party libraries
Expand Down Expand Up @@ -89,7 +92,7 @@ import (
// "config_source": {
// "ads": {}
// },
// "route_config_name": "ambassador-listener-8443-routeconfig-0"
// "route_config_name": "ambassador-listener-8443-routeconfig-376bf87fb310abb282f452533940481d-0"
// }
// }
// }
Expand All @@ -100,7 +103,7 @@ import (
//
// routes = [
// {
// "name": "ambassador-listener-8443-routeconfig-0",
// "name": "ambassador-listener-8443-routeconfig-376bf87fb310abb282f452533940481d-0",
// "virtual_hosts": [
// {
// "name": "ambassador-listener-8443-*",
Expand All @@ -114,6 +117,10 @@ import (
// V3ListenerToRdsListener is the v3 variety of ListnerToRdsListener
func V3ListenerToRdsListener(lnr *v3listener.Listener) (*v3listener.Listener, []*v3route.RouteConfiguration, error) {
l := proto.Clone(lnr).(*v3listener.Listener)

// Keep track of number of filter chain matches that hash to the same key for collisions
matchKeyIndex := make(map[string]int)

var routes []*v3route.RouteConfiguration
for _, fc := range l.FilterChains {
for _, f := range fc.Filters {
Expand All @@ -135,10 +142,20 @@ func V3ListenerToRdsListener(lnr *v3listener.Listener) (*v3listener.Listener, []
if rc.Name == "" {
// Generate a unique name for the RouteConfiguration that we can use to
// correlate the listener to the RDS record. We use the listener name plus
// an index because there can be more than one route configuration
// filter_chain_match hash because there can be more than one route configuration
// associated with a given listener.
rc.Name = fmt.Sprintf("%s-routeconfig-%d", l.Name, len(routes))
filterChainMatch, _ := json.Marshal(fc.GetFilterChainMatch())

// Use MD5 because it's decently fast and cryptographic security isn't needed.
matchHash := md5.Sum(filterChainMatch)
matchKey := hex.EncodeToString(matchHash[:])

rc.Name = fmt.Sprintf("%s-routeconfig-%s-%d", l.Name, matchKey, matchKeyIndex[matchKey])

// Add or update map entry for this filter chain key to dedupe those that hash to the same key.
matchKeyIndex[matchKey]++
}

routes = append(routes, rc)
// Now that we have extracted and named the RouteConfiguration, we change the
// RouteSpecifier from the inline RouteConfig variation to RDS via ADS. This
Expand Down
89 changes: 89 additions & 0 deletions pkg/ambex/transforms_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package ambex

import (
"fmt"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/durationpb"
"google.golang.org/protobuf/types/known/wrapperspb"

v3Listener "github.com/emissary-ingress/emissary/v3/pkg/api/envoy/config/listener/v3"
v3Route "github.com/emissary-ingress/emissary/v3/pkg/api/envoy/config/route/v3"
v3Httpman "github.com/emissary-ingress/emissary/v3/pkg/api/envoy/extensions/filters/network/http_connection_manager/v3"
v3Wellknown "github.com/emissary-ingress/emissary/v3/pkg/envoy-control-plane/wellknown"
)

func TestV3ListenerToRdsListener(t *testing.T) {
testRoute := &v3Route.Route_Route{
Route: &v3Route.RouteAction{
ClusterSpecifier: &v3Route.RouteAction_Cluster{
Cluster: "cluster_quote_default_default",
},
PrefixRewrite: "/",
Timeout: durationpb.New(3 * time.Second),
},
}

testHcm := &v3Httpman.HttpConnectionManager{
RouteSpecifier: &v3Httpman.HttpConnectionManager_RouteConfig{
RouteConfig: &v3Route.RouteConfiguration{
VirtualHosts: []*v3Route.VirtualHost{{
Name: "emissary-ingress-listener-8080-*",
Domains: []string{"*"},
Routes: []*v3Route.Route{{
Match: &v3Route.RouteMatch{
PathSpecifier: &v3Route.RouteMatch_Prefix{
Prefix: "/backend/",
},
},
Action: testRoute,
}},
}},
},
},
}

anyTestHcm, err := anypb.New(testHcm)
require.NoError(t, err)

//Create a second identical Hcm
anyTestHcm2, err := anypb.New(testHcm)
require.NoError(t, err)

testListener := &v3Listener.Listener{
Name: "emissary-ingress-listener-8080",
FilterChains: []*v3Listener.FilterChain{{
Filters: []*v3Listener.Filter{{
Name: v3Wellknown.HTTPConnectionManager,
ConfigType: &v3Listener.Filter_TypedConfig{TypedConfig: anyTestHcm},
}, {
Name: v3Wellknown.HTTPConnectionManager,
ConfigType: &v3Listener.Filter_TypedConfig{TypedConfig: anyTestHcm2},
}},
FilterChainMatch: &v3Listener.FilterChainMatch{
DestinationPort: &wrapperspb.UInt32Value{Value: uint32(8080)},
},
}},
}

_, routes, err := V3ListenerToRdsListener(testListener)
require.NoError(t, err)

//Should have 2 routes
assert.Equal(t, 2, len(routes))

for i, rc := range routes {
// Confirm that the route name was transformed to the hashed version
assert.Equal(t, fmt.Sprintf("emissary-ingress-listener-8080-routeconfig-8c82e45fa3f94ab4e879543e0a1a30ac-%d", i), rc.GetName())

// Make sure the virtual hosts are unmodified
virtualHosts := rc.GetVirtualHosts()
assert.Equal(t, 1, len(virtualHosts))
assert.Equal(t, "emissary-ingress-listener-8080-*", virtualHosts[0].GetName())
assert.Equal(t, []string{"*"}, virtualHosts[0].GetDomains())
}
}

0 comments on commit d725060

Please sign in to comment.