Skip to content

Commit

Permalink
feat(limit-count): allow to use environment variables for settings (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
ikatlinsky committed Dec 18, 2023
1 parent ad242db commit bf8940d
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 0 deletions.
2 changes: 2 additions & 0 deletions apisix/plugins/limit-count.lua
Expand Up @@ -14,6 +14,7 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
local fetch_secrets = require("apisix.secret").fetch_secrets
local limit_count = require("apisix.plugins.limit-count.init")

local plugin_name = "limit-count"
Expand All @@ -31,6 +32,7 @@ end


function _M.access(conf, ctx)
conf = fetch_secrets(conf)
return limit_count.rate_limit(conf, ctx, plugin_name, 1)
end

Expand Down
31 changes: 31 additions & 0 deletions docs/en/latest/plugins/limit-count.md
Expand Up @@ -257,6 +257,37 @@ curl -i http://127.0.0.1:9180/apisix/admin/routes/1 \
}'
```

In addition, you can use APISIX secret to store and reference plugin attributes. APISIX currently supports storing secrets in two ways - [Environment Variables and HashiCorp Vault](../terminology/secret.md). For example, in
case you have environment variables `REDIS_HOST` and `REDIS_PASSWORD` set, you can use them in the plugin configuration as shown below:

```shell
curl -i http://127.0.0.1:9180/apisix/admin/routes/1 \
-H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uri": "/index.html",
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr",
"policy": "redis",
"redis_host": "$ENV://REDIS_HOST",
"redis_port": 6379,
"redis_password": "$ENV://REDIS_PASSWORD",
"redis_database": 1,
"redis_timeout": 1001
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

## Example usage

The above configuration limits to 2 requests in 60 seconds. The first two requests will work and the response headers will contain the headers `X-RateLimit-Limit` and `X-RateLimit-Remaining` and `X-RateLimit-Reset`, represents the total number of requests that are limited, the number of requests that can still be sent, and the number of seconds left for the counter to reset:
Expand Down
55 changes: 55 additions & 0 deletions t/plugin/limit-count-redis-cluster3.t
Expand Up @@ -14,6 +14,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
BEGIN {
$ENV{REDIS_NODE_0} = "127.0.0.1:5000";
$ENV{REDIS_NODE_1} = "127.0.0.1:5001";
}

use t::APISIX;

Expand Down Expand Up @@ -128,3 +132,54 @@ passed
["GET /hello", "GET /hello", "GET /hello"]
--- error_code eval
[200, 200, 503]
=== TEST 4: set route, with redis_cluster_nodes as environment variables and redis_cluster_name
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/hello",
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr",
"policy": "redis-cluster",
"redis_timeout": 1001,
"redis_cluster_nodes": [
"$ENV://REDIS_NODE_0",
"$ENV://REDIS_NODE_1"
],
"redis_cluster_name": "redis-cluster-1"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 5: up the limit with environment variables for redis_cluster_nodes
--- pipelined_requests eval
["GET /hello", "GET /hello", "GET /hello"]
--- error_code eval
[200, 200, 503]
49 changes: 49 additions & 0 deletions t/plugin/limit-count-redis4.t
Expand Up @@ -22,6 +22,8 @@ BEGIN {
$ENV{TEST_NGINX_USE_HUP} = 1;
undef $ENV{TEST_NGINX_USE_STAP};
}

$ENV{REDIS_HOST} = "127.0.0.1";
}

use t::APISIX;
Expand Down Expand Up @@ -85,3 +87,50 @@ __DATA__
}
--- response_body
remaining: 1
=== TEST 2: set route, with redis host as environment variable
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/hello",
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr",
"policy": "redis",
"redis_host": "$ENV://REDIS_HOST"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 3: up the limit with host environment variable
--- pipelined_requests eval
["GET /hello", "GET /hello", "GET /hello"]
--- error_code eval
[200, 200, 503]
48 changes: 48 additions & 0 deletions t/plugin/limit-count5.t
Expand Up @@ -22,6 +22,8 @@ BEGIN {
$ENV{TEST_NGINX_USE_HUP} = 1;
undef $ENV{TEST_NGINX_USE_STAP};
}

$ENV{LIMIT_COUNT_KEY} = "remote_addr";
}

use t::APISIX;
Expand Down Expand Up @@ -89,3 +91,49 @@ remaining: 2
remaining: 0
rejected
rejected
=== TEST 2: set route(id: 1) using environment variable for key
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"methods": ["GET"],
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "$ENV://LIMIT_COUNT_KEY"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 3: up the limit with environment variable for key
--- pipelined_requests eval
["GET /hello", "GET /hello", "GET /hello", "GET /hello"]
--- error_code eval
[200, 200, 503, 503]

0 comments on commit bf8940d

Please sign in to comment.