Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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 api/docs/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ package_group(
proto_library(
name = "protos",
deps = [
"//envoy/admin/v2alpha:clusters",
"//envoy/admin/v2alpha:config_dump",
"//envoy/api/v2:cds",
"//envoy/api/v2:discovery",
Expand Down
9 changes: 9 additions & 0 deletions api/envoy/admin/v2alpha/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,12 @@ api_proto_library(
"//envoy/config/bootstrap/v2:bootstrap",
],
)

api_proto_library(
name = "clusters",
srcs = ["clusters.proto"],
visibility = ["//visibility:public"],
deps = [
"//envoy/api/v2/core:base",
],
)
77 changes: 77 additions & 0 deletions api/envoy/admin/v2alpha/clusters.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
syntax = "proto3";

package envoy.admin.v2alpha;

import "envoy/api/v2/core/base.proto";

// [#protodoc-title: Clusters]

// Admin endpoint uses this wrapper for `/clusters` to display cluster status information.
// See :ref:`/clusters <operations_admin_interface_clusters>` for more information.
message Clusters {
// Mapping from cluster name to each cluster's status.
map<string, ClusterStatus> cluster_statuses = 1;
}

// Details an individual cluster's current status.
message ClusterStatus {
// General outlier statistics if installed for this cluster.
OutlierInfo outlier_info = 1;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you reorder the protos so that they are in topological sort order? This make the documentation clearer and is a convention we have adopted.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Just to be clear, you're suggesting that if one message depends on another, the dependent message should go below the dependency? Is this a new convention? I was following the example of the bootstrap proto and others, which seem to do the opposite.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Actually, I think I'm wrong here, the other opposite convention seems to mostly hold.


// Mapping from priority to circuit breaker settings for that priority.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

style nit: I'd prefer a blank line between fields for readability.

map<string, CircuitSettings> circuit_settings = 2;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do you want

enum RoutingPriority {
?


// Denotes whether this cluster was added via API or configured statically.
bool added_via_api = 3;

// Mapping from host address to the host's current status.
map<string, HostStatus> host_statuses = 4;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we want to use https://github.com/envoyproxy/envoy/blob/master/api/envoy/api/v2/core/address.proto#L93 here? I.e. have some structure since this is proto, rather than encoding ports etc. in strings.

@mrice32 mrice32 May 25, 2018

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This brings up a broader question. I think I have made uncharacteristic (in the scope of Envoy) use of maps. Both messages and enums (as mentioned in your other comment below) cannot be used as key types. Should we try to avoid maps here, generally (even when the key types allow), or just remove them in these two incompatible places?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think it probably makes sense for the HostStatus.stats field, but I think the rest are debatable.

}

// Cluster outlier detection statistics. -1 for any of these statistics denotes that there was not
// enough data to compute it.
message OutlierInfo {
// The average success rate of the hosts in the Detector for the last aggregation interval.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

References back to docs on this?

double success_rate_average = 1;

// The success rate threshold used in the last interval. The threshold is used to eject hosts
// based on their success rate.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

double success_rate_ejection_threshold = 2;
}

// Circuit settings for a particular priority setting.
message CircuitSettings {
// Total TCP connection limit.
int64 max_connections = 1;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In Envoy, we prefer unsigned types for things that are actually unsigned.


// Pending request limit. A request is pending if it is waiting to be attached to a connection
// pool connection.
int64 max_pending_requests = 2;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Aren't these

? They are already available on /config_dump, so can we elide here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I was trying to be consistent with the info provided in the text printout, but I'll remove as long as there are no back-compat objections.


// Active request limit. A request is active if it is bound to a connection pool connection and
// awaiting a response.
int64 max_requests = 3;

// Per-request retry limit.
int64 max_retries = 4;
}

message HostStatus {
// Mapping from the name of the statistic to the current value.
map<string, int64> stats = 1;

// A string representation of the host's current health status.
string health_flags = 2;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Prefer proto structure rather than opaque strings here.


// Configured load balancing weight for this host.
int64 weight = 3;

// Configured locality for the host.
envoy.api.v2.core.Locality locality = 4;

// Denotes whether this is configured as a canary host or not.
bool canary = 5;

// Request success rate for this host over the last calculated interval.
double success_rate = 6;
}
1 change: 1 addition & 0 deletions docs/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ bazel --batch build ${BAZEL_BUILD_OPTIONS} @envoy_api//docs:protos --aspects \
# These are the protos we want to put in docs, this list will grow.
# TODO(htuch): Factor this out of this script.
PROTO_RST="
/envoy/admin/v2alpha/clusters/envoy/admin/v2alpha/clusters.proto.rst
/envoy/admin/v2alpha/config_dump/envoy/admin/v2alpha/config_dump.proto.rst
/envoy/api/v2/core/address/envoy/api/v2/core/address.proto.rst
/envoy/api/v2/core/base/envoy/api/v2/core/base.proto.rst
Expand Down
1 change: 1 addition & 0 deletions docs/root/api-v2/admin/admin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ Admin
:maxdepth: 2

../admin/v2alpha/config_dump.proto
../admin/v2alpha/clusters.proto
2 changes: 2 additions & 0 deletions docs/root/intro/version_history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Version history
to filter logs based on request headers
* admin: added :http:get:`/config_dump` for dumping the current configuration and associated xDS
version information (if applicable).
* admin: added :http:get:`/clusters?format=json` for outputing a JSON-serialized proto detailing
the current status of all clusters.
* admin: added :http:get:`/stats/prometheus` as an alternative endpoint for getting stats in prometheus format.
* admin: added :ref:`/runtime_modify endpoint <operations_admin_interface_runtime_modify>` to add or change runtime values
* admin: mutations must be sent as POSTs, rather than GETs. Mutations include:
Expand Down
5 changes: 5 additions & 0 deletions docs/root/operations/admin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ modify different aspects of the server:

*/failed_outlier_check*: The host has failed an outlier detection check.

.. http:get:: /clusters?format=json

Dump the */clusters* output in a JSON-serialized proto. See the
:ref:`definition <envoy_api_msg_admin.v2alpha.Clusters>` for more information.

.. _operations_admin_interface_config_dump:

.. http:get:: /config_dump
Expand Down
1 change: 1 addition & 0 deletions source/server/http/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ envoy_cc_library(
"//source/common/stats:stats_lib",
"//source/common/upstream:host_utility_lib",
"//source/extensions/access_loggers/file:file_access_log_lib",
"@envoy_api//envoy/admin/v2alpha:clusters_cc",
"@envoy_api//envoy/admin/v2alpha:config_dump_cc",
],
)
Expand Down
74 changes: 72 additions & 2 deletions source/server/http/admin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <utility>
#include <vector>

#include "envoy/admin/v2alpha/clusters.pb.h"
#include "envoy/admin/v2alpha/config_dump.pb.h"
#include "envoy/filesystem/filesystem.h"
#include "envoy/runtime/runtime.h"
Expand Down Expand Up @@ -242,8 +243,63 @@ void AdminImpl::addCircuitSettings(const std::string& cluster_name, const std::s
resource_manager.retries().max()));
}

Http::Code AdminImpl::handlerClusters(absl::string_view, Http::HeaderMap&,
Buffer::Instance& response, AdminStream&) {
void AdminImpl::addCircuitSettings(envoy::admin::v2alpha::CircuitSettings& circuit_settings,
Upstream::ResourceManager& resource_manager) {
circuit_settings.set_max_connections(resource_manager.connections().max());
circuit_settings.set_max_pending_requests(resource_manager.pendingRequests().max());
circuit_settings.set_max_requests(resource_manager.requests().max());
circuit_settings.set_max_retries(resource_manager.retries().max());
}

void AdminImpl::writeClustersAsJson(Buffer::Instance& response) {
envoy::admin::v2alpha::Clusters clusters;
for (auto& cluster_pair : server_.clusterManager().clusters()) {
const Upstream::Cluster& cluster = cluster_pair.second.get();
Upstream::ClusterInfoConstSharedPtr cluster_info = cluster.info();

envoy::admin::v2alpha::ClusterStatus& cluster_status =
(*clusters.mutable_cluster_statuses())[cluster_info->name()];

const Upstream::Outlier::Detector* outlier_detector = cluster.outlierDetector();
if (outlier_detector != nullptr) {
cluster_status.mutable_outlier_info()->set_success_rate_average(
outlier_detector->successRateAverage());
cluster_status.mutable_outlier_info()->set_success_rate_ejection_threshold(
outlier_detector->successRateEjectionThreshold());
}

addCircuitSettings((*cluster_status.mutable_circuit_settings())["default"],
cluster_info->resourceManager(Upstream::ResourcePriority::Default));
addCircuitSettings((*cluster_status.mutable_circuit_settings())["high"],
cluster_info->resourceManager(Upstream::ResourcePriority::High));

cluster_status.set_added_via_api(cluster_info->addedViaApi());

for (auto& host_set : cluster.prioritySet().hostSetsPerPriority()) {
for (auto& host : host_set->hosts()) {
envoy::admin::v2alpha::HostStatus& host_status =
(*cluster_status.mutable_host_statuses())[host->address()->asString()];

for (const Stats::CounterSharedPtr& counter : host->counters()) {
(*host_status.mutable_stats())[counter->name()] = counter->value();
}

for (const Stats::GaugeSharedPtr& gauge : host->gauges()) {
(*host_status.mutable_stats())[gauge->name()] = gauge->value();
}

host_status.set_health_flags(Upstream::HostUtility::healthFlagsToString(*host));
host_status.set_weight(host->weight());
*host_status.mutable_locality() = host->locality();
host_status.set_canary(host->canary());
host_status.set_success_rate(host->outlierDetector().successRate());
}
}
}
response.add(MessageUtil::getJsonStringFromMessage(clusters, true)); // pretty-print
}

void AdminImpl::writeClustersAsText(Buffer::Instance& response) {
for (auto& cluster : server_.clusterManager().clusters()) {
addOutlierInfo(cluster.second.get().info()->name(), cluster.second.get().outlierDetector(),
response);
Expand Down Expand Up @@ -293,6 +349,20 @@ Http::Code AdminImpl::handlerClusters(absl::string_view, Http::HeaderMap&,
}
}
}
}

Http::Code AdminImpl::handlerClusters(absl::string_view url, Http::HeaderMap& response_headers,
Buffer::Instance& response, AdminStream&) {
Http::Utility::QueryParams query_params = Http::Utility::parseQueryString(url);
auto it = query_params.find("format");

if (it != query_params.end() && it->second == "json") {
writeClustersAsJson(response);
response_headers.insertContentType().value().setReference(
Http::Headers::get().ContentTypeValues.Json);
} else {
writeClustersAsText(response);
}

return Http::Code::OK;
}
Expand Down
10 changes: 10 additions & 0 deletions source/server/http/admin.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <utility>
#include <vector>

#include "envoy/admin/v2alpha/clusters.pb.h"
#include "envoy/http/filter.h"
#include "envoy/network/filter.h"
#include "envoy/network/listen_socket.h"
Expand Down Expand Up @@ -137,11 +138,20 @@ class AdminImpl : public Admin,
* @return TRUE if level change succeeded, FALSE otherwise.
*/
bool changeLogLevel(const Http::Utility::QueryParams& params);

/**
* Helper methods for the /clusters url handler.
*/
void addCircuitSettings(const std::string& cluster_name, const std::string& priority_str,
Upstream::ResourceManager& resource_manager, Buffer::Instance& response);
void addCircuitSettings(envoy::admin::v2alpha::CircuitSettings& circuit_settings,
Upstream::ResourceManager& resource_manager);
void addOutlierInfo(const std::string& cluster_name,
const Upstream::Outlier::Detector* outlier_detector,
Buffer::Instance& response);
void writeClustersAsJson(Buffer::Instance& response);
void writeClustersAsText(Buffer::Instance& response);

static std::string statsAsJson(const std::map<std::string, uint64_t>& all_stats,
const std::vector<Stats::ParentHistogramSharedPtr>& all_histograms,
bool show_all, bool pretty_print = false);
Expand Down
2 changes: 2 additions & 0 deletions test/server/http/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ envoy_cc_test(
"//source/common/http:message_lib",
"//source/common/json:json_loader_lib",
"//source/common/profiler:profiler_lib",
"//source/common/protobuf",
"//source/common/protobuf:utility_lib",
"//source/common/stats:thread_local_store_lib",
"//source/server/http:admin_lib",
"//test/mocks/runtime:runtime_mocks",
Expand Down
Loading