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

feature: supported to set more upstream options. #451

Merged
merged 5 commits into from
Aug 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 3 additions & 0 deletions doc/architecture-design-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ APISIX 支持对上游的健康检查,你可以设置需要检查的 host、ur
`key` 在同一个对象中,永远返回相同 id 。
* `retries`: APISIX 将使用底层的 Nginx 重试机制将请求传递给下一个上游。这是一个可选项,默认是不启用重试机制。
* `checks`: 配置健康检查的参数。
* `uri`: 转发到上游的新 `uri` 地址。
* `host`: 转发到上游的新 `host`。
* `enable_websocket`: 是否启用 websocket (布尔值),默认不启用。

创建上游对象用例:

Expand Down
27 changes: 27 additions & 0 deletions lua/apisix.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ local ngx_exit = ngx.exit
local ngx_ERROR = ngx.ERROR
local math = math
local error = error
local ngx_var = ngx.var
local ipairs = ipairs
local load_balancer


Expand Down Expand Up @@ -138,6 +140,17 @@ function _M.http_ssl_phase()
end


local upstream_vars = {
uri = "upstream_uri",
scheme = "upstream_scheme",
host = "upstream_host",
upgrade = "upstream_upgrade",
connection = "upstream_connection",
}
local upstream_names = {}
for name, _ in pairs(upstream_vars) do
core.table.insert(upstream_names, name)
end
function _M.http_access_phase()
local ngx_ctx = ngx.ctx
local api_ctx = ngx_ctx.api_ctx
Expand All @@ -164,6 +177,20 @@ function _M.http_access_phase()
return ngx.exec("@grpc_pass")
end

local upstream = route.value.upstream
if upstream then
for _, name in ipairs(upstream_names) do
if upstream[name] then
ngx_var[upstream_vars[name]] = upstream[name]
end
end

if upstream.enable_websocket then
api_ctx.var["upstream_upgrade"] = api_ctx.var["http_upgrade"]
api_ctx.var["upstream_connection"] = api_ctx.var["http_connection"]
end
end

if route.value.service_id then
-- core.log.info("matched route: ", core.json.delay_encode(route.value))
local service = service_fetch(route.value.service_id)
Expand Down
6 changes: 4 additions & 2 deletions lua/apisix/admin/proto.lua
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ function _M.delete(id)
for _, route in ipairs(routes) do
if type(route) == "table" and route.value
and route.value.plugins then
return _M.check_proto_used(route.value.plugins, id, "route", route.value.id)
return _M.check_proto_used(route.value.plugins, id, "route",
route.value.id)
end
end
end
Expand All @@ -133,7 +134,8 @@ function _M.delete(id)
for _, service in ipairs(services) do
if type(service) == "table" and service.value
and service.value.plugins then
return _M.check_proto_used(service.value.plugins, id, "service", service.value.id)
return _M.check_proto_used(service.value.plugins, id,
"service", service.value.id)
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lua/apisix/admin/routes.lua
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ local function check_conf(id, conf, need_id)
return nil, {error_msg = "wrong route id"}
end

core.log.info("schema: ", core.schema.route)
core.log.info("schema: ", core.json.delay_encode(core.schema.route))
core.log.info("conf : ", core.json.delay_encode(conf))
local ok, err = core.schema.check(core.schema.route, conf)
if not ok then
Expand Down
43 changes: 31 additions & 12 deletions lua/apisix/core/ctx.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ local setmetatable = setmetatable
local ffi = require("ffi")
local C = ffi.C
local sub_str = string.sub
local rawset = rawset
local ngx_var = ngx.var


ffi.cdef[[
Expand All @@ -19,38 +21,55 @@ local _M = {version = 0.2}

do
local var_methods = {
["method"] = ngx.req.get_method,
["cookie"] = function () return ck:new() end
method = ngx.req.get_method,
cookie = function () return ck:new() end
}

local ngx_var_names = {
upstream_scheme = true,
upstream_host = true,
upstream_upgrade = true,
upstream_connection = true,
upstream_uri = true,
}

local mt = {
__index = function(t, name)
__index = function(t, key)
local val
local method = var_methods[name]
local method = var_methods[key]
if method then
val = method()

elseif C.memcmp(name, "cookie_", 7) == 0 then
local cookie = t["cookie"]
elseif C.memcmp(key, "cookie_", 7) == 0 then
local cookie = t.cookie
if cookie then
local err
val, err = cookie:get(sub_str(name, 8))
val, err = cookie:get(sub_str(key, 8))
if not val then
log.warn("failed to fetch cookie value by name: ",
name, " error: ", err)
log.warn("failed to fetch cookie value by key: ",
key, " error: ", err)
end
end

else
val = get_var(name, t._request)
val = get_var(key, t._request)
end

if val ~= nil then
t[name] = val
rawset(t, key, val)
end

return val
end
end,

__newindex = function(t, key, val)
if ngx_var_names[key] then
ngx_var[key] = val
end

-- log.info("key: ", key, " new val: ", val)
rawset(t, key, val)
end,
}

function _M.set_vars_meta(ctx)
Expand Down
29 changes: 27 additions & 2 deletions lua/apisix/core/schema.lua
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,32 @@ local upstream_schema = {
enum = {"remote_addr"},
},
desc = {type = "string", maxLength = 256},
id = id_schema
id = id_schema,
scheme = {
description = "scheme of upstream",
type = "string",
enum = {"http", "https"},
},
host = {
description = "host of upstream",
type = "string",
},
upgrade = {
description = "upgrade header for upstream",
type = "string",
},
connection = {
description = "connection header for upstream",
type = "string",
},
uri = {
description = "new uri for upstream",
type = "string",
},
enable_websocket = {
description = "enable websocket for request",
type = "boolean",
}
},
required = {"nodes", "type"},
additionalProperties = false,
Expand Down Expand Up @@ -298,7 +323,7 @@ do
if err then
error("invalid route: " .. route)
end
_M.route = cjson.encode(route_t)
_M.route = route_t
end


Expand Down
3 changes: 2 additions & 1 deletion lua/apisix/plugins/grpc-transcode/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ function _M.map_message(field, default_values)
end
request[name] = sub
else
request[name] = get_from_request(name, field_type) or default_values[name] or nil
request[name] = get_from_request(name, field_type)
or default_values[name] or nil
end
end
return request
Expand Down
2 changes: 1 addition & 1 deletion t/core/ctx.t
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ GET /t?a=aaa
--- response_body
cookie_host: nil
--- error_log
failed to fetch cookie value by name: cookie_host error: no cookie found in the current request
failed to fetch cookie value by key: cookie_host error: no cookie found in the current request



Expand Down
18 changes: 18 additions & 0 deletions t/lib/server.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,24 @@ function _M.sleep1()
ngx.say("ok")
end

function _M.uri()
-- ngx.sleep(1)
ngx.say("uri: ", ngx.var.uri)
local headers = ngx.req.get_headers()
for k, v in pairs(headers) do
ngx.say(k, ": ", v)
end
end

function _M.old_uri()
-- ngx.sleep(1)
ngx.say("uri: ", ngx.var.uri)
local headers = ngx.req.get_headers()
for k, v in pairs(headers) do
ngx.say(k, ": ", v)
end
end


function _M.opentracing()
ngx.say("opentracing")
Expand Down
116 changes: 116 additions & 0 deletions t/node/upstream-more-options.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use t::APISix 'no_plan';

repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();

run_tests();

__DATA__

=== TEST 1: set route(more upstream options)
--- 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": "/old_uri",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1
},
"scheme": "http",
"host": "foo.com",
"upgrade": "upgrade.com",
"connection": "connection.com",
"uri": "/uri"
}
}]]
)

if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]



=== TEST 2: hit routes
--- request
GET /old_uri
--- response_body
uri: /uri
host: foo.com
upgrade: upgrade.com
connection: connection.com
x-real-ip: 127.0.0.1
--- no_error_log
[error]



=== TEST 3: set route(enable websocket)
--- 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": "/old_uri",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1
},
"scheme": "http",
"host": "foo.com",
"enable_websocket": true,
"uri": "/uri"
}
}]]
)

if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]



=== TEST 4: hit routes
--- more_headers
upgrade: upgrade
connection: close
--- request
GET /old_uri
--- response_body
uri: /uri
host: foo.com
upgrade: upgrade
connection: close
x-real-ip: 127.0.0.1
--- no_error_log
[error]