Skip to content

Commit

Permalink
feat: add RateLimitPolicy CRD (#78)
Browse files Browse the repository at this point in the history
* feat: [skip ci] add RateLimitPolicy CRD

Signed-off-by: Lin Yang <[email protected]>

* feat: [skip ci] add comments

Signed-off-by: Lin Yang <[email protected]>

* fix: json maker

Signed-off-by: Lin Yang <[email protected]>

* wip: [skip ci] RateLimitPolicy

Signed-off-by: Lin Yang <[email protected]>

* chore: initialize version v1.2.0-alpha.1

Signed-off-by: Lin Yang <[email protected]>

* wip: [skip ci]

Signed-off-by: Lin Yang <[email protected]>

* feat: build config.json and enrich RateLimitPolicy

Signed-off-by: Lin Yang <[email protected]>

* fix: golang lint

Signed-off-by: Lin Yang <[email protected]>

* feat: detect conflicts

Signed-off-by: Lin Yang <[email protected]>

* feat: sort rate limits by timestamp

Signed-off-by: Lin Yang <[email protected]>

* fix: golang lint

Signed-off-by: Lin Yang <[email protected]>

* fix: ratelimitpolicies RBAC

Signed-off-by: Lin Yang <[email protected]>

* fix: ratelimitpolicies events

Signed-off-by: Lin Yang <[email protected]>

* fix: register ratelimitpolicies reconciler

Signed-off-by: Lin Yang <[email protected]>

* feat: enable the ratelimit policy matches multiple routes

Signed-off-by: Lin Yang <[email protected]>

* feat: enable the ratelimit policy matches multiple gateway ports

Signed-off-by: Lin Yang <[email protected]>

* feat: add feature flags to enable/disable validating hostnames of GatewayAPI resources (#83)

* feat: bump fgw scripts and config chains (#85)

Signed-off-by: Lin Yang <[email protected]>

* wip: [skip ci] refactoring RateLimitPolicy

Signed-off-by: Lin Yang <[email protected]>

* cloud connector with gateway api (#86)

* cloud connector with gateway api.

* cloud connector with gateway api.

* feat: new FGW options to control per-request/per-connection load balancing (#87)

Signed-off-by: Lin Yang <[email protected]>

* fix: package-scripts

Signed-off-by: Lin Yang <[email protected]>

* wip: [skip ci]

Signed-off-by: Lin Yang <[email protected]>

* feat: add more options to configure FGW (#89)

* feat: add more options to configure FGW

Signed-off-by: Lin Yang <[email protected]>

* fix: make chart-readme

Signed-off-by: Lin Yang <[email protected]>

---------

Signed-off-by: Lin Yang <[email protected]>

* fix: code checks [skip ci]

Signed-off-by: Lin Yang <[email protected]>

* docs: add testcases for RateLimitPolicy

Signed-off-by: Lin Yang <[email protected]>

* fix: register policy attachment scheme

Signed-off-by: Lin Yang <[email protected]>

---------

Signed-off-by: Lin Yang <[email protected]>
Co-authored-by: Cybwan <[email protected]>
  • Loading branch information
reaver-flomesh and cybwan authored Oct 30, 2023
1 parent 4c05d89 commit 171ea46
Show file tree
Hide file tree
Showing 58 changed files with 4,273 additions and 55 deletions.
11 changes: 11 additions & 0 deletions charts/fsm/templates/fsm-rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,17 @@ rules:
resources: [ "gatewayclasses/status", "gateways/status", "httproutes/status", "grpcroutes/status", "referencegrants/status", "tcproutes/status", "tlsroutes/status", "udproutes/status" ]
verbs: [ "get", "patch", "update" ]

# PolicyAttachment
- apiGroups: [ "gateway.flomesh.io" ]
resources: [ "ratelimitpolicies" ]
verbs: [ "get", "list", "watch", "create", "update", "patch", "delete" ]
- apiGroups: [ "gateway.flomesh.io" ]
resources: [ "ratelimitpolicies/finalizers" ]
verbs: [ "update" ]
- apiGroups: [ "gateway.flomesh.io" ]
resources: [ "ratelimitpolicies/status"]
verbs: [ "get", "patch", "update" ]

# Used for interacting with cert-manager CertificateRequest resources.
- apiGroups: ["cert-manager.io"]
resources: ["certificaterequests"]
Expand Down
652 changes: 652 additions & 0 deletions cmd/fsm-bootstrap/crds/gateway.flomesh.io_ratelimitpolicies.yaml

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions cmd/fsm-controller/fsm-controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"strings"
"time"

policyAttachmentClientset "github.com/flomesh-io/fsm/pkg/gen/client/policyattachment/clientset/versioned"

ctrl "sigs.k8s.io/controller-runtime"

fctx "github.com/flomesh-io/fsm/pkg/context"
Expand All @@ -38,6 +40,7 @@ import (

mcscheme "github.com/flomesh-io/fsm/pkg/gen/client/multicluster/clientset/versioned/scheme"
nsigscheme "github.com/flomesh-io/fsm/pkg/gen/client/namespacedingress/clientset/versioned/scheme"
pascheme "github.com/flomesh-io/fsm/pkg/gen/client/policyattachment/clientset/versioned/scheme"

"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/runtime"
Expand Down Expand Up @@ -162,6 +165,7 @@ func init() {
_ = gwscheme.AddToScheme(scheme)
_ = mcscheme.AddToScheme(scheme)
_ = nsigscheme.AddToScheme(scheme)
_ = pascheme.AddToScheme(scheme)
}

// TODO(#4502): This function can be deleted once we get rid of cert options.
Expand Down Expand Up @@ -239,6 +243,7 @@ func main() {
smiTrafficTargetClientSet := smiAccessClient.NewForConfigOrDie(kubeConfig)
gatewayAPIClient := gatewayApiClientset.NewForConfigOrDie(kubeConfig)
namespacedIngressClient := nsigClientset.NewForConfigOrDie(kubeConfig)
policyAttachmentClient := policyAttachmentClientset.NewForConfigOrDie(kubeConfig)

informerCollection, err := informers.NewInformerCollection(meshName, stop,
informers.WithKubeClient(kubeClient),
Expand All @@ -250,6 +255,7 @@ func main() {
informers.WithNetworkingClient(networkingClient),
informers.WithIngressClient(kubeClient, namespacedIngressClient),
informers.WithGatewayAPIClient(gatewayAPIClient),
informers.WithPolicyAttachmentClient(policyAttachmentClient),
)
if err != nil {
events.GenericEventRecorder().FatalEvent(err, events.InitializationError, "Error creating informer collection")
Expand Down
5 changes: 4 additions & 1 deletion codegen/gen-crd-client.sh
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,7 @@ echo "##### Generating flomesh.io plugin client ######"
generate_client "plugin" "v1alpha1"

echo "##### Generating flomesh.io NamespacedIngress client ######"
generate_client "namespacedingress" "v1alpha1"
generate_client "namespacedingress" "v1alpha1"

echo "##### Generating gateway.flomesh.io PolicyAttachment client ######"
generate_client "policyattachment" "v1alpha1"
71 changes: 71 additions & 0 deletions docs/tests/gateway-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -749,4 +749,75 @@ date: Thu, 06 Jul 2023 04:44:06 GMT
<h2>Object moved to <a href="https://www.bing.com:443/?toWww=1&amp;redig=CA7F9D7F0A6C47FFAFA16A6589BCBB8F">here</a>.</h2>
</body></html>
* Connection #0 to host bing.com left intact
```
### Test RateLimitPolicy
#### Test Port Based Rate Limit
```shell
cat <<EOF | kubectl apply -f -
apiVersion: gateway.flomesh.io/v1alpha1
kind: RateLimitPolicy
metadata:
name: ratelimit-port
spec:
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: test-gw-1
namespace: default
ports:
- port: 80
bps: 100000
EOF
```
#### Test Hostname Based Rate Limit
```shell
cat <<EOF | kubectl apply -f -
apiVersion: gateway.flomesh.io/v1alpha1
kind: RateLimitPolicy
metadata:
name: ratelimit-hostname-http
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: http-app-1
namespace: httpbin
hostnames:
- hostname: httptest.localhost
rateLimit:
mode: Local
backlog: 15
requests: 100
statTimeWindow: 60
EOF
```
#### Test Route Based Rate Limit
```shell
cat <<EOF | kubectl apply -f -
apiVersion: gateway.flomesh.io/v1alpha1
kind: RateLimitPolicy
metadata:
name: ratelimit-route-http
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: http-app-1
namespace: httpbin
http:
- match:
path:
type: PathPrefix
value: /bar
rateLimit:
mode: Local
backlog: 15
requests: 100
statTimeWindow: 60
EOF
```
11 changes: 11 additions & 0 deletions pkg/announcements/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,17 @@ const (

// GatewayAPITCPRouteUpdated is the type of announcement emitted when we observe an update to tcproutes.gateway.networking.k8s.io
GatewayAPITCPRouteUpdated Kind = "gwapi-tcproute-updated"

// ---

// RateLimitPolicyAdded is the type of announcement emitted when we observe an addition of ratelimitpolicies.gateway.flomesh.io
RateLimitPolicyAdded Kind = "ratelimitpolicy-added"

// RateLimitPolicyDeleted the type of announcement emitted when we observe a deletion of ratelimitpolicies.gateway.flomesh.io
RateLimitPolicyDeleted Kind = "ratelimitpolicy-deleted"

// RateLimitPolicyUpdated is the type of announcement emitted when we observe an update to ratelimitpolicies.gateway.flomesh.io
RateLimitPolicyUpdated Kind = "ratelimitpolicy-updated"
)

// Announcement is a struct for messages between various components of FSM signaling a need for a change in Sidecar proxy configuration
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/policyattachment/v1alpha1/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// +k8s:deepcopy-gen=package,register
// +groupName=gateway.flomesh.io

// Package v1alpha1 is the v1alpha3 version of the API.
package v1alpha1
149 changes: 149 additions & 0 deletions pkg/apis/policyattachment/v1alpha1/ratelimit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package v1alpha1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
)

type RateLimitPolicyMode string

const (
// RateLimitPolicyModeLocal is the local mode
RateLimitPolicyModeLocal RateLimitPolicyMode = "Local"

// RateLimitPolicyModeGlobal is the global mode
RateLimitPolicyModeGlobal RateLimitPolicyMode = "Global"
)

// RateLimitPolicySpec defines the desired state of RateLimitPolicy
type RateLimitPolicySpec struct {
// TargetRef is the reference to the target resource to which the policy is applied
TargetRef gwv1alpha2.PolicyTargetReference `json:"targetRef"`

// +optional
// Ports is the rate limit configuration for ports
Ports []PortRateLimit `json:"ports,omitempty"`

// +optional
// DefaultBPS is the default rate limit for all ports
DefaultBPS *int64 `json:"bps,omitempty"`

// +optional
// Hostnames is the rate limit configuration for hostnames
Hostnames []HostnameRateLimit `json:"hostnames,omitempty"`

// +optional
// HTTPRateLimits is the rate limit configuration for HTTP routes
HTTPRateLimits []HTTPRateLimit `json:"http,omitempty"`

// +optional
// GRPCRateLimits is the rate limit configuration for GRPC routes
GRPCRateLimits []GRPCRateLimit `json:"grpc,omitempty"`

// +optional
// DefaultRateLimit is the default rate limit for all routes and hostnames
DefaultL7RateLimit *L7RateLimit `json:"rateLimit,omitempty"`
}

// PortRateLimit defines the rate limit configuration for a port
type PortRateLimit struct {
Port gwv1beta1.PortNumber `json:"port"`
BPS *int64 `json:"bps,omitempty"`
}

// HostnameRateLimit defines the rate limit configuration for a hostname
type HostnameRateLimit struct {
Hostname gwv1beta1.Hostname `json:"hostname"`
RateLimit *L7RateLimit `json:"rateLimit,omitempty"`
}

// RouteRateLimitConfig defines the rate limit configuration for routes
type RouteRateLimitConfig struct {
HttpRateLimits []HTTPRateLimit `json:"http,omitempty"`
GrpcRateLimits []GRPCRateLimit `json:"grpc,omitempty"`
DefaultRateLimit *L7RateLimit `json:"rateLimit,omitempty"`
}

// HTTPRateLimit defines the rate limit configuration for a HTTP route
type HTTPRateLimit struct {
Match gwv1beta1.HTTPRouteMatch `json:"match"`
RateLimit *L7RateLimit `json:"rateLimit,omitempty"`
}

// GRPCRateLimit defines the rate limit configuration for a GRPC route
type GRPCRateLimit struct {
Match gwv1alpha2.GRPCRouteMatch `json:"match"`
RateLimit *L7RateLimit `json:"rateLimit,omitempty"`
}

// L7RateLimit defines the rate limit configuration for a route
type L7RateLimit struct {
// +optional
// +kubebuilder:default=Local
// +kubebuilder:validation:Enum=Local;Global
// Mode is the mode of the rate limit policy, Local or Global, default is Local
Mode *RateLimitPolicyMode `json:"mode"`

// +optional
// +kubebuilder:default=10
// Backlog is the number of requests allowed to wait in the queue
Backlog *int `json:"backlog,omitempty"`

// Requests is the number of requests allowed per statTimeWindow
Requests int `json:"requests"`

// Burst is the number of requests allowed to be bursted, if not specified, it will be the same as Requests
// +optional
Burst *int `json:"burst,omitempty"`

// StatTimeWindow is the time window in seconds
StatTimeWindow int `json:"statTimeWindow"`

// ResponseStatusCode is the response status code to be returned when the rate limit is exceeded
// +optional
// +kubebuilder:default=429
ResponseStatusCode *int `json:"responseStatusCode"`

// +optional
// ResponseHeadersToAdd is the response headers to be added when the rate limit is exceeded
ResponseHeadersToAdd map[string]string `json:"responseHeadersToAdd,omitempty"`
}

// RateLimitPolicyStatus defines the observed state of RateLimitPolicy
type RateLimitPolicyStatus struct {
// Conditions describe the current conditions of the RateLimitPolicy.
//
// +optional
// +listType=map
// +listMapKey=type
// +kubebuilder:validation:MaxItems=8
Conditions []metav1.Condition `json:"conditions,omitempty"`
}

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:openapi-gen=true
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:scope=Namespaced
// +kubebuilder:metadata:labels=app.kubernetes.io/name=flomesh.io

// RateLimitPolicy is the Schema for the RateLimitPolicys API
type RateLimitPolicy struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec RateLimitPolicySpec `json:"spec,omitempty"`
Status RateLimitPolicyStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// RateLimitPolicyList contains a list of RateLimitPolicy
type RateLimitPolicyList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []RateLimitPolicy `json:"items"`
}
49 changes: 49 additions & 0 deletions pkg/apis/policyattachment/v1alpha1/register.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// +k8s:deepcopy-gen=package,register
// +groupName=gateway.flomesh.io

// Package v1alpha1 contains API Schema definitions for the gateway.flomesh.io v1alpha1 API group
package v1alpha1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)

var (
// SchemeGroupVersion is group version used to register MeshConfig
SchemeGroupVersion = schema.GroupVersion{
Group: "gateway.flomesh.io",
Version: "v1alpha1",
}

// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)

// AddToScheme adds all Resources to the Scheme
AddToScheme = SchemeBuilder.AddToScheme
)

// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}

// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}

// Adds the list of known types to Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&RateLimitPolicy{},
&RateLimitPolicyList{},
)

metav1.AddToGroupVersion(
scheme,
SchemeGroupVersion,
)
return nil
}
Loading

0 comments on commit 171ea46

Please sign in to comment.