| // |
| // Copyright 2022 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 "src/core/ext/xds/xds_cluster_specifier_plugin.h" |
| |
| #include <stddef.h> |
| |
| #include <map> |
| #include <utility> |
| |
| #include "absl/status/statusor.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/types/variant.h" |
| #include "upb/base/status.h" |
| #include "upb/json/encode.h" |
| #include "upb/upb.hpp" |
| |
| #include <grpc/support/json.h> |
| #include <grpc/support/log.h> |
| |
| #include "src/core/lib/json/json.h" |
| #include "src/core/lib/json/json_reader.h" |
| #include "src/proto/grpc/lookup/v1/rls_config.upb.h" |
| #include "src/proto/grpc/lookup/v1/rls_config.upbdefs.h" |
| |
| namespace grpc_core { |
| |
| // |
| // XdsRouteLookupClusterSpecifierPlugin |
| // |
| |
| absl::string_view XdsRouteLookupClusterSpecifierPlugin::ConfigProtoName() |
| const { |
| return "grpc.lookup.v1.RouteLookupClusterSpecifier"; |
| } |
| |
| void XdsRouteLookupClusterSpecifierPlugin::PopulateSymtab( |
| upb_DefPool* symtab) const { |
| grpc_lookup_v1_RouteLookupConfig_getmsgdef(symtab); |
| } |
| |
| Json XdsRouteLookupClusterSpecifierPlugin::GenerateLoadBalancingPolicyConfig( |
| XdsExtension extension, upb_Arena* arena, upb_DefPool* symtab, |
| ValidationErrors* errors) const { |
| absl::string_view* serialized_plugin_config = |
| absl::get_if<absl::string_view>(&extension.value); |
| if (serialized_plugin_config == nullptr) { |
| errors->AddError("could not parse plugin config"); |
| return {}; |
| } |
| const auto* specifier = grpc_lookup_v1_RouteLookupClusterSpecifier_parse( |
| serialized_plugin_config->data(), serialized_plugin_config->size(), |
| arena); |
| if (specifier == nullptr) { |
| errors->AddError("could not parse plugin config"); |
| return {}; |
| } |
| const auto* plugin_config = |
| grpc_lookup_v1_RouteLookupClusterSpecifier_route_lookup_config(specifier); |
| if (plugin_config == nullptr) { |
| ValidationErrors::ScopedField field(errors, ".route_lookup_config"); |
| errors->AddError("field not present"); |
| return {}; |
| } |
| upb::Status status; |
| const upb_MessageDef* msg_type = |
| grpc_lookup_v1_RouteLookupConfig_getmsgdef(symtab); |
| size_t json_size = upb_JsonEncode(plugin_config, msg_type, symtab, 0, nullptr, |
| 0, status.ptr()); |
| if (json_size == static_cast<size_t>(-1)) { |
| errors->AddError(absl::StrCat("failed to dump proto to JSON: ", |
| upb_Status_ErrorMessage(status.ptr()))); |
| return {}; |
| } |
| void* buf = upb_Arena_Malloc(arena, json_size + 1); |
| upb_JsonEncode(plugin_config, msg_type, symtab, 0, |
| reinterpret_cast<char*>(buf), json_size + 1, status.ptr()); |
| auto json = JsonParse(reinterpret_cast<char*>(buf)); |
| GPR_ASSERT(json.ok()); |
| return Json::FromArray({Json::FromObject( |
| {{"rls_experimental", |
| Json::FromObject({ |
| {"routeLookupConfig", std::move(*json)}, |
| {"childPolicy", |
| Json::FromArray({ |
| Json::FromObject({{"cds_experimental", Json::FromObject({})}}), |
| })}, |
| {"childPolicyConfigTargetFieldName", Json::FromString("cluster")}, |
| })}})}); |
| } |
| |
| // |
| // XdsClusterSpecifierPluginRegistry |
| // |
| |
| XdsClusterSpecifierPluginRegistry::XdsClusterSpecifierPluginRegistry() { |
| RegisterPlugin(std::make_unique<XdsRouteLookupClusterSpecifierPlugin>()); |
| } |
| |
| void XdsClusterSpecifierPluginRegistry::RegisterPlugin( |
| std::unique_ptr<XdsClusterSpecifierPluginImpl> plugin) { |
| absl::string_view name = plugin->ConfigProtoName(); |
| registry_[name] = std::move(plugin); |
| } |
| |
| const XdsClusterSpecifierPluginImpl* |
| XdsClusterSpecifierPluginRegistry::GetPluginForType( |
| absl::string_view config_proto_type_name) const { |
| auto it = registry_.find(config_proto_type_name); |
| if (it == registry_.end()) return nullptr; |
| return it->second.get(); |
| } |
| |
| void XdsClusterSpecifierPluginRegistry::PopulateSymtab( |
| upb_DefPool* symtab) const { |
| for (const auto& p : registry_) { |
| p.second->PopulateSymtab(symtab); |
| } |
| } |
| |
| } // namespace grpc_core |