Skip to content
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

Design and Implementation of Filters #1

Closed
markmandel opened this issue Jan 28, 2020 · 5 comments · Fixed by #198
Closed

Design and Implementation of Filters #1

markmandel opened this issue Jan 28, 2020 · 5 comments · Fixed by #198
Assignees
Labels
area/user-experience Pertaining to developers trying to use Quilkin, e.g. cli interface, configuration, etc kind/feature New feature or request

Comments

@markmandel
Copy link
Contributor

Need to come up with a design for filters, and then implement it!

@markmandel markmandel added the kind/feature New feature or request label Jan 28, 2020
@markmandel markmandel added the area/user-experience Pertaining to developers trying to use Quilkin, e.g. cli interface, configuration, etc label Feb 19, 2020
@markmandel
Copy link
Contributor Author

Coming up with a filter configuration that works for both client and server configuration. This is what I came up with:

  1. Added a "filters" section, that sits above the client/server section. The idea being that filters should be passed information that makes them aware of if they are in client or server mode.
  2. Filters get passed a name. internally we should have some kind of registry of Filters that are a available (long term, if you used quilkin as a library, you could then add your own to the registry)
  3. Filters can also have an arbitrary config passed in as well (probably passed in as serde enum.Value, which controls how filters work.

For example:

client-proxy.yaml

local:
  port: 7000 # the port to receive traffic to locally
filters: # new filters section
  - name: "quilkin.core.v1.rate-limiter" # the name that this filter is registered under
    config:
      map: of arbitrary key value pairs
      could:
        - also
        - be
        - an
        - array
client:
  address: 127.0.0.1:7001 # the address to send traffic to
  connection_id: 1x7ijy6 # the connection string to attach to the traffic

server-proxy.yaml

local:
  port: 7001 # the port to receive traffic to locally
filters:
  - name: "quilkin.core.v1.rate-limiter" # the name that this filter is registered under
    config:
      map: of arbitrary key value pairs
      could: 42
server:
  endpoints: # array of potential endpoints to send on traffic to
    - name: Game Server No. 1
      address: 127.0.0.1:26000
      connection_ids:
        - 1x7ijy6 # connection ids to route on
        - 8gj3v2i
    - name: Game Server No. 2
      address: 127.0.0.1:26001
      connection_ids:
        - nkuy70x

How do we feel about a setup like this?

@luna-duclos
Copy link
Collaborator

I'd prefer it if the client could get as much config as possible from the server rather than having its own, does that make sense ? It avoids people modifying the client config file in a way we don't want them to, and also makes it easier for us to update.
As such, I'd like the client to know of exactly two things only: Its own ID, and the server to connect to.

@markmandel
Copy link
Contributor Author

So you raise an interesting idea @luna-duclos !

So in my mind, the yaml file is a useful data structure design tool / stopgap / during game development tool util we have a gRPC control API (#10) down the line -- which would let you configure everything we can see in the yaml file (which is basically how Envoy works - you have a static config, i.e. yaml and a dynamic config, i.e. via the API)

So in production, the client would likely make a gRPC connection to the proxy to configure it - meaning there is far less surface area for a user to manipulate (especially easily on the client side).

Then it would be the responsibility of the custom client/game system to receive and propagate out any configuration updates as required.

In my mind - Quilkin doesn't provide the control plane, but provides the foundation for a control plane (much like the difference between Envoy and Istio). We could then down the line have separate opinionated control plane implementations on top of Quilkin.

That all being said, we should think about how we can ensure the client side proxy is relatively tamper proof - or at least, if people DO tamper with it, it doesn't really affect anything. (maybe part we have a filter for quilkin that sends a hash of the current config, and the server receives the hash, and if it's changed, it refuses the connection???) - but this feels to me like a separate design ticket.

Also, depending on how we do the gRPC control plane API (which I think comes once we've locked down the design of some of the basic config data structures), what you propose might actually be possible -- depending on how you set it up. (i.e. should the control plane reach out to something? Should it be only accept connections? maybe both? but that's a discussion for #10)

That sound good?

@markmandel
Copy link
Contributor Author

Had an offline slack chat. We agreed that this is an appropriate data structure for filters at this stage.
Also agreed that concerns about client side safety will continue to be explored in #10

@markmandel markmandel self-assigned this Mar 5, 2020
markmandel added a commit that referenced this issue Apr 28, 2020
Not sure why I decided to have that function return a HashMap, but to
implement filters, we need access to the underlying Endpoints, since
they get passed into several Filter functions.

So refactored the function to return a Vec<Endpoint>, which will make
things much easier to work with.

Work on #1
markmandel added a commit that referenced this issue Apr 29, 2020
Not sure why I decided to have that function return a HashMap, but to
implement filters, we need access to the underlying Endpoints, since
they get passed into several Filter functions.

So refactored the function to return a Vec<Endpoint>, which will make
things much easier to work with.

Work on #1
markmandel added a commit that referenced this issue May 27, 2020
Since packets might not come back from the endpoint address that we
expect it to, we should track this data in our filter.

Now we can!

Work on #1
markmandel added a commit that referenced this issue May 27, 2020
Since packets might not come back from the endpoint address that we
expect it to, we should track this data in our filter.

Now we can!

Work on #1
markmandel added a commit that referenced this issue May 27, 2020
Since packets might not come back from the endpoint address that we
expect it to, we should track this data in our filter.

Now we can!

Work on #1
markmandel added a commit that referenced this issue May 31, 2020
FilterChain for local_receive_filter is in place, and working as
expected, with accompanying unit tests.

Found a small issue in Session as well that also got fixed in this PR
that came up in the unit tests.

Work on #1
markmandel added a commit that referenced this issue Jun 1, 2020
FilterChain for local_receive_filter is in place, and working as
expected, with accompanying unit tests.

Found a small issue in Session as well that also got fixed in this PR
that came up in the unit tests.

Work on #1
markmandel added a commit that referenced this issue Jun 1, 2020
FilterChain for local_receive_filter is in place, and working as
expected, with accompanying unit tests.

Found a small issue in Session as well that also got fixed in this PR
that came up in the unit tests.

Work on #1
markmandel added a commit that referenced this issue Jun 2, 2020
Implementation plus unit tests!

Work on #1
markmandel added a commit that referenced this issue Jun 4, 2020
* Implementation of local_send_filter

Implementation plus unit tests!

Work on #1
markmandel added a commit that referenced this issue Jun 8, 2020
This includes passing the FilterChain into the Session, so that is can
call endpoint_send_filter when sending data out through the endpoint.

Work on #1
markmandel added a commit that referenced this issue Jun 15, 2020
* Implementation of endpoint_send_filter

This includes passing the FilterChain into the Session, so that is can
call endpoint_send_filter when sending data out through the endpoint.

Work on #1
markmandel added a commit that referenced this issue Jun 16, 2020
This includes a unit test to cover the full set of filters.
Next step - more integration tests!

Work on #1
markmandel added a commit that referenced this issue Jun 16, 2020
Next step - more integration tests!

Work on #1
markmandel added a commit that referenced this issue Jun 16, 2020
Better testing, now we have more filters implemented.

Work on #1
markmandel added a commit that referenced this issue Jun 16, 2020
Next step - more integration tests!

Work on #1
markmandel added a commit that referenced this issue Jun 22, 2020
Better testing, now we have more filters implemented.

Work on #1
@markmandel
Copy link
Contributor Author

From conversation today, we need to look at the filter ordering is reversed appropriately between sending and recieving, so that filters run in the correct order.

For example, we may need to flip ordering around here on endpoint receive:
https://github.com/googleforgames/quilkin/blob/master/src/extensions/filter_chain.rs#L97-L107

markmandel added a commit that referenced this issue Jun 30, 2020
End to end test of the TestFilter implementation, proving an integration
test for the full Filter trait experience.

Work on #1
markmandel added a commit that referenced this issue Jul 6, 2020
End to end test of the TestFilter implementation, proving an integration
test for the full Filter trait experience.

Work on #1
markmandel added a commit that referenced this issue Jul 11, 2020
This PR implements lazy instantiation of filters through a closure -
which also leads to the ability to pass the server_yaml::Value for the
config of the filter, which was a nice side effect.

To prove the lazy eval and config passing was working, this also added
the ability to pass an "id" value to the DebugFilter, such that you
could implement several of them in a Filter configuration in between
other filters, and be able to identify which log statement is which
step.

This also led to finding multiple places in which an Arc was being used,
but only the guarantees of a Box where actually needed, so this was also
switched out.

An integration test for the DebugFilter is still incoming.

Work on #1
markmandel added a commit that referenced this issue Jul 11, 2020
This PR implements lazy instantiation of filters through a closure -
which also leads to the ability to pass the server_yaml::Value for the
config of the filter, which was a nice side effect.

To prove the lazy eval and config passing was working, this also added
the ability to pass an "id" value to the DebugFilter, such that you
could implement several of them in a Filter configuration in between
other filters, and be able to identify which log statement is which
step.

This also led to finding multiple places in which an Arc was being used,
but only the guarantees of a Box where actually needed, so this was also
switched out.

An integration test for the DebugFilter is still incoming.

Work on #1
markmandel added a commit that referenced this issue Jul 17, 2020
This PR implements lazy instantiation of filters through a closure -
which also leads to the ability to pass the server_yaml::Value for the
config of the filter, which was a nice side effect.

To prove the lazy eval and config passing was working, this also added
the ability to pass an "id" value to the DebugFilter, such that you
could implement several of them in a Filter configuration in between
other filters, and be able to identify which log statement is which
step.

This also led to finding multiple places in which an Arc was being used,
but only the guarantees of a Box where actually needed, so this was also
switched out.

An integration test for the DebugFilter is still incoming.

Work on #1
markmandel added a commit that referenced this issue Jul 28, 2020
This PR implements lazy instantiation of filters through a closure -
which also leads to the ability to pass the server_yaml::Value for the
config of the filter, which was a nice side effect.

To prove the lazy eval and config passing was working, this also added
the ability to pass an "id" value to the DebugFilter, such that you
could implement several of them in a Filter configuration in between
other filters, and be able to identify which log statement is which
step.

This also led to finding multiple places in which an Arc was being used,
but only the guarantees of a Box where actually needed, so this was also
switched out.

An integration test for the DebugFilter is still incoming.

Work on #1
markmandel added a commit that referenced this issue Jul 29, 2020
* Lazy instantiation of Filters

This PR implements lazy instantiation of filters through a closure -
which also leads to the ability to pass the server_yaml::Value for the
config of the filter, which was a nice side effect.

To prove the lazy eval and config passing was working, this also added
the ability to pass an "id" value to the DebugFilter, such that you
could implement several of them in a Filter configuration in between
other filters, and be able to identify which log statement is which
step.

This also led to finding multiple places in which an Arc was being used,
but only the guarantees of a Box where actually needed, so this was also
switched out.

An integration test for the DebugFilter is still incoming.

Work on #1

* FilterProvider implementation.
* Switch to FilterProvider being instantiatable.
* Implement from_config() returning Result
* Move log into Provider.
* Refactor Provider -> Factory
markmandel added a commit that referenced this issue Jul 30, 2020
markmandel added a commit that referenced this issue Aug 4, 2020
markmandel added a commit that referenced this issue Aug 26, 2020
Some filters will need to be aware of whether they are client/server,
and also authentication connection details.

To provide this functionality, this PR added ConnectionConfig to the
CreateFilterArgs, so it can be passed into FilterFactory's when needed.

Work on #1
markmandel added a commit that referenced this issue Aug 28, 2020
* Added ConnectionConfig to CreateFilterArgs

Some filters will need to be aware of whether they are client/server,
and also authentication connection details.

To provide this functionality, this PR added ConnectionConfig to the
CreateFilterArgs, so it can be passed into FilterFactory's when needed.

Work on #1

* Updates based on review.
markmandel added a commit that referenced this issue Feb 24, 2021
This implements that the FilterChain executes the set of Filters in a
forward order on read, and then in reverse order on write.

Also provides an integration test to confirm that the ordering is
working as expected.

Closes #1
markmandel added a commit that referenced this issue Feb 24, 2021
This implements that the FilterChain executes the set of Filters in a
forward order on read, and then in reverse order on write.

Also provides an integration test to confirm that the ordering is
working as expected.

Closes #1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/user-experience Pertaining to developers trying to use Quilkin, e.g. cli interface, configuration, etc kind/feature New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants