Skip to content

JSON Schema: HTTP Filter schemas #405

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

Merged
merged 9 commits into from
Feb 1, 2017
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
96 changes: 59 additions & 37 deletions docs/configuration/http_filters/fault_filter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ providing the ability to stage different failure scenarios such as service
failures, service overloads, high network latency, network partitions,
etc. Faults injection can be limited to a specific set of requests based on
the (destination) upstream cluster of a request and/or a set of pre-defined
request headers.
request headers.

The scope of failures is restricted to those that are observable by an
application communicating over the network. CPU and disk failures on the
Expand All @@ -33,57 +33,80 @@ including the router filter.*

.. code-block:: json

{
"type" : "decoder",
"name" : "fault",
"config" : {
"abort" : {
"abort_percent" : "...",
"http_status" : "..."
},
"delay" : {
"type" : "...",
"fixed_delay_percent" : "...",
"fixed_duration_ms" : "..."
},
"upstream_cluster" : "...",
"headers" : []
}
{
"type" : "decoder",
"name" : "fault",
"config" : {
"abort" : "{...}",
"delay" : "{...}",
"upstream_cluster" : "...",
"headers" : []
}
}

abort.abort_percent
:ref:`abort <config_http_filters_fault_injection_abort>`
*(sometimes required, object)* If specified, the filter will abort requests based on
the values in the object. At least *abort* or *delay* must be specified.

:ref:`delay <config_http_filters_fault_injection_delay>`
*(sometimes required, object)* If specified, the filter will inject delays based on the values
in the object. At least *abort* or *delay* must be specified.

upstream_cluster:
*(optional, string)* Specifies the name of the (destination) upstream
cluster that the filter should match on. Fault injection will be
restricted to requests bound to the specific upstream cluster.

:ref:`headers <config_http_filters_fault_injection_headers>`
*(optional, array)* Specifies a set of headers that the filter should match on.

The abort and delay blocks can be omitted. If they are not specified in the
configuration file, their respective values will be obtained from the
runtime.

.. _config_http_filters_fault_injection_abort:

Abort
-----
.. code-block:: json

{
"abort_percent" : "...",
"http_status" : "..."
}

abort_percent
*(required, integer)* The percentage of requests that
should be aborted with the specified *http_status* code. Valid values
range from 0 to 100.

abort.http_status
http_status
*(required, integer)* The HTTP status code that will be used as the
response code for the request being aborted.

delay.type:
.. _config_http_filters_fault_injection_delay:

Delay
-----
.. code-block:: json

{
"type" : "...",
"fixed_delay_percent" : "...",
"fixed_duration_ms" : "..."
}

type:
*(required, string)* Specifies the type of delay being
injected. Currently only *fixed* delay type (step function) is supported.

delay.fixed_delay_percent:
fixed_delay_percent:
*(required, integer)* The percentage of requests that will
be delayed for the duration specified by *fixed_duration_ms*. Valid
values range from 0 to 100.

delay.fixed_duration_ms:
*(required, integer)* The delay duration in
milliseconds. Must be greater than 0.

upstream_cluster:
*(optional, string)* Specifies the name of the (destination) upstream
cluster that the filter should match on. Fault injection will be
restricted to requests bound to the specific upstream cluster.

:ref:`headers <config_http_filters_fault_injection_headers>`
*(optional, array)* Specifies a set of headers that the filter should match on.

The abort and delay blocks can be omitted. If they are not specified in the
configuration file, their respective values will be obtained from the
runtime.
fixed_duration_ms:
*(required, integer)* The delay duration in milliseconds. Must be greater than 0.

Runtime
-------
Expand Down Expand Up @@ -158,4 +181,3 @@ prefix <config_http_conn_man_stat_prefix>` comes from the owning HTTP connection

delays_injected, Counter, Total requests that were delayed
aborts_injected, Counter, Total requests that were aborted

5 changes: 5 additions & 0 deletions include/envoy/json/json_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ class Object {
* valid.
*/
virtual void validateSchema(const std::string& schema) const PURE;

/**
* @return true if the JSON object is empty;
*/
virtual bool empty() const PURE;
};

} // Json
16 changes: 12 additions & 4 deletions source/common/http/filter/fault_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "common/http/codes.h"
#include "common/http/header_map_impl.h"
#include "common/http/headers.h"
#include "common/json/config_schemas.h"
#include "common/router/config_impl.h"

namespace Http {
Expand All @@ -18,8 +19,16 @@ FaultFilterConfig::FaultFilterConfig(const Json::Object& json_config, Runtime::L
const std::string& stat_prefix, Stats::Store& stats)
: runtime_(runtime), stats_(generateStats(stat_prefix, stats)) {

if (json_config.hasObject("abort")) {
const Json::ObjectPtr& abort = json_config.getObject("abort");
json_config.validateSchema(Json::Schema::FAULT_HTTP_FILTER_SCHEMA);

const Json::ObjectPtr abort = json_config.getObject("abort", true);
const Json::ObjectPtr delay = json_config.getObject("delay", true);

if (abort->empty() && delay->empty()) {
throw EnvoyException("fault filter must have at least abort or delay specified in the config.");
}

if (!abort->empty()) {
abort_percent_ = static_cast<uint64_t>(abort->getInteger("abort_percent", 0));

if (abort_percent_ > 0) {
Expand All @@ -36,8 +45,7 @@ FaultFilterConfig::FaultFilterConfig(const Json::Object& json_config, Runtime::L
}
}

if (json_config.hasObject("delay")) {
const Json::ObjectPtr& delay = json_config.getObject("delay");
if (!delay->empty()) {
const std::string type = delay->getString("type", "empty");
if (type == "fixed") {
fixed_delay_percent_ = static_cast<uint64_t>(delay->getInteger("fixed_delay_percent", 0));
Expand Down
9 changes: 9 additions & 0 deletions source/common/http/filter/ratelimit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,20 @@
#include "common/common/empty_string.h"
#include "common/common/enum_to_int.h"
#include "common/http/codes.h"
#include "common/json/config_schemas.h"
#include "common/router/config_impl.h"

namespace Http {
namespace RateLimit {

FilterConfig::FilterConfig(const Json::Object& config, const LocalInfo::LocalInfo& local_info,
Stats::Store& global_store, Runtime::Loader& runtime,
Upstream::ClusterManager& cm)
: domain_(config.getString("domain")), stage_(config.getInteger("stage", 0)),
local_info_(local_info), global_store_(global_store), runtime_(runtime), cm_(cm) {
config.validateSchema(Json::Schema::RATE_LIMIT_HTTP_FILTER_SCHEMA);
}

const Http::HeaderMapPtr Filter::TOO_MANY_REQUESTS_HEADER{new Http::HeaderMapImpl{
{Http::Headers::get().Status, std::to_string(enumToInt(Code::TooManyRequests))}}};

Expand Down
4 changes: 1 addition & 3 deletions source/common/http/filter/ratelimit.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ namespace RateLimit {
class FilterConfig {
public:
FilterConfig(const Json::Object& config, const LocalInfo::LocalInfo& local_info,
Stats::Store& global_store, Runtime::Loader& runtime, Upstream::ClusterManager& cm)
: domain_(config.getString("domain")), stage_(config.getInteger("stage", 0)),
local_info_(local_info), global_store_(global_store), runtime_(runtime), cm_(cm) {}
Stats::Store& global_store, Runtime::Loader& runtime, Upstream::ClusterManager& cm);

const std::string& domain() const { return domain_; }
const LocalInfo::LocalInfo& localInfo() const { return local_info_; }
Expand Down
117 changes: 111 additions & 6 deletions source/common/json/config_schemas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -187,12 +187,12 @@ const std::string Json::Schema::RATELIMIT_NETWORK_FILTER_SCHEMA(R"EOF(

const std::string Json::Schema::REDIS_PROXY_NETWORK_FILTER_SCHEMA(R"EOF(
{
"$schema": "http://json-schema.org/schema#",
"properties":{
"cluster_name" : {"type" : "string"}
},
"required": ["cluster_name"],
"additionalProperties": false
"$schema": "http://json-schema.org/schema#",
"properties":{
"cluster_name" : {"type" : "string"}
},
"required": ["cluster_name"],
"additionalProperties": false
}
)EOF");

Expand Down Expand Up @@ -425,3 +425,108 @@ const std::string Json::Schema::HTTP_RATE_LIMITS_CONFIGURATION_SCHEMA(R"EOF(
"additionalProperties" : false
}
)EOF");

const std::string Json::Schema::BUFFER_HTTP_FILTER_SCHEMA(R"EOF(
{
"$schema": "http://json-schema.org/schema#",
"properties" : {
"max_request_bytes" : {"type" : "integer"},
"max_request_time_s" : {"type" : "integer"}
},
"required" : ["max_request_bytes", "max_request_time_s"],
"additionalProperties" : false
}
)EOF");

const std::string Json::Schema::FAULT_HTTP_FILTER_SCHEMA(R"EOF(
{
"$schema": "http://json-schema.org/schema#",
"properties" : {
"abort": {
"type" : "object",
"properties" : {
"abort_percent" : {
"type" : "integer",
"minimum" : 0,
"maximum" : 100
},
"http_status" : {"type" : "integer"}
},
"required" : ["abort_percent", "http_status"],
"additionalProperties" : false
},
"delay" : {
"type" : "object",
"properties" : {
"type" : {
"type" : "string",
"enum" : ["fixed"]
},
"fixed_delay_percent" : {
"type" : "integer",
"minimum" : 0,
"maximum" : 100
},
"fixed_duration_ms" : {
"type" : "integer",
"minimum" : 0,
"exclusiveMinimum" : true
}
},
"required" : ["type", "fixed_delay_percent", "fixed_duration_ms"],
"additionalProperties" : false
},
"upstream_cluster" : {"type" : "string"},
"headers" : {
"type" : "array",
"minItems" : 1,
"items" : {
"type" : "object",
"properties" : {
"name" : {"type" : "string"},
"value" : {"type" : "string"},
"regex" : {"type" : "boolean"}
},
"required" : ["name"],
"additionalProperties" : false
}
}
},
"additionalProperties" : false
}
)EOF");

const std::string Json::Schema::HEALTH_CHECK_HTTP_FILTER_SCHEMA(R"EOF(
{
"$schema": "http://json-schema.org/schema#",
"properties" : {
"pass_through_mode" : {"type" : "boolean"},
"endpoint" : {"type" : "string"},
"cache_time_ms" : {"type" : "integer"}
},
"required" : ["pass_through_mode", "endpoint"],
"additionalProperties" : false
}
)EOF");

const std::string Json::Schema::RATE_LIMIT_HTTP_FILTER_SCHEMA(R"EOF(
{
"$schema": "http://json-schema.org/schema#",
"properties" : {
"domain" : {"type" : "string"},
"stage" : {"type" : "integer"}
},
"required" : ["domain"],
"additionalProperties" : false
}
)EOF");

const std::string Json::Schema::ROUTER_HTTP_FILTER_SCHEMA(R"EOF(
{
"$schema": "http://json-schema.org/schema#",
"properties" : {
"dynamic_stats" : {"type" : "boolean"}
},
"additionalProperties" : false
}
)EOF");
7 changes: 7 additions & 0 deletions source/common/json/config_schemas.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ class Schema {
static const std::string VIRTUAL_HOST_CONFIGURATION_SCHEMA;
static const std::string ROUTE_ENTRY_CONFIGURATION_SCHEMA;
static const std::string HTTP_RATE_LIMITS_CONFIGURATION_SCHEMA;

// HTTP Filter Schemas
static const std::string BUFFER_HTTP_FILTER_SCHEMA;
static const std::string FAULT_HTTP_FILTER_SCHEMA;
static const std::string HEALTH_CHECK_HTTP_FILTER_SCHEMA;
static const std::string RATE_LIMIT_HTTP_FILTER_SCHEMA;
static const std::string ROUTER_HTTP_FILTER_SCHEMA;
};

} // Json
2 changes: 2 additions & 0 deletions source/common/json/json_loader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ class ObjectImplBase : public Object {
}
}

bool empty() const override { return value_.IsObject() && value_.ObjectEmpty(); }

private:
const std::string name_;
const rapidjson::Value& value_;
Expand Down
Loading