mirror of https://github.com/grpc/grpc.git
parent
cdb3b827a4
commit
71050c88b9
19 changed files with 656 additions and 49 deletions
@ -0,0 +1,571 @@ |
|||||||
|
//
|
||||||
|
// Copyright 2018 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "absl/strings/string_view.h" |
||||||
|
|
||||||
|
#include <grpc/grpc.h> |
||||||
|
|
||||||
|
#include "src/core/ext/filters/client_channel/lb_policy.h" |
||||||
|
#include "src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h" |
||||||
|
#include "src/core/ext/filters/client_channel/lb_policy_factory.h" |
||||||
|
#include "src/core/ext/filters/client_channel/lb_policy_registry.h" |
||||||
|
#include "src/core/ext/xds/xds_client.h" |
||||||
|
#include "src/core/ext/xds/xds_client_stats.h" |
||||||
|
#include "src/core/lib/channel/channel_args.h" |
||||||
|
#include "src/core/lib/gpr/string.h" |
||||||
|
#include "src/core/lib/gprpp/orphanable.h" |
||||||
|
#include "src/core/lib/gprpp/ref_counted_ptr.h" |
||||||
|
#include "src/core/lib/iomgr/work_serializer.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
TraceFlag grpc_eds_drop_lb_trace(false, "eds_drop_lb"); |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
constexpr char kEdsDrop[] = "eds_drop_experimental"; |
||||||
|
|
||||||
|
// Config for EDS drop LB policy.
|
||||||
|
class EdsDropLbConfig : public LoadBalancingPolicy::Config { |
||||||
|
public: |
||||||
|
EdsDropLbConfig(RefCountedPtr<LoadBalancingPolicy::Config> child_policy, |
||||||
|
std::string cluster_name, std::string eds_service_name, |
||||||
|
absl::optional<std::string> lrs_load_reporting_server_name, |
||||||
|
RefCountedPtr<XdsApi::EdsUpdate::DropConfig> drop_config) |
||||||
|
: child_policy_(std::move(child_policy)), |
||||||
|
cluster_name_(std::move(cluster_name)), |
||||||
|
eds_service_name_(std::move(eds_service_name)), |
||||||
|
lrs_load_reporting_server_name_( |
||||||
|
std::move(lrs_load_reporting_server_name)), |
||||||
|
drop_config_(std::move(drop_config)) {} |
||||||
|
|
||||||
|
const char* name() const override { return kEdsDrop; } |
||||||
|
|
||||||
|
RefCountedPtr<LoadBalancingPolicy::Config> child_policy() const { |
||||||
|
return child_policy_; |
||||||
|
} |
||||||
|
const std::string& cluster_name() const { return cluster_name_; } |
||||||
|
const std::string& eds_service_name() const { return eds_service_name_; } |
||||||
|
const absl::optional<std::string>& lrs_load_reporting_server_name() const { |
||||||
|
return lrs_load_reporting_server_name_; |
||||||
|
}; |
||||||
|
RefCountedPtr<XdsApi::EdsUpdate::DropConfig> drop_config() const { |
||||||
|
return drop_config_; |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
RefCountedPtr<LoadBalancingPolicy::Config> child_policy_; |
||||||
|
std::string cluster_name_; |
||||||
|
std::string eds_service_name_; |
||||||
|
absl::optional<std::string> lrs_load_reporting_server_name_; |
||||||
|
RefCountedPtr<XdsApi::EdsUpdate::DropConfig> drop_config_; |
||||||
|
}; |
||||||
|
|
||||||
|
// EDS Drop LB policy.
|
||||||
|
class EdsDropLb : public LoadBalancingPolicy { |
||||||
|
public: |
||||||
|
EdsDropLb(RefCountedPtr<XdsClient> xds_client, Args args); |
||||||
|
|
||||||
|
const char* name() const override { return kEdsDrop; } |
||||||
|
|
||||||
|
void UpdateLocked(UpdateArgs args) override; |
||||||
|
void ExitIdleLocked() override; |
||||||
|
void ResetBackoffLocked() override; |
||||||
|
|
||||||
|
private: |
||||||
|
// A simple wrapper for ref-counting a picker from the child policy.
|
||||||
|
class RefCountedPicker : public RefCounted<RefCountedPicker> { |
||||||
|
public: |
||||||
|
explicit RefCountedPicker(std::unique_ptr<SubchannelPicker> picker) |
||||||
|
: picker_(std::move(picker)) {} |
||||||
|
PickResult Pick(PickArgs args) { return picker_->Pick(args); } |
||||||
|
|
||||||
|
private: |
||||||
|
std::unique_ptr<SubchannelPicker> picker_; |
||||||
|
}; |
||||||
|
|
||||||
|
// A picker that wraps the picker from the child to perform drops.
|
||||||
|
class DropPicker : public SubchannelPicker { |
||||||
|
public: |
||||||
|
DropPicker(EdsDropLb* eds_drop_lb, RefCountedPtr<RefCountedPicker> picker) |
||||||
|
: drop_config_(eds_drop_lb->config_->drop_config()), |
||||||
|
drop_stats_(eds_drop_lb->drop_stats_), |
||||||
|
picker_(std::move(picker)) {} |
||||||
|
|
||||||
|
PickResult Pick(PickArgs args); |
||||||
|
|
||||||
|
private: |
||||||
|
RefCountedPtr<XdsApi::EdsUpdate::DropConfig> drop_config_; |
||||||
|
RefCountedPtr<XdsClusterDropStats> drop_stats_; |
||||||
|
RefCountedPtr<RefCountedPicker> picker_; |
||||||
|
}; |
||||||
|
|
||||||
|
class Helper : public ChannelControlHelper { |
||||||
|
public: |
||||||
|
explicit Helper(RefCountedPtr<EdsDropLb> eds_drop_policy) |
||||||
|
: eds_drop_policy_(std::move(eds_drop_policy)) {} |
||||||
|
|
||||||
|
~Helper() { eds_drop_policy_.reset(DEBUG_LOCATION, "Helper"); } |
||||||
|
|
||||||
|
RefCountedPtr<SubchannelInterface> CreateSubchannel( |
||||||
|
ServerAddress address, const grpc_channel_args& args) override; |
||||||
|
void UpdateState(grpc_connectivity_state state, const absl::Status& status, |
||||||
|
std::unique_ptr<SubchannelPicker> picker) override; |
||||||
|
void RequestReresolution() override; |
||||||
|
void AddTraceEvent(TraceSeverity severity, |
||||||
|
absl::string_view message) override; |
||||||
|
|
||||||
|
private: |
||||||
|
RefCountedPtr<EdsDropLb> eds_drop_policy_; |
||||||
|
}; |
||||||
|
|
||||||
|
~EdsDropLb(); |
||||||
|
|
||||||
|
void ShutdownLocked() override; |
||||||
|
|
||||||
|
OrphanablePtr<LoadBalancingPolicy> CreateChildPolicyLocked( |
||||||
|
const grpc_channel_args* args); |
||||||
|
void UpdateChildPolicyLocked(ServerAddressList addresses, |
||||||
|
const grpc_channel_args* args); |
||||||
|
|
||||||
|
void MaybeUpdatePickerLocked(); |
||||||
|
|
||||||
|
// Current config from the resolver.
|
||||||
|
RefCountedPtr<EdsDropLbConfig> config_; |
||||||
|
|
||||||
|
// Internal state.
|
||||||
|
bool shutting_down_ = false; |
||||||
|
|
||||||
|
// The xds client.
|
||||||
|
RefCountedPtr<XdsClient> xds_client_; |
||||||
|
|
||||||
|
// The stats for client-side load reporting.
|
||||||
|
RefCountedPtr<XdsClusterDropStats> drop_stats_; |
||||||
|
|
||||||
|
OrphanablePtr<LoadBalancingPolicy> child_policy_; |
||||||
|
|
||||||
|
// Latest state and picker reported by the child policy.
|
||||||
|
grpc_connectivity_state state_ = GRPC_CHANNEL_IDLE; |
||||||
|
absl::Status status_; |
||||||
|
RefCountedPtr<RefCountedPicker> picker_; |
||||||
|
}; |
||||||
|
|
||||||
|
//
|
||||||
|
// EdsDropLb::DropPicker
|
||||||
|
//
|
||||||
|
|
||||||
|
LoadBalancingPolicy::PickResult EdsDropLb::DropPicker::Pick( |
||||||
|
LoadBalancingPolicy::PickArgs args) { |
||||||
|
// Handle drop.
|
||||||
|
const std::string* drop_category; |
||||||
|
if (drop_config_->ShouldDrop(&drop_category)) { |
||||||
|
if (drop_stats_ != nullptr) drop_stats_->AddCallDropped(*drop_category); |
||||||
|
PickResult result; |
||||||
|
result.type = PickResult::PICK_COMPLETE; |
||||||
|
return result; |
||||||
|
} |
||||||
|
// If we're not dropping the call, we should always have a child picker.
|
||||||
|
if (picker_ == nullptr) { // Should never happen.
|
||||||
|
PickResult result; |
||||||
|
result.type = PickResult::PICK_FAILED; |
||||||
|
result.error = |
||||||
|
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"eds_drop picker not given any child picker"), |
||||||
|
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_INTERNAL); |
||||||
|
return result; |
||||||
|
} |
||||||
|
// Not dropping, so delegate to child picker.
|
||||||
|
return picker_->Pick(args); |
||||||
|
} |
||||||
|
|
||||||
|
//
|
||||||
|
// EdsDropLb
|
||||||
|
//
|
||||||
|
|
||||||
|
EdsDropLb::EdsDropLb(RefCountedPtr<XdsClient> xds_client, Args args) |
||||||
|
: LoadBalancingPolicy(std::move(args)), xds_client_(std::move(xds_client)) { |
||||||
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_eds_drop_lb_trace)) { |
||||||
|
gpr_log(GPR_INFO, "[eds_drop_lb %p] created -- using xds client %p", this, |
||||||
|
xds_client_.get()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
EdsDropLb::~EdsDropLb() { |
||||||
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_eds_drop_lb_trace)) { |
||||||
|
gpr_log(GPR_INFO, "[eds_drop_lb %p] destroying xds LB policy", this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void EdsDropLb::ShutdownLocked() { |
||||||
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_eds_drop_lb_trace)) { |
||||||
|
gpr_log(GPR_INFO, "[eds_drop_lb %p] shutting down", this); |
||||||
|
} |
||||||
|
shutting_down_ = true; |
||||||
|
// Remove the child policy's interested_parties pollset_set from the
|
||||||
|
// xDS policy.
|
||||||
|
if (child_policy_ != nullptr) { |
||||||
|
grpc_pollset_set_del_pollset_set(child_policy_->interested_parties(), |
||||||
|
interested_parties()); |
||||||
|
child_policy_.reset(); |
||||||
|
} |
||||||
|
// Drop our ref to the child's picker, in case it's holding a ref to
|
||||||
|
// the child.
|
||||||
|
picker_.reset(); |
||||||
|
drop_stats_.reset(); |
||||||
|
xds_client_.reset(); |
||||||
|
} |
||||||
|
|
||||||
|
void EdsDropLb::ExitIdleLocked() { |
||||||
|
if (child_policy_ != nullptr) child_policy_->ExitIdleLocked(); |
||||||
|
} |
||||||
|
|
||||||
|
void EdsDropLb::ResetBackoffLocked() { |
||||||
|
// The XdsClient will have its backoff reset by the xds resolver, so we
|
||||||
|
// don't need to do it here.
|
||||||
|
if (child_policy_ != nullptr) child_policy_->ResetBackoffLocked(); |
||||||
|
} |
||||||
|
|
||||||
|
void EdsDropLb::UpdateLocked(UpdateArgs args) { |
||||||
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_eds_drop_lb_trace)) { |
||||||
|
gpr_log(GPR_INFO, "[eds_drop_lb %p] Received update", this); |
||||||
|
} |
||||||
|
// Update config.
|
||||||
|
auto old_config = std::move(config_); |
||||||
|
config_ = std::move(args.config); |
||||||
|
// Update load reporting if needed.
|
||||||
|
if (old_config == nullptr || |
||||||
|
config_->lrs_load_reporting_server_name() != |
||||||
|
old_config->lrs_load_reporting_server_name() || |
||||||
|
config_->cluster_name() != old_config->cluster_name() || |
||||||
|
config_->eds_service_name() != old_config->eds_service_name()) { |
||||||
|
drop_stats_.reset(); |
||||||
|
if (config_->lrs_load_reporting_server_name().has_value()) { |
||||||
|
drop_stats_ = xds_client_->AddClusterDropStats( |
||||||
|
config_->lrs_load_reporting_server_name().value(), |
||||||
|
config_->cluster_name(), config_->eds_service_name()); |
||||||
|
} |
||||||
|
MaybeUpdatePickerLocked(); |
||||||
|
} |
||||||
|
// Update child policy.
|
||||||
|
UpdateChildPolicyLocked(std::move(args.addresses), args.args); |
||||||
|
args.args = nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
void EdsDropLb::MaybeUpdatePickerLocked() { |
||||||
|
// If we're dropping all calls, report READY, regardless of what (or
|
||||||
|
// whether) the child has reported.
|
||||||
|
if (config_->drop_config() != nullptr && config_->drop_config()->drop_all()) { |
||||||
|
auto drop_picker = absl::make_unique<DropPicker>(this, picker_); |
||||||
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_eds_drop_lb_trace)) { |
||||||
|
gpr_log(GPR_INFO, |
||||||
|
"[eds_drop_lb %p] updating connectivity (drop all): state=READY " |
||||||
|
"picker=%p", |
||||||
|
this, drop_picker.get()); |
||||||
|
} |
||||||
|
channel_control_helper()->UpdateState(GRPC_CHANNEL_READY, absl::Status(), |
||||||
|
std::move(drop_picker)); |
||||||
|
return; |
||||||
|
} |
||||||
|
// Otherwise, update only if we have a child picker.
|
||||||
|
if (picker_ != nullptr) { |
||||||
|
auto drop_picker = absl::make_unique<DropPicker>(this, picker_); |
||||||
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_eds_drop_lb_trace)) { |
||||||
|
gpr_log(GPR_INFO, |
||||||
|
"[eds_drop_lb %p] updating connectivity: state=%s status=(%s) " |
||||||
|
"picker=%p", |
||||||
|
this, ConnectivityStateName(state_), status_.ToString().c_str(), |
||||||
|
drop_picker.get()); |
||||||
|
} |
||||||
|
channel_control_helper()->UpdateState(state_, status_, |
||||||
|
std::move(drop_picker)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
OrphanablePtr<LoadBalancingPolicy> EdsDropLb::CreateChildPolicyLocked( |
||||||
|
const grpc_channel_args* args) { |
||||||
|
LoadBalancingPolicy::Args lb_policy_args; |
||||||
|
lb_policy_args.work_serializer = work_serializer(); |
||||||
|
lb_policy_args.args = args; |
||||||
|
lb_policy_args.channel_control_helper = |
||||||
|
absl::make_unique<Helper>(Ref(DEBUG_LOCATION, "Helper")); |
||||||
|
OrphanablePtr<LoadBalancingPolicy> lb_policy = |
||||||
|
MakeOrphanable<ChildPolicyHandler>(std::move(lb_policy_args), |
||||||
|
&grpc_eds_drop_lb_trace); |
||||||
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_eds_drop_lb_trace)) { |
||||||
|
gpr_log(GPR_INFO, "[eds_drop_lb %p] Created new child policy handler %p", |
||||||
|
this, lb_policy.get()); |
||||||
|
} |
||||||
|
// Add our interested_parties pollset_set to that of the newly created
|
||||||
|
// child policy. This will make the child policy progress upon activity on
|
||||||
|
// this policy, which in turn is tied to the application's call.
|
||||||
|
grpc_pollset_set_add_pollset_set(lb_policy->interested_parties(), |
||||||
|
interested_parties()); |
||||||
|
return lb_policy; |
||||||
|
} |
||||||
|
|
||||||
|
void EdsDropLb::UpdateChildPolicyLocked(ServerAddressList addresses, |
||||||
|
const grpc_channel_args* args) { |
||||||
|
// Create policy if needed.
|
||||||
|
if (child_policy_ == nullptr) { |
||||||
|
child_policy_ = CreateChildPolicyLocked(args); |
||||||
|
} |
||||||
|
// Construct update args.
|
||||||
|
UpdateArgs update_args; |
||||||
|
update_args.addresses = std::move(addresses); |
||||||
|
update_args.config = config_->child_policy(); |
||||||
|
update_args.args = args; |
||||||
|
// Update the policy.
|
||||||
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_eds_drop_lb_trace)) { |
||||||
|
gpr_log(GPR_INFO, "[eds_drop_lb %p] Updating child policy handler %p", this, |
||||||
|
child_policy_.get()); |
||||||
|
} |
||||||
|
child_policy_->UpdateLocked(std::move(update_args)); |
||||||
|
} |
||||||
|
|
||||||
|
//
|
||||||
|
// EdsDropLb::Helper
|
||||||
|
//
|
||||||
|
|
||||||
|
RefCountedPtr<SubchannelInterface> EdsDropLb::Helper::CreateSubchannel( |
||||||
|
ServerAddress address, const grpc_channel_args& args) { |
||||||
|
if (eds_drop_policy_->shutting_down_) return nullptr; |
||||||
|
return eds_drop_policy_->channel_control_helper()->CreateSubchannel( |
||||||
|
std::move(address), args); |
||||||
|
} |
||||||
|
|
||||||
|
void EdsDropLb::Helper::UpdateState(grpc_connectivity_state state, |
||||||
|
const absl::Status& status, |
||||||
|
std::unique_ptr<SubchannelPicker> picker) { |
||||||
|
if (eds_drop_policy_->shutting_down_) return; |
||||||
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_eds_drop_lb_trace)) { |
||||||
|
gpr_log(GPR_INFO, |
||||||
|
"[eds_drop_lb %p] child connectivity state update: state=%s (%s) " |
||||||
|
"picker=%p", |
||||||
|
eds_drop_policy_.get(), ConnectivityStateName(state), |
||||||
|
status.ToString().c_str(), picker.get()); |
||||||
|
} |
||||||
|
// Save the state and picker.
|
||||||
|
eds_drop_policy_->state_ = state; |
||||||
|
eds_drop_policy_->status_ = status; |
||||||
|
eds_drop_policy_->picker_ = |
||||||
|
MakeRefCounted<RefCountedPicker>(std::move(picker)); |
||||||
|
// Wrap the picker and return it to the channel.
|
||||||
|
eds_drop_policy_->MaybeUpdatePickerLocked(); |
||||||
|
} |
||||||
|
|
||||||
|
void EdsDropLb::Helper::RequestReresolution() { |
||||||
|
if (eds_drop_policy_->shutting_down_) return; |
||||||
|
eds_drop_policy_->channel_control_helper()->RequestReresolution(); |
||||||
|
} |
||||||
|
|
||||||
|
void EdsDropLb::Helper::AddTraceEvent(TraceSeverity severity, |
||||||
|
absl::string_view message) { |
||||||
|
if (eds_drop_policy_->shutting_down_) return; |
||||||
|
eds_drop_policy_->channel_control_helper()->AddTraceEvent(severity, message); |
||||||
|
} |
||||||
|
|
||||||
|
//
|
||||||
|
// factory
|
||||||
|
//
|
||||||
|
|
||||||
|
class EdsDropLbFactory : public LoadBalancingPolicyFactory { |
||||||
|
public: |
||||||
|
OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy( |
||||||
|
LoadBalancingPolicy::Args args) const override { |
||||||
|
grpc_error* error = GRPC_ERROR_NONE; |
||||||
|
RefCountedPtr<XdsClient> xds_client = XdsClient::GetOrCreate(&error); |
||||||
|
if (error != GRPC_ERROR_NONE) { |
||||||
|
gpr_log(GPR_ERROR, |
||||||
|
"cannot get XdsClient to instantiate eds_drop LB policy: %s", |
||||||
|
grpc_error_string(error)); |
||||||
|
GRPC_ERROR_UNREF(error); |
||||||
|
return nullptr; |
||||||
|
} |
||||||
|
return MakeOrphanable<EdsDropLb>(std::move(xds_client), std::move(args)); |
||||||
|
} |
||||||
|
|
||||||
|
const char* name() const override { return kEdsDrop; } |
||||||
|
|
||||||
|
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( |
||||||
|
const Json& json, grpc_error** error) const override { |
||||||
|
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE); |
||||||
|
if (json.type() == Json::Type::JSON_NULL) { |
||||||
|
// This policy was configured in the deprecated loadBalancingPolicy
|
||||||
|
// field or in the client API.
|
||||||
|
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"field:loadBalancingPolicy error:eds_drop policy requires " |
||||||
|
"configuration. Please use loadBalancingConfig field of service " |
||||||
|
"config instead."); |
||||||
|
return nullptr; |
||||||
|
} |
||||||
|
std::vector<grpc_error*> error_list; |
||||||
|
// Child policy.
|
||||||
|
RefCountedPtr<LoadBalancingPolicy::Config> child_policy; |
||||||
|
auto it = json.object_value().find("childPolicy"); |
||||||
|
if (it == json.object_value().end()) { |
||||||
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"field:childPolicy error:required field missing")); |
||||||
|
} else { |
||||||
|
grpc_error* parse_error = GRPC_ERROR_NONE; |
||||||
|
child_policy = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig( |
||||||
|
it->second, &parse_error); |
||||||
|
if (child_policy == nullptr) { |
||||||
|
GPR_DEBUG_ASSERT(parse_error != GRPC_ERROR_NONE); |
||||||
|
std::vector<grpc_error*> child_errors; |
||||||
|
child_errors.push_back(parse_error); |
||||||
|
error_list.push_back( |
||||||
|
GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors)); |
||||||
|
} |
||||||
|
} |
||||||
|
// Cluster name.
|
||||||
|
std::string cluster_name; |
||||||
|
it = json.object_value().find("clusterName"); |
||||||
|
if (it == json.object_value().end()) { |
||||||
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"field:clusterName error:required field missing")); |
||||||
|
} else if (it->second.type() != Json::Type::STRING) { |
||||||
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"field:clusterName error:type should be string")); |
||||||
|
} else { |
||||||
|
cluster_name = it->second.string_value(); |
||||||
|
} |
||||||
|
// EDS service name.
|
||||||
|
std::string eds_service_name; |
||||||
|
it = json.object_value().find("edsServiceName"); |
||||||
|
if (it != json.object_value().end()) { |
||||||
|
if (it->second.type() != Json::Type::STRING) { |
||||||
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"field:edsServiceName error:type should be string")); |
||||||
|
} else { |
||||||
|
eds_service_name = it->second.string_value(); |
||||||
|
} |
||||||
|
} |
||||||
|
// LRS load reporting server name.
|
||||||
|
absl::optional<std::string> lrs_load_reporting_server_name; |
||||||
|
it = json.object_value().find("lrsLoadReportingServerName"); |
||||||
|
if (it != json.object_value().end()) { |
||||||
|
if (it->second.type() != Json::Type::STRING) { |
||||||
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"field:lrsLoadReportingServerName error:type should be string")); |
||||||
|
} else { |
||||||
|
lrs_load_reporting_server_name = it->second.string_value(); |
||||||
|
} |
||||||
|
} |
||||||
|
// Drop config.
|
||||||
|
auto drop_config = MakeRefCounted<XdsApi::EdsUpdate::DropConfig>(); |
||||||
|
it = json.object_value().find("dropCategories"); |
||||||
|
if (it == json.object_value().end()) { |
||||||
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"field:dropCategories error:required field missing")); |
||||||
|
} else { |
||||||
|
std::vector<grpc_error*> child_errors = |
||||||
|
ParseDropCategories(it->second, drop_config.get()); |
||||||
|
if (!child_errors.empty()) { |
||||||
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_VECTOR( |
||||||
|
"field:dropCategories", &child_errors)); |
||||||
|
} |
||||||
|
} |
||||||
|
if (!error_list.empty()) { |
||||||
|
*error = GRPC_ERROR_CREATE_FROM_VECTOR( |
||||||
|
"eds_drop_experimental LB policy config", &error_list); |
||||||
|
return nullptr; |
||||||
|
} |
||||||
|
return MakeRefCounted<EdsDropLbConfig>( |
||||||
|
std::move(child_policy), std::move(cluster_name), |
||||||
|
std::move(eds_service_name), std::move(lrs_load_reporting_server_name), |
||||||
|
std::move(drop_config)); |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
static std::vector<grpc_error*> ParseDropCategories( |
||||||
|
const Json& json, XdsApi::EdsUpdate::DropConfig* drop_config) { |
||||||
|
std::vector<grpc_error*> error_list; |
||||||
|
if (json.type() != Json::Type::ARRAY) { |
||||||
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"dropCategories field is not an array")); |
||||||
|
return error_list; |
||||||
|
} |
||||||
|
for (size_t i = 0; i < json.array_value().size(); ++i) { |
||||||
|
const Json& entry = json.array_value()[i]; |
||||||
|
std::vector<grpc_error*> child_errors = |
||||||
|
ParseDropCategory(entry, drop_config); |
||||||
|
if (!child_errors.empty()) { |
||||||
|
grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING( |
||||||
|
absl::StrCat("errors parsing index ", i).c_str()); |
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
static std::vector<grpc_error*> ParseDropCategory( |
||||||
|
const Json& json, XdsApi::EdsUpdate::DropConfig* drop_config) { |
||||||
|
std::vector<grpc_error*> error_list; |
||||||
|
if (json.type() != Json::Type::OBJECT) { |
||||||
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"dropCategories entry is not an object")); |
||||||
|
return error_list; |
||||||
|
} |
||||||
|
std::string category; |
||||||
|
auto it = json.object_value().find("category"); |
||||||
|
if (it == json.object_value().end()) { |
||||||
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"\"category\" field not present")); |
||||||
|
} else if (it->second.type() != Json::Type::STRING) { |
||||||
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"\"category\" field is not a string")); |
||||||
|
} else { |
||||||
|
category = it->second.string_value(); |
||||||
|
} |
||||||
|
uint32_t requests_per_million = 0; |
||||||
|
it = json.object_value().find("requests_per_million"); |
||||||
|
if (it == json.object_value().end()) { |
||||||
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"\"requests_per_million\" field is not present")); |
||||||
|
} else if (it->second.type() != Json::Type::NUMBER) { |
||||||
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"\"requests_per_million\" field is not a number")); |
||||||
|
} else { |
||||||
|
requests_per_million = |
||||||
|
gpr_parse_nonnegative_int(it->second.string_value().c_str()); |
||||||
|
} |
||||||
|
if (error_list.empty()) { |
||||||
|
drop_config->AddCategory(std::move(category), requests_per_million); |
||||||
|
} |
||||||
|
return error_list; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
//
|
||||||
|
// Plugin registration
|
||||||
|
//
|
||||||
|
|
||||||
|
void grpc_lb_policy_eds_drop_init() { |
||||||
|
grpc_core::LoadBalancingPolicyRegistry::Builder:: |
||||||
|
RegisterLoadBalancingPolicyFactory( |
||||||
|
absl::make_unique<grpc_core::EdsDropLbFactory>()); |
||||||
|
} |
||||||
|
|
||||||
|
void grpc_lb_policy_eds_drop_shutdown() {} |
Loading…
Reference in new issue