Second attempt: LB policy API: use absl::Status instead of grpc_error (#30386)

* Revert "Revert "LB policy API: use absl::Status instead of grpc_error (#30313)" (#30359)"

This reverts commit dec4451c0c.

* Automated change: Fix sanity tests

Co-authored-by: markdroth <markdroth@users.noreply.github.com>
pull/30338/head
Mark D. Roth 2 years ago committed by GitHub
parent 93fbacb534
commit e0581db977
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      src/core/ext/filters/client_channel/client_channel.cc
  2. 4
      src/core/ext/filters/client_channel/lb_policy.h
  3. 15
      src/core/ext/filters/client_channel/lb_policy/child_policy_handler.cc
  4. 9
      src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h
  5. 47
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
  6. 60
      src/core/ext/filters/client_channel/lb_policy/outlier_detection/outlier_detection.cc
  7. 14
      src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
  8. 95
      src/core/ext/filters/client_channel/lb_policy/priority/priority.cc
  9. 73
      src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc
  10. 11
      src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h
  11. 62
      src/core/ext/filters/client_channel/lb_policy/rls/rls.cc
  12. 14
      src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
  13. 95
      src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc
  14. 46
      src/core/ext/filters/client_channel/lb_policy/xds/cds.cc
  15. 137
      src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc
  16. 89
      src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc
  17. 47
      src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc
  18. 45
      src/core/ext/filters/client_channel/lb_policy_factory.h
  19. 115
      src/core/ext/filters/client_channel/lb_policy_registry.cc
  20. 42
      src/core/ext/filters/client_channel/lb_policy_registry.h
  21. 17
      src/core/ext/filters/client_channel/resolver_result_parsing.cc
  22. 12
      src/core/ext/xds/xds_cluster_specifier_plugin.cc
  23. 12
      test/core/client_channel/rls_lb_config_parser_test.cc
  24. 18
      test/core/client_channel/service_config_test.cc
  25. 15
      test/core/end2end/tests/retry_lb_drop.cc
  26. 15
      test/core/end2end/tests/retry_lb_fail.cc
  27. 71
      test/core/util/test_lb_policies.cc
  28. 4
      test/core/util/test_lb_policies.h
  29. 6
      test/core/xds/xds_lb_policy_registry_test.cc

@ -1135,9 +1135,8 @@ RefCountedPtr<LoadBalancingPolicy::Config> ChooseLbPolicy(
Json config_json = Json::Array{Json::Object{ Json config_json = Json::Array{Json::Object{
{std::string(*policy_name), Json::Object{}}, {std::string(*policy_name), Json::Object{}},
}}; }};
grpc_error_handle parse_error = GRPC_ERROR_NONE; auto lb_policy_config =
auto lb_policy_config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig( LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(config_json);
config_json, &parse_error);
// The policy name came from one of three places: // The policy name came from one of three places:
// - The deprecated loadBalancingPolicy field in the service config, // - The deprecated loadBalancingPolicy field in the service config,
// in which case the code in ClientChannelServiceConfigParser // in which case the code in ClientChannelServiceConfigParser
@ -1147,9 +1146,8 @@ RefCountedPtr<LoadBalancingPolicy::Config> ChooseLbPolicy(
// - A channel arg, in which case we check that the specified policy exists // - A channel arg, in which case we check that the specified policy exists
// and accepts an empty config. If not, we revert to using pick_first // and accepts an empty config. If not, we revert to using pick_first
// lb_policy // lb_policy
GPR_ASSERT(lb_policy_config != nullptr); GPR_ASSERT(lb_policy_config.ok());
GPR_ASSERT(GRPC_ERROR_IS_NONE(parse_error)); return std::move(*lb_policy_config);
return lb_policy_config;
} }
} // namespace } // namespace
@ -1248,9 +1246,9 @@ void ClientChannel::OnResolverResultChangedLocked(Resolver::Result result) {
// If either has changed, apply the global parameters now. // If either has changed, apply the global parameters now.
if (service_config_changed || config_selector_changed) { if (service_config_changed || config_selector_changed) {
// Update service config in control plane. // Update service config in control plane.
UpdateServiceConfigInControlPlaneLocked(std::move(service_config), UpdateServiceConfigInControlPlaneLocked(
std::move(config_selector), std::move(service_config), std::move(config_selector),
lb_policy_config->name()); std::string(lb_policy_config->name()));
} else if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { } else if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) {
gpr_log(GPR_INFO, "chand=%p: service config not changed", this); gpr_log(GPR_INFO, "chand=%p: service config not changed", this);
} }

@ -305,7 +305,7 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
~Config() override = default; ~Config() override = default;
// Returns the load balancing policy name // Returns the load balancing policy name
virtual const char* name() const = 0; virtual absl::string_view name() const = 0;
}; };
/// Data passed to the UpdateLocked() method when new addresses and /// Data passed to the UpdateLocked() method when new addresses and
@ -349,7 +349,7 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
LoadBalancingPolicy& operator=(const LoadBalancingPolicy&) = delete; LoadBalancingPolicy& operator=(const LoadBalancingPolicy&) = delete;
/// Returns the name of the LB policy. /// Returns the name of the LB policy.
virtual const char* name() const = 0; virtual absl::string_view name() const = 0;
/// Updates the policy with new data from the resolver. Will be invoked /// Updates the policy with new data from the resolver. Will be invoked
/// immediately after LB policy is constructed, and then again whenever /// immediately after LB policy is constructed, and then again whenever

@ -18,7 +18,6 @@
#include "src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h" #include "src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h"
#include <cstring>
#include <memory> #include <memory>
#include <string> #include <string>
@ -230,7 +229,8 @@ void ChildPolicyHandler::UpdateLocked(UpdateArgs args) {
if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) {
gpr_log(GPR_INFO, gpr_log(GPR_INFO,
"[child_policy_handler %p] creating new %schild policy %s", this, "[child_policy_handler %p] creating new %schild policy %s", this,
child_policy_ == nullptr ? "" : "pending ", args.config->name()); child_policy_ == nullptr ? "" : "pending ",
std::string(args.config->name()).c_str());
} }
auto& lb_policy = auto& lb_policy =
child_policy_ == nullptr ? child_policy_ : pending_child_policy_; child_policy_ == nullptr ? child_policy_ : pending_child_policy_;
@ -274,7 +274,7 @@ void ChildPolicyHandler::ResetBackoffLocked() {
} }
OrphanablePtr<LoadBalancingPolicy> ChildPolicyHandler::CreateChildPolicy( OrphanablePtr<LoadBalancingPolicy> ChildPolicyHandler::CreateChildPolicy(
const char* child_policy_name, const ChannelArgs& args) { absl::string_view child_policy_name, const ChannelArgs& args) {
Helper* helper = new Helper(Ref(DEBUG_LOCATION, "Helper")); Helper* helper = new Helper(Ref(DEBUG_LOCATION, "Helper"));
LoadBalancingPolicy::Args lb_policy_args; LoadBalancingPolicy::Args lb_policy_args;
lb_policy_args.work_serializer = work_serializer(); lb_policy_args.work_serializer = work_serializer();
@ -284,14 +284,15 @@ OrphanablePtr<LoadBalancingPolicy> ChildPolicyHandler::CreateChildPolicy(
OrphanablePtr<LoadBalancingPolicy> lb_policy = OrphanablePtr<LoadBalancingPolicy> lb_policy =
CreateLoadBalancingPolicy(child_policy_name, std::move(lb_policy_args)); CreateLoadBalancingPolicy(child_policy_name, std::move(lb_policy_args));
if (GPR_UNLIKELY(lb_policy == nullptr)) { if (GPR_UNLIKELY(lb_policy == nullptr)) {
gpr_log(GPR_ERROR, "could not create LB policy \"%s\"", child_policy_name); gpr_log(GPR_ERROR, "could not create LB policy \"%s\"",
std::string(child_policy_name).c_str());
return nullptr; return nullptr;
} }
helper->set_child(lb_policy.get()); helper->set_child(lb_policy.get());
if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) {
gpr_log(GPR_INFO, gpr_log(GPR_INFO,
"[child_policy_handler %p] created new LB policy \"%s\" (%p)", this, "[child_policy_handler %p] created new LB policy \"%s\" (%p)", this,
child_policy_name, lb_policy.get()); std::string(child_policy_name).c_str(), lb_policy.get());
} }
channel_control_helper()->AddTraceEvent( channel_control_helper()->AddTraceEvent(
ChannelControlHelper::TRACE_INFO, ChannelControlHelper::TRACE_INFO,
@ -304,12 +305,12 @@ OrphanablePtr<LoadBalancingPolicy> ChildPolicyHandler::CreateChildPolicy(
bool ChildPolicyHandler::ConfigChangeRequiresNewPolicyInstance( bool ChildPolicyHandler::ConfigChangeRequiresNewPolicyInstance(
LoadBalancingPolicy::Config* old_config, LoadBalancingPolicy::Config* old_config,
LoadBalancingPolicy::Config* new_config) const { LoadBalancingPolicy::Config* new_config) const {
return strcmp(old_config->name(), new_config->name()) != 0; return old_config->name() != new_config->name();
} }
OrphanablePtr<LoadBalancingPolicy> OrphanablePtr<LoadBalancingPolicy>
ChildPolicyHandler::CreateLoadBalancingPolicy( ChildPolicyHandler::CreateLoadBalancingPolicy(
const char* name, LoadBalancingPolicy::Args args) const { absl::string_view name, LoadBalancingPolicy::Args args) const {
return LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy( return LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
name, std::move(args)); name, std::move(args));
} }

@ -16,11 +16,12 @@
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_CHILD_POLICY_HANDLER_H #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_CHILD_POLICY_HANDLER_H
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_CHILD_POLICY_HANDLER_H #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_CHILD_POLICY_HANDLER_H
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
#include <utility> #include <utility>
#include "absl/strings/string_view.h"
#include "src/core/ext/filters/client_channel/lb_policy.h" #include "src/core/ext/filters/client_channel/lb_policy.h"
#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/debug/trace.h" #include "src/core/lib/debug/trace.h"
@ -40,7 +41,7 @@ class ChildPolicyHandler : public LoadBalancingPolicy {
ChildPolicyHandler(Args args, TraceFlag* tracer) ChildPolicyHandler(Args args, TraceFlag* tracer)
: LoadBalancingPolicy(std::move(args)), tracer_(tracer) {} : LoadBalancingPolicy(std::move(args)), tracer_(tracer) {}
const char* name() const override { return "child_policy_handler"; } absl::string_view name() const override { return "child_policy_handler"; }
void UpdateLocked(UpdateArgs args) override; void UpdateLocked(UpdateArgs args) override;
void ExitIdleLocked() override; void ExitIdleLocked() override;
@ -56,7 +57,7 @@ class ChildPolicyHandler : public LoadBalancingPolicy {
// May be overridden by subclasses to avoid recursion when an LB // May be overridden by subclasses to avoid recursion when an LB
// policy factory returns a ChildPolicyHandler. // policy factory returns a ChildPolicyHandler.
virtual OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy( virtual OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
const char* name, LoadBalancingPolicy::Args args) const; absl::string_view name, LoadBalancingPolicy::Args args) const;
private: private:
class Helper; class Helper;
@ -64,7 +65,7 @@ class ChildPolicyHandler : public LoadBalancingPolicy {
void ShutdownLocked() override; void ShutdownLocked() override;
OrphanablePtr<LoadBalancingPolicy> CreateChildPolicy( OrphanablePtr<LoadBalancingPolicy> CreateChildPolicy(
const char* child_policy_name, const ChannelArgs& args); absl::string_view child_policy_name, const ChannelArgs& args);
// Passed in from caller at construction time. // Passed in from caller at construction time.
TraceFlag* tracer_; TraceFlag* tracer_;

@ -160,7 +160,7 @@ namespace {
using ::grpc_event_engine::experimental::EventEngine; using ::grpc_event_engine::experimental::EventEngine;
using ::grpc_event_engine::experimental::GetDefaultEventEngine; using ::grpc_event_engine::experimental::GetDefaultEventEngine;
constexpr char kGrpclb[] = "grpclb"; constexpr absl::string_view kGrpclb = "grpclb";
class GrpcLbConfig : public LoadBalancingPolicy::Config { class GrpcLbConfig : public LoadBalancingPolicy::Config {
public: public:
@ -168,7 +168,8 @@ class GrpcLbConfig : public LoadBalancingPolicy::Config {
std::string service_name) std::string service_name)
: child_policy_(std::move(child_policy)), : child_policy_(std::move(child_policy)),
service_name_(std::move(service_name)) {} service_name_(std::move(service_name)) {}
const char* name() const override { return kGrpclb; }
absl::string_view name() const override { return kGrpclb; }
RefCountedPtr<LoadBalancingPolicy::Config> child_policy() const { RefCountedPtr<LoadBalancingPolicy::Config> child_policy() const {
return child_policy_; return child_policy_;
@ -185,7 +186,7 @@ class GrpcLb : public LoadBalancingPolicy {
public: public:
explicit GrpcLb(Args args); explicit GrpcLb(Args args);
const char* name() const override { return kGrpclb; } absl::string_view name() const override { return kGrpclb; }
void UpdateLocked(UpdateArgs args) override; void UpdateLocked(UpdateArgs args) override;
void ResetBackoffLocked() override; void ResetBackoffLocked() override;
@ -1845,28 +1846,27 @@ class GrpcLbFactory : public LoadBalancingPolicyFactory {
return MakeOrphanable<GrpcLb>(std::move(args)); return MakeOrphanable<GrpcLb>(std::move(args));
} }
const char* name() const override { return kGrpclb; } absl::string_view name() const override { return kGrpclb; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& json, grpc_error_handle* error) const override { ParseLoadBalancingConfig(const Json& json) const override {
GPR_DEBUG_ASSERT(error != nullptr && GRPC_ERROR_IS_NONE(*error));
if (json.type() == Json::Type::JSON_NULL) { if (json.type() == Json::Type::JSON_NULL) {
return MakeRefCounted<GrpcLbConfig>(nullptr, ""); return MakeRefCounted<GrpcLbConfig>(nullptr, "");
} }
std::vector<grpc_error_handle> error_list; std::vector<std::string> error_list;
Json child_policy_config_json_tmp;
const Json* child_policy_config_json;
std::string service_name; std::string service_name;
auto it = json.object_value().find("serviceName"); auto it = json.object_value().find("serviceName");
if (it != json.object_value().end()) { if (it != json.object_value().end()) {
const Json& service_name_json = it->second; const Json& service_name_json = it->second;
if (service_name_json.type() != Json::Type::STRING) { if (service_name_json.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( error_list.emplace_back(
"field:serviceName error:type should be string")); "field:serviceName error:type should be string");
} else { } else {
service_name = service_name_json.string_value(); service_name = service_name_json.string_value();
} }
} }
Json child_policy_config_json_tmp;
const Json* child_policy_config_json;
it = json.object_value().find("childPolicy"); it = json.object_value().find("childPolicy");
if (it == json.object_value().end()) { if (it == json.object_value().end()) {
child_policy_config_json_tmp = Json::Array{Json::Object{ child_policy_config_json_tmp = Json::Array{Json::Object{
@ -1876,25 +1876,24 @@ class GrpcLbFactory : public LoadBalancingPolicyFactory {
} else { } else {
child_policy_config_json = &it->second; child_policy_config_json = &it->second;
} }
grpc_error_handle parse_error = GRPC_ERROR_NONE; auto child_policy_config =
RefCountedPtr<LoadBalancingPolicy::Config> child_policy_config =
LoadBalancingPolicyRegistry::ParseLoadBalancingConfig( LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
*child_policy_config_json, &parse_error); *child_policy_config_json);
if (!GRPC_ERROR_IS_NONE(parse_error)) { if (!child_policy_config.ok()) {
std::vector<grpc_error_handle> child_errors; error_list.emplace_back(
child_errors.push_back(parse_error); absl::StrCat("error parsing childPolicy field: ",
error_list.push_back( child_policy_config.status().message()));
GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors));
} }
if (error_list.empty()) { if (error_list.empty()) {
return MakeRefCounted<GrpcLbConfig>(std::move(child_policy_config), return MakeRefCounted<GrpcLbConfig>(std::move(*child_policy_config),
std::move(service_name)); std::move(service_name));
} else { } else {
*error = GRPC_ERROR_CREATE_FROM_VECTOR("GrpcLb Parser", &error_list); return absl::InvalidArgumentError(
return nullptr; absl::StrCat("errors parsing grpclb LB policy config: [",
absl::StrJoin(error_list, "; "), "]"));
} }
} }
}; // namespace grpc_core };
} // namespace } // namespace

@ -36,6 +36,8 @@
#include "absl/random/random.h" #include "absl/random/random.h"
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/types/variant.h" #include "absl/types/variant.h"
@ -84,7 +86,8 @@ bool XdsOutlierDetectionEnabled() {
namespace { namespace {
constexpr char kOutlierDetection[] = "outlier_detection_experimental"; constexpr absl::string_view kOutlierDetection =
"outlier_detection_experimental";
// Config for xDS Cluster Impl LB policy. // Config for xDS Cluster Impl LB policy.
class OutlierDetectionLbConfig : public LoadBalancingPolicy::Config { class OutlierDetectionLbConfig : public LoadBalancingPolicy::Config {
@ -95,7 +98,7 @@ class OutlierDetectionLbConfig : public LoadBalancingPolicy::Config {
: outlier_detection_config_(outlier_detection_config), : outlier_detection_config_(outlier_detection_config),
child_policy_(std::move(child_policy)) {} child_policy_(std::move(child_policy)) {}
const char* name() const override { return kOutlierDetection; } absl::string_view name() const override { return kOutlierDetection; }
bool CountingEnabled() const { bool CountingEnabled() const {
return ( return (
@ -122,7 +125,7 @@ class OutlierDetectionLb : public LoadBalancingPolicy {
public: public:
explicit OutlierDetectionLb(Args args); explicit OutlierDetectionLb(Args args);
const char* name() const override { return kOutlierDetection; } absl::string_view name() const override { return kOutlierDetection; }
void UpdateLocked(UpdateArgs args) override; void UpdateLocked(UpdateArgs args) override;
void ExitIdleLocked() override; void ExitIdleLocked() override;
@ -1008,28 +1011,27 @@ class OutlierDetectionLbFactory : public LoadBalancingPolicyFactory {
return MakeOrphanable<OutlierDetectionLb>(std::move(args)); return MakeOrphanable<OutlierDetectionLb>(std::move(args));
} }
const char* name() const override { return kOutlierDetection; } absl::string_view name() const override { return kOutlierDetection; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& json, grpc_error_handle* error) const override { ParseLoadBalancingConfig(const Json& json) const override {
GPR_DEBUG_ASSERT(error != nullptr && GRPC_ERROR_IS_NONE(*error));
if (json.type() == Json::Type::JSON_NULL) { if (json.type() == Json::Type::JSON_NULL) {
// This policy was configured in the deprecated loadBalancingPolicy // This policy was configured in the deprecated loadBalancingPolicy
// field or in the client API. // field or in the client API.
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( return absl::InvalidArgumentError(
"field:loadBalancingPolicy error:outlier_detection policy requires " "field:loadBalancingPolicy error:outlier_detection policy requires "
"configuration. Please use loadBalancingConfig field of service " "configuration. Please use loadBalancingConfig field of service "
"config instead."); "config instead.");
return nullptr;
} }
std::vector<std::string> errors;
std::vector<grpc_error_handle> error_list; std::vector<grpc_error_handle> error_list;
// Outlier detection config // Outlier detection config
OutlierDetectionConfig outlier_detection_config; OutlierDetectionConfig outlier_detection_config;
auto it = json.object_value().find("successRateEjection"); auto it = json.object_value().find("successRateEjection");
if (it != json.object_value().end()) { if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::OBJECT) { if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back(
"field:successRateEjection error:type must be object")); "field:successRateEjection error:type must be object");
} else { } else {
OutlierDetectionConfig::SuccessRateEjection success_config; OutlierDetectionConfig::SuccessRateEjection success_config;
const Json::Object& object = it->second.object_value(); const Json::Object& object = it->second.object_value();
@ -1051,8 +1053,8 @@ class OutlierDetectionLbFactory : public LoadBalancingPolicyFactory {
it = json.object_value().find("failurePercentageEjection"); it = json.object_value().find("failurePercentageEjection");
if (it != json.object_value().end()) { if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::OBJECT) { if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back(
"field:successRateEjection error:type must be object")); "field:successRateEjection error:type must be object");
} else { } else {
OutlierDetectionConfig::FailurePercentageEjection failure_config; OutlierDetectionConfig::FailurePercentageEjection failure_config;
const Json::Object& object = it->second.object_value(); const Json::Object& object = it->second.object_value();
@ -1089,24 +1091,26 @@ class OutlierDetectionLbFactory : public LoadBalancingPolicyFactory {
RefCountedPtr<LoadBalancingPolicy::Config> child_policy; RefCountedPtr<LoadBalancingPolicy::Config> child_policy;
it = json.object_value().find("childPolicy"); it = json.object_value().find("childPolicy");
if (it == json.object_value().end()) { if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:childPolicy error:required field missing");
"field:childPolicy error:required field missing"));
} else { } else {
grpc_error_handle parse_error = GRPC_ERROR_NONE; auto child_policy_config =
child_policy = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig( LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(it->second);
it->second, &parse_error); if (!child_policy_config.ok()) {
if (child_policy == nullptr) { errors.emplace_back(
GPR_DEBUG_ASSERT(!GRPC_ERROR_IS_NONE(parse_error)); absl::StrCat("error parsing childPolicy field: ",
std::vector<grpc_error_handle> child_errors; child_policy_config.status().message()));
child_errors.push_back(parse_error); } else {
error_list.push_back( child_policy = std::move(*child_policy_config);
GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors));
} }
} }
if (!error_list.empty()) { for (auto& error : error_list) {
*error = GRPC_ERROR_CREATE_FROM_VECTOR( errors.emplace_back(grpc_error_std_string(error));
"outlier_detection_experimental LB policy config", &error_list); GRPC_ERROR_UNREF(error);
return nullptr; }
if (!errors.empty()) {
return absl::InvalidArgumentError(
absl::StrCat("outlier_detection_experimental LB policy config: [",
absl::StrJoin(errors, "; "), "]"));
} }
return MakeRefCounted<OutlierDetectionLbConfig>(outlier_detection_config, return MakeRefCounted<OutlierDetectionLbConfig>(outlier_detection_config,
std::move(child_policy)); std::move(child_policy));

@ -29,6 +29,7 @@
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
#include <grpc/impl/codegen/connectivity_state.h> #include <grpc/impl/codegen/connectivity_state.h>
@ -45,7 +46,6 @@
#include "src/core/lib/gprpp/debug_location.h" #include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
#include "src/core/lib/resolver/server_address.h" #include "src/core/lib/resolver/server_address.h"
#include "src/core/lib/transport/connectivity_state.h" #include "src/core/lib/transport/connectivity_state.h"
@ -60,13 +60,13 @@ namespace {
// pick_first LB policy // pick_first LB policy
// //
constexpr char kPickFirst[] = "pick_first"; constexpr absl::string_view kPickFirst = "pick_first";
class PickFirst : public LoadBalancingPolicy { class PickFirst : public LoadBalancingPolicy {
public: public:
explicit PickFirst(Args args); explicit PickFirst(Args args);
const char* name() const override { return kPickFirst; } absl::string_view name() const override { return kPickFirst; }
void UpdateLocked(UpdateArgs args) override; void UpdateLocked(UpdateArgs args) override;
void ExitIdleLocked() override; void ExitIdleLocked() override;
@ -502,7 +502,7 @@ void PickFirst::PickFirstSubchannelData::ProcessUnselectedReadyLocked() {
class PickFirstConfig : public LoadBalancingPolicy::Config { class PickFirstConfig : public LoadBalancingPolicy::Config {
public: public:
const char* name() const override { return kPickFirst; } absl::string_view name() const override { return kPickFirst; }
}; };
// //
@ -516,10 +516,10 @@ class PickFirstFactory : public LoadBalancingPolicyFactory {
return MakeOrphanable<PickFirst>(std::move(args)); return MakeOrphanable<PickFirst>(std::move(args));
} }
const char* name() const override { return kPickFirst; } absl::string_view name() const override { return kPickFirst; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& /*json*/, grpc_error_handle* /*error*/) const override { ParseLoadBalancingConfig(const Json& /*json*/) const override {
return MakeRefCounted<PickFirstConfig>(); return MakeRefCounted<PickFirstConfig>();
} }
}; };

@ -30,6 +30,7 @@
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
@ -66,7 +67,7 @@ TraceFlag grpc_lb_priority_trace(false, "priority_lb");
namespace { namespace {
constexpr char kPriority[] = "priority_experimental"; constexpr absl::string_view kPriority = "priority_experimental";
// How long we keep a child around for after it is no longer being used // How long we keep a child around for after it is no longer being used
// (either because it has been removed from the config or because we // (either because it has been removed from the config or because we
@ -89,7 +90,7 @@ class PriorityLbConfig : public LoadBalancingPolicy::Config {
std::vector<std::string> priorities) std::vector<std::string> priorities)
: children_(std::move(children)), priorities_(std::move(priorities)) {} : children_(std::move(children)), priorities_(std::move(priorities)) {}
const char* name() const override { return kPriority; } absl::string_view name() const override { return kPriority; }
const std::map<std::string, PriorityLbChild>& children() const { const std::map<std::string, PriorityLbChild>& children() const {
return children_; return children_;
@ -106,7 +107,7 @@ class PriorityLb : public LoadBalancingPolicy {
public: public:
explicit PriorityLb(Args args); explicit PriorityLb(Args args);
const char* name() const override { return kPriority; } absl::string_view name() const override { return kPriority; }
void UpdateLocked(UpdateArgs args) override; void UpdateLocked(UpdateArgs args) override;
void ExitIdleLocked() override; void ExitIdleLocked() override;
@ -926,49 +927,40 @@ class PriorityLbFactory : public LoadBalancingPolicyFactory {
return MakeOrphanable<PriorityLb>(std::move(args)); return MakeOrphanable<PriorityLb>(std::move(args));
} }
const char* name() const override { return kPriority; } absl::string_view name() const override { return kPriority; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& json, grpc_error_handle* error) const override { ParseLoadBalancingConfig(const Json& json) const override {
GPR_DEBUG_ASSERT(error != nullptr && GRPC_ERROR_IS_NONE(*error));
if (json.type() == Json::Type::JSON_NULL) { if (json.type() == Json::Type::JSON_NULL) {
// priority was mentioned as a policy in the deprecated // priority was mentioned as a policy in the deprecated
// loadBalancingPolicy field or in the client API. // loadBalancingPolicy field or in the client API.
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( return absl::InvalidArgumentError(
"field:loadBalancingPolicy error:priority policy requires " "field:loadBalancingPolicy error:priority policy requires "
"configuration. Please use loadBalancingConfig field of service " "configuration. Please use loadBalancingConfig field of service "
"config instead."); "config instead.");
return nullptr;
} }
std::vector<grpc_error_handle> error_list; std::vector<std::string> errors;
// Children. // Children.
std::map<std::string, PriorityLbConfig::PriorityLbChild> children; std::map<std::string, PriorityLbConfig::PriorityLbChild> children;
auto it = json.object_value().find("children"); auto it = json.object_value().find("children");
if (it == json.object_value().end()) { if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:children error:required field missing");
"field:children error:required field missing"));
} else if (it->second.type() != Json::Type::OBJECT) { } else if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:children error:type should be object");
"field:children error:type should be object"));
} else { } else {
const Json::Object& object = it->second.object_value(); const Json::Object& object = it->second.object_value();
for (const auto& p : object) { for (const auto& p : object) {
const std::string& child_name = p.first; const std::string& child_name = p.first;
const Json& element = p.second; const Json& element = p.second;
if (element.type() != Json::Type::OBJECT) { if (element.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING( errors.emplace_back(absl::StrCat("field:children key:", child_name,
absl::StrCat("field:children key:", child_name, " error:should be type object"));
" error:should be type object")));
} else { } else {
auto it2 = element.object_value().find("config"); auto it2 = element.object_value().find("config");
if (it2 == element.object_value().end()) { if (it2 == element.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING( errors.emplace_back(absl::StrCat("field:children key:", child_name,
absl::StrCat("field:children key:", child_name, " error:missing 'config' field"));
" error:missing 'config' field")));
} else { } else {
grpc_error_handle parse_error = GRPC_ERROR_NONE;
auto config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
it2->second, &parse_error);
bool ignore_resolution_requests = false; bool ignore_resolution_requests = false;
// If present, ignore_reresolution_requests must be of type // If present, ignore_reresolution_requests must be of type
// boolean. // boolean.
@ -978,23 +970,23 @@ class PriorityLbFactory : public LoadBalancingPolicyFactory {
if (it3->second.type() == Json::Type::JSON_TRUE) { if (it3->second.type() == Json::Type::JSON_TRUE) {
ignore_resolution_requests = true; ignore_resolution_requests = true;
} else if (it3->second.type() != Json::Type::JSON_FALSE) { } else if (it3->second.type() != Json::Type::JSON_FALSE) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING( errors.emplace_back(
absl::StrCat("field:children key:", child_name, absl::StrCat("field:children key:", child_name,
" field:ignore_reresolution_requests:should " " field:ignore_reresolution_requests:should "
"be type boolean"))); "be type boolean"));
} }
} }
if (config == nullptr) { auto config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
GPR_DEBUG_ASSERT(!GRPC_ERROR_IS_NONE(parse_error)); it2->second);
error_list.push_back( if (!config.ok()) {
GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING( errors.emplace_back(
absl::StrCat("field:children key:", child_name).c_str(), absl::StrCat("field:children key:", child_name, ": ",
&parse_error, 1)); config.status().message()));
GRPC_ERROR_UNREF(parse_error); } else {
children[child_name].config = std::move(*config);
children[child_name].ignore_reresolution_requests =
ignore_resolution_requests;
} }
children[child_name].config = std::move(config);
children[child_name].ignore_reresolution_requests =
ignore_resolution_requests;
} }
} }
} }
@ -1003,40 +995,37 @@ class PriorityLbFactory : public LoadBalancingPolicyFactory {
std::vector<std::string> priorities; std::vector<std::string> priorities;
it = json.object_value().find("priorities"); it = json.object_value().find("priorities");
if (it == json.object_value().end()) { if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:priorities error:required field missing");
"field:priorities error:required field missing"));
} else if (it->second.type() != Json::Type::ARRAY) { } else if (it->second.type() != Json::Type::ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:priorities error:type should be array");
"field:priorities error:type should be array"));
} else { } else {
const Json::Array& array = it->second.array_value(); const Json::Array& array = it->second.array_value();
for (size_t i = 0; i < array.size(); ++i) { for (size_t i = 0; i < array.size(); ++i) {
const Json& element = array[i]; const Json& element = array[i];
if (element.type() != Json::Type::STRING) { if (element.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat( errors.emplace_back(absl::StrCat("field:priorities element:", i,
"field:priorities element:", i, " error:should be type string"))); " error:should be type string"));
} else if (children.find(element.string_value()) == children.end()) { } else if (children.find(element.string_value()) == children.end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat( errors.emplace_back(absl::StrCat("field:priorities element:", i,
"field:priorities element:", i, " error:unknown child '", " error:unknown child '",
element.string_value(), "'"))); element.string_value(), "'"));
} else { } else {
priorities.emplace_back(element.string_value()); priorities.emplace_back(element.string_value());
} }
} }
if (priorities.size() != children.size()) { if (priorities.size() != children.size()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat( errors.emplace_back(absl::StrCat(
"field:priorities error:priorities size (", priorities.size(), "field:priorities error:priorities size (", priorities.size(),
") != children size (", children.size(), ")"))); ") != children size (", children.size(), ")"));
} }
} }
if (error_list.empty()) { if (!errors.empty()) {
return MakeRefCounted<PriorityLbConfig>(std::move(children), return absl::InvalidArgumentError(
std::move(priorities)); absl::StrCat("priority_experimental LB policy config: [",
} else { absl::StrJoin(errors, "; "), "]"));
*error = GRPC_ERROR_CREATE_FROM_VECTOR(
"priority_experimental LB policy config", &error_list);
return nullptr;
} }
return MakeRefCounted<PriorityLbConfig>(std::move(children),
std::move(priorities));
} }
}; };

@ -16,6 +16,8 @@
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
#include "src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h"
#include <inttypes.h> #include <inttypes.h>
#include <stdlib.h> #include <stdlib.h>
@ -36,11 +38,10 @@
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/numbers.h" #include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
#include "src/core/lib/channel/channel_args.h"
#define XXH_INLINE_ALL #define XXH_INLINE_ALL
#include "xxhash.h" #include "xxhash.h"
@ -54,6 +55,7 @@
#include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
#include "src/core/ext/filters/client_channel/subchannel_interface.h" #include "src/core/ext/filters/client_channel/subchannel_interface.h"
#include "src/core/lib/address_utils/sockaddr_utils.h" #include "src/core/lib/address_utils/sockaddr_utils.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/debug/trace.h" #include "src/core/lib/debug/trace.h"
#include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/debug_location.h" #include "src/core/lib/gprpp/debug_location.h"
@ -80,56 +82,60 @@ UniqueTypeName RequestHashAttributeName() {
} }
// Helper Parser method // Helper Parser method
void ParseRingHashLbConfig(const Json& json, size_t* min_ring_size, absl::StatusOr<RingHashConfig> ParseRingHashLbConfig(const Json& json) {
size_t* max_ring_size,
std::vector<grpc_error_handle>* error_list) {
*min_ring_size = 1024;
*max_ring_size = 8388608;
if (json.type() != Json::Type::OBJECT) { if (json.type() != Json::Type::OBJECT) {
error_list->push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( return absl::InvalidArgumentError(
"ring_hash_experimental should be of type object")); "ring_hash_experimental should be of type object");
return;
} }
RingHashConfig config;
std::vector<std::string> errors;
const Json::Object& ring_hash = json.object_value(); const Json::Object& ring_hash = json.object_value();
auto ring_hash_it = ring_hash.find("min_ring_size"); auto ring_hash_it = ring_hash.find("min_ring_size");
if (ring_hash_it != ring_hash.end()) { if (ring_hash_it != ring_hash.end()) {
if (ring_hash_it->second.type() != Json::Type::NUMBER) { if (ring_hash_it->second.type() != Json::Type::NUMBER) {
error_list->push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back(
"field:min_ring_size error: should be of type number")); "field:min_ring_size error: should be of type number");
} else { } else {
*min_ring_size = gpr_parse_nonnegative_int( config.min_ring_size = gpr_parse_nonnegative_int(
ring_hash_it->second.string_value().c_str()); ring_hash_it->second.string_value().c_str());
} }
} }
ring_hash_it = ring_hash.find("max_ring_size"); ring_hash_it = ring_hash.find("max_ring_size");
if (ring_hash_it != ring_hash.end()) { if (ring_hash_it != ring_hash.end()) {
if (ring_hash_it->second.type() != Json::Type::NUMBER) { if (ring_hash_it->second.type() != Json::Type::NUMBER) {
error_list->push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back(
"field:max_ring_size error: should be of type number")); "field:max_ring_size error: should be of type number");
} else { } else {
*max_ring_size = gpr_parse_nonnegative_int( config.max_ring_size = gpr_parse_nonnegative_int(
ring_hash_it->second.string_value().c_str()); ring_hash_it->second.string_value().c_str());
} }
} }
if (*min_ring_size == 0 || *min_ring_size > 8388608 || *max_ring_size == 0 || if (config.min_ring_size == 0 || config.min_ring_size > 8388608 ||
*max_ring_size > 8388608 || *min_ring_size > *max_ring_size) { config.max_ring_size == 0 || config.max_ring_size > 8388608 ||
error_list->push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( config.min_ring_size > config.max_ring_size) {
errors.emplace_back(
"field:max_ring_size and or min_ring_size error: " "field:max_ring_size and or min_ring_size error: "
"values need to be in the range of 1 to 8388608 " "values need to be in the range of 1 to 8388608 "
"and max_ring_size cannot be smaller than " "and max_ring_size cannot be smaller than "
"min_ring_size")); "min_ring_size");
} }
if (!errors.empty()) {
return absl::InvalidArgumentError(
absl::StrCat("errors parsing ring hash LB config: [",
absl::StrJoin(errors, "; "), "]"));
}
return config;
} }
namespace { namespace {
constexpr char kRingHash[] = "ring_hash_experimental"; constexpr absl::string_view kRingHash = "ring_hash_experimental";
class RingHashLbConfig : public LoadBalancingPolicy::Config { class RingHashLbConfig : public LoadBalancingPolicy::Config {
public: public:
RingHashLbConfig(size_t min_ring_size, size_t max_ring_size) RingHashLbConfig(size_t min_ring_size, size_t max_ring_size)
: min_ring_size_(min_ring_size), max_ring_size_(max_ring_size) {} : min_ring_size_(min_ring_size), max_ring_size_(max_ring_size) {}
const char* name() const override { return kRingHash; } absl::string_view name() const override { return kRingHash; }
size_t min_ring_size() const { return min_ring_size_; } size_t min_ring_size() const { return min_ring_size_; }
size_t max_ring_size() const { return max_ring_size_; } size_t max_ring_size() const { return max_ring_size_; }
@ -146,7 +152,7 @@ class RingHash : public LoadBalancingPolicy {
public: public:
explicit RingHash(Args args); explicit RingHash(Args args);
const char* name() const override { return kRingHash; } absl::string_view name() const override { return kRingHash; }
void UpdateLocked(UpdateArgs args) override; void UpdateLocked(UpdateArgs args) override;
void ResetBackoffLocked() override; void ResetBackoffLocked() override;
@ -874,21 +880,14 @@ class RingHashFactory : public LoadBalancingPolicyFactory {
return MakeOrphanable<RingHash>(std::move(args)); return MakeOrphanable<RingHash>(std::move(args));
} }
const char* name() const override { return kRingHash; } absl::string_view name() const override { return kRingHash; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& json, grpc_error_handle* error) const override { ParseLoadBalancingConfig(const Json& json) const override {
size_t min_ring_size; auto config = ParseRingHashLbConfig(json);
size_t max_ring_size; if (!config.ok()) return config.status();
std::vector<grpc_error_handle> error_list; return MakeRefCounted<RingHashLbConfig>(config->min_ring_size,
ParseRingHashLbConfig(json, &min_ring_size, &max_ring_size, &error_list); config->max_ring_size);
if (error_list.empty()) {
return MakeRefCounted<RingHashLbConfig>(min_ring_size, max_ring_size);
} else {
*error = GRPC_ERROR_CREATE_FROM_VECTOR(
"ring_hash_experimental LB policy config", &error_list);
return nullptr;
}
} }
}; };

@ -21,10 +21,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <vector> #include "absl/status/statusor.h"
#include "src/core/lib/gprpp/unique_type_name.h" #include "src/core/lib/gprpp/unique_type_name.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
namespace grpc_core { namespace grpc_core {
@ -33,9 +32,11 @@ UniqueTypeName RequestHashAttributeName();
// Helper Parsing method to parse ring hash policy configs; for example, ring // Helper Parsing method to parse ring hash policy configs; for example, ring
// hash size validity. // hash size validity.
void ParseRingHashLbConfig(const Json& json, size_t* min_ring_size, struct RingHashConfig {
size_t* max_ring_size, size_t min_ring_size = 1024;
std::vector<grpc_error_handle>* error_list); size_t max_ring_size = 8388608;
};
absl::StatusOr<RingHashConfig> ParseRingHashLbConfig(const Json& json);
} // namespace grpc_core } // namespace grpc_core

@ -107,7 +107,7 @@ TraceFlag grpc_lb_rls_trace(false, "rls_lb");
namespace { namespace {
const char* kRls = "rls_experimental"; constexpr absl::string_view kRls = "rls_experimental";
const char kGrpc[] = "grpc"; const char kGrpc[] = "grpc";
const char* kRlsRequestPath = "/grpc.lookup.v1.RouteLookupService/RouteLookup"; const char* kRlsRequestPath = "/grpc.lookup.v1.RouteLookupService/RouteLookup";
const char* kFakeTargetFieldValue = "fake_target_field_value"; const char* kFakeTargetFieldValue = "fake_target_field_value";
@ -162,7 +162,7 @@ class RlsLbConfig : public LoadBalancingPolicy::Config {
default_child_policy_parsed_config_( default_child_policy_parsed_config_(
std::move(default_child_policy_parsed_config)) {} std::move(default_child_policy_parsed_config)) {}
const char* name() const override { return kRls; } absl::string_view name() const override { return kRls; }
const KeyBuilderMap& key_builder_map() const { const KeyBuilderMap& key_builder_map() const {
return route_lookup_config_.key_builder_map; return route_lookup_config_.key_builder_map;
@ -207,7 +207,7 @@ class RlsLb : public LoadBalancingPolicy {
public: public:
explicit RlsLb(Args args); explicit RlsLb(Args args);
const char* name() const override { return kRls; } absl::string_view name() const override { return kRls; }
void UpdateLocked(UpdateArgs args) override; void UpdateLocked(UpdateArgs args) override;
void ExitIdleLocked() override; void ExitIdleLocked() override;
void ResetBackoffLocked() override; void ResetBackoffLocked() override;
@ -790,23 +790,23 @@ void RlsLb::ChildPolicyWrapper::StartUpdate() {
lb_policy_.get(), this, target_.c_str(), lb_policy_.get(), this, target_.c_str(),
child_policy_config.Dump().c_str()); child_policy_config.Dump().c_str());
} }
pending_config_ = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig( auto config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
child_policy_config, &error); child_policy_config);
// Returned RLS target fails the validation. // Returned RLS target fails the validation.
if (!GRPC_ERROR_IS_NONE(error)) { if (!config.ok()) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_rls_trace)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_rls_trace)) {
gpr_log(GPR_INFO, gpr_log(GPR_INFO,
"[rlslb %p] ChildPolicyWrapper=%p [%s]: config failed to parse: " "[rlslb %p] ChildPolicyWrapper=%p [%s]: config failed to parse: "
"%s; config: %s", "%s",
lb_policy_.get(), this, target_.c_str(), lb_policy_.get(), this, target_.c_str(),
grpc_error_std_string(error).c_str(), config.status().ToString().c_str());
child_policy_config.Dump().c_str());
} }
pending_config_.reset(); pending_config_.reset();
picker_ = absl::make_unique<TransientFailurePicker>( picker_ = absl::make_unique<TransientFailurePicker>(
grpc_error_to_absl_status(error)); absl::UnavailableError(config.status().message()));
GRPC_ERROR_UNREF(error);
child_policy_.reset(); child_policy_.reset();
} else {
pending_config_ = std::move(*config);
} }
} }
@ -2441,43 +2441,42 @@ grpc_error_handle ValidateChildPolicyList(
child_policy_config_target_field_name, target, child_policy_config); child_policy_config_target_field_name, target, child_policy_config);
if (!GRPC_ERROR_IS_NONE(error)) return error; if (!GRPC_ERROR_IS_NONE(error)) return error;
// Parse the config. // Parse the config.
RefCountedPtr<LoadBalancingPolicy::Config> parsed_config = auto parsed_config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
LoadBalancingPolicyRegistry::ParseLoadBalancingConfig( *child_policy_config);
*child_policy_config, &error); if (!parsed_config.ok()) {
if (!GRPC_ERROR_IS_NONE(error)) return error; return absl_status_to_grpc_error(parsed_config.status());
}
// Find the chosen config and return it in JSON form. // Find the chosen config and return it in JSON form.
// We remove all non-selected configs, and in the selected config, we leave // We remove all non-selected configs, and in the selected config, we leave
// the target field in place, set to the default value. This slightly // the target field in place, set to the default value. This slightly
// optimizes what we need to do later when we update a child policy for a // optimizes what we need to do later when we update a child policy for a
// given target. // given target.
if (parsed_config != nullptr) { for (Json& config : *(child_policy_config->mutable_array())) {
for (Json& config : *(child_policy_config->mutable_array())) { if (config.object_value().begin()->first == (*parsed_config)->name()) {
if (config.object_value().begin()->first == parsed_config->name()) { Json save_config = std::move(config);
Json save_config = std::move(config); child_policy_config->mutable_array()->clear();
child_policy_config->mutable_array()->clear(); child_policy_config->mutable_array()->push_back(std::move(save_config));
child_policy_config->mutable_array()->push_back(std::move(save_config)); break;
break;
}
} }
} }
// If default target is set, return the parsed config. // If default target is set, return the parsed config.
if (!default_target.empty()) { if (!default_target.empty()) {
*default_child_policy_parsed_config = std::move(parsed_config); *default_child_policy_parsed_config = std::move(*parsed_config);
} }
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }
class RlsLbFactory : public LoadBalancingPolicyFactory { class RlsLbFactory : public LoadBalancingPolicyFactory {
public: public:
const char* name() const override { return kRls; } absl::string_view name() const override { return kRls; }
OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy( OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
LoadBalancingPolicy::Args args) const override { LoadBalancingPolicy::Args args) const override {
return MakeOrphanable<RlsLb>(std::move(args)); return MakeOrphanable<RlsLb>(std::move(args));
} }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& config, grpc_error_handle* error) const override { ParseLoadBalancingConfig(const Json& config) const override {
std::vector<grpc_error_handle> error_list; std::vector<grpc_error_handle> error_list;
// Parse routeLookupConfig. // Parse routeLookupConfig.
RlsLbConfig::RouteLookupConfig route_lookup_config; RlsLbConfig::RouteLookupConfig route_lookup_config;
@ -2542,8 +2541,13 @@ class RlsLbFactory : public LoadBalancingPolicyFactory {
} }
} }
// Return result. // Return result.
*error = GRPC_ERROR_CREATE_FROM_VECTOR( if (!error_list.empty()) {
"errors parsing RLS LB policy config", &error_list); grpc_error_handle error = GRPC_ERROR_CREATE_FROM_VECTOR(
"errors parsing RLS LB policy config", &error_list);
std::string error_string = grpc_error_std_string(error);
GRPC_ERROR_UNREF(error);
return absl::InvalidArgumentError(error_string);
}
return MakeRefCounted<RlsLbConfig>( return MakeRefCounted<RlsLbConfig>(
std::move(route_lookup_config), std::move(rls_channel_service_config), std::move(route_lookup_config), std::move(rls_channel_service_config),
std::move(child_policy_config), std::move(child_policy_config),

@ -29,6 +29,7 @@
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
#include <grpc/impl/codegen/connectivity_state.h> #include <grpc/impl/codegen/connectivity_state.h>
@ -44,7 +45,6 @@
#include "src/core/lib/gprpp/debug_location.h" #include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
#include "src/core/lib/resolver/server_address.h" #include "src/core/lib/resolver/server_address.h"
#include "src/core/lib/transport/connectivity_state.h" #include "src/core/lib/transport/connectivity_state.h"
@ -59,13 +59,13 @@ namespace {
// round_robin LB policy // round_robin LB policy
// //
constexpr char kRoundRobin[] = "round_robin"; constexpr absl::string_view kRoundRobin = "round_robin";
class RoundRobin : public LoadBalancingPolicy { class RoundRobin : public LoadBalancingPolicy {
public: public:
explicit RoundRobin(Args args); explicit RoundRobin(Args args);
const char* name() const override { return kRoundRobin; } absl::string_view name() const override { return kRoundRobin; }
void UpdateLocked(UpdateArgs args) override; void UpdateLocked(UpdateArgs args) override;
void ResetBackoffLocked() override; void ResetBackoffLocked() override;
@ -499,7 +499,7 @@ void RoundRobin::RoundRobinSubchannelData::UpdateLogicalConnectivityStateLocked(
class RoundRobinConfig : public LoadBalancingPolicy::Config { class RoundRobinConfig : public LoadBalancingPolicy::Config {
public: public:
const char* name() const override { return kRoundRobin; } absl::string_view name() const override { return kRoundRobin; }
}; };
class RoundRobinFactory : public LoadBalancingPolicyFactory { class RoundRobinFactory : public LoadBalancingPolicyFactory {
@ -509,10 +509,10 @@ class RoundRobinFactory : public LoadBalancingPolicyFactory {
return MakeOrphanable<RoundRobin>(std::move(args)); return MakeOrphanable<RoundRobin>(std::move(args));
} }
const char* name() const override { return kRoundRobin; } absl::string_view name() const override { return kRoundRobin; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& /*json*/, grpc_error_handle* /*error*/) const override { ParseLoadBalancingConfig(const Json& /*json*/) const override {
return MakeRefCounted<RoundRobinConfig>(); return MakeRefCounted<RoundRobinConfig>();
} }
}; };

@ -30,6 +30,7 @@
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
@ -53,7 +54,6 @@
#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/time.h" #include "src/core/lib/gprpp/time.h"
#include "src/core/lib/gprpp/work_serializer.h" #include "src/core/lib/gprpp/work_serializer.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/pollset_set.h" #include "src/core/lib/iomgr/pollset_set.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
#include "src/core/lib/resolver/server_address.h" #include "src/core/lib/resolver/server_address.h"
@ -70,7 +70,7 @@ namespace {
using ::grpc_event_engine::experimental::EventEngine; using ::grpc_event_engine::experimental::EventEngine;
using ::grpc_event_engine::experimental::GetDefaultEventEngine; using ::grpc_event_engine::experimental::GetDefaultEventEngine;
constexpr char kWeightedTarget[] = "weighted_target_experimental"; constexpr absl::string_view kWeightedTarget = "weighted_target_experimental";
// How long we keep a child around for after it has been removed from // How long we keep a child around for after it has been removed from
// the config. // the config.
@ -89,7 +89,7 @@ class WeightedTargetLbConfig : public LoadBalancingPolicy::Config {
explicit WeightedTargetLbConfig(TargetMap target_map) explicit WeightedTargetLbConfig(TargetMap target_map)
: target_map_(std::move(target_map)) {} : target_map_(std::move(target_map)) {}
const char* name() const override { return kWeightedTarget; } absl::string_view name() const override { return kWeightedTarget; }
const TargetMap& target_map() const { return target_map_; } const TargetMap& target_map() const { return target_map_; }
@ -102,7 +102,7 @@ class WeightedTargetLb : public LoadBalancingPolicy {
public: public:
explicit WeightedTargetLb(Args args); explicit WeightedTargetLb(Args args);
const char* name() const override { return kWeightedTarget; } absl::string_view name() const override { return kWeightedTarget; }
void UpdateLocked(UpdateArgs args) override; void UpdateLocked(UpdateArgs args) override;
void ResetBackoffLocked() override; void ResetBackoffLocked() override;
@ -683,96 +683,87 @@ class WeightedTargetLbFactory : public LoadBalancingPolicyFactory {
return MakeOrphanable<WeightedTargetLb>(std::move(args)); return MakeOrphanable<WeightedTargetLb>(std::move(args));
} }
const char* name() const override { return kWeightedTarget; } absl::string_view name() const override { return kWeightedTarget; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& json, grpc_error_handle* error) const override { ParseLoadBalancingConfig(const Json& json) const override {
GPR_DEBUG_ASSERT(error != nullptr && GRPC_ERROR_IS_NONE(*error));
if (json.type() == Json::Type::JSON_NULL) { if (json.type() == Json::Type::JSON_NULL) {
// weighted_target was mentioned as a policy in the deprecated // weighted_target was mentioned as a policy in the deprecated
// loadBalancingPolicy field or in the client API. // loadBalancingPolicy field or in the client API.
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( return absl::InvalidArgumentError(
"field:loadBalancingPolicy error:weighted_target policy requires " "field:loadBalancingPolicy error:weighted_target policy requires "
"configuration. Please use loadBalancingConfig field of service " "configuration. Please use loadBalancingConfig field of service "
"config instead."); "config instead.");
return nullptr;
} }
std::vector<grpc_error_handle> error_list; std::vector<std::string> errors;
// Weight map. // Weight map.
WeightedTargetLbConfig::TargetMap target_map; WeightedTargetLbConfig::TargetMap target_map;
auto it = json.object_value().find("targets"); auto it = json.object_value().find("targets");
if (it == json.object_value().end()) { if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:targets error:required field not present");
"field:targets error:required field not present"));
} else if (it->second.type() != Json::Type::OBJECT) { } else if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:targets error:type should be object");
"field:targets error:type should be object"));
} else { } else {
for (const auto& p : it->second.object_value()) { for (const auto& p : it->second.object_value()) {
WeightedTargetLbConfig::ChildConfig child_config; auto config = ParseChildConfig(p.second);
std::vector<grpc_error_handle> child_errors = if (!config.ok()) {
ParseChildConfig(p.second, &child_config); errors.emplace_back(config.status().message());
if (!child_errors.empty()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_VECTOR_AND_CPP_STRING(
absl::StrCat("field:targets key:", p.first), &child_errors));
} else { } else {
target_map[p.first] = std::move(child_config); target_map[p.first] = std::move(*config);
} }
} }
} }
if (!error_list.empty()) { if (!errors.empty()) {
*error = GRPC_ERROR_CREATE_FROM_VECTOR( return absl::InvalidArgumentError(
"weighted_target_experimental LB policy config", &error_list); absl::StrCat("weighted_target_experimental LB policy config: [",
return nullptr; absl::StrJoin(errors, "; "), "]"));
} }
return MakeRefCounted<WeightedTargetLbConfig>(std::move(target_map)); return MakeRefCounted<WeightedTargetLbConfig>(std::move(target_map));
} }
private: private:
static std::vector<grpc_error_handle> ParseChildConfig( static absl::StatusOr<WeightedTargetLbConfig::ChildConfig> ParseChildConfig(
const Json& json, WeightedTargetLbConfig::ChildConfig* child_config) { const Json& json) {
std::vector<grpc_error_handle> error_list;
if (json.type() != Json::Type::OBJECT) { if (json.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( return absl::InvalidArgumentError("value should be of type object");
"value should be of type object"));
return error_list;
} }
WeightedTargetLbConfig::ChildConfig child_config;
std::vector<std::string> errors;
// Weight. // Weight.
auto it = json.object_value().find("weight"); auto it = json.object_value().find("weight");
if (it == json.object_value().end()) { if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("required field \"weight\" not specified");
"required field \"weight\" not specified"));
} else if (it->second.type() != Json::Type::NUMBER) { } else if (it->second.type() != Json::Type::NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:weight error:must be of type number");
"field:weight error:must be of type number"));
} else { } else {
int weight = gpr_parse_nonnegative_int(it->second.string_value().c_str()); int weight = gpr_parse_nonnegative_int(it->second.string_value().c_str());
if (weight == -1) { if (weight == -1) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:weight error:unparseable value");
"field:weight error:unparseable value"));
} else if (weight == 0) { } else if (weight == 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back(
"field:weight error:value must be greater than zero")); "field:weight error:value must be greater than zero");
} else { } else {
child_config->weight = weight; child_config.weight = weight;
} }
} }
// Child policy. // Child policy.
it = json.object_value().find("childPolicy"); it = json.object_value().find("childPolicy");
if (it != json.object_value().end()) { if (it != json.object_value().end()) {
grpc_error_handle parse_error = GRPC_ERROR_NONE; auto config =
child_config->config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(it->second);
LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(it->second, if (!config.ok()) {
&parse_error); errors.emplace_back(
if (child_config->config == nullptr) { absl::StrCat("field:childPolicy: ", config.status().message()));
GPR_DEBUG_ASSERT(!GRPC_ERROR_IS_NONE(parse_error)); } else {
std::vector<grpc_error_handle> child_errors; child_config.config = std::move(*config);
child_errors.push_back(parse_error);
error_list.push_back(
GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors));
} }
} }
return error_list; // Return result.
if (!errors.empty()) {
return absl::InvalidArgumentError(absl::StrCat(
"errors parsing target config: [", absl::StrJoin(errors, "; "), "]"));
}
return child_config;
} }
}; };

@ -28,6 +28,7 @@
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
@ -74,7 +75,7 @@ TraceFlag grpc_cds_lb_trace(false, "cds_lb");
namespace { namespace {
constexpr char kCds[] = "cds_experimental"; constexpr absl::string_view kCds = "cds_experimental";
constexpr int kMaxAggregateClusterRecursionDepth = 16; constexpr int kMaxAggregateClusterRecursionDepth = 16;
@ -83,7 +84,7 @@ class CdsLbConfig : public LoadBalancingPolicy::Config {
public: public:
explicit CdsLbConfig(std::string cluster) : cluster_(std::move(cluster)) {} explicit CdsLbConfig(std::string cluster) : cluster_(std::move(cluster)) {}
const std::string& cluster() const { return cluster_; } const std::string& cluster() const { return cluster_; }
const char* name() const override { return kCds; } absl::string_view name() const override { return kCds; }
private: private:
std::string cluster_; std::string cluster_;
@ -94,7 +95,7 @@ class CdsLb : public LoadBalancingPolicy {
public: public:
CdsLb(RefCountedPtr<XdsClient> xds_client, Args args); CdsLb(RefCountedPtr<XdsClient> xds_client, Args args);
const char* name() const override { return kCds; } absl::string_view name() const override { return kCds; }
void UpdateLocked(UpdateArgs args) override; void UpdateLocked(UpdateArgs args) override;
void ResetBackoffLocked() override; void ResetBackoffLocked() override;
@ -516,11 +517,9 @@ void CdsLb::OnClusterChanged(const std::string& name,
this, json_str.c_str()); this, json_str.c_str());
} }
grpc_error_handle error = GRPC_ERROR_NONE; grpc_error_handle error = GRPC_ERROR_NONE;
RefCountedPtr<LoadBalancingPolicy::Config> config = auto config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(json);
LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(json, &error); if (!config.ok()) {
if (!GRPC_ERROR_IS_NONE(error)) { OnError(name, absl::UnavailableError(config.status().message()));
OnError(name, absl::UnavailableError(grpc_error_std_string(error)));
GRPC_ERROR_UNREF(error);
return; return;
} }
// Create child policy if not already present. // Create child policy if not already present.
@ -530,7 +529,7 @@ void CdsLb::OnClusterChanged(const std::string& name,
args.args = args_; args.args = args_;
args.channel_control_helper = absl::make_unique<Helper>(Ref()); args.channel_control_helper = absl::make_unique<Helper>(Ref());
child_policy_ = LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy( child_policy_ = LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
config->name(), std::move(args)); (*config)->name(), std::move(args));
if (child_policy_ == nullptr) { if (child_policy_ == nullptr) {
OnError(name, absl::UnavailableError("failed to create child policy")); OnError(name, absl::UnavailableError("failed to create child policy"));
return; return;
@ -539,12 +538,12 @@ void CdsLb::OnClusterChanged(const std::string& name,
interested_parties()); interested_parties());
if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) {
gpr_log(GPR_INFO, "[cdslb %p] created child policy %s (%p)", this, gpr_log(GPR_INFO, "[cdslb %p] created child policy %s (%p)", this,
config->name(), child_policy_.get()); std::string((*config)->name()).c_str(), child_policy_.get());
} }
} }
// Update child policy. // Update child policy.
UpdateArgs args; UpdateArgs args;
args.config = std::move(config); args.config = std::move(*config);
if (xds_certificate_provider_ != nullptr) { if (xds_certificate_provider_ != nullptr) {
args.args = args_.SetObject(xds_certificate_provider_); args.args = args_.SetObject(xds_certificate_provider_);
} else { } else {
@ -724,35 +723,32 @@ class CdsLbFactory : public LoadBalancingPolicyFactory {
return MakeOrphanable<CdsLb>(std::move(xds_client), std::move(args)); return MakeOrphanable<CdsLb>(std::move(xds_client), std::move(args));
} }
const char* name() const override { return kCds; } absl::string_view name() const override { return kCds; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& json, grpc_error_handle* error) const override { ParseLoadBalancingConfig(const Json& json) const override {
GPR_DEBUG_ASSERT(error != nullptr && GRPC_ERROR_IS_NONE(*error));
if (json.type() == Json::Type::JSON_NULL) { if (json.type() == Json::Type::JSON_NULL) {
// xds was mentioned as a policy in the deprecated loadBalancingPolicy // xds was mentioned as a policy in the deprecated loadBalancingPolicy
// field or in the client API. // field or in the client API.
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( return absl::InvalidArgumentError(
"field:loadBalancingPolicy error:cds policy requires configuration. " "field:loadBalancingPolicy error:cds policy requires configuration. "
"Please use loadBalancingConfig field of service config instead."); "Please use loadBalancingConfig field of service config instead.");
return nullptr;
} }
std::vector<grpc_error_handle> error_list; std::vector<std::string> errors;
// cluster name. // cluster name.
std::string cluster; std::string cluster;
auto it = json.object_value().find("cluster"); auto it = json.object_value().find("cluster");
if (it == json.object_value().end()) { if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("required field 'cluster' not present");
"required field 'cluster' not present"));
} else if (it->second.type() != Json::Type::STRING) { } else if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:cluster error:type should be string");
"field:cluster error:type should be string"));
} else { } else {
cluster = it->second.string_value(); cluster = it->second.string_value();
} }
if (!error_list.empty()) { if (!errors.empty()) {
*error = GRPC_ERROR_CREATE_FROM_VECTOR("Cds Parser", &error_list); return absl::InvalidArgumentError(
return nullptr; absl::StrCat("errors parsing CDS LB policy config: [",
absl::StrJoin(errors, "; "), "]"));
} }
return MakeRefCounted<CdsLbConfig>(std::move(cluster)); return MakeRefCounted<CdsLbConfig>(std::move(cluster));
} }

@ -32,6 +32,7 @@
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
#include "absl/types/variant.h" #include "absl/types/variant.h"
@ -137,7 +138,7 @@ CircuitBreakerCallCounterMap::CallCounter::~CallCounter() {
// LB policy // LB policy
// //
constexpr char kXdsClusterImpl[] = "xds_cluster_impl_experimental"; constexpr absl::string_view kXdsClusterImpl = "xds_cluster_impl_experimental";
// Config for xDS Cluster Impl LB policy. // Config for xDS Cluster Impl LB policy.
class XdsClusterImplLbConfig : public LoadBalancingPolicy::Config { class XdsClusterImplLbConfig : public LoadBalancingPolicy::Config {
@ -155,7 +156,7 @@ class XdsClusterImplLbConfig : public LoadBalancingPolicy::Config {
max_concurrent_requests_(max_concurrent_requests), max_concurrent_requests_(max_concurrent_requests),
drop_config_(std::move(drop_config)) {} drop_config_(std::move(drop_config)) {}
const char* name() const override { return kXdsClusterImpl; } absl::string_view name() const override { return kXdsClusterImpl; }
RefCountedPtr<LoadBalancingPolicy::Config> child_policy() const { RefCountedPtr<LoadBalancingPolicy::Config> child_policy() const {
return child_policy_; return child_policy_;
@ -185,7 +186,7 @@ class XdsClusterImplLb : public LoadBalancingPolicy {
public: public:
XdsClusterImplLb(RefCountedPtr<XdsClient> xds_client, Args args); XdsClusterImplLb(RefCountedPtr<XdsClient> xds_client, Args args);
const char* name() const override { return kXdsClusterImpl; } absl::string_view name() const override { return kXdsClusterImpl; }
void UpdateLocked(UpdateArgs args) override; void UpdateLocked(UpdateArgs args) override;
void ExitIdleLocked() override; void ExitIdleLocked() override;
@ -703,48 +704,41 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
std::move(args)); std::move(args));
} }
const char* name() const override { return kXdsClusterImpl; } absl::string_view name() const override { return kXdsClusterImpl; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& json, grpc_error_handle* error) const override { ParseLoadBalancingConfig(const Json& json) const override {
GPR_DEBUG_ASSERT(error != nullptr && GRPC_ERROR_IS_NONE(*error));
if (json.type() == Json::Type::JSON_NULL) { if (json.type() == Json::Type::JSON_NULL) {
// This policy was configured in the deprecated loadBalancingPolicy // This policy was configured in the deprecated loadBalancingPolicy
// field or in the client API. // field or in the client API.
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( return absl::InvalidArgumentError(
"field:loadBalancingPolicy error:xds_cluster_impl policy requires " "field:loadBalancingPolicy error:xds_cluster_impl policy requires "
"configuration. Please use loadBalancingConfig field of service " "configuration. Please use loadBalancingConfig field of service "
"config instead."); "config instead.");
return nullptr;
} }
std::vector<grpc_error_handle> error_list; std::vector<std::string> errors;
// Child policy. // Child policy.
RefCountedPtr<LoadBalancingPolicy::Config> child_policy; RefCountedPtr<LoadBalancingPolicy::Config> child_policy;
auto it = json.object_value().find("childPolicy"); auto it = json.object_value().find("childPolicy");
if (it == json.object_value().end()) { if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:childPolicy error:required field missing");
"field:childPolicy error:required field missing"));
} else { } else {
grpc_error_handle parse_error = GRPC_ERROR_NONE; auto config =
child_policy = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig( LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(it->second);
it->second, &parse_error); if (!config.ok()) {
if (child_policy == nullptr) { errors.emplace_back(absl::StrCat("field:childPolicy error:",
GPR_DEBUG_ASSERT(!GRPC_ERROR_IS_NONE(parse_error)); config.status().message()));
std::vector<grpc_error_handle> child_errors; } else {
child_errors.push_back(parse_error); child_policy = std::move(*config);
error_list.push_back(
GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors));
} }
} }
// Cluster name. // Cluster name.
std::string cluster_name; std::string cluster_name;
it = json.object_value().find("clusterName"); it = json.object_value().find("clusterName");
if (it == json.object_value().end()) { if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:clusterName error:required field missing");
"field:clusterName error:required field missing"));
} else if (it->second.type() != Json::Type::STRING) { } else if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:clusterName error:type should be string");
"field:clusterName error:type should be string"));
} else { } else {
cluster_name = it->second.string_value(); cluster_name = it->second.string_value();
} }
@ -753,8 +747,7 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
it = json.object_value().find("edsServiceName"); it = json.object_value().find("edsServiceName");
if (it != json.object_value().end()) { if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::STRING) { if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:edsServiceName error:type should be string");
"field:edsServiceName error:type should be string"));
} else { } else {
eds_service_name = it->second.string_value(); eds_service_name = it->second.string_value();
} }
@ -764,16 +757,17 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
it = json.object_value().find("lrsLoadReportingServer"); it = json.object_value().find("lrsLoadReportingServer");
if (it != json.object_value().end()) { if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::OBJECT) { if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back(
"field:lrsLoadReportingServer error:type should be object")); "field:lrsLoadReportingServer error:type should be object");
} else { } else {
grpc_error_handle parser_error; grpc_error_handle parser_error;
lrs_load_reporting_server = XdsBootstrap::XdsServer::Parse( lrs_load_reporting_server = XdsBootstrap::XdsServer::Parse(
it->second.object_value(), &parser_error); it->second.object_value(), &parser_error);
if (!GRPC_ERROR_IS_NONE(parser_error)) { if (!GRPC_ERROR_IS_NONE(parser_error)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING( errors.emplace_back(
absl::StrCat("errors parsing lrs_load_reporting_server"))); absl::StrCat("error parsing lrs_load_reporting_server: ",
error_list.push_back(parser_error); grpc_error_std_string(parser_error)));
GRPC_ERROR_UNREF(parser_error);
} }
} }
} }
@ -782,8 +776,8 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
it = json.object_value().find("maxConcurrentRequests"); it = json.object_value().find("maxConcurrentRequests");
if (it != json.object_value().end()) { if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::NUMBER) { if (it->second.type() != Json::Type::NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back(
"field:max_concurrent_requests error:must be of type number")); "field:max_concurrent_requests error:must be of type number");
} else { } else {
max_concurrent_requests = max_concurrent_requests =
gpr_parse_nonnegative_int(it->second.string_value().c_str()); gpr_parse_nonnegative_int(it->second.string_value().c_str());
@ -793,20 +787,15 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
auto drop_config = MakeRefCounted<XdsEndpointResource::DropConfig>(); auto drop_config = MakeRefCounted<XdsEndpointResource::DropConfig>();
it = json.object_value().find("dropCategories"); it = json.object_value().find("dropCategories");
if (it == json.object_value().end()) { if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:dropCategories error:required field missing");
"field:dropCategories error:required field missing"));
} else { } else {
std::vector<grpc_error_handle> child_errors = absl::Status status = ParseDropCategories(it->second, drop_config.get());
ParseDropCategories(it->second, drop_config.get()); if (!status.ok()) errors.emplace_back(status.message());
if (!child_errors.empty()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_VECTOR(
"field:dropCategories", &child_errors));
}
} }
if (!error_list.empty()) { if (!errors.empty()) {
*error = GRPC_ERROR_CREATE_FROM_VECTOR( return absl::InvalidArgumentError(absl::StrCat(
"xds_cluster_impl_experimental LB policy config", &error_list); "errors parseing xds_cluster_impl_experimental LB policy config: [",
return nullptr; absl::StrJoin(errors, "; "), "]"));
} }
return MakeRefCounted<XdsClusterImplLbConfig>( return MakeRefCounted<XdsClusterImplLbConfig>(
std::move(child_policy), std::move(cluster_name), std::move(child_policy), std::move(cluster_name),
@ -815,65 +804,59 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
} }
private: private:
static std::vector<grpc_error_handle> ParseDropCategories( static absl::Status ParseDropCategories(
const Json& json, XdsEndpointResource::DropConfig* drop_config) { const Json& json, XdsEndpointResource::DropConfig* drop_config) {
std::vector<grpc_error_handle> error_list;
if (json.type() != Json::Type::ARRAY) { if (json.type() != Json::Type::ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( return absl::InvalidArgumentError("dropCategories field is not an array");
"dropCategories field is not an array"));
return error_list;
} }
std::vector<std::string> errors;
for (size_t i = 0; i < json.array_value().size(); ++i) { for (size_t i = 0; i < json.array_value().size(); ++i) {
const Json& entry = json.array_value()[i]; const Json& entry = json.array_value()[i];
std::vector<grpc_error_handle> child_errors = absl::Status status = ParseDropCategory(entry, drop_config);
ParseDropCategory(entry, drop_config); if (!status.ok()) {
if (!child_errors.empty()) { errors.emplace_back(
grpc_error_handle error = GRPC_ERROR_CREATE_FROM_CPP_STRING( absl::StrCat("error parsing index ", i, ": ", status.message()));
absl::StrCat("errors parsing index ", i));
for (size_t i = 0; i < child_errors.size(); ++i) {
error = grpc_error_add_child(error, child_errors[i]);
}
error_list.push_back(error);
} }
} }
return error_list; if (!errors.empty()) {
return absl::InvalidArgumentError(
absl::StrCat("errors parsing dropCategories field: [",
absl::StrJoin(errors, "; "), "]"));
}
return absl::OkStatus();
} }
static std::vector<grpc_error_handle> ParseDropCategory( static absl::Status ParseDropCategory(
const Json& json, XdsEndpointResource::DropConfig* drop_config) { const Json& json, XdsEndpointResource::DropConfig* drop_config) {
std::vector<grpc_error_handle> error_list;
if (json.type() != Json::Type::OBJECT) { if (json.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( return absl::InvalidArgumentError(
"dropCategories entry is not an object")); "dropCategories entry is not an object");
return error_list;
} }
std::vector<std::string> errors;
std::string category; std::string category;
auto it = json.object_value().find("category"); auto it = json.object_value().find("category");
if (it == json.object_value().end()) { if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("\"category\" field not present");
"\"category\" field not present"));
} else if (it->second.type() != Json::Type::STRING) { } else if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("\"category\" field is not a string");
"\"category\" field is not a string"));
} else { } else {
category = it->second.string_value(); category = it->second.string_value();
} }
uint32_t requests_per_million = 0; uint32_t requests_per_million = 0;
it = json.object_value().find("requests_per_million"); it = json.object_value().find("requests_per_million");
if (it == json.object_value().end()) { if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("\"requests_per_million\" field is not present");
"\"requests_per_million\" field is not present"));
} else if (it->second.type() != Json::Type::NUMBER) { } else if (it->second.type() != Json::Type::NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("\"requests_per_million\" field is not a number");
"\"requests_per_million\" field is not a number"));
} else { } else {
requests_per_million = requests_per_million =
gpr_parse_nonnegative_int(it->second.string_value().c_str()); gpr_parse_nonnegative_int(it->second.string_value().c_str());
} }
if (error_list.empty()) { if (!errors.empty()) {
drop_config->AddCategory(std::move(category), requests_per_million); return absl::InvalidArgumentError(absl::StrJoin(errors, "; "));
} }
return error_list; drop_config->AddCategory(std::move(category), requests_per_million);
return absl::OkStatus();
} }
}; };

@ -30,6 +30,7 @@
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include <grpc/impl/codegen/connectivity_state.h> #include <grpc/impl/codegen/connectivity_state.h>
@ -67,7 +68,8 @@ TraceFlag grpc_xds_cluster_manager_lb_trace(false, "xds_cluster_manager_lb");
namespace { namespace {
constexpr char kXdsClusterManager[] = "xds_cluster_manager_experimental"; constexpr absl::string_view kXdsClusterManager =
"xds_cluster_manager_experimental";
// Config for xds_cluster_manager LB policy. // Config for xds_cluster_manager LB policy.
class XdsClusterManagerLbConfig : public LoadBalancingPolicy::Config { class XdsClusterManagerLbConfig : public LoadBalancingPolicy::Config {
@ -78,7 +80,7 @@ class XdsClusterManagerLbConfig : public LoadBalancingPolicy::Config {
explicit XdsClusterManagerLbConfig(ClusterMap cluster_map) explicit XdsClusterManagerLbConfig(ClusterMap cluster_map)
: cluster_map_(std::move(cluster_map)) {} : cluster_map_(std::move(cluster_map)) {}
const char* name() const override { return kXdsClusterManager; } absl::string_view name() const override { return kXdsClusterManager; }
const ClusterMap& cluster_map() const { return cluster_map_; } const ClusterMap& cluster_map() const { return cluster_map_; }
@ -91,7 +93,7 @@ class XdsClusterManagerLb : public LoadBalancingPolicy {
public: public:
explicit XdsClusterManagerLb(Args args); explicit XdsClusterManagerLb(Args args);
const char* name() const override { return kXdsClusterManager; } absl::string_view name() const override { return kXdsClusterManager; }
void UpdateLocked(UpdateArgs args) override; void UpdateLocked(UpdateArgs args) override;
void ExitIdleLocked() override; void ExitIdleLocked() override;
@ -622,89 +624,80 @@ class XdsClusterManagerLbFactory : public LoadBalancingPolicyFactory {
return MakeOrphanable<XdsClusterManagerLb>(std::move(args)); return MakeOrphanable<XdsClusterManagerLb>(std::move(args));
} }
const char* name() const override { return kXdsClusterManager; } absl::string_view name() const override { return kXdsClusterManager; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& json, grpc_error_handle* error) const override { ParseLoadBalancingConfig(const Json& json) const override {
GPR_DEBUG_ASSERT(error != nullptr && GRPC_ERROR_IS_NONE(*error));
if (json.type() == Json::Type::JSON_NULL) { if (json.type() == Json::Type::JSON_NULL) {
// xds_cluster_manager was mentioned as a policy in the deprecated // xds_cluster_manager was mentioned as a policy in the deprecated
// loadBalancingPolicy field or in the client API. // loadBalancingPolicy field or in the client API.
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( return absl::InvalidArgumentError(
"field:loadBalancingPolicy error:xds_cluster_manager policy requires " "field:loadBalancingPolicy error:xds_cluster_manager policy requires "
"configuration. Please use loadBalancingConfig field of service " "configuration. Please use loadBalancingConfig field of service "
"config instead."); "config instead.");
return nullptr;
} }
std::vector<grpc_error_handle> error_list; std::vector<std::string> errors;
XdsClusterManagerLbConfig::ClusterMap cluster_map; XdsClusterManagerLbConfig::ClusterMap cluster_map;
std::set<std::string /*cluster_name*/> clusters_to_be_used; std::set<std::string /*cluster_name*/> clusters_to_be_used;
auto it = json.object_value().find("children"); auto it = json.object_value().find("children");
if (it == json.object_value().end()) { if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:children error:required field not present");
"field:children error:required field not present"));
} else if (it->second.type() != Json::Type::OBJECT) { } else if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:children error:type should be object");
"field:children error:type should be object"));
} else { } else {
for (const auto& p : it->second.object_value()) { for (const auto& p : it->second.object_value()) {
const std::string& child_name = p.first; const std::string& child_name = p.first;
if (child_name.empty()) { if (child_name.empty()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( errors.emplace_back("field:children error: name cannot be empty");
"field:children element error: name cannot be empty"));
continue; continue;
} }
RefCountedPtr<LoadBalancingPolicy::Config> child_config; auto config = ParseChildConfig(p.second);
std::vector<grpc_error_handle> child_errors = if (!config.ok()) {
ParseChildConfig(p.second, &child_config); errors.emplace_back(
if (!child_errors.empty()) { absl::StrCat("field:children name:", child_name,
error_list.push_back(GRPC_ERROR_CREATE_FROM_VECTOR_AND_CPP_STRING( " error:", config.status().message()));
absl::StrCat("field:children name:", child_name), &child_errors));
} else { } else {
cluster_map[child_name] = std::move(child_config); cluster_map[child_name] = std::move(*config);
clusters_to_be_used.insert(child_name); clusters_to_be_used.insert(child_name);
} }
} }
} }
if (cluster_map.empty()) { if (cluster_map.empty()) {
error_list.push_back( errors.emplace_back("no valid children configured");
GRPC_ERROR_CREATE_FROM_STATIC_STRING("no valid children configured"));
} }
if (!error_list.empty()) { if (!errors.empty()) {
*error = GRPC_ERROR_CREATE_FROM_VECTOR( return absl::InvalidArgumentError(absl::StrCat(
"xds_cluster_manager_experimental LB policy config", &error_list); "errors parsing xds_cluster_manager_experimental LB policy config: [",
return nullptr; absl::StrJoin(errors, "; "), "]"));
} }
return MakeRefCounted<XdsClusterManagerLbConfig>(std::move(cluster_map)); return MakeRefCounted<XdsClusterManagerLbConfig>(std::move(cluster_map));
} }
private: private:
static std::vector<grpc_error_handle> ParseChildConfig( static absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& json, ParseChildConfig(const Json& json) {
RefCountedPtr<LoadBalancingPolicy::Config>* child_config) {
std::vector<grpc_error_handle> error_list;
if (json.type() != Json::Type::OBJECT) { if (json.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( return absl::InvalidArgumentError("value should be of type object");
"value should be of type object"));
return error_list;
} }
RefCountedPtr<LoadBalancingPolicy::Config> child_config;
std::vector<std::string> errors;
auto it = json.object_value().find("childPolicy"); auto it = json.object_value().find("childPolicy");
if (it == json.object_value().end()) { if (it == json.object_value().end()) {
error_list.push_back( errors.emplace_back("did not find childPolicy");
GRPC_ERROR_CREATE_FROM_STATIC_STRING("did not find childPolicy"));
} else { } else {
grpc_error_handle parse_error = GRPC_ERROR_NONE; auto config =
*child_config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig( LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(it->second);
it->second, &parse_error); if (!config.ok()) {
if (*child_config == nullptr) { errors.emplace_back(absl::StrCat("field:childPolicy error:",
GPR_DEBUG_ASSERT(!GRPC_ERROR_IS_NONE(parse_error)); config.status().message()));
std::vector<grpc_error_handle> child_errors; } else {
child_errors.push_back(parse_error); child_config = std::move(*config);
error_list.push_back(
GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors));
} }
} }
return error_list; if (!errors.empty()) {
return absl::InvalidArgumentError(absl::StrJoin(errors, "; "));
}
return child_config;
} }
}; };

@ -72,6 +72,7 @@
#include "src/core/lib/resolver/resolver_registry.h" #include "src/core/lib/resolver/resolver_registry.h"
#include "src/core/lib/resolver/server_address.h" #include "src/core/lib/resolver/server_address.h"
#include "src/core/lib/transport/connectivity_state.h" #include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/error_utils.h"
#define GRPC_EDS_DEFAULT_FALLBACK_TIMEOUT 10000 #define GRPC_EDS_DEFAULT_FALLBACK_TIMEOUT 10000
@ -83,7 +84,8 @@ const char* kXdsLocalityNameAttributeKey = "xds_locality_name";
namespace { namespace {
constexpr char kXdsClusterResolver[] = "xds_cluster_resolver_experimental"; constexpr absl::string_view kXdsClusterResolver =
"xds_cluster_resolver_experimental";
// Config for EDS LB policy. // Config for EDS LB policy.
class XdsClusterResolverLbConfig : public LoadBalancingPolicy::Config { class XdsClusterResolverLbConfig : public LoadBalancingPolicy::Config {
@ -117,7 +119,8 @@ class XdsClusterResolverLbConfig : public LoadBalancingPolicy::Config {
: discovery_mechanisms_(std::move(discovery_mechanisms)), : discovery_mechanisms_(std::move(discovery_mechanisms)),
xds_lb_policy_(std::move(xds_lb_policy)) {} xds_lb_policy_(std::move(xds_lb_policy)) {}
const char* name() const override { return kXdsClusterResolver; } absl::string_view name() const override { return kXdsClusterResolver; }
const std::vector<DiscoveryMechanism>& discovery_mechanisms() const { const std::vector<DiscoveryMechanism>& discovery_mechanisms() const {
return discovery_mechanisms_; return discovery_mechanisms_;
} }
@ -134,7 +137,7 @@ class XdsClusterResolverLb : public LoadBalancingPolicy {
public: public:
XdsClusterResolverLb(RefCountedPtr<XdsClient> xds_client, Args args); XdsClusterResolverLb(RefCountedPtr<XdsClient> xds_client, Args args);
const char* name() const override { return kXdsClusterResolver; } absl::string_view name() const override { return kXdsClusterResolver; }
void UpdateLocked(UpdateArgs args) override; void UpdateLocked(UpdateArgs args) override;
void ResetBackoffLocked() override; void ResetBackoffLocked() override;
@ -976,17 +979,15 @@ XdsClusterResolverLb::CreateChildPolicyConfigLocked() {
"[xds_cluster_resolver_lb %p] generated config for child policy: %s", "[xds_cluster_resolver_lb %p] generated config for child policy: %s",
this, json_str.c_str()); this, json_str.c_str());
} }
grpc_error_handle error = GRPC_ERROR_NONE; auto config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(json);
RefCountedPtr<LoadBalancingPolicy::Config> config = if (!config.ok()) {
LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(json, &error);
if (!GRPC_ERROR_IS_NONE(error)) {
// This should never happen, but if it does, we basically have no // This should never happen, but if it does, we basically have no
// way to fix it, so we put the channel in TRANSIENT_FAILURE. // way to fix it, so we put the channel in TRANSIENT_FAILURE.
gpr_log(GPR_ERROR, gpr_log(GPR_ERROR,
"[xds_cluster_resolver_lb %p] error parsing generated child policy " "[xds_cluster_resolver_lb %p] error parsing generated child policy "
"config -- " "config -- "
"will put channel in TRANSIENT_FAILURE: %s", "will put channel in TRANSIENT_FAILURE: %s",
this, grpc_error_std_string(error).c_str()); this, config.status().ToString().c_str());
absl::Status status = absl::InternalError( absl::Status status = absl::InternalError(
"xds_cluster_resolver LB policy: error parsing generated child policy " "xds_cluster_resolver LB policy: error parsing generated child policy "
"config"); "config");
@ -995,7 +996,7 @@ XdsClusterResolverLb::CreateChildPolicyConfigLocked() {
absl::make_unique<TransientFailurePicker>(status)); absl::make_unique<TransientFailurePicker>(status));
return nullptr; return nullptr;
} }
return config; return std::move(*config);
} }
void XdsClusterResolverLb::UpdateChildPolicyLocked() { void XdsClusterResolverLb::UpdateChildPolicyLocked() {
@ -1071,19 +1072,17 @@ class XdsClusterResolverLbFactory : public LoadBalancingPolicyFactory {
std::move(args)); std::move(args));
} }
const char* name() const override { return kXdsClusterResolver; } absl::string_view name() const override { return kXdsClusterResolver; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& json, grpc_error_handle* error) const override { ParseLoadBalancingConfig(const Json& json) const override {
GPR_DEBUG_ASSERT(error != nullptr && GRPC_ERROR_IS_NONE(*error));
if (json.type() == Json::Type::JSON_NULL) { if (json.type() == Json::Type::JSON_NULL) {
// xds_cluster_resolver was mentioned as a policy in the deprecated // xds_cluster_resolver was mentioned as a policy in the deprecated
// loadBalancingPolicy field or in the client API. // loadBalancingPolicy field or in the client API.
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( return absl::InvalidArgumentError(
"field:loadBalancingPolicy error:xds_cluster_resolver policy " "field:loadBalancingPolicy error:xds_cluster_resolver policy "
"requires configuration. " "requires configuration. "
"Please use loadBalancingConfig field of service config instead."); "Please use loadBalancingConfig field of service config instead.");
return nullptr;
} }
std::vector<grpc_error_handle> error_list; std::vector<grpc_error_handle> error_list;
std::vector<XdsClusterResolverLbConfig::DiscoveryMechanism> std::vector<XdsClusterResolverLbConfig::DiscoveryMechanism>
@ -1145,10 +1144,11 @@ class XdsClusterResolverLbFactory : public LoadBalancingPolicyFactory {
policy_it = policy.find("RING_HASH"); policy_it = policy.find("RING_HASH");
if (policy_it != policy.end()) { if (policy_it != policy.end()) {
xds_lb_policy = array[i]; xds_lb_policy = array[i];
size_t min_ring_size; auto config = ParseRingHashLbConfig(policy_it->second);
size_t max_ring_size; if (!config.ok()) {
ParseRingHashLbConfig(policy_it->second, &min_ring_size, error_list.emplace_back(
&max_ring_size, &error_list); absl_status_to_grpc_error(config.status()));
}
} }
} }
} }
@ -1158,9 +1158,11 @@ class XdsClusterResolverLbFactory : public LoadBalancingPolicyFactory {
return MakeRefCounted<XdsClusterResolverLbConfig>( return MakeRefCounted<XdsClusterResolverLbConfig>(
std::move(discovery_mechanisms), std::move(xds_lb_policy)); std::move(discovery_mechanisms), std::move(xds_lb_policy));
} else { } else {
*error = GRPC_ERROR_CREATE_FROM_VECTOR( grpc_error_handle error = GRPC_ERROR_CREATE_FROM_VECTOR(
"xds_cluster_resolver_experimental LB policy config", &error_list); "xds_cluster_resolver_experimental LB policy config", &error_list);
return nullptr; absl::Status status = grpc_error_to_absl_status(error);
GRPC_ERROR_UNREF(error);
return status;
} }
} }
@ -1300,7 +1302,8 @@ class XdsClusterResolverLbFactory : public LoadBalancingPolicyFactory {
} }
OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy( OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
const char* /*name*/, LoadBalancingPolicy::Args args) const override { absl::string_view /*name*/,
LoadBalancingPolicy::Args args) const override {
return MakeOrphanable<XdsClusterResolverLb>( return MakeOrphanable<XdsClusterResolverLb>(
xds_client_->Ref(DEBUG_LOCATION, "XdsClusterResolverLb"), xds_client_->Ref(DEBUG_LOCATION, "XdsClusterResolverLb"),
std::move(args)); std::move(args));

@ -1,30 +1,30 @@
/* //
* // Copyright 2015 gRPC authors.
* Copyright 2015 gRPC authors. //
* // Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License. // You may obtain a copy of the License at
* You may obtain a copy of the License at //
* // http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0 //
* // Unless required by applicable law or agreed to in writing, software
* Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS,
* distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and
* See the License for the specific language governing permissions and // limitations under the License.
* limitations under the License. //
*
*/
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "src/core/ext/filters/client_channel/lb_policy.h" #include "src/core/ext/filters/client_channel/lb_policy.h"
#include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
namespace grpc_core { namespace grpc_core {
@ -38,13 +38,12 @@ class LoadBalancingPolicyFactory {
LoadBalancingPolicy::Args) const = 0; LoadBalancingPolicy::Args) const = 0;
/// Returns the LB policy name that this factory provides. /// Returns the LB policy name that this factory provides.
/// Caller does NOT take ownership of result. virtual absl::string_view name() const = 0;
virtual const char* name() const = 0;
virtual RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( virtual absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& json, grpc_error_handle* error) const = 0; ParseLoadBalancingConfig(const Json& json) const = 0;
}; };
} // namespace grpc_core } // namespace grpc_core
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H */ #endif // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H

@ -1,33 +1,30 @@
/* //
* // Copyright 2015 gRPC authors.
* Copyright 2015 gRPC authors. //
* // Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License. // You may obtain a copy of the License at
* You may obtain a copy of the License at //
* // http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0 //
* // Unless required by applicable law or agreed to in writing, software
* Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS,
* distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and
* See the License for the specific language governing permissions and // limitations under the License.
* limitations under the License. //
*
*/
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
#include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
#include <string.h>
#include <algorithm> #include <algorithm>
#include <map> #include <map>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "absl/status/status.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
#include "absl/strings/str_join.h" #include "absl/strings/str_join.h"
@ -41,30 +38,24 @@ namespace {
class RegistryState { class RegistryState {
public: public:
RegistryState() {}
void RegisterLoadBalancingPolicyFactory( void RegisterLoadBalancingPolicyFactory(
std::unique_ptr<LoadBalancingPolicyFactory> factory) { std::unique_ptr<LoadBalancingPolicyFactory> factory) {
gpr_log(GPR_DEBUG, "registering LB policy factory for \"%s\"", gpr_log(GPR_DEBUG, "registering LB policy factory for \"%s\"",
factory->name()); std::string(factory->name()).c_str());
for (size_t i = 0; i < factories_.size(); ++i) { GPR_ASSERT(factories_.find(factory->name()) == factories_.end());
GPR_ASSERT(strcmp(factories_[i]->name(), factory->name()) != 0); factories_.emplace(factory->name(), std::move(factory));
}
factories_.push_back(std::move(factory));
} }
LoadBalancingPolicyFactory* GetLoadBalancingPolicyFactory( LoadBalancingPolicyFactory* GetLoadBalancingPolicyFactory(
absl::string_view name) const { absl::string_view name) const {
for (size_t i = 0; i < factories_.size(); ++i) { auto it = factories_.find(name);
if (name == factories_[i]->name()) { if (it == factories_.end()) return nullptr;
return factories_[i].get(); return it->second.get();
}
}
return nullptr;
} }
private: private:
std::vector<std::unique_ptr<LoadBalancingPolicyFactory>> factories_; std::map<absl::string_view, std::unique_ptr<LoadBalancingPolicyFactory>>
factories_;
}; };
RegistryState* g_state = nullptr; RegistryState* g_state = nullptr;
@ -96,7 +87,7 @@ void LoadBalancingPolicyRegistry::Builder::RegisterLoadBalancingPolicyFactory(
OrphanablePtr<LoadBalancingPolicy> OrphanablePtr<LoadBalancingPolicy>
LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy( LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
const char* name, LoadBalancingPolicy::Args args) { absl::string_view name, LoadBalancingPolicy::Args args) {
GPR_ASSERT(g_state != nullptr); GPR_ASSERT(g_state != nullptr);
// Find factory. // Find factory.
LoadBalancingPolicyFactory* factory = LoadBalancingPolicyFactory* factory =
@ -110,15 +101,11 @@ bool LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(
absl::string_view name, bool* requires_config) { absl::string_view name, bool* requires_config) {
GPR_ASSERT(g_state != nullptr); GPR_ASSERT(g_state != nullptr);
auto* factory = g_state->GetLoadBalancingPolicyFactory(name); auto* factory = g_state->GetLoadBalancingPolicyFactory(name);
if (factory == nullptr) { if (factory == nullptr) return false;
return false; // If requested, check if the load balancing policy allows an empty config.
}
if (requires_config != nullptr) { if (requires_config != nullptr) {
grpc_error_handle error = GRPC_ERROR_NONE; auto config = factory->ParseLoadBalancingConfig(Json());
// Check if the load balancing policy allows an empty config *requires_config = !config.ok();
*requires_config =
factory->ParseLoadBalancingConfig(Json(), &error) == nullptr;
GRPC_ERROR_UNREF(error);
} }
return true; return true;
} }
@ -127,64 +114,54 @@ namespace {
// Returns the JSON node of policy (with both policy name and config content) // Returns the JSON node of policy (with both policy name and config content)
// given the JSON node of a LoadBalancingConfig array. // given the JSON node of a LoadBalancingConfig array.
grpc_error_handle ParseLoadBalancingConfigHelper( absl::StatusOr<Json::Object::const_iterator> ParseLoadBalancingConfigHelper(
const Json& lb_config_array, Json::Object::const_iterator* result) { const Json& lb_config_array) {
if (lb_config_array.type() != Json::Type::ARRAY) { if (lb_config_array.type() != Json::Type::ARRAY) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("type should be array"); return absl::InvalidArgumentError("type should be array");
} }
// Find the first LB policy that this client supports. // Find the first LB policy that this client supports.
std::vector<absl::string_view> policies_tried; std::vector<absl::string_view> policies_tried;
for (const Json& lb_config : lb_config_array.array_value()) { for (const Json& lb_config : lb_config_array.array_value()) {
if (lb_config.type() != Json::Type::OBJECT) { if (lb_config.type() != Json::Type::OBJECT) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING( return absl::InvalidArgumentError("child entry should be of type object");
"child entry should be of type object");
} }
if (lb_config.object_value().empty()) { if (lb_config.object_value().empty()) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING( return absl::InvalidArgumentError("no policy found in child entry");
"no policy found in child entry");
} }
if (lb_config.object_value().size() > 1) { if (lb_config.object_value().size() > 1) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("oneOf violation"); return absl::InvalidArgumentError("oneOf violation");
} }
auto it = lb_config.object_value().begin(); auto it = lb_config.object_value().begin();
if (it->second.type() != Json::Type::OBJECT) { if (it->second.type() != Json::Type::OBJECT) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING( return absl::InvalidArgumentError("child entry should be of type object");
"child entry should be of type object");
} }
// If we support this policy, then select it. // If we support this policy, then select it.
if (LoadBalancingPolicyRegistry::LoadBalancingPolicyExists( if (LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(
it->first.c_str(), nullptr)) { it->first.c_str(), nullptr)) {
*result = it; return it;
return GRPC_ERROR_NONE;
} }
policies_tried.push_back(it->first); policies_tried.push_back(it->first);
} }
return GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat( return absl::FailedPreconditionError(absl::StrCat(
"No known policies in list: ", absl::StrJoin(policies_tried, " "))); "No known policies in list: ", absl::StrJoin(policies_tried, " ")));
} }
} // namespace } // namespace
RefCountedPtr<LoadBalancingPolicy::Config> absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
LoadBalancingPolicyRegistry::ParseLoadBalancingConfig( LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(const Json& json) {
const Json& json, grpc_error_handle* error) {
GPR_DEBUG_ASSERT(error != nullptr && GRPC_ERROR_IS_NONE(*error));
GPR_ASSERT(g_state != nullptr); GPR_ASSERT(g_state != nullptr);
Json::Object::const_iterator policy; auto policy = ParseLoadBalancingConfigHelper(json);
*error = ParseLoadBalancingConfigHelper(json, &policy); if (!policy.ok()) return policy.status();
if (!GRPC_ERROR_IS_NONE(*error)) {
return nullptr;
}
// Find factory. // Find factory.
LoadBalancingPolicyFactory* factory = LoadBalancingPolicyFactory* factory =
g_state->GetLoadBalancingPolicyFactory(policy->first.c_str()); g_state->GetLoadBalancingPolicyFactory((*policy)->first.c_str());
if (factory == nullptr) { if (factory == nullptr) {
*error = GRPC_ERROR_CREATE_FROM_CPP_STRING( return absl::FailedPreconditionError(absl::StrFormat(
absl::StrFormat("Factory not found for policy \"%s\"", policy->first)); "Factory not found for policy \"%s\"", (*policy)->first));
return nullptr;
} }
// Parse load balancing config via factory. // Parse load balancing config via factory.
return factory->ParseLoadBalancingConfig(policy->second, error); return factory->ParseLoadBalancingConfig((*policy)->second);
} }
} // namespace grpc_core } // namespace grpc_core

@ -1,20 +1,18 @@
/* //
* // Copyright 2015 gRPC authors.
* Copyright 2015 gRPC authors. //
* // Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License. // You may obtain a copy of the License at
* You may obtain a copy of the License at //
* // http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0 //
* // Unless required by applicable law or agreed to in writing, software
* Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS,
* distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and
* See the License for the specific language governing permissions and // limitations under the License.
* limitations under the License. //
*
*/
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H
@ -23,13 +21,13 @@
#include <memory> #include <memory>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "src/core/ext/filters/client_channel/lb_policy.h" #include "src/core/ext/filters/client_channel/lb_policy.h"
#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/lb_policy_factory.h"
#include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
namespace grpc_core { namespace grpc_core {
@ -53,7 +51,7 @@ class LoadBalancingPolicyRegistry {
/// Creates an LB policy of the type specified by \a name. /// Creates an LB policy of the type specified by \a name.
static OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy( static OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
const char* name, LoadBalancingPolicy::Args args); absl::string_view name, LoadBalancingPolicy::Args args);
/// Returns true if the LB policy factory specified by \a name exists in this /// Returns true if the LB policy factory specified by \a name exists in this
/// registry. If the load balancing policy requires a config to be specified /// registry. If the load balancing policy requires a config to be specified
@ -63,10 +61,10 @@ class LoadBalancingPolicyRegistry {
/// Returns a parsed object of the load balancing policy to be used from a /// Returns a parsed object of the load balancing policy to be used from a
/// LoadBalancingConfig array \a json. /// LoadBalancingConfig array \a json.
static RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( static absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& json, grpc_error_handle* error); ParseLoadBalancingConfig(const Json& json);
}; };
} // namespace grpc_core } // namespace grpc_core
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H */ #endif // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H

@ -25,6 +25,8 @@
#include <vector> #include <vector>
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
@ -88,14 +90,13 @@ ClientChannelServiceConfigParser::ParseGlobalParams(const ChannelArgs& /*args*/,
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config; RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config;
auto it = json.object_value().find("loadBalancingConfig"); auto it = json.object_value().find("loadBalancingConfig");
if (it != json.object_value().end()) { if (it != json.object_value().end()) {
grpc_error_handle parse_error = GRPC_ERROR_NONE; auto config =
parsed_lb_config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig( LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(it->second);
it->second, &parse_error); if (!config.ok()) {
if (!GRPC_ERROR_IS_NONE(parse_error)) { error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat(
std::vector<grpc_error_handle> lb_errors; "field:loadBalancingConfig error:", config.status().message())));
lb_errors.push_back(parse_error); } else {
error_list.push_back(GRPC_ERROR_CREATE_FROM_VECTOR( parsed_lb_config = std::move(*config);
"field:loadBalancingConfig", &lb_errors));
} }
} }
// Parse deprecated LB policy. // Parse deprecated LB policy.

@ -99,15 +99,13 @@ XdsRouteLookupClusterSpecifierPlugin::GenerateLoadBalancingPolicyConfig(
// somehow such that we automatically validate the resulting config against // somehow such that we automatically validate the resulting config against
// the gRPC LB policy registry instead of requiring each plugin to do that // the gRPC LB policy registry instead of requiring each plugin to do that
// itself. // itself.
LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(lb_policy_config, auto config =
&parse_error); LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(lb_policy_config);
if (!GRPC_ERROR_IS_NONE(parse_error)) { if (!config.ok()) {
absl::Status status = absl::InvalidArgumentError(absl::StrCat( return absl::InvalidArgumentError(absl::StrCat(
kXdsRouteLookupClusterSpecifierPluginConfigName, kXdsRouteLookupClusterSpecifierPluginConfigName,
" ClusterSpecifierPlugin returned invalid LB policy config: ", " ClusterSpecifierPlugin returned invalid LB policy config: ",
grpc_error_std_string(parse_error))); config.status().message()));
GRPC_ERROR_UNREF(parse_error);
return status;
} }
return lb_policy_config.Dump(); return lb_policy_config.Dump();
} }

@ -161,12 +161,12 @@ TEST_F(RlsConfigParsingTest, InvalidChildPolicyConfig) {
grpc_error_handle error = GRPC_ERROR_NONE; grpc_error_handle error = GRPC_ERROR_NONE;
auto service_config = auto service_config =
ServiceConfigImpl::Create(ChannelArgs(), service_config_json, &error); ServiceConfigImpl::Create(ChannelArgs(), service_config_json, &error);
EXPECT_THAT( EXPECT_THAT(grpc_error_std_string(error),
grpc_error_std_string(error), ::testing::ContainsRegex(
::testing::ContainsRegex( "errors parsing RLS LB policy config" CHILD_ERROR_TAG
"errors parsing RLS LB policy config" CHILD_ERROR_TAG "field:childPolicy" CHILD_ERROR_TAG
"field:childPolicy" CHILD_ERROR_TAG "GrpcLb Parser" CHILD_ERROR_TAG "errors parsing grpclb LB policy config: \\["
"field:childPolicy" CHILD_ERROR_TAG "type should be array")); "error parsing childPolicy field: type should be array\\]"));
GRPC_ERROR_UNREF(error); GRPC_ERROR_UNREF(error);
} }

@ -534,7 +534,7 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigPickFirst) {
static_cast<internal::ClientChannelGlobalParsedConfig*>( static_cast<internal::ClientChannelGlobalParsedConfig*>(
svc_cfg->GetGlobalParsedConfig(0)); svc_cfg->GetGlobalParsedConfig(0));
auto lb_config = parsed_config->parsed_lb_config(); auto lb_config = parsed_config->parsed_lb_config();
EXPECT_STREQ(lb_config->name(), "pick_first"); EXPECT_EQ(lb_config->name(), "pick_first");
} }
TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigRoundRobin) { TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigRoundRobin) {
@ -546,7 +546,7 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigRoundRobin) {
auto parsed_config = static_cast<internal::ClientChannelGlobalParsedConfig*>( auto parsed_config = static_cast<internal::ClientChannelGlobalParsedConfig*>(
svc_cfg->GetGlobalParsedConfig(0)); svc_cfg->GetGlobalParsedConfig(0));
auto lb_config = parsed_config->parsed_lb_config(); auto lb_config = parsed_config->parsed_lb_config();
EXPECT_STREQ(lb_config->name(), "round_robin"); EXPECT_EQ(lb_config->name(), "round_robin");
} }
TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigGrpclb) { TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigGrpclb) {
@ -560,7 +560,7 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigGrpclb) {
static_cast<internal::ClientChannelGlobalParsedConfig*>( static_cast<internal::ClientChannelGlobalParsedConfig*>(
svc_cfg->GetGlobalParsedConfig(0)); svc_cfg->GetGlobalParsedConfig(0));
auto lb_config = parsed_config->parsed_lb_config(); auto lb_config = parsed_config->parsed_lb_config();
EXPECT_STREQ(lb_config->name(), "grpclb"); EXPECT_EQ(lb_config->name(), "grpclb");
} }
TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigXds) { TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigXds) {
@ -583,7 +583,7 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigXds) {
static_cast<internal::ClientChannelGlobalParsedConfig*>( static_cast<internal::ClientChannelGlobalParsedConfig*>(
svc_cfg->GetGlobalParsedConfig(0)); svc_cfg->GetGlobalParsedConfig(0));
auto lb_config = parsed_config->parsed_lb_config(); auto lb_config = parsed_config->parsed_lb_config();
EXPECT_STREQ(lb_config->name(), "xds_cluster_resolver_experimental"); EXPECT_EQ(lb_config->name(), "xds_cluster_resolver_experimental");
} }
TEST_F(ClientChannelParserTest, UnknownLoadBalancingConfig) { TEST_F(ClientChannelParserTest, UnknownLoadBalancingConfig) {
@ -595,8 +595,8 @@ TEST_F(ClientChannelParserTest, UnknownLoadBalancingConfig) {
::testing::ContainsRegex("Service config parsing error" CHILD_ERROR_TAG ::testing::ContainsRegex("Service config parsing error" CHILD_ERROR_TAG
"Global Params" CHILD_ERROR_TAG "Global Params" CHILD_ERROR_TAG
"Client channel global parser" CHILD_ERROR_TAG "Client channel global parser" CHILD_ERROR_TAG
"field:loadBalancingConfig" CHILD_ERROR_TAG "field:loadBalancingConfig "
"No known policies in list: unknown")); "error:No known policies in list: unknown"));
GRPC_ERROR_UNREF(error); GRPC_ERROR_UNREF(error);
} }
@ -613,9 +613,9 @@ TEST_F(ClientChannelParserTest, InvalidGrpclbLoadBalancingConfig) {
"Service config parsing error" CHILD_ERROR_TAG "Service config parsing error" CHILD_ERROR_TAG
"Global Params" CHILD_ERROR_TAG "Global Params" CHILD_ERROR_TAG
"Client channel global parser" CHILD_ERROR_TAG "Client channel global parser" CHILD_ERROR_TAG
"field:loadBalancingConfig" CHILD_ERROR_TAG "field:loadBalancingConfig error:"
"GrpcLb Parser" CHILD_ERROR_TAG "errors parsing grpclb LB policy config: \\["
"field:childPolicy" CHILD_ERROR_TAG "type should be array")); "error parsing childPolicy field: type should be array\\]"));
GRPC_ERROR_UNREF(error); GRPC_ERROR_UNREF(error);
} }

@ -24,6 +24,8 @@
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include <grpc/byte_buffer.h> #include <grpc/byte_buffer.h>
#include <grpc/grpc.h> #include <grpc/grpc.h>
@ -39,7 +41,6 @@
#include "src/core/lib/gpr/useful.h" #include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
#include "test/core/end2end/cq_verifier.h" #include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/end2end_tests.h" #include "test/core/end2end/end2end_tests.h"
@ -49,13 +50,13 @@
namespace grpc_core { namespace grpc_core {
namespace { namespace {
const char* kDropPolicyName = "drop_lb"; constexpr absl::string_view kDropPolicyName = "drop_lb";
class DropPolicy : public LoadBalancingPolicy { class DropPolicy : public LoadBalancingPolicy {
public: public:
explicit DropPolicy(Args args) : LoadBalancingPolicy(std::move(args)) {} explicit DropPolicy(Args args) : LoadBalancingPolicy(std::move(args)) {}
const char* name() const override { return kDropPolicyName; } absl::string_view name() const override { return kDropPolicyName; }
void UpdateLocked(UpdateArgs) override { void UpdateLocked(UpdateArgs) override {
channel_control_helper()->UpdateState(GRPC_CHANNEL_READY, absl::Status(), channel_control_helper()->UpdateState(GRPC_CHANNEL_READY, absl::Status(),
@ -77,7 +78,7 @@ class DropPolicy : public LoadBalancingPolicy {
class DropLbConfig : public LoadBalancingPolicy::Config { class DropLbConfig : public LoadBalancingPolicy::Config {
public: public:
const char* name() const override { return kDropPolicyName; } absl::string_view name() const override { return kDropPolicyName; }
}; };
class DropPolicyFactory : public LoadBalancingPolicyFactory { class DropPolicyFactory : public LoadBalancingPolicyFactory {
@ -87,10 +88,10 @@ class DropPolicyFactory : public LoadBalancingPolicyFactory {
return MakeOrphanable<DropPolicy>(std::move(args)); return MakeOrphanable<DropPolicy>(std::move(args));
} }
const char* name() const override { return kDropPolicyName; } absl::string_view name() const override { return kDropPolicyName; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& /*json*/, grpc_error_handle* /*error*/) const override { ParseLoadBalancingConfig(const Json& /*json*/) const override {
return MakeRefCounted<DropLbConfig>(); return MakeRefCounted<DropLbConfig>();
} }
}; };

@ -23,6 +23,8 @@
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include <grpc/byte_buffer.h> #include <grpc/byte_buffer.h>
#include <grpc/grpc.h> #include <grpc/grpc.h>
@ -38,7 +40,6 @@
#include "src/core/lib/gpr/useful.h" #include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
#include "test/core/end2end/cq_verifier.h" #include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/end2end_tests.h" #include "test/core/end2end/end2end_tests.h"
@ -47,7 +48,7 @@
namespace grpc_core { namespace grpc_core {
namespace { namespace {
const char* kFailPolicyName = "fail_lb"; constexpr absl::string_view kFailPolicyName = "fail_lb";
std::atomic<int> g_num_lb_picks; std::atomic<int> g_num_lb_picks;
@ -55,7 +56,7 @@ class FailPolicy : public LoadBalancingPolicy {
public: public:
explicit FailPolicy(Args args) : LoadBalancingPolicy(std::move(args)) {} explicit FailPolicy(Args args) : LoadBalancingPolicy(std::move(args)) {}
const char* name() const override { return kFailPolicyName; } absl::string_view name() const override { return kFailPolicyName; }
void UpdateLocked(UpdateArgs) override { void UpdateLocked(UpdateArgs) override {
absl::Status status = absl::AbortedError("LB pick failed"); absl::Status status = absl::AbortedError("LB pick failed");
@ -84,7 +85,7 @@ class FailPolicy : public LoadBalancingPolicy {
class FailLbConfig : public LoadBalancingPolicy::Config { class FailLbConfig : public LoadBalancingPolicy::Config {
public: public:
const char* name() const override { return kFailPolicyName; } absl::string_view name() const override { return kFailPolicyName; }
}; };
class FailPolicyFactory : public LoadBalancingPolicyFactory { class FailPolicyFactory : public LoadBalancingPolicyFactory {
@ -94,10 +95,10 @@ class FailPolicyFactory : public LoadBalancingPolicyFactory {
return MakeOrphanable<FailPolicy>(std::move(args)); return MakeOrphanable<FailPolicy>(std::move(args));
} }
const char* name() const override { return kFailPolicyName; } absl::string_view name() const override { return kFailPolicyName; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& /*json*/, grpc_error_handle* /*error*/) const override { ParseLoadBalancingConfig(const Json& /*json*/) const override {
return MakeRefCounted<FailLbConfig>(); return MakeRefCounted<FailLbConfig>();
} }
}; };

@ -60,7 +60,7 @@ class ForwardingLoadBalancingPolicy : public LoadBalancingPolicy {
public: public:
ForwardingLoadBalancingPolicy( ForwardingLoadBalancingPolicy(
std::unique_ptr<ChannelControlHelper> delegating_helper, Args args, std::unique_ptr<ChannelControlHelper> delegating_helper, Args args,
const char* delegate_policy_name, intptr_t initial_refcount = 1) absl::string_view delegate_policy_name, intptr_t initial_refcount = 1)
: LoadBalancingPolicy(std::move(args), initial_refcount) { : LoadBalancingPolicy(std::move(args), initial_refcount) {
Args delegate_args; Args delegate_args;
delegate_args.work_serializer = work_serializer(); delegate_args.work_serializer = work_serializer();
@ -92,12 +92,12 @@ class ForwardingLoadBalancingPolicy : public LoadBalancingPolicy {
// TestPickArgsLb // TestPickArgsLb
// //
constexpr char kTestPickArgsLbPolicyName[] = "test_pick_args_lb"; constexpr absl::string_view kTestPickArgsLbPolicyName = "test_pick_args_lb";
class TestPickArgsLb : public ForwardingLoadBalancingPolicy { class TestPickArgsLb : public ForwardingLoadBalancingPolicy {
public: public:
TestPickArgsLb(Args args, TestPickArgsCallback cb, TestPickArgsLb(Args args, TestPickArgsCallback cb,
const char* delegate_policy_name) absl::string_view delegate_policy_name)
: ForwardingLoadBalancingPolicy( : ForwardingLoadBalancingPolicy(
absl::make_unique<Helper>(RefCountedPtr<TestPickArgsLb>(this), cb), absl::make_unique<Helper>(RefCountedPtr<TestPickArgsLb>(this), cb),
std::move(args), delegate_policy_name, std::move(args), delegate_policy_name,
@ -105,7 +105,7 @@ class TestPickArgsLb : public ForwardingLoadBalancingPolicy {
~TestPickArgsLb() override = default; ~TestPickArgsLb() override = default;
const char* name() const override { return kTestPickArgsLbPolicyName; } absl::string_view name() const override { return kTestPickArgsLbPolicyName; }
private: private:
class Picker : public SubchannelPicker { class Picker : public SubchannelPicker {
@ -167,13 +167,13 @@ class TestPickArgsLb : public ForwardingLoadBalancingPolicy {
class TestPickArgsLbConfig : public LoadBalancingPolicy::Config { class TestPickArgsLbConfig : public LoadBalancingPolicy::Config {
public: public:
const char* name() const override { return kTestPickArgsLbPolicyName; } absl::string_view name() const override { return kTestPickArgsLbPolicyName; }
}; };
class TestPickArgsLbFactory : public LoadBalancingPolicyFactory { class TestPickArgsLbFactory : public LoadBalancingPolicyFactory {
public: public:
explicit TestPickArgsLbFactory(TestPickArgsCallback cb, explicit TestPickArgsLbFactory(TestPickArgsCallback cb,
const char* delegate_policy_name) absl::string_view delegate_policy_name)
: cb_(std::move(cb)), delegate_policy_name_(delegate_policy_name) {} : cb_(std::move(cb)), delegate_policy_name_(delegate_policy_name) {}
OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy( OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
@ -182,16 +182,16 @@ class TestPickArgsLbFactory : public LoadBalancingPolicyFactory {
delegate_policy_name_); delegate_policy_name_);
} }
const char* name() const override { return kTestPickArgsLbPolicyName; } absl::string_view name() const override { return kTestPickArgsLbPolicyName; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& /*json*/, grpc_error_handle* /*error*/) const override { ParseLoadBalancingConfig(const Json& /*json*/) const override {
return MakeRefCounted<TestPickArgsLbConfig>(); return MakeRefCounted<TestPickArgsLbConfig>();
} }
private: private:
TestPickArgsCallback cb_; TestPickArgsCallback cb_;
const char* delegate_policy_name_; std::string delegate_policy_name_;
}; };
// //
@ -217,7 +217,7 @@ class InterceptRecvTrailingMetadataLoadBalancingPolicy
~InterceptRecvTrailingMetadataLoadBalancingPolicy() override = default; ~InterceptRecvTrailingMetadataLoadBalancingPolicy() override = default;
const char* name() const override { absl::string_view name() const override {
return kInterceptRecvTrailingMetadataLbPolicyName; return kInterceptRecvTrailingMetadataLbPolicyName;
} }
@ -305,7 +305,7 @@ class InterceptRecvTrailingMetadataLoadBalancingPolicy
class InterceptTrailingConfig : public LoadBalancingPolicy::Config { class InterceptTrailingConfig : public LoadBalancingPolicy::Config {
public: public:
const char* name() const override { absl::string_view name() const override {
return kInterceptRecvTrailingMetadataLbPolicyName; return kInterceptRecvTrailingMetadataLbPolicyName;
} }
}; };
@ -321,12 +321,12 @@ class InterceptTrailingFactory : public LoadBalancingPolicyFactory {
std::move(args), cb_); std::move(args), cb_);
} }
const char* name() const override { absl::string_view name() const override {
return kInterceptRecvTrailingMetadataLbPolicyName; return kInterceptRecvTrailingMetadataLbPolicyName;
} }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& /*json*/, grpc_error_handle* /*error*/) const override { ParseLoadBalancingConfig(const Json& /*json*/) const override {
return MakeRefCounted<InterceptTrailingConfig>(); return MakeRefCounted<InterceptTrailingConfig>();
} }
@ -353,7 +353,7 @@ class AddressTestLoadBalancingPolicy : public ForwardingLoadBalancingPolicy {
~AddressTestLoadBalancingPolicy() override = default; ~AddressTestLoadBalancingPolicy() override = default;
const char* name() const override { return kAddressTestLbPolicyName; } absl::string_view name() const override { return kAddressTestLbPolicyName; }
private: private:
class Helper : public ChannelControlHelper { class Helper : public ChannelControlHelper {
@ -396,7 +396,7 @@ class AddressTestLoadBalancingPolicy : public ForwardingLoadBalancingPolicy {
class AddressTestConfig : public LoadBalancingPolicy::Config { class AddressTestConfig : public LoadBalancingPolicy::Config {
public: public:
const char* name() const override { return kAddressTestLbPolicyName; } absl::string_view name() const override { return kAddressTestLbPolicyName; }
}; };
class AddressTestFactory : public LoadBalancingPolicyFactory { class AddressTestFactory : public LoadBalancingPolicyFactory {
@ -408,10 +408,10 @@ class AddressTestFactory : public LoadBalancingPolicyFactory {
return MakeOrphanable<AddressTestLoadBalancingPolicy>(std::move(args), cb_); return MakeOrphanable<AddressTestLoadBalancingPolicy>(std::move(args), cb_);
} }
const char* name() const override { return kAddressTestLbPolicyName; } absl::string_view name() const override { return kAddressTestLbPolicyName; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& /*json*/, grpc_error_handle* /*error*/) const override { ParseLoadBalancingConfig(const Json& /*json*/) const override {
return MakeRefCounted<AddressTestConfig>(); return MakeRefCounted<AddressTestConfig>();
} }
@ -430,7 +430,7 @@ class FixedAddressConfig : public LoadBalancingPolicy::Config {
explicit FixedAddressConfig(std::string address) explicit FixedAddressConfig(std::string address)
: address_(std::move(address)) {} : address_(std::move(address)) {}
const char* name() const override { return kFixedAddressLbPolicyName; } absl::string_view name() const override { return kFixedAddressLbPolicyName; }
const std::string& address() const { return address_; } const std::string& address() const { return address_; }
@ -450,7 +450,7 @@ class FixedAddressLoadBalancingPolicy : public ForwardingLoadBalancingPolicy {
~FixedAddressLoadBalancingPolicy() override = default; ~FixedAddressLoadBalancingPolicy() override = default;
const char* name() const override { return kFixedAddressLbPolicyName; } absl::string_view name() const override { return kFixedAddressLbPolicyName; }
void UpdateLocked(UpdateArgs args) override { void UpdateLocked(UpdateArgs args) override {
auto* config = static_cast<FixedAddressConfig*>(args.config.get()); auto* config = static_cast<FixedAddressConfig*>(args.config.get());
@ -517,17 +517,20 @@ class FixedAddressFactory : public LoadBalancingPolicyFactory {
return MakeOrphanable<FixedAddressLoadBalancingPolicy>(std::move(args)); return MakeOrphanable<FixedAddressLoadBalancingPolicy>(std::move(args));
} }
const char* name() const override { return kFixedAddressLbPolicyName; } absl::string_view name() const override { return kFixedAddressLbPolicyName; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& json, grpc_error_handle* error) const override { ParseLoadBalancingConfig(const Json& json) const override {
std::vector<grpc_error_handle> error_list; std::vector<grpc_error_handle> error_list;
std::string address; std::string address;
ParseJsonObjectField(json.object_value(), "address", &address, &error_list); ParseJsonObjectField(json.object_value(), "address", &address, &error_list);
if (!error_list.empty()) { if (!error_list.empty()) {
*error = GRPC_ERROR_CREATE_FROM_VECTOR( grpc_error_handle error = GRPC_ERROR_CREATE_FROM_VECTOR(
"errors parsing fixed_address_lb config", &error_list); "errors parsing fixed_address_lb config", &error_list);
return nullptr; absl::Status status =
absl::InvalidArgumentError(grpc_error_std_string(error));
GRPC_ERROR_UNREF(error);
return status;
} }
return MakeRefCounted<FixedAddressConfig>(std::move(address)); return MakeRefCounted<FixedAddressConfig>(std::move(address));
} }
@ -542,7 +545,7 @@ constexpr char kOobBackendMetricTestLbPolicyName[] =
class OobBackendMetricTestConfig : public LoadBalancingPolicy::Config { class OobBackendMetricTestConfig : public LoadBalancingPolicy::Config {
public: public:
const char* name() const override { absl::string_view name() const override {
return kOobBackendMetricTestLbPolicyName; return kOobBackendMetricTestLbPolicyName;
} }
}; };
@ -562,7 +565,7 @@ class OobBackendMetricTestLoadBalancingPolicy
~OobBackendMetricTestLoadBalancingPolicy() override = default; ~OobBackendMetricTestLoadBalancingPolicy() override = default;
const char* name() const override { absl::string_view name() const override {
return kOobBackendMetricTestLbPolicyName; return kOobBackendMetricTestLbPolicyName;
} }
@ -638,12 +641,12 @@ class OobBackendMetricTestFactory : public LoadBalancingPolicyFactory {
std::move(args), cb_); std::move(args), cb_);
} }
const char* name() const override { absl::string_view name() const override {
return kOobBackendMetricTestLbPolicyName; return kOobBackendMetricTestLbPolicyName;
} }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& /*json*/, grpc_error_handle* /*error*/) const override { ParseLoadBalancingConfig(const Json& /*json*/) const override {
return MakeRefCounted<OobBackendMetricTestConfig>(); return MakeRefCounted<OobBackendMetricTestConfig>();
} }
@ -653,8 +656,8 @@ class OobBackendMetricTestFactory : public LoadBalancingPolicyFactory {
} // namespace } // namespace
void RegisterTestPickArgsLoadBalancingPolicy(TestPickArgsCallback cb, void RegisterTestPickArgsLoadBalancingPolicy(
const char* delegate_policy_name) { TestPickArgsCallback cb, absl::string_view delegate_policy_name) {
LoadBalancingPolicyRegistry::Builder::RegisterLoadBalancingPolicyFactory( LoadBalancingPolicyRegistry::Builder::RegisterLoadBalancingPolicyFactory(
absl::make_unique<TestPickArgsLbFactory>(std::move(cb), absl::make_unique<TestPickArgsLbFactory>(std::move(cb),
delegate_policy_name)); delegate_policy_name));

@ -23,6 +23,7 @@
#include <vector> #include <vector>
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "src/core/ext/filters/client_channel/lb_policy/backend_metric_data.h" #include "src/core/ext/filters/client_channel/lb_policy/backend_metric_data.h"
#include "src/core/lib/resolver/server_address.h" #include "src/core/lib/resolver/server_address.h"
@ -41,7 +42,8 @@ using TestPickArgsCallback = std::function<void(const PickArgsSeen&)>;
// Registers an LB policy called "test_pick_args_lb" that passes the args // Registers an LB policy called "test_pick_args_lb" that passes the args
// passed to SubchannelPicker::Pick() to cb. // passed to SubchannelPicker::Pick() to cb.
void RegisterTestPickArgsLoadBalancingPolicy( void RegisterTestPickArgsLoadBalancingPolicy(
TestPickArgsCallback cb, const char* delegate_policy_name = "pick_first"); TestPickArgsCallback cb,
absl::string_view delegate_policy_name = "pick_first");
struct TrailingMetadataArgsSeen { struct TrailingMetadataArgsSeen {
absl::Status status; absl::Status status;

@ -274,10 +274,10 @@ class CustomLbPolicyFactory : public LoadBalancingPolicyFactory {
return nullptr; return nullptr;
} }
const char* name() const override { return "test.CustomLb"; } absl::string_view name() const override { return "test.CustomLb"; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
const Json& /* json */, grpc_error_handle* /* error */) const override { ParseLoadBalancingConfig(const Json& /*json*/) const override {
return nullptr; return nullptr;
} }
}; };

Loading…
Cancel
Save