Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
18 changes: 18 additions & 0 deletions api/envoy/admin/v2alpha/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,21 @@ api_proto_library(
"//envoy/config/bootstrap/v2:bootstrap",
],
)

api_proto_library(
name = "clusters",
srcs = ["clusters.proto"],
visibility = ["//visibility:public"],
deps = [
":metrics",
"//envoy/api/v2/core:address",
"//envoy/api/v2/core:health_check",
"//envoy/type:percent",
],
)

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

package envoy.admin.v2alpha;

import "envoy/admin/v2alpha/metrics.proto";
import "envoy/api/v2/core/address.proto";
import "envoy/api/v2/core/health_check.proto";
import "envoy/type/percent.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.
repeated ClusterStatus cluster_statuses = 1;
}

// Details an individual cluster's current status.
message ClusterStatus {
// Name of the cluster.
string name = 1;

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

// The success rate threshold used in the last interval. The threshold is used to eject hosts
// based on their success rate. See
// :ref:`Cluster outlier detection <arch_overview_outlier_detection>` statistics
//
// Note: this field may be omitted in any of the three following cases:
// 1. There were not enough hosts with enough request volume to proceed with success rate based outlier ejection.
// 2. The threshold is computed to be < 0 because a negative value implies that there was no threshold for that
// interval.
// 3. Outlier detection is not enabled for this cluster.
envoy.type.Percent success_rate_ejection_threshold = 3;

// Mapping from host address to the host's current status.
repeated HostStatus host_statuses = 4;
}

// Current state of a particular host.
message HostStatus {
// Address of this host.
envoy.api.v2.core.Address address = 1;

// Mapping from the name of the statistic to the current value.
map<string, SimpleMetric> stats = 2;

// The host's current health status.
HostHealthStatus health_status = 3;

// Request success rate for this host over the last calculated interval.
//
// Note: the message will not be present if host did not have enough request volume to calculate
// success rate or the cluster did not have enough hosts to run through success rate outlier
// ejection.
envoy.type.Percent success_rate = 4;
}

// Health status for a host.
message HostHealthStatus {
// The host is currently failing active health checks.
bool failed_active_health_check = 1;

// The host is currently considered an outlier and has been ejected.
bool failed_outlier_check = 2;

// Health status as reported by EDS. Note: only HEALTHY and UNHEALTHY are currently supported here.
// TODO(mrice32): pipe through remaining EDS health status possibilities.
envoy.api.v2.core.HealthStatus eds_health_status = 3;
}
19 changes: 19 additions & 0 deletions api/envoy/admin/v2alpha/metrics.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
syntax = "proto3";

package envoy.admin.v2alpha;

// [#protodoc-title: Metrics]

// Proto representation of an Envoy Counter or Gauge value.
message SimpleMetric {
enum Type {
COUNTER = 0;
GAUGE = 1;
}

// Type of metric represented.
Type type = 1;

// Current metric value.
uint64 value = 2;
}
2 changes: 2 additions & 0 deletions docs/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ 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/admin/v2alpha/clusters/envoy/admin/v2alpha/metrics.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
/envoy/api/v2/core/http_uri/envoy/api/v2/core/http_uri.proto.rst
Expand Down
2 changes: 2 additions & 0 deletions docs/root/api-v2/admin/admin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ Admin
:maxdepth: 2

../admin/v2alpha/config_dump.proto
../admin/v2alpha/clusters.proto
../admin/v2alpha/metrics.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 @@ -26,6 +26,8 @@ Version history
* access log: improved WebSocket logging.
* 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
2 changes: 2 additions & 0 deletions source/server/http/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,13 @@ envoy_cc_library(
"//source/common/http/http1:codec_lib",
"//source/common/network:listen_socket_lib",
"//source/common/network:raw_buffer_socket_lib",
"//source/common/network:utility_lib",
"//source/common/profiler:profiler_lib",
"//source/common/router:config_lib",
"//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 All @@ -34,6 +35,7 @@
#include "common/http/http1/codec_impl.h"
#include "common/json/json_loader.h"
#include "common/network/listen_socket_impl.h"
#include "common/network/utility.h"
#include "common/profiler/profiler.h"
#include "common/router/config_impl.h"
#include "common/stats/stats_impl.h"
Expand Down Expand Up @@ -258,8 +260,62 @@ 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::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.add_cluster_statuses();
cluster_status.set_name(cluster_info->name());

const Upstream::Outlier::Detector* outlier_detector = cluster.outlierDetector();
if (outlier_detector != nullptr && outlier_detector->successRateEjectionThreshold() > 0.0) {
cluster_status.mutable_success_rate_ejection_threshold()->set_value(
outlier_detector->successRateEjectionThreshold());
}

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.add_host_statuses();
Network::Utility::addressToProtobufAddress(*host->address(),
*host_status.mutable_address());

for (const Stats::CounterSharedPtr& counter : host->counters()) {
auto& metric = (*host_status.mutable_stats())[counter->name()];
metric.set_type(envoy::admin::v2alpha::SimpleMetric::COUNTER);
metric.set_value(counter->value());
}

for (const Stats::GaugeSharedPtr& gauge : host->gauges()) {
auto& metric = (*host_status.mutable_stats())[gauge->name()];
metric.set_type(envoy::admin::v2alpha::SimpleMetric::GAUGE);
metric.set_value(gauge->value());
}

envoy::admin::v2alpha::HostHealthStatus& health_status =
*host_status.mutable_health_status();
health_status.set_failed_active_health_check(
host->healthFlagGet(Upstream::Host::HealthFlag::FAILED_ACTIVE_HC));
health_status.set_failed_outlier_check(
host->healthFlagGet(Upstream::Host::HealthFlag::FAILED_OUTLIER_CHECK));
health_status.set_eds_health_status(
host->healthFlagGet(Upstream::Host::HealthFlag::FAILED_EDS_HEALTH)
? envoy::api::v2::core::HealthStatus::UNHEALTHY
: envoy::api::v2::core::HealthStatus::HEALTHY);
double success_rate = host->outlierDetector().successRate();
if (success_rate >= 0.0) {
host_status.mutable_success_rate()->set_value(success_rate);
}
}
}
}
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 @@ -309,6 +365,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
8 changes: 8 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 @@ -146,11 +147,18 @@ 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 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