1 // Copyright 2023 The gRPC Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "src/core/resolver/dns/event_engine/service_config_helper.h"
15
16 #include <grpc/support/port_platform.h>
17 #include <stdlib.h>
18
19 #include <algorithm>
20 #include <vector>
21
22 #include "absl/status/statusor.h"
23 #include "absl/strings/string_view.h"
24 #include "src/core/util/gethostname.h"
25 #include "src/core/util/json/json.h"
26 #include "src/core/util/json/json_args.h"
27 #include "src/core/util/json/json_object_loader.h"
28 #include "src/core/util/json/json_reader.h"
29 #include "src/core/util/json/json_writer.h"
30 #include "src/core/util/status_helper.h"
31
32 namespace grpc_core {
33
34 namespace {
35
36 struct ServiceConfigChoice {
37 std::vector<std::string> client_language;
38 int percentage = -1;
39 std::vector<std::string> client_hostname;
40 Json::Object service_config;
41
JsonLoadergrpc_core::__anon894ddc220111::ServiceConfigChoice42 static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
43 static const auto* loader =
44 JsonObjectLoader<ServiceConfigChoice>()
45 .OptionalField("clientLanguage",
46 &ServiceConfigChoice::client_language)
47 .OptionalField("percentage", &ServiceConfigChoice::percentage)
48 .OptionalField("clientHostname",
49 &ServiceConfigChoice::client_hostname)
50 .Field("serviceConfig", &ServiceConfigChoice::service_config)
51 .Finish();
52 return loader;
53 }
54 };
55
vector_contains(const std::vector<std::string> & v,const std::string & value)56 bool vector_contains(const std::vector<std::string>& v,
57 const std::string& value) {
58 return std::find(v.begin(), v.end(), value) != v.end();
59 }
60
61 } // namespace
62
ChooseServiceConfig(absl::string_view service_config_json)63 absl::StatusOr<std::string> ChooseServiceConfig(
64 absl::string_view service_config_json) {
65 auto json = JsonParse(service_config_json);
66 GRPC_RETURN_IF_ERROR(json.status());
67 auto choices = LoadFromJson<std::vector<ServiceConfigChoice>>(*json);
68 GRPC_RETURN_IF_ERROR(choices.status());
69 for (const ServiceConfigChoice& choice : *choices) {
70 // Check client language, if specified.
71 if (!choice.client_language.empty() &&
72 !vector_contains(choice.client_language, "c++")) {
73 continue;
74 }
75 // Check client hostname, if specified.
76 if (!choice.client_hostname.empty()) {
77 const char* hostname = grpc_gethostname();
78 if (!vector_contains(choice.client_hostname, hostname)) {
79 continue;
80 }
81 }
82 // Check percentage, if specified.
83 if (choice.percentage != -1) {
84 int random_pct = rand() % 100;
85 if (random_pct > choice.percentage || choice.percentage == 0) {
86 continue;
87 }
88 }
89 return JsonDump(Json::FromObject(choice.service_config));
90 }
91 // No matching service config was found
92 return "";
93 }
94
95 } // namespace grpc_core
96