1 //
2 // Copyright 2018 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 #ifndef GRPC_SRC_CORE_EXT_XDS_XDS_API_H
18 #define GRPC_SRC_CORE_EXT_XDS_XDS_API_H
19 
20 #include <grpc/support/port_platform.h>
21 
22 #include <stddef.h>
23 
24 #include <map>
25 #include <set>
26 #include <string>
27 #include <utility>
28 #include <vector>
29 
30 #include "absl/status/status.h"
31 #include "absl/strings/string_view.h"
32 #include "envoy/admin/v3/config_dump_shared.upb.h"
33 #include "upb/mem/arena.h"
34 #include "upb/reflection/def.hpp"
35 
36 #include "src/core/ext/xds/xds_bootstrap.h"
37 #include "src/core/ext/xds/xds_client_stats.h"
38 #include "src/core/lib/debug/trace.h"
39 #include "src/core/lib/gprpp/ref_counted_ptr.h"
40 #include "src/core/lib/gprpp/time.h"
41 
42 namespace grpc_core {
43 
44 class XdsClient;
45 
46 // TODO(roth): When we have time, split this into multiple pieces:
47 // - ADS request/response handling
48 // - LRS request/response handling
49 // - CSDS response generation
50 class XdsApi {
51  public:
52   // Interface defined by caller and passed to ParseAdsResponse().
53   class AdsResponseParserInterface {
54    public:
55     struct AdsResponseFields {
56       std::string type_url;
57       std::string version;
58       std::string nonce;
59       size_t num_resources;
60     };
61 
62     virtual ~AdsResponseParserInterface() = default;
63 
64     // Called when the top-level ADS fields are parsed.
65     // If this returns non-OK, parsing will stop, and the individual
66     // resources will not be processed.
67     virtual absl::Status ProcessAdsResponseFields(AdsResponseFields fields) = 0;
68 
69     // Called to parse each individual resource in the ADS response.
70     // Note that resource_name is non-empty only when the resource was
71     // wrapped in a Resource wrapper proto.
72     virtual void ParseResource(upb_Arena* arena, size_t idx,
73                                absl::string_view type_url,
74                                absl::string_view resource_name,
75                                absl::string_view serialized_resource) = 0;
76 
77     // Called when a resource is wrapped in a Resource wrapper proto but
78     // we fail to parse the Resource wrapper.
79     virtual void ResourceWrapperParsingFailed(size_t idx,
80                                               absl::string_view message) = 0;
81   };
82 
83   struct ClusterLoadReport {
84     XdsClusterDropStats::Snapshot dropped_requests;
85     std::map<RefCountedPtr<XdsLocalityName>, XdsClusterLocalityStats::Snapshot,
86              XdsLocalityName::Less>
87         locality_stats;
88     Duration load_report_interval;
89   };
90   using ClusterLoadReportMap = std::map<
91       std::pair<std::string /*cluster_name*/, std::string /*eds_service_name*/>,
92       ClusterLoadReport>;
93 
94   // The metadata of the xDS resource; used by the xDS config dump.
95   struct ResourceMetadata {
96     // Resource status from the view of a xDS client, which tells the
97     // synchronization status between the xDS client and the xDS server.
98     enum ClientResourceStatus {
99       // Client requested this resource but hasn't received any update from
100       // management server. The client will not fail requests, but will queue
101       // them
102       // until update arrives or the client times out waiting for the resource.
103       REQUESTED = 1,
104       // This resource has been requested by the client but has either not been
105       // delivered by the server or was previously delivered by the server and
106       // then subsequently removed from resources provided by the server.
107       DOES_NOT_EXIST,
108       // Client received this resource and replied with ACK.
109       ACKED,
110       // Client received this resource and replied with NACK.
111       NACKED
112     };
113 
114     // The client status of this resource.
115     ClientResourceStatus client_status = REQUESTED;
116     // The serialized bytes of the last successfully updated raw xDS resource.
117     std::string serialized_proto;
118     // The timestamp when the resource was last successfully updated.
119     Timestamp update_time;
120     // The last successfully updated version of the resource.
121     std::string version;
122     // The rejected version string of the last failed update attempt.
123     std::string failed_version;
124     // Details about the last failed update attempt.
125     std::string failed_details;
126     // Timestamp of the last failed update attempt.
127     Timestamp failed_update_time;
128   };
129   using ResourceMetadataMap =
130       std::map<std::string /*resource_name*/, const ResourceMetadata*>;
131   using ResourceTypeMetadataMap =
132       std::map<absl::string_view /*type_url*/, ResourceMetadataMap>;
133   static_assert(static_cast<ResourceMetadata::ClientResourceStatus>(
134                     envoy_admin_v3_REQUESTED) ==
135                     ResourceMetadata::ClientResourceStatus::REQUESTED,
136                 "");
137   static_assert(static_cast<ResourceMetadata::ClientResourceStatus>(
138                     envoy_admin_v3_DOES_NOT_EXIST) ==
139                     ResourceMetadata::ClientResourceStatus::DOES_NOT_EXIST,
140                 "");
141   static_assert(static_cast<ResourceMetadata::ClientResourceStatus>(
142                     envoy_admin_v3_ACKED) ==
143                     ResourceMetadata::ClientResourceStatus::ACKED,
144                 "");
145   static_assert(static_cast<ResourceMetadata::ClientResourceStatus>(
146                     envoy_admin_v3_NACKED) ==
147                     ResourceMetadata::ClientResourceStatus::NACKED,
148                 "");
149 
150   XdsApi(XdsClient* client, TraceFlag* tracer, const XdsBootstrap::Node* node,
151          upb::SymbolTable* symtab, std::string user_agent_name,
152          std::string user_agent_version);
153 
154   // Creates an ADS request.
155   std::string CreateAdsRequest(absl::string_view type_url,
156                                absl::string_view version,
157                                absl::string_view nonce,
158                                const std::vector<std::string>& resource_names,
159                                absl::Status status, bool populate_node);
160 
161   // Returns non-OK when failing to deserialize response message.
162   // Otherwise, all events are reported to the parser.
163   absl::Status ParseAdsResponse(absl::string_view encoded_response,
164                                 AdsResponseParserInterface* parser);
165 
166   // Creates an initial LRS request.
167   std::string CreateLrsInitialRequest();
168 
169   // Creates an LRS request sending a client-side load report.
170   std::string CreateLrsRequest(ClusterLoadReportMap cluster_load_report_map);
171 
172   // Parses the LRS response and populates send_all_clusters,
173   // cluster_names, and load_reporting_interval.
174   absl::Status ParseLrsResponse(absl::string_view encoded_response,
175                                 bool* send_all_clusters,
176                                 std::set<std::string>* cluster_names,
177                                 Duration* load_reporting_interval);
178 
179   // Assemble the client config proto message and return the serialized result.
180   std::string AssembleClientConfig(
181       const ResourceTypeMetadataMap& resource_type_metadata_map);
182 
183  private:
184   XdsClient* client_;
185   TraceFlag* tracer_;
186   const XdsBootstrap::Node* node_;  // Do not own.
187   upb::SymbolTable* symtab_;        // Do not own.
188   const std::string user_agent_name_;
189   const std::string user_agent_version_;
190 };
191 
192 }  // namespace grpc_core
193 
194 #endif  // GRPC_SRC_CORE_EXT_XDS_XDS_API_H
195