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

feat: support force delete resource #9810

Merged
merged 2 commits into from
Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions apisix/admin/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,12 @@ local function run()
if seg_res == "schema" or seg_res == "plugins" then
code, data = resource[method](seg_id, req_body, seg_sub_path, uri_args)
else
if method == "delete" then
if not req_body then
req_body = {}
end
req_body._force_delete = ngx.req.get_headers()["X-Force-Delete"]
end
code, data = resource[method](resource, seg_id, req_body, seg_sub_path, uri_args)
end

Expand Down
2 changes: 1 addition & 1 deletion apisix/admin/proto.lua
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ local function check_proto_used(plugins, deleting, ptype, pid)
if type(plugins) == "table" and plugins["grpc-transcode"]
and plugins["grpc-transcode"].proto_id
and tostring(plugins["grpc-transcode"].proto_id) == deleting then
return false, {error_msg = "can not delete this proto,"
return false, {error_msg = "can not delete this proto, "
.. ptype .. " [" .. pid
.. "] is still using it now"}
end
Expand Down
2 changes: 1 addition & 1 deletion apisix/admin/resource.lua
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ function _M:delete(id, conf, sub_path)

key = key .. "/" .. id

if self.delete_checker then
if self.delete_checker and conf._force_delete ~= "true" then
local code, err = self.delete_checker(id)
if err then
return code, err
Expand Down
27 changes: 27 additions & 0 deletions docs/en/latest/admin-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,33 @@ deployment:

This will find the environment variable `ADMIN_KEY` first, and if it does not exist, it will use `edd1c9f034335f136f87ad84b625c8f1` as the default value.

### Force Delete

By default, the Admin API checks for references between resources and will refuse to delete resources in use.

You can make a force deletion by adding the request header `X-Force-Delete: true` to the delete request, for example:
lingsamuel marked this conversation as resolved.
Show resolved Hide resolved

```bash
$ curl http://127.0.0.1:9180/apisix/admin/upstreams/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}'
$ curl http://127.0.0.1:9180/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '{
"uri": "/*",
"upstream_id": 1
}'
{"value":{"priority":0,"upstream_id":1,"uri":"/*","create_time":1689038794,"id":"1","status":1,"update_time":1689038916},"key":"/apisix/routes/1"}

$ curl http://127.0.0.1:9180/apisix/admin/upstreams/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X DELETE
{"error_msg":"can not delete this upstream, route [1] is still using it now"}
$ curl http://127.0.0.1:9180/apisix/admin/upstreams/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X DELETE -H 'X-Force-Delete: any-value'
{"error_msg":"can not delete this upstream, route [1] is still using it now"}
$ curl http://127.0.0.1:9180/apisix/admin/upstreams/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X DELETE -H 'X-Force-Delete: true'
{"deleted":"1","key":"/apisix/upstreams/1"}
```

## V3 new feature

The Admin API has made some breaking changes in V3 version, as well as supporting additional features.
Expand Down
27 changes: 27 additions & 0 deletions docs/zh/latest/admin-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,33 @@ deployment:

首先查找环境变量 `ADMIN_KEY`,如果该环境变量不存在,它将使用 `edd1c9f034335f136f87ad84b625c8f1` 作为默认值。

### 强制删除 {#force-delete}

默认情况下,Admin API 会检查资源间的引用关系,将会拒绝删除正在使用中的资源。

可以通过在删除请求中添加请求头 `X-Force-Delete: true` 来进行强制删除,例如:

```bash
$ curl http://127.0.0.1:9180/apisix/admin/upstreams/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}'
$ curl http://127.0.0.1:9180/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '{
"uri": "/*",
"upstream_id": 1
}'
{"value":{"priority":0,"upstream_id":1,"uri":"/*","create_time":1689038794,"id":"1","status":1,"update_time":1689038916},"key":"/apisix/routes/1"}

$ curl http://127.0.0.1:9180/apisix/admin/upstreams/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X DELETE
{"error_msg":"can not delete this upstream, route [1] is still using it now"}
$ curl http://127.0.0.1:9180/apisix/admin/upstreams/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X DELETE -H 'X-Force-Delete: any-value'
{"error_msg":"can not delete this upstream, route [1] is still using it now"}
$ curl http://127.0.0.1:9180/apisix/admin/upstreams/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X DELETE -H 'X-Force-Delete: true'
{"deleted":"1","key":"/apisix/upstreams/1"}
```

## v3 版本新功能 {#v3-new-function}

在 APISIX v3 版本中,Admin API 支持了一些不向下兼容的新特性,比如支持新的响应体格式、支持分页查询、支持过滤资源等。
Expand Down
169 changes: 169 additions & 0 deletions t/admin/consumer-group-force-delete.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
use t::APISIX 'no_plan';

repeat_each(1);
no_long_string();
no_root_location();
no_shuffle();
log_level("info");

add_block_preprocessor(sub {
my ($block) = @_;

if (!$block->request) {
$block->set_value("request", "GET /t");
}

if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});

run_tests;

__DATA__

=== TEST 1: set consumer_group(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumer_groups/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"count": 200,
"time_window": 60,
"rejected_code": 503,
"group": "$consumer_group_id"
}
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- error_code: 201
--- response_body
passed



=== TEST 2: add consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/consumers/1',
ngx.HTTP_PUT,
[[{
"username": "1",
"plugins": {
"key-auth": {
"key": "auth-one"
}
},
"group_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
ngx.print(message)
return
end
ngx.say(message)
}
}
--- response_body
passed



=== TEST 3: delete consumer_group(wrong header)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/consumer_groups/1',
ngx.HTTP_DELETE, nil, nil,
{
["X-Force-Delete"] = "any-value",
}
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 400 message: {"error_msg":"can not delete this consumer group, consumer [1] is still using it now"}



=== TEST 4: delete consumer_group(without force delete header)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/consumer_groups/1',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 400 message: {"error_msg":"can not delete this consumer group, consumer [1] is still using it now"}



=== TEST 5: delete consumer_group(force delete)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/consumer_groups/1',
ngx.HTTP_DELETE, nil, nil,
{
["X-Force-Delete"] = "true",
}
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body chomp
[delete] code: 200 message: passed



=== TEST 6: delete consumer
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/consumers/1',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body chomp
[delete] code: 200 message: passed
Loading