• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2022 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "src/core/xds/grpc/xds_cluster_specifier_plugin.h"
18 
19 #include <grpc/support/json.h>
20 #include <grpc/support/port_platform.h>
21 #include <stddef.h>
22 
23 #include <map>
24 #include <utility>
25 
26 #include "absl/log/check.h"
27 #include "absl/status/statusor.h"
28 #include "absl/strings/str_cat.h"
29 #include "absl/types/variant.h"
30 #include "src/core/util/json/json.h"
31 #include "src/core/util/json/json_reader.h"
32 #include "src/proto/grpc/lookup/v1/rls_config.upb.h"
33 #include "src/proto/grpc/lookup/v1/rls_config.upbdefs.h"
34 #include "upb/base/status.hpp"
35 #include "upb/json/encode.h"
36 #include "upb/mem/arena.hpp"
37 
38 namespace grpc_core {
39 
40 //
41 // XdsRouteLookupClusterSpecifierPlugin
42 //
43 
ConfigProtoName() const44 absl::string_view XdsRouteLookupClusterSpecifierPlugin::ConfigProtoName()
45     const {
46   return "grpc.lookup.v1.RouteLookupClusterSpecifier";
47 }
48 
PopulateSymtab(upb_DefPool * symtab) const49 void XdsRouteLookupClusterSpecifierPlugin::PopulateSymtab(
50     upb_DefPool* symtab) const {
51   grpc_lookup_v1_RouteLookupConfig_getmsgdef(symtab);
52 }
53 
GenerateLoadBalancingPolicyConfig(XdsExtension extension,upb_Arena * arena,upb_DefPool * symtab,ValidationErrors * errors) const54 Json XdsRouteLookupClusterSpecifierPlugin::GenerateLoadBalancingPolicyConfig(
55     XdsExtension extension, upb_Arena* arena, upb_DefPool* symtab,
56     ValidationErrors* errors) const {
57   absl::string_view* serialized_plugin_config =
58       absl::get_if<absl::string_view>(&extension.value);
59   if (serialized_plugin_config == nullptr) {
60     errors->AddError("could not parse plugin config");
61     return {};
62   }
63   const auto* specifier = grpc_lookup_v1_RouteLookupClusterSpecifier_parse(
64       serialized_plugin_config->data(), serialized_plugin_config->size(),
65       arena);
66   if (specifier == nullptr) {
67     errors->AddError("could not parse plugin config");
68     return {};
69   }
70   const auto* plugin_config = reinterpret_cast<const upb_Message*>(
71       grpc_lookup_v1_RouteLookupClusterSpecifier_route_lookup_config(
72           specifier));
73   if (plugin_config == nullptr) {
74     ValidationErrors::ScopedField field(errors, ".route_lookup_config");
75     errors->AddError("field not present");
76     return {};
77   }
78   upb::Status status;
79   const upb_MessageDef* msg_type =
80       grpc_lookup_v1_RouteLookupConfig_getmsgdef(symtab);
81   size_t json_size = upb_JsonEncode(plugin_config, msg_type, symtab, 0, nullptr,
82                                     0, status.ptr());
83   if (json_size == static_cast<size_t>(-1)) {
84     errors->AddError(absl::StrCat("failed to dump proto to JSON: ",
85                                   upb_Status_ErrorMessage(status.ptr())));
86     return {};
87   }
88   void* buf = upb_Arena_Malloc(arena, json_size + 1);
89   upb_JsonEncode(plugin_config, msg_type, symtab, 0,
90                  reinterpret_cast<char*>(buf), json_size + 1, status.ptr());
91   auto json = JsonParse(reinterpret_cast<char*>(buf));
92   CHECK(json.ok());
93   return Json::FromArray({Json::FromObject(
94       {{"rls_experimental",
95         Json::FromObject({
96             {"routeLookupConfig", std::move(*json)},
97             {"childPolicy",
98              Json::FromArray({
99                  Json::FromObject({{"cds_experimental",
100                                     Json::FromObject({
101                                         {"isDynamic", Json::FromBool(true)},
102                                     })}}),
103              })},
104             {"childPolicyConfigTargetFieldName", Json::FromString("cluster")},
105         })}})});
106 }
107 
108 //
109 // XdsClusterSpecifierPluginRegistry
110 //
111 
XdsClusterSpecifierPluginRegistry()112 XdsClusterSpecifierPluginRegistry::XdsClusterSpecifierPluginRegistry() {
113   RegisterPlugin(std::make_unique<XdsRouteLookupClusterSpecifierPlugin>());
114 }
115 
RegisterPlugin(std::unique_ptr<XdsClusterSpecifierPluginImpl> plugin)116 void XdsClusterSpecifierPluginRegistry::RegisterPlugin(
117     std::unique_ptr<XdsClusterSpecifierPluginImpl> plugin) {
118   absl::string_view name = plugin->ConfigProtoName();
119   registry_[name] = std::move(plugin);
120 }
121 
122 const XdsClusterSpecifierPluginImpl*
GetPluginForType(absl::string_view config_proto_type_name) const123 XdsClusterSpecifierPluginRegistry::GetPluginForType(
124     absl::string_view config_proto_type_name) const {
125   auto it = registry_.find(config_proto_type_name);
126   if (it == registry_.end()) return nullptr;
127   return it->second.get();
128 }
129 
PopulateSymtab(upb_DefPool * symtab) const130 void XdsClusterSpecifierPluginRegistry::PopulateSymtab(
131     upb_DefPool* symtab) const {
132   for (const auto& p : registry_) {
133     p.second->PopulateSymtab(symtab);
134   }
135 }
136 
137 }  // namespace grpc_core
138