diff --git a/docs/cn/client.md b/docs/cn/client.md index 6da1690907..076549fb75 100755 --- a/docs/cn/client.md +++ b/docs/cn/client.md @@ -141,6 +141,32 @@ BNS是百度内常用的命名服务,比如bns://rdev.matrix.all,其中"bns" 如果consul不可访问,服务可自动降级到file naming service获取服务列表。此功能默认关闭,可通过设置-consul\_enable\_degrade\_to\_file\_naming\_service来打开。服务列表文件目录通过-consul \_file\_naming\_service\_dir来设置,使用service-name作为文件名。该文件可通过consul-template生成,里面会保存consul不可用之前最新的下游服务节点。当consul恢复时可自动恢复到consul naming service。 + +### nacos://\ + +NacosNamingService使用[Open-Api](https://nacos.io/zh-cn/docs/open-api.html)定时从nacos获取服务列表。 +NacosNamingService支持[简单鉴权](https://nacos.io/zh-cn/docs/auth.html)。 + +``是一个http uri query,具体参数参见`/nacos/v1/ns/instance/list`文档。 +注意:``需要urlencode。 +``` +nacos://serviceName=test&groupName=g&namespaceId=n&clusters=c&healthyOnly=true +``` + +NacosNamingService拉取列表的时间间隔为`/nacos/v1/ns/instance/list`api返回的`cacheMillis`。 +NacosNamingService只支持整形的权重值。 + +| GFlags | 描述 | 默认值 | +| ---------------------------------- | -------------------------- | ---------------------------- | +| nacos_address | nacos http url | "" | +| nacos_service_discovery_path | nacos服务发现路径 | "/nacos/v1/ns/instance/list" | +| nacos_service_auth_path | nacos登陆路径 | "/nacos/v1/auth/login" | +| nacos_service_timeout_ms | 连接nacos超时时间(毫秒) | 200 | +| nacos_username | 用户名(urlencode编码) | "" | +| nacos_password | 密码(urlencode编码) | "" | +| nacos_load_balancer | nacos集群的负载均衡 | "rr" | + + ### 更多命名服务 用户可以通过实现brpc::NamingService来对接更多命名服务,具体见[这里](https://github.com/brpc/brpc/blob/master/docs/cn/load_balancing.md#%E5%91%BD%E5%90%8D%E6%9C%8D%E5%8A%A1) diff --git a/docs/en/client.md b/docs/en/client.md index dac05b41ab..75cb504b03 100644 --- a/docs/en/client.md +++ b/docs/en/client.md @@ -139,6 +139,32 @@ If the server list returned by the consul does not follow [response format](http If consul is not accessible, the naming service can be automatically downgraded to file naming service. This feature is turned off by default and can be turned on by setting -consul\_enable\_degrade\_to\_file\_naming\_service. After downgrading, in the directory specified by -consul\_file\_naming\_service\_dir, the file whose name is the service-name will be used. This file can be generated by the consul-template, which holds the latest server list before the consul is unavailable. The consul naming service is automatically restored when consul is restored. + +### nacos://\ + +NacosNamingService gets a list of servers from nacos periodically by [Open-Api](https://nacos.io/en-us/docs/open-api.html). +NacosNamingService supports [simple authentication](https://nacos.io/en-us/docs/auth.html). + +`` is a http uri query,For more detail, refer to `/nacos/v1/ns/instance/list` api document. +NOTE: `` must be url-encoded. +``` +nacos://serviceName=test&groupName=g&namespaceId=n&clusters=c&healthyOnly=true +``` + +The server list is cached for `cacheMillis` milliseconds as specified in the response of `/nacos/v1/ns/instance/list` api. +NOTE: The value of server weight must be an integer. + +| GFlags | Description | Default value | +| ---------------------------------- | ------------------------------------ | ---------------------------- | +| nacos_address | nacos http url | "" | +| nacos_service_discovery_path | path for discovery | "/nacos/v1/ns/instance/list" | +| nacos_service_auth_path | path for login | "/nacos/v1/auth/login" | +| nacos_service_timeout_ms | timeout for connecting to nacos(ms) | 200 | +| nacos_username | url-encoded username | "" | +| nacos_password | url-encoded password | "" | +| nacos_load_balancer | load balancer for nacos clusters | "rr" | + + ### More naming services User can extend to more naming services by implementing brpc::NamingService, check [this link](https://github.com/brpc/brpc/blob/master/docs/cn/load_balancing.md#%E5%91%BD%E5%90%8D%E6%9C%8D%E5%8A%A1) for details. diff --git a/src/brpc/global.cpp b/src/brpc/global.cpp index ced8a11cbc..af8dac5c27 100755 --- a/src/brpc/global.cpp +++ b/src/brpc/global.cpp @@ -38,6 +38,7 @@ #include "brpc/policy/remote_file_naming_service.h" #include "brpc/policy/consul_naming_service.h" #include "brpc/policy/discovery_naming_service.h" +#include "brpc/policy/nacos_naming_service.h" // Load Balancers #include "brpc/policy/round_robin_load_balancer.h" @@ -135,6 +136,7 @@ struct GlobalExtensions { RemoteFileNamingService rfns; ConsulNamingService cns; DiscoveryNamingService dcns; + NacosNamingService nns; RoundRobinLoadBalancer rr_lb; WeightedRoundRobinLoadBalancer wrr_lb; @@ -358,6 +360,7 @@ static void GlobalInitializeOrDieImpl() { NamingServiceExtension()->RegisterOrDie("remotefile", &g_ext->rfns); NamingServiceExtension()->RegisterOrDie("consul", &g_ext->cns); NamingServiceExtension()->RegisterOrDie("discovery", &g_ext->dcns); + NamingServiceExtension()->RegisterOrDie("nacos", &g_ext->nns); // Load Balancers LoadBalancerExtension()->RegisterOrDie("rr", &g_ext->rr_lb); diff --git a/src/brpc/periodic_naming_service.cpp b/src/brpc/periodic_naming_service.cpp index e113624199..5e10977997 100644 --- a/src/brpc/periodic_naming_service.cpp +++ b/src/brpc/periodic_naming_service.cpp @@ -29,6 +29,10 @@ DEFINE_int32(ns_access_interval, 5, "Wait so many seconds before next access to naming service"); BRPC_VALIDATE_GFLAG(ns_access_interval, PositiveInteger); +int PeriodicNamingService::GetNamingServiceAccessIntervalMs() const { + return std::max(FLAGS_ns_access_interval, 1) * 1000; +} + int PeriodicNamingService::RunNamingService( const char* service_name, NamingServiceActions* actions) { std::vector servers; @@ -47,7 +51,7 @@ int PeriodicNamingService::RunNamingService( actions->ResetServers(servers); } - if (bthread_usleep(std::max(FLAGS_ns_access_interval, 1) * 1000000L) < 0) { + if (bthread_usleep(GetNamingServiceAccessIntervalMs() * 1000UL) < 0) { if (errno == ESTOP) { RPC_VLOG << "Quit NamingServiceThread=" << bthread_self(); return 0; diff --git a/src/brpc/periodic_naming_service.h b/src/brpc/periodic_naming_service.h index b27033f720..8216ddfdbc 100644 --- a/src/brpc/periodic_naming_service.h +++ b/src/brpc/periodic_naming_service.h @@ -29,6 +29,8 @@ class PeriodicNamingService : public NamingService { virtual int GetServers(const char *service_name, std::vector* servers) = 0; + virtual int GetNamingServiceAccessIntervalMs() const; + int RunNamingService(const char* service_name, NamingServiceActions* actions); }; diff --git a/src/brpc/policy/nacos_naming_service.cpp b/src/brpc/policy/nacos_naming_service.cpp new file mode 100644 index 0000000000..0431626ea5 --- /dev/null +++ b/src/brpc/policy/nacos_naming_service.cpp @@ -0,0 +1,289 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +#include "nacos_naming_service.h" + +#include + +#include + +#include "brpc/http_status_code.h" +#include "brpc/log.h" +#include "butil/iobuf.h" +#include "butil/logging.h" +#include "butil/third_party/rapidjson/document.h" + +namespace brpc { +namespace policy { + +DEFINE_string(nacos_address, "", + "The query string of request nacos for discovering service."); +DEFINE_string(nacos_service_discovery_path, "/nacos/v1/ns/instance/list", + "The url path for discovering service."); +DEFINE_string(nacos_service_auth_path, "/nacos/v1/auth/login", + "The url path for authentiction."); +DEFINE_int32(nacos_connect_timeout_ms, 200, + "Timeout for creating connections to nacos in milliseconds"); +DEFINE_string(nacos_username, "", "nacos username"); +DEFINE_string(nacos_password, "", "nacos password"); +DEFINE_string(nacos_load_balancer, "rr", "nacos load balancer name"); + +int NacosNamingService::Connect() { + ChannelOptions opt; + opt.protocol = PROTOCOL_HTTP; + opt.connect_timeout_ms = FLAGS_nacos_connect_timeout_ms; + const int ret = _channel.Init(FLAGS_nacos_address.c_str(), + FLAGS_nacos_load_balancer.c_str(), &opt); + if (ret != 0) { + LOG(ERROR) << "Fail to init channel to nacos at " + << FLAGS_nacos_address; + } + return ret; +} + +int NacosNamingService::RefreshAccessToken(const char *service_name) { + Controller cntl; + cntl.http_request().uri() = FLAGS_nacos_service_auth_path; + cntl.http_request().set_method(brpc::HttpMethod::HTTP_METHOD_POST); + cntl.http_request().set_content_type("application/x-www-form-urlencoded"); + + auto &buf = cntl.request_attachment(); + buf.append("username="); + buf.append(FLAGS_nacos_username); + buf.append("&password="); + buf.append(FLAGS_nacos_password); + + _channel.CallMethod(nullptr, &cntl, nullptr, nullptr, nullptr); + if (cntl.Failed()) { + LOG(ERROR) << "Fail to access " << FLAGS_nacos_service_auth_path << ": " + << cntl.ErrorText(); + return -1; + } + + BUTIL_RAPIDJSON_NAMESPACE::Document doc; + if (doc.Parse(cntl.response_attachment().to_string().c_str()) + .HasParseError()) { + LOG(ERROR) << "Failed to parse nacos auth response"; + return -1; + } + if (!doc.IsObject()) { + LOG(ERROR) << "The nacos's auth response for " << service_name + << " is not a json object"; + return -1; + } + + auto iter = doc.FindMember("accessToken"); + if (iter != doc.MemberEnd() && iter->value.IsString()) { + _access_token = iter->value.GetString(); + } else { + LOG(ERROR) << "The nacos's auth response for " << service_name + << " has no accessToken field"; + return -1; + } + + auto iter_ttl = doc.FindMember("tokenTtl"); + if (iter_ttl != doc.MemberEnd() && iter_ttl->value.IsInt()) { + _token_expire_time = time(NULL) + iter_ttl->value.GetInt() - 10; + } else { + _token_expire_time = 0; + } + + return 0; +} + +int NacosNamingService::GetServerNodes(const char *service_name, + bool token_changed, + std::vector *nodes) { + if (_nacos_url.empty() || token_changed) { + _nacos_url = FLAGS_nacos_service_discovery_path; + _nacos_url += "?"; + if (!_access_token.empty()) { + _nacos_url += "accessToken=" + _access_token; + _nacos_url += "&"; + } + _nacos_url += service_name; + } + + Controller cntl; + cntl.http_request().uri() = _nacos_url; + _channel.CallMethod(nullptr, &cntl, nullptr, nullptr, nullptr); + if (cntl.Failed()) { + LOG(ERROR) << "Fail to access " << _nacos_url << ": " + << cntl.ErrorText(); + return -1; + } + if (cntl.http_response().status_code() != HTTP_STATUS_OK) { + LOG(ERROR) << "Failed to request nacos, http status code: " + << cntl.http_response().status_code(); + return -1; + } + + BUTIL_RAPIDJSON_NAMESPACE::Document doc; + if (doc.Parse(cntl.response_attachment().to_string().c_str()) + .HasParseError()) { + LOG(ERROR) << "Failed to parse nacos response"; + return -1; + } + if (!doc.IsObject()) { + LOG(ERROR) << "The nacos's response for " << service_name + << " is not a json object"; + return -1; + } + + auto it_hosts = doc.FindMember("hosts"); + if (it_hosts == doc.MemberEnd()) { + LOG(ERROR) << "The nacos's response for " << service_name + << " has no hosts member"; + return -1; + } + auto &hosts = it_hosts->value; + if (!hosts.IsArray()) { + LOG(ERROR) << "hosts member in nacos response is not an array"; + return -1; + } + + std::set presence; + for (auto it = hosts.Begin(); it != hosts.End(); ++it) { + auto &host = *it; + if (!host.IsObject()) { + LOG(ERROR) << "host member in nacos response is not an object"; + continue; + } + + auto it_ip = host.FindMember("ip"); + if (it_ip == host.MemberEnd() || !it_ip->value.IsString()) { + LOG(ERROR) << "host in nacos response has not ip"; + continue; + } + auto &ip = it_ip->value; + + auto it_port = host.FindMember("port"); + if (it_port == host.MemberEnd() || !it_port->value.IsInt()) { + LOG(ERROR) << "host in nacos response has not port"; + continue; + } + auto &port = it_port->value; + + auto it_enabled = host.FindMember("enabled"); + if (it_enabled == host.MemberEnd() || !(it_enabled->value.IsBool()) || + !(it_enabled->value.GetBool())) { + LOG(INFO) << "nacos " << ip.GetString() << ":" << port.GetInt() + << " is not enable"; + continue; + } + + auto it_healthy = host.FindMember("healthy"); + if (it_healthy == host.MemberEnd() || !(it_healthy->value.IsBool()) || + !(it_healthy->value.GetBool())) { + LOG(INFO) << "nacos " << ip.GetString() << ":" << port.GetInt() + << " is not healthy"; + continue; + } + + butil::EndPoint end_point; + if (str2endpoint(ip.GetString(), port.GetUint(), &end_point) != 0) { + LOG(ERROR) << "ncos service with illegal address or port: " + << ip.GetString() << ":" << port.GetUint(); + continue; + } + + ServerNode node(end_point); + auto it_weight = host.FindMember("weight"); + if (it_weight != host.MemberEnd() && it_weight->value.IsNumber()) { + node.tag = + std::to_string(static_cast(it_weight->value.GetDouble())); + } + + presence.insert(node); + } + + nodes->reserve(presence.size()); + nodes->assign(presence.begin(), presence.end()); + + if (nodes->empty() && hosts.Size() != 0) { + LOG(ERROR) << "All service about " << service_name + << " from nacos is invalid, refuse to update servers"; + return -1; + } + + RPC_VLOG << "Got " << nodes->size() + << (nodes->size() > 1 ? " servers" : " server") << " from " + << service_name; + + auto it_cache = doc.FindMember("cacheMillis"); + if (it_cache != doc.MemberEnd() && it_cache->value.IsInt64()) { + _cache_ms = it_cache->value.GetInt64(); + } + + return 0; +} + +NacosNamingService::NacosNamingService() + : _nacos_connected(false), _cache_ms(-1), _token_expire_time(0) {} + +int NacosNamingService::GetNamingServiceAccessIntervalMs() const { + if (0 < _cache_ms) { + return _cache_ms; + } + return PeriodicNamingService::GetNamingServiceAccessIntervalMs(); +} + +int NacosNamingService::GetServers(const char *service_name, + std::vector *servers) { + if (!_nacos_connected) { + const int ret = Connect(); + if (0 == ret) { + _nacos_connected = true; + } else { + return ret; + } + } + + const bool authentiction_enabled = + !FLAGS_nacos_username.empty() && !FLAGS_nacos_password.empty(); + const bool has_invalid_access_token = + _access_token.empty() || + (0 < _token_expire_time && _token_expire_time <= time(NULL)); + bool token_changed = false; + + if (authentiction_enabled && has_invalid_access_token) { + const int ret = RefreshAccessToken(service_name); + if (ret == 0) { + token_changed = true; + } else { + return ret; + } + } + + servers->clear(); + return GetServerNodes(service_name, token_changed, servers); +} + +void NacosNamingService::Describe(std::ostream &os, + const DescribeOptions &) const { + os << "nacos"; + return; +} + +NamingService *NacosNamingService::New() const { + return new NacosNamingService; +} + +void NacosNamingService::Destroy() { delete this; } + +} // namespace policy +} // namespace brpc diff --git a/src/brpc/policy/nacos_naming_service.h b/src/brpc/policy/nacos_naming_service.h new file mode 100644 index 0000000000..dcd7713617 --- /dev/null +++ b/src/brpc/policy/nacos_naming_service.h @@ -0,0 +1,67 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +#ifndef BRPC_POLICY_NACOS_NAMING_SERVICE_H +#define BRPC_POLICY_NACOS_NAMING_SERVICE_H + +#include + +#include +#include + +#include "brpc/channel.h" +#include "brpc/periodic_naming_service.h" +#include "brpc/server_node.h" + +namespace brpc { +namespace policy { + +// Acquire server list from nacos +class NacosNamingService : public PeriodicNamingService { +public: + NacosNamingService(); + + int GetServers(const char* service_name, + std::vector* servers) override; + + int GetNamingServiceAccessIntervalMs() const override; + + void Describe(std::ostream& os, const DescribeOptions&) const override; + + NamingService* New() const override; + + void Destroy() override; + +private: + int Connect(); + int RefreshAccessToken(const char* service_name); + int GetServerNodes(const char* service_name, bool token_changed, + std::vector* nodes); + +private: + brpc::Channel _channel; + std::string _nacos_url; + std::string _access_token; + bool _nacos_connected; + long _cache_ms; + time_t _token_expire_time; +}; + +} // namespace policy +} // namespace brpc + +#endif // BRPC_POLICY_NACOS_NAMING_SERVICE_H diff --git a/test/brpc_naming_service_unittest.cpp b/test/brpc_naming_service_unittest.cpp index e6a62c85d6..43ac9f474a 100644 --- a/test/brpc_naming_service_unittest.cpp +++ b/test/brpc_naming_service_unittest.cpp @@ -19,8 +19,10 @@ #include #include #include "butil/string_printf.h" +#include "butil/strings/string_split.h" #include "butil/files/temp_file.h" #include "bthread/bthread.h" +#include "brpc/http_status_code.h" #ifdef BAIDU_INTERNAL #include "brpc/policy/baidu_naming_service.h" #endif @@ -30,6 +32,7 @@ #include "brpc/policy/list_naming_service.h" #include "brpc/policy/remote_file_naming_service.h" #include "brpc/policy/discovery_naming_service.h" +#include "brpc/policy/nacos_naming_service.h" #include "echo.pb.h" #include "brpc/server.h" @@ -45,6 +48,9 @@ DECLARE_string(consul_service_discovery_url); DECLARE_string(discovery_api_addr); DECLARE_string(discovery_env); DECLARE_int32(discovery_renew_interval_s); +DECLARE_string(nacos_address); +DECLARE_string(nacos_username); +DECLARE_string(nacos_password); } // policy } // brpc @@ -697,4 +703,139 @@ TEST(NamingServiceTest, discovery_sanity) { } } +class NacosNamingServiceImpl : public test::NacosNamingService { +public: + void Login(google::protobuf::RpcController* cntl_base, + const test::HttpRequest*, test::HttpResponse*, + google::protobuf::Closure* done) override { + brpc::ClosureGuard done_guard(done); + brpc::Controller* cntl = static_cast(cntl_base); + + butil::StringPairs user; + butil::SplitStringIntoKeyValuePairs( + cntl->request_attachment().to_string(), '=', '&', &user); + + const auto expected_user = + butil::StringPairs{{"username", "nacos"}, {"password", "nacos"}}; + + if (user == expected_user) { + cntl->http_response().set_content_type("application/json"); + cntl->response_attachment().append( +R"({ + "accessToken": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTY2MzAwODMzNn0.YKJJwzHT4v9cpC7kVqWroeJK1WioOYe0JZy4KX8nExs", + "tokenTtl": 18000, + "globalAdmin": true, + "username": "nacos" + })"); + } else { + cntl->http_response().set_status_code(brpc::HTTP_STATUS_FORBIDDEN); + cntl->response_attachment().append("unknow user!"); + } + } + + void List(google::protobuf::RpcController* cntl_base, + const test::HttpRequest*, test::HttpResponse*, + google::protobuf::Closure* done) override { + brpc::ClosureGuard done_guard(done); + brpc::Controller* cntl = (brpc::Controller*)cntl_base; + + auto token = cntl->http_request().uri().GetQuery("accessToken"); + if (token == nullptr || + *token != + "eyJhbGciOiJIUzI1NiJ9." + "eyJzdWIiOiJuYWNvcyIsImV4cCI6MTY2MzAwODMzNn0." + "YKJJwzHT4v9cpC7kVqWroeJK1WioOYe0JZy4KX8nExs") { + cntl->http_response().set_status_code(brpc::HTTP_STATUS_FORBIDDEN); + cntl->response_attachment().append( +R"({ + "timestamp": "2022-09-12T22:56:02.730+08:00", + "status": 403, + "error": "Forbidden", + "path": "/nacos/v1/ns/instance/list" + })"); + return; + } + + auto service_name = cntl->http_request().uri().GetQuery("serviceName"); + auto group_name = cntl->http_request().uri().GetQuery("groupName"); + auto namespace_id = cntl->http_request().uri().GetQuery("namespaceId"); + auto clusters = cntl->http_request().uri().GetQuery("clusters"); + if (service_name == nullptr || *service_name != "test" || + group_name == nullptr || *group_name != "g1" || + namespace_id == nullptr || *namespace_id != "n1" || + clusters == nullptr || *clusters != "wx") { + cntl->http_response().set_status_code(brpc::HTTP_STATUS_NOT_FOUND); + return; + } + + cntl->http_response().set_content_type("application/json"); + cntl->response_attachment().append( +R"({ + "name": "g1@@test", + "groupName": "g1", + "clusters": "wx", + "cacheMillis": 10000, + "hosts": + [ + { + "instanceId": "127.0.0.1#8888#wx#g1@@test", + "ip": "127.0.0.1", + "port": 8888, + "weight": 10.0, + "healthy": true, + "enabled": true, + "ephemeral": true, + "clusterName": "wx", + "serviceName": "g1@@test", + "metadata": {}, + "instanceHeartBeatInterval": 5000, + "instanceHeartBeatTimeOut": 15000, + "ipDeleteTimeout": 30000, + "instanceIdGenerator": "simple" + } + ], + "lastRefTime": 1662990336712, + "checksum": "", + "allIPs": false, + "reachProtectionThreshold": false, + "valid": true + })"); + } +}; + +TEST(NamingServiceTest, nacos) { + brpc::Server server; + NacosNamingServiceImpl svc; + ASSERT_EQ(0, server.AddService(&svc, brpc::SERVER_DOESNT_OWN_SERVICE, + "/nacos/v1/auth/login => Login, " + "/nacos/v1/ns/instance/list => List")); + ASSERT_EQ(0, server.Start("localhost:8848", nullptr)); + + bthread_usleep(5000000); + + butil::EndPoint ep; + ASSERT_EQ(0, butil::str2endpoint("127.0.0.1:8888", &ep)); + const auto expected_node = brpc::ServerNode(ep, "10"); + + const char* service_name = + "serviceName=test&groupName=g1&namespaceId=n1&clusters=wx"; + brpc::policy::FLAGS_nacos_address = "http://localhost:8848"; + brpc::policy::FLAGS_nacos_username = "nacos"; + brpc::policy::FLAGS_nacos_password = "nacos"; + + { + brpc::policy::NacosNamingService nns; + std::vector nodes; + ASSERT_EQ(0, nns.GetServers(service_name, &nodes)); + ASSERT_EQ(nodes.size(), 1); + ASSERT_EQ(expected_node, nodes[0]); + } + { + brpc::policy::FLAGS_nacos_password = "invalid_password"; + brpc::policy::NacosNamingService nns; + std::vector nodes; + ASSERT_NE(0, nns.GetServers(service_name, &nodes)); + } +} + } //namespace diff --git a/test/echo.proto b/test/echo.proto index 10e12d474c..2a47b234e9 100644 --- a/test/echo.proto +++ b/test/echo.proto @@ -78,6 +78,11 @@ service DiscoveryNamingService { rpc Cancel(HttpRequest) returns (HttpResponse); }; +service NacosNamingService { + rpc Login(HttpRequest) returns (HttpResponse); + rpc List(HttpRequest) returns (HttpResponse); +}; + enum State0 { STATE0_NUM_0 = 0; STATE0_NUM_1 = 1;