help request: What is the best way to dynamically route a cluster by token in customer plugin?
Description
i got tenantid in jwt token, and i want to use this id to route the cluster, how can i do it ?
local jwt_obj = jwt:verify(conf.jwt_secret, token)
if jwt_obj.valid and jwt_obj.verified then
local tid = jwt_obj.payload.tid
if tid ~= nil then
local red, err = redis.new(conf)
if not red then
return 502, err
end
local domain, redis_err = red:get("tid-" .. tid)
if not domain or domain == nil or (type(domain) == "userdata" and tostring(domain) == "userdata: NULL") then
return 502, redis_err
else
-- Here I do not know,how can i set the cluster domain?use the upstream id is the best way?
--like this? ctx.upstream_id = "512895159801742021"
core.request.set_header(ctx, "x-cluster", domain)
end
else
-- todo: add no token handle
core.log.warn("tid is nil, set default cluster")
end
else
core.log.warn("jwt valid error:" .. core.json.encode(jwt_obj))
return 502, jwt_obj.reason
end
Environment
- APISIX version (run
3.9.0): - Operating system (run
uname -a): - OpenResty / Nginx version (run
openresty -Vornginx -V): - etcd version, if relevant (run
curl http://127.0.0.1:9090/v1/server_info): - APISIX Dashboard version, if relevant:
- Plugin runner version, for issues related to plugin runners:
- LuaRocks version, for installation issues (run
luarocks --version):
APISIX doesn't support this.
I found an implementation, which is done through the following code: dymainc_uri_upstream.lua
local up_conf = {
timeout = {
connect = 6,
send = 300,
read = 300
},
scheme = "http",
type = "roundrobin",
pass_host = "pass",
keepalive_pool = {
idle_timeout = 60,
requests = 1000,
size = 320
},
hash_on = "vars",
nodes = {
{
priority = 0,
port = upstream_port,
host = parse_domain(upstream_host),
weight = 1
}
}
}
local ok, err = upstream.check_schema(up_conf)
if not ok then
core.log.error("failed to validate generated upstream: ", err)
return 500, err
end
local matched_route = ctx.matched_route
up_conf.parent = matched_route
local upstream_key = up_conf.type .. "#route_" .. matched_route.value.id
core.log.info("upstream_key: ", upstream_key)
upstream.set(ctx, upstream_key, ctx.conf_version, up_conf)
But I don't think it's a best practice because many parameters become fixed values and cannot be dynamically configured. I found that it can also be achieved by setting the upstream_id, but I don't know what the risks are.
APISIX doesn't support this. Dynamic routing based on user (token) information is crucial in a multi-cluster mode, and I hope APISIX can implement this.
You can do this by writing custom plugins. If there is still a problem, please open it again.