Skip to content

Commit

Permalink
feat(xds): add rate limit unit multiplier
Browse files Browse the repository at this point in the history
Signed-off-by: Tobias Sommer <[email protected]>
  • Loading branch information
Tobias Sommer authored and harpunius committed Apr 9, 2024
1 parent 58eb514 commit d6cef5f
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 16 deletions.
4 changes: 4 additions & 0 deletions api/ratelimit/config/ratelimit/v3/rls_conf.proto
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ message RateLimitPolicy {
// For more information: https://github.com/envoyproxy/ratelimit/tree/0b2f4d5fb04bf55e1873e2c5e2bb28da67c0643f#replaces
// Example: https://github.com/envoyproxy/ratelimit/tree/0b2f4d5fb04bf55e1873e2c5e2bb28da67c0643f#example-7
repeated RateLimitReplace replaces = 5;

// Multiplier for the unit of time for the rate limit.
// Used to create custom periods e.g. 10 seconds or 5 minutes.
optional uint32 unit_multiplier = 6;
}

// Replace specifies the rate limit policy that should be replaced (dropped evaluation).
Expand Down
1 change: 1 addition & 0 deletions src/config/config_xds.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func rateLimitPolicyPbToYaml(pb *rls_conf_v3.RateLimitPolicy) *YamlRateLimit {
return &YamlRateLimit{
RequestsPerUnit: pb.RequestsPerUnit,
Unit: pb.Unit.String(),
UnitMultiplier: pb.UnitMultiplier,
Unlimited: pb.Unlimited,
Name: pb.Name,
Replaces: rateLimitReplacesPbToYaml(pb.Replaces),
Expand Down
75 changes: 59 additions & 16 deletions test/provider/xds_grpc_sotw_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/envoyproxy/go-control-plane/pkg/cache/v3"
"github.com/envoyproxy/go-control-plane/pkg/resource/v3"

"github.com/envoyproxy/ratelimit/src/config"
"github.com/envoyproxy/ratelimit/src/provider"
"github.com/envoyproxy/ratelimit/src/settings"
"github.com/envoyproxy/ratelimit/test/common"
Expand All @@ -27,6 +28,7 @@ const (
)

func TestXdsProvider(t *testing.T) {
var unitMultiplier uint32 = 4
intSnapshot, _ := cache.NewSnapshot("1",
map[resource.Type][]types.Resource{
resource.RateLimitConfigType: {
Expand All @@ -40,6 +42,7 @@ func TestXdsProvider(t *testing.T) {
RateLimit: &rls_config.RateLimitPolicy{
Unit: rls_config.RateLimitUnit_MINUTE,
RequestsPerUnit: 3,
UnitMultiplier: &unitMultiplier,
},
},
},
Expand Down Expand Up @@ -73,7 +76,9 @@ func TestXdsProvider(t *testing.T) {
if err != nil {
t.Error("Error setting 'MERGE_DOMAIN_CONFIG' environment variable", err)
}
t.Run("Test same domain multiple times xDS config update", testSameDomainMultipleXdsConfigUpdate(setSnapshotFunc, providerEventChan))
t.Run("Test same domain multiple times xDS config update", testSameDomainMultipleXdsConfigUpdate(&snapVersion, setSnapshotFunc, providerEventChan))

t.Run("Test setting unit multiplier to 0", testZeroUnitMultiplier(&snapVersion, setSnapshotFunc, providerEventChan))
}

func testInitialXdsConfig(snapVersion *int, setSnapshotFunc common.SetSnapshotFunc, providerEventChan <-chan provider.ConfigUpdateEvent) func(t *testing.T) {
Expand All @@ -86,7 +91,7 @@ func testInitialXdsConfig(snapVersion *int, setSnapshotFunc common.SetSnapshotFu

config, err := configEvent.GetConfig()
assert.Nil(err)
assert.Equal("foo.k1_v1: unit=MINUTE requests_per_unit=3, shadow_mode: false\n", config.Dump())
assert.Equal("foo.k1_v1: unit=MINUTE, unit_multiplier=4, requests_per_unit=3, shadow_mode: false\n", config.Dump())
}
}

Expand Down Expand Up @@ -122,7 +127,7 @@ func testNewXdsConfigUpdate(snapVersion *int, setSnapshotFunc common.SetSnapshot

config, err := configEvent.GetConfig()
assert.Nil(err)
assert.Equal("foo.k2_v2: unit=MINUTE requests_per_unit=5, shadow_mode: false\n", config.Dump())
assert.Equal("foo.k2_v2: unit=MINUTE, unit_multiplier=1, requests_per_unit=5, shadow_mode: false\n", config.Dump())
}
}

Expand Down Expand Up @@ -173,8 +178,8 @@ func testMultiDomainXdsConfigUpdate(snapVersion *int, setSnapshotFunc common.Set
config, err := configEvent.GetConfig()
assert.Nil(err)
assert.ElementsMatch([]string{
"foo.k1_v1: unit=MINUTE requests_per_unit=10, shadow_mode: false",
"bar.k1_v1: unit=MINUTE requests_per_unit=100, shadow_mode: false",
"foo.k1_v1: unit=MINUTE, unit_multiplier=1, requests_per_unit=10, shadow_mode: false",
"bar.k1_v1: unit=MINUTE, unit_multiplier=1, requests_per_unit=100, shadow_mode: false",
}, strings.Split(strings.TrimSuffix(config.Dump(), "\n"), "\n"))
}
}
Expand Down Expand Up @@ -266,22 +271,23 @@ func testDeeperLimitsXdsConfigUpdate(snapVersion *int, setSnapshotFunc common.Se
config, err := configEvent.GetConfig()
assert.Nil(err)
assert.ElementsMatch([]string{
"foo.k1_v1: unit=MINUTE requests_per_unit=10, shadow_mode: false",
"foo.k1_v1.k2: unit=UNKNOWN requests_per_unit=0, shadow_mode: false",
"foo.k1_v1.k2_v2: unit=HOUR requests_per_unit=15, shadow_mode: false",
"foo.j1_v2: unit=UNKNOWN requests_per_unit=0, shadow_mode: false",
"foo.j1_v2.j2: unit=UNKNOWN requests_per_unit=0, shadow_mode: false",
"foo.j1_v2.j2_v2: unit=DAY requests_per_unit=15, shadow_mode: true",
"bar.k1_v1: unit=MINUTE requests_per_unit=100, shadow_mode: false",
"foo.k1_v1: unit=MINUTE, unit_multiplier=1, requests_per_unit=10, shadow_mode: false",
"foo.k1_v1.k2: unit=UNKNOWN, unit_multiplier=1, requests_per_unit=0, shadow_mode: false",
"foo.k1_v1.k2_v2: unit=HOUR, unit_multiplier=1, requests_per_unit=15, shadow_mode: false",
"foo.j1_v2: unit=UNKNOWN, unit_multiplier=1, requests_per_unit=0, shadow_mode: false",
"foo.j1_v2.j2: unit=UNKNOWN, unit_multiplier=1, requests_per_unit=0, shadow_mode: false",
"foo.j1_v2.j2_v2: unit=DAY, unit_multiplier=1, requests_per_unit=15, shadow_mode: true",
"bar.k1_v1: unit=MINUTE, unit_multiplier=1, requests_per_unit=100, shadow_mode: false",
}, strings.Split(strings.TrimSuffix(config.Dump(), "\n"), "\n"))
}
}

func testSameDomainMultipleXdsConfigUpdate(setSnapshotFunc common.SetSnapshotFunc, providerEventChan <-chan provider.ConfigUpdateEvent) func(t *testing.T) {
func testSameDomainMultipleXdsConfigUpdate(snapVersion *int, setSnapshotFunc common.SetSnapshotFunc, providerEventChan <-chan provider.ConfigUpdateEvent) func(t *testing.T) {
*snapVersion += 1
return func(t *testing.T) {
assert := assert.New(t)

snapshot, _ := cache.NewSnapshot("3",
snapshot, _ := cache.NewSnapshot(fmt.Sprint(*snapVersion),
map[resource.Type][]types.Resource{
resource.RateLimitConfigType: {
&rls_config.RateLimitConfig{
Expand Down Expand Up @@ -323,8 +329,45 @@ func testSameDomainMultipleXdsConfigUpdate(setSnapshotFunc common.SetSnapshotFun
config, err := configEvent.GetConfig()
assert.Nil(err)
assert.ElementsMatch([]string{
"foo.k1_v2: unit=MINUTE requests_per_unit=100, shadow_mode: false",
"foo.k1_v1: unit=MINUTE requests_per_unit=10, shadow_mode: false",
"foo.k1_v2: unit=MINUTE, unit_multiplier=1, requests_per_unit=100, shadow_mode: false",
"foo.k1_v1: unit=MINUTE, unit_multiplier=1, requests_per_unit=10, shadow_mode: false",
}, strings.Split(strings.TrimSuffix(config.Dump(), "\n"), "\n"))
}
}

func testZeroUnitMultiplier(snapVersion *int, setSnapshotFunc common.SetSnapshotFunc, providerEventChan <-chan provider.ConfigUpdateEvent) func(t *testing.T) {
*snapVersion += 1
return func(t *testing.T) {
assert := assert.New(t)

snapshot, _ := cache.NewSnapshot(fmt.Sprint(*snapVersion),
map[resource.Type][]types.Resource{
resource.RateLimitConfigType: {
&rls_config.RateLimitConfig{
Name: "foo-1",
Domain: "foo",
Descriptors: []*rls_config.RateLimitDescriptor{
{
Key: "k1",
Value: "v1",
RateLimit: &rls_config.RateLimitPolicy{
Unit: rls_config.RateLimitUnit_MINUTE,
RequestsPerUnit: 10,
UnitMultiplier: new(uint32),
},
},
},
},
},
},
)
setSnapshotFunc(snapshot)

configEvent := <-providerEventChan
assert.NotNil(configEvent)

_, err := configEvent.GetConfig()
configError, _ := err.(config.RateLimitConfigError)
assert.Equal("foo-1: invalid unit multiplier of 0", configError.Error())
}
}

0 comments on commit d6cef5f

Please sign in to comment.