Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding streaming response to AdminClusters endpoint #33879

Open
wants to merge 77 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
22a6e7d
Add support for boolean type to Envoy::Json::Streamer
miroswan Apr 23, 2024
797c8ca
Harden variant selection with static_assert
miroswan Apr 24, 2024
b2dc336
Remove unused variable
miroswan Apr 24, 2024
85275f8
Setup new request route for /clusters
miroswan Apr 2, 2024
0a0245e
Updating documentation comments.
miroswan Apr 2, 2024
2ed400a
Adding boilerplate for clusters_request.cc
miroswan Apr 2, 2024
ecec95d
Small update set
miroswan Apr 2, 2024
6f36f5c
Adding preliminary unit testing for clusters_request.cc
miroswan Apr 3, 2024
eeb5fbc
Adding ClustersParams struct
miroswan Apr 3, 2024
0060cce
Add dependency on ClustersParams to ClustersRequest
miroswan Apr 3, 2024
c104f43
Adding the interface for ClustersRenderer.
miroswan Apr 3, 2024
233def0
Adding ClustersRenderer implementation boilerplate
miroswan Apr 3, 2024
71c3b3e
Implemented ClustersRequest
miroswan Apr 3, 2024
a6658f6
Updating unit tests to accommodate new dependencies
miroswan Apr 3, 2024
c9c7d3a
Implement ClustersTextRenderer
miroswan Apr 4, 2024
1638f2e
Modify iteration strategy for the text renderer
miroswan Apr 4, 2024
253b0d2
Implement render to simplify nextChunk
miroswan Apr 19, 2024
d19238a
Add clusters_params_test.cc
miroswan Apr 20, 2024
f4600ba
Refactor of rendering.
miroswan Apr 20, 2024
6b5cc1d
refactor and start Json implementation
miroswan Apr 22, 2024
1d9ba05
Json processing working
miroswan Apr 22, 2024
3aadf0d
Adding addCircuitBreakerSettingsAsJson
miroswan Apr 23, 2024
8715ec0
Fixing test with addCircuitBreakerSettingsAsJson
miroswan Apr 23, 2024
423d769
Format update
miroswan Apr 23, 2024
f37ef5a
Small refactor for circuit breaker rendering
miroswan Apr 23, 2024
7bf62d4
Fixed mocking for Upstream::Cluster
miroswan Apr 23, 2024
d2e6ddb
Fix formatting
miroswan Apr 23, 2024
4c1ce2f
Add added_via_api
miroswan Apr 24, 2024
9f9152f
Save progress on host config
miroswan Apr 24, 2024
d25966f
Fix formatting
miroswan Apr 24, 2024
0dd628f
Fix formatting
miroswan Apr 24, 2024
a82222c
Host config code building
miroswan Apr 24, 2024
4b0daf6
Saving progress on testing host config
miroswan Apr 24, 2024
84e92bd
Saving progress on testing host config
miroswan Apr 24, 2024
ed7e066
Saving progress on testing host config
miroswan Apr 25, 2024
161adcd
Saving progress on testing host config
miroswan Apr 25, 2024
fa698e4
Save point
miroswan Apr 25, 2024
ce42c2a
Test passing for json streaming
miroswan Apr 30, 2024
1db72b4
Using absl::btree_map instead of absl::flat_hash_map for deterministi…
miroswan Apr 30, 2024
a171714
Some minor fixes and formating changes
miroswan Apr 30, 2024
485dd01
VerifyTextOutput done
miroswan Apr 30, 2024
15c1dd3
Format fix
miroswan Apr 30, 2024
75a8590
Remove temp files
miroswan Apr 30, 2024
a23e9ec
Handle omission of empty object
miroswan Apr 30, 2024
fe47bf2
Set content type header for JSON output to satisfy integration tests
miroswan May 2, 2024
e2eec3a
Fix spelling issue and update comments
miroswan May 2, 2024
fdf459a
Fix formatting
miroswan May 2, 2024
ccc5f45
Fix odd bug in gcc 11.4.0 build
miroswan May 4, 2024
97690ed
Fix some formatting issues
miroswan May 4, 2024
bbba348
Remove unused import
miroswan May 4, 2024
c0dc33f
Set text content type and prevent unnecessary fallthrough in switch s…
miroswan May 4, 2024
6a93146
Allow default content type for text processing
miroswan May 6, 2024
65574bd
Remove build target that is not yet used
miroswan May 6, 2024
c1a9934
Remove unused import
miroswan May 6, 2024
a7e4a78
Remove declaration from when member functions where static functions
miroswan May 8, 2024
3175c39
Remove redundant ternary expression
miroswan May 8, 2024
bae0781
Removing designated initialization since C++20 is not yet supported
miroswan May 8, 2024
c7f4ece
Using a vector and sorting instead of std::map
miroswan May 8, 2024
12347d2
Formatting fix
miroswan May 8, 2024
d5bc39b
Use structured bindings in loop
miroswan May 8, 2024
3bcfdf7
Add TODO comment for adding designated initialization in handler conf…
miroswan May 8, 2024
9c95663
Fix spelling
miroswan May 8, 2024
c096e71
Wrapped reference to reference
miroswan May 10, 2024
188aa47
Adding anonymous namespace for the unit tests
miroswan May 11, 2024
63edb28
Return Http::Code::BadRequest if format query parameter is invalid
miroswan May 24, 2024
1aaabac
Update unit tests for ClustersParams
miroswan May 24, 2024
db88b19
Updating ClustersHandler::makeRequest to return text response when qu…
miroswan May 24, 2024
8c5790c
Implement nextChunk within sub classes of Request
miroswan May 25, 2024
594b51c
Remove cluster chunk processor since nextChunk is fully implemented i…
miroswan May 25, 2024
7379a1e
Resolve: control reaches end of non-void function
miroswan May 25, 2024
f910712
Remove unused code from the clusters_params_test
miroswan May 25, 2024
22c5961
Remove raw pointers from API surface in clusters_request.h and cluste…
miroswan Jun 5, 2024
c9b9131
Remove default case from switch statement in clusters_handler
miroswan Jun 5, 2024
7271018
Remove default constructor for ClustersParams and add necessary break…
miroswan Jun 5, 2024
c8d379b
Remove UNKNOWN format from ClustersParams
miroswan Jun 5, 2024
51ab1e1
Update documentation comment for ClustersRequest
miroswan Jun 5, 2024
6bb869e
Cleanup unit tests
miroswan Jun 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions envoy/http/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ envoy_cc_library(
name = "query_params_interface",
hdrs = ["query_params.h"],
external_deps = ["abseil_btree"],
deps = [":header_map_interface"],
)

envoy_cc_library(
Expand Down
10 changes: 10 additions & 0 deletions envoy/server/admin.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,16 @@ class AdminStream {
return X(response_headers, data, admin_stream); \
}

/**
* This macro is used to add streaming handlers to the Admin HTTP Endpoint. It builds
* a callback that executes X when the specified admin handler is hit. Member
* functions must be called when referenced, so this macro DRYs up the process of
* passing member functions to route-handling configuration within
* Envoy::Server::AdminImpl.
*/
#define MAKE_STREAMING_HANDLER(X) \
[this](AdminStream& admin_stream) -> Admin::RequestPtr { return X(admin_stream); }

/**
* Global admin HTTP endpoint for the server, holding a map from URL prefixes to
* handlers. When an HTTP request arrives at the admin port, the URL is linearly
Expand Down
38 changes: 38 additions & 0 deletions source/server/admin/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -336,13 +336,16 @@ envoy_cc_library(
deps = [
":handler_ctx_lib",
":utils_lib",
"//envoy/buffer:buffer_interface",
"//envoy/http:codes_interface",
"//envoy/server:admin_interface",
"//envoy/server:instance_interface",
"//source/common/buffer:buffer_lib",
"//source/common/http:codes_lib",
"//source/common/http:header_map_lib",
"//source/common/upstream:host_utility_lib",
"//source/server/admin:clusters_params_lib",
"//source/server/admin:clusters_request_lib",
"@envoy_api//envoy/admin/v3:pkg_cc_proto",
],
)
Expand Down Expand Up @@ -410,3 +413,38 @@ envoy_cc_library(
"//source/common/common:macros",
],
)

envoy_cc_library(
name = "clusters_request_lib",
srcs = ["clusters_request.cc"],
hdrs = ["clusters_request.h"],
deps = [
":clusters_params_lib",
"//envoy/buffer:buffer_interface",
"//envoy/http:codes_interface",
"//envoy/http:header_map_interface",
"//envoy/server:admin_interface",
"//envoy/server:instance_interface",
"//source/common/buffer:buffer_lib",
"//source/common/common:logger_lib",
"//source/common/http:headers_lib",
"//source/common/json:json_streamer_lib",
"//source/common/upstream:host_utility_lib",
"@envoy_api//envoy/admin/v3:pkg_cc_proto",
],
)

envoy_cc_library(
name = "clusters_params_lib",
srcs = ["clusters_params.cc"],
hdrs = ["clusters_params.h"],
external_deps = [
"abseil_optional",
"abseil_strings",
],
deps = [
"//envoy/buffer:buffer_interface",
"//envoy/http:codes_interface",
"//envoy/http:query_params_interface",
],
)
6 changes: 4 additions & 2 deletions source/server/admin/admin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "envoy/extensions/http/header_validators/envoy_default/v3/header_validator.pb.h"
#include "envoy/http/header_validator_factory.h"
#include "envoy/server/admin.h"
#include "envoy/server/hot_restart.h"
#include "envoy/server/instance.h"
#include "envoy/server/options.h"
Expand Down Expand Up @@ -123,12 +124,13 @@ AdminImpl::AdminImpl(const std::string& profile_path, Server::Instance& server,
runtime_handler_(server), listeners_handler_(server), server_cmd_handler_(server),
server_info_handler_(server),
// TODO(jsedgwick) add /runtime_reset endpoint that removes all admin-set values
// TODO(demitriswan) When C++20 is supported we might want to use designated initialization
// for readability.
handlers_{
makeHandler("/", "Admin home page", MAKE_ADMIN_HANDLER(handlerAdminHome), false, false),
makeHandler("/certs", "print certs on machine",
MAKE_ADMIN_HANDLER(server_info_handler_.handlerCerts), false, false),
makeHandler("/clusters", "upstream cluster status",
MAKE_ADMIN_HANDLER(clusters_handler_.handlerClusters), false, false),
clusters_handler_.urlHandler(),
makeHandler(
"/config_dump", "dump current Envoy configs (experimental)",
MAKE_ADMIN_HANDLER(config_dump_handler_.handlerConfigDump), false, false,
Expand Down
46 changes: 46 additions & 0 deletions source/server/admin/clusters_handler.cc
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
#include "source/server/admin/clusters_handler.h"

#include "envoy/admin/v3/clusters.pb.h"
#include "envoy/server/admin.h"

#include "source/common/buffer/buffer_impl.h"
#include "source/common/common/macros.h"
#include "source/common/http/headers.h"
#include "source/common/http/utility.h"
#include "source/common/network/utility.h"
#include "source/common/upstream/host_utility.h"
#include "source/server/admin/clusters_params.h"
#include "source/server/admin/clusters_request.h"
#include "source/server/admin/utils.h"

namespace Envoy {
Expand Down Expand Up @@ -40,6 +45,25 @@ void addCircuitBreakerSettingsAsJson(const envoy::config::core::v3::RoutingPrior

} // namespace

Admin::UrlHandler ClustersHandler::urlHandler() {
return {
/* prefix =*/"/clusters",
/* help_text =*/"upstream clusters status",
/* handler =*/MAKE_STREAMING_HANDLER(makeRequest),
/* removable =*/false,
/* mutates_server_state =*/false,
/* params =*/
{
{
/* type =*/Admin::ParamDescriptor::Type::Enum,
/* id =*/"format",
/* help =*/"The output format",
/* enum_choices =*/{"text", "json"},
},
},
};
}

ClustersHandler::ClustersHandler(Server::Instance& server) : HandlerContextBase(server) {}

Http::Code ClustersHandler::handlerClusters(Http::ResponseHeaderMap& response_headers,
Expand All @@ -56,6 +80,28 @@ Http::Code ClustersHandler::handlerClusters(Http::ResponseHeaderMap& response_he
return Http::Code::OK;
}

Admin::RequestPtr ClustersHandler::makeRequest(AdminStream& admin_stream) {
Buffer::OwnedImpl response;
ClustersParams params;
Http::Code code = params.parse(admin_stream.getRequestHeaders().getPathValue(), response);
if (code != Http::Code::OK) {
return Admin::makeStaticTextRequest(response, code);
}
Admin::RequestPtr request{nullptr};
switch (params.format_) {
case ClustersParams::Format::Text:
request =
std::make_unique<TextClustersRequest>(ClustersRequest::DefaultChunkLimit, server_, params);
break;
case ClustersParams::Format::Json:
request =
std::make_unique<JsonClustersRequest>(ClustersRequest::DefaultChunkLimit, server_, params);
break;
}
ASSERT(request != nullptr);
return request;
}

// Helper method that ensures that we've setting flags based on all the health flag values on the
// host.
void setHealthFlag(Upstream::Host::HealthFlag flag, const Upstream::Host& host,
Expand Down
4 changes: 4 additions & 0 deletions source/server/admin/clusters_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ class ClustersHandler : public HandlerContextBase {

Http::Code handlerClusters(Http::ResponseHeaderMap& response_headers, Buffer::Instance& response,
AdminStream&);
// Returns a RequestPtr implementation suitable for streaming its response.
Admin::RequestPtr makeRequest(AdminStream& admin_stream);
// Returns a UrlHandler suitable for AdminImpl.
Admin::UrlHandler urlHandler();

private:
void addOutlierInfo(const std::string& cluster_name,
Expand Down
30 changes: 30 additions & 0 deletions source/server/admin/clusters_params.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "source/server/admin/clusters_params.h"

#include "envoy/http/codes.h"
#include "envoy/http/query_params.h"

#include "absl/strings/string_view.h"
#include "absl/types/optional.h"

namespace Envoy {
namespace Server {

Http::Code ClustersParams::parse(absl::string_view url, Buffer::Instance& response) {
Http::Utility::QueryParamsMulti query =
Http::Utility::QueryParamsMulti::parseAndDecodeQueryString(url);
absl::optional<std::string> optional_format = query.getFirstValue("format");
if (optional_format.has_value()) {
if (*optional_format == "json") {
format_ = Format::Json;
} else if (*optional_format == "text") {
format_ = Format::Text;
miroswan marked this conversation as resolved.
Show resolved Hide resolved
} else {
response.addFragments({"invalid format ", *optional_format});
return Http::Code::BadRequest;
}
}
return Http::Code::OK;
}

} // namespace Server
} // namespace Envoy
23 changes: 23 additions & 0 deletions source/server/admin/clusters_params.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include "envoy/buffer/buffer.h"
#include "envoy/http/codes.h"

#include "absl/strings/string_view.h"

namespace Envoy {
namespace Server {

struct ClustersParams {
enum class Format {
Text,
Json,
};

Http::Code parse(absl::string_view url, Buffer::Instance& response);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doxygen here please, e.g. it might not be obvious that response is only written if there's an error.


Format format_{Format::Text};
};

} // namespace Server
} // namespace Envoy
Loading
Loading