From 4e5913dbd60b608748841701332c284c5e750b73 Mon Sep 17 00:00:00 2001 From: Aapo Talvensaari Date: Mon, 6 Nov 2023 13:06:08 +0200 Subject: [PATCH 1/2] docs(plugins): add docs about `plugin:configure` handler ### Summary In Kong 3.5 we added `plugin:configure` as an additional handler that is called each time there is a change in Kong plugin iterator. This commit adds documentation for it. Signed-off-by: Aapo Talvensaari --- .../plugin-development/custom-logic.md | 57 ++++++++++++------- .../plugin-development/entities-cache.md | 5 ++ 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/app/_src/gateway/plugin-development/custom-logic.md b/app/_src/gateway/plugin-development/custom-logic.md index d1a9b3798b73..c1f711836f85 100644 --- a/app/_src/gateway/plugin-development/custom-logic.md +++ b/app/_src/gateway/plugin-development/custom-logic.md @@ -16,7 +16,9 @@ more functions with predetermined names. Those functions will be invoked by {{site.base_gateway}} at different phases when it processes traffic. The first parameter they take is always `self`. All functions except `init_worker` -can receive a second parameter which is a table with the plugin configuration. +and `configure`can receive a second parameter which is a table with the plugin +configuration. The `configure` receives an array of all configurations for the +specific plugin. ## Module @@ -32,20 +34,21 @@ of {{site.base_gateway}}'s execution life-cycle: - **[HTTP Module]** *is used for plugins written for HTTP/HTTPS requests* -| Function name | Phase | Request Protocol | Description -|---------------------|-------------------|-------------------------|------------ -| `init_worker` | [init_worker] | * | Executed upon every Nginx worker process's startup. -| `certificate` | [ssl_certificate] | `https`, `grpcs`, `wss` | Executed during the SSL certificate serving phase of the SSL handshake. -| `rewrite` | [rewrite] | * | Executed for every request upon its reception from a client as a rewrite phase handler.
In this phase, neither the `Service` nor the `Consumer` have been identified, hence this handler will only be executed if the plugin was configured as a global plugin. -| `access` | [access] | `http(s)`, `grpc(s)`, `ws(s)` | Executed for every request from a client and before it is being proxied to the upstream service. -| `ws_handshake` | [access] | `ws(s)` | Executed for every request to a WebSocket service just before completing the WebSocket handshake. -| `response` | [access] | `http(s)`, `grpc(s)` | Replaces both `header_filter()` and `body_filter()`. Executed after the whole response has been received from the upstream service, but before sending any part of it to the client. -| `header_filter` | [header_filter] | `http(s)`, `grpc(s)` | Executed when all response headers bytes have been received from the upstream service. -| `ws_client_frame` | [content] | `ws(s)` | Executed for each WebSocket message received from the client. -| `ws_upstream_frame` | [content] | `ws(s)` | Executed for each WebSocket message received from the upstream service. -| `body_filter` | [body_filter] | `http(s)`, `grpc(s)` | Executed for each chunk of the response body received from the upstream service. Since the response is streamed back to the client, it can exceed the buffer size and be streamed chunk by chunk. This function can be called multiple times if the response is large. See the [lua-nginx-module] documentation for more details. -| `log` | [log] | `http(s)`, `grpc(s)` | Executed when the last response byte has been sent to the client. -| `ws_close` | [log] | `ws(s)` | Executed after the WebSocket connection has been terminated. +| Function name | Phase | Request Protocol | Description +|---------------------|---------------------|-------------------------------|------------ +| `init_worker` | [init_worker] | * | Executed upon every Nginx worker process's startup. +| `configure` | [init_worker/timer] | * | Executed everytime Kong plugin iterator is rebuild (aka after changes to configure plugins) +| `certificate` | [ssl_certificate] | `https`, `grpcs`, `wss` | Executed during the SSL certificate serving phase of the SSL handshake. +| `rewrite` | [rewrite] | * | Executed for every request upon its reception from a client as a rewrite phase handler.
In this phase, neither the `Service` nor the `Consumer` have been identified, hence this handler will only be executed if the plugin was configured as a global plugin. +| `access` | [access] | `http(s)`, `grpc(s)`, `ws(s)` | Executed for every request from a client and before it is being proxied to the upstream service. +| `ws_handshake` | [access] | `ws(s)` | Executed for every request to a WebSocket service just before completing the WebSocket handshake. +| `response` | [access] | `http(s)`, `grpc(s)` | Replaces both `header_filter()` and `body_filter()`. Executed after the whole response has been received from the upstream service, but before sending any part of it to the client. +| `header_filter` | [header_filter] | `http(s)`, `grpc(s)` | Executed when all response headers bytes have been received from the upstream service. +| `ws_client_frame` | [content] | `ws(s)` | Executed for each WebSocket message received from the client. +| `ws_upstream_frame` | [content] | `ws(s)` | Executed for each WebSocket message received from the upstream service. +| `body_filter` | [body_filter] | `http(s)`, `grpc(s)` | Executed for each chunk of the response body received from the upstream service. Since the response is streamed back to the client, it can exceed the buffer size and be streamed chunk by chunk. This function can be called multiple times if the response is large. See the [lua-nginx-module] documentation for more details. +| `log` | [log] | `http(s)`, `grpc(s)` | Executed when the last response byte has been sent to the client. +| `ws_close` | [log] | `ws(s)` | Executed after the WebSocket connection has been terminated. {:.note} > **Note:** If a module implements the `response` function, {{site.base_gateway}} will automatically activate the "buffered proxy" mode, as if the [`kong.service.request.enable_buffering()` function][enable_buffering] had been called. Because of a current Nginx limitation, this doesn't work for HTTP/2 or gRPC upstreams. @@ -57,21 +60,29 @@ To reduce unexpected behaviour changes, {{site.base_gateway}} does not start if | Function name | Phase | Description |-----------------|------------------------------------------------------------------------------|------------ | `init_worker` | [init_worker] | Executed upon every Nginx worker process's startup. +| `configure` | [init_worker/timer] | Executed everytime Kong plugin iterator is rebuild (aka after changes to configure plugins) | `preread` | [preread] | Executed once for every connection. | `log` | [log](https://github.com/openresty/stream-lua-nginx-module#log_by_lua_block) | Executed once for each connection after it has been closed. -| `certificate` | [ssl_certificate] | Executed during the SSL certificate serving phase of the SSL handshake. +| `certificate` | [ssl_certificate] | Executed during the SSL certificate serving phase of the SSL handshake. -All of those functions, except `init_worker`, take one parameter which is given +All of those functions, except `init_worker` and `configure`, take one parameter which is given by {{site.base_gateway}} upon its invocation: the configuration of your plugin. This parameter is a Lua table, and contains values defined by your users, according to your plugin's schema (described in the `schema.lua` module). More on plugins schemas -in the [next chapter]({{page.book.next.url}}). +in the [next chapter]({{page.book.next.url}}). The `configure` is called with an array of all the enabled +plugin configurations for the particular plugin (or in case there is no active configurations +to plugin, a `nil` is passed). `init_worker` and `configure` happens outside +requests or frames, while the rest of the phases are bound to incoming request/frame. Note that UDP streams don't have real connections. {{site.base_gateway}} will consider all packets with the same origin and destination host and port as a single connection. After a configurable time without any packet, the connection is considered closed and the `log` function is executed. +{:.note} +> The `configure` handler was added on Kong 3.5. We are currently looking feedback for this new phase, +> and there is a slight possibility that its signature might change in a future. + ## handler.lua specifications {{site.base_gateway}} processes requests in **phases**. A plugin is a piece of code that gets @@ -79,7 +90,8 @@ activated by {{site.base_gateway}} as each phase is executed while the request g Phases are limited in what they can do. For example, the `init_worker` phase does not have access to the `config` parameter because that information isn't -available when kong is initializing each worker. +available when kong is initializing each worker. On the other hand the `configure` +is passed with all the active configurations for the plugin (or `nil` if not configured). A plugin's `handler.lua` must return a table containing the functions it must execute on each phase. @@ -114,6 +126,12 @@ function CustomHandler:init_worker() end +function CustomHandler:configure(configs) + -- Implement logic for the configure phase here + --(called whenever there is change to any of the plugins) + kong.log("configure") +end + function CustomHandler:preread(config) -- Implement logic for the preread phase here (stream) kong.log("preread") @@ -280,6 +298,7 @@ The following handlers are _unique to_ WebSocket services: The following handlers are executed for both WebSocket _and_ non-Websocket services: - `init_worker` + - `configure` - `certificate` (TLS/SSL requests only) - `rewrite` diff --git a/app/_src/gateway/plugin-development/entities-cache.md b/app/_src/gateway/plugin-development/entities-cache.md index 07ffbee1ee27..787c19280b71 100644 --- a/app/_src/gateway/plugin-development/entities-cache.md +++ b/app/_src/gateway/plugin-development/entities-cache.md @@ -320,6 +320,11 @@ kong.worker_events.register(function(data) end, "crud", "consumers") ``` +{:.note} +> In many cases it is worth to check whether implementing `configure` with the plugin +> solves the issue/need without having to use events. For examples events might work +> differently depending on Kong node's role (traditional, dbless, or data plane). + ## Extending the Admin API As you are probably aware, the [Admin API] is where Kong users communicate with From 19329c23980a460204ebb66062a1aee597cecad9 Mon Sep 17 00:00:00 2001 From: Angel Date: Tue, 7 Nov 2023 12:34:58 -0500 Subject: [PATCH 2/2] if_version + cleanup --- .../plugin-development/custom-logic.md | 62 +++++++++++++++++-- .../plugin-development/entities-cache.md | 4 +- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/app/_src/gateway/plugin-development/custom-logic.md b/app/_src/gateway/plugin-development/custom-logic.md index c1f711836f85..c5b7acd46344 100644 --- a/app/_src/gateway/plugin-development/custom-logic.md +++ b/app/_src/gateway/plugin-development/custom-logic.md @@ -15,10 +15,17 @@ connection as it is proxied by {{site.base_gateway}}. To do so, the file more functions with predetermined names. Those functions will be invoked by {{site.base_gateway}} at different phases when it processes traffic. +{% if_version gte: 3.5.x %} The first parameter they take is always `self`. All functions except `init_worker` and `configure`can receive a second parameter which is a table with the plugin configuration. The `configure` receives an array of all configurations for the specific plugin. +{% endif_version %} + +{% if_version lte:3.4.x %} +The first parameter they take is always `self`. All functions except `init_worker` +can receive a second parameter which is a table with the plugin configuration. +{% endif_version %} ## Module @@ -33,11 +40,44 @@ file you'll implement custom logic at various entry-points of {{site.base_gateway}}'s execution life-cycle: - **[HTTP Module]** *is used for plugins written for HTTP/HTTPS requests* +{% if_version lte: 3.4.x %} + +| Function name | Phase | Request Protocol | Description +|---------------------|-------------------|-------------------------|------------ +| `init_worker` | [init_worker] | * | Executed upon every Nginx worker process's startup. +| `certificate` | [ssl_certificate] | `https`, `grpcs`, `wss` | Executed during the SSL certificate serving phase of the SSL handshake. +| `rewrite` | [rewrite] | * | Executed for every request upon its reception from a client as a rewrite phase handler.
In this phase, neither the `Service` nor the `Consumer` have been identified, hence this handler will only be executed if the plugin was configured as a global plugin. +| `access` | [access] | `http(s)`, `grpc(s)`, `ws(s)` | Executed for every request from a client and before it is being proxied to the upstream service. +| `ws_handshake` | [access] | `ws(s)` | Executed for every request to a WebSocket service just before completing the WebSocket handshake. +| `response` | [access] | `http(s)`, `grpc(s)` | Replaces both `header_filter()` and `body_filter()`. Executed after the whole response has been received from the upstream service, but before sending any part of it to the client. +| `header_filter` | [header_filter] | `http(s)`, `grpc(s)` | Executed when all response headers bytes have been received from the upstream service. +| `ws_client_frame` | [content] | `ws(s)` | Executed for each WebSocket message received from the client. +| `ws_upstream_frame` | [content] | `ws(s)` | Executed for each WebSocket message received from the upstream service. +| `body_filter` | [body_filter] | `http(s)`, `grpc(s)` | Executed for each chunk of the response body received from the upstream service. Since the response is streamed back to the client, it can exceed the buffer size and be streamed chunk by chunk. This function can be called multiple times if the response is large. See the [lua-nginx-module] documentation for more details. +| `log` | [log] | `http(s)`, `grpc(s)` | Executed when the last response byte has been sent to the client. +| `ws_close` | [log] | `ws(s)` | Executed after the WebSocket connection has been terminated. + +{:.note} +> **Note:** If a module implements the `response` function, {{site.base_gateway}} will automatically activate the "buffered proxy" mode, as if the [`kong.service.request.enable_buffering()` function][enable_buffering] had been called. Because of a current Nginx limitation, this doesn't work for HTTP/2 or gRPC upstreams. + +To reduce unexpected behaviour changes, {{site.base_gateway}} does not start if a plugin implements both `response` and either `header_filter` or `body_filter`. + +- **[Stream Module]** *is used for Plugins written for TCP and UDP stream connections* + +| Function name | Phase | Description +|-----------------|------------------------------------------------------------------------------|------------ +| `init_worker` | [init_worker] | Executed upon every Nginx worker process's startup. +| `preread` | [preread] | Executed once for every connection. +| `log` | [log](https://github.com/openresty/stream-lua-nginx-module#log_by_lua_block) | Executed once for each connection after it has been closed. +| `certificate` | [ssl_certificate] | Executed during the SSL certificate serving phase of the SSL handshake. +{% endif_version %} + +{% if_version gte: 3.5.x %} | Function name | Phase | Request Protocol | Description |---------------------|---------------------|-------------------------------|------------ | `init_worker` | [init_worker] | * | Executed upon every Nginx worker process's startup. -| `configure` | [init_worker/timer] | * | Executed everytime Kong plugin iterator is rebuild (aka after changes to configure plugins) +| `configure` | [init_worker]/timer | * | Executed everytime Kong plugin iterator is rebuild (aka after changes to configure plugins) | `certificate` | [ssl_certificate] | `https`, `grpcs`, `wss` | Executed during the SSL certificate serving phase of the SSL handshake. | `rewrite` | [rewrite] | * | Executed for every request upon its reception from a client as a rewrite phase handler.
In this phase, neither the `Service` nor the `Consumer` have been identified, hence this handler will only be executed if the plugin was configured as a global plugin. | `access` | [access] | `http(s)`, `grpc(s)`, `ws(s)` | Executed for every request from a client and before it is being proxied to the upstream service. @@ -60,11 +100,13 @@ To reduce unexpected behaviour changes, {{site.base_gateway}} does not start if | Function name | Phase | Description |-----------------|------------------------------------------------------------------------------|------------ | `init_worker` | [init_worker] | Executed upon every Nginx worker process's startup. -| `configure` | [init_worker/timer] | Executed everytime Kong plugin iterator is rebuild (aka after changes to configure plugins) +| `configure` | [init_worker]/timer | Executed everytime Kong plugin iterator is rebuild (aka after changes to configure plugins) | `preread` | [preread] | Executed once for every connection. | `log` | [log](https://github.com/openresty/stream-lua-nginx-module#log_by_lua_block) | Executed once for each connection after it has been closed. | `certificate` | [ssl_certificate] | Executed during the SSL certificate serving phase of the SSL handshake. + + All of those functions, except `init_worker` and `configure`, take one parameter which is given by {{site.base_gateway}} upon its invocation: the configuration of your plugin. This parameter is a Lua table, and contains values defined by your users, according to your @@ -82,17 +124,23 @@ considered closed and the `log` function is executed. {:.note} > The `configure` handler was added on Kong 3.5. We are currently looking feedback for this new phase, > and there is a slight possibility that its signature might change in a future. - +{% endif_version %} ## handler.lua specifications {{site.base_gateway}} processes requests in **phases**. A plugin is a piece of code that gets activated by {{site.base_gateway}} as each phase is executed while the request gets proxied. +{% if_version gte:3.5.x %} Phases are limited in what they can do. For example, the `init_worker` phase does not have access to the `config` parameter because that information isn't available when kong is initializing each worker. On the other hand the `configure` is passed with all the active configurations for the plugin (or `nil` if not configured). - +{% endif_version %} +{% if_version lte: 3.4.x %} +Phases are limited in what they can do. For example, the `init_worker` phase +does not have access to the `config` parameter because that information isn't +available when kong is initializing each worker. +{% endif_version %} A plugin's `handler.lua` must return a table containing the functions it must execute on each phase. @@ -125,13 +173,13 @@ function CustomHandler:init_worker() kong.log("init_worker") end - +{% if_version gte:3.5.x %} function CustomHandler:configure(configs) -- Implement logic for the configure phase here --(called whenever there is change to any of the plugins) kong.log("configure") end - +{% endif_version %} function CustomHandler:preread(config) -- Implement logic for the preread phase here (stream) kong.log("preread") @@ -298,7 +346,9 @@ The following handlers are _unique to_ WebSocket services: The following handlers are executed for both WebSocket _and_ non-Websocket services: - `init_worker` + {% if_version gte:3.5.x %} - `configure` + {% endif_version %} - `certificate` (TLS/SSL requests only) - `rewrite` diff --git a/app/_src/gateway/plugin-development/entities-cache.md b/app/_src/gateway/plugin-development/entities-cache.md index 787c19280b71..e69599889046 100644 --- a/app/_src/gateway/plugin-development/entities-cache.md +++ b/app/_src/gateway/plugin-development/entities-cache.md @@ -319,12 +319,12 @@ kong.worker_events.register(function(data) end end, "crud", "consumers") ``` - +{% if_version gte:3.5.x %} {:.note} > In many cases it is worth to check whether implementing `configure` with the plugin > solves the issue/need without having to use events. For examples events might work > differently depending on Kong node's role (traditional, dbless, or data plane). - +{% endif_version %} ## Extending the Admin API As you are probably aware, the [Admin API] is where Kong users communicate with