Skip to content

Commit

Permalink
Deprecate Envoy API v2 primitives in configuration for our Envoy filt…
Browse files Browse the repository at this point in the history
…ers. (#588)

Adds a new field `v3_response_headers` alongside the old v2 `response_headers` in `api/server/response_options.proto` and marks the old field as deprecated. The old field retains its functionality for backward compatibility.

Since these are repeated fields, we cannot use a oneof. Instead validation is added to ensure the filters report an error on configuration that has both the v2 and the v3 fields set. `Envoy::EnvoyException` is thrown on validation errors to comply with the `Envoy::Server::Configuration::NamedHttpFilterConfigFactory` interface.

Also:
- sorting imports in `response_options.proto ` alphabetically.
- adding missing anonymous namespace in `http_dynamic_delay_filter_integration_test.cc`.

Works on #580.

Signed-off-by: Jakub Sobon <mumak@google.com>
  • Loading branch information
mum4k authored Dec 8, 2020
1 parent 90af260 commit facd66b
Show file tree
Hide file tree
Showing 13 changed files with 427 additions and 16 deletions.
1 change: 1 addition & 0 deletions api/server/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ api_cc_py_proto_library(
srcs = ["response_options.proto"],
deps = [
"@envoy_api//envoy/api/v2/core:pkg",
"@envoy_api//envoy/config/core/v3:pkg",
],
)
15 changes: 12 additions & 3 deletions api/server/response_options.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ syntax = "proto3";

package nighthawk.server;

import "google/protobuf/wrappers.proto";
import "validate/validate.proto";
import "envoy/api/v2/core/base.proto";
import "envoy/config/core/v3/base.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/wrappers.proto";
import "validate/validate.proto";

message ConcurrencyBasedLinearDelay {
// Minimal delay to add to replies.
Expand All @@ -20,7 +21,15 @@ message ConcurrencyBasedLinearDelay {
// configuration will override.
message ResponseOptions {
// List of additional response headers.
repeated envoy.api.v2.core.HeaderValueOption response_headers = 1;
//
// Envoy deprecated its v2 API, prefer to use v3_response_headers instead.
// Mutually exclusive with v3_response_headers.
repeated envoy.api.v2.core.HeaderValueOption response_headers = 1 [deprecated = true];

// List of additional response headers.
// Mutually exclusive with response_headers.
repeated envoy.config.core.v3.HeaderValueOption v3_response_headers = 7;

// Number of 'a' characters in the the response body.
uint32 response_body_size = 2 [(validate.rules).uint32 = {lte: 4194304}];
// If true, then echo request headers in the response body.
Expand Down
2 changes: 2 additions & 0 deletions source/server/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ envoy_cc_library(
"@envoy//source/common/protobuf:message_validator_lib_with_external_headers",
"@envoy//source/common/protobuf:utility_lib_with_external_headers",
"@envoy//source/common/singleton:const_singleton_with_external_headers",
"@envoy_api//envoy/api/v2/core:pkg_cc_proto",
"@envoy_api//envoy/config/core/v3:pkg_cc_proto",
],
)

Expand Down
43 changes: 41 additions & 2 deletions source/server/configuration.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

#include <string>

#include "envoy/api/v2/core/base.pb.h"
#include "envoy/config/core/v3/base.pb.h"

#include "external/envoy/source/common/protobuf/message_validator_impl.h"
#include "external/envoy/source/common/protobuf/utility.h"

Expand Down Expand Up @@ -30,8 +33,20 @@ bool mergeJsonConfig(absl::string_view json, nighthawk::server::ResponseOptions&

void applyConfigToResponseHeaders(Envoy::Http::ResponseHeaderMap& response_headers,
const nighthawk::server::ResponseOptions& response_options) {
for (const auto& header_value_option : response_options.response_headers()) {
const auto& header = header_value_option.header();

// The validation guarantees we only get one of the fields (response_headers, v3_response_headers)
// set.
validateResponseOptions(response_options);
nighthawk::server::ResponseOptions v3_only_response_options = response_options;
for (const envoy::api::v2::core::HeaderValueOption& header_value_option :
v3_only_response_options.response_headers()) {
*v3_only_response_options.add_v3_response_headers() =
upgradeDeprecatedEnvoyV2HeaderValueOptionToV3(header_value_option);
}

for (const envoy::config::core::v3::HeaderValueOption& header_value_option :
v3_only_response_options.v3_response_headers()) {
const envoy::config::core::v3::HeaderValue& header = header_value_option.header();
auto lower_case_key = Envoy::Http::LowerCaseString(header.key());
if (!header_value_option.append().value()) {
response_headers.remove(lower_case_key);
Expand All @@ -40,6 +55,30 @@ void applyConfigToResponseHeaders(Envoy::Http::ResponseHeaderMap& response_heade
}
}

envoy::config::core::v3::HeaderValueOption upgradeDeprecatedEnvoyV2HeaderValueOptionToV3(
const envoy::api::v2::core::HeaderValueOption& v2_header_value_option) {
envoy::config::core::v3::HeaderValueOption v3_header_value_option;
if (v2_header_value_option.has_append()) {
*v3_header_value_option.mutable_append() = v2_header_value_option.append();
}
if (v2_header_value_option.has_header()) {
envoy::config::core::v3::HeaderValue* v3_header = v3_header_value_option.mutable_header();
v3_header->set_key(v2_header_value_option.header().key());
v3_header->set_value(v2_header_value_option.header().value());
}
return v3_header_value_option;
}

void validateResponseOptions(const nighthawk::server::ResponseOptions& response_options) {
if (response_options.response_headers_size() > 0 &&
response_options.v3_response_headers_size() > 0) {
throw Envoy::EnvoyException(
absl::StrCat("invalid configuration in nighthawk::server::ResponseOptions ",
"cannot specify both response_headers and v3_response_headers ",
"configuration was: ", response_options.ShortDebugString()));
}
}

} // namespace Configuration
} // namespace Server
} // namespace Nighthawk
20 changes: 20 additions & 0 deletions source/server/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <string>

#include "envoy/api/v2/core/base.pb.h"
#include "envoy/config/core/v3/base.pb.h"
#include "envoy/http/header_map.h"

#include "api/server/response_options.pb.h"
Expand All @@ -27,10 +29,28 @@ bool mergeJsonConfig(absl::string_view json, nighthawk::server::ResponseOptions&
* @param response_headers Response headers to transform to reflect the passed in response
* options.
* @param response_options Configuration specifying how to transform the header map.
*
* @throws Envoy::EnvoyException if invalid response_options are provided.
*/
void applyConfigToResponseHeaders(Envoy::Http::ResponseHeaderMap& response_headers,
const nighthawk::server::ResponseOptions& response_options);

/**
* Upgrades Envoy's HeaderValueOption from the deprecated v2 API version to v3.
*
* @param v2_header_value_option The HeaderValueOption to be upgraded.
* @return a version of HeaderValueOption upgraded to Envoy API v3.
*/
envoy::config::core::v3::HeaderValueOption upgradeDeprecatedEnvoyV2HeaderValueOptionToV3(
const envoy::api::v2::core::HeaderValueOption& v2_header_value_option);

/**
* Validates the ResponseOptions.
*
* @throws Envoy::EnvoyException on validation errors.
*/
void validateResponseOptions(const nighthawk::server::ResponseOptions& response_options);

} // namespace Configuration
} // namespace Server
} // namespace Nighthawk
8 changes: 5 additions & 3 deletions source/server/http_dynamic_delay_filter_config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "api/server/response_options.pb.h"
#include "api/server/response_options.pb.validate.h"

#include "server/configuration.h"
#include "server/http_dynamic_delay_filter.h"

namespace Nighthawk {
Expand All @@ -22,10 +23,11 @@ class HttpDynamicDelayDecoderFilterConfigFactory
Envoy::Server::Configuration::FactoryContext& context) override {

auto& validation_visitor = Envoy::ProtobufMessage::getStrictValidationVisitor();
return createFilter(
const nighthawk::server::ResponseOptions& response_options =
Envoy::MessageUtil::downcastAndValidate<const nighthawk::server::ResponseOptions&>(
proto_config, validation_visitor),
context);
proto_config, validation_visitor);
validateResponseOptions(response_options);
return createFilter(response_options, context);
}

Envoy::ProtobufTypes::MessagePtr createEmptyConfigProto() override {
Expand Down
9 changes: 5 additions & 4 deletions source/server/http_test_server_filter_config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "api/server/response_options.pb.h"
#include "api/server/response_options.pb.validate.h"

#include "server/configuration.h"
#include "server/http_test_server_filter.h"

namespace Nighthawk {
Expand All @@ -19,12 +20,12 @@ class HttpTestServerDecoderFilterConfig
Envoy::Http::FilterFactoryCb
createFilterFactoryFromProto(const Envoy::Protobuf::Message& proto_config, const std::string&,
Envoy::Server::Configuration::FactoryContext& context) override {

auto& validation_visitor = Envoy::ProtobufMessage::getStrictValidationVisitor();
return createFilter(
const nighthawk::server::ResponseOptions& response_options =
Envoy::MessageUtil::downcastAndValidate<const nighthawk::server::ResponseOptions&>(
proto_config, validation_visitor),
context);
proto_config, validation_visitor);
validateResponseOptions(response_options);
return createFilter(response_options, context);
}

Envoy::ProtobufTypes::MessagePtr createEmptyConfigProto() override {
Expand Down
8 changes: 5 additions & 3 deletions source/server/http_time_tracking_filter_config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "api/server/response_options.pb.h"
#include "api/server/response_options.pb.validate.h"

#include "server/configuration.h"
#include "server/http_time_tracking_filter.h"

namespace Nighthawk {
Expand All @@ -21,10 +22,11 @@ class HttpTimeTrackingFilterConfig
Envoy::Server::Configuration::FactoryContext& context) override {
Envoy::ProtobufMessage::ValidationVisitor& validation_visitor =
Envoy::ProtobufMessage::getStrictValidationVisitor();
return createFilter(
const nighthawk::server::ResponseOptions& response_options =
Envoy::MessageUtil::downcastAndValidate<const nighthawk::server::ResponseOptions&>(
proto_config, validation_visitor),
context);
proto_config, validation_visitor);
validateResponseOptions(response_options);
return createFilter(response_options, context);
}

Envoy::ProtobufTypes::MessagePtr createEmptyConfigProto() override {
Expand Down
13 changes: 13 additions & 0 deletions test/server/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,16 @@ envoy_cc_test(
"@envoy//test/test_common:simulated_time_system_lib",
],
)

envoy_cc_test(
name = "configuration_test",
srcs = ["configuration_test.cc"],
repository = "@envoy",
deps = [
"//api/server:response_options_proto_cc_proto",
"//source/server:configuration_lib",
"@envoy//test/test_common:utility_lib",
"@envoy_api//envoy/api/v2/core:pkg_cc_proto",
"@envoy_api//envoy/config/core/v3:pkg_cc_proto",
],
)
Loading

0 comments on commit facd66b

Please sign in to comment.