@@ -868,3 +868,171 @@ v1 nodes: 2
868868dev nodes: 0
869869--- no_error_log
870870[error]
871+
872+
873+
874+ === TEST 17: fetch_services_from_server tolerates services without Meta (preserve_metadata=true)
875+ --- yaml_config
876+ apisix:
877+ node_listen: 1984
878+ deployment:
879+ role: data_plane
880+ role_data_plane:
881+ config_provider: yaml
882+ discovery:
883+ consul:
884+ servers:
885+ - "http://127.0.0.1:8500"
886+ timeout:
887+ connect: 1000
888+ read: 1000
889+ wait: 60
890+ weight: 1
891+ fetch_interval: 1
892+ keepalive: true
893+ --- apisix_yaml
894+ routes: []
895+ #END
896+ --- config
897+ location /consul1 {
898+ rewrite ^/consul1/(.*) /v1/agent/service/$1 break;
899+ proxy_pass http://127.0.0.1:8500;
900+ }
901+ location /t {
902+ content_by_lua_block {
903+ -- register a consul service WITHOUT a Meta field; consul returns
904+ -- "Meta": null which cjson decodes as a userdata sentinel.
905+ -- Before the fix, fetch_services_from_server crashed with
906+ -- "bad argument #1 to 'next' (table expected, got userdata)"
907+ -- on the very first scrape and never recovered.
908+ local httpc = require("resty.http").new()
909+ local deregister = function()
910+ local res, err = httpc:request_uri(
911+ "http://127.0.0.1:1984/consul1/deregister/svc_no_meta_1",
912+ { method = "PUT" }
913+ )
914+ if not res or res.status ~= 200 then
915+ ngx.log(ngx.WARN, "deregister failed: ", err or res.status)
916+ end
917+ end
918+ local register = function(body)
919+ local res, err = httpc:request_uri(
920+ "http://127.0.0.1:1984/consul1/register",
921+ { method = "PUT", body = body }
922+ )
923+ if not res or res.status ~= 200 then
924+ ngx.say("register failed: ", err or res.status)
925+ return false
926+ end
927+ return true
928+ end
929+ deregister()
930+ if not register('{"ID":"svc_no_meta_1","Name":"service_no_meta",'
931+ .. '"Address":"127.0.0.1","Port":30511}') then
932+ return
933+ end
934+
935+ local consul_client = require("apisix.discovery.consul.client")
936+ local servers = consul_client.format_consul_params({
937+ servers = {"http://127.0.0.1:8500"},
938+ timeout = {connect = 2000, read = 2000, wait = 60},
939+ weight = 1,
940+ keepalive = true,
941+ fetch_interval = 3,
942+ })
943+
944+ local up, err = consul_client.fetch_services_from_server(servers[1], {
945+ default_weight = 1,
946+ preserve_metadata = true,
947+ key_builder = function(name) return "no_meta_test/" .. name end,
948+ })
949+ if err then
950+ ngx.say("err: ", err)
951+ deregister()
952+ return
953+ end
954+
955+ local nodes = up and up["no_meta_test/service_no_meta"]
956+ if not nodes or #nodes == 0 then
957+ ngx.say("no nodes returned")
958+ deregister()
959+ return
960+ end
961+ ngx.say("nodes: ", #nodes)
962+ ngx.say("metadata: ", tostring(nodes[1].metadata))
963+
964+ deregister()
965+ }
966+ }
967+ --- request
968+ GET /t
969+ --- error_code: 200
970+ --- response_body
971+ nodes: 1
972+ metadata: nil
973+ --- no_error_log
974+ [error]
975+
976+
977+
978+ === TEST 18: route-level E2E — consul service without Meta does not crash discovery
979+ --- yaml_config
980+ apisix:
981+ node_listen: 1984
982+ deployment:
983+ role: data_plane
984+ role_data_plane:
985+ config_provider: yaml
986+ discovery:
987+ consul:
988+ servers:
989+ - "http://127.0.0.1:8500"
990+ timeout:
991+ connect: 1000
992+ read: 1000
993+ wait: 60
994+ weight: 1
995+ fetch_interval: 3
996+ keepalive: true
997+ default_service:
998+ host: "127.0.0.1"
999+ port: 20999
1000+ --- apisix_yaml
1001+ routes:
1002+ -
1003+ uri: /hello
1004+ upstream:
1005+ service_name: service_no_meta
1006+ discovery_type: consul
1007+ type: roundrobin
1008+ #END
1009+ --- config
1010+ location /v1/agent {
1011+ proxy_pass http://127.0.0.1:8500;
1012+ }
1013+ location /sleep {
1014+ content_by_lua_block {
1015+ local args = ngx.req.get_uri_args()
1016+ local sec = args.sec or "2"
1017+ ngx.sleep(tonumber(sec))
1018+ ngx.say("ok")
1019+ }
1020+ }
1021+ --- timeout: 6
1022+ --- request eval
1023+ [
1024+ "GET /hello",
1025+ "PUT /v1/agent/service/register\n" . "{\"ID\":\"svc_no_meta_e2e\",\"Name\":\"service_no_meta\",\"Address\":\"127.0.0.1\",\"Port\":30511}",
1026+ "GET /sleep?sec=5",
1027+ "GET /hello",
1028+ "PUT /v1/agent/service/deregister/svc_no_meta_e2e",
1029+ ]
1030+ --- response_body_like eval
1031+ [
1032+ qr/missing consul services\n/,
1033+ qr//,
1034+ qr/ok\n/,
1035+ qr/server 1\n/,
1036+ qr//,
1037+ ]
1038+ --- ignore_error_log
0 commit comments