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

Deprecate Envoy API v2 primitives in configuration for our Envoy filters. #588

Merged
merged 6 commits into from
Dec 8, 2020
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/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];
mum4k marked this conversation as resolved.
Show resolved Hide resolved

// 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