feat: add nacos support#3820
Conversation
add nacos support
spacewander
left a comment
There was a problem hiding this comment.
Please add test under t/discovery.
|
Please make sure it can pass the lint. |
| discovery: | ||
| nacos: | ||
| host: | ||
| - "http://192.168.33.1:8848" |
There was a problem hiding this comment.
Why don't mention the user / password feature?
There was a problem hiding this comment.
Because Nacos not need login yet.
| }, | ||
| fetch_interval = {type = "integer", minimum = 1, default = 30}, | ||
| prefix = {type = "string"}, | ||
| weight = {type = "integer", minimum = 0}, |
There was a problem hiding this comment.
Missing default for weight?
And the minimum weight should be 1.
There was a problem hiding this comment.
OK,I copy from eureka.
|
|
||
| local httpc = http.new() | ||
| local timeout = local_conf.discovery.nacos.timeout | ||
| local connect_timeout = timeout and timeout.connect or 2000 |
There was a problem hiding this comment.
The default value will be injected via schema check. We don't need to assign it.
| log.info("default_weight:", default_weight, ".") | ||
| local fetch_interval = local_conf.discovery.nacos.fetch_interval or 30 | ||
| log.info("fetch_interval:", fetch_interval, ".") | ||
| service_list_path = local_conf.discovery.nacos.service_list_path or |
There was a problem hiding this comment.
Where should I configure service_list_path? There is neither schema nor doc for it.
| log.info("fetch_interval:", fetch_interval, ".") | ||
| service_list_path = local_conf.discovery.nacos.service_list_path or | ||
| 'ns/service/list?pageNo=1&pageSize=20' | ||
| instance_list_path = local_conf.discovery.nacos.instance_list_path or |
| end | ||
|
|
||
| local up_apps = core.table.new(0, 0) | ||
| local data = get_url(base_uri,basic_auth,service_list_path) |
There was a problem hiding this comment.
Need space after the comma.
And please check the returned value of get_url.
| log.info("nacos uri:", request_uri, ".") | ||
| local url = request_uri .. path | ||
| local headers = core.table.new(0, 5) | ||
| headers['Connection'] = 'Keep-Alive' |
There was a problem hiding this comment.
We don't need it for HTTP 1.1
| local function request(request_uri, basic_auth, method, path, query, body) | ||
| log.info("nacos uri:", request_uri, ".") | ||
| local url = request_uri .. path | ||
| local headers = core.table.new(0, 5) |
| if local_conf.discovery.nacos.prefix then | ||
| url = url .. local_conf.discovery.nacos.prefix | ||
| end | ||
| if string_sub(url, #url) ~= "/" then |
There was a problem hiding this comment.
Better to use str_byte(uri, #uri) == str_byte("/")
| fetch_interval: 30 # default 30 sec | ||
| weight: 100 # default 100 | ||
| timeout: | ||
| connect: 2000 # default 2000 |
There was a problem hiding this comment.
Better to mention the unit is ms.
| --- pipelined_requests eval | ||
| [ | ||
| "POST /nacos/v1/ns/instance?port=18001&healthy=true&ip=127.0.0.1&weight=1.0&serviceName=APISIX-NACOS&encoding=GBK&enabled=true", | ||
| "DELETE /nacos/v1/ns/service?serviceName=APISIX-NACOS", |
There was a problem hiding this comment.
If has no data,delete return code is 400,if has data,delete return code is 200.
There was a problem hiding this comment.
But it is not the feature of APISIX. We don't need to test nacos itself.
| #END | ||
| --- request | ||
| GET /hello | ||
| --- error_code: 200 |
There was a problem hiding this comment.
We need to show if server 1 or server 2 is hit.
And we need a test to show the default weight
| ```shell | ||
| $ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d ' | ||
| { | ||
| "uri": "/nacos/**", |
| docker run --rm --name consul_2 -d -p 8600:8500 consul:1.7 consul agent -server -bootstrap-expect=1 -client 0.0.0.0 -log-level info -data-dir=/consul/data | ||
|
|
||
| # start nacos server | ||
| docker run --rm --name nacos_1 -d --env PREFER_HOST_MODE=hostname --env MODE=standalone --env JVM_XMS=512m --env JVM_XMX=512m --env JVM_XMN=256m -p8848:8848 nacos/nacos-server:latest |
There was a problem hiding this comment.
We need test the user/password feature.
There was a problem hiding this comment.
If add NACOS_AUTH_ENABLE=true, file nacos.t need login too.
Could you give me a t file login demo?
There was a problem hiding this comment.
You can use different conf in different tests, one for auth success and another for auth fail.
There was a problem hiding this comment.
How to check nacos in discovery plugin whether authed?
There was a problem hiding this comment.
If the auth enable nacos can be used, the auth is successful.
There was a problem hiding this comment.
But if nacos start with auth mode,in nacos.t add services to nacos need send auth token.
How can i save auth token in nacos.t?
There was a problem hiding this comment.
You can export the auth function: https://github.com/apache/apisix/pull/3820/files#diff-46fd008790f9ea29612a92ca5c94212ae43c81ab6b902ef3014d3d6b4bdfc5b3R202
and call it in the test file.
| } | ||
|
|
||
|
|
||
| local function str_split (inputstr, sep) |
There was a problem hiding this comment.
Should use existent API:
apisix/apisix/plugins/proxy-cache.lua
Line 194 in e9a59ac
| prefix = {type = "string", default = "/nacos/v1/"}, | ||
| auth_path = {type = "string", default = "auth/login"}, | ||
| service_list_path = {type = "string", default = "ns/service/list?pageNo=1&pageSize=20"}, | ||
| instance_list_path = {type = "string", default = "ns/instance/list?serviceName="}, |
There was a problem hiding this comment.
Need a test to check the user-defined paths.
BTW, in what situation people need to redefine the paths?
There was a problem hiding this comment.
When Nacos api change.
There was a problem hiding this comment.
@benx203
I think we can remove it now and add it if needed.
We need to add a doc and test for this feature if you insist to keep it.
(I don't recommend to do that as this PR is big enough)
| fetch_interval = {type = "integer", minimum = 1, default = 30}, | ||
| prefix = {type = "string", default = "/nacos/v1/"}, | ||
| auth_path = {type = "string", default = "auth/login"}, | ||
| service_list_path = {type = "string", default = "ns/service/list?pageNo=1&pageSize=20"}, |
There was a problem hiding this comment.
Only return the first 20 services is not a good idea.
We need to iterate the upstreams and build a service list from those that have nacos discovery_type.
Like this:
Lines 144 to 149 in e9a59ac
You might need some lazy load trick to break the dependent cycle.
| end | ||
|
|
||
| for _, host in ipairs(data.hosts) do | ||
| if tostring(host.valid) == 'true' and |
There was a problem hiding this comment.
I set up the environment and debug it myself.
Here is the host: {"enabled":true,"instanceHeartBeatTimeOut":15000,"ipDeleteTimeout":30000,"instanceHeartBeatInterval":5000,"metadata":{"preserved.register.source":"SPRING_CLOUD"},"port":18001,"serviceName":"DEFAULT_GROUP@@APISIX-NACOS","instanceId":"192.168.65.3#18001#DEFAULT#DEFAULT_GROUP@@APISIX-NACOS","healthy":true,"ip":"192.168.65.3","ephemeral":true,"clusterName":"DEFAULT","weight":1}
There is not valid field. The response doesn't match their API doc: https://nacos.io/en-us/docs/open-api.html
I am not sure if it is because the latest Nacos has changed the API. Maybe we need to use the tagged nacos image 2.0.0 instead of the latest one?
| nohup docker network rm nacos_net > /dev/null 2>&1 & | ||
| nohup docker network create nacos_net > /dev/null 2>&1 & | ||
| # nacos no auth server - for test no auth | ||
| docker run --rm -d --name nacos_no_auth --network nacos_net --hostname nacos2 --env NACOS_SERVERS="nacos1:8848 nacos2:8848" --env PREFER_HOST_MODE=hostname --env MODE=cluster --env EMBEDDED_STORAGE=embedded --env JVM_XMS=512m --env JVM_XMX=512m --env JVM_XMN=256m -p8858:8848 nacos/nacos-server:latest |
There was a problem hiding this comment.
Would it be better to use nacos/nacos-server:2.0.0?
There was a problem hiding this comment.
The nacos version should be 1.4.1,2.0.0 just released few days ago.
There was a problem hiding this comment.
@benx203
Why can't we support 2.0.0 directly? Is 2.0.0 incompatible with 1.4.1?
There was a problem hiding this comment.
I think better way is support both 2.0.0 and 1.4.1.
Maybe support 2.0.0 later?
| rm -rf tmp | ||
| mkdir tmp | ||
| cd tmp | ||
| wget https://raw.githubusercontent.com/benx203/nacos-test-service/main/spring-nacos-1.0-SNAPSHOT.jar |
There was a problem hiding this comment.
@benx203
Would you also submit the Java code to https://github.com/benx203/nacos-test-service? Thanks!
| for _, host in ipairs(data.hosts) do | ||
| if tostring(host.valid) == 'true' and | ||
| tostring(host.healthy) == 'true' and | ||
| tostring(host.enabled) == 'true' then |
There was a problem hiding this comment.
One more question: why we need to filter the result according to those fields?
There was a problem hiding this comment.
If query all records,need to filter.
But now should not need any more.
Signed-off-by: spacewander <[email protected]>
Signed-off-by: spacewander <[email protected]>
|
@benx203 |
|
@spacewander |
Signed-off-by: spacewander <[email protected]>
Signed-off-by: spacewander <[email protected]>
Signed-off-by: spacewander <[email protected]>
| type = "array", | ||
| minItems = 1, | ||
| items = { | ||
| type = "string", |
There was a problem hiding this comment.
add a pattern to limit the string to the host format
| }, | ||
| }, | ||
| fetch_interval = {type = "integer", minimum = 1, default = 30}, | ||
| prefix = {type = "string", default = "/nacos/v1/"}, |
|
|
||
|
|
||
| local _M = { | ||
| version = 0.1, |
There was a problem hiding this comment.
this version is useless, we can drop it
| local url = request_uri .. path | ||
| log.info("request url:", url) | ||
| local headers = core.table.new(0, 0) | ||
| headers['Accept'] = 'application/json' |
There was a problem hiding this comment.
for the string object, I think we use ", it is easier for reading.
headers["Accept"] = "application/json"
There was a problem hiding this comment.
and please fix the similar points
|
|
||
|
|
||
| local function get_token_param(base_uri, username, password) | ||
| if username and password then |
There was a problem hiding this comment.
better style:
if not username or not password then
return ""
end
...|
|
||
| local function get_token_param(base_uri, username, password) | ||
| if username and password then | ||
| local data, err = post_url(base_uri, auth_path .. "?username=" .. username |
There was a problem hiding this comment.
I think we should call ngx.encode_args for username and password
|
|
||
|
|
||
| local function iter_and_add_service(services, values) | ||
| if not values then |
| local host = local_conf.discovery.nacos.host | ||
| -- TODO Add health check to get healthy nodes. | ||
| local url = host[math_random(#host)] | ||
| local auth_idx = str_find(url, "@") |
There was a problem hiding this comment.
we'd better use the plain text model, better performance.
|
|
||
| function _M.nodes(service_name) | ||
| local logged = false | ||
| while not applications do |
There was a problem hiding this comment.
I think we need to set a maximum waiting time , eg: 5 seconds
|
@benx203 thanks for your contribution. |
OK,i will try,thank you all. |
|
|
||
|
|
||
| function _M.nodes(service_name) | ||
| local logged = false |
There was a problem hiding this comment.
The original code is good. We just need to set a 5s limitation.
There was a problem hiding this comment.
The lazy init is important as the sync is slow.
There was a problem hiding this comment.
OK,i rollback the code.
| local host = local_conf.discovery.nacos.host | ||
| -- TODO Add health check to get healthy nodes. | ||
| local url = host[math_random(#host)] | ||
| local auth_idx = str_find(url, '@', 1, true) |
There was a problem hiding this comment.
The core.string.find is already the plain string find... 😅
Not all the suggestion from the reviewer is correct.
| local values = get_upstreams() | ||
| iter_and_add_service(services, values) | ||
| values = get_routes() | ||
| iter_and_add_service(services, values) |
There was a problem hiding this comment.
By the way,Are there 'discovery_type' config in service and route?
@spacewander
There was a problem hiding this comment.
Those can have embedded upstream field.
feat:add nacos support