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(plugins/bk-traffic-label.lua): add new plugin #86

Merged
merged 9 commits into from
Nov 25, 2024
4 changes: 3 additions & 1 deletion src/apisix/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ test-busted:
-v ${ROOT_DIR}/plugins:/bkgateway/apisix/plugins \
apisix-test-busted "/run-test-busted.sh"

# make test-nginx
# make test-nginx CASE_FILE=bk-traffic-label.t
.PHONY: test-nginx
test-nginx:
@docker run --rm ${RUN_WITH_IT} \
-v ${ROOT_DIR}/t:/bkgateway/t/ \
-v ${ROOT_DIR}/plugins:/bkgateway/apisix/plugins \
apisix-test-nginx "/run-test-nginx.sh"
apisix-test-nginx "/run-test-nginx.sh" $(if $(CASE_FILE),$(CASE_FILE))

.PHONY: apisix-test-images
apisix-test-images: apisix-test-busted apisix-test-nginx
Expand Down
7 changes: 6 additions & 1 deletion src/apisix/ci/run-test-nginx.sh
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,10 @@ export OPENRESTY_PREFIX="/usr/local/openresty-debug"
export APISIX_MAIN="https://raw.githubusercontent.com/apache/incubator-apisix/master/rockspec/apisix-master-0.rockspec"
export PATH=$OPENRESTY_PREFIX/nginx/sbin:$OPENRESTY_PREFIX/luajit/bin:$OPENRESTY_PREFIX/bin:$PATH

FLUSH_ETCD=1 prove --timer -Itest-nginx/lib -I./ t/bk-*.t
if [ -n "$1" ]; then
CASE_FILE=$1
FLUSH_ETCD=1 prove --timer -Itest-nginx/lib -I./ t/bk-00.t t/$CASE_FILE
else
FLUSH_ETCD=1 prove --timer -Itest-nginx/lib -I./ t/bk-*.t
fi

1 change: 1 addition & 0 deletions src/apisix/plugins/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@

proxy 预处理:17000 ~ 17500

- bk-traffic-label # priority: 17460
- bk-delete-sensitive # priority: 17450
- bk-delete-cookie # priority: 17440
- bk-proxy-rewrite # priority: 17430 # 该插件供 operator 进行后端地址转换使用
Expand Down
164 changes: 164 additions & 0 deletions src/apisix/plugins/bk-traffic-label.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
--
-- TencentBlueKing is pleased to support the open source community by making
-- 蓝鲸智云 - API 网关(BlueKing - APIGateway) available.
-- Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
-- Licensed under the MIT License (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
--
-- http://opensource.org/licenses/MIT
--
-- 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.
--
-- We undertake not to change the open source license (MIT license) applicable
-- to the current version of the project delivered to anyone in the future.
--

-- this plugin is impls based on the doc of api7 traffic-label
-- link: https://docs.api7.ai/hub/traffic-label/

local core = require("apisix.core")
local expr = require("resty.expr.v1")
local pairs = pairs
local ipairs = ipairs

local match_schema = {
type = "array",
}

local actions_schema = {
type = "array",
items = {
type = "object",
properties = {
set_headers = {
type = "object",
additionalProperties = {
type = "string"
}
},
weight = {
description = "percentage of all matched which would do the actions",
type = "integer",
default = 1,
minimum = 0
}
}
},
minItems = 1,
maxItems = 20
}

local schema = {
type = "object",
properties = {
rules = {
type = "array",
items = {
type = "object",
properties = {
match = match_schema,
actions = actions_schema
},
}
}
},
required = {"rules"},
}

local plugin_name = "bk-traffic-label"

local _M = {
version = 0.1,
priority = 17460,
name = plugin_name,
schema = schema
}

function _M.check_schema(conf)
-- Validate the configuration schema
local ok, err = core.schema.check(schema, conf)
if not ok then
return false, err
end

if conf.rules then
for _, rule in ipairs(conf.rules) do
if rule.match then
-- Validate the match expression
local _, err2 = expr.new(rule.match)
wklken marked this conversation as resolved.
Show resolved Hide resolved
if err2 then
core.log.error("failed to validate the 'match' expression: ", err2)
return false, "failed to validate the 'match' expression: " .. err2
end
end

-- Calculate total weight of all actions and preprocess actions to set default weight
local total_weight = 0
for _, action in ipairs(rule.actions) do
if action.weight == nil or action.weight < 0 then
action.weight = 1
end
total_weight = total_weight + action.weight
end

-- Normalize the weight of each action
local accumulated_weight = 0
for i, action in ipairs(rule.actions) do
if i == #rule.actions then
-- Assign the remaining weight to the last action to ensure the total is 100
action.weight = 100 - accumulated_weight
wklken marked this conversation as resolved.
Show resolved Hide resolved
else
action.weight = math.floor(action.weight / total_weight * 100)
wklken marked this conversation as resolved.
Show resolved Hide resolved
accumulated_weight = accumulated_weight + action.weight
end
end
end
end

return true
end

local function apply_actions(actions, ctx)
-- Generate a random number between 0 and 100
local random_weight = math.random(0, 100)
local current_weight = 0

for _, action in ipairs(actions) do
current_weight = current_weight + action.weight
-- Apply the action if the random number falls within the current weight range
if random_weight <= current_weight then
if action.set_headers then
-- Set the specified headers
for k, v in pairs(action.set_headers) do
core.request.set_header(ctx, k, v)
end
end
break
end
end
end

function _M.access(conf, ctx)
if not conf or not conf.rules then
return
end

for _, rule in ipairs(conf.rules) do
if rule.match then
-- Evaluate the match expression
local ex, _ = expr.new(rule.match)
local match_passed = ex:eval(ctx.var)
if match_passed then
-- Apply the actions if the match condition is met
apply_actions(rule.actions, ctx)
end
end
end

return
end

return _M
54 changes: 54 additions & 0 deletions src/apisix/t/bk-00.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#
# TencentBlueKing is pleased to support the open source community by making
# 蓝鲸智云 - API 网关(BlueKing - APIGateway) available.
# Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
# Licensed under the MIT License (the "License"); you may not use this file except
# in compliance with the License. You may obtain a copy of the License at
#
# http://opensource.org/licenses/MIT
#
# 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.
#
# We undertake not to change the open source license (MIT license) applicable
# to the current version of the project delivered to anyone in the future.
#

# NOTE: this file should be ran as the first test file
# otherwise other test files would fail

use t::APISIX 'no_plan';

repeat_each(1);
no_long_string();
no_root_location();
no_shuffle();

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

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

run_tests;

__DATA__

=== TEST 1: sanity
--- config
location /t {
content_by_lua_block {
local ok = true
if not ok then
ngx.say(err)
end

ngx.say("done")
}
}
--- response_body
done
Loading
Loading