Skip to content

Commit ac45849

Browse files
committed
core: Added retry mechanism
1 parent c9245b8 commit ac45849

File tree

12 files changed

+518
-95
lines changed

12 files changed

+518
-95
lines changed

.vscode/launch.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"type": "emmylua_new",
9+
"request": "launch",
10+
"name": "EmmyLua New Debug",
11+
"host": "localhost",
12+
"port": 9966,
13+
"ext": [
14+
".lua",
15+
".lua.txt",
16+
".lua.bytes"
17+
],
18+
"ideConnectDebugger": true,
19+
}
20+
]
21+
}

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Initial implementation of plugin
1313
- Added GitHub action build for linting and unit testing
14+
- Added function to handle unexpected errors and exit the plugin
15+
- Added function to make FGA requests with retry logic
16+
- Added unit tests to mock HTTP requests and return different responses based on call count
17+
- Added support for EMMY Debugger with configurable host and port
1418

1519
### Changed
1620

21+
- Extracted `kong.response.exit(500, "An unexpected error occurred")` to its own function
22+
- Extracted the code inside the `repeat ... until` loop into its own function
23+
- Modified `make_fga_request` to return a boolean indicating allow/deny
24+
1725
### Fixed
1826

1927
### Removed

Makefile

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,31 @@ DOCKER_NO_CACHE :=
3131

3232
BUILDKIT_PROGRESS :=
3333

34+
# Busted runtime profile
3435
BUSTED_RUN_PROFILE := default
3536
BUSTED_FILTER :=
3637

38+
# Busted exclude tags
3739
BUSTED_EXCLUDE_TAGS := postgres
40+
BUSTED_NO_KEEP_GOING := false
3841
BUSTED_COVERAGE := false
42+
BUSTED_EMMY_DEBUGGER := false
43+
44+
BUSTED_EMMY_DEBUGGER_ENABLED_ARGS =
3945

4046
BUSTED_ARGS = --config-file $(DOCKER_MOUNT_IN_CONTAINER)/.busted --run '$(BUSTED_RUN_PROFILE)' --exclude-tags='$(BUSTED_EXCLUDE_TAGS)' --filter '$(BUSTED_FILTER)'
41-
ifdef BUSTED_NO_KEEP_GOING
47+
ifneq ($(BUSTED_NO_KEEP_GOING), false)
4248
BUSTED_ARGS += --no-keep-going
4349
endif
4450

4551
ifneq ($(BUSTED_COVERAGE), false)
4652
BUSTED_ARGS += --coverage
4753
endif
4854

55+
ifneq ($(BUSTED_EMMY_DEBUGGER), false)
56+
BUSTED_EMMY_DEBUGGER_ENABLED_ARGS = -e BUSTED_EMMY_DEBUGGER='/usr/local/lib/lua/5.1/emmy_core.so'
57+
endif
58+
4959
KONG_SMOKE_TEST_DEPLOYMENT_PATH := _build/deployment/kong-smoke-test
5060

5161
CONTAINER_CI_KONG_TOOLING_IMAGE_PATH := _build/images/kong-tooling
@@ -82,10 +92,10 @@ CONTAINER_CI_OPENFGA_MIGRATION := $(DOCKER) run $(DOCKER_RUN_FLAGS) \
8292
migrate --verbose
8393

8494
CONTAINER_CI_OPENFGA_RUN := $(DOCKER) run -d $(DOCKER_RUN_FLAGS) \
85-
-p '8080:8080' \
86-
-p '8081:8081' \
87-
-p '3000:3000' \
88-
-p '2112:2112' \
95+
-p 8080:8080 \
96+
-p 8081:8081 \
97+
-p 3000:3000 \
98+
-p 2112:2112 \
8999
-e OPENFGA_DATASTORE_ENGINE=sqlite \
90100
-e OPENFGA_DATASTORE_URI=file:/data/openfga.sqlite \
91101
-e OPENFGA_DATASTORE_MAX_OPEN_CONNS=100 \
@@ -124,6 +134,7 @@ CONTAINER_CI_KONG_TOOLING_BUILD = DOCKER_BUILDKIT=1 BUILDKIT_PROGRESS=$(BUILDKIT
124134
--build-arg PONGO_KONG_VERSION='$(PONGO_KONG_VERSION)' \
125135
--build-arg PONGO_ARCHIVE='$(PONGO_ARCHIVE)' \
126136
--build-arg STYLUA_VERSION='$(STYLUA_VERSION)' \
137+
--build-arg EMMY_LUA_DEBUGGER_VERSION='$(EMMY_LUA_DEBUGGER_VERSION)' \
127138
.
128139

129140
CONTAINER_CI_KONG_SMOKE_TEST_BUILD = DOCKER_BUILDKIT=1 BUILDKIT_PROGRESS=$(BUILDKIT_PROGRESS) $(DOCKER) build \
@@ -139,12 +150,20 @@ CONTAINER_CI_KONG_SMOKE_TEST_BUILD = DOCKER_BUILDKIT=1 BUILDKIT_PROGRESS=$(BUILD
139150
.
140151

141152
CONTAINER_CI_KONG_TOOLING_RUN := MSYS_NO_PATHCONV=1 $(DOCKER) run $(DOCKER_RUN_FLAGS) \
142-
-v '$(PWD):$(DOCKER_MOUNT_IN_CONTAINER)' \
153+
-p 9966:9966 \
143154
-e KONG_SPEC_TEST_REDIS_HOST='$(CONTAINER_CI_REDIS_NAME)' \
144155
-e KONG_SPEC_TEST_LIVE_HOSTNAME='$(CONTAINER_CI_OPENFGA_NAME)' \
145156
-e KONG_LICENSE_PATH=$(DOCKER_MOUNT_IN_CONTAINER)/kong-license.json \
146157
-e KONG_DNS_ORDER='LAST,A,SRV' \
158+
-e BUSTED_EMMY_DEBUGGER_HOST='0.0.0.0' \
159+
-e BUSTED_EMMY_DEBUGGER_PORT='9966' \
160+
-e BUSTED_EMMY_DEBUGGER_SOURCE_PATH='$(DOCKER_MOUNT_IN_CONTAINER)' \
161+
-e BUSTED_EMMY_DEBUGGER_SOURCE_PATH_MAPPING='$(DOCKER_MOUNT_IN_CONTAINER);$(PWD)' \
162+
$(BUSTED_EMMY_DEBUGGER_ENABLED_ARGS) \
147163
--network='$(CONTAINER_CI_NETWORK_NAME)' \
164+
-v '$(PWD):$(DOCKER_MOUNT_IN_CONTAINER)' \
165+
-v '$(PWD)/_build/debugger/emmy_debugger.lua:/usr/local/share/lua/5.1/kong/tools/emmy_debugger.lua' \
166+
-v '$(PWD)/_build/debugger/busted:/kong/bin/busted' \
148167
'$(CONTAINER_CI_KONG_TOOLING_IMAGE_NAME)'
149168

150169
CONTAINER_CI_KONG_SMOKE_TEST_RUN_SERVER_NAME = kong-plugin-$(KONG_PLUGIN_NAME)-smoke-test

README.md

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ Below is the example configuration one might use in `declarative_config`:
5050
port: 1234
5151
https: true
5252
https_verify: true
53+
max_attempts: 3
54+
failed_attempts_backoff_timeout: 1000
5355
timeout: 10000
5456
keepalive: 60000
5557
store_id: "your_store_id"
@@ -72,24 +74,26 @@ Below is the example configuration one might use in `declarative_config`:
7274

7375
## Configuration
7476

75-
| Property | Default value | Description |
76-
| ------------------------------------------------------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
77-
| `host`<br/>_required_<br/><br/>**Type:** hostname (string) | - | Hostname of the OpenFGA server |
78-
| `port`<br/>_required_<br/><br/>**Type:** port (number) | 8080 | HTTP API port of OpenFGA |
79-
| `https`<br/>_optional_<br/><br/>**Type:** boolean | false | Use HTTPS to connect to OpenFGA |
80-
| `https_verify`<br/>_optional_<br/><br/>**Type:** boolean | false | Verify HTTPS certificate |
81-
| `timeout`<br/>_optional_<br/><br/>**Type:** number | 10000 | The total timeout time in milliseconds for a request and response cycle. |
82-
| `keepalive`<br/>_optional_<br/><br/>**Type:** number | 60000 | The maximal idle timeout in milliseconds for the current connection. See [tcpsock:setkeepalive](https://github.com/openresty/lua-nginx-module#tcpsocksetkeepalive) for more details. |
83-
| `store_id`<br/>_required_<br/><br/>**Type:** string | - | The store ID in OpenFGA |
84-
| `model_id`<br/>_optional_<br/><br/>**Type:** string | - | Optional model ID (version). Latest is used if this is empty |
85-
| `api_token`<br/>_optional_<br/><br/>**Type:** string | - | Optional API token |
86-
| `api_token_issuer`<br/>_optional_<br/><br/>**Type:** string | - | API token issuer |
87-
| `api_audience`<br/>_optional_<br/><br/>**Type:** string | - | API audience |
88-
| `api_client_id`<br/>_optional_<br/><br/>**Type:** string | - | API client ID |
89-
| `api_client_secret`<br/>_optional_<br/><br/>**Type:** string | - | API client secret |
90-
| `api_token_cache`<br/>_optional_<br/><br/>**Type:** number | 600 | API token cache duration in seconds |
91-
| `tuple`<br/>_required_<br/><br/>**Type:** record | - | Tuple key for authorization |
92-
| `contextual_tuples`<br/>_optional_<br/><br/>**Type:** set | {} | Set of contextual tuples for authorization |
77+
| Property | Default value | Description |
78+
| --------------------------------------------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
79+
| `host`<br/>_required_<br/><br/>**Type:** hostname (string) | - | Hostname of the OpenFGA server |
80+
| `port`<br/>_required_<br/><br/>**Type:** port (number) | 8080 | HTTP API port of OpenFGA |
81+
| `https`<br/>_optional_<br/><br/>**Type:** boolean | false | Use HTTPS to connect to OpenFGA |
82+
| `https_verify`<br/>_optional_<br/><br/>**Type:** boolean | false | Verify HTTPS certificate |
83+
| `max_attempts`<br/>_optional_<br/><br/>**Type:** integer | 3 | @TODO |
84+
| `failed_attempts_backoff_timeout`<br/>_optional_<br/><br/>**Type:** integer | 1000 | @TODO failed_attempts_backoff_timeout \* 2 ^ (attempts - 1) / 1000 |
85+
| `timeout`<br/>_optional_<br/><br/>**Type:** number | 10000 | The total timeout time in milliseconds for a request and response cycle. |
86+
| `keepalive`<br/>_optional_<br/><br/>**Type:** number | 60000 | The maximal idle timeout in milliseconds for the current connection. See [tcpsock:setkeepalive](https://github.com/openresty/lua-nginx-module#tcpsocksetkeepalive) for more details. |
87+
| `store_id`<br/>_required_<br/><br/>**Type:** string | - | The store ID in OpenFGA |
88+
| `model_id`<br/>_optional_<br/><br/>**Type:** string | - | Optional model ID (version). Latest is used if this is empty |
89+
| `api_token`<br/>_optional_<br/><br/>**Type:** string | - | Optional API token |
90+
| `api_token_issuer`<br/>_optional_<br/><br/>**Type:** string | - | API token issuer |
91+
| `api_audience`<br/>_optional_<br/><br/>**Type:** string | - | API audience |
92+
| `api_client_id`<br/>_optional_<br/><br/>**Type:** string | - | API client ID |
93+
| `api_client_secret`<br/>_optional_<br/><br/>**Type:** string | - | API client secret |
94+
| `api_token_cache`<br/>_optional_<br/><br/>**Type:** number | 600 | API token cache duration in seconds |
95+
| `tuple`<br/>_required_<br/><br/>**Type:** record | - | Tuple key for authorization |
96+
| `contextual_tuples`<br/>_optional_<br/><br/>**Type:** set | {} | Set of contextual tuples for authorization |
9397

9498
## Plugin version
9599

@@ -149,6 +153,12 @@ make lint
149153
make test-unit
150154
```
151155

156+
| Runtime configuration | Description |
157+
| --------------------- | ----------- |
158+
| BUSTED_NO_KEEP_GOING | |
159+
| BUSTED_COVERAGE | |
160+
| BUSTED_EMMY_DEBUGGER | |
161+
152162
### Pack the plugin into a .rock
153163

154164
```sh

_build/debugger/busted

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/usr/bin/env resty
2+
3+
setmetatable(_G, nil)
4+
5+
local pl_path = require("pl.path")
6+
local pl_file = require("pl.file")
7+
8+
local tools_system = require("kong.tools.system")
9+
10+
local emmy_debugger = require("kong.tools.emmy_debugger")
11+
12+
local cert_path do
13+
local busted_cert_file = pl_path.tmpname()
14+
local busted_cert_content = pl_file.read("spec/fixtures/kong_spec.crt")
15+
16+
local system_cert_path, err = tools_system.get_system_trusted_certs_filepath()
17+
if system_cert_path then
18+
busted_cert_content = busted_cert_content .. "\n" .. pl_file.read(system_cert_path)
19+
end
20+
21+
pl_file.write(busted_cert_file, busted_cert_content)
22+
cert_path = busted_cert_file
23+
end
24+
25+
local DEFAULT_RESTY_FLAGS=string.format(" -c 4096 --http-conf 'lua_ssl_trusted_certificate %s;' ", cert_path)
26+
27+
if not os.getenv("KONG_BUSTED_RESPAWNED") then
28+
-- initial run, so go update the environment
29+
local script = {}
30+
for line in io.popen("set"):lines() do
31+
local ktvar, val = line:match("^KONG_TEST_([^=]*)=(.*)")
32+
if ktvar then
33+
-- reinserted KONG_TEST_xxx as KONG_xxx; append
34+
table.insert(script, "export KONG_" .. ktvar .. "=" ..val)
35+
end
36+
37+
local var = line:match("^(KONG_[^=]*)")
38+
local var_for_spec = line:match("^(KONG_SPEC_[^=]*)")
39+
if var and not var_for_spec then
40+
-- remove existing KONG_xxx and KONG_TEST_xxx variables; prepend
41+
table.insert(script, 1, "unset " .. var)
42+
end
43+
end
44+
-- add cli recursion detection
45+
table.insert(script, "export KONG_BUSTED_RESPAWNED=1")
46+
47+
-- XXX EE
48+
table.insert(script, "export KONG_IS_TESTING=1")
49+
50+
-- rebuild the invoked commandline, while inserting extra resty-flags
51+
local resty_flags = DEFAULT_RESTY_FLAGS
52+
local cmd = { "exec", "/usr/bin/env", "resty" }
53+
local cmd_prefix_count = #cmd
54+
for i = 0, #arg do
55+
if arg[i]:sub(1, 12) == "RESTY_FLAGS=" then
56+
resty_flags = arg[i]:sub(13, -1)
57+
58+
else
59+
table.insert(cmd, "'" .. arg[i] .. "'")
60+
end
61+
end
62+
63+
-- create shared dict
64+
resty_flags = resty_flags .. require("spec.fixtures.shared_dict")
65+
66+
if resty_flags then
67+
table.insert(cmd, cmd_prefix_count+1, resty_flags)
68+
end
69+
70+
table.insert(script, table.concat(cmd, " "))
71+
72+
-- recurse cli command, with proper variables (un)set for clean testing
73+
local _, _, rc = os.execute(table.concat(script, "; "))
74+
os.exit(rc)
75+
end
76+
77+
pcall(require, "luarocks.loader")
78+
79+
if os.getenv("BUSTED_EMMY_DEBUGGER") then
80+
emmy_debugger.init({
81+
debugger = os.getenv("BUSTED_EMMY_DEBUGGER"),
82+
host = os.getenv("BUSTED_EMMY_DEBUGGER_HOST"),
83+
port = os.getenv("BUSTED_EMMY_DEBUGGER_PORT"),
84+
wait = true,
85+
source_path = os.getenv("BUSTED_EMMY_DEBUGGER_SOURCE_PATH"),
86+
source_path_mapping = os.getenv("BUSTED_EMMY_DEBUGGER_SOURCE_PATH_MAPPING"),
87+
})
88+
end
89+
90+
require("kong.globalpatches")({
91+
cli = true,
92+
rbusted = true
93+
})
94+
95+
-- some libraries used in test like spec/helpers
96+
-- calls cosocket in module level, and as LuaJIT's
97+
-- `require` is implemented in C, this throws
98+
-- "attempt to yield across C-call boundary" error
99+
-- the following pure-lua implementation is to bypass
100+
-- this limitation, without need to modify all tests
101+
_G.require = require "spec.require".require
102+
103+
-- Busted command-line runner
104+
require 'busted.runner'({ standalone = false })
105+
106+
107+
-- vim: set ft=lua ts=2 sw=2 sts=2 et :

0 commit comments

Comments
 (0)