mirror of
https://github.com/status-im/consul.git
synced 2025-02-04 18:03:39 +00:00
e027c94b52
* server: add placeholder glue for rate limit handler This commit adds a no-op implementation of the rate-limit handler and adds it to the `consul.Server` struct and setup code. This allows us to start working on the net/rpc and gRPC interceptors and config logic. * Add handler errors * Set the global read and write limits * fixing multilimiter moving packages * Fix typo * Simplify globalLimit usage * add multilimiter and tests * exporting LimitedEntity * Apply suggestions from code review Co-authored-by: John Murret <john.murret@hashicorp.com> * add config update and rename config params * add doc string and split config * Apply suggestions from code review Co-authored-by: Dan Upton <daniel@floppy.co> * use timer to avoid go routine leak and change the interface * add comments to tests * fix failing test * add prefix with config edge, refactor tests * Apply suggestions from code review Co-authored-by: Dan Upton <daniel@floppy.co> * refactor to apply configs for limiters under a prefix * add fuzz tests and fix bugs found. Refactor reconcile loop to have a simpler logic * make KeyType an exported type * split the config and limiter trees to fix race conditions in config update * rename variables * fix race in test and remove dead code * fix reconcile loop to not create a timer on each loop * add extra benchmark tests and fix tests * fix benchmark test to pass value to func * server: add placeholder glue for rate limit handler This commit adds a no-op implementation of the rate-limit handler and adds it to the `consul.Server` struct and setup code. This allows us to start working on the net/rpc and gRPC interceptors and config logic. * Set the global read and write limits * fixing multilimiter moving packages * add server configuration for global rate limiting. * remove agent test * remove added stuff from handler * remove added stuff from multilimiter * removing unnecessary TODOs * Removing TODO comment from handler * adding in defaulting to infinite * add disabled status in there * adding in documentation for disabled mode. * make disabled the default. * Add mock and agent test * addig documentation and missing mock file. * Fixing test TestLoad_IntegrationWithFlags * updating docs based on PR feedback. * Updating Request Limits mode to use int based on PR feedback. * Adding RequestLimits struct so we have a nested struct in ReloadableConfig. * fixing linting references * Update agent/consul/rate/handler.go Co-authored-by: Dan Upton <daniel@floppy.co> * Update agent/consul/config.go Co-authored-by: Dan Upton <daniel@floppy.co> * removing the ignore of the request limits in JSON. addingbuilder logic to convert any read rate or write rate less than 0 to rate.Inf * added conversion function to convert request limits object to handler config. * Updating docs to reflect gRPC and RPC are rate limit and as a result, HTTP requests are as well. * Updating values for TestLoad_FullConfig() so that they were different and discernable. * Updating TestRuntimeConfig_Sanitize * Fixing TestLoad_IntegrationWithFlags test * putting nil check in place * fixing rebase * removing change for missing error checks. will put in another PR * Rebasing after default multilimiter config change * resolving rebase issues * updating reference for incomingRPCLimiter to use interface * updating interface * Updating interfaces * Fixing mock reference Co-authored-by: Daniel Upton <daniel@floppy.co> Co-authored-by: Dhia Ayachi <dhia@hashicorp.com>
59 lines
1.7 KiB
Go
59 lines
1.7 KiB
Go
package middleware
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/peer"
|
|
"google.golang.org/grpc/status"
|
|
"google.golang.org/grpc/tap"
|
|
|
|
recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
|
|
|
|
"github.com/hashicorp/consul/agent/consul/rate"
|
|
)
|
|
|
|
// ServerRateLimiterMiddleware implements a ServerInHandle function to perform
|
|
// RPC rate limiting at the cheapest possible point (before the full request has
|
|
// been decoded).
|
|
func ServerRateLimiterMiddleware(limiter rate.RequestLimitsHandler, panicHandler recovery.RecoveryHandlerFunc) tap.ServerInHandle {
|
|
return func(ctx context.Context, info *tap.Info) (_ context.Context, retErr error) {
|
|
// This function is called before unary and stream RPC interceptors, so we
|
|
// must handle our own panics here.
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
retErr = panicHandler(r)
|
|
}
|
|
}()
|
|
|
|
// Do not rate-limit the xDS service, it handles its own limiting.
|
|
if info.FullMethodName == "/envoy.service.discovery.v3.AggregatedDiscoveryService/DeltaAggregatedResources" {
|
|
return ctx, nil
|
|
}
|
|
|
|
peer, ok := peer.FromContext(ctx)
|
|
if !ok {
|
|
// This should never happen!
|
|
return ctx, status.Error(codes.Internal, "gRPC rate limit middleware unable to read peer")
|
|
}
|
|
|
|
err := limiter.Allow(rate.Operation{
|
|
Name: info.FullMethodName,
|
|
SourceAddr: peer.Addr,
|
|
// TODO: operation type.
|
|
})
|
|
|
|
switch {
|
|
case err == nil:
|
|
return ctx, nil
|
|
case errors.Is(err, rate.ErrRetryElsewhere):
|
|
return ctx, status.Error(codes.ResourceExhausted, err.Error())
|
|
case errors.Is(err, rate.ErrRetryLater):
|
|
return ctx, status.Error(codes.Unavailable, err.Error())
|
|
default:
|
|
return ctx, status.Error(codes.Internal, err.Error())
|
|
}
|
|
}
|
|
}
|