Skip to content

Commit

Permalink
Build rate limit service config (#893)
Browse files Browse the repository at this point in the history
* Build rate limit service config

* Translates Xds IR into ratelimit service config
https://github.com/envoyproxy/ratelimit#configuration

Relates to #670

Signed-off-by: Arko Dasgupta <arko@tetrate.io>

* fix yamlint

Signed-off-by: Arko Dasgupta <arko@tetrate.io>

* lint

Signed-off-by: Arko Dasgupta <arko@tetrate.io>

Signed-off-by: Arko Dasgupta <arko@tetrate.io>
  • Loading branch information
arkodg authored Jan 18, 2023
1 parent c4cf1f8 commit 27253bb
Show file tree
Hide file tree
Showing 16 changed files with 391 additions and 2 deletions.
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.19
require (
github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc
github.com/envoyproxy/go-control-plane v0.10.3-0.20221028143534-ed9652aebfd9
github.com/envoyproxy/ratelimit v1.4.1-0.20230109191524-5f3f5a4cf573
github.com/go-logr/logr v1.2.3
github.com/go-logr/zapr v1.2.3
github.com/google/go-cmp v0.5.9
Expand All @@ -17,6 +18,7 @@ require (
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e
google.golang.org/grpc v1.52.0
google.golang.org/protobuf v1.28.1
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.26.0
k8s.io/apimachinery v0.26.0
k8s.io/client-go v0.26.0
Expand Down Expand Up @@ -51,6 +53,8 @@ require (
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kelseyhightower/envconfig v1.4.0 // indirect
github.com/lyft/gostats v0.4.1 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
Expand All @@ -62,6 +66,7 @@ require (
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/tsaarni/x500dn v0.0.0-20210331182804-14283c7f5a16 // indirect
go.uber.org/atomic v1.7.0 // indirect
Expand All @@ -77,7 +82,6 @@ require (
google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.26.0 // indirect
k8s.io/component-base v0.26.0 // indirect
k8s.io/klog/v2 v2.80.1 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ github.com/envoyproxy/go-control-plane v0.10.3-0.20221028143534-ed9652aebfd9/go.
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.6.7 h1:qcZcULcd/abmQg6dwigimCNEyi4gg31M/xaciQlDml8=
github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
github.com/envoyproxy/ratelimit v1.4.1-0.20230109191524-5f3f5a4cf573 h1:R0q3SnW2O9CnSHt9Mx6I/v3nz3HH3xzqeOQ+zSpszpA=
github.com/envoyproxy/ratelimit v1.4.1-0.20230109191524-5f3f5a4cf573/go.mod h1:J780gPM5tWaDEY2n+A7q744I9Bot8OJuBHZbwCfDpVc=
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
Expand Down Expand Up @@ -218,6 +220,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
Expand All @@ -230,6 +234,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lyft/gostats v0.4.1 h1:oR6p4HRCGxt0nUntmZIWmYMgyothBi3eZH2A71vRjsc=
github.com/lyft/gostats v0.4.1/go.mod h1:Tpx2xRzz4t+T2Tx0xdVgIoBdR2UMVz+dKnE3X01XSd8=
github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
Expand Down Expand Up @@ -293,6 +299,7 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
Expand Down Expand Up @@ -464,6 +471,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
81 changes: 81 additions & 0 deletions internal/xds/translator/ratelimit.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
ratelimitfilter "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/ratelimit/v3"
hcm "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
wkt "github.com/envoyproxy/go-control-plane/pkg/wellknown"
ratelimitserviceconfig "github.com/envoyproxy/ratelimit/src/config"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/durationpb"
"google.golang.org/protobuf/types/known/wrapperspb"
Expand Down Expand Up @@ -165,6 +166,86 @@ func buildRouteRateLimits(descriptorPrefix string, global *ir.GlobalRateLimit) [
return rateLimits
}

// BuildRateLimitServiceConfig builds the rate limit service configuration based on
// https://github.com/envoyproxy/ratelimit#the-configuration-format
func BuildRateLimitServiceConfig(irListener *ir.HTTPListener) *ratelimitserviceconfig.YamlRoot {
yamlDescs := make([]ratelimitserviceconfig.YamlDescriptor, 0, 1)

for _, route := range irListener.Routes {
if route.RateLimit != nil && route.RateLimit.Global != nil {
descs := buildRateLimitServiceDescriptors(route.Name, route.RateLimit.Global)
yamlDescs = append(yamlDescs, descs...)
}
}

if len(yamlDescs) == 0 {
return nil
}

return &ratelimitserviceconfig.YamlRoot{
Domain: getRateLimitDomain(irListener),
Descriptors: yamlDescs,
}
}

// buildRateLimitServiceDescriptors creates the rate limit service yaml descriptors based on the global rate limit IR config.
func buildRateLimitServiceDescriptors(descriptorPrefix string, global *ir.GlobalRateLimit) []ratelimitserviceconfig.YamlDescriptor {
yamlDescs := make([]ratelimitserviceconfig.YamlDescriptor, 0, 1)

for rIdx, rule := range global.Rules {
var head, cur *ratelimitserviceconfig.YamlDescriptor
if len(rule.HeaderMatches) == 0 {
yamlDesc := new(ratelimitserviceconfig.YamlDescriptor)
// GenericKey case
yamlDesc.Key = getRateLimitDescriptorKey(descriptorPrefix, rIdx, -1)
yamlDesc.Value = getRateLimitDescriptorValue(descriptorPrefix, rIdx, -1)
rateLimit := ratelimitserviceconfig.YamlRateLimit{
RequestsPerUnit: rule.Limit.Requests,
Unit: string(rule.Limit.Unit),
}
yamlDesc.RateLimit = &rateLimit

head = yamlDesc
cur = head
}

for mIdx, match := range rule.HeaderMatches {
yamlDesc := new(ratelimitserviceconfig.YamlDescriptor)
// Case for distinct match
if match.Distinct {
// RequestHeader case
yamlDesc.Key = getRateLimitDescriptorKey(descriptorPrefix, rIdx, mIdx)
} else {
// HeaderValueMatch case
yamlDesc.Key = getRateLimitDescriptorKey(descriptorPrefix, rIdx, mIdx)
yamlDesc.Value = getRateLimitDescriptorValue(descriptorPrefix, rIdx, mIdx)

}

// Add the ratelimit values to the last descriptor
if mIdx == len(rule.HeaderMatches)-1 {
rateLimit := ratelimitserviceconfig.YamlRateLimit{
RequestsPerUnit: rule.Limit.Requests,
Unit: string(rule.Limit.Unit),
}
yamlDesc.RateLimit = &rateLimit
}

if mIdx == 0 {
head = yamlDesc
} else {
cur.Descriptors = []ratelimitserviceconfig.YamlDescriptor{*yamlDesc}
}

cur = yamlDesc
}

yamlDescs = append(yamlDescs, *head)
}

return yamlDescs
}

func buildRateLimitServiceCluster(irListener *ir.HTTPListener) *cluster.Cluster {
// Return early if rate limits dont exist.
if !isRateLimitPresent(irListener) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: "first-listener"
address: "0.0.0.0"
port: 10080
hostnames:
- "*"
routes:
- name: "first-route"
rateLimit:
global:
rules:
- headerMatches:
- name: "x-user-id"
distinct: true
limit:
requests: 5
unit: second
pathMatch:
exact: "foo/bar"
destinations:
- host: "1.2.3.4"
port: 50000
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: "first-listener"
address: "0.0.0.0"
port: 10080
hostnames:
- "*"
routes:
- name: "first-route"
rateLimit:
global:
rules:
- limit:
requests: 5
unit: second
pathMatch:
exact: "foo/bar"
destinations:
- host: "1.2.3.4"
port: 50000
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: "first-listener"
address: "0.0.0.0"
port: 10080
hostnames:
- "*"
routes:
- name: "first-route"
rateLimit:
global:
rules:
- headerMatches:
- name: "x-user-id"
exact: "one"
- name: "x-user-id"
exact: "two"
limit:
requests: 5
unit: second
pathMatch:
exact: "foo/bar"
destinations:
- host: "1.2.3.4"
port: 50000
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: "first-listener"
address: "0.0.0.0"
port: 10080
hostnames:
- "*"
routes:
- name: "first-route"
rateLimit:
global:
rules:
- headerMatches:
- name: "x-user-id"
exact: "one"
limit:
requests: 5
unit: second
pathMatch:
exact: "foo/baz"
- name: "second-route"
rateLimit:
global:
rules:
- headerMatches:
- name: "x-user-id"
exact: "two"
limit:
requests: 10
unit: second
pathMatch:
exact: "foo/bar"
destinations:
- host: "1.2.3.4"
port: 50000
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: "first-listener"
address: "0.0.0.0"
port: 10080
hostnames:
- "*"
routes:
- name: "first-route"
rateLimit:
global:
rules:
- headerMatches:
- name: "x-user-id"
exact: "one"
limit:
requests: 5
unit: second
- headerMatches:
- name: "x-user-id"
exact: "two"
limit:
requests: 10
unit: second
pathMatch:
exact: "foo/bar"
destinations:
- host: "1.2.3.4"
port: 50000
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: "first-listener"
address: "0.0.0.0"
port: 10080
hostnames:
- "*"
routes:
- name: "first-route"
rateLimit:
global:
rules:
- headerMatches:
- name: "x-user-id"
exact: "one"
limit:
requests: 5
unit: second
pathMatch:
exact: "foo/bar"
destinations:
- host: "1.2.3.4"
port: 50000
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
domain: first-listener
descriptors:
- key: first-route-key-rule-0-match-0
value: ""
rate_limit:
requests_per_unit: 5
unit: second
unlimited: false
name: ""
replaces: []
descriptors: []
shadow_mode: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
domain: first-listener
descriptors:
- key: first-route-key-rule-0-match--1
value: first-route-value-rule-0-match--1
rate_limit:
requests_per_unit: 5
unit: second
unlimited: false
name: ""
replaces: []
descriptors: []
shadow_mode: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
domain: first-listener
descriptors:
- key: first-route-key-rule-0-match-0
value: first-route-value-rule-0-match-0
rate_limit: null
descriptors:
- key: first-route-key-rule-0-match-1
value: first-route-value-rule-0-match-1
rate_limit:
requests_per_unit: 5
unit: second
unlimited: false
name: ""
replaces: []
descriptors: []
shadow_mode: false
shadow_mode: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
domain: first-listener
descriptors:
- key: first-route-key-rule-0-match-0
value: first-route-value-rule-0-match-0
rate_limit:
requests_per_unit: 5
unit: second
unlimited: false
name: ""
replaces: []
descriptors: []
shadow_mode: false
- key: second-route-key-rule-0-match-0
value: second-route-value-rule-0-match-0
rate_limit:
requests_per_unit: 10
unit: second
unlimited: false
name: ""
replaces: []
descriptors: []
shadow_mode: false
Loading

0 comments on commit 27253bb

Please sign in to comment.