Skip to content
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
899ec21
Init work with configuration proposition
Aug 12, 2019
6da905d
Added missing dependency
Aug 31, 2019
8eb6f82
Merge branch 'master' into local_reply_mapper
Aug 31, 2019
9bf0e6b
Without passed config
Aug 31, 2019
fc3c545
WIP config
Sep 2, 2019
c9a686e
Response flags added
Sep 3, 2019
4213f2e
Applied changes from code review
Sep 4, 2019
f8df3ae
repeated match
Sep 4, 2019
dac4695
Merge branch 'master' into local_reply_mapper
Sep 7, 2019
052aeeb
WIP local reply formatter with access log reuse
Sep 7, 2019
1499746
Merge branch 'master' into local_reply_mapper
Sep 13, 2019
8f022b6
Added mapper config
Sep 15, 2019
419a59c
Changed to access log filter
Sep 18, 2019
468308a
Merge branch 'master' into local_reply_mapper
Sep 19, 2019
1cce878
Cleanup and initial work docs
Sep 19, 2019
1efc2e3
Cleanup and initial work docs
Sep 19, 2019
7c75f6c
added comments
Sep 20, 2019
2670d0f
Added possibility to define custom format for each mapper
Sep 26, 2019
955bf79
Merge branch 'master' into local_reply_mapper
Sep 26, 2019
cd31254
Extracted new format StringOrJson
Sep 27, 2019
a77c82f
Removed docs and fixed format. I will provide docs file with implemen…
Oct 1, 2019
20abff0
Merge branch 'master' into local_reply_mapper
Oct 2, 2019
9c8d757
Added more docs
Oct 2, 2019
cc55bb4
Merge branch 'master' into local_reply_mapper
Oct 4, 2019
7784130
Code review fix
Oct 4, 2019
31f3cbf
Merge branch 'master' into local_reply_mapper
Oct 10, 2019
5eadeca
Fix build
Oct 11, 2019
199dd43
Merge branch 'master' into local_reply_mapper
Oct 11, 2019
0aee07a
Generated v3 files
Oct 11, 2019
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ api_proto_library_internal(
"//envoy/api/v2/core:config_source",
"//envoy/api/v2/core:protocol",
"//envoy/config/filter/accesslog/v2:accesslog",
"//envoy/data/accesslog/v2:accesslog",
"//envoy/type:percent",
"//envoy/type/matcher:string",
],
)

Expand All @@ -26,6 +28,8 @@ api_go_proto_library(
"//envoy/api/v2/core:config_source_go_proto",
"//envoy/api/v2/core:protocol_go_proto",
"//envoy/config/filter/accesslog/v2:accesslog_go_proto",
"//envoy/data/accesslog/v2:accesslog_go_proto",
"//envoy/type:percent_go_proto",
"//envoy/type/matcher:string_go_proto",
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import "envoy/api/v2/core/protocol.proto";
import "envoy/api/v2/rds.proto";
import "envoy/api/v2/srds.proto";
import "envoy/config/filter/accesslog/v2/accesslog.proto";
import "envoy/data/accesslog/v2/accesslog.proto";
import "envoy/type/percent.proto";
import "envoy/type/matcher/string.proto";

import "google/protobuf/any.proto";
import "google/protobuf/duration.proto";
Expand All @@ -25,7 +27,7 @@ import "gogoproto/gogo.proto";
// [#protodoc-title: HTTP connection manager]
// HTTP connection manager :ref:`configuration overview <config_http_conn_man>`.

// [#comment:next free field: 35]
// [#comment:next free field: 36]
message HttpConnectionManager {
enum CodecType {
option (gogoproto.goproto_enum_prefix) = false;
Expand Down Expand Up @@ -450,6 +452,34 @@ message HttpConnectionManager {
// with `prefix` match set to `/dir`. Defaults to `false`. Note that slash merging is not part of
// `HTTP spec <https://tools.ietf.org/html/rfc3986>` and is provided for convenience.
bool merge_slashes = 33;

// Configuration of local reply send by envoy for http responses. Allows to define custom rules
// which maps response attribute returned by envoy to different one. Currently mapping of
// status code is implemented.
message SendLocalReplyConfig {
// Configuration which allows to define custom rules for matching local response.
// It works like and operator e.g: if you define status code 404 and body pattern
// then response must match both
message Match {

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.

I really, really, really would like to unify our HTTP match capabilities, but maybe we defer this to v4 as I think any other solution will be too disruptive. @htuch any thoughts here?

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.

I think that we should tackle this in v4, but meanwhile, for new mathers, can we align them behind either access log or TAP matchers as the basis (even if only subsetted)? I'd prefer not to add yet another matcher format (and surrounding code cruft for parsing and executing match expressions).

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.

My high level question here is do we really need a match/rewrite semantics here? Since local reply is the output from Envoy (either from core HCM, or extensions), can we change the code of local reply to emit some structured data, and map it to the actual response based on config? A Rewrite here seems based on how current local reply works.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I am not sure if we want always to map some response. I thought that it would be nice to just map specifice responses to another one like it has been written in #7537.

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.

IMO it's a bit easier to allow the operator to have generic rules for local replies versus having to account for every possible location where a reply is generated, but I could definitely be convinced otherwise.

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.

I understand the context of #7537, but I'd like this to be generic enough to make it possible to convert all local reply to JSON. Particularly can Rewrite be some sort of formatter instead?

Rewrite proposed here seems based on how current local reply works (i.e. take what current sendLocalReply send, and rewrite the response header/body), instead can we just make sendLocalReply emit what formatter says for those?

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.

Yeah agreed this makes sense to rethink rewrite is some combination of both rewriting fields as well as a final format phase?

// Definition of status codes to match.
repeated uint32 status_codes = 1;
Comment thread
htuch marked this conversation as resolved.
Outdated
// Definition of body pattern to match.
envoy.type.matcher.StringMatcher body_pattern = 2;
// Definition of response flags to match.
envoy.data.accesslog.v2.ResponseFlags response_flags = 3;
};

// Configuration which allows to define custom mapping for matched response.
message Rewrite {
// Definition of status code to which matched one will be mapped.
uint32 status = 1 [(validate.rules).uint32 = {gte: 100, lt: 600}];
Comment thread
htuch marked this conversation as resolved.
Outdated
};

Match match = 1;
Comment thread
htuch marked this conversation as resolved.
Outdated
Rewrite rewrite = 2;
};

repeated SendLocalReplyConfig send_local_reply_config = 35;
}

message Rds {
Expand Down
1 change: 1 addition & 0 deletions api/envoy/data/accesslog/v2/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ api_proto_library_internal(
name = "accesslog",
srcs = ["accesslog.proto"],
visibility = [
"//envoy/config/filter/network/http_connection_manager/v2:__pkg__",

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.

Why is this needed?

@lukidzi lukidzi Sep 4, 2019

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've added this because ResponseFlags wasn't visible in proto.

"//envoy/service/accesslog/v2:__pkg__",
],
deps = [
Expand Down
11 changes: 11 additions & 0 deletions source/common/http/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ envoy_cc_library(
"//include/envoy/config:config_provider_interface",
"//include/envoy/http:filter_interface",
"//include/envoy/router:rds_interface",
"//source/common/http:local_reply_lib",
"//source/common/network:utility_lib",
],
)
Expand Down Expand Up @@ -238,6 +239,16 @@ envoy_cc_library(
],
)

envoy_cc_library(
name = "local_reply_lib",
hdrs = ["local_reply.h"],
deps = [
"//source/common/common:matchers_lib",
"@envoy_api//envoy/config/filter/network/http_connection_manager/v2:http_connection_manager_cc",
"@envoy_api//envoy/service/accesslog/v2:als_cc",
],
)

envoy_cc_library(
name = "message_lib",
srcs = ["message_impl.cc"],
Expand Down
6 changes: 6 additions & 0 deletions source/common/http/conn_manager_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "common/http/date_provider.h"
#include "common/network/utility.h"
#include "common/http/local_reply.h"

namespace Envoy {
namespace Http {
Expand Down Expand Up @@ -368,6 +369,11 @@ class ConnectionManagerConfig {
* one.
*/
virtual bool shouldMergeSlashes() const PURE;

/**
* @return supplies the local reply mapping configuration
*/
virtual const LocalReplyConfig* localReplyConfig() const PURE;
};
} // namespace Http
} // namespace Envoy
137 changes: 137 additions & 0 deletions source/common/http/local_reply.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#pragma once

#include <list>
#include <string>
#include <vector>

#include "envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.pb.validate.h"
#include "envoy/config/filter/accesslog/v2/accesslog.pb.validate.h"

#include "common/common/matchers.h"

namespace Envoy {
namespace Http {
static uint64_t toBitMask(const envoy::data::accesslog::v2::ResponseFlags& response_flags){
uint64_t bit_mask = 0;
if (response_flags.failed_local_healthcheck()) {
bit_mask |= StreamInfo::ResponseFlag::FailedLocalHealthCheck;
}

if (response_flags.no_healthy_upstream()) {
bit_mask |= StreamInfo::ResponseFlag::NoHealthyUpstream;
}

if (response_flags.upstream_request_timeout()) {
bit_mask |= StreamInfo::ResponseFlag::UpstreamRequestTimeout;
}

if (response_flags.local_reset()) {
bit_mask |= StreamInfo::ResponseFlag::LocalReset;
}

if (response_flags.upstream_remote_reset()) {
bit_mask |= StreamInfo::ResponseFlag::UpstreamRemoteReset;
}

if (response_flags.upstream_connection_failure()) {
bit_mask |= StreamInfo::ResponseFlag::UpstreamConnectionFailure;
}

if (response_flags.upstream_connection_termination()) {
bit_mask |= StreamInfo::ResponseFlag::UpstreamConnectionTermination;
}

if (response_flags.upstream_overflow()) {
bit_mask |= StreamInfo::ResponseFlag::UpstreamOverflow;
}

if (response_flags.no_route_found()) {
bit_mask |= StreamInfo::ResponseFlag::NoRouteFound;
}

if (response_flags.delay_injected()) {
bit_mask |= StreamInfo::ResponseFlag::DelayInjected;
}

if (response_flags.fault_injected()) {
bit_mask |= StreamInfo::ResponseFlag::FaultInjected;
}

if (response_flags.rate_limited()) {
bit_mask |= StreamInfo::ResponseFlag::RateLimited;
}

// if (response_flags.unauthorized_details()) {
// bit_mask |= StreamInfo::ResponseFlag::UnauthorizedExternalService;
// }

if (response_flags.rate_limit_service_error()) {
bit_mask |= StreamInfo::ResponseFlag::RateLimitServiceError;
}

if (response_flags.downstream_connection_termination()) {
bit_mask |= StreamInfo::ResponseFlag::DownstreamConnectionTermination;
}

if (response_flags.upstream_retry_limit_exceeded()) {
bit_mask |= StreamInfo::ResponseFlag::UpstreamRetryLimitExceeded;
}

if (response_flags.stream_idle_timeout()) {
bit_mask |= StreamInfo::ResponseFlag::StreamIdleTimeout;
}

if (response_flags.invalid_envoy_request_headers()) {
bit_mask |= StreamInfo::ResponseFlag::InvalidEnvoyRequestHeaders;
}

return bit_mask;
}

struct LocalReplyMatcher {
LocalReplyMatcher(std::vector<uint32_t>& status_codes,
const envoy::type::matcher::StringMatcher& body_pattern,
const envoy::data::accesslog::v2::ResponseFlags& response_flags)
: status_codes_(move(status_codes)), body_pattern_(body_pattern), response_flags_(toBitMask(response_flags)){};

bool match(const absl::string_view value) const {
return body_pattern_.match(value);
}

std::vector<uint32_t> status_codes_;
Matchers::StringMatcherImpl body_pattern_;
uint64_t response_flags_;
};

/**
* Structure which holds rewriter configuration from proto file for LocalReplyConfig.
*/
struct LocalReplyRewriter {
uint32_t status_;
};

class LocalReplyConfig {
public:
LocalReplyConfig(
const envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager&
config) {
for (const auto& match_rewrite_config : config.send_local_reply_config()) {
std::vector<uint32_t> status_codes;
for (const auto code : match_rewrite_config.match().status_codes()) {
status_codes.emplace_back(code);
}

std::pair<LocalReplyMatcher, LocalReplyRewriter> pair = std::make_pair(
LocalReplyMatcher{status_codes, match_rewrite_config.match().body_pattern(), match_rewrite_config.match().response_flags()},
LocalReplyRewriter{match_rewrite_config.rewrite().status()});
match_rewrite_pair_list_.emplace_back(std::move(pair));
}
};
private:
std::list<std::pair<LocalReplyMatcher, LocalReplyRewriter>> match_rewrite_pair_list_;
};

using LocalReplyConfigConstPtr = std::unique_ptr<const LocalReplyConfig>;

} // namespace Http
} // namespace Envoy
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ envoy_cc_library(
"//source/common/config:utility_lib",
"//source/common/http:conn_manager_lib",
"//source/common/http:default_server_string_lib",
"//source/common/http:local_reply_lib",
"//source/common/http:utility_lib",
"//source/common/http/http1:codec_lib",
"//source/common/http/http2:codec_lib",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,9 @@ HttpConnectionManagerConfig::HttpConnectionManagerConfig(
std::make_pair(name, FilterConfig{std::move(factories), enabled}));
}
}
if (config.send_local_reply_config().size() > 0) {
local_reply_config_ = Http::LocalReplyConfigConstPtr(new Http::LocalReplyConfig(config));
}
}

void HttpConnectionManagerConfig::processFilter(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "common/common/logger.h"
#include "common/http/conn_manager_impl.h"
#include "common/http/local_reply.h"
#include "common/json/json_loader.h"

#include "extensions/filters/network/common/factory_base.h"
Expand Down Expand Up @@ -142,6 +143,9 @@ class HttpConnectionManagerConfig : Logger::Loggable<Logger::Id::config>,
const Http::Http1Settings& http1Settings() const override { return http1_settings_; }
bool shouldNormalizePath() const override { return normalize_path_; }
bool shouldMergeSlashes() const override { return merge_slashes_; }
const Http::LocalReplyConfig* localReplyConfig() const override {
return local_reply_config_.get();
}
std::chrono::milliseconds delayedCloseTimeout() const override { return delayed_close_timeout_; }

private:
Expand Down Expand Up @@ -189,6 +193,7 @@ class HttpConnectionManagerConfig : Logger::Loggable<Logger::Id::config>,
std::chrono::milliseconds delayed_close_timeout_;
const bool normalize_path_;
const bool merge_slashes_;
Http::LocalReplyConfigConstPtr local_reply_config_;

// Default idle timeout is 5 minutes if nothing is specified in the HCM config.
static const uint64_t StreamIdleTimeoutMs = 5 * 60 * 1000;
Expand Down
1 change: 1 addition & 0 deletions source/extensions/filters/network/kafka/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ envoy_cc_library(
name = "kafka_request_codec_lib",
srcs = ["request_codec.cc"],
hdrs = [
"codec.h",
"request_codec.h",
],
deps = [
Expand Down
1 change: 1 addition & 0 deletions source/server/http/admin.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ class AdminImpl : public Admin,
const Http::Http1Settings& http1Settings() const override { return http1_settings_; }
bool shouldNormalizePath() const override { return true; }
bool shouldMergeSlashes() const override { return true; }
Http::LocalReplyConfig* localReplyConfig() const override { return nullptr; }
Http::Code request(absl::string_view path_and_query, absl::string_view method,
Http::HeaderMap& response_headers, std::string& body) override;
void closeSocket();
Expand Down