-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🔥 conditions et at, replacing with proper cel::Predicate
s & ::Expression
s
#396
Conversation
787bf96
to
9edeb4e
Compare
limitador/src/limit/cel.rs
Outdated
} | ||
|
||
impl Context<'_> { | ||
pub(crate) fn new(limit: &Limit, root: String, values: &HashMap<String, String>) -> Self { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, this root
relates to this point from #385
Should the descriptor(s) and their entries be first class citizens and have their own root binding?
Right now, limit
binds the limit info (id
& name
), I was thinking that possibly we could have some root binding for the descriptor entries (e.g. descriptor
), which... could then also be a List
and hold multiple of them and all their entries: descriptor[0].foo == '1' && descriptor[1].bar != 'bad'
... See this issue here, so it'd probably be a List<HashMap<String, String>>
as well then...
Whatever the case, who would set that root
namespace/binding to something? I'd expect it to be the server code... but that then creates further issues in the (de)serialization paths... Also, the logic of resolving the Limit.variables()
would need to account for that (along side what happens in the wasm-shim's code to lazily resolve attributes from the host).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, doing so would tie releasing this with a release of the kuadrant-operator... right now, this isn't necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So... thinking about this a little more, and given this comment, here's how I'm proposing to go about this:
- Have a blanket
From<&HashMap<String, String>
forContext
... which would not add the binding forlimit
. - Change
Limit::applies
&::resolve_variables
to take a&Context
instead of creating it explicitly -
Have the(Async)RateLimiter::counters_that_apply
also take the&Context
-
Have the(Async)RateLimiter
APIs expose theContext
, instead of&HashMap<String, String>
- Specialize the
Context
on resolvingPredicates
only, so the derivedcel_interpreter::Context::Child
contains the&limit
data - Expose some API around
Context
to set theroot
(s) - Have the
(Async)RateLimiter::counters_that_apply
also take the&Context
- Have the
(Async)RateLimiter
APIs expose theContext
, instead of&HashMap<String, String>
- Wire in the server code
That way, the server code can decide how it wires the RateLimitDescriptor
s and their .entries
from envoy's protocol for external rate limiting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have the (Async)RateLimiter::counters_that_apply also take the &Context
Have the (Async)RateLimiter APIs expose the Context, instead of &HashMap<String, String>
duh! this obviously doesn't work 🤦 Or at least not while injecting the Limit
this operates on.
Pretty big PR, but I tried to keep a somewhat meaningful history and broke it down according to the #385 |
@@ -333,6 +334,15 @@ fn encode_counter_to_key(counter: &Counter) -> Vec<u8> { | |||
} | |||
|
|||
fn encode_limit_to_key(limit: &Limit) -> Vec<u8> { | |||
let counter = Counter::new(limit.clone(), HashMap::default()); | |||
// fixme this is broken! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has always been broken... and will need revisiting! But we can't just fake a the variables values like this (and they were simply left empty before, but this won't work now, as they'd fail resolution. I could "just" use the new Counter::resolved_vars
, but that would just hide the problem a little more again.
limitador/src/counter.rs
Outdated
let var = "timestamp(ts).getHours()"; | ||
let limit = Limit::new( | ||
"", | ||
10, | ||
60, | ||
Vec::default(), | ||
[var.try_into().expect("failed parsing!")], | ||
); | ||
let counter = Counter::new( | ||
limit, | ||
HashMap::from([("ts".to_string(), "2019-10-12T13:20:50.52Z".to_string())]), | ||
) | ||
.expect("failed creating counter"); | ||
assert_eq!( | ||
counter.set_variables.get(var), | ||
Some("13".to_string()).as_ref() | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I guess this is now new...
4e2db75
to
b318247
Compare
Signed-off-by: Alex Snaps <[email protected]>
Signed-off-by: Alex Snaps <[email protected]>
Signed-off-by: Alex Snaps <[email protected]>
Signed-off-by: Alex Snaps <[email protected]>
Signed-off-by: Alex Snaps <[email protected]>
Signed-off-by: Alex Snaps <[email protected]>
Signed-off-by: Alex Snaps <[email protected]>
Signed-off-by: Alex Snaps <[email protected]>
Signed-off-by: Alex Snaps <[email protected]>
Signed-off-by: Alex Snaps <[email protected]>
Signed-off-by: Alex Snaps <[email protected]>
Signed-off-by: Alex Snaps <[email protected]>
Signed-off-by: Alex Snaps <[email protected]>
b318247
to
7c33b77
Compare
As per this, starting to address these issues |
Signed-off-by: Alex Snaps <[email protected]>
4716e30
to
b816ec3
Compare
Signed-off-by: Alex Snaps <[email protected]>
Signed-off-by: Alex Snaps <[email protected]>
Signed-off-by: Alex Snaps <[email protected]>
Signed-off-by: Alex Snaps <[email protected]>
Signed-off-by: Alex Snaps <[email protected]>
This now fixes #62 as well |
103eddf
to
2dde346
Compare
Signed-off-by: Alex Snaps <[email protected]>
2dde346
to
8941898
Compare
- "descriptors[0]['req.method'] == 'GET'" | ||
- "descriptors[0]['req.path'] == '/json'" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is now a breaking change obviously...
We could tell the server to not do that tho. But this is the only way I can think of to support multiple RateLimitDescriptor
coming in from envoy, as well as the fact that each of their entries are String, String
... i.e. any valid utf-8 string, which for the key
has to be exposed as a Map<String, _>
somehow.
For Kuadrant tho, we can now use the limit.id == '3f5e80af-1056-4349-bb84-c8010f34ecbb'
if we'd wanted (and wire the id
field of the Limit
itself in the config)... eventually this semantic could then be optimized for
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After our discussion the other day and time to go through it, the changes look sound to me, so I'm happy to approve to unblock
Can we tell that this is a breaking change? Just to confirm the |
Is there any plan to have some documentation here or somewhere else? So, whenever I want to write some limitador configuration, what context do I have available in CEL expressions? How do I make reference to descriptor entries to write predicates? |
After merging this, is it correct to say that Kuadrant's RatelimitPolicies are broken on HEAD of |
fix #385