From 6a3f13bf1ce2b8c54e0838469c12d2519e7c4d25 Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Tue, 11 Jun 2019 15:31:18 -0400 Subject: [PATCH 01/21] add scope key-builder impl and test Signed-off-by: Xin Zhuang --- api/envoy/api/v2/discovery.proto | 62 +++-- .../v2/http_connection_manager.proto | 13 + bazel/BUILD | 14 + bazel/external/quiche.BUILD | 43 +++ .../configuration/http_conn_man/headers.rst | 7 +- docs/root/intro/version_history.rst | 2 + source/common/grpc/BUILD | 22 +- source/common/grpc/common.cc | 78 ------ source/common/grpc/common.h | 53 +--- source/common/grpc/context_impl.cc | 89 +++++++ source/common/grpc/context_impl.h | 70 +++++ source/common/http/conn_manager_config.h | 2 +- source/common/http/conn_manager_impl.cc | 20 +- source/common/http/conn_manager_impl.h | 10 +- source/common/http/conn_manager_utility.cc | 22 +- source/common/http/http2/codec_impl.cc | 1 + source/common/router/rds_impl.cc | 8 +- source/common/router/scoped_config_impl.cc | 56 ++++ source/common/router/scoped_config_impl.h | 147 ++++++++++ .../filters/http/grpc_http1_bridge/BUILD | 1 + .../grpc_http1_bridge/http1_bridge_filter.cc | 3 +- .../grpc_http1_bridge/http1_bridge_filter.h | 2 +- source/extensions/filters/http/grpc_web/BUILD | 3 +- .../filters/http/grpc_web/grpc_web_filter.cc | 4 +- .../filters/http/grpc_web/grpc_web_filter.h | 2 +- .../network/http_connection_manager/config.cc | 3 + source/extensions/quic_listeners/quiche/BUILD | 27 +- .../quic_listeners/quiche/envoy_quic_alarm.cc | 35 +++ .../quic_listeners/quiche/envoy_quic_alarm.h | 39 +++ .../quiche/envoy_quic_alarm_factory.cc | 22 ++ .../quiche/envoy_quic_alarm_factory.h | 39 +++ .../quic_listeners/quiche/platform/BUILD | 7 - source/extensions/tracers/lightstep/BUILD | 2 + .../tracers/lightstep/lightstep_tracer_impl.h | 3 +- source/server/BUILD | 2 +- source/server/config_validation/server.h | 2 +- source/server/http/admin.cc | 24 +- source/server/http/admin.h | 10 +- source/server/server.h | 4 +- test/common/grpc/BUILD | 14 +- test/common/grpc/common_test.cc | 83 +----- test/common/grpc/context_impl_test.cc | 80 ++++++ test/common/http/conn_manager_impl_test.cc | 48 ++++ test/common/http/conn_manager_utility_test.cc | 24 +- test/common/router/BUILD | 22 +- ...minimized-route_fuzz_test-5077190058704896 | 1 + test/common/router/route_fuzz_test.cc | 19 +- test/common/router/scoped_config_impl_test.cc | 252 ++++++++++++++++++ test/config_test/config_test.cc | 24 ++ .../http1_bridge_filter_test.cc | 6 +- .../http/grpc_web/grpc_web_filter_test.cc | 2 +- test/extensions/quic_listeners/quiche/BUILD | 12 +- .../quiche/envoy_quic_alarm_test.cc | 194 ++++++++++++++ .../lightstep/lightstep_tracer_impl_test.cc | 2 +- test/integration/http2_integration_test.cc | 17 ++ test/integration/http_integration.h | 1 + test/integration/integration_admin_test.cc | 2 + test/mocks/server/BUILD | 1 + test/mocks/server/mocks.h | 5 +- test/server/http/admin_test.cc | 58 +++- test/test_common/simulated_time_system.cc | 2 +- .../test_common/simulated_time_system_test.cc | 6 + 62 files changed, 1499 insertions(+), 329 deletions(-) mode change 100644 => 100755 bazel/BUILD create mode 100644 source/common/grpc/context_impl.cc create mode 100644 source/common/grpc/context_impl.h create mode 100644 source/extensions/quic_listeners/quiche/envoy_quic_alarm.cc create mode 100644 source/extensions/quic_listeners/quiche/envoy_quic_alarm.h create mode 100644 source/extensions/quic_listeners/quiche/envoy_quic_alarm_factory.cc create mode 100644 source/extensions/quic_listeners/quiche/envoy_quic_alarm_factory.h create mode 100644 test/common/grpc/context_impl_test.cc create mode 100644 test/common/router/route_corpus/clusterfuzz-testcase-minimized-route_fuzz_test-5077190058704896 create mode 100644 test/common/router/scoped_config_impl_test.cc create mode 100644 test/extensions/quic_listeners/quiche/envoy_quic_alarm_test.cc diff --git a/api/envoy/api/v2/discovery.proto b/api/envoy/api/v2/discovery.proto index fe11fc8fd69c..fb95252a9aec 100644 --- a/api/envoy/api/v2/discovery.proto +++ b/api/envoy/api/v2/discovery.proto @@ -108,7 +108,7 @@ message DiscoveryResponse { // With Delta xDS, the DeltaDiscoveryResponses do not need to include a full // snapshot of the tracked resources. Instead, DeltaDiscoveryResponses are a // diff to the state of a xDS client. -// In Delta XDS there are per resource versions, which allow tracking state at +// In Delta XDS there are per-resource versions, which allow tracking state at // the resource granularity. // An xDS Delta session is always in the context of a gRPC bidirectional // stream. This allows the xDS server to keep track of the state of xDS clients @@ -119,22 +119,27 @@ message DiscoveryResponse { // Optionally, a response message level system_version_info is present for // debugging purposes only. // -// DeltaDiscoveryRequest can be sent in 3 situations: -// 1. Initial message in a xDS bidirectional gRPC stream. -// 2. As a ACK or NACK response to a previous DeltaDiscoveryResponse. -// In this case the response_nonce is set to the nonce value in the Response. -// ACK or NACK is determined by the absence or presence of error_detail. -// 3. Spontaneous DeltaDiscoveryRequest from the client. -// This can be done to dynamically add or remove elements from the tracked -// resource_names set. In this case response_nonce must be omitted. +// DeltaDiscoveryRequest plays two independent roles. Any DeltaDiscoveryRequest +// can be either or both of: [1] informing the server of what resources the +// client has gained/lost interest in (using resource_names_subscribe and +// resource_names_unsubscribe), or [2] (N)ACKing an earlier resource update from +// the server (using response_nonce, with presence of error_detail making it a NACK). +// Additionally, the first message (for a given type_url) of a reconnected gRPC stream +// has a third role: informing the server of the resources (and their versions) +// that the client already possesses, using the initial_resource_versions field. +// +// As with state-of-the-world, when multiple resource types are multiplexed (ADS), +// all requests/acknowledgments/updates are logically walled off by type_url: +// a Cluster ACK exists in a completely separate world from a prior Route NACK. +// In particular, initial_resource_versions being sent at the "start" of every +// gRPC stream actually entails a message for each type_url, each with its own +// initial_resource_versions. message DeltaDiscoveryRequest { // The node making the request. core.Node node = 1; // Type of the resource that is being requested, e.g. - // "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". This is implicit - // in requests made via singleton xDS APIs such as CDS, LDS, etc. but is - // required for ADS. + // "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". string type_url = 2; // DeltaDiscoveryRequests allow the client to add or remove individual @@ -142,32 +147,35 @@ message DeltaDiscoveryRequest { // All resource names in the resource_names_subscribe list are added to the // set of tracked resources and all resource names in the resource_names_unsubscribe // list are removed from the set of tracked resources. - // Unlike in state-of-the-world xDS, an empty resource_names_subscribe or + // + // *Unlike* state-of-the-world xDS, an empty resource_names_subscribe or // resource_names_unsubscribe list simply means that no resources are to be // added or removed to the resource list. - // The xDS server must send updates for all tracked resources but can also - // send updates for resources the client has not subscribed to. This behavior - // is similar to state-of-the-world xDS. - // These two fields can be set for all types of DeltaDiscoveryRequests - // (initial, ACK/NACK or spontaneous). + // *Like* state-of-the-world xDS, the server must send updates for all tracked + // resources, but can also send updates for resources the client has not subscribed to. // // NOTE: the server must respond with all resources listed in resource_names_subscribe, // even if it believes the client has the most recent version of them. The reason: // the client may have dropped them, but then regained interest before it had a chance // to send the unsubscribe message. See DeltaSubscriptionStateTest.RemoveThenAdd. // + // These two fields can be set in any DeltaDiscoveryRequest, including ACKs + // and initial_resource_versions. + // // A list of Resource names to add to the list of tracked resources. repeated string resource_names_subscribe = 3; // A list of Resource names to remove from the list of tracked resources. repeated string resource_names_unsubscribe = 4; - // This map must be populated when the DeltaDiscoveryRequest is the - // first in a stream (assuming there are any resources - this field's purpose is to enable - // a session to continue in a reconnected gRPC stream, and so will not be used in the very - // first stream of a session). The keys are the resources names of the xDS resources - // known to the xDS client. The values in the map are the associated resource - // level version info. + // Informs the server of the versions of the resources the xDS client knows of, to enable the + // client to continue the same logical xDS session even in the face of gRPC stream reconnection. + // It will not be populated: [1] in the very first stream of a session, since the client will + // not yet have any resources, [2] in any message after the first in a stream (for a given + // type_url), since the server will already be correctly tracking the client's state. + // (In ADS, the first message *of each type_url* of a reconnected stream populates this map.) + // The map's keys are names of xDS resources known to the xDS client. + // The map's values are opaque resource versions. map initial_resource_versions = 5; // When the DeltaDiscoveryRequest is a ACK or NACK message in response @@ -186,8 +194,8 @@ message DeltaDiscoveryResponse { // The version of the response data (used for debugging). string system_version_info = 1; - // The response resources. These are typed resources that match the type url - // in the DeltaDiscoveryRequest. + // The response resources. These are typed resources, whose types must match + // the type_url field. repeated Resource resources = 2 [(gogoproto.nullable) = false]; // field id 3 IS available! @@ -201,7 +209,7 @@ message DeltaDiscoveryResponse { repeated string removed_resources = 6; // The nonce provides a way for DeltaDiscoveryRequests to uniquely - // reference a DeltaDiscoveryResponse. The nonce is required. + // reference a DeltaDiscoveryResponse when (N)ACKing. The nonce is required. string nonce = 5; } diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto index be0b3926ff79..78f5aa4c0b1e 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +++ b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -317,6 +317,7 @@ message HttpConnectionManager { ForwardClientCertDetails forward_client_cert_details = 16 [(validate.rules).enum.defined_only = true]; + // [#comment:next free field: 7] message SetCurrentClientCertDetails { // Whether to forward the subject of the client cert. Defaults to false. google.protobuf.BoolValue subject = 1; @@ -328,6 +329,12 @@ message HttpConnectionManager { // Defaults to false. bool cert = 3; + // Whether to forward the entire client cert chain (including the leaf cert) in URL encoded PEM + // format. This will appear in the XFCC header comma separated from other values with the value + // Chain="PEM". + // Defaults to false. + bool chain = 6; + // Whether to forward the DNS type Subject Alternative Names of the client cert. // Defaults to false. bool dns = 4; @@ -477,6 +484,10 @@ message ScopedRoutes { // Specifies a header field's key value pair to match on. message KvElement { // The separator between key and value (e.g., '=' separates 'k=v;...'). + // If an element is an empty string, the element is ignored. + // If an element contains no separator, the whole element is parsed as key and the + // fragment value is an empty string. + // If there are multiple values for a matched key, the first value is returned. string separator = 1 [(validate.rules).string.min_bytes = 1]; // The key to match on. @@ -485,6 +496,8 @@ message ScopedRoutes { oneof extract_type { // Specifies the zero based index of the element to extract. + // Note Envoy concatenates multiple values of the same header key into a comma separated + // string, the splitting always happens after the concatenation. uint32 index = 3; // Specifies the key value pair to extract the value from. diff --git a/bazel/BUILD b/bazel/BUILD old mode 100644 new mode 100755 index 08c18f4ddd17..c3ac13989d2a --- a/bazel/BUILD +++ b/bazel/BUILD @@ -273,3 +273,17 @@ alias( }, ), ) + +alias( + name = "x86", + actual = select( + { + ":darwin_x86_64": ":darwin_x86_64", + ":ios_x86_64": "ios_x86_64", + "linux_x86_64": "linux_x86_64", + "windows_x86_64": "windows_x86_64", + # If we're not on an x86 platform return a value that will never match in the select() statement calling this since it would have already been matched above. + "//conditions:default": ":darwin_x86_64", + }, + ), +) diff --git a/bazel/external/quiche.BUILD b/bazel/external/quiche.BUILD index 898ea9918c52..c094ad2e5125 100644 --- a/bazel/external/quiche.BUILD +++ b/bazel/external/quiche.BUILD @@ -362,6 +362,37 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "quic_core_arena_scoped_ptr_lib", + hdrs = ["quiche/quic/core/quic_arena_scoped_ptr.h"], + repository = "@envoy", + visibility = ["//visibility:public"], + deps = [":quic_platform_base"], +) + +envoy_cc_library( + name = "quic_core_alarm_lib", + srcs = ["quiche/quic/core/quic_alarm.cc"], + hdrs = ["quiche/quic/core/quic_alarm.h"], + repository = "@envoy", + visibility = ["//visibility:public"], + deps = [ + ":quic_core_arena_scoped_ptr_lib", + ":quic_core_time_lib", + ], +) + +envoy_cc_library( + name = "quic_core_alarm_factory_lib", + hdrs = ["quiche/quic/core/quic_alarm_factory.h"], + repository = "@envoy", + visibility = ["//visibility:public"], + deps = [ + ":quic_core_alarm_lib", + ":quic_core_one_block_arena_lib", + ], +) + envoy_cc_library( name = "quic_core_buffer_allocator_lib", srcs = [ @@ -387,6 +418,18 @@ envoy_cc_library( deps = [":quic_platform_export"], ) +envoy_cc_library( + name = "quic_core_one_block_arena_lib", + srcs = ["quiche/quic/core/quic_one_block_arena.h"], + repository = "@envoy", + visibility = ["//visibility:public"], + deps = [ + ":quic_core_arena_scoped_ptr_lib", + ":quic_core_types_lib", + ":quic_platform_base", + ], +) + envoy_cc_library( name = "quic_core_time_lib", srcs = ["quiche/quic/core/quic_time.cc"], diff --git a/docs/root/configuration/http_conn_man/headers.rst b/docs/root/configuration/http_conn_man/headers.rst index f6380190a6b9..492dc850d0ac 100644 --- a/docs/root/configuration/http_conn_man/headers.rst +++ b/docs/root/configuration/http_conn_man/headers.rst @@ -133,9 +133,10 @@ The following keys are supported: 1. ``By`` The Subject Alternative Name (URI type) of the current proxy's certificate. 2. ``Hash`` The SHA 256 digest of the current client certificate. 3. ``Cert`` The entire client certificate in URL encoded PEM format. -4. ``Subject`` The Subject field of the current client certificate. The value is always double-quoted. -5. ``URI`` The URI type Subject Alternative Name field of the current client certificate. -6. ``DNS`` The DNS type Subject Alternative Name field of the current client certificate. A client certificate may contain multiple DNS type Subject Alternative Names, each will be a separate key-value pair. +4. ``Chain`` The entire client certificate chain (including the leaf certificate) in URL encoded PEM format. +5. ``Subject`` The Subject field of the current client certificate. The value is always double-quoted. +6. ``URI`` The URI type Subject Alternative Name field of the current client certificate. +7. ``DNS`` The DNS type Subject Alternative Name field of the current client certificate. A client certificate may contain multiple DNS type Subject Alternative Names, each will be a separate key-value pair. A client certificate may contain multiple Subject Alternative Name types. For details on different Subject Alternative Name types, please refer `RFC 2459`_. diff --git a/docs/root/intro/version_history.rst b/docs/root/intro/version_history.rst index e6c8d9348237..3b3c45e73538 100644 --- a/docs/root/intro/version_history.rst +++ b/docs/root/intro/version_history.rst @@ -21,6 +21,8 @@ Version history `. * health check: added :ref:`initial jitter ` to add jitter to the first health check in order to prevent thundering herd on Envoy startup. * hot restart: stats are no longer shared between hot restart parent/child via shared memory, but rather by RPC. Hot restart version incremented to 11. +* http: added the ability to pass a URL encoded PEM encoded peer certificate chain in the + :ref:`config_http_conn_man_headers_x-forwarded-client-cert` header. * http: fixed a bug where large unbufferable responses were not tracked in stats and logs correctly. * http: fixed a crashing bug where gRPC local replies would cause segfaults when upstream access logging was on. * http: mitigated a race condition with the :ref:`delayed_close_timeout` where it could trigger while actively flushing a pending write buffer for a downstream connection. diff --git a/source/common/grpc/BUILD b/source/common/grpc/BUILD index 15de0f1ecb01..603474289767 100644 --- a/source/common/grpc/BUILD +++ b/source/common/grpc/BUILD @@ -15,7 +15,7 @@ envoy_cc_library( hdrs = ["typed_async_client.h"], deps = [ ":codec_lib", - ":common_lib", + ":context_lib", "//include/envoy/grpc:async_client_interface", "//source/common/buffer:zero_copy_input_stream_lib", "//source/common/http:async_client_lib", @@ -28,7 +28,7 @@ envoy_cc_library( hdrs = ["async_client_impl.h"], deps = [ ":codec_lib", - ":common_lib", + ":context_lib", ":typed_async_client_lib", "//include/envoy/grpc:async_client_interface", "//source/common/buffer:zero_copy_input_stream_lib", @@ -42,7 +42,7 @@ envoy_cc_library( hdrs = ["async_client_manager_impl.h"], deps = [ ":async_client_lib", - ":common_lib", + ":context_lib", "//include/envoy/grpc:async_client_manager_interface", "//include/envoy/singleton:manager_interface", "//include/envoy/thread_local:thread_local_interface", @@ -78,7 +78,6 @@ envoy_cc_library( hdrs = ["common.h"], external_deps = ["abseil_optional"], deps = [ - "//include/envoy/grpc:context_interface", "//include/envoy/http:header_map_interface", "//include/envoy/http:message_interface", "//include/envoy/stats:stats_interface", @@ -97,6 +96,19 @@ envoy_cc_library( "//source/common/http:message_lib", "//source/common/http:utility_lib", "//source/common/protobuf", + ], +) + +envoy_cc_library( + name = "context_lib", + srcs = ["context_impl.cc"], + hdrs = ["context_impl.h"], + external_deps = ["abseil_optional"], + deps = [ + "//include/envoy/grpc:context_interface", + "//include/envoy/http:header_map_interface", + "//include/envoy/stats:stats_interface", + "//source/common/common:hash_lib", "//source/common/stats:symbol_table_lib", ], ) @@ -129,7 +141,7 @@ envoy_cc_library( "grpc", ], deps = [ - ":common_lib", + ":context_lib", ":google_grpc_creds_lib", ":google_grpc_utils_lib", ":typed_async_client_lib", diff --git a/source/common/grpc/common.cc b/source/common/grpc/common.cc index 4b28e8e39d1e..43ff985a661f 100644 --- a/source/common/grpc/common.cc +++ b/source/common/grpc/common.cc @@ -26,29 +26,6 @@ namespace Envoy { namespace Grpc { -Common::Common(Stats::SymbolTable& symbol_table) - : symbol_table_(symbol_table), stat_name_pool_(symbol_table), - grpc_(stat_name_pool_.add("grpc")), grpc_web_(stat_name_pool_.add("grpc-web")), - success_(stat_name_pool_.add("success")), failure_(stat_name_pool_.add("failure")), - total_(stat_name_pool_.add("total")), zero_(stat_name_pool_.add("0")) {} - -// Makes a stat name from a string, if we don't already have one for it. -// This always takes a lock on mutex_, and if we haven't seen the name -// before, it also takes a lock on the symbol table. -// -// TODO(jmarantz): See https://github.com/envoyproxy/envoy/pull/7008 for -// a lock-free approach to creating dynamic stat-names based on requests. -Stats::StatName Common::makeDynamicStatName(absl::string_view name) { - Thread::LockGuard lock(mutex_); - auto iter = stat_name_map_.find(name); - if (iter != stat_name_map_.end()) { - return iter->second; - } - const Stats::StatName stat_name = stat_name_pool_.add(name); - stat_name_map_[std::string(name)] = stat_name; - return stat_name; -} - bool Common::hasGrpcContentType(const Http::HeaderMap& headers) { const Http::HeaderEntry* content_type = headers.ContentType(); // Content type is gRPC if it is exactly "application/grpc" or starts with @@ -72,45 +49,6 @@ bool Common::isGrpcResponseHeader(const Http::HeaderMap& headers, bool end_strea return hasGrpcContentType(headers); } -void Common::chargeStat(const Upstream::ClusterInfo& cluster, Protocol protocol, - const RequestNames& request_names, const Http::HeaderEntry* grpc_status) { - if (!grpc_status) { - return; - } - - absl::string_view status_str = grpc_status->value().getStringView(); - const bool success = (status_str == "0"); - - // TODO(jmarantz): Perhaps the universe of likely grpc status codes is - // sufficiently bounded that we should precompute status StatNames for popular - // ones beyond "0". - const Stats::StatName status_stat_name = success ? zero_ : makeDynamicStatName(status_str); - const Stats::SymbolTable::StoragePtr stat_name_storage = - symbol_table_.join({protocolStatName(protocol), request_names.service_, request_names.method_, - status_stat_name}); - - cluster.statsScope().counterFromStatName(Stats::StatName(stat_name_storage.get())).inc(); - chargeStat(cluster, protocol, request_names, success); -} - -void Common::chargeStat(const Upstream::ClusterInfo& cluster, Protocol protocol, - const RequestNames& request_names, bool success) { - const Stats::SymbolTable::StoragePtr prefix_storage = symbol_table_.join( - {protocolStatName(protocol), request_names.service_, request_names.method_}); - const Stats::StatName prefix(prefix_storage.get()); - const Stats::SymbolTable::StoragePtr status = - symbol_table_.join({prefix, successStatName(success)}); - const Stats::SymbolTable::StoragePtr total = symbol_table_.join({prefix, total_}); - - cluster.statsScope().counterFromStatName(Stats::StatName(status.get())).inc(); - cluster.statsScope().counterFromStatName(Stats::StatName(total.get())).inc(); -} - -void Common::chargeStat(const Upstream::ClusterInfo& cluster, const RequestNames& request_names, - bool success) { - chargeStat(cluster, Protocol::Grpc, request_names, success); -} - absl::optional Common::getGrpcStatus(const Http::HeaderMap& trailers) { const Http::HeaderEntry* grpc_status_header = trailers.GrpcStatus(); @@ -130,22 +68,6 @@ std::string Common::getGrpcMessage(const Http::HeaderMap& trailers) { return entry ? std::string(entry->value().getStringView()) : EMPTY_STRING; } -absl::optional -Common::resolveServiceAndMethod(const Http::HeaderEntry* path) { - absl::optional request_names; - if (path == nullptr) { - return request_names; - } - const auto parts = StringUtil::splitToken(path->value().getStringView(), "/"); - if (parts.size() != 2) { - return request_names; - } - const Stats::StatName service = makeDynamicStatName(parts[0]); - const Stats::StatName method = makeDynamicStatName(parts[1]); - request_names = RequestNames{service, method}; - return request_names; -} - Buffer::InstancePtr Common::serializeToGrpcFrame(const Protobuf::Message& message) { // http://www.grpc.io/docs/guides/wire.html // Reserve enough space for the entire message and the 5 byte header. diff --git a/source/common/grpc/common.h b/source/common/grpc/common.h index 82778b5f7d29..fa5fe72f7bc7 100644 --- a/source/common/grpc/common.h +++ b/source/common/grpc/common.h @@ -4,7 +4,6 @@ #include #include "envoy/common/exception.h" -#include "envoy/grpc/context.h" #include "envoy/grpc/status.h" #include "envoy/http/filter.h" #include "envoy/http/header_map.h" @@ -13,7 +12,6 @@ #include "common/common/hash.h" #include "common/grpc/status.h" #include "common/protobuf/protobuf.h" -#include "common/stats/symbol_table_impl.h" #include "absl/types/optional.h" @@ -28,16 +26,8 @@ class Exception : public EnvoyException { const absl::optional grpc_status_; }; -struct Context::RequestNames { - Stats::StatName service_; // supplies the service name. - Stats::StatName method_; // supplies the method name. -}; - -// TODO(jmarantz): Rename 'Common' to 'ContextImpl'. -class Common : public Context { +class Common { public: - explicit Common(Stats::SymbolTable& symbol_table); - /** * @param headers the headers to parse. * @return bool indicating whether content-type is gRPC. @@ -85,23 +75,6 @@ class Common : public Context { */ static void toGrpcTimeout(const std::chrono::milliseconds& timeout, Http::HeaderString& value); - // Context - void chargeStat(const Upstream::ClusterInfo& cluster, Protocol protocol, - const RequestNames& request_names, const Http::HeaderEntry* grpc_status) override; - void chargeStat(const Upstream::ClusterInfo& cluster, Protocol protocol, - const RequestNames& request_names, bool success) override; - void chargeStat(const Upstream::ClusterInfo& cluster, const RequestNames& request_names, - bool success) override; - - /** - * Resolve the gRPC service and method from the HTTP2 :path header. - * @param path supplies the :path header. - * @param service supplies the output pointer of the gRPC service. - * @param method supplies the output pointer of the gRPC method. - * @return bool true if both gRPC serve and method have been resolved successfully. - */ - absl::optional resolveServiceAndMethod(const Http::HeaderEntry* path) override; - /** * Serialize protobuf message with gRPC frame header. */ @@ -143,11 +116,6 @@ class Common : public Context { */ static void prependGrpcFrameHeader(Buffer::Instance& buffer); - Stats::StatName successStatName(bool success) const { return success ? success_ : failure_; } - Stats::StatName protocolStatName(Protocol protocol) const { - return protocol == Context::Protocol::Grpc ? grpc_ : grpc_web_; - } - /** * Parse a Buffer::Instance into a Protobuf::Message. * @param buffer containing the data to be parsed. @@ -158,25 +126,6 @@ class Common : public Context { private: static void checkForHeaderOnlyError(Http::Message& http_response); - - // Makes a stat name from a string, if we don't already have one for it. - // This always takes a lock on mutex_, and if we haven't seen the name - // before, it also takes a lock on the symbol table. - // - // TODO(jmarantz): See https://github.com/envoyproxy/envoy/pull/7008 for - // a lock-free approach to creating dynamic stat-names based on requests. - Stats::StatName makeDynamicStatName(absl::string_view name); - - Stats::SymbolTable& symbol_table_; - mutable Thread::MutexBasicLockable mutex_; - Stats::StatNamePool stat_name_pool_ GUARDED_BY(mutex_); - StringMap stat_name_map_ GUARDED_BY(mutex_); - const Stats::StatName grpc_; - const Stats::StatName grpc_web_; - const Stats::StatName success_; - const Stats::StatName failure_; - const Stats::StatName total_; - const Stats::StatName zero_; }; } // namespace Grpc diff --git a/source/common/grpc/context_impl.cc b/source/common/grpc/context_impl.cc new file mode 100644 index 000000000000..94465cd3e10f --- /dev/null +++ b/source/common/grpc/context_impl.cc @@ -0,0 +1,89 @@ +#include "common/grpc/context_impl.h" + +#include +#include + +namespace Envoy { +namespace Grpc { + +ContextImpl::ContextImpl(Stats::SymbolTable& symbol_table) + : symbol_table_(symbol_table), stat_name_pool_(symbol_table), + grpc_(stat_name_pool_.add("grpc")), grpc_web_(stat_name_pool_.add("grpc-web")), + success_(stat_name_pool_.add("success")), failure_(stat_name_pool_.add("failure")), + total_(stat_name_pool_.add("total")), zero_(stat_name_pool_.add("0")) {} + +// Makes a stat name from a string, if we don't already have one for it. +// This always takes a lock on mutex_, and if we haven't seen the name +// before, it also takes a lock on the symbol table. +// +// TODO(jmarantz): See https://github.com/envoyproxy/envoy/pull/7008 for +// a lock-free approach to creating dynamic stat-names based on requests. +Stats::StatName ContextImpl::makeDynamicStatName(absl::string_view name) { + Thread::LockGuard lock(mutex_); + auto iter = stat_name_map_.find(name); + if (iter != stat_name_map_.end()) { + return iter->second; + } + const Stats::StatName stat_name = stat_name_pool_.add(name); + stat_name_map_[std::string(name)] = stat_name; + return stat_name; +} + +void ContextImpl::chargeStat(const Upstream::ClusterInfo& cluster, Protocol protocol, + const RequestNames& request_names, + const Http::HeaderEntry* grpc_status) { + if (!grpc_status) { + return; + } + + absl::string_view status_str = grpc_status->value().getStringView(); + const bool success = (status_str == "0"); + + // TODO(jmarantz): Perhaps the universe of likely grpc status codes is + // sufficiently bounded that we should precompute status StatNames for popular + // ones beyond "0". + const Stats::StatName status_stat_name = success ? zero_ : makeDynamicStatName(status_str); + const Stats::SymbolTable::StoragePtr stat_name_storage = + symbol_table_.join({protocolStatName(protocol), request_names.service_, request_names.method_, + status_stat_name}); + + cluster.statsScope().counterFromStatName(Stats::StatName(stat_name_storage.get())).inc(); + chargeStat(cluster, protocol, request_names, success); +} + +void ContextImpl::chargeStat(const Upstream::ClusterInfo& cluster, Protocol protocol, + const RequestNames& request_names, bool success) { + const Stats::SymbolTable::StoragePtr prefix_storage = symbol_table_.join( + {protocolStatName(protocol), request_names.service_, request_names.method_}); + const Stats::StatName prefix(prefix_storage.get()); + const Stats::SymbolTable::StoragePtr status = + symbol_table_.join({prefix, successStatName(success)}); + const Stats::SymbolTable::StoragePtr total = symbol_table_.join({prefix, total_}); + + cluster.statsScope().counterFromStatName(Stats::StatName(status.get())).inc(); + cluster.statsScope().counterFromStatName(Stats::StatName(total.get())).inc(); +} + +void ContextImpl::chargeStat(const Upstream::ClusterInfo& cluster, + const RequestNames& request_names, bool success) { + chargeStat(cluster, Protocol::Grpc, request_names, success); +} + +absl::optional +ContextImpl::resolveServiceAndMethod(const Http::HeaderEntry* path) { + absl::optional request_names; + if (path == nullptr) { + return request_names; + } + const auto parts = StringUtil::splitToken(path->value().getStringView(), "/"); + if (parts.size() != 2) { + return request_names; + } + const Stats::StatName service = makeDynamicStatName(parts[0]); + const Stats::StatName method = makeDynamicStatName(parts[1]); + request_names = RequestNames{service, method}; + return request_names; +} + +} // namespace Grpc +} // namespace Envoy diff --git a/source/common/grpc/context_impl.h b/source/common/grpc/context_impl.h new file mode 100644 index 000000000000..accf3d9c89fe --- /dev/null +++ b/source/common/grpc/context_impl.h @@ -0,0 +1,70 @@ +#pragma once + +#include +#include + +#include "envoy/grpc/context.h" +#include "envoy/http/header_map.h" + +#include "common/common/hash.h" +#include "common/stats/symbol_table_impl.h" + +#include "absl/types/optional.h" + +namespace Envoy { +namespace Grpc { + +struct Context::RequestNames { + Stats::StatName service_; // supplies the service name. + Stats::StatName method_; // supplies the method name. +}; + +class ContextImpl : public Context { +public: + explicit ContextImpl(Stats::SymbolTable& symbol_table); + + // Context + void chargeStat(const Upstream::ClusterInfo& cluster, Protocol protocol, + const RequestNames& request_names, const Http::HeaderEntry* grpc_status) override; + void chargeStat(const Upstream::ClusterInfo& cluster, Protocol protocol, + const RequestNames& request_names, bool success) override; + void chargeStat(const Upstream::ClusterInfo& cluster, const RequestNames& request_names, + bool success) override; + + /** + * Resolve the gRPC service and method from the HTTP2 :path header. + * @param path supplies the :path header. + * @param service supplies the output pointer of the gRPC service. + * @param method supplies the output pointer of the gRPC method. + * @return bool true if both gRPC serve and method have been resolved successfully. + */ + absl::optional resolveServiceAndMethod(const Http::HeaderEntry* path) override; + + Stats::StatName successStatName(bool success) const { return success ? success_ : failure_; } + Stats::StatName protocolStatName(Protocol protocol) const { + return protocol == Context::Protocol::Grpc ? grpc_ : grpc_web_; + } + +private: + // Makes a stat name from a string, if we don't already have one for it. + // This always takes a lock on mutex_, and if we haven't seen the name + // before, it also takes a lock on the symbol table. + // + // TODO(jmarantz): See https://github.com/envoyproxy/envoy/pull/7008 for + // a lock-free approach to creating dynamic stat-names based on requests. + Stats::StatName makeDynamicStatName(absl::string_view name); + + Stats::SymbolTable& symbol_table_; + mutable Thread::MutexBasicLockable mutex_; + Stats::StatNamePool stat_name_pool_ GUARDED_BY(mutex_); + StringMap stat_name_map_ GUARDED_BY(mutex_); + const Stats::StatName grpc_; + const Stats::StatName grpc_web_; + const Stats::StatName success_; + const Stats::StatName failure_; + const Stats::StatName total_; + const Stats::StatName zero_; +}; + +} // namespace Grpc +} // namespace Envoy diff --git a/source/common/http/conn_manager_config.h b/source/common/http/conn_manager_config.h index 66530c2754f3..80f89cb17f55 100644 --- a/source/common/http/conn_manager_config.h +++ b/source/common/http/conn_manager_config.h @@ -144,7 +144,7 @@ enum class ForwardClientCertType { * Configuration for the fields of the client cert, used for populating the current client cert * information to the next hop. */ -enum class ClientCertDetailsType { Cert, Subject, URI, DNS }; +enum class ClientCertDetailsType { Cert, Chain, Subject, URI, DNS }; /** * Configuration for what addresses should be considered internal beyond the defaults. diff --git a/source/common/http/conn_manager_impl.cc b/source/common/http/conn_manager_impl.cc index 6c7d5459c23a..0c5a221b7bf9 100644 --- a/source/common/http/conn_manager_impl.cc +++ b/source/common/http/conn_manager_impl.cc @@ -180,10 +180,12 @@ void ConnectionManagerImpl::doEndStream(ActiveStream& stream) { // explicitly nulls out response_encoder to avoid the downstream being notified of the // Envoy-internal stream instance being ended. if (stream.response_encoder_ != nullptr && - (!stream.state_.remote_complete_ || !stream.state_.local_complete_)) { + (!stream.state_.remote_complete_ || !stream.state_.codec_saw_local_complete_)) { // Indicate local is complete at this point so that if we reset during a continuation, we don't // raise further data or trailers. + ENVOY_STREAM_LOG(debug, "doEndStream() resetting stream", stream); stream.state_.local_complete_ = true; + stream.state_.codec_saw_local_complete_ = true; stream.response_encoder_->getStream().resetStream(StreamResetReason::LocalReset); reset_stream = true; } @@ -311,8 +313,17 @@ Network::FilterStatus ConnectionManagerImpl::onData(Buffer::Instance& data, bool void ConnectionManagerImpl::resetAllStreams() { while (!streams_.empty()) { - // Mimic a downstream reset in this case. - streams_.front()->onResetStream(StreamResetReason::ConnectionTermination, absl::string_view()); + // Mimic a downstream reset in this case. We must also remove callbacks here. Though we are + // about to close the connection and will disable further reads, it is possible that flushing + // data out can cause stream callbacks to fire (e.g., low watermark callbacks). + // + // TODO(mattklein123): I tried to actually reset through the codec here, but ran into issues + // with nghttp2 state and being unhappy about sending reset frames after the connection had + // been terminated via GOAWAY. It might be possible to do something better here inside the h2 + // codec but there are no easy answers and this seems simpler. + auto& stream = *streams_.front(); + stream.response_encoder_->getStream().removeCallbacks(stream); + stream.onResetStream(StreamResetReason::ConnectionTermination, absl::string_view()); } } @@ -1524,6 +1535,8 @@ void ConnectionManagerImpl::ActiveStream::encodeTrailers(ActiveStreamEncoderFilt void ConnectionManagerImpl::ActiveStream::maybeEndEncode(bool end_stream) { if (end_stream) { + ASSERT(!state_.codec_saw_local_complete_); + state_.codec_saw_local_complete_ = true; stream_info_.onLastDownstreamTxByteSent(); request_response_timespan_->complete(); connection_manager_.doEndStream(*this); @@ -1549,6 +1562,7 @@ void ConnectionManagerImpl::ActiveStream::onResetStream(StreamResetReason, absl: // 2) The codec TX a codec level reset // 3) The codec RX a reset // If we need to differentiate we need to do it inside the codec. Can start with this. + ENVOY_STREAM_LOG(debug, "stream reset", *this); connection_manager_.stats_.named_.downstream_rq_rx_reset_.inc(); connection_manager_.doDeferredStreamDestroy(*this); } diff --git a/source/common/http/conn_manager_impl.h b/source/common/http/conn_manager_impl.h index 02a718e81d8c..dc23f0810b8a 100644 --- a/source/common/http/conn_manager_impl.h +++ b/source/common/http/conn_manager_impl.h @@ -451,8 +451,8 @@ class ConnectionManagerImpl : Logger::Loggable, // All state for the stream. Put here for readability. struct State { State() - : remote_complete_(false), local_complete_(false), saw_connection_close_(false), - successful_upgrade_(false), created_filter_chain_(false), + : remote_complete_(false), local_complete_(false), codec_saw_local_complete_(false), + saw_connection_close_(false), successful_upgrade_(false), created_filter_chain_(false), is_internally_created_(false) {} uint32_t filter_call_state_{0}; @@ -463,7 +463,11 @@ class ConnectionManagerImpl : Logger::Loggable, bool decoder_filters_streaming_{true}; bool destroyed_{false}; bool remote_complete_ : 1; - bool local_complete_ : 1; + bool local_complete_ : 1; // This indicates that local is complete prior to filter processing. + // A filter can still stop the stream from being complete as seen + // by the codec. + bool codec_saw_local_complete_ : 1; // This indicates that local is complete as written all + // the way through to the codec. bool saw_connection_close_ : 1; bool successful_upgrade_ : 1; bool created_filter_chain_ : 1; diff --git a/source/common/http/conn_manager_utility.cc b/source/common/http/conn_manager_utility.cc index 5c8d31fa21be..e81fe4c74a6b 100644 --- a/source/common/http/conn_manager_utility.cc +++ b/source/common/http/conn_manager_utility.cc @@ -16,6 +16,7 @@ #include "common/runtime/uuid_util.h" #include "common/tracing/http_tracer_impl.h" +#include "absl/strings/str_cat.h" #include "absl/strings/str_join.h" namespace Envoy { @@ -294,38 +295,45 @@ void ConnectionManagerUtility::mutateXfccRequestHeader(HeaderMap& request_header config.forwardClientCert() == ForwardClientCertType::SanitizeSet) { const auto uri_sans_local_cert = connection.ssl()->uriSanLocalCertificate(); if (!uri_sans_local_cert.empty()) { - client_cert_details.push_back("By=" + uri_sans_local_cert[0]); + client_cert_details.push_back(absl::StrCat("By=", uri_sans_local_cert[0])); } const std::string cert_digest = connection.ssl()->sha256PeerCertificateDigest(); if (!cert_digest.empty()) { - client_cert_details.push_back("Hash=" + cert_digest); + client_cert_details.push_back(absl::StrCat("Hash=", cert_digest)); } for (const auto& detail : config.setCurrentClientCertDetails()) { switch (detail) { case ClientCertDetailsType::Cert: { const std::string peer_cert = connection.ssl()->urlEncodedPemEncodedPeerCertificate(); if (!peer_cert.empty()) { - client_cert_details.push_back("Cert=\"" + peer_cert + "\""); + client_cert_details.push_back(absl::StrCat("Cert=\"", peer_cert, "\"")); + } + break; + } + case ClientCertDetailsType::Chain: { + const std::string peer_chain = connection.ssl()->urlEncodedPemEncodedPeerCertificateChain(); + if (!peer_chain.empty()) { + client_cert_details.push_back(absl::StrCat("Chain=\"", peer_chain, "\"")); } break; } case ClientCertDetailsType::Subject: // The "Subject" key still exists even if the subject is empty. - client_cert_details.push_back("Subject=\"" + connection.ssl()->subjectPeerCertificate() + - "\""); + client_cert_details.push_back( + absl::StrCat("Subject=\"", connection.ssl()->subjectPeerCertificate(), "\"")); break; case ClientCertDetailsType::URI: { // The "URI" key still exists even if the URI is empty. const auto sans = connection.ssl()->uriSanPeerCertificate(); const auto& uri_san = sans.empty() ? "" : sans[0]; - client_cert_details.push_back("URI=" + uri_san); + client_cert_details.push_back(absl::StrCat("URI=", uri_san)); break; } case ClientCertDetailsType::DNS: { const std::vector dns_sans = connection.ssl()->dnsSansPeerCertificate(); if (!dns_sans.empty()) { for (const std::string& dns : dns_sans) { - client_cert_details.push_back("DNS=" + dns); + client_cert_details.push_back(absl::StrCat("DNS=", dns)); } } break; diff --git a/source/common/http/http2/codec_impl.cc b/source/common/http/http2/codec_impl.cc index 5fe699fc1a98..5f288926387e 100644 --- a/source/common/http/http2/codec_impl.cc +++ b/source/common/http/http2/codec_impl.cc @@ -511,6 +511,7 @@ int ConnectionImpl::onFrameSend(const nghttp2_frame* frame) { ENVOY_CONN_LOG(trace, "sent frame type={}", connection_, static_cast(frame->hd.type)); switch (frame->hd.type) { case NGHTTP2_GOAWAY: { + ENVOY_CONN_LOG(debug, "sent goaway code={}", connection_, frame->goaway.error_code); if (frame->goaway.error_code != NGHTTP2_NO_ERROR) { return NGHTTP2_ERR_CALLBACK_FAILURE; } diff --git a/source/common/router/rds_impl.cc b/source/common/router/rds_impl.cc index 5ea463ec37ce..0a291ae4727b 100644 --- a/source/common/router/rds_impl.cc +++ b/source/common/router/rds_impl.cc @@ -129,8 +129,7 @@ void RdsRouteConfigSubscription::onConfigUpdate( void RdsRouteConfigSubscription::onConfigUpdate( const Protobuf::RepeatedPtrField& added_resources, - const Protobuf::RepeatedPtrField& removed_resources, - const std::string& system_version_info) { + const Protobuf::RepeatedPtrField& removed_resources, const std::string&) { if (!removed_resources.empty()) { // TODO(#2500) when on-demand resource loading is supported, an RDS removal may make sense (see // discussion in #6879), and so we should do something other than ignoring here. @@ -139,13 +138,10 @@ void RdsRouteConfigSubscription::onConfigUpdate( "Server sent a delta RDS update attempting to remove a resource (name: {}). Ignoring.", removed_resources[0]); } - Protobuf::RepeatedPtrField unwrapped_resource; if (!added_resources.empty()) { + Protobuf::RepeatedPtrField unwrapped_resource; *unwrapped_resource.Add() = added_resources[0].resource(); onConfigUpdate(unwrapped_resource, added_resources[0].version()); - } else { - onConfigUpdate({}, system_version_info); - return; } } diff --git a/source/common/router/scoped_config_impl.cc b/source/common/router/scoped_config_impl.cc index 0274381ae850..e32887b7612f 100644 --- a/source/common/router/scoped_config_impl.cc +++ b/source/common/router/scoped_config_impl.cc @@ -3,6 +3,62 @@ namespace Envoy { namespace Router { +std::unique_ptr +HeaderValueExtractorImpl::computeFragment(const Http::HeaderMap& headers) const { + const Envoy::Http::HeaderEntry* header_entry = + headers.get(Envoy::Http::LowerCaseString(header_value_extractor_config_.name())); + if (header_entry == nullptr) { + return nullptr; + } + + std::vector elements{header_entry->value().getStringView()}; + if (header_value_extractor_config_.element_separator().length() > 0) { + elements = absl::StrSplit(header_entry->value().getStringView(), + header_value_extractor_config_.element_separator()); + } + switch (header_value_extractor_config_.extract_type_case()) { + case ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::HeaderValueExtractor::kElement: + for (const auto& element : elements) { + std::pair key_value = absl::StrSplit( + element, absl::MaxSplits(header_value_extractor_config_.element().separator(), 1)); + if (key_value.first == header_value_extractor_config_.element().key()) { + return std::make_unique(key_value.second); + } + } + break; + case ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::HeaderValueExtractor::kIndex: + if (header_value_extractor_config_.index() < elements.size()) { + return std::make_unique(elements[header_value_extractor_config_.index()]); + } + break; + default: // EXTRACT_TYPE_NOT_SET + NOT_REACHED_GCOVR_EXCL_LINE; // Caught in constructor already. + } + + return nullptr; +} + +ScopeKeyBuilderImpl::ScopeKeyBuilderImpl(ScopedRoutes::ScopeKeyBuilder config) + : ScopeKeyBuilderBase(config) { + for (const auto& fragment_builder : config_.fragments()) { + switch (fragment_builder.type_case()) { + case ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::kHeaderValueExtractor: + fragment_builders_.emplace_back(std::make_unique(fragment_builder)); + break; + default: + NOT_REACHED_GCOVR_EXCL_LINE; + } + } +} + +const ScopeKey ScopeKeyBuilderImpl::computeScopeKey(const Http::HeaderMap& headers) const { + ScopeKey key; + for (const auto& builder : fragment_builders_) { + key.addFragment(builder->computeFragment(headers)); + } + return key; +} + void ThreadLocalScopedConfigImpl::addOrUpdateRoutingScope(const ScopedRouteInfoConstSharedPtr&) {} void ThreadLocalScopedConfigImpl::removeRoutingScope(const std::string&) {} diff --git a/source/common/router/scoped_config_impl.h b/source/common/router/scoped_config_impl.h index 94d376b2a354..3153da37baff 100644 --- a/source/common/router/scoped_config_impl.h +++ b/source/common/router/scoped_config_impl.h @@ -1,17 +1,164 @@ #pragma once +#include + #include "envoy/api/v2/srds.pb.h" #include "envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.pb.h" #include "envoy/router/router.h" #include "envoy/router/scopes.h" #include "envoy/thread_local/thread_local.h" +#include "common/protobuf/utility.h" #include "common/router/config_impl.h" #include "common/router/scoped_config_manager.h" namespace Envoy { namespace Router { +using envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes; + +/** + * Scope key fragment base class. + */ +class ScopeKeyFragmentBase { +public: + bool operator==(const ScopeKeyFragmentBase& other) const { + if (typeid(*this) == typeid(other)) { + return equals(other); + } + return false; + } + virtual ~ScopeKeyFragmentBase() = default; + +private: + // Returns true if the two fragments equal else false. + virtual bool equals(const ScopeKeyFragmentBase&) const PURE; +}; + +class ScopeKey { +public: + ScopeKey() = default; + ScopeKey(ScopeKey&& other) = default; + void addFragment(std::unique_ptr&& part) { + contains_null_fragment_ = contains_null_fragment_ || (part == nullptr); + fragments_.emplace_back(std::move(part)); + } + + bool operator!=(const ScopeKey& other) const { return !(*this == other); } + + bool operator==(const ScopeKey& other) const { + if (this->fragments_.size() != other.fragments_.size()) { + return false; + } + if (this->fragments_.size() == 0 || other.fragments_.size() == 0) { + // An empty key equals to nothing, "NULL" != "NULL". + return false; + } + // A "NULL" fragment value equals to nothing. + if (this->contains_null_fragment_ || other.contains_null_fragment_) { + return false; + } + return std::equal(this->fragments_.begin(), this->fragments_.end(), other.fragments_.begin(), + [](const std::unique_ptr& left, + const std::unique_ptr& right) -> bool { + // Both should be non-NULL now. + return *left == *right; + }); + } + +private: + bool contains_null_fragment_{false}; + std::vector> fragments_; +}; + +// String fragment. +class StringKeyFragment : public ScopeKeyFragmentBase { +public: + explicit StringKeyFragment(absl::string_view value) : value_(value) {} + +private: + bool equals(const ScopeKeyFragmentBase& other) const override { + return value_ == static_cast(other).value_; + } + + std::string value_; +}; + +/** + * Base class for fragment builders. + */ +class FragmentBuilderBase { +public: + explicit FragmentBuilderBase(ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config) + : config_(std::move(config)) {} + virtual ~FragmentBuilderBase() = default; + + // Returns a fragment if the fragment rule applies, a nullptr indicates no fragment could be + // generated from the headers. + virtual std::unique_ptr + computeFragment(const Http::HeaderMap& headers) const PURE; + +protected: + const ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config_; +}; + +class HeaderValueExtractorImpl : public FragmentBuilderBase { +public: + explicit HeaderValueExtractorImpl(ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config) + : FragmentBuilderBase(config), + header_value_extractor_config_(config_.header_value_extractor()) { + ASSERT(config_.type_case() == + ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::kHeaderValueExtractor, + "header_value_extractor is not set."); + if (header_value_extractor_config_.extract_type_case() == + ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::HeaderValueExtractor::kIndex) { + if (header_value_extractor_config_.index() != 0 && + header_value_extractor_config_.element_separator().length() == 0) { + throw ProtoValidationException("when element separator is set to an empty string, index " + "should be set to 0 in HeaderValueExtractor.", + header_value_extractor_config_); + } + } + if (header_value_extractor_config_.extract_type_case() == + ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::HeaderValueExtractor:: + EXTRACT_TYPE_NOT_SET) { + throw ProtoValidationException("HeaderValueExtractor extract_type not set.", + header_value_extractor_config_); + } + } + + std::unique_ptr + computeFragment(const Http::HeaderMap& headers) const override; + +private: + const ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::HeaderValueExtractor& + header_value_extractor_config_; +}; + +/** + * Base class for ScopeKeyBuilder implementations. + */ +class ScopeKeyBuilderBase { +public: + explicit ScopeKeyBuilderBase(ScopedRoutes::ScopeKeyBuilder config) : config_(std::move(config)) {} + virtual ~ScopeKeyBuilderBase() = default; + + virtual const ScopeKey computeScopeKey(const Http::HeaderMap& headers) const PURE; + +protected: + ScopedRoutes::ScopeKeyBuilder config_; +}; + +class ScopeKeyBuilderImpl : public ScopeKeyBuilderBase { +public: + explicit ScopeKeyBuilderImpl(ScopedRoutes::ScopeKeyBuilder config); + + const ScopeKey computeScopeKey(const Http::HeaderMap& headers) const override; + +private: + std::vector> fragment_builders_; +}; + /** * TODO(AndresGuedez): implement scoped routing logic. * diff --git a/source/extensions/filters/http/grpc_http1_bridge/BUILD b/source/extensions/filters/http/grpc_http1_bridge/BUILD index c7ceb6cfd4b1..8f664f320c57 100644 --- a/source/extensions/filters/http/grpc_http1_bridge/BUILD +++ b/source/extensions/filters/http/grpc_http1_bridge/BUILD @@ -23,6 +23,7 @@ envoy_cc_library( "//source/common/common:enum_to_int", "//source/common/common:utility_lib", "//source/common/grpc:common_lib", + "//source/common/grpc:context_lib", "//source/common/http:headers_lib", "//source/common/http/http1:codec_lib", ], diff --git a/source/extensions/filters/http/grpc_http1_bridge/http1_bridge_filter.cc b/source/extensions/filters/http/grpc_http1_bridge/http1_bridge_filter.cc index c2929ff46a1a..5a9ffc9869d0 100644 --- a/source/extensions/filters/http/grpc_http1_bridge/http1_bridge_filter.cc +++ b/source/extensions/filters/http/grpc_http1_bridge/http1_bridge_filter.cc @@ -9,6 +9,7 @@ #include "common/common/enum_to_int.h" #include "common/common/utility.h" #include "common/grpc/common.h" +#include "common/grpc/context_impl.h" #include "common/http/headers.h" #include "common/http/http1/codec_impl.h" @@ -18,7 +19,7 @@ namespace HttpFilters { namespace GrpcHttp1Bridge { void Http1BridgeFilter::chargeStat(const Http::HeaderMap& headers) { - context_.chargeStat(*cluster_, Grpc::Common::Protocol::Grpc, *request_names_, + context_.chargeStat(*cluster_, Grpc::Context::Protocol::Grpc, *request_names_, headers.GrpcStatus()); } diff --git a/source/extensions/filters/http/grpc_http1_bridge/http1_bridge_filter.h b/source/extensions/filters/http/grpc_http1_bridge/http1_bridge_filter.h index 514e3a31d41a..2e697da9ddc0 100644 --- a/source/extensions/filters/http/grpc_http1_bridge/http1_bridge_filter.h +++ b/source/extensions/filters/http/grpc_http1_bridge/http1_bridge_filter.h @@ -3,7 +3,7 @@ #include "envoy/http/filter.h" #include "envoy/upstream/cluster_manager.h" -#include "common/grpc/common.h" +#include "common/grpc/context_impl.h" namespace Envoy { namespace Extensions { diff --git a/source/extensions/filters/http/grpc_web/BUILD b/source/extensions/filters/http/grpc_web/BUILD index 28d7317948e0..2304f5dc211f 100644 --- a/source/extensions/filters/http/grpc_web/BUILD +++ b/source/extensions/filters/http/grpc_web/BUILD @@ -22,8 +22,9 @@ envoy_cc_library( "//source/common/common:base64_lib", "//source/common/common:utility_lib", "//source/common/grpc:codec_lib", - "//source/common/grpc:common_lib", + "//source/common/grpc:context_lib", "//source/common/http:headers_lib", + "//source/common/http:utility_lib", ], ) diff --git a/source/extensions/filters/http/grpc_web/grpc_web_filter.cc b/source/extensions/filters/http/grpc_web/grpc_web_filter.cc index c54954e3e509..423baa890bca 100644 --- a/source/extensions/filters/http/grpc_web/grpc_web_filter.cc +++ b/source/extensions/filters/http/grpc_web/grpc_web_filter.cc @@ -6,7 +6,7 @@ #include "common/common/base64.h" #include "common/common/empty_string.h" #include "common/common/utility.h" -#include "common/grpc/common.h" +#include "common/grpc/context_impl.h" #include "common/http/headers.h" #include "common/http/utility.h" @@ -234,7 +234,7 @@ void GrpcWebFilter::setupStatTracking(const Http::HeaderMap& headers) { } void GrpcWebFilter::chargeStat(const Http::HeaderMap& headers) { - context_.chargeStat(*cluster_, Grpc::Common::Protocol::GrpcWeb, *request_names_, + context_.chargeStat(*cluster_, Grpc::Context::Protocol::GrpcWeb, *request_names_, headers.GrpcStatus()); } diff --git a/source/extensions/filters/http/grpc_web/grpc_web_filter.h b/source/extensions/filters/http/grpc_web/grpc_web_filter.h index f6a1e47ab574..79c1c562ae7e 100644 --- a/source/extensions/filters/http/grpc_web/grpc_web_filter.h +++ b/source/extensions/filters/http/grpc_web/grpc_web_filter.h @@ -8,7 +8,7 @@ #include "common/buffer/buffer_impl.h" #include "common/common/non_copyable.h" #include "common/grpc/codec.h" -#include "common/grpc/common.h" +#include "common/grpc/context_impl.h" namespace Envoy { namespace Extensions { diff --git a/source/extensions/filters/network/http_connection_manager/config.cc b/source/extensions/filters/network/http_connection_manager/config.cc index 7802508b3b44..002db490e4f1 100644 --- a/source/extensions/filters/network/http_connection_manager/config.cc +++ b/source/extensions/filters/network/http_connection_manager/config.cc @@ -220,6 +220,9 @@ HttpConnectionManagerConfig::HttpConnectionManagerConfig( if (set_current_client_cert_details.cert()) { set_current_client_cert_details_.push_back(Http::ClientCertDetailsType::Cert); } + if (set_current_client_cert_details.chain()) { + set_current_client_cert_details_.push_back(Http::ClientCertDetailsType::Chain); + } if (PROTOBUF_GET_WRAPPED_OR_DEFAULT(set_current_client_cert_details, subject, false)) { set_current_client_cert_details_.push_back(Http::ClientCertDetailsType::Subject); } diff --git a/source/extensions/quic_listeners/quiche/BUILD b/source/extensions/quic_listeners/quiche/BUILD index 17444da358f8..09c338fec0a5 100644 --- a/source/extensions/quic_listeners/quiche/BUILD +++ b/source/extensions/quic_listeners/quiche/BUILD @@ -8,11 +8,26 @@ load( envoy_package() -# Placeholder library to verify/illustrate depending on a QUICHE build target. -# TODO(mpwarres): remove once real build rules added here. envoy_cc_library( - name = "dummy_lib", - srcs = ["dummy.cc"], - hdrs = ["dummy.h"], - external_deps = ["quiche_http2_platform"], + name = "envoy_quic_alarm_lib", + srcs = ["envoy_quic_alarm.cc"], + hdrs = ["envoy_quic_alarm.h"], + external_deps = ["quiche_quic_platform"], + deps = [ + "//include/envoy/event:timer_interface", + "@com_googlesource_quiche//:quic_core_alarm_lib", + ], +) + +envoy_cc_library( + name = "envoy_quic_alarm_factory_lib", + srcs = ["envoy_quic_alarm_factory.cc"], + hdrs = ["envoy_quic_alarm_factory.h"], + external_deps = ["quiche_quic_platform"], + deps = [ + ":envoy_quic_alarm_lib", + "@com_googlesource_quiche//:quic_core_alarm_factory_lib", + "@com_googlesource_quiche//:quic_core_arena_scoped_ptr_lib", + "@com_googlesource_quiche//:quic_core_one_block_arena_lib", + ], ) diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_alarm.cc b/source/extensions/quic_listeners/quiche/envoy_quic_alarm.cc new file mode 100644 index 000000000000..695a525777ce --- /dev/null +++ b/source/extensions/quic_listeners/quiche/envoy_quic_alarm.cc @@ -0,0 +1,35 @@ +#include "extensions/quic_listeners/quiche/envoy_quic_alarm.h" + +namespace Envoy { +namespace Quic { + +EnvoyQuicAlarm::EnvoyQuicAlarm(Event::Scheduler& scheduler, quic::QuicClock& clock, + quic::QuicArenaScopedPtr delegate) + : QuicAlarm(std::move(delegate)), scheduler_(scheduler), + timer_(scheduler_.createTimer([this]() { Fire(); })), clock_(clock) {} + +void EnvoyQuicAlarm::CancelImpl() { timer_->disableTimer(); } + +void EnvoyQuicAlarm::SetImpl() { + // TODO(#7170) switch to use microseconds if it is supported. + timer_->enableTimer(std::chrono::milliseconds(getDurationBeforeDeadline().ToMilliseconds())); +} + +void EnvoyQuicAlarm::UpdateImpl() { + // Since Timer::enableTimer() overrides its deadline from previous calls, + // there is no need to disable the timer before enabling it again. + SetImpl(); +} + +quic::QuicTime::Delta EnvoyQuicAlarm::getDurationBeforeDeadline() { + quic::QuicTime::Delta duration(quic::QuicTime::Delta::Zero()); + quic::QuicTime now = clock_.ApproximateNow(); + quic::QuicTime tmp = deadline(); + if (tmp > now) { + duration = tmp - now; + } + return duration; +} + +} // namespace Quic +} // namespace Envoy diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_alarm.h b/source/extensions/quic_listeners/quiche/envoy_quic_alarm.h new file mode 100644 index 000000000000..e50b4afc05ce --- /dev/null +++ b/source/extensions/quic_listeners/quiche/envoy_quic_alarm.h @@ -0,0 +1,39 @@ +#pragma once + +#include "envoy/event/timer.h" + +#include "common/common/assert.h" + +#include "quiche/quic/core/quic_alarm.h" +#include "quiche/quic/core/quic_time.h" +#include "quiche/quic/platform/api/quic_clock.h" + +namespace Envoy { +namespace Quic { + +// Implements QUIC interface +// https://quiche.googlesource.com/quiche/+/refs/heads/master/quic/core/quic_alarm.h This class +// wraps an Event::Timer object and provide interface for QUIC to interact with the timer. +class EnvoyQuicAlarm : public quic::QuicAlarm { +public: + EnvoyQuicAlarm(Event::Scheduler& scheduler, quic::QuicClock& clock, + quic::QuicArenaScopedPtr delegate); + + ~EnvoyQuicAlarm() override { ASSERT(!IsSet()); }; + + // quic::QuicAlarm + void CancelImpl() override; + void SetImpl() override; + // Overridden to avoid cancel before set. + void UpdateImpl() override; + +private: + quic::QuicTime::Delta getDurationBeforeDeadline(); + + Event::Scheduler& scheduler_; + Event::TimerPtr timer_; + quic::QuicClock& clock_; +}; + +} // namespace Quic +} // namespace Envoy diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_alarm_factory.cc b/source/extensions/quic_listeners/quiche/envoy_quic_alarm_factory.cc new file mode 100644 index 000000000000..5595c9c308e9 --- /dev/null +++ b/source/extensions/quic_listeners/quiche/envoy_quic_alarm_factory.cc @@ -0,0 +1,22 @@ +#include "extensions/quic_listeners/quiche/envoy_quic_alarm_factory.h" + +namespace Envoy { +namespace Quic { + +quic::QuicAlarm* EnvoyQuicAlarmFactory::CreateAlarm(quic::QuicAlarm::Delegate* delegate) { + return new EnvoyQuicAlarm(scheduler_, clock_, + quic::QuicArenaScopedPtr(delegate)); +} + +quic::QuicArenaScopedPtr +EnvoyQuicAlarmFactory::CreateAlarm(quic::QuicArenaScopedPtr delegate, + quic::QuicConnectionArena* arena) { + if (arena != nullptr) { + return arena->New(scheduler_, clock_, std::move(delegate)); + } + return quic::QuicArenaScopedPtr( + new EnvoyQuicAlarm(scheduler_, clock_, std::move(delegate))); +} + +} // namespace Quic +} // namespace Envoy diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_alarm_factory.h b/source/extensions/quic_listeners/quiche/envoy_quic_alarm_factory.h new file mode 100644 index 000000000000..24f91efc4bc9 --- /dev/null +++ b/source/extensions/quic_listeners/quiche/envoy_quic_alarm_factory.h @@ -0,0 +1,39 @@ +#pragma once + +#include "common/common/non_copyable.h" + +#include "extensions/quic_listeners/quiche/envoy_quic_alarm.h" + +#pragma GCC diagnostic push + +// QUICHE allows unused parameters. +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include "quiche/quic/core/quic_alarm_factory.h" +#include "quiche/quic/core/quic_arena_scoped_ptr.h" +#include "quiche/quic/core/quic_one_block_arena.h" + +#pragma GCC diagnostic pop + +namespace Envoy { +namespace Quic { + +class EnvoyQuicAlarmFactory : public quic::QuicAlarmFactory, NonCopyable { +public: + EnvoyQuicAlarmFactory(Event::Scheduler& scheduler, quic::QuicClock& clock) + : scheduler_(scheduler), clock_(clock) {} + + ~EnvoyQuicAlarmFactory() override {} + + // QuicAlarmFactory + quic::QuicAlarm* CreateAlarm(quic::QuicAlarm::Delegate* delegate) override; + quic::QuicArenaScopedPtr + CreateAlarm(quic::QuicArenaScopedPtr delegate, + quic::QuicConnectionArena* arena) override; + +private: + Event::Scheduler& scheduler_; + quic::QuicClock& clock_; +}; + +} // namespace Quic +} // namespace Envoy diff --git a/source/extensions/quic_listeners/quiche/platform/BUILD b/source/extensions/quic_listeners/quiche/platform/BUILD index 158575b9f5ec..49108d806959 100644 --- a/source/extensions/quic_listeners/quiche/platform/BUILD +++ b/source/extensions/quic_listeners/quiche/platform/BUILD @@ -252,13 +252,6 @@ envoy_cc_library( ], ) -envoy_cc_library( - name = "quic_platform_sleep_impl_lib", - hdrs = ["quic_sleep_impl.h"], - visibility = ["//visibility:public"], - deps = ["@com_googlesource_quiche//:quic_core_time_lib"], -) - envoy_cc_library( name = "spdy_platform_impl_lib", hdrs = [ diff --git a/source/extensions/tracers/lightstep/BUILD b/source/extensions/tracers/lightstep/BUILD index 7b46ebd6e4c4..0f2805e8cd74 100644 --- a/source/extensions/tracers/lightstep/BUILD +++ b/source/extensions/tracers/lightstep/BUILD @@ -21,6 +21,8 @@ envoy_cc_library( external_deps = ["lightstep"], deps = [ "//source/common/config:utility_lib", + "//source/common/grpc:context_lib", + "//source/common/stats:symbol_table_lib", "//source/common/tracing:http_tracer_lib", "//source/extensions/tracers:well_known_names", "//source/extensions/tracers/common/ot:opentracing_driver_lib", diff --git a/source/extensions/tracers/lightstep/lightstep_tracer_impl.h b/source/extensions/tracers/lightstep/lightstep_tracer_impl.h index 224475f9de20..d6046ccd4e40 100644 --- a/source/extensions/tracers/lightstep/lightstep_tracer_impl.h +++ b/source/extensions/tracers/lightstep/lightstep_tracer_impl.h @@ -9,11 +9,12 @@ #include "envoy/tracing/http_tracer.h" #include "envoy/upstream/cluster_manager.h" -#include "common/grpc/common.h" +#include "common/grpc/context_impl.h" #include "common/http/header_map_impl.h" #include "common/http/message_impl.h" #include "common/json/json_loader.h" #include "common/protobuf/protobuf.h" +#include "common/stats/symbol_table_impl.h" #include "extensions/tracers/common/ot/opentracing_driver_impl.h" diff --git a/source/server/BUILD b/source/server/BUILD index f3676164ac8d..3a6770091f36 100644 --- a/source/server/BUILD +++ b/source/server/BUILD @@ -361,7 +361,7 @@ envoy_cc_library( "//source/common/common:version_lib", "//source/common/config:utility_lib", "//source/common/grpc:async_client_manager_lib", - "//source/common/grpc:common_lib", + "//source/common/grpc:context_lib", "//source/common/http:codes_lib", "//source/common/http:context_lib", "//source/common/init:manager_lib", diff --git a/source/server/config_validation/server.h b/source/server/config_validation/server.h index 65a0be91d74b..aab91280ac2c 100644 --- a/source/server/config_validation/server.h +++ b/source/server/config_validation/server.h @@ -192,7 +192,7 @@ class ValidationInstance : Logger::Loggable, std::unique_ptr listener_manager_; std::unique_ptr overload_manager_; MutexTracer* mutex_tracer_; - Grpc::Common grpc_context_; + Grpc::ContextImpl grpc_context_; Http::ContextImpl http_context_; Event::TimeSystem& time_system_; }; diff --git a/source/server/http/admin.cc b/source/server/http/admin.cc index cb3a22238d01..9ccba827322a 100644 --- a/source/server/http/admin.cc +++ b/source/server/http/admin.cc @@ -155,6 +155,13 @@ void populateFallbackResponseHeaders(Http::Code code, Http::HeaderMap& header_ma header_map.addReference(headers.XContentTypeOptions, headers.XContentTypeOptionValues.Nosniff); } +// Helper method to get filter parameter +absl::optional filterParam(Http::Utility::QueryParams params) { + return (params.find("filter") != params.end()) + ? absl::optional{std::regex(params.at("filter"))} + : absl::nullopt; +} + // Helper method that ensures that we've setting flags based on all the health flag values on the // host. void setHealthFlag(Upstream::Host::HealthFlag flag, const Upstream::Host& host, @@ -696,10 +703,7 @@ Http::Code AdminImpl::handlerStats(absl::string_view url, Http::HeaderMap& respo const bool used_only = params.find("usedonly") != params.end(); const bool has_format = !(params.find("format") == params.end()); - const absl::optional regex = - (params.find("filter") != params.end()) - ? absl::optional{std::regex(params.at("filter"))} - : absl::nullopt; + const absl::optional regex = filterParam(params); std::map all_stats; for (const Stats::CounterSharedPtr& counter : server_.stats().counters()) { @@ -753,8 +757,10 @@ Http::Code AdminImpl::handlerPrometheusStats(absl::string_view path_and_query, H Buffer::Instance& response, AdminStream&) { const Http::Utility::QueryParams params = Http::Utility::parseQueryString(path_and_query); const bool used_only = params.find("usedonly") != params.end(); + const absl::optional regex = filterParam(params); PrometheusStatsFormatter::statsAsPrometheus(server_.stats().counters(), server_.stats().gauges(), - server_.stats().histograms(), response, used_only); + server_.stats().histograms(), response, used_only, + regex); return Http::Code::OK; } @@ -788,10 +794,10 @@ uint64_t PrometheusStatsFormatter::statsAsPrometheus( const std::vector& counters, const std::vector& gauges, const std::vector& histograms, Buffer::Instance& response, - const bool used_only) { + const bool used_only, const absl::optional& regex) { std::unordered_set metric_type_tracker; for (const auto& counter : counters) { - if (!shouldShowMetric(counter, used_only)) { + if (!shouldShowMetric(counter, used_only, regex)) { continue; } @@ -805,7 +811,7 @@ uint64_t PrometheusStatsFormatter::statsAsPrometheus( } for (const auto& gauge : gauges) { - if (!shouldShowMetric(gauge, used_only)) { + if (!shouldShowMetric(gauge, used_only, regex)) { continue; } @@ -819,7 +825,7 @@ uint64_t PrometheusStatsFormatter::statsAsPrometheus( } for (const auto& histogram : histograms) { - if (!shouldShowMetric(histogram, used_only)) { + if (!shouldShowMetric(histogram, used_only, regex)) { continue; } diff --git a/source/server/http/admin.h b/source/server/http/admin.h index a0c2c8fccb2d..3bd4754a2aec 100644 --- a/source/server/http/admin.h +++ b/source/server/http/admin.h @@ -220,6 +220,7 @@ class AdminImpl : public Admin, bool used_only, const absl::optional regex = absl::nullopt, bool pretty_print = false); + static std::string runtimeAsJson(const std::vector>& entries); std::vector sortedHandlers() const; @@ -413,7 +414,8 @@ class PrometheusStatsFormatter { static uint64_t statsAsPrometheus(const std::vector& counters, const std::vector& gauges, const std::vector& histograms, - Buffer::Instance& response, const bool used_only); + Buffer::Instance& response, const bool used_only, + const absl::optional& regex); /** * Format the given tags, returning a string as a comma-separated list * of ="" pairs. @@ -434,8 +436,10 @@ class PrometheusStatsFormatter { * Determine whether a metric has never been emitted and choose to * not show it if we only wanted used metrics. */ - static bool shouldShowMetric(const std::shared_ptr& metric, const bool used_only) { - return !used_only || metric->used(); + static bool shouldShowMetric(const std::shared_ptr& metric, const bool used_only, + const absl::optional& regex) { + return ((!used_only || metric->used()) && + (!regex.has_value() || std::regex_search(metric->name(), regex.value()))); } }; diff --git a/source/server/server.h b/source/server/server.h index e9f7283311de..75eff17064c5 100644 --- a/source/server/server.h +++ b/source/server/server.h @@ -22,7 +22,7 @@ #include "common/common/cleanup.h" #include "common/common/logger_delegates.h" #include "common/grpc/async_client_manager_impl.h" -#include "common/grpc/common.h" +#include "common/grpc/context_impl.h" #include "common/http/context_impl.h" #include "common/init/manager_impl.h" #include "common/memory/heap_shrinker.h" @@ -270,7 +270,7 @@ class InstanceImpl : Logger::Loggable, Upstream::HdsDelegatePtr hds_delegate_; std::unique_ptr overload_manager_; Envoy::MutexTracer* mutex_tracer_; - Grpc::Common grpc_context_; + Grpc::ContextImpl grpc_context_; Http::ContextImpl http_context_; std::unique_ptr process_context_; std::unique_ptr heap_shrinker_; diff --git a/test/common/grpc/BUILD b/test/common/grpc/BUILD index 0a1ca7e3bc8b..ed8df64ca6ca 100644 --- a/test/common/grpc/BUILD +++ b/test/common/grpc/BUILD @@ -52,14 +52,24 @@ envoy_cc_test( deps = [ "//source/common/grpc:common_lib", "//source/common/http:headers_lib", - "//source/common/stats:fake_symbol_table_lib", "//test/mocks/upstream:upstream_mocks", "//test/proto:helloworld_proto_cc", - "//test/test_common:global_lib", "//test/test_common:utility_lib", ], ) +envoy_cc_test( + name = "context_impl_test", + srcs = ["context_impl_test.cc"], + deps = [ + "//source/common/grpc:common_lib", + "//source/common/http:headers_lib", + "//source/common/stats:fake_symbol_table_lib", + "//test/mocks/upstream:upstream_mocks", + "//test/test_common:global_lib", + ], +) + envoy_cc_test( name = "google_grpc_utils_test", srcs = envoy_select_google_grpc(["google_grpc_utils_test.cc"]), diff --git a/test/common/grpc/common_test.cc b/test/common/grpc/common_test.cc index 98b65423a99e..b2ab23f919ad 100644 --- a/test/common/grpc/common_test.cc +++ b/test/common/grpc/common_test.cc @@ -4,7 +4,6 @@ #include "common/http/headers.h" #include "common/http/message_impl.h" #include "common/http/utility.h" -#include "common/stats/fake_symbol_table_impl.h" #include "test/mocks/upstream/mocks.h" #include "test/proto/helloworld.pb.h" @@ -16,7 +15,7 @@ namespace Envoy { namespace Grpc { -TEST(GrpcCommonTest, GetGrpcStatus) { +TEST(GrpcContextTest, GetGrpcStatus) { Http::TestHeaderMapImpl ok_trailers{{"grpc-status", "0"}}; EXPECT_EQ(Status::Ok, Common::getGrpcStatus(ok_trailers).value()); @@ -33,7 +32,7 @@ TEST(GrpcCommonTest, GetGrpcStatus) { EXPECT_EQ(Status::InvalidCode, Common::getGrpcStatus(invalid_trailers).value()); } -TEST(GrpcCommonTest, GetGrpcMessage) { +TEST(GrpcContextTest, GetGrpcMessage) { Http::TestHeaderMapImpl empty_trailers; EXPECT_EQ("", Common::getGrpcMessage(empty_trailers)); @@ -44,7 +43,7 @@ TEST(GrpcCommonTest, GetGrpcMessage) { EXPECT_EQ("", Common::getGrpcMessage(empty_error_trailers)); } -TEST(GrpcCommonTest, GetGrpcTimeout) { +TEST(GrpcContextTest, GetGrpcTimeout) { Http::TestHeaderMapImpl empty_headers; EXPECT_EQ(std::chrono::milliseconds(0), Common::getGrpcTimeout(empty_headers)); @@ -79,7 +78,7 @@ TEST(GrpcCommonTest, GetGrpcTimeout) { // so we don't test for them. } -TEST(GrpcCommonTest, ToGrpcTimeout) { +TEST(GrpcContextTest, ToGrpcTimeout) { Http::HeaderString value; Common::toGrpcTimeout(std::chrono::milliseconds(0UL), value); @@ -104,43 +103,7 @@ TEST(GrpcCommonTest, ToGrpcTimeout) { EXPECT_EQ("99999999H", value.getStringView()); } -TEST(GrpcCommonTest, ChargeStats) { - NiceMock cluster; - Envoy::Test::Global symbol_table_; - Stats::StatNamePool pool(*symbol_table_); - const Stats::StatName service = pool.add("service"); - const Stats::StatName method = pool.add("method"); - Common::RequestNames request_names{service, method}; - Common common(*symbol_table_); - common.chargeStat(cluster, request_names, true); - EXPECT_EQ(1U, cluster.stats_store_.counter("grpc.service.method.success").value()); - EXPECT_EQ(0U, cluster.stats_store_.counter("grpc.service.method.failure").value()); - EXPECT_EQ(1U, cluster.stats_store_.counter("grpc.service.method.total").value()); - - common.chargeStat(cluster, request_names, false); - EXPECT_EQ(1U, cluster.stats_store_.counter("grpc.service.method.success").value()); - EXPECT_EQ(1U, cluster.stats_store_.counter("grpc.service.method.failure").value()); - EXPECT_EQ(2U, cluster.stats_store_.counter("grpc.service.method.total").value()); - - Http::TestHeaderMapImpl trailers; - Http::HeaderEntry& status = trailers.insertGrpcStatus(); - status.value("0", 1); - common.chargeStat(cluster, Context::Protocol::Grpc, request_names, &status); - EXPECT_EQ(1U, cluster.stats_store_.counter("grpc.service.method.0").value()); - EXPECT_EQ(2U, cluster.stats_store_.counter("grpc.service.method.success").value()); - EXPECT_EQ(1U, cluster.stats_store_.counter("grpc.service.method.failure").value()); - EXPECT_EQ(3U, cluster.stats_store_.counter("grpc.service.method.total").value()); - - status.value("1", 1); - common.chargeStat(cluster, Context::Protocol::Grpc, request_names, &status); - EXPECT_EQ(1U, cluster.stats_store_.counter("grpc.service.method.0").value()); - EXPECT_EQ(1U, cluster.stats_store_.counter("grpc.service.method.1").value()); - EXPECT_EQ(2U, cluster.stats_store_.counter("grpc.service.method.success").value()); - EXPECT_EQ(2U, cluster.stats_store_.counter("grpc.service.method.failure").value()); - EXPECT_EQ(4U, cluster.stats_store_.counter("grpc.service.method.total").value()); -} - -TEST(GrpcCommonTest, PrepareHeaders) { +TEST(GrpcContextTest, PrepareHeaders) { { Http::MessagePtr message = Common::prepareHeaders("cluster", "service_name", "method_name", absl::nullopt); @@ -213,31 +176,7 @@ TEST(GrpcCommonTest, PrepareHeaders) { } } -TEST(GrpcCommonTest, ResolveServiceAndMethod) { - std::string service; - std::string method; - Http::HeaderMapImpl headers; - Http::HeaderEntry& path = headers.insertPath(); - path.value(std::string("/service_name/method_name")); - Envoy::Test::Global symbol_table; - Common common(*symbol_table); - absl::optional request_names = common.resolveServiceAndMethod(&path); - EXPECT_TRUE(request_names); - EXPECT_EQ("service_name", symbol_table->toString(request_names->service_)); - EXPECT_EQ("method_name", symbol_table->toString(request_names->method_)); - path.value(std::string("")); - EXPECT_FALSE(common.resolveServiceAndMethod(&path)); - path.value(std::string("/")); - EXPECT_FALSE(common.resolveServiceAndMethod(&path)); - path.value(std::string("//")); - EXPECT_FALSE(common.resolveServiceAndMethod(&path)); - path.value(std::string("/service_name")); - EXPECT_FALSE(common.resolveServiceAndMethod(&path)); - path.value(std::string("/service_name/")); - EXPECT_FALSE(common.resolveServiceAndMethod(&path)); -} - -TEST(GrpcCommonTest, GrpcToHttpStatus) { +TEST(GrpcContextTest, GrpcToHttpStatus) { const std::vector> test_set = { {Status::GrpcStatus::Ok, 200}, {Status::GrpcStatus::Canceled, 499}, @@ -263,7 +202,7 @@ TEST(GrpcCommonTest, GrpcToHttpStatus) { } } -TEST(GrpcCommonTest, HttpToGrpcStatus) { +TEST(GrpcContextTest, HttpToGrpcStatus) { const std::vector> test_set = { {400, Status::GrpcStatus::Internal}, {401, Status::GrpcStatus::Unauthenticated}, {403, Status::GrpcStatus::PermissionDenied}, {404, Status::GrpcStatus::Unimplemented}, @@ -276,7 +215,7 @@ TEST(GrpcCommonTest, HttpToGrpcStatus) { } } -TEST(GrpcCommonTest, HasGrpcContentType) { +TEST(GrpcContextTest, HasGrpcContentType) { { Http::TestHeaderMapImpl headers{}; EXPECT_FALSE(Common::hasGrpcContentType(headers)); @@ -295,7 +234,7 @@ TEST(GrpcCommonTest, HasGrpcContentType) { EXPECT_FALSE(isGrpcContentType("application/grpc-web+foo")); } -TEST(GrpcCommonTest, IsGrpcResponseHeader) { +TEST(GrpcContextTest, IsGrpcResponseHeader) { Http::TestHeaderMapImpl grpc_status_only{{":status", "500"}, {"grpc-status", "14"}}; EXPECT_TRUE(Common::isGrpcResponseHeader(grpc_status_only, true)); EXPECT_FALSE(Common::isGrpcResponseHeader(grpc_status_only, false)); @@ -311,7 +250,7 @@ TEST(GrpcCommonTest, IsGrpcResponseHeader) { EXPECT_FALSE(Common::isGrpcResponseHeader(json_response_header, false)); } -TEST(GrpcCommonTest, ValidateResponse) { +TEST(GrpcContextTest, ValidateResponse) { { Http::ResponseMessageImpl response( Http::HeaderMapPtr{new Http::TestHeaderMapImpl{{":status", "200"}}}); @@ -363,7 +302,7 @@ TEST(GrpcCommonTest, ValidateResponse) { } // Ensure that the correct gPRC header is constructed for a Buffer::Instance. -TEST(GrpcCommonTest, PrependGrpcFrameHeader) { +TEST(GrpcContextTest, PrependGrpcFrameHeader) { auto buffer = std::make_unique(); buffer->add("test", 4); std::array expected_header; diff --git a/test/common/grpc/context_impl_test.cc b/test/common/grpc/context_impl_test.cc new file mode 100644 index 000000000000..ace45801ca11 --- /dev/null +++ b/test/common/grpc/context_impl_test.cc @@ -0,0 +1,80 @@ +#include + +#include "common/grpc/common.h" +#include "common/grpc/context_impl.h" +#include "common/http/headers.h" +#include "common/http/message_impl.h" +#include "common/http/utility.h" +#include "common/stats/fake_symbol_table_impl.h" + +#include "test/mocks/upstream/mocks.h" +#include "test/test_common/global.h" +#include "test/test_common/utility.h" + +#include "gtest/gtest.h" + +namespace Envoy { +namespace Grpc { + +TEST(GrpcContextTest, ChargeStats) { + NiceMock cluster; + Envoy::Test::Global symbol_table_; + Stats::StatNamePool pool(*symbol_table_); + const Stats::StatName service = pool.add("service"); + const Stats::StatName method = pool.add("method"); + Context::RequestNames request_names{service, method}; + ContextImpl context(*symbol_table_); + context.chargeStat(cluster, request_names, true); + EXPECT_EQ(1U, cluster.stats_store_.counter("grpc.service.method.success").value()); + EXPECT_EQ(0U, cluster.stats_store_.counter("grpc.service.method.failure").value()); + EXPECT_EQ(1U, cluster.stats_store_.counter("grpc.service.method.total").value()); + + context.chargeStat(cluster, request_names, false); + EXPECT_EQ(1U, cluster.stats_store_.counter("grpc.service.method.success").value()); + EXPECT_EQ(1U, cluster.stats_store_.counter("grpc.service.method.failure").value()); + EXPECT_EQ(2U, cluster.stats_store_.counter("grpc.service.method.total").value()); + + Http::TestHeaderMapImpl trailers; + Http::HeaderEntry& status = trailers.insertGrpcStatus(); + status.value("0", 1); + context.chargeStat(cluster, Context::Protocol::Grpc, request_names, &status); + EXPECT_EQ(1U, cluster.stats_store_.counter("grpc.service.method.0").value()); + EXPECT_EQ(2U, cluster.stats_store_.counter("grpc.service.method.success").value()); + EXPECT_EQ(1U, cluster.stats_store_.counter("grpc.service.method.failure").value()); + EXPECT_EQ(3U, cluster.stats_store_.counter("grpc.service.method.total").value()); + + status.value("1", 1); + context.chargeStat(cluster, Context::Protocol::Grpc, request_names, &status); + EXPECT_EQ(1U, cluster.stats_store_.counter("grpc.service.method.0").value()); + EXPECT_EQ(1U, cluster.stats_store_.counter("grpc.service.method.1").value()); + EXPECT_EQ(2U, cluster.stats_store_.counter("grpc.service.method.success").value()); + EXPECT_EQ(2U, cluster.stats_store_.counter("grpc.service.method.failure").value()); + EXPECT_EQ(4U, cluster.stats_store_.counter("grpc.service.method.total").value()); +} + +TEST(GrpcContextTest, ResolveServiceAndMethod) { + std::string service; + std::string method; + Http::HeaderMapImpl headers; + Http::HeaderEntry& path = headers.insertPath(); + path.value(std::string("/service_name/method_name")); + Envoy::Test::Global symbol_table; + ContextImpl context(*symbol_table); + absl::optional request_names = context.resolveServiceAndMethod(&path); + EXPECT_TRUE(request_names); + EXPECT_EQ("service_name", symbol_table->toString(request_names->service_)); + EXPECT_EQ("method_name", symbol_table->toString(request_names->method_)); + path.value(std::string("")); + EXPECT_FALSE(context.resolveServiceAndMethod(&path)); + path.value(std::string("/")); + EXPECT_FALSE(context.resolveServiceAndMethod(&path)); + path.value(std::string("//")); + EXPECT_FALSE(context.resolveServiceAndMethod(&path)); + path.value(std::string("/service_name")); + EXPECT_FALSE(context.resolveServiceAndMethod(&path)); + path.value(std::string("/service_name/")); + EXPECT_FALSE(context.resolveServiceAndMethod(&path)); +} + +} // namespace Grpc +} // namespace Envoy diff --git a/test/common/http/conn_manager_impl_test.cc b/test/common/http/conn_manager_impl_test.cc index 81a555eb2c90..9324add9ca30 100644 --- a/test/common/http/conn_manager_impl_test.cc +++ b/test/common/http/conn_manager_impl_test.cc @@ -2297,6 +2297,7 @@ TEST_F(HttpConnectionManagerImplTest, DownstreamProtocolError) { throw CodecProtocolException("protocol error"); })); + EXPECT_CALL(response_encoder_.stream_, removeCallbacks(_)); EXPECT_CALL(filter_factory_, createFilterChain(_)).Times(0); // A protocol exception should result in reset of the streams followed by a remote or local close @@ -3352,6 +3353,53 @@ TEST_F(HttpConnectionManagerImplTest, FilterHeadReply) { conn_manager_->onData(fake_input, false); } +// Verify that if an encoded stream has been ended, but gets stopped by a filter chain, we end +// up resetting the stream in the doEndStream() path (e.g., via filter reset due to timeout, etc.), +// we emit a reset to the codec. +TEST_F(HttpConnectionManagerImplTest, ResetWithStoppedFilter) { + InSequence s; + setup(false, ""); + + EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance& data) -> void { + StreamDecoder* decoder = &conn_manager_->newStream(response_encoder_); + HeaderMapPtr headers{ + new TestHeaderMapImpl{{":authority", "host"}, {":path", "/"}, {":method", "GET"}}}; + decoder->decodeHeaders(std::move(headers), true); + data.drain(4); + })); + + setupFilterChain(1, 1); + + EXPECT_CALL(*decoder_filters_[0], decodeHeaders(_, true)) + .WillOnce(InvokeWithoutArgs([&]() -> FilterHeadersStatus { + decoder_filters_[0]->callbacks_->sendLocalReply(Code::BadRequest, "Bad request", nullptr, + absl::nullopt, ""); + return FilterHeadersStatus::Continue; + })); + + EXPECT_CALL(*encoder_filters_[0], encodeHeaders(_, false)) + .WillOnce(Invoke([&](HeaderMap& headers, bool) -> FilterHeadersStatus { + EXPECT_EQ("11", headers.ContentLength()->value().getStringView()); + return FilterHeadersStatus::Continue; + })); + EXPECT_CALL(response_encoder_, encodeHeaders(_, false)); + EXPECT_CALL(*encoder_filters_[0], encodeData(_, true)) + .WillOnce(Invoke([&](Buffer::Instance&, bool) -> FilterDataStatus { + return FilterDataStatus::StopIterationAndBuffer; + })); + + EXPECT_CALL(*encoder_filters_[0], encodeComplete()); + EXPECT_CALL(*decoder_filters_[0], decodeComplete()); + + // Kick off the incoming data. + Buffer::OwnedImpl fake_input("1234"); + conn_manager_->onData(fake_input, false); + + EXPECT_CALL(response_encoder_.stream_, resetStream(_)); + expectOnDestroy(); + encoder_filters_[0]->callbacks_->resetStream(); +} + TEST_F(HttpConnectionManagerImplTest, FilterContinueAndEndStreamHeaders) { InSequence s; setup(false, ""); diff --git a/test/common/http/conn_manager_utility_test.cc b/test/common/http/conn_manager_utility_test.cc index f78bce8b01ee..fad349c3d9de 100644 --- a/test/common/http/conn_manager_utility_test.cc +++ b/test/common/http/conn_manager_utility_test.cc @@ -769,6 +769,9 @@ TEST_F(ConnectionManagerUtilityTest, MtlsSetForwardClientCert) { EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return(peer_uri_sans)); std::string expected_pem("%3D%3Dabc%0Ade%3D"); EXPECT_CALL(ssl, urlEncodedPemEncodedPeerCertificate()).WillOnce(ReturnRef(expected_pem)); + std::string expected_chain_pem(expected_pem + "%3D%3Dlmn%0Aop%3D"); + EXPECT_CALL(ssl, urlEncodedPemEncodedPeerCertificateChain()) + .WillOnce(ReturnRef(expected_chain_pem)); std::vector expected_dns = {"www.example.com"}; EXPECT_CALL(ssl, dnsSansPeerCertificate()).WillOnce(Return(expected_dns)); ON_CALL(connection_, ssl()).WillByDefault(Return(&ssl)); @@ -777,6 +780,7 @@ TEST_F(ConnectionManagerUtilityTest, MtlsSetForwardClientCert) { std::vector details = std::vector(); details.push_back(Http::ClientCertDetailsType::URI); details.push_back(Http::ClientCertDetailsType::Cert); + details.push_back(Http::ClientCertDetailsType::Chain); details.push_back(Http::ClientCertDetailsType::DNS); ON_CALL(config_, setCurrentClientCertDetails()).WillByDefault(ReturnRef(details)); TestHeaderMapImpl headers; @@ -788,6 +792,7 @@ TEST_F(ConnectionManagerUtilityTest, MtlsSetForwardClientCert) { "Hash=abcdefg;" "URI=test://foo.com/fe;" "Cert=\"%3D%3Dabc%0Ade%3D\";" + "Chain=\"%3D%3Dabc%0Ade%3D%3D%3Dlmn%0Aop%3D\";" "DNS=www.example.com", headers.get_("x-forwarded-client-cert")); } @@ -807,6 +812,9 @@ TEST_F(ConnectionManagerUtilityTest, MtlsAppendForwardClientCert) { EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return(peer_uri_sans)); std::string expected_pem("%3D%3Dabc%0Ade%3D"); EXPECT_CALL(ssl, urlEncodedPemEncodedPeerCertificate()).WillOnce(ReturnRef(expected_pem)); + std::string expected_chain_pem(expected_pem + "%3D%3Dlmn%0Aop%3D"); + EXPECT_CALL(ssl, urlEncodedPemEncodedPeerCertificateChain()) + .WillOnce(ReturnRef(expected_chain_pem)); std::vector expected_dns = {"www.example.com"}; EXPECT_CALL(ssl, dnsSansPeerCertificate()).WillOnce(Return(expected_dns)); ON_CALL(connection_, ssl()).WillByDefault(Return(&ssl)); @@ -815,6 +823,7 @@ TEST_F(ConnectionManagerUtilityTest, MtlsAppendForwardClientCert) { std::vector details = std::vector(); details.push_back(Http::ClientCertDetailsType::URI); details.push_back(Http::ClientCertDetailsType::Cert); + details.push_back(Http::ClientCertDetailsType::Chain); details.push_back(Http::ClientCertDetailsType::DNS); ON_CALL(config_, setCurrentClientCertDetails()).WillByDefault(ReturnRef(details)); TestHeaderMapImpl headers{{"x-forwarded-client-cert", "By=test://foo.com/fe;" @@ -824,10 +833,11 @@ TEST_F(ConnectionManagerUtilityTest, MtlsAppendForwardClientCert) { EXPECT_EQ((MutateRequestRet{"10.0.0.3:50000", false}), callMutateRequestHeaders(headers, Protocol::Http2)); EXPECT_TRUE(headers.has("x-forwarded-client-cert")); - EXPECT_EQ("By=test://foo.com/fe;URI=test://bar.com/be;DNS=test.com;DNS=test.com," - "By=test://foo.com/be;Hash=abcdefg;URI=test://foo.com/fe;" - "Cert=\"%3D%3Dabc%0Ade%3D\";DNS=www.example.com", - headers.get_("x-forwarded-client-cert")); + EXPECT_EQ( + "By=test://foo.com/fe;URI=test://bar.com/be;DNS=test.com;DNS=test.com," + "By=test://foo.com/be;Hash=abcdefg;URI=test://foo.com/fe;" + "Cert=\"%3D%3Dabc%0Ade%3D\";Chain=\"%3D%3Dabc%0Ade%3D%3D%3Dlmn%0Aop%3D\";DNS=www.example.com", + headers.get_("x-forwarded-client-cert")); } // This test assumes the following scenario: @@ -876,6 +886,9 @@ TEST_F(ConnectionManagerUtilityTest, MtlsSanitizeSetClientCert) { EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return(peer_uri_sans)); std::string expected_pem("abcde="); EXPECT_CALL(ssl, urlEncodedPemEncodedPeerCertificate()).WillOnce(ReturnRef(expected_pem)); + std::string expected_chain_pem(expected_pem + "lmnop="); + EXPECT_CALL(ssl, urlEncodedPemEncodedPeerCertificateChain()) + .WillOnce(ReturnRef(expected_chain_pem)); ON_CALL(connection_, ssl()).WillByDefault(Return(&ssl)); ON_CALL(config_, forwardClientCert()) .WillByDefault(Return(Http::ForwardClientCertType::SanitizeSet)); @@ -883,6 +896,7 @@ TEST_F(ConnectionManagerUtilityTest, MtlsSanitizeSetClientCert) { details.push_back(Http::ClientCertDetailsType::Subject); details.push_back(Http::ClientCertDetailsType::URI); details.push_back(Http::ClientCertDetailsType::Cert); + details.push_back(Http::ClientCertDetailsType::Chain); ON_CALL(config_, setCurrentClientCertDetails()).WillByDefault(ReturnRef(details)); TestHeaderMapImpl headers{ {"x-forwarded-client-cert", "By=test://foo.com/fe;URI=test://bar.com/be"}}; @@ -892,7 +906,7 @@ TEST_F(ConnectionManagerUtilityTest, MtlsSanitizeSetClientCert) { EXPECT_TRUE(headers.has("x-forwarded-client-cert")); EXPECT_EQ("By=test://foo.com/be;Hash=abcdefg;Subject=\"/C=US/ST=CA/L=San " "Francisco/OU=Lyft/CN=test.lyft.com\";URI=test://foo.com/" - "fe;Cert=\"abcde=\"", + "fe;Cert=\"abcde=\";Chain=\"abcde=lmnop=\"", headers.get_("x-forwarded-client-cert")); } diff --git a/test/common/router/BUILD b/test/common/router/BUILD index 9e5a061f7370..c6dd8f9ae6d5 100644 --- a/test/common/router/BUILD +++ b/test/common/router/BUILD @@ -78,6 +78,18 @@ envoy_cc_test( ], ) +envoy_cc_test( + name = "scoped_config_impl_test", + srcs = ["scoped_config_impl_test.cc"], + external_deps = [ + "abseil_strings", + ], + deps = [ + "//source/common/router:scoped_config_lib", + "//test/test_common:utility_lib", + ], +) + envoy_cc_test( name = "scoped_rds_test", srcs = ["scoped_rds_test.cc"], @@ -173,7 +185,15 @@ envoy_directory_genrule( filegroup( name = "route_corpus", testonly = 1, - srcs = [":corpus_from_config_impl"] + glob(["route_corpus/**"]), + srcs = select({ + # TODO(asraa): Clean this up for cross-compilation. Right now we assume + # the host and target are the same on x86 builds, so we only execute the + # corpus generation binary on x86 platforms. + "//bazel:x86": [":corpus_from_config_impl"], + "//conditions:default": [], + }) + glob([ + "route_corpus/**", + ]), ) envoy_cc_fuzz_test( diff --git a/test/common/router/route_corpus/clusterfuzz-testcase-minimized-route_fuzz_test-5077190058704896 b/test/common/router/route_corpus/clusterfuzz-testcase-minimized-route_fuzz_test-5077190058704896 new file mode 100644 index 000000000000..06cb05362396 --- /dev/null +++ b/test/common/router/route_corpus/clusterfuzz-testcase-minimized-route_fuzz_test-5077190058704896 @@ -0,0 +1 @@ +config { internal_only_headers: "\0 " } \ No newline at end of file diff --git a/test/common/router/route_fuzz_test.cc b/test/common/router/route_fuzz_test.cc index f12de7a7837e..206bcd876575 100644 --- a/test/common/router/route_fuzz_test.cc +++ b/test/common/router/route_fuzz_test.cc @@ -11,13 +11,30 @@ namespace Envoy { namespace Router { namespace { +// Return a new RouteConfiguration with invalid characters replaces in all header fields. +envoy::api::v2::RouteConfiguration +replaceInvalidHeaders(envoy::api::v2::RouteConfiguration route_config) { + envoy::api::v2::RouteConfiguration clean_config = route_config; + clean_config.mutable_request_headers_to_add()->CopyFrom( + Fuzz::replaceInvalidHeaders(route_config.request_headers_to_add())); + clean_config.mutable_response_headers_to_add()->CopyFrom( + Fuzz::replaceInvalidHeaders(route_config.response_headers_to_add())); + auto internal_only_headers = clean_config.mutable_internal_only_headers(); + std::for_each(internal_only_headers->begin(), internal_only_headers->end(), + [](std::string& n) { n = Fuzz::replaceInvalidCharacters(n); }); + auto request_headers_to_remove = clean_config.mutable_request_headers_to_remove(); + std::for_each(request_headers_to_remove->begin(), request_headers_to_remove->end(), + [](std::string& n) { n = Fuzz::replaceInvalidCharacters(n); }); + return clean_config; +} + // TODO(htuch): figure out how to generate via a genrule from config_impl_test the full corpus. DEFINE_PROTO_FUZZER(const test::common::router::RouteTestCase& input) { try { NiceMock stream_info; NiceMock factory_context; MessageUtil::validate(input.config()); - ConfigImpl config(input.config(), factory_context, true); + ConfigImpl config(replaceInvalidHeaders(input.config()), factory_context, true); Http::TestHeaderMapImpl headers = Fuzz::fromHeaders(input.headers()); // It's a precondition of routing that {:authority, :path, x-forwarded-proto} headers exists, // HCM enforces this. diff --git a/test/common/router/scoped_config_impl_test.cc b/test/common/router/scoped_config_impl_test.cc new file mode 100644 index 000000000000..98d32562e2e1 --- /dev/null +++ b/test/common/router/scoped_config_impl_test.cc @@ -0,0 +1,252 @@ +#include + +#include "common/router/scoped_config_impl.h" + +#include "test/test_common/utility.h" + +#include "gtest/gtest.h" + +namespace Envoy { +namespace Router { +namespace { + +using ::Envoy::Http::TestHeaderMapImpl; + +class FooFragment : public ScopeKeyFragmentBase { +private: + virtual bool equals(const ScopeKeyFragmentBase&) const { return true; }; +}; + +TEST(ScopeKeyFragmentBaseTest, EqualSign) { + FooFragment foo; + StringKeyFragment bar("a random string"); + + EXPECT_FALSE(foo == bar); +} + +TEST(StringKeyFragmentTest, Empty) { + StringKeyFragment a(""); + StringKeyFragment b(""); + EXPECT_EQ(a, b); + + StringKeyFragment non_empty("ABC"); + + EXPECT_FALSE(a == non_empty); +} + +TEST(StringKeyFragmentTest, Normal) { + StringKeyFragment str("Abc"); + + StringKeyFragment same_str("Abc"); + EXPECT_EQ(str, same_str); + + StringKeyFragment upper_cased_str("ABC"); + EXPECT_FALSE(str == upper_cased_str); + + StringKeyFragment another_str("DEF"); + EXPECT_FALSE(str == another_str); +} + +TEST(HeaderValueExtractorImplTest, InvalidConfig) { + ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config; + // Type not set. + EXPECT_DEATH(HeaderValueExtractorImpl{config}, "header_value_extractor is not set."); + + // Index non-zero when element separator is an empty string. + std::string yaml_plain = R"EOF( + header_value_extractor: + name: 'foo_header' + element_separator: '' + index: 1 +)EOF"; + TestUtility::loadFromYaml(yaml_plain, config); + + EXPECT_THROW_WITH_REGEX(HeaderValueExtractorImpl{config}, ProtoValidationException, + "when element separator is set to an empty string, index should be set " + "to 0 in HeaderValueExtractor.+"); + // extract_type not set. + yaml_plain = R"EOF( + header_value_extractor: + name: 'foo_header' + element_separator: '' +)EOF"; + TestUtility::loadFromYaml(yaml_plain, config); + + EXPECT_THROW_WITH_REGEX(HeaderValueExtractorImpl{config}, ProtoValidationException, + "HeaderValueExtractor extract_type not set.+"); +} + +TEST(HeaderValueExtractorImplTest, HeaderExtractionByIndex) { + ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config; + std::string yaml_plain = R"EOF( + header_value_extractor: + name: 'foo_header' + element_separator: ',' + index: 1 +)EOF"; + + TestUtility::loadFromYaml(yaml_plain, config); + HeaderValueExtractorImpl extractor(config); + std::unique_ptr fragment = + extractor.computeFragment(TestHeaderMapImpl{{"foo_header", "part-0,part-1:value_bluh"}}); + + EXPECT_NE(fragment, nullptr); + EXPECT_EQ(*fragment, StringKeyFragment{"part-1:value_bluh"}); + + // No such header. + fragment = extractor.computeFragment(TestHeaderMapImpl{{"bar_header", "part-0"}}); + EXPECT_EQ(fragment, nullptr); + + // Empty header value. + fragment = extractor.computeFragment(TestHeaderMapImpl{ + {"foo_header", ""}, + }); + EXPECT_EQ(fragment, nullptr); + + // Index out of bound. + fragment = extractor.computeFragment(TestHeaderMapImpl{ + {"foo_header", "part-0"}, + }); + EXPECT_EQ(fragment, nullptr); + + // Element is empty. + fragment = extractor.computeFragment(TestHeaderMapImpl{ + {"foo_header", "part-0,,,bluh"}, + }); + EXPECT_NE(fragment, nullptr); + EXPECT_EQ(*fragment, StringKeyFragment("")); +} + +TEST(HeaderValueExtractorImplTest, HeaderExtractionByKey) { + ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config; + std::string yaml_plain = R"EOF( + header_value_extractor: + name: 'foo_header' + element_separator: ';' + element: + key: 'bar' + separator: '=>' +)EOF"; + + TestUtility::loadFromYaml(yaml_plain, config); + HeaderValueExtractorImpl extractor(config); + std::unique_ptr fragment = extractor.computeFragment(TestHeaderMapImpl{ + {"foo_header", "part-0;bar=>bluh;foo=>foo_value"}, + }); + + EXPECT_NE(fragment, nullptr); + EXPECT_EQ(*fragment, StringKeyFragment{"bluh"}); + + // No such header. + fragment = extractor.computeFragment(TestHeaderMapImpl{ + {"bluh", "part-0;"}, + }); + EXPECT_EQ(fragment, nullptr); + + // Empty header value. + fragment = extractor.computeFragment(TestHeaderMapImpl{ + {"foo_header", ""}, + }); + EXPECT_EQ(fragment, nullptr); + + // No such key. + fragment = extractor.computeFragment(TestHeaderMapImpl{ + {"foo_header", "part-0"}, + }); + EXPECT_EQ(fragment, nullptr); + + // Empty value. + fragment = extractor.computeFragment(TestHeaderMapImpl{ + {"foo_header", "bluh;;bar=>;foo=>last_value"}, + }); + EXPECT_NE(fragment, nullptr); + EXPECT_EQ(*fragment, StringKeyFragment{""}); + + // Duplicate values, the first value returned. + fragment = extractor.computeFragment(TestHeaderMapImpl{ + {"foo_header", "bluh;;bar=>value1;bar=>value2;bluh;;bar=>last_value"}, + }); + EXPECT_NE(fragment, nullptr); + EXPECT_EQ(*fragment, StringKeyFragment{"value1"}); + + // No separator in the element, value is set to empty string. + fragment = extractor.computeFragment(TestHeaderMapImpl{ + {"foo_header", "bluh;;bar;bar=>value2;bluh;;bar=>last_value"}, + }); + EXPECT_NE(fragment, nullptr); + EXPECT_EQ(*fragment, StringKeyFragment{""}); +} + +TEST(HeaderValueExtractorImplTest, ElementSeparatorEmpty) { + ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config; + std::string yaml_plain = R"EOF( + header_value_extractor: + name: 'foo_header' + element_separator: '' + element: + key: 'bar' + separator: '=' +)EOF"; + + TestUtility::loadFromYaml(yaml_plain, config); + HeaderValueExtractorImpl extractor(config); + std::unique_ptr fragment = extractor.computeFragment(TestHeaderMapImpl{ + {"foo_header", "bar=b;c=d;e=f"}, + }); + EXPECT_NE(fragment, nullptr); + EXPECT_EQ(*fragment, StringKeyFragment{"b;c=d;e=f"}); + + fragment = extractor.computeFragment(TestHeaderMapImpl{ + {"foo_header", "a=b;bar=d;e=f"}, + }); + EXPECT_EQ(fragment, nullptr); +} + +// Helper function which makes a ScopeKey from a list of strings. +ScopeKey makeKey(const std::vector& parts) { + ScopeKey key; + for (const auto& part : parts) { + if (part != nullptr) { + key.addFragment(std::make_unique(part)); + } else { + key.addFragment(nullptr); + } + } + return key; +} + +TEST(ScopeKeyTest, Unmatches) { + ScopeKey key1; + ScopeKey key2; + // Empty key != empty key. + EXPECT_NE(key1, key2); + + // Empty key != non-empty key. + EXPECT_NE(key1, makeKey({""})); + + EXPECT_EQ(makeKey({"a", "b", "c"}), makeKey({"a", "b", "c"})); + + // A null part matches nothing. + EXPECT_NE(makeKey({"a", "b", "c"}), makeKey({"a", "b", nullptr})); + + // A null part doesn't match "". + EXPECT_NE(makeKey({"a", "b", ""}), makeKey({"a", "b", nullptr})); + + // Two keys of different length won't match. + EXPECT_NE(makeKey({"a", "b"}), makeKey({"a", "b", "c"})); + // Case sensitive. + EXPECT_NE(makeKey({"a", "b"}), makeKey({"A", "b"})); +} + +TEST(ScopeKeyTest, Matches) { + // An empty string fragment equals another. + EXPECT_EQ(makeKey({"", ""}), makeKey({"", ""})); + EXPECT_EQ(makeKey({"a", "", ""}), makeKey({"a", "", ""})); + + // Non empty fragments comparision. + EXPECT_EQ(makeKey({"A", "b"}), makeKey({"A", "b"})); +} + +} // namespace +} // namespace Router +} // namespace Envoy diff --git a/test/config_test/config_test.cc b/test/config_test/config_test.cc index 515fd8bec51c..b552cb9ec31b 100644 --- a/test/config_test/config_test.cc +++ b/test/config_test/config_test.cc @@ -6,6 +6,7 @@ #include "common/common/fmt.h" #include "common/protobuf/utility.h" +#include "common/runtime/runtime_features.h" #include "server/config_validation/server.h" #include "server/configuration_impl.h" @@ -39,6 +40,15 @@ OptionsImpl asConfigYaml(const OptionsImpl& src, Api::Api& api) { src.localAddressIpVersion()); } +class ScopedRuntimeInjector { +public: + ScopedRuntimeInjector(Runtime::Loader& runtime) { + Runtime::LoaderSingleton::initialize(&runtime); + } + + ~ScopedRuntimeInjector() { Runtime::LoaderSingleton::clear(); } +}; + } // namespace class ConfigTest { @@ -56,6 +66,20 @@ class ConfigTest { return api_->fileSystem().fileReadToEnd(file); })); + // Here we setup runtime to mimic the actual deprecated feature list used in the + // production code. Note that this test is actually more strict than production because + // in production runtime is not setup until after the bootstrap config is loaded. This seems + // better for configuration tests. + ScopedRuntimeInjector scoped_runtime(server_.runtime()); + ON_CALL(server_.runtime_loader_.snapshot_, deprecatedFeatureEnabled(_)) + .WillByDefault(Invoke([](const std::string& key) { + if (Runtime::RuntimeFeaturesDefaults::get().disallowedByDefault(key)) { + return false; + } else { + return true; + } + })); + envoy::config::bootstrap::v2::Bootstrap bootstrap; Server::InstanceUtil::loadBootstrapConfig(bootstrap, options_, server_.messageValidationVisitor(), *api_); diff --git a/test/extensions/filters/http/grpc_http1_bridge/http1_bridge_filter_test.cc b/test/extensions/filters/http/grpc_http1_bridge/http1_bridge_filter_test.cc index ee9c679cecca..d7c40ab86991 100644 --- a/test/extensions/filters/http/grpc_http1_bridge/http1_bridge_filter_test.cc +++ b/test/extensions/filters/http/grpc_http1_bridge/http1_bridge_filter_test.cc @@ -28,16 +28,16 @@ namespace { class GrpcHttp1BridgeFilterTest : public testing::Test { public: - GrpcHttp1BridgeFilterTest() : common_(*symbol_table_), filter_(common_) { + GrpcHttp1BridgeFilterTest() : context_(*symbol_table_), filter_(context_) { filter_.setDecoderFilterCallbacks(decoder_callbacks_); filter_.setEncoderFilterCallbacks(encoder_callbacks_); ON_CALL(decoder_callbacks_.stream_info_, protocol()).WillByDefault(ReturnPointee(&protocol_)); } - ~GrpcHttp1BridgeFilterTest() { filter_.onDestroy(); } + ~GrpcHttp1BridgeFilterTest() override { filter_.onDestroy(); } Envoy::Test::Global symbol_table_; - Grpc::Common common_; + Grpc::ContextImpl context_; Http1BridgeFilter filter_; NiceMock decoder_callbacks_; NiceMock encoder_callbacks_; diff --git a/test/extensions/filters/http/grpc_web/grpc_web_filter_test.cc b/test/extensions/filters/http/grpc_web/grpc_web_filter_test.cc index aa9915db1595..1500708fe3c6 100644 --- a/test/extensions/filters/http/grpc_web/grpc_web_filter_test.cc +++ b/test/extensions/filters/http/grpc_web/grpc_web_filter_test.cc @@ -107,7 +107,7 @@ class GrpcWebFilterTest : public testing::TestWithParam symbol_table_; - Grpc::Common grpc_context_; + Grpc::ContextImpl grpc_context_; GrpcWebFilter filter_; NiceMock decoder_callbacks_; NiceMock encoder_callbacks_; diff --git a/test/extensions/quic_listeners/quiche/BUILD b/test/extensions/quic_listeners/quiche/BUILD index 3195a9bff53a..ce334636c88e 100644 --- a/test/extensions/quic_listeners/quiche/BUILD +++ b/test/extensions/quic_listeners/quiche/BUILD @@ -13,11 +13,13 @@ load( envoy_package() envoy_cc_test( - name = "dummy_test", - srcs = ["dummy_test.cc"], - external_deps = ["quiche_http2_platform"], + name = "envoy_quic_alarm_test", + srcs = ["envoy_quic_alarm_test.cc"], + external_deps = ["quiche_quic_platform"], deps = [ - "//source/extensions/quic_listeners/quiche:dummy_lib", - "//test/test_common:utility_lib", + "//source/extensions/quic_listeners/quiche:envoy_quic_alarm_factory_lib", + "//source/extensions/quic_listeners/quiche:envoy_quic_alarm_lib", + "//source/extensions/quic_listeners/quiche/platform:envoy_quic_clock_lib", + "//test/test_common:simulated_time_system_lib", ], ) diff --git a/test/extensions/quic_listeners/quiche/envoy_quic_alarm_test.cc b/test/extensions/quic_listeners/quiche/envoy_quic_alarm_test.cc new file mode 100644 index 000000000000..6dc18d378150 --- /dev/null +++ b/test/extensions/quic_listeners/quiche/envoy_quic_alarm_test.cc @@ -0,0 +1,194 @@ +#include "common/event/libevent_scheduler.h" + +#include "extensions/quic_listeners/quiche/envoy_quic_alarm.h" +#include "extensions/quic_listeners/quiche/envoy_quic_alarm_factory.h" +#include "extensions/quic_listeners/quiche/platform/envoy_quic_clock.h" + +#include "test/test_common/simulated_time_system.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using Envoy::Event::Dispatcher; +using quic::QuicTime; + +namespace Envoy { +namespace Quic { + +class TestDelegate : public quic::QuicAlarm::Delegate { +public: + TestDelegate() : fired_(false) {} + + // quic::QuicAlarm::Delegate + void OnAlarm() override { fired_ = true; } + + bool fired() const { return fired_; } + void set_fired(bool fired) { fired_ = fired; } + +private: + bool fired_; +}; + +class EnvoyQuicAlarmTest : public ::testing::Test { +public: + EnvoyQuicAlarmTest() + : clock_(time_system_), scheduler_(time_system_.createScheduler(base_scheduler_)), + alarm_factory_(*scheduler_, clock_) {} + + void advanceMsAndLoop(int64_t delay_ms) { + time_system_.sleep(std::chrono::milliseconds(delay_ms)); + base_scheduler_.run(Dispatcher::RunType::NonBlock); + } + +protected: + Event::SimulatedTimeSystemHelper time_system_; + EnvoyQuicClock clock_; + Event::LibeventScheduler base_scheduler_; + Event::SchedulerPtr scheduler_; + EnvoyQuicAlarmFactory alarm_factory_; + quic::QuicConnectionArena arena_; +}; + +TEST_F(EnvoyQuicAlarmTest, CreateAlarmByFactory) { + auto unowned_delegate = new TestDelegate(); + quic::QuicAlarm* alarm = alarm_factory_.CreateAlarm(unowned_delegate); + alarm->Set(clock_.Now() + QuicTime::Delta::FromMilliseconds(10)); + // Advance 9us, alarm shouldn't fire. + advanceMsAndLoop(9); + EXPECT_FALSE(unowned_delegate->fired()); + // Advance 1us, alarm should have fired. + advanceMsAndLoop(1); + EXPECT_TRUE(unowned_delegate->fired()); + delete alarm; + + unowned_delegate = new TestDelegate(); + quic::QuicArenaScopedPtr alarm_ptr = alarm_factory_.CreateAlarm( + quic::QuicArenaScopedPtr(unowned_delegate), &arena_); + EXPECT_FALSE(alarm_ptr->IsSet()); + unowned_delegate = new TestDelegate(); + alarm_ptr = alarm_factory_.CreateAlarm( + quic::QuicArenaScopedPtr(unowned_delegate), nullptr); + EXPECT_FALSE(alarm_ptr->IsSet()); +} + +TEST_F(EnvoyQuicAlarmTest, CreateAlarmAndCancel) { + auto unowned_delegate1 = new TestDelegate(); + quic::QuicArenaScopedPtr alarm1(alarm_factory_.CreateAlarm(unowned_delegate1)); + alarm1->Set(clock_.Now() + QuicTime::Delta::FromMilliseconds(10)); + EXPECT_TRUE(alarm1->IsSet()); + auto unowned_delegate2 = new TestDelegate(); + quic::QuicArenaScopedPtr alarm2(alarm_factory_.CreateAlarm(unowned_delegate2)); + alarm2->Set(clock_.Now() + QuicTime::Delta::FromMilliseconds(10)); + EXPECT_TRUE(alarm2->IsSet()); + + alarm1->Cancel(); + EXPECT_FALSE(alarm1->IsSet()); + // Advance 10us, alarm1 shouldn't fire, but alarm2 should. + advanceMsAndLoop(10); + EXPECT_TRUE(unowned_delegate2->fired()); + EXPECT_FALSE(unowned_delegate1->fired()); +} + +TEST_F(EnvoyQuicAlarmTest, CreateAlarmAndReset) { + auto unowned_delegate1 = new TestDelegate(); + quic::QuicArenaScopedPtr alarm1(alarm_factory_.CreateAlarm(unowned_delegate1)); + alarm1->Set(clock_.Now() + QuicTime::Delta::FromMilliseconds(10)); + auto unowned_delegate2 = new TestDelegate(); + quic::QuicArenaScopedPtr alarm2(alarm_factory_.CreateAlarm(unowned_delegate2)); + alarm2->Set(clock_.Now() + QuicTime::Delta::FromMilliseconds(10)); + EXPECT_TRUE(alarm2->IsSet()); + + // Reset alarm1 to a different deadline. + alarm1->Cancel(); + alarm1->Set(clock_.Now() + QuicTime::Delta::FromMilliseconds(5)); + // Advance 9us, alarm1 should have fired but alarm2 shouldn't. + advanceMsAndLoop(9); + EXPECT_TRUE(unowned_delegate1->fired()); + EXPECT_FALSE(unowned_delegate2->fired()); + + advanceMsAndLoop(1); + EXPECT_TRUE(unowned_delegate2->fired()); +} + +TEST_F(EnvoyQuicAlarmTest, CreateAlarmAndUpdate) { + auto unowned_delegate1 = new TestDelegate(); + quic::QuicArenaScopedPtr alarm1(alarm_factory_.CreateAlarm(unowned_delegate1)); + alarm1->Set(clock_.Now() + QuicTime::Delta::FromMilliseconds(10)); + auto unowned_delegate2 = new TestDelegate(); + quic::QuicArenaScopedPtr alarm2(alarm_factory_.CreateAlarm(unowned_delegate2)); + alarm2->Set(clock_.Now() + QuicTime::Delta::FromMilliseconds(10)); + EXPECT_TRUE(alarm2->IsSet()); + + // Update alarm1 to an earlier deadline. + alarm1->Update(clock_.Now() + QuicTime::Delta::FromMilliseconds(5), + quic::QuicTime::Delta::Zero()); + // Advance 9us, alarm1 should have fired but alarm2 shouldn't. + advanceMsAndLoop(9); + EXPECT_TRUE(unowned_delegate1->fired()); + EXPECT_FALSE(unowned_delegate2->fired()); + + advanceMsAndLoop(1); + EXPECT_TRUE(unowned_delegate2->fired()); +} + +TEST_F(EnvoyQuicAlarmTest, PostponeDeadline) { + auto unowned_delegate = new TestDelegate(); + quic::QuicArenaScopedPtr alarm(alarm_factory_.CreateAlarm(unowned_delegate)); + alarm->Set(clock_.Now() + QuicTime::Delta::FromMilliseconds(10)); + advanceMsAndLoop(9); + EXPECT_FALSE(unowned_delegate->fired()); + // Postpone deadline to a later time. + alarm->Update(clock_.Now() + QuicTime::Delta::FromMilliseconds(5), quic::QuicTime::Delta::Zero()); + advanceMsAndLoop(1); + EXPECT_EQ(10, (clock_.Now() - quic::QuicTime::Zero()).ToMilliseconds()); + // alarm shouldn't fire at old deadline. + EXPECT_FALSE(unowned_delegate->fired()); + + advanceMsAndLoop(4); + // alarm should fire at new deadline. + EXPECT_TRUE(unowned_delegate->fired()); +} + +TEST_F(EnvoyQuicAlarmTest, SetAlarmToPastTime) { + advanceMsAndLoop(100); + EXPECT_EQ(100, (clock_.Now() - quic::QuicTime::Zero()).ToMilliseconds()); + auto unowned_delegate = new TestDelegate(); + quic::QuicArenaScopedPtr alarm(alarm_factory_.CreateAlarm(unowned_delegate)); + // alarm becomes active upon Set(). + alarm->Set(clock_.Now() - QuicTime::Delta::FromMilliseconds(10)); + EXPECT_FALSE(unowned_delegate->fired()); + base_scheduler_.run(Dispatcher::RunType::NonBlock); + EXPECT_TRUE(unowned_delegate->fired()); +} + +TEST_F(EnvoyQuicAlarmTest, UpdateAlarmWithPastDeadline) { + auto unowned_delegate = new TestDelegate(); + quic::QuicArenaScopedPtr alarm(alarm_factory_.CreateAlarm(unowned_delegate)); + alarm->Set(clock_.Now() + QuicTime::Delta::FromMilliseconds(10)); + advanceMsAndLoop(9); + EXPECT_EQ(9, (clock_.Now() - quic::QuicTime::Zero()).ToMilliseconds()); + EXPECT_FALSE(unowned_delegate->fired()); + // alarm becomes active upon Update(). + alarm->Update(clock_.Now() - QuicTime::Delta::FromMilliseconds(1), quic::QuicTime::Delta::Zero()); + base_scheduler_.run(Dispatcher::RunType::NonBlock); + EXPECT_TRUE(unowned_delegate->fired()); + unowned_delegate->set_fired(false); + advanceMsAndLoop(1); + // alarm shouldn't fire at the original deadline. + EXPECT_FALSE(unowned_delegate->fired()); +} + +TEST_F(EnvoyQuicAlarmTest, CancelActiveAlarm) { + advanceMsAndLoop(100); + EXPECT_EQ(100, (clock_.Now() - quic::QuicTime::Zero()).ToMilliseconds()); + auto unowned_delegate = new TestDelegate(); + quic::QuicArenaScopedPtr alarm(alarm_factory_.CreateAlarm(unowned_delegate)); + // alarm becomes active upon Set(). + alarm->Set(clock_.Now() - QuicTime::Delta::FromMilliseconds(10)); + alarm->Cancel(); + base_scheduler_.run(Dispatcher::RunType::NonBlock); + EXPECT_FALSE(unowned_delegate->fired()); +} + +} // namespace Quic +} // namespace Envoy diff --git a/test/extensions/tracers/lightstep/lightstep_tracer_impl_test.cc b/test/extensions/tracers/lightstep/lightstep_tracer_impl_test.cc index 09920ae029da..b253dd30899e 100644 --- a/test/extensions/tracers/lightstep/lightstep_tracer_impl_test.cc +++ b/test/extensions/tracers/lightstep/lightstep_tracer_impl_test.cc @@ -89,7 +89,7 @@ class LightStepDriverTest : public testing::Test { StreamInfo::MockStreamInfo stream_info_; Envoy::Test::Global symbol_table_; - Grpc::Common grpc_context_; + Grpc::ContextImpl grpc_context_; NiceMock tls_; Stats::IsolatedStoreImpl stats_; std::unique_ptr driver_; diff --git a/test/integration/http2_integration_test.cc b/test/integration/http2_integration_test.cc index 4df3a31141cb..9100cc57e194 100644 --- a/test/integration/http2_integration_test.cc +++ b/test/integration/http2_integration_test.cc @@ -430,6 +430,23 @@ TEST_P(Http2IntegrationTest, GrpcRouterNotFound) { TEST_P(Http2IntegrationTest, GrpcRetry) { testGrpcRetry(); } +// Verify the case where there is an HTTP/2 codec/protocol error with an active stream. +TEST_P(Http2IntegrationTest, CodecErrorAfterStreamStart) { + initialize(); + codec_client_ = makeHttpConnection(lookupPort("http")); + + // Sends a request. + auto response = codec_client_->makeRequestWithBody(default_request_headers_, 10); + waitForNextUpstreamRequest(); + + // Send bogus raw data on the connection. + Buffer::OwnedImpl bogus_data("some really bogus data"); + codec_client_->rawConnection().write(bogus_data, false); + + // Verifies reset is received. + response->waitForReset(); +} + TEST_P(Http2IntegrationTest, BadMagic) { initialize(); Buffer::OwnedImpl buffer("hello"); diff --git a/test/integration/http_integration.h b/test/integration/http_integration.h index c914831cb6b6..00beabdd0114 100644 --- a/test/integration/http_integration.h +++ b/test/integration/http_integration.h @@ -39,6 +39,7 @@ class IntegrationCodecClient : public Http::CodecClientProd { bool waitForDisconnect(std::chrono::milliseconds time_to_wait = std::chrono::milliseconds(0)); Network::ClientConnection* connection() const { return connection_.get(); } Network::ConnectionEvent last_connection_event() const { return last_connection_event_; } + Network::Connection& rawConnection() { return *connection_; } private: struct ConnectionCallbacks : public Network::ConnectionCallbacks { diff --git a/test/integration/integration_admin_test.cc b/test/integration/integration_admin_test.cc index 09adf7ca6382..aa0a0fdb3f56 100644 --- a/test/integration/integration_admin_test.cc +++ b/test/integration/integration_admin_test.cc @@ -534,6 +534,8 @@ TEST_P(StatsMatcherIntegrationTest, ExcludeMultipleExact) { // blocks on its creation (see waitForCounterGe and the suite of waitFor* functions). // If this invariant is changed, this test must be rewritten. TEST_P(StatsMatcherIntegrationTest, IncludeExact) { + // Stats matching does not play well with LDS, at least in test. See #7215. + use_lds_ = false; stats_matcher_.mutable_inclusion_list()->add_patterns()->set_exact( "listener_manager.listener_create_success"); initialize(); diff --git a/test/mocks/server/BUILD b/test/mocks/server/BUILD index fd64aafbf173..f6384d37070d 100644 --- a/test/mocks/server/BUILD +++ b/test/mocks/server/BUILD @@ -26,6 +26,7 @@ envoy_cc_mock( "//include/envoy/server:worker_interface", "//include/envoy/ssl:context_manager_interface", "//include/envoy/upstream:health_checker_interface", + "//source/common/grpc:context_lib", "//source/common/http:context_lib", "//source/common/secret:secret_manager_impl_lib", "//source/common/singleton:manager_impl_lib", diff --git a/test/mocks/server/mocks.h b/test/mocks/server/mocks.h index 57fa1b858650..08c08f7bfccf 100644 --- a/test/mocks/server/mocks.h +++ b/test/mocks/server/mocks.h @@ -20,6 +20,7 @@ #include "envoy/stats/scope.h" #include "envoy/thread/thread.h" +#include "common/grpc/context_impl.h" #include "common/http/context_impl.h" #include "common/secret/secret_manager_impl.h" #include "common/stats/fake_symbol_table_impl.h" @@ -403,7 +404,7 @@ class MockInstance : public Instance { testing::NiceMock listener_manager_; testing::NiceMock overload_manager_; Singleton::ManagerPtr singleton_manager_; - Grpc::Common grpc_context_; + Grpc::ContextImpl grpc_context_; Http::ContextImpl http_context_; }; @@ -478,7 +479,7 @@ class MockFactoryContext : public virtual FactoryContext { Stats::IsolatedStoreImpl listener_scope_; Event::GlobalTimeSystem time_system_; testing::NiceMock overload_manager_; - Grpc::Common grpc_context_; + Grpc::ContextImpl grpc_context_; Http::ContextImpl http_context_; testing::NiceMock api_; }; diff --git a/test/server/http/admin_test.cc b/test/server/http/admin_test.cc index 0d9fcfd63d7d..d8ac9debd063 100644 --- a/test/server/http/admin_test.cc +++ b/test/server/http/admin_test.cc @@ -1391,8 +1391,8 @@ TEST_F(PrometheusStatsFormatterTest, MetricNameCollison) { {{"another_tag_name_4", "another_tag_4-value"}}); Buffer::OwnedImpl response; - auto size = - PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, false); + auto size = PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, + false, absl::nullopt); EXPECT_EQ(2UL, size); } @@ -1411,8 +1411,8 @@ TEST_F(PrometheusStatsFormatterTest, UniqueMetricName) { {{"another_tag_name_4", "another_tag_4-value"}}); Buffer::OwnedImpl response; - auto size = - PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, false); + auto size = PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, + false, absl::nullopt); EXPECT_EQ(4UL, size); } @@ -1430,8 +1430,8 @@ TEST_F(PrometheusStatsFormatterTest, HistogramWithNoValuesAndNoTags) { addHistogram(histogram); Buffer::OwnedImpl response; - auto size = - PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, false); + auto size = PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, + false, absl::nullopt); EXPECT_EQ(1UL, size); const std::string expected_output = R"EOF(# TYPE envoy_histogram1 histogram @@ -1483,8 +1483,8 @@ TEST_F(PrometheusStatsFormatterTest, HistogramWithHighCounts) { addHistogram(histogram); Buffer::OwnedImpl response; - auto size = - PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, false); + auto size = PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, + false, absl::nullopt); EXPECT_EQ(1UL, size); const std::string expected_output = R"EOF(# TYPE envoy_histogram1 histogram @@ -1535,8 +1535,8 @@ TEST_F(PrometheusStatsFormatterTest, OutputWithAllMetricTypes) { .WillOnce(testing::ReturnRef(h1_cumulative_statistics)); Buffer::OwnedImpl response; - auto size = - PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, false); + auto size = PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, + false, absl::nullopt); EXPECT_EQ(5UL, size); const std::string expected_output = R"EOF(# TYPE envoy_cluster_test_1_upstream_cx_total counter @@ -1595,8 +1595,8 @@ TEST_F(PrometheusStatsFormatterTest, OutputWithUsedOnly) { .WillOnce(testing::ReturnRef(h1_cumulative_statistics)); Buffer::OwnedImpl response; - auto size = - PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, true); + auto size = PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, + true, absl::nullopt); EXPECT_EQ(1UL, size); const std::string expected_output = R"EOF(# TYPE envoy_cluster_test_1_upstream_rq_time histogram @@ -1645,7 +1645,7 @@ TEST_F(PrometheusStatsFormatterTest, OutputWithUsedOnlyHistogram) { Buffer::OwnedImpl response; auto size = PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, - response, used_only); + response, used_only, absl::nullopt); EXPECT_EQ(0UL, size); } @@ -1656,10 +1656,40 @@ TEST_F(PrometheusStatsFormatterTest, OutputWithUsedOnlyHistogram) { Buffer::OwnedImpl response; auto size = PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, - response, used_only); + response, used_only, absl::nullopt); EXPECT_EQ(1UL, size); } } +TEST_F(PrometheusStatsFormatterTest, OutputWithRegexp) { + addCounter("cluster.test_1.upstream_cx_total", {{"a.tag-name", "a.tag-value"}}); + addCounter("cluster.test_2.upstream_cx_total", {{"another_tag_name", "another_tag-value"}}); + addGauge("cluster.test_3.upstream_cx_total", {{"another_tag_name_3", "another_tag_3-value"}}); + addGauge("cluster.test_4.upstream_cx_total", {{"another_tag_name_4", "another_tag_4-value"}}); + + const std::vector h1_values = {50, 20, 30, 70, 100, 5000, 200}; + HistogramWrapper h1_cumulative; + h1_cumulative.setHistogramValues(h1_values); + Stats::HistogramStatisticsImpl h1_cumulative_statistics(h1_cumulative.getHistogram()); + + auto histogram1 = std::make_shared>(); + histogram1->name_ = "cluster.test_1.upstream_rq_time"; + histogram1->setTags({Stats::Tag{"key1", "value1"}, Stats::Tag{"key2", "value2"}}); + addHistogram(histogram1); + + Buffer::OwnedImpl response; + auto size = PrometheusStatsFormatter::statsAsPrometheus( + counters_, gauges_, histograms_, response, false, + absl::optional{std::regex("cluster.test_1.upstream_cx_total")}); + EXPECT_EQ(1UL, size); + + const std::string expected_output = + R"EOF(# TYPE envoy_cluster_test_1_upstream_cx_total counter +envoy_cluster_test_1_upstream_cx_total{a_tag_name="a.tag-value"} 0 +)EOF"; + + EXPECT_EQ(expected_output, response.toString()); +} + } // namespace Server } // namespace Envoy diff --git a/test/test_common/simulated_time_system.cc b/test/test_common/simulated_time_system.cc index 5cf614ba6c1f..1e700f650832 100644 --- a/test/test_common/simulated_time_system.cc +++ b/test/test_common/simulated_time_system.cc @@ -62,7 +62,7 @@ class SimulatedTimeSystemHelper::Alarm : public Timer { void enableTimer(const std::chrono::milliseconds& duration) override; bool enabled() override { Thread::LockGuard lock(time_system_.mutex_); - return armed_; + return armed_ || base_timer_->enabled(); } void disableTimerLockHeld() EXCLUSIVE_LOCKS_REQUIRED(time_system_.mutex_); diff --git a/test/test_common/simulated_time_system_test.cc b/test/test_common/simulated_time_system_test.cc index 941aae844202..399ee31a87b1 100644 --- a/test/test_common/simulated_time_system_test.cc +++ b/test/test_common/simulated_time_system_test.cc @@ -233,6 +233,12 @@ TEST_F(SimulatedTimeSystemTest, DuplicateTimer) { thread->join(); } +TEST_F(SimulatedTimeSystemTest, Enabled) { + TimerPtr timer = scheduler_->createTimer({}); + timer->enableTimer(std::chrono::milliseconds(0)); + EXPECT_TRUE(timer->enabled()); +} + } // namespace } // namespace Test } // namespace Event From bb55a4498d3792c6d704cd5b964dad4e61e35bf3 Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Tue, 11 Jun 2019 17:14:26 -0400 Subject: [PATCH 02/21] fix typo Signed-off-by: Xin Zhuang --- test/common/router/scoped_config_impl_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common/router/scoped_config_impl_test.cc b/test/common/router/scoped_config_impl_test.cc index 98d32562e2e1..50c61eee3d5e 100644 --- a/test/common/router/scoped_config_impl_test.cc +++ b/test/common/router/scoped_config_impl_test.cc @@ -243,7 +243,7 @@ TEST(ScopeKeyTest, Matches) { EXPECT_EQ(makeKey({"", ""}), makeKey({"", ""})); EXPECT_EQ(makeKey({"a", "", ""}), makeKey({"a", "", ""})); - // Non empty fragments comparision. + // Non empty fragments comparison. EXPECT_EQ(makeKey({"A", "b"}), makeKey({"A", "b"})); } From 8d7b4da5ab00393ba963b8311d696dff617a3b56 Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Tue, 11 Jun 2019 22:14:11 -0400 Subject: [PATCH 03/21] move impl code from header to cc file. Signed-off-by: Xin Zhuang --- source/common/router/scoped_config_impl.cc | 45 +++++++++++++++++++++ source/common/router/scoped_config_impl.h | 46 ++-------------------- 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/source/common/router/scoped_config_impl.cc b/source/common/router/scoped_config_impl.cc index e32887b7612f..4b5c995c52f8 100644 --- a/source/common/router/scoped_config_impl.cc +++ b/source/common/router/scoped_config_impl.cc @@ -3,6 +3,51 @@ namespace Envoy { namespace Router { +bool ScopeKey::operator!=(const ScopeKey& other) const { return !(*this == other); } + +bool ScopeKey::operator==(const ScopeKey& other) const { + if (this->fragments_.size() != other.fragments_.size()) { + return false; + } + if (this->fragments_.size() == 0 || other.fragments_.size() == 0) { + // An empty key equals to nothing, "NULL" != "NULL". + return false; + } + // A "NULL" fragment value equals to nothing. + if (this->contains_null_fragment_ || other.contains_null_fragment_) { + return false; + } + return std::equal(this->fragments_.begin(), this->fragments_.end(), other.fragments_.begin(), + [](const std::unique_ptr& left, + const std::unique_ptr& right) -> bool { + // Both should be non-NULL now. + return *left == *right; + }); +} + +HeaderValueExtractorImpl::HeaderValueExtractorImpl( + ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config) + : FragmentBuilderBase(config), + header_value_extractor_config_(config_.header_value_extractor()) { + ASSERT(config_.type_case() == + ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::kHeaderValueExtractor, + "header_value_extractor is not set."); + if (header_value_extractor_config_.extract_type_case() == + ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::HeaderValueExtractor::kIndex) { + if (header_value_extractor_config_.index() != 0 && + header_value_extractor_config_.element_separator().length() == 0) { + throw ProtoValidationException("when element separator is set to an empty string, index " + "should be set to 0 in HeaderValueExtractor.", + header_value_extractor_config_); + } + } + if (header_value_extractor_config_.extract_type_case() == + ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::HeaderValueExtractor::EXTRACT_TYPE_NOT_SET) { + throw ProtoValidationException("HeaderValueExtractor extract_type not set.", + header_value_extractor_config_); + } +} + std::unique_ptr HeaderValueExtractorImpl::computeFragment(const Http::HeaderMap& headers) const { const Envoy::Http::HeaderEntry* header_entry = diff --git a/source/common/router/scoped_config_impl.h b/source/common/router/scoped_config_impl.h index 3153da37baff..ac9a8fcaee34 100644 --- a/source/common/router/scoped_config_impl.h +++ b/source/common/router/scoped_config_impl.h @@ -44,29 +44,12 @@ class ScopeKey { fragments_.emplace_back(std::move(part)); } - bool operator!=(const ScopeKey& other) const { return !(*this == other); } + bool operator!=(const ScopeKey& other) const; - bool operator==(const ScopeKey& other) const { - if (this->fragments_.size() != other.fragments_.size()) { - return false; - } - if (this->fragments_.size() == 0 || other.fragments_.size() == 0) { - // An empty key equals to nothing, "NULL" != "NULL". - return false; - } - // A "NULL" fragment value equals to nothing. - if (this->contains_null_fragment_ || other.contains_null_fragment_) { - return false; - } - return std::equal(this->fragments_.begin(), this->fragments_.end(), other.fragments_.begin(), - [](const std::unique_ptr& left, - const std::unique_ptr& right) -> bool { - // Both should be non-NULL now. - return *left == *right; - }); - } + bool operator==(const ScopeKey& other) const; private: + // If there is a NULL fragment in the key. bool contains_null_fragment_{false}; std::vector> fragments_; }; @@ -104,28 +87,7 @@ class FragmentBuilderBase { class HeaderValueExtractorImpl : public FragmentBuilderBase { public: - explicit HeaderValueExtractorImpl(ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config) - : FragmentBuilderBase(config), - header_value_extractor_config_(config_.header_value_extractor()) { - ASSERT(config_.type_case() == - ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::kHeaderValueExtractor, - "header_value_extractor is not set."); - if (header_value_extractor_config_.extract_type_case() == - ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::HeaderValueExtractor::kIndex) { - if (header_value_extractor_config_.index() != 0 && - header_value_extractor_config_.element_separator().length() == 0) { - throw ProtoValidationException("when element separator is set to an empty string, index " - "should be set to 0 in HeaderValueExtractor.", - header_value_extractor_config_); - } - } - if (header_value_extractor_config_.extract_type_case() == - ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::HeaderValueExtractor:: - EXTRACT_TYPE_NOT_SET) { - throw ProtoValidationException("HeaderValueExtractor extract_type not set.", - header_value_extractor_config_); - } - } + explicit HeaderValueExtractorImpl(ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config); std::unique_ptr computeFragment(const Http::HeaderMap& headers) const override; From 8bcddcec0d22b1c0f06d1e2d2271f5e10604ec59 Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Wed, 12 Jun 2019 14:11:57 -0400 Subject: [PATCH 04/21] add review fixes and unit test case for keybuidler Signed-off-by: Xin Zhuang --- source/common/router/scoped_config_impl.cc | 16 ++-- source/common/router/scoped_config_impl.h | 20 ++-- test/common/router/scoped_config_impl_test.cc | 93 +++++++++++++++---- 3 files changed, 99 insertions(+), 30 deletions(-) diff --git a/source/common/router/scoped_config_impl.cc b/source/common/router/scoped_config_impl.cc index 4b5c995c52f8..4aeff6665760 100644 --- a/source/common/router/scoped_config_impl.cc +++ b/source/common/router/scoped_config_impl.cc @@ -13,10 +13,6 @@ bool ScopeKey::operator==(const ScopeKey& other) const { // An empty key equals to nothing, "NULL" != "NULL". return false; } - // A "NULL" fragment value equals to nothing. - if (this->contains_null_fragment_ || other.contains_null_fragment_) { - return false; - } return std::equal(this->fragments_.begin(), this->fragments_.end(), other.fragments_.begin(), [](const std::unique_ptr& left, const std::unique_ptr& right) -> bool { @@ -96,12 +92,18 @@ ScopeKeyBuilderImpl::ScopeKeyBuilderImpl(ScopedRoutes::ScopeKeyBuilder config) } } -const ScopeKey ScopeKeyBuilderImpl::computeScopeKey(const Http::HeaderMap& headers) const { +std::unique_ptr +ScopeKeyBuilderImpl::computeScopeKey(const Http::HeaderMap& headers) const { ScopeKey key; for (const auto& builder : fragment_builders_) { - key.addFragment(builder->computeFragment(headers)); + // returns nullopt if a null fragment is found. + std::unique_ptr fragment = builder->computeFragment(headers); + if (fragment == nullptr) { + return nullptr; + } + key.addFragment(std::move(fragment)); } - return key; + return std::make_unique(std::move(key)); } void ThreadLocalScopedConfigImpl::addOrUpdateRoutingScope(const ScopedRouteInfoConstSharedPtr&) {} diff --git a/source/common/router/scoped_config_impl.h b/source/common/router/scoped_config_impl.h index ac9a8fcaee34..b1fd0ee8652b 100644 --- a/source/common/router/scoped_config_impl.h +++ b/source/common/router/scoped_config_impl.h @@ -22,6 +22,8 @@ using envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes; */ class ScopeKeyFragmentBase { public: + bool operator!=(const ScopeKeyFragmentBase& other) const { return !(*this == other); } + bool operator==(const ScopeKeyFragmentBase& other) const { if (typeid(*this) == typeid(other)) { return equals(other); @@ -35,13 +37,18 @@ class ScopeKeyFragmentBase { virtual bool equals(const ScopeKeyFragmentBase&) const PURE; }; +/** + * Scope Key is composed of non-null fragments. + * + **/ class ScopeKey { public: ScopeKey() = default; ScopeKey(ScopeKey&& other) = default; - void addFragment(std::unique_ptr&& part) { - contains_null_fragment_ = contains_null_fragment_ || (part == nullptr); - fragments_.emplace_back(std::move(part)); + + // Caller should guarantee the fragment is not nullptr. + void addFragment(std::unique_ptr&& fragment) { + fragments_.emplace_back(std::move(fragment)); } bool operator!=(const ScopeKey& other) const; @@ -49,8 +56,6 @@ class ScopeKey { bool operator==(const ScopeKey& other) const; private: - // If there is a NULL fragment in the key. - bool contains_null_fragment_{false}; std::vector> fragments_; }; @@ -105,7 +110,8 @@ class ScopeKeyBuilderBase { explicit ScopeKeyBuilderBase(ScopedRoutes::ScopeKeyBuilder config) : config_(std::move(config)) {} virtual ~ScopeKeyBuilderBase() = default; - virtual const ScopeKey computeScopeKey(const Http::HeaderMap& headers) const PURE; + // Computes scope key for given headers, returns nullptr if a key can't be computed. + virtual std::unique_ptr computeScopeKey(const Http::HeaderMap& headers) const PURE; protected: ScopedRoutes::ScopeKeyBuilder config_; @@ -115,7 +121,7 @@ class ScopeKeyBuilderImpl : public ScopeKeyBuilderBase { public: explicit ScopeKeyBuilderImpl(ScopedRoutes::ScopeKeyBuilder config); - const ScopeKey computeScopeKey(const Http::HeaderMap& headers) const override; + std::unique_ptr computeScopeKey(const Http::HeaderMap& headers) const override; private: std::vector> fragment_builders_; diff --git a/test/common/router/scoped_config_impl_test.cc b/test/common/router/scoped_config_impl_test.cc index 50c61eee3d5e..5cf21de16af0 100644 --- a/test/common/router/scoped_config_impl_test.cc +++ b/test/common/router/scoped_config_impl_test.cc @@ -21,7 +21,7 @@ TEST(ScopeKeyFragmentBaseTest, EqualSign) { FooFragment foo; StringKeyFragment bar("a random string"); - EXPECT_FALSE(foo == bar); + EXPECT_NE(foo, bar); } TEST(StringKeyFragmentTest, Empty) { @@ -31,7 +31,7 @@ TEST(StringKeyFragmentTest, Empty) { StringKeyFragment non_empty("ABC"); - EXPECT_FALSE(a == non_empty); + EXPECT_NE(a, non_empty); } TEST(StringKeyFragmentTest, Normal) { @@ -41,13 +41,13 @@ TEST(StringKeyFragmentTest, Normal) { EXPECT_EQ(str, same_str); StringKeyFragment upper_cased_str("ABC"); - EXPECT_FALSE(str == upper_cased_str); + EXPECT_NE(str, upper_cased_str); StringKeyFragment another_str("DEF"); - EXPECT_FALSE(str == another_str); + EXPECT_NE(str, another_str); } -TEST(HeaderValueExtractorImplTest, InvalidConfig) { +TEST(HeaderValueExtractorImplDeathTest, InvalidConfig) { ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config; // Type not set. EXPECT_DEATH(HeaderValueExtractorImpl{config}, "header_value_extractor is not set."); @@ -206,11 +206,7 @@ TEST(HeaderValueExtractorImplTest, ElementSeparatorEmpty) { ScopeKey makeKey(const std::vector& parts) { ScopeKey key; for (const auto& part : parts) { - if (part != nullptr) { - key.addFragment(std::make_unique(part)); - } else { - key.addFragment(nullptr); - } + key.addFragment(std::make_unique(part)); } return key; } @@ -226,14 +222,9 @@ TEST(ScopeKeyTest, Unmatches) { EXPECT_EQ(makeKey({"a", "b", "c"}), makeKey({"a", "b", "c"})); - // A null part matches nothing. - EXPECT_NE(makeKey({"a", "b", "c"}), makeKey({"a", "b", nullptr})); - - // A null part doesn't match "". - EXPECT_NE(makeKey({"a", "b", ""}), makeKey({"a", "b", nullptr})); - // Two keys of different length won't match. EXPECT_NE(makeKey({"a", "b"}), makeKey({"a", "b", "c"})); + // Case sensitive. EXPECT_NE(makeKey({"a", "b"}), makeKey({"A", "b"})); } @@ -247,6 +238,76 @@ TEST(ScopeKeyTest, Matches) { EXPECT_EQ(makeKey({"A", "b"}), makeKey({"A", "b"})); } +TEST(ScopeKeyBuilderImplTest, Parse) { + std::string yaml_plain = R"EOF( + fragments: + - header_value_extractor: + name: 'foo_header' + element_separator: ',' + element: + key: 'bar' + separator: '=' + - header_value_extractor: + name: 'bar_header' + element_separator: ';' + index: 2 +)EOF"; + + ScopedRoutes::ScopeKeyBuilder config; + TestUtility::loadFromYaml(yaml_plain, config); + ScopeKeyBuilderImpl key_builder(config); + + std::unique_ptr key = key_builder.computeScopeKey(TestHeaderMapImpl{ + {"foo_header", "a=b,bar=bar_value,e=f"}, + {"bar_header", "a=b;bar=bar_value;index2"}, + }); + EXPECT_NE(key, nullptr); + EXPECT_EQ(*key, makeKey({"bar_value", "index2"})); + + // Empty string fragment is fine. + key = key_builder.computeScopeKey(TestHeaderMapImpl{ + {"foo_header", "a=b,bar,e=f"}, + {"bar_header", "a=b;bar=bar_value;"}, + }); + EXPECT_NE(key, nullptr); + EXPECT_EQ(*key, makeKey({"", ""})); + + // Key not found. + key = key_builder.computeScopeKey(TestHeaderMapImpl{ + {"foo_header", "a=b,meh,e=f"}, + {"bar_header", "a=b;bar=bar_value;"}, + }); + EXPECT_EQ(key, nullptr); + + // Index out of bound. + key = key_builder.computeScopeKey(TestHeaderMapImpl{ + {"foo_header", "a=b,bar=bar_value,e=f"}, + {"bar_header", "a=b;bar=bar_value"}, + }); + EXPECT_EQ(key, nullptr); + + // Header missing. + key = key_builder.computeScopeKey(TestHeaderMapImpl{ + {"foo_header", "a=b,bar=bar_value,e=f"}, + {"foobar_header", "a=b;bar=bar_value;index2"}, + }); + EXPECT_EQ(key, nullptr); + + // Header value empty. + key = key_builder.computeScopeKey(TestHeaderMapImpl{ + {"foo_header", ""}, + {"bar_header", "a=b;bar=bar_value;index2"}, + }); + EXPECT_EQ(key, nullptr); + + // Case sensitive. + key = key_builder.computeScopeKey(TestHeaderMapImpl{ + {"foo_header", "a=b,Bar=bar_value,e=f"}, + {"bar_header", "a=b;bar=bar_value;index2"}, + }); + EXPECT_EQ(key, nullptr); +} + } // namespace } // namespace Router } // namespace Envoy From b1d0d5c08f9a4a9768824f171fa9be9994022e1d Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Wed, 12 Jun 2019 15:51:18 -0400 Subject: [PATCH 05/21] clang-tidy fix Signed-off-by: Xin Zhuang --- source/common/router/scoped_config_impl.cc | 4 ++-- test/common/router/scoped_config_impl_test.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/common/router/scoped_config_impl.cc b/source/common/router/scoped_config_impl.cc index 4aeff6665760..07f86a6a1243 100644 --- a/source/common/router/scoped_config_impl.cc +++ b/source/common/router/scoped_config_impl.cc @@ -9,7 +9,7 @@ bool ScopeKey::operator==(const ScopeKey& other) const { if (this->fragments_.size() != other.fragments_.size()) { return false; } - if (this->fragments_.size() == 0 || other.fragments_.size() == 0) { + if (this->fragments_.empty() || other.fragments_.empty()) { // An empty key equals to nothing, "NULL" != "NULL". return false; } @@ -23,7 +23,7 @@ bool ScopeKey::operator==(const ScopeKey& other) const { HeaderValueExtractorImpl::HeaderValueExtractorImpl( ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config) - : FragmentBuilderBase(config), + : FragmentBuilderBase(std::move(config)), header_value_extractor_config_(config_.header_value_extractor()) { ASSERT(config_.type_case() == ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::kHeaderValueExtractor, diff --git a/test/common/router/scoped_config_impl_test.cc b/test/common/router/scoped_config_impl_test.cc index 5cf21de16af0..e8d8917e1a51 100644 --- a/test/common/router/scoped_config_impl_test.cc +++ b/test/common/router/scoped_config_impl_test.cc @@ -14,7 +14,7 @@ using ::Envoy::Http::TestHeaderMapImpl; class FooFragment : public ScopeKeyFragmentBase { private: - virtual bool equals(const ScopeKeyFragmentBase&) const { return true; }; + bool equals(const ScopeKeyFragmentBase&) const override { return true; }; }; TEST(ScopeKeyFragmentBaseTest, EqualSign) { From 1007ee08b86bef33f84fa9c08e3594ee5ab31449 Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Wed, 12 Jun 2019 16:08:26 -0400 Subject: [PATCH 06/21] use expect_debug_death for assertion test Signed-off-by: Xin Zhuang --- test/common/router/scoped_config_impl_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common/router/scoped_config_impl_test.cc b/test/common/router/scoped_config_impl_test.cc index e8d8917e1a51..1060f6948e44 100644 --- a/test/common/router/scoped_config_impl_test.cc +++ b/test/common/router/scoped_config_impl_test.cc @@ -50,7 +50,7 @@ TEST(StringKeyFragmentTest, Normal) { TEST(HeaderValueExtractorImplDeathTest, InvalidConfig) { ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config; // Type not set. - EXPECT_DEATH(HeaderValueExtractorImpl{config}, "header_value_extractor is not set."); + EXPECT_DEBUG_DEATH(HeaderValueExtractorImpl{config}, "header_value_extractor is not set."); // Index non-zero when element separator is an empty string. std::string yaml_plain = R"EOF( From 184ff2f501e11995cdb515f24c454849b3d08aa1 Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Wed, 12 Jun 2019 17:41:39 -0400 Subject: [PATCH 07/21] fix failed test in opt mode Signed-off-by: Xin Zhuang --- test/common/router/scoped_config_impl_test.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/common/router/scoped_config_impl_test.cc b/test/common/router/scoped_config_impl_test.cc index 1060f6948e44..39524b60a2f0 100644 --- a/test/common/router/scoped_config_impl_test.cc +++ b/test/common/router/scoped_config_impl_test.cc @@ -49,8 +49,10 @@ TEST(StringKeyFragmentTest, Normal) { TEST(HeaderValueExtractorImplDeathTest, InvalidConfig) { ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config; - // Type not set. + // Type not set, ASSERT only fails in debug mode. +#if !defined(NDEBUG) EXPECT_DEBUG_DEATH(HeaderValueExtractorImpl{config}, "header_value_extractor is not set."); +#endif // !defined(NDEBUG) // Index non-zero when element separator is an empty string. std::string yaml_plain = R"EOF( From fe6b643e8f51f6b8216ad55cbd0f851adb88d58e Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Thu, 13 Jun 2019 17:36:25 -0400 Subject: [PATCH 08/21] add assert around addFragment and test, and a few review fix Signed-off-by: Xin Zhuang --- source/common/router/scoped_config_impl.cc | 4 +--- source/common/router/scoped_config_impl.h | 6 +++++- test/common/router/scoped_config_impl_test.cc | 10 ++++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/source/common/router/scoped_config_impl.cc b/source/common/router/scoped_config_impl.cc index 07f86a6a1243..49e5a44d4496 100644 --- a/source/common/router/scoped_config_impl.cc +++ b/source/common/router/scoped_config_impl.cc @@ -6,14 +6,12 @@ namespace Router { bool ScopeKey::operator!=(const ScopeKey& other) const { return !(*this == other); } bool ScopeKey::operator==(const ScopeKey& other) const { - if (this->fragments_.size() != other.fragments_.size()) { - return false; - } if (this->fragments_.empty() || other.fragments_.empty()) { // An empty key equals to nothing, "NULL" != "NULL". return false; } return std::equal(this->fragments_.begin(), this->fragments_.end(), other.fragments_.begin(), + other.fragments_.end(), [](const std::unique_ptr& left, const std::unique_ptr& right) -> bool { // Both should be non-NULL now. diff --git a/source/common/router/scoped_config_impl.h b/source/common/router/scoped_config_impl.h index b1fd0ee8652b..3485895c07f6 100644 --- a/source/common/router/scoped_config_impl.h +++ b/source/common/router/scoped_config_impl.h @@ -39,15 +39,19 @@ class ScopeKeyFragmentBase { /** * Scope Key is composed of non-null fragments. - * **/ class ScopeKey { public: ScopeKey() = default; ScopeKey(ScopeKey&& other) = default; + // Scopekey is not copy-assignable and copy-constructible as it contains unique_ptr inside itself. + ScopeKey(const ScopeKey&) = delete; + ScopeKey operator=(const ScopeKey&) = delete; + // Caller should guarantee the fragment is not nullptr. void addFragment(std::unique_ptr&& fragment) { + ASSERT(fragment != nullptr, "null fragment not allowed in ScopeKey."); fragments_.emplace_back(std::move(fragment)); } diff --git a/test/common/router/scoped_config_impl_test.cc b/test/common/router/scoped_config_impl_test.cc index 39524b60a2f0..c086ed03a5a5 100644 --- a/test/common/router/scoped_config_impl_test.cc +++ b/test/common/router/scoped_config_impl_test.cc @@ -52,6 +52,9 @@ TEST(HeaderValueExtractorImplDeathTest, InvalidConfig) { // Type not set, ASSERT only fails in debug mode. #if !defined(NDEBUG) EXPECT_DEBUG_DEATH(HeaderValueExtractorImpl{config}, "header_value_extractor is not set."); +#else + EXPECT_THROW_WITH_REGEX(HeaderValueExtractorImpl{config}, ProtoValidationException, + "HeaderValueExtractor extract_type not set.+"); #endif // !defined(NDEBUG) // Index non-zero when element separator is an empty string. @@ -213,6 +216,13 @@ ScopeKey makeKey(const std::vector& parts) { return key; } +TEST(ScopeKeyDeathTest, AddNullFragment) { + ScopeKey key; +#if !defined(NDEBUG) + EXPECT_DEATH(key.addFragment(nullptr), "null fragment not allowed in ScopeKey."); +#endif // !defined(NDEBUG) +} + TEST(ScopeKeyTest, Unmatches) { ScopeKey key1; ScopeKey key2; From 75718d96a9ad9bb07c122e9d9b525d93a0bccf30 Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Fri, 21 Jun 2019 16:45:17 -0400 Subject: [PATCH 09/21] fix based on feedbacks Signed-off-by: Xin Zhuang --- test/common/router/scoped_config_impl_test.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/common/router/scoped_config_impl_test.cc b/test/common/router/scoped_config_impl_test.cc index c086ed03a5a5..5ba2da84fd18 100644 --- a/test/common/router/scoped_config_impl_test.cc +++ b/test/common/router/scoped_config_impl_test.cc @@ -51,7 +51,7 @@ TEST(HeaderValueExtractorImplDeathTest, InvalidConfig) { ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config; // Type not set, ASSERT only fails in debug mode. #if !defined(NDEBUG) - EXPECT_DEBUG_DEATH(HeaderValueExtractorImpl{config}, "header_value_extractor is not set."); + EXPECT_DEATH(HeaderValueExtractorImpl{config}, "header_value_extractor is not set."); #else EXPECT_THROW_WITH_REGEX(HeaderValueExtractorImpl{config}, ProtoValidationException, "HeaderValueExtractor extract_type not set.+"); @@ -218,9 +218,7 @@ ScopeKey makeKey(const std::vector& parts) { TEST(ScopeKeyDeathTest, AddNullFragment) { ScopeKey key; -#if !defined(NDEBUG) - EXPECT_DEATH(key.addFragment(nullptr), "null fragment not allowed in ScopeKey."); -#endif // !defined(NDEBUG) + EXPECT_DEBUG_DEATH(key.addFragment(nullptr), "null fragment not allowed in ScopeKey."); } TEST(ScopeKeyTest, Unmatches) { From d84839dcc9d8664a2bd634ab5a1576b62876b7ed Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Tue, 25 Jun 2019 10:20:50 -0400 Subject: [PATCH 10/21] fix nits Signed-off-by: Xin Zhuang --- source/common/router/scoped_config_impl.cc | 18 +++++++++--------- source/common/router/scoped_config_impl.h | 16 ++++++++-------- source/common/router/scoped_rds.cc | 2 +- test/common/router/scoped_config_impl_test.cc | 19 +++++++++---------- 4 files changed, 27 insertions(+), 28 deletions(-) diff --git a/source/common/router/scoped_config_impl.cc b/source/common/router/scoped_config_impl.cc index 49e5a44d4496..ee3ce1318568 100644 --- a/source/common/router/scoped_config_impl.cc +++ b/source/common/router/scoped_config_impl.cc @@ -6,11 +6,11 @@ namespace Router { bool ScopeKey::operator!=(const ScopeKey& other) const { return !(*this == other); } bool ScopeKey::operator==(const ScopeKey& other) const { - if (this->fragments_.empty() || other.fragments_.empty()) { + if (fragments_.empty() || other.fragments_.empty()) { // An empty key equals to nothing, "NULL" != "NULL". return false; } - return std::equal(this->fragments_.begin(), this->fragments_.end(), other.fragments_.begin(), + return std::equal(fragments_.begin(), fragments_.end(), other.fragments_.begin(), other.fragments_.end(), [](const std::unique_ptr& left, const std::unique_ptr& right) -> bool { @@ -20,7 +20,7 @@ bool ScopeKey::operator==(const ScopeKey& other) const { } HeaderValueExtractorImpl::HeaderValueExtractorImpl( - ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config) + ScopedRoutes::ScopeKeyBuilder::FragmentBuilder&& config) : FragmentBuilderBase(std::move(config)), header_value_extractor_config_(config_.header_value_extractor()) { ASSERT(config_.type_case() == @@ -29,9 +29,8 @@ HeaderValueExtractorImpl::HeaderValueExtractorImpl( if (header_value_extractor_config_.extract_type_case() == ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::HeaderValueExtractor::kIndex) { if (header_value_extractor_config_.index() != 0 && - header_value_extractor_config_.element_separator().length() == 0) { - throw ProtoValidationException("when element separator is set to an empty string, index " - "should be set to 0 in HeaderValueExtractor.", + header_value_extractor_config_.element_separator().empty()) { + throw ProtoValidationException("Index > 0 for empty string element separator.", header_value_extractor_config_); } } @@ -77,12 +76,13 @@ HeaderValueExtractorImpl::computeFragment(const Http::HeaderMap& headers) const return nullptr; } -ScopeKeyBuilderImpl::ScopeKeyBuilderImpl(ScopedRoutes::ScopeKeyBuilder config) - : ScopeKeyBuilderBase(config) { +ScopeKeyBuilderImpl::ScopeKeyBuilderImpl(ScopedRoutes::ScopeKeyBuilder&& config) + : ScopeKeyBuilderBase(std::move(config)) { for (const auto& fragment_builder : config_.fragments()) { switch (fragment_builder.type_case()) { case ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::kHeaderValueExtractor: - fragment_builders_.emplace_back(std::make_unique(fragment_builder)); + fragment_builders_.emplace_back(std::make_unique( + ScopedRoutes::ScopeKeyBuilder::FragmentBuilder(fragment_builder))); break; default: NOT_REACHED_GCOVR_EXCL_LINE; diff --git a/source/common/router/scoped_config_impl.h b/source/common/router/scoped_config_impl.h index 3485895c07f6..1fea085986cb 100644 --- a/source/common/router/scoped_config_impl.h +++ b/source/common/router/scoped_config_impl.h @@ -73,7 +73,7 @@ class StringKeyFragment : public ScopeKeyFragmentBase { return value_ == static_cast(other).value_; } - std::string value_; + const std::string value_; }; /** @@ -81,7 +81,7 @@ class StringKeyFragment : public ScopeKeyFragmentBase { */ class FragmentBuilderBase { public: - explicit FragmentBuilderBase(ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config) + explicit FragmentBuilderBase(ScopedRoutes::ScopeKeyBuilder::FragmentBuilder&& config) : config_(std::move(config)) {} virtual ~FragmentBuilderBase() = default; @@ -96,7 +96,7 @@ class FragmentBuilderBase { class HeaderValueExtractorImpl : public FragmentBuilderBase { public: - explicit HeaderValueExtractorImpl(ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config); + explicit HeaderValueExtractorImpl(ScopedRoutes::ScopeKeyBuilder::FragmentBuilder&& config); std::unique_ptr computeFragment(const Http::HeaderMap& headers) const override; @@ -111,19 +111,19 @@ class HeaderValueExtractorImpl : public FragmentBuilderBase { */ class ScopeKeyBuilderBase { public: - explicit ScopeKeyBuilderBase(ScopedRoutes::ScopeKeyBuilder config) : config_(std::move(config)) {} + explicit ScopeKeyBuilderBase(ScopedRoutes::ScopeKeyBuilder&& config) : config_(config) {} virtual ~ScopeKeyBuilderBase() = default; // Computes scope key for given headers, returns nullptr if a key can't be computed. virtual std::unique_ptr computeScopeKey(const Http::HeaderMap& headers) const PURE; protected: - ScopedRoutes::ScopeKeyBuilder config_; + const ScopedRoutes::ScopeKeyBuilder config_; }; class ScopeKeyBuilderImpl : public ScopeKeyBuilderBase { public: - explicit ScopeKeyBuilderImpl(ScopedRoutes::ScopeKeyBuilder config); + explicit ScopeKeyBuilderImpl(ScopedRoutes::ScopeKeyBuilder&& config); std::unique_ptr computeScopeKey(const Http::HeaderMap& headers) const override; @@ -143,9 +143,9 @@ class ScopeKeyBuilderImpl : public ScopeKeyBuilderBase { class ThreadLocalScopedConfigImpl : public ScopedConfig, public ThreadLocal::ThreadLocalObject { public: ThreadLocalScopedConfigImpl( - envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes::ScopeKeyBuilder + envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes::ScopeKeyBuilder&& scope_key_builder) - : scope_key_builder_(std::move(scope_key_builder)) {} + : scope_key_builder_(scope_key_builder) {} void addOrUpdateRoutingScope(const ScopedRouteInfoConstSharedPtr& scoped_route_info); void removeRoutingScope(const std::string& scope_name); diff --git a/source/common/router/scoped_rds.cc b/source/common/router/scoped_rds.cc index 0ea1c4ed5a2d..d8ae81833c4c 100644 --- a/source/common/router/scoped_rds.cc +++ b/source/common/router/scoped_rds.cc @@ -159,7 +159,7 @@ ScopedRdsConfigProvider::ScopedRdsConfigProvider( MutableConfigProviderCommonBase::subscription_.get())), rds_config_source_(std::move(rds_config_source)) { initialize([scope_key_builder](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { - return std::make_shared(scope_key_builder); + return std::make_shared(std::move(scope_key_builder)); }); } diff --git a/test/common/router/scoped_config_impl_test.cc b/test/common/router/scoped_config_impl_test.cc index 5ba2da84fd18..9c9a06a25934 100644 --- a/test/common/router/scoped_config_impl_test.cc +++ b/test/common/router/scoped_config_impl_test.cc @@ -51,9 +51,9 @@ TEST(HeaderValueExtractorImplDeathTest, InvalidConfig) { ScopedRoutes::ScopeKeyBuilder::FragmentBuilder config; // Type not set, ASSERT only fails in debug mode. #if !defined(NDEBUG) - EXPECT_DEATH(HeaderValueExtractorImpl{config}, "header_value_extractor is not set."); + EXPECT_DEATH(HeaderValueExtractorImpl(std::move(config)), "header_value_extractor is not set."); #else - EXPECT_THROW_WITH_REGEX(HeaderValueExtractorImpl{config}, ProtoValidationException, + EXPECT_THROW_WITH_REGEX(HeaderValueExtractorImpl(std::move(config)), ProtoValidationException, "HeaderValueExtractor extract_type not set.+"); #endif // !defined(NDEBUG) @@ -66,9 +66,8 @@ TEST(HeaderValueExtractorImplDeathTest, InvalidConfig) { )EOF"; TestUtility::loadFromYaml(yaml_plain, config); - EXPECT_THROW_WITH_REGEX(HeaderValueExtractorImpl{config}, ProtoValidationException, - "when element separator is set to an empty string, index should be set " - "to 0 in HeaderValueExtractor.+"); + EXPECT_THROW_WITH_REGEX(HeaderValueExtractorImpl(std::move(config)), ProtoValidationException, + "Index > 0 for empty string element separator."); // extract_type not set. yaml_plain = R"EOF( header_value_extractor: @@ -77,7 +76,7 @@ TEST(HeaderValueExtractorImplDeathTest, InvalidConfig) { )EOF"; TestUtility::loadFromYaml(yaml_plain, config); - EXPECT_THROW_WITH_REGEX(HeaderValueExtractorImpl{config}, ProtoValidationException, + EXPECT_THROW_WITH_REGEX(HeaderValueExtractorImpl(std::move(config)), ProtoValidationException, "HeaderValueExtractor extract_type not set.+"); } @@ -91,7 +90,7 @@ TEST(HeaderValueExtractorImplTest, HeaderExtractionByIndex) { )EOF"; TestUtility::loadFromYaml(yaml_plain, config); - HeaderValueExtractorImpl extractor(config); + HeaderValueExtractorImpl extractor(std::move(config)); std::unique_ptr fragment = extractor.computeFragment(TestHeaderMapImpl{{"foo_header", "part-0,part-1:value_bluh"}}); @@ -134,7 +133,7 @@ TEST(HeaderValueExtractorImplTest, HeaderExtractionByKey) { )EOF"; TestUtility::loadFromYaml(yaml_plain, config); - HeaderValueExtractorImpl extractor(config); + HeaderValueExtractorImpl extractor(std::move(config)); std::unique_ptr fragment = extractor.computeFragment(TestHeaderMapImpl{ {"foo_header", "part-0;bar=>bluh;foo=>foo_value"}, }); @@ -194,7 +193,7 @@ TEST(HeaderValueExtractorImplTest, ElementSeparatorEmpty) { )EOF"; TestUtility::loadFromYaml(yaml_plain, config); - HeaderValueExtractorImpl extractor(config); + HeaderValueExtractorImpl extractor(std::move(config)); std::unique_ptr fragment = extractor.computeFragment(TestHeaderMapImpl{ {"foo_header", "bar=b;c=d;e=f"}, }); @@ -265,7 +264,7 @@ TEST(ScopeKeyBuilderImplTest, Parse) { ScopedRoutes::ScopeKeyBuilder config; TestUtility::loadFromYaml(yaml_plain, config); - ScopeKeyBuilderImpl key_builder(config); + ScopeKeyBuilderImpl key_builder(std::move(config)); std::unique_ptr key = key_builder.computeScopeKey(TestHeaderMapImpl{ {"foo_header", "a=b,bar=bar_value,e=f"}, From 27ff0a3e1699a41c5c6c531b676bb6f603863277 Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Tue, 25 Jun 2019 10:51:53 -0400 Subject: [PATCH 11/21] switch from constructing proto memeber by value(copy-elision) to more explicit constructing by moving Signed-off-by: Xin Zhuang --- source/common/router/scoped_config_impl.h | 9 ++++----- source/common/router/scoped_rds.cc | 4 +++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/source/common/router/scoped_config_impl.h b/source/common/router/scoped_config_impl.h index 1fea085986cb..808b442838c4 100644 --- a/source/common/router/scoped_config_impl.h +++ b/source/common/router/scoped_config_impl.h @@ -111,7 +111,8 @@ class HeaderValueExtractorImpl : public FragmentBuilderBase { */ class ScopeKeyBuilderBase { public: - explicit ScopeKeyBuilderBase(ScopedRoutes::ScopeKeyBuilder&& config) : config_(config) {} + explicit ScopeKeyBuilderBase(ScopedRoutes::ScopeKeyBuilder&& config) + : config_(std::move(config)) {} virtual ~ScopeKeyBuilderBase() = default; // Computes scope key for given headers, returns nullptr if a key can't be computed. @@ -142,10 +143,8 @@ class ScopeKeyBuilderImpl : public ScopeKeyBuilderBase { */ class ThreadLocalScopedConfigImpl : public ScopedConfig, public ThreadLocal::ThreadLocalObject { public: - ThreadLocalScopedConfigImpl( - envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes::ScopeKeyBuilder&& - scope_key_builder) - : scope_key_builder_(scope_key_builder) {} + ThreadLocalScopedConfigImpl(ScopedRoutes::ScopeKeyBuilder&& scope_key_builder) + : scope_key_builder_(std::move(scope_key_builder)) {} void addOrUpdateRoutingScope(const ScopedRouteInfoConstSharedPtr& scoped_route_info); void removeRoutingScope(const std::string& scope_name); diff --git a/source/common/router/scoped_rds.cc b/source/common/router/scoped_rds.cc index d8ae81833c4c..86e1d1dc88b8 100644 --- a/source/common/router/scoped_rds.cc +++ b/source/common/router/scoped_rds.cc @@ -159,7 +159,9 @@ ScopedRdsConfigProvider::ScopedRdsConfigProvider( MutableConfigProviderCommonBase::subscription_.get())), rds_config_source_(std::move(rds_config_source)) { initialize([scope_key_builder](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { - return std::make_shared(std::move(scope_key_builder)); + return std::make_shared( + envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes::ScopeKeyBuilder( + scope_key_builder)); }); } From 467a6a198dadb4cae8a7661106feb06183eb3f6e Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Tue, 23 Jul 2019 22:46:06 -0400 Subject: [PATCH 12/21] refactor config provider framework Signed-off-by: Xin Zhuang --- source/common/config/config_provider_impl.cc | 61 +--- source/common/config/config_provider_impl.h | 289 +++++++----------- source/common/router/BUILD | 1 + source/common/router/scoped_config_impl.h | 2 +- source/common/router/scoped_rds.cc | 59 ++-- source/common/router/scoped_rds.h | 24 +- .../config/config_provider_impl_test.cc | 206 ++++++------- test/mocks/config/mocks.cc | 7 - test/mocks/config/mocks.h | 14 - 9 files changed, 238 insertions(+), 425 deletions(-) diff --git a/source/common/config/config_provider_impl.cc b/source/common/config/config_provider_impl.cc index ed209e8427ad..8deac8cae62e 100644 --- a/source/common/config/config_provider_impl.cc +++ b/source/common/config/config_provider_impl.cc @@ -23,24 +23,6 @@ ConfigSubscriptionCommonBase::~ConfigSubscriptionCommonBase() { init_target_.ready(); config_provider_manager_.unbindSubscription(manager_identifier_); } - -void ConfigSubscriptionCommonBase::bindConfigProvider(MutableConfigProviderCommonBase* provider) { - // All config providers bound to a ConfigSubscriptionCommonBase must be of the same concrete - // type; this is assumed by ConfigSubscriptionInstance::checkAndApplyConfigUpdate() and is - // verified by the assertion below. NOTE: an inlined statement ASSERT() triggers a potentially - // evaluated expression warning from clang due to `typeid(**mutable_config_providers_.begin())`. - // To avoid this, we use a lambda to separate the first mutable provider dereference from the - // typeid() statement. - ASSERT([&]() { - if (!mutable_config_providers_.empty()) { - const auto& first_provider = **mutable_config_providers_.begin(); - return typeid(*provider) == typeid(first_provider); - } - return true; - }()); - mutable_config_providers_.insert(provider); -} - bool ConfigSubscriptionInstance::checkAndApplyConfigUpdate(const Protobuf::Message& config_proto, const std::string& config_name, const std::string& version_info) { @@ -55,49 +37,12 @@ bool ConfigSubscriptionInstance::checkAndApplyConfigUpdate(const Protobuf::Messa config_info_ = {new_hash, version_info}; ENVOY_LOG(debug, "{}: loading new configuration: config_name={} hash={}", name_, config_name, new_hash); - - ASSERT(!mutable_config_providers_.empty()); - ConfigProvider::ConfigConstSharedPtr new_config; - for (auto* provider : mutable_config_providers_) { - // All bound mutable config providers must be of the same type (see the ASSERT... in - // bindConfigProvider()). - // This makes it safe to call any of the provider's onConfigProtoUpdate() to get a new config - // impl, which can then be passed to all providers. - auto* typed_provider = static_cast(provider); - if (new_config == nullptr) { - if ((new_config = typed_provider->onConfigProtoUpdate(config_proto)) == nullptr) { - return false; - } - } - typed_provider->onConfigUpdate(new_config); - } - + auto new_config_impl = onConfigProtoUpdate(config_proto); + applyConfigUpdate([new_config_impl](ConfigProvider::ConfigConstSharedPtr) + -> ConfigProvider::ConfigConstSharedPtr { return new_config_impl; }); return true; } -void DeltaConfigSubscriptionInstance::applyDeltaConfigUpdate( - const std::function& update_fn) { - // The Config implementation is assumed to be shared across the config providers bound to this - // subscription, therefore, simply propagating the update to all worker threads for a single bound - // provider will be sufficient. - if (mutable_config_providers_.size() > 1) { - ASSERT(static_cast(*mutable_config_providers_.begin()) - ->getConfig() == static_cast( - *std::next(mutable_config_providers_.begin())) - ->getConfig()); - } - - // TODO(AndresGuedez): currently, the caller has to compute the differences in resources between - // DS API config updates and passes a granular update_fn() that adds/modifies/removes resources as - // needed. Such logic could be generalized as part of this framework such that this function owns - // the diffing and issues the corresponding call to add/modify/remove a resource according to a - // vector of functions passed by the caller. - auto* typed_provider = - static_cast(getAnyBoundMutableConfigProvider()); - ConfigSharedPtr config = typed_provider->getConfig(); - typed_provider->onConfigUpdate([config, update_fn]() { update_fn(config); }); -} - ConfigProviderManagerImplBase::ConfigProviderManagerImplBase(Server::Admin& admin, const std::string& config_name) { config_tracker_entry_ = diff --git a/source/common/config/config_provider_impl.h b/source/common/config/config_provider_impl.h index 2553b3976e59..de914b0df7df 100644 --- a/source/common/config/config_provider_impl.h +++ b/source/common/config/config_provider_impl.h @@ -20,11 +20,11 @@ namespace Envoy { namespace Config { // This file provides a set of base classes, (ImmutableConfigProviderBase, -// MutableConfigProviderCommonBase, MutableConfigProviderBase, DeltaMutableConfigProviderBase, -// ConfigProviderManagerImplBase, ConfigSubscriptionCommonBase, ConfigSubscriptionInstance, -// DeltaConfigSubscriptionInstance), conforming to the ConfigProvider/ConfigProviderManager -// interfaces, which in tandem provide a framework for implementing statically defined (i.e., -// immutable) and dynamic (mutable via subscriptions) configuration for Envoy. +// MutableConfigProviderCommonBase, ConfigProviderManagerImplBase, ConfigSubscriptionCommonBase, +// ConfigSubscriptionInstance, DeltaConfigSubscriptionInstance), conforming to the +// ConfigProvider/ConfigProviderManager interfaces, which in tandem provide a framework for +// implementing statically defined (i.e., immutable) and dynamic (mutable via subscriptions) +// configuration for Envoy. // // The mutability property applies to the ConfigProvider itself and _not_ the underlying config // proto, which is always immutable. MutableConfigProviderCommonBase objects receive config proto @@ -58,11 +58,12 @@ namespace Config { // interface. // // For mutable (xDS) providers: -// 1) According to the API type, create a class derived from MutableConfigProviderBase or -// DeltaMutableConfigProviderBase and implement the required interface. -// 2) According to the API type, create a class derived from ConfigSubscriptionInstance or -// DeltaConfigSubscriptionInstance; this is the entity responsible for owning and managing the -// Envoy::Config::Subscription that provides the underlying config subscription. +// 1) According to the API type, create a class derived from MutableConfigProviderCommonBase and +// implement the required interface. +// 2) According to the API type, create a class derived from +// ConfigSubscriptionInstance or DeltaConfigSubscriptionInstance; this is the entity responsible +// for owning and managing the Envoy::Config::Subscription that provides the +// underlying config subscription, and the Config implemention shared by associated providers. // a) For a ConfigProvider::ApiType::Full subscription instance (i.e., a // ConfigSubscriptionInstance child): // - When subscription callbacks (onConfigUpdate, onConfigUpdateFailed) are issued by the @@ -78,8 +79,8 @@ namespace Config { // - When subscription callbacks (onConfigUpdate, onConfigUpdateFailed) are issued by the // underlying subscription, the corresponding ConfigSubscriptionInstance functions must be called // as well. -// - On a successful config update, applyConfigUpdate() should be called to propagate the config -// updates to all bound config providers and worker threads. +// - On a successful config update, applyConfigUpdate() should be called to propagate the +// config updates to all bound config providers and worker threads. class ConfigProviderManagerImplBase; @@ -130,12 +131,13 @@ class ImmutableConfigProviderBase : public ConfigProvider { class MutableConfigProviderCommonBase; /** - * Provides common DS API subscription functionality required by the ConfigProvider::ApiType - * specific base classes (see ConfigSubscriptionInstance and DeltaConfigSubscriptionInstance). + * Provides common DS API subscription functionality required by the ConfigProvider::ApiType. * - * To do so, this class keeps track of a set of MutableConfigProviderCommonBase instances associated - * with an underlying subscription; providers are bound/unbound as needed as they are created and - * destroyed. + * This class can not be instantiated directly; instead, it provides the foundation for + * config subscription implementations which derive from it. + * + * A subscription is supposed to be co-owned by config providers with the same config source, it's + * designed to be created/destructed on admin thread only. * * xDS config providers and subscriptions are split to avoid lifetime issues with arguments * required by the config providers. An example is the Server::Configuration::FactoryContext, which @@ -143,10 +145,10 @@ class MutableConfigProviderCommonBase; * in use (see #3960). This split enables single ownership of the config providers, while enabling * shared ownership of the underlying subscription. * - * This class can not be instantiated directly; instead, it provides the foundation for - * config subscription implementations which derive from it. */ -class ConfigSubscriptionCommonBase : protected Logger::Loggable { +class ConfigSubscriptionCommonBase + : protected Logger::Loggable, + public std::enable_shared_from_this { public: struct LastConfigInfo { absl::optional last_config_hash_; @@ -166,6 +168,10 @@ class ConfigSubscriptionCommonBase : protected Logger::Loggable& configInfo() const { return config_info_; } + ConfigProvider::ConfigConstSharedPtr getConfig() const { + return tls_->getTyped().config_; + } + /** * Must be called by derived classes when the onConfigUpdate() callback associated with the * underlying subscription is issued. @@ -184,25 +190,45 @@ class ConfigSubscriptionCommonBase : protected Logger::Loggable& update_fn, + Event::PostCb complete_cb = []() {}) { + // It is safe to call shared_from_this here as this is in main thread, and destruction of a + // ConfigSubscriptionCommonBase owner (i.e., a provider) happens in main thread as well. + auto shared_this = shared_from_this(); + tls_->runOnAllThreads( + [this, update_fn]() { + tls_->getTyped().config_ = update_fn(this->getConfig()); + }, + /*Make sure this subscription will not be teared down during the update propagation.*/ + [shared_this, complete_cb]() { complete_cb(); }); } void setLastUpdated() { last_updated_ = time_source_.systemTime(); } @@ -212,16 +238,12 @@ class ConfigSubscriptionCommonBase : protected Logger::Loggable mutable_config_providers_; absl::optional config_info_; + // This slot holds a Config implementation in each thread, which is shared between + // bound providers. + ThreadLocal::SlotPtr tls_; private: - void bindConfigProvider(MutableConfigProviderCommonBase* provider); - - void unbindConfigProvider(MutableConfigProviderCommonBase* provider) { - mutable_config_providers_.erase(provider); - } - Init::TargetImpl init_target_; const uint64_t manager_identifier_; ConfigProviderManagerImplBase& config_provider_manager_; @@ -235,28 +257,34 @@ class ConfigSubscriptionCommonBase : protected Logger::Loggables and // instead centralizing lifetime management in the ConfigProviderManagerImplBase with explicit // reference counting would be more maintainable. - friend class MutableConfigProviderCommonBase; - friend class MutableConfigProviderBase; - friend class DeltaMutableConfigProviderBase; friend class ConfigProviderManagerImplBase; - friend class MockMutableConfigProviderBase; }; using ConfigSubscriptionCommonBaseSharedPtr = std::shared_ptr; /** * Provides common subscription functionality required by ConfigProvider::ApiType::Full DS APIs. + * A single Config instance is shared across all providers and all workers associated with this + * subscription. */ class ConfigSubscriptionInstance : public ConfigSubscriptionCommonBase { -protected: +public: ConfigSubscriptionInstance(const std::string& name, const uint64_t manager_identifier, ConfigProviderManagerImplBase& config_provider_manager, - TimeSource& time_source, const SystemTime& last_updated, - const LocalInfo::LocalInfo& local_info) - : ConfigSubscriptionCommonBase(name, manager_identifier, config_provider_manager, time_source, - last_updated, local_info) {} + Server::Configuration::FactoryContext& factory_context) + : ConfigSubscriptionCommonBase(name, manager_identifier, config_provider_manager, + factory_context) {} - ~ConfigSubscriptionInstance() override = default; + /** + * Must be called by the derived class' constructor. + * @param initial_config supplies an initial Envoy::Config::ConfigProvider::Config associated with + * the underlying subscription, shared across all providers and workers. + */ + void initialize(const ConfigProvider::ConfigConstSharedPtr& initial_config) { + tls_->set([initial_config](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { + return std::make_shared(initial_config); + }); + } /** * Determines whether a configuration proto is a new update, and if so, propagates it to all @@ -268,43 +296,52 @@ class ConfigSubscriptionInstance : public ConfigSubscriptionCommonBase { */ bool checkAndApplyConfigUpdate(const Protobuf::Message& config_proto, const std::string& config_name, const std::string& version_info); -}; -using ConfigSharedPtr = std::shared_ptr; +protected: + /** + * Called when a new config proto is received via an xDS subscription. + * On successful validation of the config, must return a shared_ptr to a ConfigProvider::Config + * implementation that will be propagated to all mutable config providers sharing the + * subscription. + * Note that this function is called _once_ across all shared config providers per xDS + * subscription config update. + * @param config_proto supplies the configuration proto. + * @return ConfigConstSharedPtr the ConfigProvider::Config to share with other providers. + */ + virtual ConfigProvider::ConfigConstSharedPtr + onConfigProtoUpdate(const Protobuf::Message& config_proto) PURE; +}; /** * Provides common subscription functionality required by ConfigProvider::ApiType::Delta DS APIs. */ class DeltaConfigSubscriptionInstance : public ConfigSubscriptionCommonBase { protected: - DeltaConfigSubscriptionInstance(const std::string& name, const uint64_t manager_identifier, - ConfigProviderManagerImplBase& config_provider_manager, - TimeSource& time_source, const SystemTime& last_updated, - const LocalInfo::LocalInfo& local_info) - : ConfigSubscriptionCommonBase(name, manager_identifier, config_provider_manager, time_source, - last_updated, local_info) {} - + using ConfigSubscriptionCommonBase::ConfigSubscriptionCommonBase; ~DeltaConfigSubscriptionInstance() override = default; /** - * Propagates a config update to the config providers and worker threads associated with the - * subscription. - * - * @param update_fn the callback to run on each worker thread. + * Must be called by the derived class' constructor. + * @param init_cb supplies an initial Envoy::Config::ConfigProvider::Config associated with the + * underlying subscription for each worker thread. */ - void applyDeltaConfigUpdate(const std::function& update_fn); + void initialize(const std::function& init_cb) { + tls_->set([init_cb](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { + return std::make_shared(init_cb()); + }); + } }; /** * Provides generic functionality required by the ConfigProvider::ApiType specific dynamic config - * providers (see MutableConfigProviderBase and DeltaMutableConfigProviderBase). + * providers (see MutableConfigProviderBase for example). * * This class can not be instantiated directly; instead, it provides the foundation for * dynamic config provider implementations which derive from it. */ class MutableConfigProviderCommonBase : public ConfigProvider { public: - ~MutableConfigProviderCommonBase() override { subscription_->unbindConfigProvider(this); } + ~MutableConfigProviderCommonBase() override = default; // Envoy::Config::ConfigProvider SystemTime lastUpdated() const override { return subscription_->lastUpdated(); } @@ -312,126 +349,16 @@ class MutableConfigProviderCommonBase : public ConfigProvider { protected: MutableConfigProviderCommonBase(ConfigSubscriptionCommonBaseSharedPtr&& subscription, - Server::Configuration::FactoryContext& factory_context, ApiType api_type) - : tls_(factory_context.threadLocal().allocateSlot()), subscription_(subscription), - api_type_(api_type) {} - - ThreadLocal::SlotPtr tls_; - ConfigSubscriptionCommonBaseSharedPtr subscription_; + : subscription_(subscription), api_type_(api_type) {} -private: - ApiType api_type_; -}; - -/** - * Provides common mutable (dynamic) config provider functionality required by - * ConfigProvider::ApiType::Full DS APIs. - */ -class MutableConfigProviderBase : public MutableConfigProviderCommonBase { -public: // Envoy::Config::ConfigProvider - // NOTE: This is being promoted to public for internal uses to avoid an unnecessary dynamic_cast - // in the public API (ConfigProvider::config()). - ConfigConstSharedPtr getConfig() const override { - return tls_->getTyped().config_; - } - - /** - * Called when a new config proto is received via an xDS subscription. - * On successful validation of the config, must return a shared_ptr to a ConfigProvider::Config - * implementation that will be propagated to all mutable config providers sharing the - * subscription. - * Note that this function is called _once_ across all shared config providers per xDS - * subscription config update. - * @param config_proto supplies the configuration proto. - * @return ConfigConstSharedPtr the ConfigProvider::Config to share with other providers. - */ - virtual ConfigConstSharedPtr onConfigProtoUpdate(const Protobuf::Message& config_proto) PURE; - - /** - * Must be called by the derived class' constructor. - * @param initial_config supplies an initial Envoy::Config::ConfigProvider::Config associated with - * the underlying subscription. - */ - void initialize(const ConfigConstSharedPtr& initial_config) { - subscription_->bindConfigProvider(this); - tls_->set([initial_config](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { - return std::make_shared(initial_config); - }); - } - - /** - * Propagates a newly instantiated Envoy::Config::ConfigProvider::Config to all workers. - * @param config supplies the newly instantiated config. - */ - void onConfigUpdate(const ConfigConstSharedPtr& config) { - if (getConfig() == config) { - return; - } - tls_->runOnAllThreads( - [this, config]() -> void { tls_->getTyped().config_ = config; }); - } + ConfigConstSharedPtr getConfig() const override { return subscription_->getConfig(); } -protected: - MutableConfigProviderBase(ConfigSubscriptionCommonBaseSharedPtr&& subscription, - Server::Configuration::FactoryContext& factory_context, - ApiType api_type) - : MutableConfigProviderCommonBase(std::move(subscription), factory_context, api_type) {} - - ~MutableConfigProviderBase() override = default; + ConfigSubscriptionCommonBaseSharedPtr subscription_; private: - struct ThreadLocalConfig : public ThreadLocal::ThreadLocalObject { - ThreadLocalConfig(ConfigProvider::ConfigConstSharedPtr initial_config) - : config_(std::move(initial_config)) {} - - ConfigProvider::ConfigConstSharedPtr config_; - }; -}; - -/** - * Provides common mutable (dynamic) config provider functionality required by - * ConfigProvider::ApiType::Delta DS APIs. - */ -class DeltaMutableConfigProviderBase : public MutableConfigProviderCommonBase { -public: - // Envoy::Config::ConfigProvider - // This promotes getConfig() to public so that internal uses can avoid an unnecessary dynamic_cast - // in the public API (ConfigProvider::config()). - ConfigConstSharedPtr getConfig() const override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } - - /** - * Non-const overload for use within the framework. - * @return ConfigSharedPtr the config implementation associated with the provider. - */ - virtual ConfigSharedPtr getConfig() PURE; - - /** - * Propagates a delta config update to all workers. - * @param updateCb the callback to run on each worker. - */ - void onConfigUpdate(Envoy::Event::PostCb update_cb) { - tls_->runOnAllThreads(std::move(update_cb)); - } - -protected: - DeltaMutableConfigProviderBase(ConfigSubscriptionCommonBaseSharedPtr&& subscription, - Server::Configuration::FactoryContext& factory_context, - ApiType api_type) - : MutableConfigProviderCommonBase(std::move(subscription), factory_context, api_type) {} - - ~DeltaMutableConfigProviderBase() override = default; - - /** - * Must be called by the derived class' constructor. - * @param initializeCb supplies the initialization callback to be issued for each worker - * thread. - */ - void initialize(ThreadLocal::Slot::InitializeCb initializeCb) { - subscription_->bindConfigProvider(this); - tls_->set(std::move(initializeCb)); - } + ApiType api_type_; }; /** diff --git a/source/common/router/BUILD b/source/common/router/BUILD index 445cc2232673..b08e7c763fbb 100644 --- a/source/common/router/BUILD +++ b/source/common/router/BUILD @@ -175,6 +175,7 @@ envoy_cc_library( hdrs = ["scoped_rds.h"], deps = [ ":scoped_config_lib", + "//include/envoy/config:config_provider_interface", "//include/envoy/config:subscription_interface", "//include/envoy/stats:stats_interface", "//source/common/common:assert_lib", diff --git a/source/common/router/scoped_config_impl.h b/source/common/router/scoped_config_impl.h index 808b442838c4..9f7a02b75f99 100644 --- a/source/common/router/scoped_config_impl.h +++ b/source/common/router/scoped_config_impl.h @@ -141,7 +141,7 @@ class ScopeKeyBuilderImpl : public ScopeKeyBuilderBase { * ConnectionManagerImpl::refreshCachedRoute() will call getRouterConfig() to obtain the * Router::ConfigConstSharedPtr to use for route selection. */ -class ThreadLocalScopedConfigImpl : public ScopedConfig, public ThreadLocal::ThreadLocalObject { +class ThreadLocalScopedConfigImpl : public ScopedConfig { public: ThreadLocalScopedConfigImpl(ScopedRoutes::ScopeKeyBuilder&& scope_key_builder) : scope_key_builder_(std::move(scope_key_builder)) {} diff --git a/source/common/router/scoped_rds.cc b/source/common/router/scoped_rds.cc index 86e1d1dc88b8..9aa94a915a29 100644 --- a/source/common/router/scoped_rds.cc +++ b/source/common/router/scoped_rds.cc @@ -76,12 +76,13 @@ InlineScopedRoutesConfigProvider::InlineScopedRoutesConfigProvider( ScopedRdsConfigSubscription::ScopedRdsConfigSubscription( const envoy::config::filter::network::http_connection_manager::v2::ScopedRds& scoped_rds, const uint64_t manager_identifier, const std::string& name, + const envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes:: + ScopeKeyBuilder& scope_key_builder, Server::Configuration::FactoryContext& factory_context, const std::string& stat_prefix, ScopedRoutesConfigProviderManager& config_provider_manager) - : DeltaConfigSubscriptionInstance( - "SRDS", manager_identifier, config_provider_manager, factory_context.timeSource(), - factory_context.timeSource().systemTime(), factory_context.localInfo()), - name_(name), + : DeltaConfigSubscriptionInstance("SRDS", manager_identifier, config_provider_manager, + factory_context), + name_(name), scope_key_builder_(scope_key_builder), scope_(factory_context.scope().createScope(stat_prefix + "scoped_rds." + name + ".")), stats_({ALL_SCOPED_RDS_STATS(POOL_COUNTER(*scope_))}), validation_visitor_(factory_context.messageValidationVisitor()) { @@ -91,6 +92,12 @@ ScopedRdsConfigSubscription::ScopedRdsConfigSubscription( Grpc::Common::typeUrl( envoy::api::v2::ScopedRouteConfiguration().GetDescriptor()->full_name()), *scope_, *this); + + initialize([scope_key_builder]() -> Envoy::Config::ConfigProvider::ConfigConstSharedPtr { + return std::make_shared( + envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes::ScopeKeyBuilder( + scope_key_builder)); + }); } void ScopedRdsConfigSubscription::onConfigUpdate( @@ -124,10 +131,12 @@ void ScopedRdsConfigSubscription::onConfigUpdate( ScopedRouteInfoConstSharedPtr scoped_route_info = scoped_config_manager_.addOrUpdateRoutingScope(scoped_route, version_info); ENVOY_LOG(debug, "srds: add/update scoped_route '{}'", scoped_route_name); - applyDeltaConfigUpdate([scoped_route_info](const ConfigProvider::ConfigConstSharedPtr& config) { + applyConfigUpdate([scoped_route_info](const ConfigProvider::ConfigConstSharedPtr& config) + -> ConfigProvider::ConfigConstSharedPtr { auto* thread_local_scoped_config = const_cast( static_cast(config.get())); thread_local_scoped_config->addOrUpdateRoutingScope(scoped_route_info); + return config; }); } @@ -135,35 +144,28 @@ void ScopedRdsConfigSubscription::onConfigUpdate( const std::string scoped_route_name = scoped_route.first; ENVOY_LOG(debug, "srds: remove scoped route '{}'", scoped_route_name); scoped_config_manager_.removeRoutingScope(scoped_route_name); - applyDeltaConfigUpdate([scoped_route_name](const ConfigProvider::ConfigConstSharedPtr& config) { + applyConfigUpdate([scoped_route_name](const ConfigProvider::ConfigConstSharedPtr& config) + -> ConfigProvider::ConfigConstSharedPtr { + // In place update. auto* thread_local_scoped_config = const_cast( static_cast(config.get())); thread_local_scoped_config->removeRoutingScope(scoped_route_name); + return config; }); } - ConfigSubscriptionCommonBase::onConfigUpdate(); + DeltaConfigSubscriptionInstance::onConfigUpdate(); setLastConfigInfo(absl::optional({absl::nullopt, version_info})); stats_.config_reload_.inc(); } ScopedRdsConfigProvider::ScopedRdsConfigProvider( ScopedRdsConfigSubscriptionSharedPtr&& subscription, - Server::Configuration::FactoryContext& factory_context, - envoy::api::v2::core::ConfigSource rds_config_source, - const envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes:: - ScopeKeyBuilder& scope_key_builder) - : DeltaMutableConfigProviderBase(std::move(subscription), factory_context, - ConfigProvider::ApiType::Delta), + envoy::api::v2::core::ConfigSource rds_config_source) + : MutableConfigProviderCommonBase(std::move(subscription), ConfigProvider::ApiType::Delta), subscription_(static_cast( MutableConfigProviderCommonBase::subscription_.get())), - rds_config_source_(std::move(rds_config_source)) { - initialize([scope_key_builder](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { - return std::make_shared( - envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes::ScopeKeyBuilder( - scope_key_builder)); - }); -} + rds_config_source_(std::move(rds_config_source)) {} ProtobufTypes::MessagePtr ScopedRoutesConfigProviderManager::dumpConfigs() const { auto config_dump = std::make_unique(); @@ -207,28 +209,25 @@ ConfigProviderPtr ScopedRoutesConfigProviderManager::createXdsConfigProvider( const Protobuf::Message& config_source_proto, Server::Configuration::FactoryContext& factory_context, const std::string& stat_prefix, const ConfigProviderManager::OptionalArg& optarg) { + const auto& typed_optarg = static_cast(optarg); ScopedRdsConfigSubscriptionSharedPtr subscription = ConfigProviderManagerImplBase::getSubscription( config_source_proto, factory_context.initManager(), [&config_source_proto, &factory_context, &stat_prefix, - &optarg](const uint64_t manager_identifier, - ConfigProviderManagerImplBase& config_provider_manager) + &typed_optarg](const uint64_t manager_identifier, + ConfigProviderManagerImplBase& config_provider_manager) -> Envoy::Config::ConfigSubscriptionCommonBaseSharedPtr { const auto& scoped_rds_config_source = dynamic_cast< const envoy::config::filter::network::http_connection_manager::v2::ScopedRds&>( config_source_proto); return std::make_shared( - scoped_rds_config_source, manager_identifier, - static_cast(optarg) - .scoped_routes_name_, - factory_context, stat_prefix, + scoped_rds_config_source, manager_identifier, typed_optarg.scoped_routes_name_, + typed_optarg.scope_key_builder_, factory_context, stat_prefix, static_cast(config_provider_manager)); }); - const auto& typed_optarg = static_cast(optarg); - return std::make_unique(std::move(subscription), factory_context, - typed_optarg.rds_config_source_, - typed_optarg.scope_key_builder_); + return std::make_unique(std::move(subscription), + typed_optarg.rds_config_source_); } ConfigProviderPtr ScopedRoutesConfigProviderManager::createStaticConfigProvider( diff --git a/source/common/router/scoped_rds.h b/source/common/router/scoped_rds.h index f0cc72f71c15..725c3ec755ea 100644 --- a/source/common/router/scoped_rds.h +++ b/source/common/router/scoped_rds.h @@ -86,6 +86,8 @@ class ScopedRdsConfigSubscription : public Envoy::Config::DeltaConfigSubscriptio ScopedRdsConfigSubscription( const envoy::config::filter::network::http_connection_manager::v2::ScopedRds& scoped_rds, const uint64_t manager_identifier, const std::string& name, + const envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes:: + ScopeKeyBuilder& scope_key_builder, Server::Configuration::FactoryContext& factory_context, const std::string& stat_prefix, ScopedRoutesConfigProviderManager& config_provider_manager); @@ -98,7 +100,7 @@ class ScopedRdsConfigSubscription : public Envoy::Config::DeltaConfigSubscriptio } private: - // Envoy::Config::ConfigSubscriptionCommonBase + // Envoy::Config::DeltaConfigSubscriptionInstance void start() override { subscription_->start({}); } // Envoy::Config::SubscriptionCallbacks @@ -109,7 +111,7 @@ class ScopedRdsConfigSubscription : public Envoy::Config::DeltaConfigSubscriptio NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } void onConfigUpdateFailed(const EnvoyException*) override { - ConfigSubscriptionCommonBase::onConfigUpdateFailed(); + DeltaConfigSubscriptionInstance::onConfigUpdateFailed(); } std::string resourceName(const ProtobufWkt::Any& resource) override { return MessageUtil::anyConvert(resource, @@ -119,6 +121,8 @@ class ScopedRdsConfigSubscription : public Envoy::Config::DeltaConfigSubscriptio const std::string name_; std::unique_ptr subscription_; + const envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes::ScopeKeyBuilder + scope_key_builder_; Stats::ScopePtr scope_; ScopedRdsStats stats_; ScopedConfigManager scoped_config_manager_; @@ -129,25 +133,13 @@ using ScopedRdsConfigSubscriptionSharedPtr = std::shared_ptr(tls_->get()); - } - private: ScopedRdsConfigSubscription* subscription_; const envoy::api::v2::core::ConfigSource rds_config_source_; diff --git a/test/common/config/config_provider_impl_test.cc b/test/common/config/config_provider_impl_test.cc index 2b3e320a7a62..a7d631188a55 100644 --- a/test/common/config/config_provider_impl_test.cc +++ b/test/common/config/config_provider_impl_test.cc @@ -4,7 +4,6 @@ #include "common/protobuf/utility.h" #include "test/common/config/dummy_config.pb.h" -#include "test/mocks/config/mocks.h" #include "test/mocks/server/mocks.h" #include "test/test_common/simulated_time_system.h" #include "test/test_common/utility.h" @@ -20,6 +19,22 @@ using testing::InSequence; class DummyConfigProviderManager; +class DummyConfig : public Envoy::Config::ConfigProvider::Config { +public: + DummyConfig() {} + DummyConfig(const test::common::config::DummyConfig& config_proto) { + protos_.push_back(config_proto); + } + void addProto(const test::common::config::DummyConfig& config_proto) { + protos_.push_back(config_proto); + } + + uint32_t numProtos() const { return protos_.size(); } + +private: + std::vector protos_; +}; + class StaticDummyConfigProvider : public ImmutableConfigProviderBase { public: StaticDummyConfigProvider(const test::common::config::DummyConfig& config_proto, @@ -48,12 +63,18 @@ class DummyConfigSubscription : public ConfigSubscriptionInstance, DummyConfigSubscription(const uint64_t manager_identifier, Server::Configuration::FactoryContext& factory_context, DummyConfigProviderManager& config_provider_manager); - ~DummyConfigSubscription() override = default; // Envoy::Config::ConfigSubscriptionCommonBase void start() override {} + // Envoy::Config::ConfigSubscriptionInstance + ConfigProvider::ConfigConstSharedPtr + onConfigProtoUpdate(const Protobuf::Message& config_proto) override { + return std::make_shared( + static_cast(config_proto)); + } + // Envoy::Config::SubscriptionCallbacks void onConfigUpdate(const Protobuf::RepeatedPtrField& resources, const std::string& version_info) override { @@ -84,33 +105,17 @@ class DummyConfigSubscription : public ConfigSubscriptionInstance, }; using DummyConfigSubscriptionSharedPtr = std::shared_ptr; -class DummyConfig : public ConfigProvider::Config { +class DummyDynamicConfigProvider : public MutableConfigProviderCommonBase { public: - DummyConfig(const test::common::config::DummyConfig&) {} -}; - -class DummyDynamicConfigProvider : public MutableConfigProviderBase { -public: - DummyDynamicConfigProvider(DummyConfigSubscriptionSharedPtr&& subscription, - const ConfigConstSharedPtr& initial_config, - Server::Configuration::FactoryContext& factory_context) - : MutableConfigProviderBase(std::move(subscription), factory_context, ApiType::Full), + DummyDynamicConfigProvider(DummyConfigSubscriptionSharedPtr&& subscription) + : MutableConfigProviderCommonBase(std::move(subscription), ApiType::Full), subscription_(static_cast( - MutableConfigProviderCommonBase::subscription_.get())) { - initialize(initial_config); - } + MutableConfigProviderCommonBase::subscription_.get())) {} ~DummyDynamicConfigProvider() override = default; DummyConfigSubscription& subscription() { return *subscription_; } - // Envoy::Config::MutableConfigProviderBase - ConfigProvider::ConfigConstSharedPtr - onConfigProtoUpdate(const Protobuf::Message& config) override { - return std::make_shared( - static_cast(config)); - } - // Envoy::Config::ConfigProvider const Protobuf::Message* getConfigProto() const override { if (!subscription_->config_proto().has_value()) { @@ -177,14 +182,7 @@ class DummyConfigProviderManager : public ConfigProviderManagerImplBase { static_cast(config_provider_manager)); }); - ConfigProvider::ConfigConstSharedPtr initial_config; - const auto* provider = static_cast( - subscription->getAnyBoundMutableConfigProvider()); - if (provider) { - initial_config = provider->getConfig(); - } - return std::make_unique(std::move(subscription), initial_config, - factory_context); + return std::make_unique(std::move(subscription)); } // Envoy::Config::ConfigProviderManager @@ -204,6 +202,15 @@ class DummyConfigProviderManager : public ConfigProviderManagerImplBase { } }; +DummyConfigSubscription::DummyConfigSubscription( + const uint64_t manager_identifier, Server::Configuration::FactoryContext& factory_context, + DummyConfigProviderManager& config_provider_manager) + : ConfigSubscriptionInstance("DummyDS", manager_identifier, config_provider_manager, + factory_context) { + // Returns a null value. + initialize(nullptr); +} + StaticDummyConfigProvider::StaticDummyConfigProvider( const test::common::config::DummyConfig& config_proto, Server::Configuration::FactoryContext& factory_context, @@ -212,13 +219,6 @@ StaticDummyConfigProvider::StaticDummyConfigProvider( ConfigProviderInstanceType::Static, ApiType::Full), config_(std::make_shared(config_proto)), config_proto_(config_proto) {} -DummyConfigSubscription::DummyConfigSubscription( - const uint64_t manager_identifier, Server::Configuration::FactoryContext& factory_context, - DummyConfigProviderManager& config_provider_manager) - : ConfigSubscriptionInstance( - "DummyDS", manager_identifier, config_provider_manager, factory_context.timeSource(), - factory_context.timeSource().systemTime(), factory_context.localInfo()) {} - class ConfigProviderImplTest : public testing::Test { public: void initialize() { @@ -338,15 +338,14 @@ class DummyConfigProviderManagerMockConfigProvider : public DummyConfigProviderM manager_identifier, factory_context, static_cast(config_provider_manager)); }); - return std::make_unique(std::move(subscription), nullptr, - factory_context); + return std::make_unique(std::move(subscription)); } }; // Test that duplicate config updates will not trigger creation of a new ConfigProvider::Config. TEST_F(ConfigProviderImplTest, DuplicateConfigProto) { InSequence sequence; - // This provider manager returns a MockMutableConfigProviderBase. + // This provider manager returns a DummyDynamicConfigProvider. auto provider_manager = std::make_unique(factory_context_.admin_); envoy::api::v2::core::ApiConfigSource config_source_proto; @@ -354,18 +353,22 @@ TEST_F(ConfigProviderImplTest, DuplicateConfigProto) { ConfigProviderPtr provider = provider_manager->createXdsConfigProvider( config_source_proto, factory_context_, "dummy_prefix", ConfigProviderManager::NullOptionalArg()); - auto* typed_provider = static_cast(provider.get()); + auto* typed_provider = static_cast(provider.get()); DummyConfigSubscription& subscription = static_cast(typed_provider->subscription()); + EXPECT_EQ(subscription.getConfig(), nullptr); // First time issuing a configUpdate(). A new ConfigProvider::Config should be created. - EXPECT_CALL(*typed_provider, onConfigProtoUpdate(_)).Times(1); Protobuf::RepeatedPtrField untyped_dummy_configs; untyped_dummy_configs.Add()->PackFrom(parseDummyConfigFromYaml("a: a dynamic dummy config")); subscription.onConfigUpdate(untyped_dummy_configs, "1"); + EXPECT_NE(subscription.getConfig(), nullptr); + auto config_ptr = subscription.getConfig(); + EXPECT_EQ(typed_provider->config().get(), config_ptr.get()); // Second time issuing the configUpdate(), this time with a duplicate proto. A new // ConfigProvider::Config _should not_ be created. - EXPECT_CALL(*typed_provider, onConfigProtoUpdate(_)).Times(0); - subscription.onConfigUpdate(untyped_dummy_configs, "1"); + subscription.onConfigUpdate(untyped_dummy_configs, "2"); + EXPECT_EQ(config_ptr, subscription.getConfig()); + EXPECT_EQ(typed_provider->config().get(), config_ptr.get()); } // An empty config provider tests on base class' constructor. @@ -518,7 +521,31 @@ class DeltaDummyConfigSubscription : public DeltaConfigSubscriptionInstance, // Envoy::Config::SubscriptionCallbacks void onConfigUpdate(const Protobuf::RepeatedPtrField& resources, - const std::string& version_info) override; + const std::string& version_info) override { + if (resources.empty()) { + return; + } + + // For simplicity, there is no logic here to track updates and/or removals to the existing + // config proto set (i.e., this is append only). Real xDS APIs will need to track additions, + // updates and removals to the config set and apply the diffs to the underlying config + // implementations. + for (const auto& resource_any : resources) { + auto dummy_config = TestUtility::anyConvert(resource_any); + proto_map_[version_info] = dummy_config; + // Propagate the new config proto to all worker threads. + applyConfigUpdate([&dummy_config](ConfigProvider::ConfigConstSharedPtr prev_config) + -> ConfigProvider::ConfigConstSharedPtr { + auto* config = const_cast(static_cast(prev_config.get())); + // Per above, append only for now. + config->addProto(dummy_config); + return prev_config; + }); + } + + ConfigSubscriptionCommonBase::onConfigUpdate(); + setLastConfigInfo(absl::optional({absl::nullopt, version_info})); + } void onConfigUpdate(const Protobuf::RepeatedPtrField&, const Protobuf::RepeatedPtrField&, const std::string&) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; @@ -537,32 +564,12 @@ class DeltaDummyConfigSubscription : public DeltaConfigSubscriptionInstance, }; using DeltaDummyConfigSubscriptionSharedPtr = std::shared_ptr; -class ThreadLocalDummyConfig : public ThreadLocal::ThreadLocalObject, - public Envoy::Config::ConfigProvider::Config { +class DeltaDummyDynamicConfigProvider : public Envoy::Config::MutableConfigProviderCommonBase { public: - void addProto(const test::common::config::DummyConfig& config_proto) { - protos_.push_back(config_proto); - } - - uint32_t numProtos() const { return protos_.size(); } - -private: - std::vector protos_; -}; - -class DeltaDummyDynamicConfigProvider : public Envoy::Config::DeltaMutableConfigProviderBase { -public: - DeltaDummyDynamicConfigProvider(DeltaDummyConfigSubscriptionSharedPtr&& subscription, - Server::Configuration::FactoryContext& factory_context, - std::shared_ptr dummy_config) - : DeltaMutableConfigProviderBase(std::move(subscription), factory_context, - ConfigProvider::ApiType::Delta), + DeltaDummyDynamicConfigProvider(DeltaDummyConfigSubscriptionSharedPtr&& subscription) + : MutableConfigProviderCommonBase(std::move(subscription), ConfigProvider::ApiType::Delta), subscription_(static_cast( - MutableConfigProviderCommonBase::subscription_.get())) { - initialize([&dummy_config](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { - return (dummy_config != nullptr) ? dummy_config : std::make_shared(); - }); - } + MutableConfigProviderCommonBase::subscription_.get())) {} DeltaDummyConfigSubscription& subscription() { return *subscription_; } @@ -574,23 +581,12 @@ class DeltaDummyDynamicConfigProvider : public Envoy::Config::DeltaMutableConfig } return proto_vector; } + std::string getConfigVersion() const override { return (subscription_->configInfo().has_value()) ? subscription_->configInfo().value().last_config_version_ : ""; } - ConfigConstSharedPtr getConfig() const override { - return std::dynamic_pointer_cast(tls_->get()); - } - - // Envoy::Config::DeltaMutableConfigProviderBase - ConfigSharedPtr getConfig() override { - return std::dynamic_pointer_cast(tls_->get()); - } - - std::shared_ptr getThreadLocalDummyConfig() { - return std::dynamic_pointer_cast(tls_->get()); - } private: DeltaDummyConfigSubscription* subscription_; @@ -632,6 +628,7 @@ class DeltaDummyConfigProviderManager : public ConfigProviderManagerImplBase { const std::string&, const Envoy::Config::ConfigProviderManager::OptionalArg&) override { DeltaDummyConfigSubscriptionSharedPtr subscription = + getSubscription( config_source_proto, factory_context.initManager(), [&factory_context](const uint64_t manager_identifier, @@ -642,44 +639,17 @@ class DeltaDummyConfigProviderManager : public ConfigProviderManagerImplBase { static_cast(config_provider_manager)); }); - auto* existing_provider = static_cast( - subscription->getAnyBoundMutableConfigProvider()); - return std::make_unique( - std::move(subscription), factory_context, - (existing_provider != nullptr) ? existing_provider->getThreadLocalDummyConfig() : nullptr); + return std::make_unique(std::move(subscription)); } }; DeltaDummyConfigSubscription::DeltaDummyConfigSubscription( const uint64_t manager_identifier, Server::Configuration::FactoryContext& factory_context, DeltaDummyConfigProviderManager& config_provider_manager) - : DeltaConfigSubscriptionInstance( - "Dummy", manager_identifier, config_provider_manager, factory_context.timeSource(), - factory_context.timeSource().systemTime(), factory_context.localInfo()) {} - -void DeltaDummyConfigSubscription::onConfigUpdate( - const Protobuf::RepeatedPtrField& resources, - const std::string& version_info) { - if (resources.empty()) { - return; - } - - // For simplicity, there is no logic here to track updates and/or removals to the existing config - // proto set (i.e., this is append only). Real xDS APIs will need to track additions, updates and - // removals to the config set and apply the diffs to the underlying config implementations. - for (const auto& resource_any : resources) { - auto dummy_config = TestUtility::anyConvert(resource_any); - proto_map_[version_info] = dummy_config; - // Propagate the new config proto to all worker threads. - applyDeltaConfigUpdate([&dummy_config](const ConfigSharedPtr& config) { - auto* thread_local_dummy_config = static_cast(config.get()); - // Per above, append only for now. - thread_local_dummy_config->addProto(dummy_config); - }); - } - - ConfigSubscriptionCommonBase::onConfigUpdate(); - setLastConfigInfo(absl::optional({absl::nullopt, version_info})); + : DeltaConfigSubscriptionInstance("Dummy", manager_identifier, config_provider_manager, + factory_context) { + initialize( + []() -> ConfigProvider::ConfigConstSharedPtr { return std::make_shared(); }); } class DeltaConfigProviderImplTest : public testing::Test { @@ -721,7 +691,7 @@ TEST_F(DeltaConfigProviderImplTest, MultipleDeltaSubscriptions) { config_source_proto, factory_context_, "dummy_prefix", ConfigProviderManager::NullOptionalArg()); - // Providers, config implementations (i.e., the ThreadLocalDummyConfig) and config protos are + // Providers, config implementations (i.e., the DummyConfig) and config protos are // expected to be shared for a given subscription. EXPECT_EQ(&dynamic_cast(*provider1).subscription(), &dynamic_cast(*provider2).subscription()); @@ -729,17 +699,17 @@ TEST_F(DeltaConfigProviderImplTest, MultipleDeltaSubscriptions) { EXPECT_EQ( provider1->configProtoInfoVector().value().config_protos_, provider2->configProtoInfoVector().value().config_protos_); - EXPECT_EQ(provider1->config().get(), - provider2->config().get()); + EXPECT_EQ(provider1->config().get(), + provider2->config().get()); // Validate that the config protos are propagated to the thread local config implementation. - EXPECT_EQ(provider1->config()->numProtos(), 2); + EXPECT_EQ(provider1->config()->numProtos(), 2); // Issue a second config update to validate that having multiple providers bound to the // subscription causes a single update to the underlying shared config implementation. subscription.onConfigUpdate(untyped_dummy_configs, "2"); // NOTE: the config implementation is append only and _does not_ track updates/removals to the // config proto set, so the expectation is to double the size of the set. - EXPECT_EQ(provider1->config()->numProtos(), 4); + EXPECT_EQ(provider1->config()->numProtos(), 4); EXPECT_EQ(provider1->configProtoInfoVector().value().version_, "2"); } diff --git a/test/mocks/config/mocks.cc b/test/mocks/config/mocks.cc index c5bee0ccb920..4a3e3099e0c1 100644 --- a/test/mocks/config/mocks.cc +++ b/test/mocks/config/mocks.cc @@ -47,12 +47,5 @@ MockGrpcMuxCallbacks::MockGrpcMuxCallbacks() { MockGrpcMuxCallbacks::~MockGrpcMuxCallbacks() = default; -MockMutableConfigProviderBase::MockMutableConfigProviderBase( - std::shared_ptr&& subscription, - ConfigProvider::ConfigConstSharedPtr, Server::Configuration::FactoryContext& factory_context) - : MutableConfigProviderBase(std::move(subscription), factory_context, ApiType::Full) { - subscription_->bindConfigProvider(this); -} - } // namespace Config } // namespace Envoy diff --git a/test/mocks/config/mocks.h b/test/mocks/config/mocks.h index 8396fff4fc31..fbcd624a1e1a 100644 --- a/test/mocks/config/mocks.h +++ b/test/mocks/config/mocks.h @@ -109,20 +109,6 @@ class MockGrpcStreamCallbacks : public GrpcStreamCallbacks&& subscription, - ConfigProvider::ConfigConstSharedPtr initial_config, - Server::Configuration::FactoryContext& factory_context); - - MOCK_CONST_METHOD0(getConfig, ConfigConstSharedPtr()); - MOCK_METHOD1(onConfigProtoUpdate, ConfigConstSharedPtr(const Protobuf::Message& config_proto)); - MOCK_METHOD1(initialize, void(const ConfigConstSharedPtr& initial_config)); - MOCK_METHOD1(onConfigUpdate, void(const ConfigConstSharedPtr& config)); - - ConfigSubscriptionCommonBase& subscription() { return *subscription_.get(); } -}; - class MockConfigProviderManager : public ConfigProviderManager { public: MockConfigProviderManager() = default; From 7dea1a079610b5483fd76c93951a470db046c9d7 Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Wed, 24 Jul 2019 09:39:35 -0400 Subject: [PATCH 13/21] some renames and stale comment fix Signed-off-by: Xin Zhuang --- source/common/config/config_provider_impl.h | 2 +- source/common/router/scoped_config_impl.cc | 7 +++---- source/common/router/scoped_config_impl.h | 4 ++-- source/common/router/scoped_rds.cc | 12 ++++++------ test/common/config/config_provider_impl_test.cc | 2 +- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/source/common/config/config_provider_impl.h b/source/common/config/config_provider_impl.h index de914b0df7df..d60b4cd83e80 100644 --- a/source/common/config/config_provider_impl.h +++ b/source/common/config/config_provider_impl.h @@ -334,7 +334,7 @@ class DeltaConfigSubscriptionInstance : public ConfigSubscriptionCommonBase { /** * Provides generic functionality required by the ConfigProvider::ApiType specific dynamic config - * providers (see MutableConfigProviderBase for example). + * providers. * * This class can not be instantiated directly; instead, it provides the foundation for * dynamic config provider implementations which derive from it. diff --git a/source/common/router/scoped_config_impl.cc b/source/common/router/scoped_config_impl.cc index ee3ce1318568..f5c8007f9e74 100644 --- a/source/common/router/scoped_config_impl.cc +++ b/source/common/router/scoped_config_impl.cc @@ -104,12 +104,11 @@ ScopeKeyBuilderImpl::computeScopeKey(const Http::HeaderMap& headers) const { return std::make_unique(std::move(key)); } -void ThreadLocalScopedConfigImpl::addOrUpdateRoutingScope(const ScopedRouteInfoConstSharedPtr&) {} +void ScopedConfigImpl::addOrUpdateRoutingScope(const ScopedRouteInfoConstSharedPtr&) {} -void ThreadLocalScopedConfigImpl::removeRoutingScope(const std::string&) {} +void ScopedConfigImpl::removeRoutingScope(const std::string&) {} -Router::ConfigConstSharedPtr -ThreadLocalScopedConfigImpl::getRouteConfig(const Http::HeaderMap&) const { +Router::ConfigConstSharedPtr ScopedConfigImpl::getRouteConfig(const Http::HeaderMap&) const { return std::make_shared(); } diff --git a/source/common/router/scoped_config_impl.h b/source/common/router/scoped_config_impl.h index 9f7a02b75f99..184929f94664 100644 --- a/source/common/router/scoped_config_impl.h +++ b/source/common/router/scoped_config_impl.h @@ -141,9 +141,9 @@ class ScopeKeyBuilderImpl : public ScopeKeyBuilderBase { * ConnectionManagerImpl::refreshCachedRoute() will call getRouterConfig() to obtain the * Router::ConfigConstSharedPtr to use for route selection. */ -class ThreadLocalScopedConfigImpl : public ScopedConfig { +class ScopedConfigImpl : public ScopedConfig { public: - ThreadLocalScopedConfigImpl(ScopedRoutes::ScopeKeyBuilder&& scope_key_builder) + ScopedConfigImpl(ScopedRoutes::ScopeKeyBuilder&& scope_key_builder) : scope_key_builder_(std::move(scope_key_builder)) {} void addOrUpdateRoutingScope(const ScopedRouteInfoConstSharedPtr& scoped_route_info); diff --git a/source/common/router/scoped_rds.cc b/source/common/router/scoped_rds.cc index 9aa94a915a29..e30ea4296b7c 100644 --- a/source/common/router/scoped_rds.cc +++ b/source/common/router/scoped_rds.cc @@ -68,7 +68,7 @@ InlineScopedRoutesConfigProvider::InlineScopedRoutesConfigProvider( ConfigProviderInstanceType::Inline, ConfigProvider::ApiType::Delta), name_(std::move(name)), - config_(std::make_shared(std::move(scope_key_builder))), + config_(std::make_shared(std::move(scope_key_builder))), config_protos_(std::make_move_iterator(config_protos.begin()), std::make_move_iterator(config_protos.end())), rds_config_source_(std::move(rds_config_source)) {} @@ -94,7 +94,7 @@ ScopedRdsConfigSubscription::ScopedRdsConfigSubscription( *scope_, *this); initialize([scope_key_builder]() -> Envoy::Config::ConfigProvider::ConfigConstSharedPtr { - return std::make_shared( + return std::make_shared( envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes::ScopeKeyBuilder( scope_key_builder)); }); @@ -133,8 +133,8 @@ void ScopedRdsConfigSubscription::onConfigUpdate( ENVOY_LOG(debug, "srds: add/update scoped_route '{}'", scoped_route_name); applyConfigUpdate([scoped_route_info](const ConfigProvider::ConfigConstSharedPtr& config) -> ConfigProvider::ConfigConstSharedPtr { - auto* thread_local_scoped_config = const_cast( - static_cast(config.get())); + auto* thread_local_scoped_config = + const_cast(static_cast(config.get())); thread_local_scoped_config->addOrUpdateRoutingScope(scoped_route_info); return config; }); @@ -147,8 +147,8 @@ void ScopedRdsConfigSubscription::onConfigUpdate( applyConfigUpdate([scoped_route_name](const ConfigProvider::ConfigConstSharedPtr& config) -> ConfigProvider::ConfigConstSharedPtr { // In place update. - auto* thread_local_scoped_config = const_cast( - static_cast(config.get())); + auto* thread_local_scoped_config = + const_cast(static_cast(config.get())); thread_local_scoped_config->removeRoutingScope(scoped_route_name); return config; }); diff --git a/test/common/config/config_provider_impl_test.cc b/test/common/config/config_provider_impl_test.cc index a7d631188a55..b887c3787b83 100644 --- a/test/common/config/config_provider_impl_test.cc +++ b/test/common/config/config_provider_impl_test.cc @@ -318,7 +318,7 @@ TEST_F(ConfigProviderImplTest, SharedOwnership) { .size()); } -// A ConfigProviderManager that returns a mock ConfigProvider. +// A ConfigProviderManager that returns a dummy ConfigProvider. class DummyConfigProviderManagerMockConfigProvider : public DummyConfigProviderManager { public: DummyConfigProviderManagerMockConfigProvider(Server::Admin& admin) From 86c455e94b70f6a228a6bc85862f847bedbc8584 Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Mon, 29 Jul 2019 23:45:04 -0400 Subject: [PATCH 14/21] fixes for review feedbacks Signed-off-by: Xin Zhuang --- source/common/config/config_provider_impl.cc | 2 +- source/common/config/config_provider_impl.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/common/config/config_provider_impl.cc b/source/common/config/config_provider_impl.cc index 8deac8cae62e..11cbf993e51c 100644 --- a/source/common/config/config_provider_impl.cc +++ b/source/common/config/config_provider_impl.cc @@ -37,7 +37,7 @@ bool ConfigSubscriptionInstance::checkAndApplyConfigUpdate(const Protobuf::Messa config_info_ = {new_hash, version_info}; ENVOY_LOG(debug, "{}: loading new configuration: config_name={} hash={}", name_, config_name, new_hash); - auto new_config_impl = onConfigProtoUpdate(config_proto); + ConfigProvider::ConfigConstSharedPtr new_config_impl = onConfigProtoUpdate(config_proto); applyConfigUpdate([new_config_impl](ConfigProvider::ConfigConstSharedPtr) -> ConfigProvider::ConfigConstSharedPtr { return new_config_impl; }); return true; diff --git a/source/common/config/config_provider_impl.h b/source/common/config/config_provider_impl.h index d60b4cd83e80..5e808aff067f 100644 --- a/source/common/config/config_provider_impl.h +++ b/source/common/config/config_provider_impl.h @@ -136,7 +136,7 @@ class MutableConfigProviderCommonBase; * This class can not be instantiated directly; instead, it provides the foundation for * config subscription implementations which derive from it. * - * A subscription is supposed to be co-owned by config providers with the same config source, it's + * A subscription is intended to be co-owned by config providers with the same config source, it's * designed to be created/destructed on admin thread only. * * xDS config providers and subscriptions are split to avoid lifetime issues with arguments @@ -239,8 +239,8 @@ class ConfigSubscriptionCommonBase const std::string name_; absl::optional config_info_; - // This slot holds a Config implementation in each thread, which is shared between - // bound providers. + // This slot holds a Config implementation in each thread, which is intended to be shared between + // config providers from the same config source. ThreadLocal::SlotPtr tls_; private: From 60dd4336b3fab95dee4617d28281e87c36e3af27 Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Tue, 30 Jul 2019 09:53:50 -0400 Subject: [PATCH 15/21] fix comment Signed-off-by: Xin Zhuang --- test/common/config/config_provider_impl_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common/config/config_provider_impl_test.cc b/test/common/config/config_provider_impl_test.cc index b887c3787b83..f75e1b06dadc 100644 --- a/test/common/config/config_provider_impl_test.cc +++ b/test/common/config/config_provider_impl_test.cc @@ -207,7 +207,7 @@ DummyConfigSubscription::DummyConfigSubscription( DummyConfigProviderManager& config_provider_manager) : ConfigSubscriptionInstance("DummyDS", manager_identifier, config_provider_manager, factory_context) { - // Returns a null value. + // A nullptr is shared as the initial value. initialize(nullptr); } From dad2d5922ef13a9d51f175a894fc78e964fa225e Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Tue, 30 Jul 2019 10:46:32 -0400 Subject: [PATCH 16/21] snowp comment, merge with upstream master Signed-off-by: Xin Zhuang --- .azure-pipelines/linux.yml | 55 +- .azure-pipelines/macos.yml | 2 +- .bazelci/presubmit.yml | 7 +- .bazelrc | 60 +- .bazelversion | 1 + .circleci/config.yml | 40 +- .clang-tidy | 8 + CODEOWNERS | 4 + DEVELOPER.md | 4 +- GOVERNANCE.md | 10 +- ISSUE_TEMPLATE.md | 4 + README.md | 2 +- SECURITY_RELEASE_PROCESS.md => SECURITY.md | 0 WORKSPACE | 19 +- api/bazel/api_build_system.bzl | 45 +- api/bazel/repositories.bzl | 176 +-- api/bazel/repository_locations.bzl | 10 +- api/envoy/admin/v2alpha/BUILD | 1 + api/envoy/admin/v2alpha/config_dump.proto | 48 +- api/envoy/api/v2/BUILD | 2 + api/envoy/api/v2/cds.proto | 11 +- api/envoy/api/v2/cluster/BUILD | 13 + api/envoy/api/v2/cluster/filter.proto | 30 + api/envoy/api/v2/core/BUILD | 6 +- api/envoy/api/v2/core/base.proto | 27 +- api/envoy/api/v2/core/config_source.proto | 3 +- api/envoy/config/bootstrap/v2/bootstrap.proto | 4 + .../config/filter/http/fault/v2/fault.proto | 24 + .../http/transcoder/v2/transcoder.proto | 6 + api/envoy/config/trace/v2/trace.proto | 3 +- api/envoy/service/tap/v2alpha/BUILD | 1 - api/envoy/service/tap/v2alpha/common.proto | 1 - bazel/BUILD | 21 + bazel/README.md | 6 +- bazel/api_binding.bzl | 36 + bazel/api_repositories.bzl | 35 +- bazel/cc_configure.bzl | 79 -- bazel/cc_wrapper.py | 128 -- bazel/dependency_imports.bzl | 12 + bazel/envoy_binary.bzl | 38 +- bazel/envoy_build_system.bzl | 9 +- bazel/envoy_internal.bzl | 10 +- bazel/envoy_library.bzl | 4 +- bazel/envoy_test.bzl | 7 +- bazel/external/gcovr.BUILD | 24 - bazel/external/quiche.BUILD | 183 +++ bazel/foreign_cc/BUILD | 20 - .../foreign_cc/com_lightstep_tracer_cpp.patch | 2 +- bazel/foreign_cc/io_opencensus_cpp.patch | 11 - bazel/repositories.bzl | 39 +- bazel/repository_locations.bzl | 42 +- bazel/toolchains/BUILD | 17 + bazel/toolchains/README.md | 13 + bazel/toolchains/configs/.gitignore | 2 + .../configs/clang/bazel_0.28.0/cc/BUILD | 148 ++ .../cc/armeabi_cc_toolchain_config.bzl | 82 ++ .../bazel_0.28.0/cc/cc_toolchain_config.bzl | 1202 +++++++++++++++++ .../clang/bazel_0.28.0/cc/cc_wrapper.sh | 25 + .../configs/clang/bazel_0.28.0/config/BUILD | 53 + .../configs/clang/bazel_0.28.0/java/BUILD | 25 + .../configs/gcc/bazel_0.28.0/cc/BUILD | 148 ++ .../cc/armeabi_cc_toolchain_config.bzl | 82 ++ .../bazel_0.28.0/cc/cc_toolchain_config.bzl | 1202 +++++++++++++++++ .../configs/gcc/bazel_0.28.0/cc/cc_wrapper.sh | 25 + .../configs/gcc/bazel_0.28.0/config/BUILD | 53 + .../configs/gcc/bazel_0.28.0/java/BUILD | 25 + bazel/toolchains/configs/versions.bzl | 17 + bazel/toolchains/empty.bzl | 18 + bazel/toolchains/rbe_toolchains_config.bzl | 80 ++ bazel/toolchains/regenerate.sh | 12 + ci/WORKSPACE.filter.example | 20 +- ci/build_container/build_container_centos.sh | 8 - ci/build_container/build_container_common.sh | 21 +- ci/build_container/build_container_ubuntu.sh | 8 +- ci/build_container/docker_push.sh | 88 +- ci/build_setup.sh | 24 +- ci/coverage_publish.sh | 4 +- ci/do_ci.sh | 48 +- ci/do_circle_ci.sh | 5 +- ci/do_circle_ci_ipv6_tests.sh | 25 - ci/filter_example_mirror.sh | 9 +- ci/mac_ci_setup.sh | 3 +- ci/mac_ci_steps.sh | 4 +- ci/run_clang_tidy.sh | 9 +- ci/run_envoy_docker.sh | 8 +- ci/setup_cache.sh | 9 +- configs/configgen.sh | 6 +- configs/envoy_double_proxy_v2.template.yaml | 17 +- configs/envoy_front_proxy_v2.template.yaml | 17 +- .../envoy_service_to_service_v2.template.yaml | 17 +- docs/build.sh | 1 + docs/root/api-v2/clusters/clusters.rst | 1 + .../http_filters/router_filter.rst | 6 +- .../listener_filters/http_inspector.rst | 38 + .../listener_filters/listener_filters.rst | 1 + docs/root/faq/transient_failures.rst | 2 +- .../intro/arch_overview/operations/init.rst | 18 +- .../load_balancing/panic_threshold.rst | 9 +- .../intro/arch_overview/upstream/upstream.rst | 1 + .../upstream/upstream_filters.rst | 11 + docs/root/intro/version_history.rst | 12 + docs/root/operations/admin.rst | 11 +- examples/BUILD | 1 + examples/lua/Dockerfile-proxy | 1 + examples/lua/envoy.yaml | 4 +- examples/lua/lib/mylibrary.lua | 7 + include/envoy/event/dispatcher.h | 6 + include/envoy/http/BUILD | 1 + include/envoy/http/conn_pool.h | 2 + include/envoy/http/filter.h | 6 + include/envoy/network/address.h | 6 + include/envoy/router/router.h | 1 + include/envoy/runtime/runtime.h | 12 +- include/envoy/server/BUILD | 1 + include/envoy/server/admin.h | 1 + include/envoy/server/configuration.h | 5 + include/envoy/server/filter_config.h | 157 ++- include/envoy/server/hot_restart.h | 2 +- include/envoy/server/lifecycle_notifier.h | 3 + include/envoy/server/options.h | 7 + include/envoy/stats/BUILD | 2 +- .../{stat_data_allocator.h => allocator.h} | 5 +- include/envoy/stats/scope.h | 11 +- include/envoy/stats/stats.h | 5 +- include/envoy/thread_local/thread_local.h | 10 + include/envoy/upstream/upstream.h | 5 + repokitteh.star | 7 + security/email-templates.md | 4 +- source/common/access_log/BUILD | 54 +- source/common/access_log/access_log_impl.cc | 4 +- source/common/access_log/access_log_impl.h | 2 +- .../access_log/access_log_manager_impl.h | 2 +- source/common/api/BUILD | 2 + source/common/common/assert.cc | 2 +- source/common/common/logger.h | 1 + source/common/config/BUILD | 53 +- source/common/config/address_json.cc | 26 - source/common/config/address_json.h | 11 - source/common/config/cds_json.cc | 223 --- source/common/config/cds_json.h | 71 - source/common/config/config_provider_impl.h | 7 +- source/common/config/datasource.h | 73 + .../common/config/delta_subscription_state.h | 2 +- source/common/config/grpc_mux_impl.h | 2 +- source/common/config/remote_data_fetcher.cc | 75 + source/common/config/remote_data_fetcher.h | 82 ++ source/common/config/tls_context_json.cc | 70 - source/common/config/tls_context_json.h | 37 - source/common/config/utility.cc | 2 +- source/common/event/dispatcher_impl.h | 6 +- .../posix/directory_iterator_impl.h | 7 +- source/common/grpc/codec.cc | 2 +- source/common/grpc/google_async_client_impl.h | 8 +- source/common/grpc/typed_async_client.h | 4 +- source/common/http/BUILD | 4 + source/common/http/async_client_impl.h | 12 +- source/common/http/codec_client.h | 2 +- source/common/http/conn_manager_impl.cc | 20 +- source/common/http/conn_manager_impl.h | 1 + source/common/http/conn_pool_base.cc | 17 +- source/common/http/conn_pool_base.h | 3 + source/common/http/header_utility.cc | 22 + source/common/http/header_utility.h | 18 + source/common/http/headers.h | 1 + source/common/http/http1/BUILD | 3 + source/common/http/http1/codec_impl.cc | 25 +- source/common/http/http1/codec_impl.h | 8 +- source/common/http/http1/conn_pool.cc | 1 + source/common/http/http2/codec_impl.h | 2 +- source/common/http/http2/conn_pool.h | 4 +- source/common/http/http2/metadata_decoder.h | 7 - source/common/json/BUILD | 6 - source/common/json/json_validator.h | 21 - source/common/memory/BUILD | 1 + source/common/memory/heap_shrinker.cc | 5 +- source/common/network/address_impl.h | 1 + source/common/network/cidr_range.cc | 8 +- source/common/network/io_socket_error_impl.h | 2 +- .../common/network/io_socket_handle_impl.cc | 3 +- source/common/network/listen_socket_impl.h | 2 +- source/common/protobuf/utility.h | 6 +- source/common/router/BUILD | 1 + source/common/router/config_impl.cc | 16 +- source/common/router/config_impl.h | 23 +- source/common/router/config_utility.h | 3 +- source/common/router/header_parser.cc | 3 +- source/common/router/header_parser.h | 2 +- source/common/router/rds_impl.h | 2 +- source/common/router/retry_state_impl.cc | 10 +- source/common/router/retry_state_impl.h | 2 +- source/common/router/router.cc | 12 + source/common/router/router.h | 7 +- source/common/runtime/runtime_features.cc | 10 +- source/common/runtime/runtime_impl.cc | 30 +- source/common/runtime/runtime_impl.h | 6 +- source/common/secret/BUILD | 1 + source/common/secret/sds_api.cc | 13 +- source/common/secret/sds_api.h | 25 +- source/common/secret/secret_manager_impl.cc | 99 ++ source/common/secret/secret_manager_impl.h | 16 + source/common/signal/signal_action.h | 4 +- source/common/stats/BUILD | 10 +- .../{heap_stat_data.cc => allocator_impl.cc} | 29 +- .../{heap_stat_data.h => allocator_impl.h} | 12 +- source/common/stats/histogram_impl.h | 4 +- source/common/stats/isolated_store_impl.cc | 3 +- source/common/stats/isolated_store_impl.h | 20 +- source/common/stats/metric_impl.h | 2 +- source/common/stats/scope_prefixer.cc | 12 +- source/common/stats/scope_prefixer.h | 9 +- source/common/stats/stat_merger.cc | 3 +- source/common/stats/stats_matcher_impl.h | 4 +- source/common/stats/symbol_table_impl.h | 4 +- source/common/stats/tag_extractor_impl.cc | 3 +- source/common/stats/tag_producer_impl.h | 2 +- source/common/stats/thread_local_store.cc | 18 +- source/common/stats/thread_local_store.h | 30 +- source/common/tcp/conn_pool.h | 10 +- source/common/tcp_proxy/tcp_proxy.h | 4 +- .../common/thread_local/thread_local_impl.cc | 6 +- .../common/thread_local/thread_local_impl.h | 5 +- source/common/upstream/BUILD | 4 +- source/common/upstream/cluster_factory_impl.h | 2 +- .../common/upstream/cluster_manager_impl.cc | 1 - source/common/upstream/cluster_manager_impl.h | 4 +- .../upstream/health_checker_base_impl.h | 2 +- source/common/upstream/health_checker_impl.cc | 2 + .../upstream/health_discovery_service.cc | 6 +- source/common/upstream/load_balancer_impl.cc | 10 +- source/common/upstream/load_balancer_impl.h | 4 +- .../common/upstream/original_dst_cluster.cc | 5 +- .../common/upstream/outlier_detection_impl.h | 2 +- .../common/upstream/resource_manager_impl.h | 2 +- source/common/upstream/upstream_impl.cc | 91 +- source/common/upstream/upstream_impl.h | 24 +- source/exe/main_common.h | 2 +- source/extensions/access_loggers/common/BUILD | 23 + .../access_loggers/common/access_log_base.cc | 34 + .../access_loggers/common/access_log_base.h | 55 + source/extensions/access_loggers/file/BUILD | 3 +- .../file/file_access_log_impl.cc | 31 +- .../file/file_access_log_impl.h | 15 +- .../extensions/access_loggers/http_grpc/BUILD | 2 +- .../access_loggers/http_grpc/config.cc | 18 +- .../http_grpc/grpc_access_log_impl.cc | 196 +-- .../http_grpc/grpc_access_log_impl.h | 137 +- .../clusters/dynamic_forward_proxy/cluster.cc | 4 +- .../common/dynamic_forward_proxy/dns_cache.h | 5 + .../dynamic_forward_proxy/dns_cache_impl.cc | 42 +- .../dynamic_forward_proxy/dns_cache_impl.h | 12 +- .../dns_cache_manager_impl.h | 4 +- source/extensions/extensions_build_config.bzl | 10 +- .../common/ext_authz/ext_authz_grpc_impl.h | 2 +- .../common/ext_authz/ext_authz_http_impl.h | 2 +- .../original_src/original_src_socket_option.h | 2 +- .../extensions/filters/common/ratelimit/BUILD | 9 + .../filters/common/ratelimit/ratelimit_impl.h | 2 +- .../filters/common/ratelimit/stat_names.h | 30 + .../common/aws/credentials_provider_impl.h | 2 +- .../filters/http/common/jwks_fetcher.cc | 11 +- source/extensions/filters/http/dynamo/BUILD | 23 +- .../extensions/filters/http/dynamo/config.cc | 8 +- .../filters/http/dynamo/dynamo_filter.cc | 69 +- .../filters/http/dynamo/dynamo_filter.h | 10 +- .../http/dynamo/dynamo_request_parser.cc | 18 + .../http/dynamo/dynamo_request_parser.h | 13 +- .../filters/http/dynamo/dynamo_stats.cc | 109 ++ .../filters/http/dynamo/dynamo_stats.h | 73 + .../filters/http/dynamo/dynamo_utility.cc | 27 - .../filters/http/dynamo/dynamo_utility.h | 32 - .../filters/http/fault/fault_filter.cc | 33 +- .../filters/http/fault/fault_filter.h | 40 +- .../json_transcoder_filter.cc | 4 + .../json_transcoder_filter.h | 1 + .../transcoder_input_stream_impl.h | 4 +- source/extensions/filters/http/gzip/BUILD | 2 - .../filters/http/gzip/gzip_filter.h | 2 - .../header_to_metadata_filter.h | 2 +- .../http/ip_tagging/ip_tagging_filter.cc | 2 +- .../http/ip_tagging/ip_tagging_filter.h | 2 +- .../extensions/filters/http/jwt_authn/BUILD | 3 + .../filters/http/jwt_authn/authenticator.cc | 10 +- .../filters/http/jwt_authn/filter.cc | 8 +- .../filters/http/jwt_authn/filter.h | 2 +- .../filters/http/jwt_authn/filter_config.h | 8 +- .../filters/http/jwt_authn/jwks_cache.cc | 2 +- .../filters/http/jwt_authn/matcher.cc | 2 +- .../extensions/filters/http/ratelimit/BUILD | 1 + .../filters/http/ratelimit/ratelimit.cc | 9 +- .../filters/http/ratelimit/ratelimit.h | 5 +- .../filters/http/squash/squash_filter.cc | 2 +- source/extensions/filters/http/tap/BUILD | 1 + .../extensions/filters/http/tap/tap_filter.h | 1 + .../filters/listener/http_inspector/BUILD | 41 + .../filters/listener/http_inspector/config.cc | 43 + .../listener/http_inspector/http_inspector.cc | 189 +++ .../listener/http_inspector/http_inspector.h | 84 ++ .../http_inspector/http_protocol_header.h | 65 + .../listener/proxy_protocol/proxy_protocol.cc | 2 +- .../filters/listener/well_known_names.h | 2 + .../network/common/redis/client_impl.h | 4 +- .../filters/network/dubbo_proxy/BUILD | 36 +- .../network/dubbo_proxy/active_message.cc | 364 ++--- .../network/dubbo_proxy/active_message.h | 152 ++- .../network/dubbo_proxy/app_exception.cc | 29 - .../network/dubbo_proxy/app_exception.h | 38 +- .../filters/network/dubbo_proxy/config.cc | 36 +- .../filters/network/dubbo_proxy/config.h | 3 +- .../network/dubbo_proxy/conn_manager.cc | 38 +- .../network/dubbo_proxy/conn_manager.h | 15 +- .../filters/network/dubbo_proxy/decoder.cc | 134 +- .../filters/network/dubbo_proxy/decoder.h | 125 +- .../dubbo_proxy/decoder_event_handler.h | 113 +- .../network/dubbo_proxy/deserializer_impl.cc | 9 - .../network/dubbo_proxy/deserializer_impl.h | 23 - .../dubbo_hessian2_serializer_impl.cc | 118 ++ .../dubbo_hessian2_serializer_impl.h | 30 + .../dubbo_proxy/dubbo_protocol_impl.cc | 105 +- .../network/dubbo_proxy/dubbo_protocol_impl.h | 14 +- .../filters/network/dubbo_proxy/filters/BUILD | 2 +- .../network/dubbo_proxy/filters/filter.h | 124 +- .../network/dubbo_proxy/heartbeat_response.cc | 10 +- .../network/dubbo_proxy/heartbeat_response.h | 4 +- .../dubbo_proxy/hessian_deserializer_impl.cc | 111 -- .../dubbo_proxy/hessian_deserializer_impl.h | 27 - .../filters/network/dubbo_proxy/message.h | 97 +- .../network/dubbo_proxy/message_impl.h | 65 + .../filters/network/dubbo_proxy/metadata.h | 105 +- .../filters/network/dubbo_proxy/protocol.h | 103 +- .../network/dubbo_proxy/protocol_constants.h | 98 ++ .../filters/network/dubbo_proxy/router/BUILD | 17 +- .../network/dubbo_proxy/router/config.cc | 3 +- .../network/dubbo_proxy/router/route.h | 121 ++ .../dubbo_proxy/router/route_matcher.cc | 59 +- .../dubbo_proxy/router/route_matcher.h | 19 +- .../network/dubbo_proxy/router/router.h | 3 + .../network/dubbo_proxy/router/router_impl.cc | 71 +- .../network/dubbo_proxy/router/router_impl.h | 15 +- .../filters/network/dubbo_proxy/serializer.h | 128 ++ .../network/dubbo_proxy/serializer_impl.cc | 48 + .../network/dubbo_proxy/serializer_impl.h | 64 + .../filters/network/ext_authz/ext_authz.h | 2 +- .../extensions/filters/network/kafka/codec.h | 2 +- .../filters/network/kafka/serialization.h | 4 +- .../filters/network/mongo_proxy/bson_impl.h | 2 +- .../filters/network/mongo_proxy/proxy.h | 2 +- .../filters/network/rbac/rbac_filter.h | 2 +- .../redis_proxy/command_splitter_impl.h | 6 +- .../network/redis_proxy/conn_pool_impl.h | 2 +- .../network/redis_proxy/proxy_filter.h | 4 +- .../thrift_proxy/compact_protocol_impl.h | 2 +- .../network/thrift_proxy/conn_manager.cc | 2 +- .../network/thrift_proxy/conn_manager.h | 4 +- .../thrift_proxy/filters/ratelimit/BUILD | 1 + .../filters/ratelimit/ratelimit.cc | 9 +- .../filters/ratelimit/ratelimit.h | 9 +- .../thrift_proxy/framed_transport_impl.h | 2 +- .../filters/network/thrift_proxy/metadata.h | 5 +- .../thrift_proxy/router/router_impl.cc | 2 +- .../network/thrift_proxy/thrift_object_impl.h | 4 +- .../filters/network/thrift_proxy/tracing.h | 8 +- .../thrift_proxy/twitter_protocol_impl.cc | 2 +- .../thrift_proxy/unframed_transport_impl.h | 2 +- .../grpc_credentials/example/config.h | 2 +- .../extensions/health_checkers/redis/redis.h | 2 +- source/extensions/quic_listeners/quiche/BUILD | 1 + .../quic_listeners/quiche/envoy_quic_alarm.cc | 6 +- .../quic_listeners/quiche/envoy_quic_alarm.h | 7 +- .../quiche/envoy_quic_alarm_factory.cc | 6 +- .../quiche/envoy_quic_alarm_factory.h | 8 +- .../quic_listeners/quiche/platform/BUILD | 2 +- .../quiche/platform/envoy_quic_clock.cc | 6 +- .../quiche/platform/envoy_quic_clock.h | 6 +- .../quiche/platform/quic_logging_impl.cc | 10 +- .../quiche/platform/quic_logging_impl.h | 2 +- .../stat_sinks/common/statsd/statsd.h | 4 +- .../extensions/tracers/common/factory_base.h | 4 +- .../tracers/datadog/datadog_tracer_impl.cc | 4 +- .../tracers/lightstep/lightstep_tracer_impl.h | 2 +- .../extensions/tracers/opencensus/config.cc | 2 +- .../opencensus/opencensus_tracer_impl.cc | 11 +- .../opencensus/opencensus_tracer_impl.h | 5 +- .../extensions/tracers/zipkin/span_buffer.h | 2 +- .../extensions/tracers/zipkin/span_context.h | 12 +- .../tracers/zipkin/span_context_extractor.cc | 2 +- .../tracers/zipkin/zipkin_core_types.h | 4 +- .../transport_sockets/alts/config.cc | 2 +- .../transport_sockets/alts/tsi_handshaker.h | 2 +- .../transport_sockets/alts/tsi_socket.h | 2 +- source/extensions/transport_sockets/tls/BUILD | 2 +- .../tls/context_config_impl.cc | 12 - .../tls/context_config_impl.h | 3 - .../transport_sockets/tls/context_impl.cc | 38 +- .../tls/context_manager_impl.h | 2 +- source/server/BUILD | 8 +- source/server/config_validation/admin.cc | 1 + source/server/config_validation/admin.h | 1 + source/server/config_validation/connection.h | 2 +- source/server/config_validation/server.cc | 2 +- source/server/configuration_impl.cc | 7 + source/server/configuration_impl.h | 2 + source/server/hot_restart_impl.h | 2 +- source/server/hot_restart_nop_impl.h | 2 +- source/server/http/admin.cc | 3 +- source/server/http/admin.h | 5 +- source/server/http/config_tracker_impl.h | 2 +- source/server/listener_manager_impl.h | 19 +- source/server/options_impl.h | 10 +- source/server/overload_manager_impl.cc | 4 +- source/server/server.cc | 49 +- source/server/server.h | 1 + test/common/common/lock_guard_test.cc | 6 +- .../compressor/zlib_compressor_impl_test.cc | 2 +- test/common/config/BUILD | 16 +- .../config/config_provider_impl_test.cc | 7 +- test/common/config/datasource_test.cc | 379 ++++++ .../config/delta_subscription_impl_test.cc | 2 +- .../config/delta_subscription_test_harness.h | 2 +- .../filesystem_subscription_impl_test.cc | 8 +- .../filesystem_subscription_test_harness.h | 10 +- .../config/grpc_subscription_impl_test.cc | 24 +- .../config/http_subscription_impl_test.cc | 20 +- .../config/http_subscription_test_harness.h | 2 +- test/common/config/metadata_test.cc | 5 +- .../config/subscription_factory_impl_test.cc | 6 +- test/common/config/subscription_impl_test.cc | 46 +- .../common/config/subscription_test_harness.h | 27 +- test/common/config/utility_test.cc | 33 +- test/common/event/dispatcher_impl_test.cc | 42 +- .../grpc/grpc_client_integration_test.cc | 2 +- .../grpc_client_integration_test_harness.h | 2 +- test/common/http/BUILD | 1 + test/common/http/async_client_impl_test.cc | 15 + test/common/http/codec_client_test.cc | 2 +- ...ized-codec_impl_fuzz_test-5107763548520448 | 1 + test/common/http/codec_impl_fuzz_test.cc | 2 +- test/common/http/common.h | 2 +- test/common/http/conn_manager_impl_test.cc | 2 +- test/common/http/header_map_impl_test.cc | 19 + test/common/http/header_utility_test.cc | 39 + test/common/http/http1/BUILD | 4 + test/common/http/http1/codec_impl_test.cc | 87 ++ test/common/http/http1/conn_pool_test.cc | 36 +- test/common/http/http2/conn_pool_test.cc | 2 +- test/common/network/address_impl_test.cc | 14 +- test/common/network/connection_impl_test.cc | 14 +- test/common/network/dns_impl_test.cc | 3 +- .../network/filter_manager_impl_test.cc | 2 +- test/common/router/config_impl_test.cc | 14 +- test/common/router/header_formatter_test.cc | 17 + ...e-header_parser_fuzz_test-5163306626580480 | 80 ++ test/common/router/rds_impl_test.cc | 6 +- test/common/router/retry_state_impl_test.cc | 13 + test/common/router/router_test.cc | 12 +- .../common/router/router_upstream_log_test.cc | 1 + test/common/runtime/runtime_impl_test.cc | 61 +- test/common/secret/BUILD | 1 + test/common/secret/sds_api_test.cc | 46 +- .../common/secret/secret_manager_impl_test.cc | 378 +++++- test/common/signal/signals_test.cc | 5 +- test/common/singleton/manager_impl_test.cc | 2 +- .../singleton/threadsafe_singleton_test.cc | 2 +- test/common/stats/BUILD | 8 +- ...locator_test.cc => allocator_impl_test.cc} | 14 +- test/common/stats/metric_impl_test.cc | 6 +- test/common/stats/stat_merger_test.cc | 4 +- test/common/stats/stat_test_utility.cc | 25 +- test/common/stats/tag_producer_impl_test.cc | 2 +- .../stats/thread_local_store_speed_test.cc | 4 +- test/common/stats/thread_local_store_test.cc | 16 +- .../stream_info/filter_state_impl_test.cc | 2 +- test/common/tcp/conn_pool_test.cc | 8 +- test/common/tcp_proxy/tcp_proxy_test.cc | 2 +- .../thread_local/thread_local_impl_test.cc | 2 +- test/common/upstream/BUILD | 3 +- .../upstream/cluster_manager_impl_test.cc | 66 +- test/common/upstream/eds_test.cc | 6 +- .../upstream/health_checker_impl_test.cc | 39 +- .../upstream/load_balancer_impl_test.cc | 15 + .../upstream/logical_dns_cluster_test.cc | 105 +- .../upstream/original_dst_cluster_test.cc | 31 +- test/common/upstream/upstream_impl_test.cc | 225 ++- test/common/upstream/utility.h | 9 - test/config/integration/BUILD | 2 - .../certs/upstreamlocalhostcert.cfg | 4 +- .../certs/upstreamlocalhostcert.pem | 36 +- .../certs/upstreamlocalhostcert_hash.h | 4 +- .../certs/upstreamlocalhostkey.pem | 50 +- test/config/integration/server.json | 526 -------- test/config/integration/server.yaml | 358 +---- test/config/integration/server_ads.yaml | 25 - .../integration/server_unix_listener.yaml | 30 +- test/config/utility.cc | 10 + test/coverage/gcc_only_test/BUILD | 16 - test/coverage/gcc_only_test/gcc_only_test.cc | 12 - test/coverage/gen_build.sh | 17 +- test/exe/main_common_test.cc | 18 +- test/extensions/access_loggers/common/BUILD | 19 + .../common/access_log_base_test.cc | 57 + .../http_grpc/grpc_access_log_impl_test.cc | 743 +++++----- .../dynamic_forward_proxy/cluster_test.cc | 1 + test/extensions/clusters/redis/mocks.h | 2 +- .../redis/redis_cluster_integration_test.cc | 18 +- .../dns_cache_impl_test.cc | 129 +- .../common/dynamic_forward_proxy/mocks.h | 13 +- test/extensions/common/tap/admin_test.cc | 4 +- test/extensions/common/tap/common.h | 4 +- .../filters/common/ext_authz/mocks.h | 4 +- .../extensions/filters/common/lua/lua_test.cc | 2 +- .../filters/common/lua/wrappers_test.cc | 4 +- .../filters/common/ratelimit/mocks.h | 2 +- .../common/ratelimit/ratelimit_impl_test.cc | 2 +- .../aws/credentials_provider_impl_test.cc | 8 +- .../filters/http/common/aws/mocks.cc | 8 +- .../filters/http/common/aws/mocks.h | 6 +- .../common/aws/region_provider_impl_test.cc | 2 +- test/extensions/filters/http/common/mock.h | 2 +- .../proxy_filter_integration_test.cc | 25 + .../proxy_filter_test.cc | 2 +- test/extensions/filters/http/dynamo/BUILD | 6 +- .../filters/http/dynamo/dynamo_filter_test.cc | 7 +- ...o_utility_test.cc => dynamo_stats_test.cc} | 27 +- .../filters/http/fault/fault_filter_test.cc | 36 + .../grpc_json_transcoder_integration_test.cc | 34 +- .../json_transcoder_filter_test.cc | 20 +- .../http/ip_tagging/ip_tagging_filter_test.cc | 2 +- .../http/jwt_authn/filter_integration_test.cc | 3 +- .../filters/http/jwt_authn/filter_test.cc | 64 +- test/extensions/filters/http/jwt_authn/mock.h | 2 +- .../filters/http/lua/lua_filter_test.cc | 2 +- .../filters/http/lua/lua_integration_test.cc | 7 +- .../filters/http/ratelimit/ratelimit_test.cc | 4 +- .../filters/http/rbac/rbac_filter_test.cc | 2 +- .../filters/listener/http_inspector/BUILD | 43 + .../http_inspector_config_test.cc | 52 + .../http_inspector/http_inspector_test.cc | 425 ++++++ .../tls_inspector/tls_inspector_test.cc | 2 +- .../client_ssl_auth/client_ssl_auth_test.cc | 2 +- .../network/common/redis/client_impl_test.cc | 2 +- .../filters/network/common/redis/mocks.h | 10 +- .../filters/network/dubbo_proxy/BUILD | 16 +- .../network/dubbo_proxy/app_exception_test.cc | 33 +- .../network/dubbo_proxy/conn_manager_test.cc | 385 +++--- .../network/dubbo_proxy/decoder_test.cc | 262 ++-- ...=> dubbo_hessian2_serializer_impl_test.cc} | 90 +- .../dubbo_proxy/dubbo_protocol_impl_test.cc | 94 +- .../network/dubbo_proxy/metadata_test.cc | 62 +- .../filters/network/dubbo_proxy/mocks.cc | 62 +- .../filters/network/dubbo_proxy/mocks.h | 218 ++- .../network/dubbo_proxy/route_matcher_test.cc | 196 ++- .../network/dubbo_proxy/router_test.cc | 113 +- .../network/ext_authz/ext_authz_test.cc | 2 +- .../network/http_connection_manager/BUILD | 3 + .../http_connection_manager/config_test.cc | 71 + .../kafka/kafka_request_parser_test.cc | 2 +- .../kafka/kafka_response_parser_test.cc | 2 +- .../network/kafka/serialization_utilities.h | 6 +- .../network/ratelimit/ratelimit_test.cc | 2 +- .../redis_proxy/command_lookup_speed_test.cc | 2 +- .../filters/network/redis_proxy/mocks.cc | 22 +- .../filters/network/redis_proxy/mocks.h | 12 +- .../filters/ratelimit/ratelimit_test.cc | 2 +- .../header_transport_impl_test.cc | 4 +- .../filters/network/thrift_proxy/mocks.cc | 42 +- .../filters/network/thrift_proxy/mocks.h | 30 +- ...le_based_metadata_grpc_credentials_test.cc | 2 +- test/extensions/quic_listeners/quiche/BUILD | 12 + .../quiche/crypto_test_utils_for_envoy.cc | 39 + .../quiche/envoy_quic_alarm_test.cc | 23 +- .../quic_listeners/quiche/platform/BUILD | 1 + .../quiche/platform/envoy_quic_clock_test.cc | 9 +- .../quiche/platform/quic_epoll_clock.h | 2 +- .../quiche/platform/quic_mock_log_impl.h | 6 +- .../quiche/platform/quic_platform_test.cc | 16 +- .../fixed_heap/fixed_heap_monitor_test.cc | 2 +- .../grpc_metrics_service_impl_test.cc | 2 +- test/extensions/tracers/opencensus/BUILD | 1 + .../tracers/opencensus/config_test.cc | 1 - .../tracers/opencensus/tracer_test.cc | 21 +- test/extensions/tracers/zipkin/tracer_test.cc | 2 +- .../noop_transport_socket_callbacks_test.cc | 2 +- test/extensions/transport_sockets/tls/BUILD | 4 + .../tls/context_impl_test.cc | 12 +- .../transport_sockets/tls/ssl_socket_test.cc | 50 + test/fuzz/utility.h | 21 +- test/integration/BUILD | 51 +- test/integration/ads_integration.cc | 280 ++++ test/integration/ads_integration.h | 71 + test/integration/ads_integration_test.cc | 316 +---- test/integration/autonomous_upstream.h | 4 +- .../cluster_filter_integration_test.cc | 131 ++ test/integration/fake_upstream.h | 2 +- .../filters/add_trailers_filter.cc | 7 +- .../filters/clear_route_cache_filter.cc | 3 +- test/integration/filters/common.h | 3 +- test/integration/filters/eds_ready_filter.cc | 3 +- .../filters/modify_buffer_filter.cc | 7 +- test/integration/filters/pause_filter.cc | 3 +- .../filters/process_context_filter.h | 2 +- .../filters/random_pause_filter.cc | 3 +- .../filters/request_metadata_filter.cc | 3 +- .../filters/response_metadata_filter.cc | 3 +- .../stop_iteration_and_continue_filter.cc | 58 +- test/integration/http2_integration_test.cc | 22 + test/integration/http_integration.h | 2 +- test/integration/integration_admin_test.cc | 9 +- test/integration/protocol_integration_test.cc | 22 + test/integration/run_envoy_test.sh | 2 +- .../sds_dynamic_integration_test.cc | 4 +- test/integration/server.cc | 2 +- test/integration/server.h | 16 +- test/integration/stats_integration_test.cc | 6 +- test/integration/tcp_dump.cc | 2 +- test/integration/utility.cc | 2 +- test/integration/xfcc_integration_test.cc | 39 +- test/mocks/access_log/mocks.cc | 14 +- test/mocks/access_log/mocks.h | 8 +- test/mocks/api/mocks.cc | 6 +- test/mocks/api/mocks.h | 4 +- test/mocks/buffer/mocks.cc | 4 +- test/mocks/buffer/mocks.h | 2 +- test/mocks/common.cc | 8 +- test/mocks/common.h | 7 +- test/mocks/config/mocks.h | 2 +- test/mocks/event/mocks.cc | 10 +- test/mocks/event/mocks.h | 9 +- test/mocks/filesystem/mocks.cc | 2 +- test/mocks/grpc/mocks.cc | 16 +- test/mocks/grpc/mocks.h | 10 +- test/mocks/http/conn_pool.h | 4 +- test/mocks/http/mocks.cc | 2 + test/mocks/http/mocks.h | 38 +- test/mocks/http/stream.cc | 2 +- test/mocks/http/stream_decoder.cc | 4 +- test/mocks/http/stream_encoder.cc | 2 +- test/mocks/http/stream_encoder.h | 2 +- test/mocks/local_info/mocks.cc | 2 +- test/mocks/local_info/mocks.h | 2 +- test/mocks/network/connection.cc | 10 +- test/mocks/network/connection.h | 8 +- test/mocks/network/mocks.cc | 84 +- test/mocks/network/mocks.h | 65 +- test/mocks/protobuf/mocks.cc | 4 +- test/mocks/protobuf/mocks.h | 2 +- test/mocks/router/mocks.cc | 48 +- test/mocks/router/mocks.h | 32 +- test/mocks/runtime/mocks.cc | 10 +- test/mocks/runtime/mocks.h | 9 +- test/mocks/secret/mocks.cc | 6 +- test/mocks/secret/mocks.h | 4 +- test/mocks/server/BUILD | 1 + test/mocks/server/mocks.cc | 7 +- test/mocks/server/mocks.h | 23 +- test/mocks/ssl/mocks.cc | 20 +- test/mocks/ssl/mocks.h | 10 +- test/mocks/stats/mocks.h | 7 +- test/mocks/stream_info/mocks.cc | 2 +- test/mocks/stream_info/mocks.h | 2 +- test/mocks/tcp/mocks.cc | 12 +- test/mocks/tcp/mocks.h | 8 +- test/mocks/thread_local/mocks.h | 6 +- test/mocks/tracing/mocks.cc | 14 +- test/mocks/tracing/mocks.h | 8 +- test/mocks/upstream/cluster_info.cc | 6 +- test/mocks/upstream/cluster_info.h | 7 +- test/mocks/upstream/host.cc | 18 +- test/mocks/upstream/host.h | 12 +- test/mocks/upstream/load_balancer_context.h | 2 +- test/mocks/upstream/mocks.h | 36 +- test/run_envoy_bazel_coverage.sh | 103 +- test/server/BUILD | 4 +- test/server/configuration_impl_test.cc | 44 + test/server/filter_chain_benchmark_test.cc | 5 +- test/server/guarddog_impl_test.cc | 4 +- test/server/http/admin_test.cc | 12 +- test/server/http/config_tracker_impl_test.cc | 2 +- test/server/listener_manager_impl_test.cc | 142 +- ...e_bootstrap_with_admin_socket_options.yaml | 19 + test/server/options_impl_test.cc | 9 + test/server/server_test.cc | 103 +- test/test_common/environment.cc | 8 + test/test_common/logging.cc | 2 +- test/test_common/logging.h | 2 +- test/test_common/simulated_time_system.cc | 2 +- test/test_common/test_time_system.h | 2 +- test/tools/router_check/router.h | 4 +- tools/check_format.py | 43 +- tools/check_format_test_helper.py | 19 +- tools/envoy_build_fixer.py | 2 +- tools/format_python_tools.sh | 4 +- tools/spelling_dictionary.txt | 2 + .../check_format/counter_from_string.cc | 7 + .../check_format/gauge_from_string.cc | 7 + .../check_format/histogram_from_string.cc | 7 + 694 files changed, 14072 insertions(+), 6821 deletions(-) create mode 100644 .bazelversion rename SECURITY_RELEASE_PROCESS.md => SECURITY.md (100%) create mode 100644 api/envoy/api/v2/cluster/filter.proto create mode 100644 bazel/api_binding.bzl delete mode 100644 bazel/cc_configure.bzl delete mode 100755 bazel/cc_wrapper.py create mode 100644 bazel/dependency_imports.bzl delete mode 100644 bazel/external/gcovr.BUILD delete mode 100644 bazel/foreign_cc/io_opencensus_cpp.patch create mode 100644 bazel/toolchains/BUILD create mode 100644 bazel/toolchains/README.md create mode 100644 bazel/toolchains/configs/.gitignore create mode 100755 bazel/toolchains/configs/clang/bazel_0.28.0/cc/BUILD create mode 100755 bazel/toolchains/configs/clang/bazel_0.28.0/cc/armeabi_cc_toolchain_config.bzl create mode 100755 bazel/toolchains/configs/clang/bazel_0.28.0/cc/cc_toolchain_config.bzl create mode 100755 bazel/toolchains/configs/clang/bazel_0.28.0/cc/cc_wrapper.sh create mode 100644 bazel/toolchains/configs/clang/bazel_0.28.0/config/BUILD create mode 100644 bazel/toolchains/configs/clang/bazel_0.28.0/java/BUILD create mode 100755 bazel/toolchains/configs/gcc/bazel_0.28.0/cc/BUILD create mode 100755 bazel/toolchains/configs/gcc/bazel_0.28.0/cc/armeabi_cc_toolchain_config.bzl create mode 100755 bazel/toolchains/configs/gcc/bazel_0.28.0/cc/cc_toolchain_config.bzl create mode 100755 bazel/toolchains/configs/gcc/bazel_0.28.0/cc/cc_wrapper.sh create mode 100644 bazel/toolchains/configs/gcc/bazel_0.28.0/config/BUILD create mode 100644 bazel/toolchains/configs/gcc/bazel_0.28.0/java/BUILD create mode 100644 bazel/toolchains/configs/versions.bzl create mode 100644 bazel/toolchains/empty.bzl create mode 100644 bazel/toolchains/rbe_toolchains_config.bzl create mode 100755 bazel/toolchains/regenerate.sh delete mode 100755 ci/do_circle_ci_ipv6_tests.sh create mode 100644 docs/root/configuration/listener_filters/http_inspector.rst create mode 100644 docs/root/intro/arch_overview/upstream/upstream_filters.rst create mode 100644 examples/lua/lib/mylibrary.lua rename include/envoy/stats/{stat_data_allocator.h => allocator.h} (92%) delete mode 100644 source/common/config/cds_json.cc delete mode 100644 source/common/config/cds_json.h create mode 100644 source/common/config/remote_data_fetcher.cc create mode 100644 source/common/config/remote_data_fetcher.h delete mode 100644 source/common/config/tls_context_json.cc delete mode 100644 source/common/config/tls_context_json.h delete mode 100644 source/common/json/json_validator.h rename source/common/stats/{heap_stat_data.cc => allocator_impl.cc} (86%) rename source/common/stats/{heap_stat_data.h => allocator_impl.h} (88%) create mode 100644 source/extensions/access_loggers/common/BUILD create mode 100644 source/extensions/access_loggers/common/access_log_base.cc create mode 100644 source/extensions/access_loggers/common/access_log_base.h create mode 100644 source/extensions/filters/common/ratelimit/stat_names.h create mode 100644 source/extensions/filters/http/dynamo/dynamo_stats.cc create mode 100644 source/extensions/filters/http/dynamo/dynamo_stats.h delete mode 100644 source/extensions/filters/http/dynamo/dynamo_utility.cc delete mode 100644 source/extensions/filters/http/dynamo/dynamo_utility.h create mode 100644 source/extensions/filters/listener/http_inspector/BUILD create mode 100644 source/extensions/filters/listener/http_inspector/config.cc create mode 100644 source/extensions/filters/listener/http_inspector/http_inspector.cc create mode 100644 source/extensions/filters/listener/http_inspector/http_inspector.h create mode 100644 source/extensions/filters/listener/http_inspector/http_protocol_header.h delete mode 100644 source/extensions/filters/network/dubbo_proxy/deserializer_impl.cc delete mode 100644 source/extensions/filters/network/dubbo_proxy/deserializer_impl.h create mode 100644 source/extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.cc create mode 100644 source/extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.h delete mode 100644 source/extensions/filters/network/dubbo_proxy/hessian_deserializer_impl.cc delete mode 100644 source/extensions/filters/network/dubbo_proxy/hessian_deserializer_impl.h create mode 100644 source/extensions/filters/network/dubbo_proxy/message_impl.h create mode 100644 source/extensions/filters/network/dubbo_proxy/protocol_constants.h create mode 100644 source/extensions/filters/network/dubbo_proxy/router/route.h create mode 100644 source/extensions/filters/network/dubbo_proxy/serializer.h create mode 100644 source/extensions/filters/network/dubbo_proxy/serializer_impl.cc create mode 100644 source/extensions/filters/network/dubbo_proxy/serializer_impl.h create mode 100644 test/common/config/datasource_test.cc create mode 100644 test/common/http/codec_impl_corpus/clusterfuzz-testcase-minimized-codec_impl_fuzz_test-5107763548520448 create mode 100644 test/common/router/header_parser_corpus/clusterfuzz-testcase-header_parser_fuzz_test-5163306626580480 rename test/common/stats/{heap_allocator_test.cc => allocator_impl_test.cc} (85%) delete mode 100644 test/config/integration/server.json delete mode 100644 test/config/integration/server_ads.yaml delete mode 100644 test/coverage/gcc_only_test/BUILD delete mode 100644 test/coverage/gcc_only_test/gcc_only_test.cc create mode 100644 test/extensions/access_loggers/common/BUILD create mode 100644 test/extensions/access_loggers/common/access_log_base_test.cc rename test/extensions/filters/http/dynamo/{dynamo_utility_test.cc => dynamo_stats_test.cc} (63%) create mode 100644 test/extensions/filters/listener/http_inspector/BUILD create mode 100644 test/extensions/filters/listener/http_inspector/http_inspector_config_test.cc create mode 100644 test/extensions/filters/listener/http_inspector/http_inspector_test.cc rename test/extensions/filters/network/dubbo_proxy/{hessian_deserializer_impl_test.cc => dubbo_hessian2_serializer_impl_test.cc} (56%) create mode 100644 test/extensions/quic_listeners/quiche/crypto_test_utils_for_envoy.cc create mode 100644 test/integration/ads_integration.cc create mode 100644 test/integration/ads_integration.h create mode 100644 test/integration/cluster_filter_integration_test.cc create mode 100644 test/server/node_bootstrap_with_admin_socket_options.yaml create mode 100644 tools/testdata/check_format/counter_from_string.cc create mode 100644 tools/testdata/check_format/gauge_from_string.cc create mode 100644 tools/testdata/check_format/histogram_from_string.cc diff --git a/.azure-pipelines/linux.yml b/.azure-pipelines/linux.yml index 725e299b19cb..13818d477f02 100644 --- a/.azure-pipelines/linux.yml +++ b/.azure-pipelines/linux.yml @@ -1,29 +1,48 @@ -resources: - containers: - - container: envoy-build - image: envoyproxy/envoy-build:8246167b9d238797cbc6c03dccc9e3921c37617d - jobs: -- job: EnvoyFullTest +- job: bazel + strategy: + matrix: + release: + CI_TARGET: 'bazel.release' + tsan: + CI_TARGET: 'bazel.tsan' + dependsOn: [] # this removes the implicit dependency on previous stage and causes this to run in parallel. timeoutInMinutes: 360 pool: vmImage: 'Ubuntu 16.04' - container: envoy-build steps: - # bazel.dev isn't for CI purpose but we use it here to experiment with Azure Pipeline - # as it builds faster, before Azure can provision larger VM or we can use RBE. - - script: ci/do_ci.sh bazel.dev + - bash: | + echo "disk space at beginning of build:" + df -h + displayName: "Check disk space at beginning" + + - bash: | + sudo mkdir -p /etc/docker + echo '{ + "ipv6": true, + "fixed-cidr-v6": "2001:db8:1::/64" + }' | sudo tee /etc/docker/daemon.json + sudo service docker restart + displayName: "Enable IPv6" + + - script: ci/run_envoy_docker.sh 'ci/do_ci.sh $(CI_TARGET)' + workingDirectory: $(Build.SourcesDirectory) env: - ENVOY_SRCDIR: $(Build.SourcesDirectory) - BUILD_DIR: $(Build.StagingDirectory) - BAZEL_EXTRA_TEST_OPTIONS: "--test_env=ENVOY_IP_TEST_VERSIONS=v4only" - BAZEL_REMOTE_CACHE: remotebuildexecution.googleapis.com + ENVOY_DOCKER_BUILD_DIR: $(Build.StagingDirectory) + BAZEL_BUILD_EXTRA_OPTIONS: "--config=remote-clang --config=remote-ci --jobs=100 --curses=no" + BAZEL_REMOTE_CACHE: grpcs://remotebuildexecution.googleapis.com BAZEL_REMOTE_INSTANCE: projects/envoy-ci/instances/default_instance GCP_SERVICE_ACCOUNT_KEY: $(GcpServiceAccountKey) + displayName: "Run CI script" + + - bash: | + echo "disk space at end of build:" + df -h + displayName: "Check disk space at end" + condition: always() - - task: PublishTestResults@2 + - task: PublishBuildArtifacts@1 inputs: - testResultsFiles: '**/testlogs/**/test.xml' - testRunTitle: 'bazel.dev' - searchFolder: $(Build.StagingDirectory) + pathtoPublish: "$(Build.StagingDirectory)/envoy" + artifactName: $(CI_TARGET) condition: always() diff --git a/.azure-pipelines/macos.yml b/.azure-pipelines/macos.yml index 8aa255052dd1..20655177351d 100644 --- a/.azure-pipelines/macos.yml +++ b/.azure-pipelines/macos.yml @@ -15,7 +15,7 @@ jobs: - script: ./ci/mac_ci_steps.sh displayName: 'Run Mac CI' env: - BAZEL_REMOTE_CACHE: remotebuildexecution.googleapis.com + BAZEL_REMOTE_CACHE: grpcs://remotebuildexecution.googleapis.com BAZEL_REMOTE_INSTANCE: projects/envoy-ci/instances/default_instance GCP_SERVICE_ACCOUNT_KEY: $(GcpServiceAccountKey) diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 02b2cfc5dc4b..9382e025d83c 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -1,8 +1,11 @@ --- tasks: - ubuntu_1804: + release: platform: ubuntu1804 build_targets: - - "//source/..." + - "//source/exe:envoy-static" test_targets: - "//test/..." + test_flags: + # Workaround for https://github.com/envoyproxy/envoy/issues/7647 + - "--deleted_packages=//test/extensions/tracers/dynamic_ot" diff --git a/.bazelrc b/.bazelrc index a365b1d064bc..3a507d5ca130 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,15 +1,25 @@ # Envoy specific Bazel build/test options. -# Bazel doesn't need more than 200MB of memory based on memory profiling: +# Bazel doesn't need more than 200MB of memory for local build based on memory profiling: # https://docs.bazel.build/versions/master/skylark/performance.html#memory-profiling +# The default JVM max heapsize is 1/4 of physical memory up to 32GB which could be large +# enough to consume all memory constrained by cgroup in large host, which is the case in CircleCI. # Limiting JVM heapsize here to let it do GC more when approaching the limit to # leave room for compiler/linker. -startup --host_jvm_args=-Xmx512m +# The number 2G is choosed heuristically to both support in CircleCI and large enough for RBE. +# Startup options cannot be selected via config. +startup --host_jvm_args=-Xmx2g + build --workspace_status_command=bazel/get_workspace_status build --experimental_remap_main_repo +build --experimental_local_memory_estimate build --host_force_python=PY2 +build --action_env=BAZEL_LINKLIBS=-l%:libstdc++.a +build --action_env=BAZEL_LINKOPTS=-lm:-static-libgcc # Basic ASAN/UBSAN that works for gcc +build:asan --action_env=BAZEL_LINKLIBS= +build:asan --action_env=BAZEL_LINKOPTS=-lstdc++:-lm build:asan --define ENVOY_CONFIG_ASAN=1 build:asan --copt -fsanitize=address,undefined build:asan --linkopt -fsanitize=address,undefined @@ -60,6 +70,8 @@ build:clang-msan --copt -fsanitize-memory-track-origins=2 build:libc++ --action_env=CC build:libc++ --action_env=CXX build:libc++ --action_env=CXXFLAGS=-stdlib=libc++ +build:libc++ --action_env=BAZEL_CXXOPTS=-stdlib=libc++ +build:libc++ --action_env=BAZEL_LINKLIBS=-l%:libc++.a:-l%:libc++abi.a:-lm build:libc++ --action_env=PATH build:libc++ --host_linkopt=-fuse-ld=lld build:libc++ --define force_libcpp=enabled @@ -69,3 +81,47 @@ build:sizeopt -c opt --copt -Os # Test options build --test_env=HEAPCHECK=normal --test_env=PPROF_PATH + +# Remote execution: https://docs.bazel.build/versions/master/remote-execution.html +build:rbe-toolchain --host_javabase=@rbe_ubuntu_clang//java:jdk +build:rbe-toolchain --javabase=@rbe_ubuntu_clang//java:jdk +build:rbe-toolchain --host_java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8 +build:rbe-toolchain --java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8 +build:rbe-toolchain --host_platform=@envoy//bazel/toolchains:rbe_ubuntu_clang_platform +build:rbe-toolchain --platforms=@envoy//bazel/toolchains:rbe_ubuntu_clang_platform +build:rbe-toolchain --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 +build:rbe-toolchain --crosstool_top=@rbe_ubuntu_clang//cc:toolchain +build:rbe-toolchain --extra_toolchains=@rbe_ubuntu_clang//config:cc-toolchain +build:rbe-toolchain --linkopt=-fuse-ld=lld +build:rbe-toolchain --action_env=CC=clang --action_env=CXX=clang++ --action_env=PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/llvm-8/bin + +build:remote --spawn_strategy=remote,sandboxed,local +build:remote --strategy=Javac=remote,sandboxed,local +build:remote --strategy=Closure=remote,sandboxed,local +build:remote --strategy=Genrule=remote,sandboxed,local +build:remote --remote_timeout=3600 +build:remote --auth_enabled=true +build:remote --experimental_inmemory_jdeps_files +build:remote --experimental_inmemory_dotd_files +build:remote --experimental_remote_download_outputs=toplevel +test:remote --experimental_remote_download_outputs=minimal + +build:remote-clang --config=remote +build:remote-clang --config=rbe-toolchain + +# Docker sandbox +build:docker-sandbox --experimental_docker_image=envoyproxy/envoy-build:cfc514546bc0284536893cca5fa43d7128edcd35 +build:docker-sandbox --spawn_strategy=docker +build:docker-sandbox --strategy=Javac=docker +build:docker-sandbox --strategy=Closure=docker +build:docker-sandbox --strategy=Genrule=docker +build:docker-sandbox --define=EXECUTOR=remote +build:docker-sandbox --experimental_docker_verbose +build:docker-sandbox --experimental_enable_docker_sandbox + +build:docker-clang --config=docker-sandbox +build:docker-clang --config=rbe-toolchain + +# CI configurations +build:remote-ci --remote_cache=grpcs://remotebuildexecution.googleapis.com +build:remote-ci --remote_executor=grpcs://remotebuildexecution.googleapis.com diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 000000000000..697f087f376a --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +0.28.0 diff --git a/.circleci/config.yml b/.circleci/config.yml index 69c8a7ed7437..9a4680614d63 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,6 +4,7 @@ executors: ubuntu-build: description: "A regular build executor based on ubuntu image" docker: + # NOTE: Update bazel/toolchains/rbe_toolchains_config.bzl with sha256 digest to match the image here. - image: envoyproxy/envoy-build:8246167b9d238797cbc6c03dccc9e3921c37617d resource_class: xlarge working_directory: /source @@ -52,15 +53,6 @@ jobs: - store_artifacts: path: /build/envoy/generated destination: / - tsan: - executor: ubuntu-build - steps: - - run: rm -rf /home/circleci/project/.git # CircleCI git caching is likely broken - - checkout - - run: ci/do_circle_ci.sh bazel.tsan - - store_artifacts: - path: /build/envoy/generated - destination: / compile_time_options: executor: ubuntu-build @@ -93,28 +85,6 @@ jobs: fingerprints: - "f6:f9:df:90:9c:4b:5f:9c:f4:69:fd:42:94:ff:88:24" - run: ci/filter_example_mirror.sh - ipv6_tests: - machine: true - steps: - - run: rm -rf /home/circleci/project/.git # CircleCI git caching is likely broken - - checkout - - run: - name: enable ipv6 - command: | - echo '{ - "ipv6": true, - "fixed-cidr-v6": "2001:db8:1::/64" - }' | sudo tee /etc/docker/daemon.json - - sudo service docker restart - - run: dig go.googlesource.com A go.googlesource.com AAAA # Debug IPv6 network issues - - run: ifconfig - - run: route -A inet -A inet6 - - run: curl -v https://go.googlesource.com - - run: curl -6 -v https://go.googlesource.com || true - - run: ./ci/do_circle_ci_ipv6_tests.sh - - store_artifacts: - path: /tmp/envoy-docker/envoy/generated/failed-testlogs coverage: executor: ubuntu-build @@ -153,11 +123,7 @@ jobs: - run: ci/do_circle_ci.sh check_spelling_pedantic build_image: docker: - - image: circleci/python:3.7 - environment: - # See comment in do_circle_ci.sh for why we do this. - NUM_CPUS: 8 - resource_class: xlarge + - image: google/cloud-sdk steps: - run: rm -rf /home/circleci/project/.git # CircleCI git caching is likely broken - checkout @@ -190,11 +156,9 @@ workflows: tags: only: /^v.*/ - asan - - tsan - compile_time_options - api - filter_example_mirror - - ipv6_tests - coverage - format - clang_tidy diff --git a/.clang-tidy b/.clang-tidy index 0692d1c459ee..c62c2829fab3 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -17,15 +17,23 @@ WarningsAsErrors: 'abseil-duration-*, abseil-string-find-startswith, abseil-upgrade-duration-conversions, bugprone-assert-side-effect, + bugprone-unused-raii, bugprone-use-after-move, + modernize-deprecated-headers, modernize-make-shared, modernize-make-unique, modernize-return-braced-init-list, + modernize-use-default-member-init, + modernize-use-equals-default, + modernize-use-override, modernize-use-using, performance-faster-string-find, performance-for-range-copy, + performance-inefficient-algorithm, performance-inefficient-vector-operation, performance-noexcept-move-constructor, + performance-move-constructor-init, + performance-type-promotion-in-math-fn, performance-unnecessary-copy-initialization, readability-braces-around-statements, readability-container-size-empty, diff --git a/CODEOWNERS b/CODEOWNERS index e6d99af3b562..a252439569d6 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -4,6 +4,8 @@ # api /api/ @envoyproxy/api-shepherds +# access loggers +/*/extensions/access_loggers/common @auni53 @zuercher # csrf extension /*/extensions/filters/http/csrf @dschaller @mattklein123 # original_src http filter extension @@ -42,3 +44,5 @@ extensions/filters/common/original_src @snowp @klarose /*/extensions/filters/http/dynamic_forward_proxy @mattklein123 @alyssawilk # omit_canary_hosts retry predicate /*/extensions/retry/host/omit_canary_hosts @sriduth @snowp +# http inspector +/*/extensions/filters/listener/http_inspector @crazyxy @PiotrSikora @lizan diff --git a/DEVELOPER.md b/DEVELOPER.md index ee76c5746310..465644c0e02c 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -2,7 +2,9 @@ Envoy is built using the Bazel build system. CircleCI builds, tests, and runs coverage against all pull requests and the master branch. -To get started building Envoy locally, see the [Bazel quick start](https://github.com/envoyproxy/envoy/blob/master/bazel/README.md#quick-start-bazel-build-for-developers). To run tests, there are Bazel [targets](https://github.com/envoyproxy/envoy/blob/master/bazel/README.md#testing-envoy-with-bazel) for Google Test. To generate a coverage report, use the tooling for [gcovr](https://github.com/envoyproxy/envoy/blob/master/bazel/README.md#coverage-builds). +To get started building Envoy locally, see the [Bazel quick start](https://github.com/envoyproxy/envoy/blob/master/bazel/README.md#quick-start-bazel-build-for-developers). +To run tests, there are Bazel [targets](https://github.com/envoyproxy/envoy/blob/master/bazel/README.md#testing-envoy-with-bazel) for Google Test. +To generate a coverage report, there is a [coverage build script](https://github.com/envoyproxy/envoy/blob/master/bazel/README.md#coverage-builds). If you plan to contribute to Envoy, you may find it useful to install the Envoy [development support toolchain](https://github.com/envoyproxy/envoy/blob/master/support/README.md), which helps automate parts of the development process, particularly those involving code review. diff --git a/GOVERNANCE.md b/GOVERNANCE.md index aa5cb0da5972..2408510145ce 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -52,10 +52,10 @@ can be promoted to other issue types once it's clear they are actionable (at which point the question label should be removed). * Make sure that ongoing PRs are moving forward at the right pace or closing them. -* Participate when called upon in the [security release process](SECURITY_RELEASE_PROCESS.md). Note - that although this should be a rare occurrence, if a serious vulnerability is found, the process - may take up to several full days of work to implement. This reality should be taken into account - when discussing time commitment obligations with employers. +* Participate when called upon in the [security release process](SECURITY.md). Note that although + this should be a rare occurrence, if a serious vulnerability is found, the process may take up to + several full days of work to implement. This reality should be taken into account when discussing + time commitment obligations with employers. * In general continue to be willing to spend at least 25% of ones time working on Envoy (~1.25 business days per week). * We currently maintain an "on-call" rotation within the maintainers. Each on-call is 1 week. @@ -103,7 +103,7 @@ or you can subscribe to the iCal feed [here](https://app.opsgenie.com/webcal/get following version. E.g., "1.7.0 (pending)". * Run the deprecate_versions.py script (e.g. `sh tools/deprecate_version/deprecate_version.sh`) to file tracking issues for code which can be removed. -* Run the deprecate_features.py script (e.g. `sh tools/deprecate_version/deprecate_features.sh`) +* Run the deprecate_features.py script (e.g. `sh tools/deprecate_features/deprecate_features.sh`) to make the last release's deprecated features fatal-by-default. Submit the resultant PR and send an email to envoy-announce. diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 342f2df00dfe..8d87611c68e8 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -1,3 +1,7 @@ +**WARNING: If you want to report crashes, leaking of sensitive information, +and/or other security issues, please consider +[reporting them using appropriate channels](https://github.com/envoyproxy/envoy#reporting-security-vulnerabilities).** + **Issue Template** *Title*: *One line description* diff --git a/README.md b/README.md index 71b468dca47b..abe4e9822462 100644 --- a/README.md +++ b/README.md @@ -85,4 +85,4 @@ If you've found a vulnerability or a potential vulnerability in Envoy please let email to acknowledge your report, and we'll send an additional email when we've identified the issue positively or negatively. -For further details please see our complete [security release process](SECURITY_RELEASE_PROCESS.md). +For further details please see our complete [security release process](SECURITY.md). diff --git a/SECURITY_RELEASE_PROCESS.md b/SECURITY.md similarity index 100% rename from SECURITY_RELEASE_PROCESS.md rename to SECURITY.md diff --git a/WORKSPACE b/WORKSPACE index 5609189bd56d..ef120bc53d4f 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,22 +1,17 @@ workspace(name = "envoy") +load("//bazel:api_binding.bzl", "envoy_api_binding") + +envoy_api_binding() + load("//bazel:api_repositories.bzl", "envoy_api_dependencies") envoy_api_dependencies() -load("//bazel:repositories.bzl", "GO_VERSION", "envoy_dependencies") -load("//bazel:cc_configure.bzl", "cc_configure") +load("//bazel:repositories.bzl", "envoy_dependencies") envoy_dependencies() -load("@rules_foreign_cc//:workspace_definitions.bzl", "rules_foreign_cc_dependencies") - -rules_foreign_cc_dependencies() - -cc_configure() - -load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") - -go_rules_dependencies() +load("//bazel:dependency_imports.bzl", "envoy_dependency_imports") -go_register_toolchains(go_version = GO_VERSION) +envoy_dependency_imports() diff --git a/api/bazel/api_build_system.bzl b/api/bazel/api_build_system.bzl index 192fdfaa8221..9eb8e434a531 100644 --- a/api/bazel/api_build_system.bzl +++ b/api/bazel/api_build_system.bzl @@ -1,4 +1,4 @@ -load("@com_google_protobuf//:protobuf.bzl", "py_proto_library") +load("@com_google_protobuf//:protobuf.bzl", _py_proto_library = "py_proto_library") load("@com_envoyproxy_protoc_gen_validate//bazel:pgv_proto_library.bzl", "pgv_cc_proto_library") load("@io_bazel_rules_go//proto:def.bzl", "go_grpc_library", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_test") @@ -24,21 +24,42 @@ def _LibrarySuffix(library_name, suffix): # https://github.com/bazelbuild/bazel/issues/3935 and/or # https://github.com/bazelbuild/bazel/issues/2626 are resolved. def api_py_proto_library(name, srcs = [], deps = [], has_services = 0): - py_proto_library( + _py_proto_library( name = _Suffix(name, _PY_SUFFIX), srcs = srcs, default_runtime = "@com_google_protobuf//:protobuf_python", protoc = "@com_google_protobuf//:protoc", deps = [_LibrarySuffix(d, _PY_SUFFIX) for d in deps] + [ "@com_envoyproxy_protoc_gen_validate//validate:validate_py", - "@googleapis//:api_httpbody_protos_py", - "@googleapis//:http_api_protos_py", - "@googleapis//:rpc_status_protos_py", + "@com_google_googleapis//google/rpc:status_py_proto", + "@com_google_googleapis//google/api:annotations_py_proto", + "@com_google_googleapis//google/api:http_py_proto", + "@com_google_googleapis//google/api:httpbody_py_proto", "@com_github_gogo_protobuf//:gogo_proto_py", ], visibility = ["//visibility:public"], ) +# This defines googleapis py_proto_library. The repository does not provide its definition and requires +# overriding it in the consuming project (see https://github.com/grpc/grpc/issues/19255 for more details). +def py_proto_library(name, deps = []): + srcs = [dep[:-6] + ".proto" if dep.endswith("_proto") else dep for dep in deps] + proto_deps = [] + + # py_proto_library in googleapis specifies *_proto rules in dependencies. + # By rewriting *_proto to *.proto above, the dependencies in *_proto rules are not preserved. + # As a workaround, manually specify the proto dependencies for the imported python rules. + if name == "annotations_py_proto": + proto_deps = proto_deps + [":http_py_proto"] + _py_proto_library( + name = name, + srcs = srcs, + default_runtime = "@com_google_protobuf//:protobuf_python", + protoc = "@com_google_protobuf//:protoc", + deps = proto_deps + ["@com_google_protobuf//:protobuf_python"], + visibility = ["//visibility:public"], + ) + def api_go_proto_library(name, proto, deps = []): go_proto_library( name = _Suffix(name, _GO_PROTO_SUFFIX), @@ -53,7 +74,7 @@ def api_go_proto_library(name, proto, deps = []): "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", "@com_envoyproxy_protoc_gen_validate//validate:go_default_library", - "@googleapis//:rpc_status_go_proto", + "@com_google_googleapis//google/rpc:status_go_proto", ], ) @@ -70,7 +91,7 @@ def api_go_grpc_library(name, proto, deps = []): "@io_bazel_rules_go//proto/wkt:struct_go_proto", "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", "@com_envoyproxy_protoc_gen_validate//validate:go_default_library", - "@googleapis//:http_api_go_proto", + "@com_google_googleapis//google/api:annotations_go_proto", ], ) @@ -109,8 +130,9 @@ def api_proto_library( "@com_google_protobuf//:struct_proto", "@com_google_protobuf//:timestamp_proto", "@com_google_protobuf//:wrappers_proto", - "@googleapis//:http_api_protos_proto", - "@googleapis//:rpc_status_protos_lib", + "@com_google_googleapis//google/api:http_proto", + "@com_google_googleapis//google/api:annotations_proto", + "@com_google_googleapis//google/rpc:status_proto", "@com_github_gogo_protobuf//:gogo_proto", "@com_envoyproxy_protoc_gen_validate//validate:validate_proto", ], @@ -121,8 +143,9 @@ def api_proto_library( linkstatic = linkstatic, cc_deps = [_LibrarySuffix(d, _CC_SUFFIX) for d in deps] + external_cc_proto_deps + [ "@com_github_gogo_protobuf//:gogo_proto_cc", - "@googleapis//:http_api_protos", - "@googleapis//:rpc_status_protos", + "@com_google_googleapis//google/api:http_cc_proto", + "@com_google_googleapis//google/api:annotations_cc_proto", + "@com_google_googleapis//google/rpc:status_cc_proto", ], deps = [":" + name], visibility = ["//visibility:public"], diff --git a/api/bazel/repositories.bzl b/api/bazel/repositories.bzl index 67d38c4fb57a..3185d0f74072 100644 --- a/api/bazel/repositories.bzl +++ b/api/bazel/repositories.bzl @@ -12,9 +12,8 @@ def api_dependencies(): locations = REPOSITORY_LOCATIONS, ) envoy_http_archive( - name = "googleapis", + name = "com_google_googleapis", locations = REPOSITORY_LOCATIONS, - build_file_content = GOOGLEAPIS_BUILD_CONTENT, ) envoy_http_archive( name = "com_github_gogo_protobuf", @@ -36,179 +35,6 @@ def api_dependencies(): build_file_content = KAFKASOURCE_BUILD_CONTENT, ) -GOOGLEAPIS_BUILD_CONTENT = """ -load("@com_google_protobuf//:protobuf.bzl", "py_proto_library") -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@com_github_grpc_grpc//bazel:cc_grpc_library.bzl", "cc_grpc_library") - -filegroup( - name = "api_httpbody_protos_src", - srcs = [ - "google/api/httpbody.proto", - ], - visibility = ["//visibility:public"], -) - -proto_library( - name = "api_httpbody_protos_proto", - srcs = [":api_httpbody_protos_src"], - deps = ["@com_google_protobuf//:descriptor_proto"], - visibility = ["//visibility:public"], -) - -cc_proto_library( - name = "api_httpbody_protos", - deps = [":api_httpbody_protos_proto"], - visibility = ["//visibility:public"], -) - -py_proto_library( - name = "api_httpbody_protos_py", - srcs = [ - "google/api/httpbody.proto", - ], - include = ".", - default_runtime = "@com_google_protobuf//:protobuf_python", - protoc = "@com_google_protobuf//:protoc", - visibility = ["//visibility:public"], - deps = ["@com_google_protobuf//:protobuf_python"], -) - -go_proto_library( - name = "api_httpbody_go_proto", - importpath = "google.golang.org/genproto/googleapis/api/httpbody", - proto = ":api_httpbody_protos_proto", - visibility = ["//visibility:public"], - deps = [ - ":descriptor_go_proto", - ], -) - -filegroup( - name = "http_api_protos_src", - srcs = [ - "google/api/annotations.proto", - "google/api/http.proto", - ], - visibility = ["//visibility:public"], -) - -go_proto_library( - name = "descriptor_go_proto", - importpath = "github.com/golang/protobuf/protoc-gen-go/descriptor", - proto = "@com_google_protobuf//:descriptor_proto", - visibility = ["//visibility:public"], -) - -proto_library( - name = "http_api_protos_proto", - srcs = [":http_api_protos_src"], - deps = ["@com_google_protobuf//:descriptor_proto"], - visibility = ["//visibility:public"], -) - -cc_proto_library( - name = "http_api_protos", - deps = [":http_api_protos_proto"], - visibility = ["//visibility:public"], -) - -py_proto_library( - name = "http_api_protos_py", - srcs = [ - "google/api/annotations.proto", - "google/api/http.proto", - ], - include = ".", - default_runtime = "@com_google_protobuf//:protobuf_python", - protoc = "@com_google_protobuf//:protoc", - visibility = ["//visibility:public"], - deps = ["@com_google_protobuf//:protobuf_python"], -) - -go_proto_library( - name = "http_api_go_proto", - importpath = "google.golang.org/genproto/googleapis/api/annotations", - proto = ":http_api_protos_proto", - visibility = ["//visibility:public"], - deps = [ - ":descriptor_go_proto", - ], -) - -filegroup( - name = "rpc_status_protos_src", - srcs = [ - "google/rpc/status.proto", - ], - visibility = ["//visibility:public"], -) - -proto_library( - name = "rpc_status_protos_lib", - srcs = [":rpc_status_protos_src"], - deps = ["@com_google_protobuf//:any_proto"], - visibility = ["//visibility:public"], -) - -cc_proto_library( - name = "rpc_status_protos", - deps = [":rpc_status_protos_lib"], - visibility = ["//visibility:public"], -) - -go_proto_library( - name = "rpc_status_go_proto", - importpath = "google.golang.org/genproto/googleapis/rpc/status", - proto = ":rpc_status_protos_lib", - visibility = ["//visibility:public"], - deps = [ - "@io_bazel_rules_go//proto/wkt:any_go_proto", - ], -) - -py_proto_library( - name = "rpc_status_protos_py", - srcs = [ - "google/rpc/status.proto", - ], - include = ".", - default_runtime = "@com_google_protobuf//:protobuf_python", - protoc = "@com_google_protobuf//:protoc", - visibility = ["//visibility:public"], - deps = ["@com_google_protobuf//:protobuf_python"], -) - -proto_library( - name = "tracing_proto_proto", - srcs = [ - "google/devtools/cloudtrace/v2/trace.proto", - "google/devtools/cloudtrace/v2/tracing.proto", - ], - deps = [ - ":http_api_protos_proto", - ":rpc_status_protos_lib", - "@com_google_protobuf//:timestamp_proto", - "@com_google_protobuf//:wrappers_proto", - "@com_google_protobuf//:empty_proto", - ], -) - -cc_proto_library( - name = "tracing_proto_cc", - deps = [":tracing_proto_proto"], -) - -cc_grpc_library( - name = "tracing_proto", - srcs = [":tracing_proto_proto"], - deps = [":tracing_proto_cc"], - grpc_only = True, - visibility = ["@io_opencensus_cpp//opencensus:__subpackages__"], -) - -""" - GOGOPROTO_BUILD_CONTENT = """ load("@com_google_protobuf//:protobuf.bzl", "cc_proto_library", "py_proto_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") diff --git a/api/bazel/repository_locations.bzl b/api/bazel/repository_locations.bzl index 541f6c4a5d76..dd661b7d7886 100644 --- a/api/bazel/repository_locations.bzl +++ b/api/bazel/repository_locations.bzl @@ -7,11 +7,11 @@ GOGOPROTO_SHA256 = "99e423905ba8921e86817607a5294ffeedb66fdd4a85efce5eb2848f715f OPENCENSUS_PROTO_GIT_SHA = "d5d80953a8c2ff4633087af6933cd152678434bb" # Mar 18, 2019 OPENCENSUS_PROTO_SHA256 = "a4e87a1da21d1b3a16674332c3ee6e2689d52f3532e2ff8cb4a626c8bcdabcfc" -PGV_GIT_SHA = "26db5cb7c01a67c6a2e21a832106406185530b2f" -PGV_SHA256 = "6510cbcf69d99059c652ae2376f6240bc761d0b019cd962225f4f609be361e26" +PGV_GIT_SHA = "dd90514d96e35023ed20201f349542b0bc64461d" +PGV_SHA256 = "f7d67677fbec5b0f561f6ee6788223fb535d3864b53a28b6678e319f5d1f4f25" -GOOGLEAPIS_GIT_SHA = "d642131a6e6582fc226caf9893cb7fe7885b3411" # May 23, 2018 -GOOGLEAPIS_SHA = "16f5b2e8bf1e747a32f9a62e211f8f33c94645492e9bbd72458061d9a9de1f63" +GOOGLEAPIS_GIT_SHA = "be480e391cc88a75cf2a81960ef79c80d5012068" # Jul 24, 2019 +GOOGLEAPIS_SHA = "c1969e5b72eab6d9b6cfcff748e45ba57294aeea1d96fd04cd081995de0605c2" PROMETHEUS_GIT_SHA = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c" # Nov 17, 2017 PROMETHEUS_SHA = "783bdaf8ee0464b35ec0c8704871e1e72afa0005c3f3587f65d9d6694bf3911b" @@ -28,7 +28,7 @@ REPOSITORY_LOCATIONS = dict( strip_prefix = "protoc-gen-validate-" + PGV_GIT_SHA, urls = ["https://github.com/envoyproxy/protoc-gen-validate/archive/" + PGV_GIT_SHA + ".tar.gz"], ), - googleapis = dict( + com_google_googleapis = dict( # TODO(dio): Consider writing a Skylark macro for importing Google API proto. sha256 = GOOGLEAPIS_SHA, strip_prefix = "googleapis-" + GOOGLEAPIS_GIT_SHA, diff --git a/api/envoy/admin/v2alpha/BUILD b/api/envoy/admin/v2alpha/BUILD index 0cbbb7f0d389..aa35aa7c8d7d 100644 --- a/api/envoy/admin/v2alpha/BUILD +++ b/api/envoy/admin/v2alpha/BUILD @@ -11,6 +11,7 @@ api_proto_library_internal( "//envoy/api/v2:lds", "//envoy/api/v2:rds", "//envoy/api/v2:srds", + "//envoy/api/v2/auth:cert", "//envoy/config/bootstrap/v2:bootstrap", ], ) diff --git a/api/envoy/admin/v2alpha/config_dump.proto b/api/envoy/admin/v2alpha/config_dump.proto index ba5b36df36c7..8ff5ba8fa102 100644 --- a/api/envoy/admin/v2alpha/config_dump.proto +++ b/api/envoy/admin/v2alpha/config_dump.proto @@ -6,6 +6,7 @@ option java_outer_classname = "ConfigDumpProto"; option java_multiple_files = true; option java_package = "io.envoyproxy.envoy.admin.v2alpha"; +import "envoy/api/v2/auth/cert.proto"; import "envoy/api/v2/cds.proto"; import "envoy/api/v2/lds.proto"; import "envoy/api/v2/rds.proto"; @@ -55,7 +56,7 @@ message ListenersConfigDump { // will be "". string version_info = 1; - // Describes a statically loaded cluster. + // Describes a statically loaded listener. message StaticListener { // The listener config. envoy.api.v2.Listener listener = 1; @@ -219,3 +220,48 @@ message ScopedRoutesConfigDump { repeated DynamicScopedRouteConfigs dynamic_scoped_route_configs = 2 [(gogoproto.nullable) = false]; } + +// Envoys SDS implementation fills this message with all secrets fetched dynamically via SDS. +message SecretsConfigDump { + // DynamicSecret contains secret information fetched via SDS. + message DynamicSecret { + // The name assigned to the secret. + string name = 1; + + // This is the per-resource version information. + string version_info = 2; + + // The timestamp when the secret was last updated. + google.protobuf.Timestamp last_updated = 3; + + // The actual secret information. + // Security sensitive information is redacted (replaced with "[redacted]") for + // private keys and passwords in TLS certificates. + envoy.api.v2.auth.Secret secret = 4; + } + + // StaticSecret specifies statically loaded secret in bootstrap. + message StaticSecret { + // The name assigned to the secret. + string name = 1; + + // The timestamp when the secret was last updated. + google.protobuf.Timestamp last_updated = 2; + + // The actual secret information. + // Security sensitive information is redacted (replaced with "[redacted]") for + // private keys and passwords in TLS certificates. + envoy.api.v2.auth.Secret secret = 3; + } + + // The statically loaded secrets. + repeated StaticSecret static_secrets = 1; + + // The dynamically loaded active secrets. These are secrets that are available to service + // clusters or listeners. + repeated DynamicSecret dynamic_active_secrets = 2; + + // The dynamically loaded warming secrets. These are secrets that are currently undergoing + // warming in preparation to service clusters or listeners. + repeated DynamicSecret dynamic_warming_secrets = 3; +} diff --git a/api/envoy/api/v2/BUILD b/api/envoy/api/v2/BUILD index 3cc2d6b2c2ec..48ddb2e13025 100644 --- a/api/envoy/api/v2/BUILD +++ b/api/envoy/api/v2/BUILD @@ -67,6 +67,7 @@ api_proto_library_internal( ":eds", "//envoy/api/v2/auth:cert", "//envoy/api/v2/cluster:circuit_breaker", + "//envoy/api/v2/cluster:filter", "//envoy/api/v2/cluster:outlier_detection", "//envoy/api/v2/core:address", "//envoy/api/v2/core:base", @@ -86,6 +87,7 @@ api_go_grpc_library( ":eds_go_grpc", "//envoy/api/v2/auth:cert_go_proto", "//envoy/api/v2/cluster:circuit_breaker_go_proto", + "//envoy/api/v2/cluster:filter_go_proto", "//envoy/api/v2/cluster:outlier_detection_go_proto", "//envoy/api/v2/core:address_go_proto", "//envoy/api/v2/core:base_go_proto", diff --git a/api/envoy/api/v2/cds.proto b/api/envoy/api/v2/cds.proto index 83fe4329e15b..bddcf1d56d37 100644 --- a/api/envoy/api/v2/cds.proto +++ b/api/envoy/api/v2/cds.proto @@ -16,6 +16,7 @@ import "envoy/api/v2/discovery.proto"; import "envoy/api/v2/core/health_check.proto"; import "envoy/api/v2/core/protocol.proto"; import "envoy/api/v2/cluster/circuit_breaker.proto"; +import "envoy/api/v2/cluster/filter.proto"; import "envoy/api/v2/cluster/outlier_detection.proto"; import "envoy/api/v2/eds.proto"; import "envoy/type/percent.proto"; @@ -51,7 +52,7 @@ service ClusterDiscoveryService { // [#protodoc-title: Clusters] // Configuration for a single upstream cluster. -// [#comment:next free field: 40] +// [#comment:next free field: 41] message Cluster { // Supplies the name of the cluster which must be unique across all clusters. // The cluster name is used when emitting @@ -188,7 +189,7 @@ message Cluster { // **This field is deprecated**. Set the // :ref:`load_assignment` field instead. // - repeated core.Address hosts = 7 [deprecated = true]; + repeated core.Address hosts = 7; // Setting this is required for specifying members of // :ref:`STATIC`, @@ -517,6 +518,7 @@ message Cluster { message CommonLbConfig { // Configures the :ref:`healthy panic threshold `. // If not specified, the default is 50%. + // To disable panic mode, set to 0%. // // .. note:: // The specified percent will be truncated to the nearest 1%. @@ -631,6 +633,11 @@ message Cluster { // If this flag is not set to true, Envoy will wait until the hosts fail active health // checking before removing it from the cluster. bool drain_connections_on_host_removal = 32; + + // An optional list of network filters that make up the filter chain for + // outgoing connections made by the cluster. Order matters as the filters are + // processed sequentially as connection events happen. + repeated cluster.Filter filters = 40; } // An extensible structure containing the address Envoy should bind to when diff --git a/api/envoy/api/v2/cluster/BUILD b/api/envoy/api/v2/cluster/BUILD index ab34f59d0e4e..5589905d859b 100644 --- a/api/envoy/api/v2/cluster/BUILD +++ b/api/envoy/api/v2/cluster/BUILD @@ -33,3 +33,16 @@ api_go_proto_library( name = "outlier_detection", proto = ":outlier_detection", ) + +api_proto_library_internal( + name = "filter", + srcs = ["filter.proto"], + visibility = [ + "//envoy/api/v2:__pkg__", + ], +) + +api_go_proto_library( + name = "filter", + proto = ":filter", +) diff --git a/api/envoy/api/v2/cluster/filter.proto b/api/envoy/api/v2/cluster/filter.proto new file mode 100644 index 000000000000..03a826976f09 --- /dev/null +++ b/api/envoy/api/v2/cluster/filter.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package envoy.api.v2.cluster; + +option java_outer_classname = "FilterProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.api.v2.cluster"; +option csharp_namespace = "Envoy.Api.V2.ClusterNS"; +option ruby_package = "Envoy.Api.V2.ClusterNS"; + +import "google/protobuf/any.proto"; +import "google/protobuf/struct.proto"; + +import "validate/validate.proto"; +import "gogoproto/gogo.proto"; + +option (gogoproto.equal_all) = true; + +// [#protodoc-title: Upstream filters] +// +// Upstream filters apply to the connections to the upstream cluster hosts. +message Filter { + // The name of the filter to instantiate. The name must match a + // :ref:`supported filter `. + string name = 1 [(validate.rules).string.min_bytes = 1]; + + // Filter specific configuration which depends on the filter being + // instantiated. See the supported filters for further documentation. + google.protobuf.Any typed_config = 2; +} diff --git a/api/envoy/api/v2/core/BUILD b/api/envoy/api/v2/core/BUILD index b324a8ad0190..b3d2be2301f1 100644 --- a/api/envoy/api/v2/core/BUILD +++ b/api/envoy/api/v2/core/BUILD @@ -38,6 +38,7 @@ api_proto_library_internal( ":friends", ], deps = [ + ":http_uri", "//envoy/type:percent", ], ) @@ -45,7 +46,10 @@ api_proto_library_internal( api_go_proto_library( name = "base", proto = ":base", - deps = ["//envoy/type:percent_go_proto"], + deps = [ + ":http_uri_go_proto", + "//envoy/type:percent_go_proto", + ], ) api_proto_library_internal( diff --git a/api/envoy/api/v2/core/base.proto b/api/envoy/api/v2/core/base.proto index 949cbfc94afd..6375d87e6824 100644 --- a/api/envoy/api/v2/core/base.proto +++ b/api/envoy/api/v2/core/base.proto @@ -7,6 +7,8 @@ option java_multiple_files = true; option java_package = "io.envoyproxy.envoy.api.v2.core"; option go_package = "core"; +import "envoy/api/v2/core/http_uri.proto"; + import "google/protobuf/any.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/wrappers.proto"; @@ -187,6 +189,28 @@ message DataSource { } } +// The message specifies how to fetch data from remote and how to verify it. +message RemoteDataSource { + // The HTTP URI to fetch the remote data. + HttpUri http_uri = 1 [(validate.rules).message.required = true]; + + // SHA256 string for verifying data. + string sha256 = 2 [(validate.rules).string.min_bytes = 1]; +} + +// Async data source which support async data fetch. +message AsyncDataSource { + oneof specifier { + option (validate.required) = true; + + // Local async data source. + DataSource local = 1; + + // Remote async data source. + RemoteDataSource remote = 2; + } +} + // Configuration for transport socket in :ref:`listeners ` and // :ref:`clusters `. If the configuration is // empty, a default transport socket implementation and configuration will be @@ -234,8 +258,7 @@ message SocketOption { } // The state in which the option will be applied. When used in BindConfig // STATE_PREBIND is currently the only valid value. - SocketState state = 6 - [(validate.rules).message.required = true, (validate.rules).enum.defined_only = true]; + SocketState state = 6 [(validate.rules).enum.defined_only = true]; } // Runtime derived FractionalPercent with defaults for when the numerator or denominator is not diff --git a/api/envoy/api/v2/core/config_source.proto b/api/envoy/api/v2/core/config_source.proto index 8b6014dcbf9d..913f3876115c 100644 --- a/api/envoy/api/v2/core/config_source.proto +++ b/api/envoy/api/v2/core/config_source.proto @@ -112,13 +112,12 @@ message ConfigSource { AggregatedConfigSource ads = 3; } - // Optional initialization timeout. // When this timeout is specified, Envoy will wait no longer than the specified time for first // config response on this xDS subscription during the :ref:`initialization process // `. After reaching the timeout, Envoy will move to the next // initialization phase, even if the first config is not delivered yet. The timer is activated // when the xDS API subscription starts, and is disarmed on first config update or on error. 0 // means no timeout - Envoy will wait indefinitely for the first xDS config (unless another - // timeout applies). Default 0. + // timeout applies). The default is 15s. google.protobuf.Duration initial_fetch_timeout = 4; } diff --git a/api/envoy/config/bootstrap/v2/bootstrap.proto b/api/envoy/config/bootstrap/v2/bootstrap.proto index ab841058c0b1..01ea30d2bcf3 100644 --- a/api/envoy/config/bootstrap/v2/bootstrap.proto +++ b/api/envoy/config/bootstrap/v2/bootstrap.proto @@ -161,6 +161,10 @@ message Admin { // The TCP address that the administration server will listen on. // If not specified, Envoy will not start an administration server. envoy.api.v2.core.Address address = 3; + + // Additional socket options that may not be present in Envoy source code or + // precompiled binaries. + repeated envoy.api.v2.core.SocketOption socket_options = 4; } // Cluster manager :ref:`architecture overview `. diff --git a/api/envoy/config/filter/http/fault/v2/fault.proto b/api/envoy/config/filter/http/fault/v2/fault.proto index bc491580bb15..51ee24ac91a8 100644 --- a/api/envoy/config/filter/http/fault/v2/fault.proto +++ b/api/envoy/config/filter/http/fault/v2/fault.proto @@ -88,4 +88,28 @@ message HTTPFault { // This is a per-stream limit versus a connection level limit. This means that concurrent streams // will each get an independent limit. filter.fault.v2.FaultRateLimit response_rate_limit = 7; + + // The runtime key to override the :ref:`default ` + // runtime. The default is: fault.http.delay.fixed_delay_percent + string delay_percent_runtime = 8; + + // The runtime key to override the :ref:`default ` + // runtime. The default is: fault.http.abort.abort_percent + string abort_percent_runtime = 9; + + // The runtime key to override the :ref:`default ` + // runtime. The default is: fault.http.delay.fixed_duration_ms + string delay_duration_runtime = 10; + + // The runtime key to override the :ref:`default ` + // runtime. The default is: fault.http.abort.http_status + string abort_http_status_runtime = 11; + + // The runtime key to override the :ref:`default ` + // runtime. The default is: fault.http.max_active_faults + string max_active_faults_runtime = 12; + + // The runtime key to override the :ref:`default ` + // runtime. The default is: fault.http.rate_limit.response_percent + string response_rate_limit_percent_runtime = 13; } diff --git a/api/envoy/config/filter/http/transcoder/v2/transcoder.proto b/api/envoy/config/filter/http/transcoder/v2/transcoder.proto index a7f092d34655..14f54124508d 100644 --- a/api/envoy/config/filter/http/transcoder/v2/transcoder.proto +++ b/api/envoy/config/filter/http/transcoder/v2/transcoder.proto @@ -114,4 +114,10 @@ message GrpcJsonTranscoder { // The client could ``post`` a json body ``{"shelf": 1234}`` with the path of // ``/bookstore.Bookstore/GetShelfRequest`` to call ``GetShelfRequest``. bool auto_mapping = 7; + + // Whether to ignore query parameters that cannot be mapped to a corresponding + // protobuf field. Use this if you cannot control the query parameters and do + // not know them beforehand. Otherwise use ``ignored_query_parameters``. + // Defaults to false. + bool ignore_unknown_query_parameters = 8; } diff --git a/api/envoy/config/trace/v2/trace.proto b/api/envoy/config/trace/v2/trace.proto index ac2a9cbb7649..3fe4d1fff66f 100644 --- a/api/envoy/config/trace/v2/trace.proto +++ b/api/envoy/config/trace/v2/trace.proto @@ -130,8 +130,7 @@ message OpenCensusConfig { // The URL to Zipkin, e.g. "http://127.0.0.1:9411/api/v2/spans" string zipkin_url = 6; - // The Zipkin service name. - string zipkin_service_name = 7; + reserved 7; // Formerly zipkin_service_name. enum TraceContext { // No-op default, no trace context is utilized. diff --git a/api/envoy/service/tap/v2alpha/BUILD b/api/envoy/service/tap/v2alpha/BUILD index 6651b9c5e10d..63d11e80a755 100644 --- a/api/envoy/service/tap/v2alpha/BUILD +++ b/api/envoy/service/tap/v2alpha/BUILD @@ -10,7 +10,6 @@ api_proto_library_internal( "//envoy/api/v2/core:base", "//envoy/api/v2/core:grpc_service", "//envoy/api/v2/route", - "//envoy/type/matcher:string", ], ) diff --git a/api/envoy/service/tap/v2alpha/common.proto b/api/envoy/service/tap/v2alpha/common.proto index 3c7bf498f42a..54437b305469 100644 --- a/api/envoy/service/tap/v2alpha/common.proto +++ b/api/envoy/service/tap/v2alpha/common.proto @@ -3,7 +3,6 @@ syntax = "proto3"; import "envoy/api/v2/route/route.proto"; import "envoy/api/v2/core/base.proto"; import "envoy/api/v2/core/grpc_service.proto"; -import "envoy/type/matcher/string.proto"; import "google/protobuf/wrappers.proto"; diff --git a/bazel/BUILD b/bazel/BUILD index c288f351054f..d449250d2390 100755 --- a/bazel/BUILD +++ b/bazel/BUILD @@ -5,6 +5,7 @@ package(default_visibility = ["//visibility:public"]) exports_files([ "gen_sh_test_runner.sh", "sh_test_wrapper.sh", + "cc_wrapper.py", ]) genrule( @@ -85,6 +86,20 @@ config_setting( values = {"define": "ENVOY_CONFIG_COVERAGE=1"}, ) +config_setting( + name = "clang_build", + flag_values = { + "@bazel_tools//tools/cpp:compiler": "clang", + }, +) + +config_setting( + name = "gcc_build", + flag_values = { + "@bazel_tools//tools/cpp:compiler": "gcc", + }, +) + config_setting( name = "disable_tcmalloc", values = {"define": "tcmalloc=disabled"}, @@ -199,6 +214,11 @@ config_setting( values = {"cpu": "ppc"}, ) +config_setting( + name = "linux_mips64", + values = {"cpu": "mips64"}, +) + config_setting( name = "windows_x86_64", values = {"cpu": "x64_windows"}, @@ -277,6 +297,7 @@ alias( ":linux_x86_64": ":linux_x86_64", ":linux_aarch64": ":linux_aarch64", ":linux_ppc": ":linux_ppc", + ":linux_mips64": ":linux_mips64", # If we're not on an linux platform return a value that will never match in the select() statement calling this # since it would have already been matched above. "//conditions:default": ":linux_x86_64", diff --git a/bazel/README.md b/bazel/README.md index 25743ffdc097..657177dbccfd 100644 --- a/bazel/README.md +++ b/bazel/README.md @@ -435,10 +435,8 @@ https://github.com/bazelbuild/bazel/issues/2805. # Coverage builds -To generate coverage results, make sure you have -[`gcovr`](https://github.com/gcovr/gcovr) 3.3 in your `PATH` (or set `GCOVR` to -point at it) and are using a GCC toolchain (clang does not work currently, see -https://github.com/envoyproxy/envoy/issues/1000). Then run: +To generate coverage results, make sure you are using a clang toolchain and have `llvm-cov` and +`llvm-profdata` in your `PATH`. Then run: ``` test/run_envoy_bazel_coverage.sh diff --git a/bazel/api_binding.bzl b/bazel/api_binding.bzl new file mode 100644 index 000000000000..bf4f304687c1 --- /dev/null +++ b/bazel/api_binding.bzl @@ -0,0 +1,36 @@ +def _default_envoy_api_impl(ctx): + ctx.file("WORKSPACE", "") + ctx.file("BUILD.bazel", "") + api_dirs = [ + "bazel", + "docs", + "envoy", + "examples", + "test", + "tools", + ] + for d in api_dirs: + ctx.symlink(ctx.path(ctx.attr.api).dirname.get_child(d), d) + +_default_envoy_api = repository_rule( + implementation = _default_envoy_api_impl, + attrs = { + "api": attr.label(default = "@envoy//api:BUILD"), + }, +) + +def envoy_api_binding(): + # Treat the data plane API as an external repo, this simplifies exporting the API to + # https://github.com/envoyproxy/data-plane-api. + if "envoy_api" not in native.existing_rules().keys(): + _default_envoy_api(name = "envoy_api") + + # TODO(https://github.com/envoyproxy/envoy/issues/7719) need to remove both bindings and use canonical rules + native.bind( + name = "api_httpbody_protos", + actual = "@com_google_googleapis//google/api:httpbody_cc_proto", + ) + native.bind( + name = "http_api_protos", + actual = "@com_google_googleapis//google/api:annotations_cc_proto", + ) diff --git a/bazel/api_repositories.bzl b/bazel/api_repositories.bzl index 016fb16c8a2e..d4d2f1abd51d 100644 --- a/bazel/api_repositories.bzl +++ b/bazel/api_repositories.bzl @@ -1,35 +1,4 @@ -def _default_envoy_api_impl(ctx): - ctx.file("WORKSPACE", "") - ctx.file("BUILD.bazel", "") - api_dirs = [ - "bazel", - "docs", - "envoy", - "examples", - "test", - "tools", - ] - for d in api_dirs: - ctx.symlink(ctx.path(ctx.attr.api).dirname.get_child(d), d) - -_default_envoy_api = repository_rule( - implementation = _default_envoy_api_impl, - attrs = { - "api": attr.label(default = "@envoy//api:BUILD"), - }, -) +load("@envoy_api//bazel:repositories.bzl", "api_dependencies") def envoy_api_dependencies(): - # Treat the data plane API as an external repo, this simplifies exporting the API to - # https://github.com/envoyproxy/data-plane-api. - if "envoy_api" not in native.existing_rules().keys(): - _default_envoy_api(name = "envoy_api") - - native.bind( - name = "api_httpbody_protos", - actual = "@googleapis//:api_httpbody_protos", - ) - native.bind( - name = "http_api_protos", - actual = "@googleapis//:http_api_protos", - ) + api_dependencies() diff --git a/bazel/cc_configure.bzl b/bazel/cc_configure.bzl deleted file mode 100644 index 30275140b917..000000000000 --- a/bazel/cc_configure.bzl +++ /dev/null @@ -1,79 +0,0 @@ -load("@bazel_tools//tools/cpp:cc_configure.bzl", _upstream_cc_autoconf_impl = "cc_autoconf_impl") -load("@bazel_tools//tools/cpp:lib_cc_configure.bzl", "get_cpu_value") -load("@bazel_tools//tools/cpp:unix_cc_configure.bzl", "find_cc") - -def _build_envoy_cc_wrapper(repository_ctx): - real_cc = find_cc(repository_ctx, {}) - - # Copy our CC wrapper script into @local_config_cc, with the true paths - # to the C and C++ compiler injected in. The wrapper will use these paths - # to invoke the compiler after deciding which one is correct for the current - # invocation. - # - # Since the script is Python, we can inject values using `repr(str(value))` - # and escaping will be handled correctly. - repository_ctx.template("extra_tools/envoy_cc_wrapper", repository_ctx.attr._envoy_cc_wrapper, { - "{ENVOY_REAL_CC}": repr(str(real_cc)), - "{ENVOY_CFLAGS}": repr(str(repository_ctx.os.environ.get("CFLAGS", ""))), - "{ENVOY_CXXFLAGS}": repr(str(repository_ctx.os.environ.get("CXXFLAGS", ""))), - }) - return repository_ctx.path("extra_tools/envoy_cc_wrapper") - -def _needs_envoy_cc_wrapper(repository_ctx): - # When building for Linux we set additional C++ compiler options that aren't - # handled well by Bazel, so we need a wrapper around $CC to fix its - # compiler invocations. - cpu_value = get_cpu_value(repository_ctx) - return cpu_value not in ["freebsd", "x64_windows", "darwin"] - -def cc_autoconf_impl(repository_ctx): - overriden_tools = {} - if _needs_envoy_cc_wrapper(repository_ctx): - # Bazel uses "gcc" as a generic name for all C and C++ compilers. - overriden_tools["gcc"] = _build_envoy_cc_wrapper(repository_ctx) - return _upstream_cc_autoconf_impl(repository_ctx, overriden_tools = overriden_tools) - -cc_autoconf = repository_rule( - implementation = cc_autoconf_impl, - attrs = { - "_envoy_cc_wrapper": attr.label(default = "@envoy//bazel:cc_wrapper.py"), - }, - environ = [ - "ABI_LIBC_VERSION", - "ABI_VERSION", - "BAZEL_COMPILER", - "BAZEL_HOST_SYSTEM", - "BAZEL_CXXOPTS", - "BAZEL_LINKOPTS", - "BAZEL_PYTHON", - "BAZEL_SH", - "BAZEL_TARGET_CPU", - "BAZEL_TARGET_LIBC", - "BAZEL_TARGET_SYSTEM", - "BAZEL_USE_CPP_ONLY_TOOLCHAIN", - "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN", - "BAZEL_USE_LLVM_NATIVE_COVERAGE", - "BAZEL_VC", - "BAZEL_VS", - "BAZEL_LLVM", - "USE_CLANG_CL", - "CC", - "CFLAGS", - "CXXFLAGS", - "CC_CONFIGURE_DEBUG", - "CC_TOOLCHAIN_NAME", - "CPLUS_INCLUDE_PATH", - "GCOV", - "HOMEBREW_RUBY_PATH", - "SYSTEMROOT", - "VS90COMNTOOLS", - "VS100COMNTOOLS", - "VS110COMNTOOLS", - "VS120COMNTOOLS", - "VS140COMNTOOLS", - ], -) - -def cc_configure(): - cc_autoconf(name = "local_config_cc") - native.bind(name = "cc_toolchain", actual = "@local_config_cc//:toolchain") diff --git a/bazel/cc_wrapper.py b/bazel/cc_wrapper.py deleted file mode 100755 index 41029a05eb4b..000000000000 --- a/bazel/cc_wrapper.py +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/python3 -import contextlib -import os -import shlex -import sys -import tempfile - -compiler = {ENVOY_REAL_CC} -envoy_cflags = {ENVOY_CFLAGS} -envoy_cxxflags = {ENVOY_CXXFLAGS} - - -@contextlib.contextmanager -def closing_fd(fd): - try: - yield fd - finally: - os.close(fd) - - -def sanitize_flagfile(in_path, out_fd): - with open(in_path, "rb") as in_fp: - for line in in_fp: - if line != "-lstdc++\n": - os.write(out_fd, line) - elif "-stdlib=libc++" in envoy_cxxflags: - os.write(out_fd, "-l:libc++.a\n-l:libc++abi.a\n") - - -# Is the arg a flag indicating that we're building for C++ (rather than C)? -def is_cpp_flag(arg): - return arg in ["-static-libstdc++", "-stdlib=libc++", "-lstdc++", "-lc++" - ] or arg.startswith("-std=c++") or arg.startswith("-std=gnu++") - - -def modify_driver_args(input_driver_flags): - # Detect if we're building for C++ or vanilla C. - if any(map(is_cpp_flag, input_driver_flags)): - # Append CXXFLAGS to all C++ targets (this is mostly for dependencies). - argv = shlex.split(envoy_cxxflags) - else: - # Append CFLAGS to all C targets (this is mostly for dependencies). - argv = shlex.split(envoy_cflags) - - # Either: - # a) remove all occurrences of -lstdc++ (when statically linking against libstdc++), - # b) replace all occurrences of -lstdc++ with -lc++ (when linking against libc++). - if "-static-libstdc++" in input_driver_flags or "-stdlib=libc++" in envoy_cxxflags: - for arg in input_driver_flags: - if arg in ("-lstdc++", "-static-libstdc++"): - pass - elif arg.startswith("-Wl,@"): - # tempfile.mkstemp will write to the out-of-sandbox tempdir - # unless the user has explicitly set environment variables - # before starting Bazel. But here in $PWD is the Bazel sandbox, - # which will be deleted automatically after the compiler exits. - (flagfile_fd, flagfile_path) = tempfile.mkstemp(dir="./", suffix=".linker-params") - with closing_fd(flagfile_fd): - sanitize_flagfile(arg[len("-Wl,@"):], flagfile_fd) - argv.append("-Wl,@" + flagfile_path) - else: - argv.append(arg) - else: - argv += input_driver_flags - - # This flags should after all libraries - if "-static-libstdc++" in input_driver_flags: - argv.append("-l:libstdc++.a") - if "-lstdc++" in input_driver_flags and "-stdlib=libc++" in envoy_cxxflags: - argv.append("-l:libc++.a") - argv.append("-l:libc++abi.a") - - # Bazel will add -fuse-ld=gold in some cases, gcc/clang will take the last -fuse-ld argument, - # so whenever we see lld once, add it to the end. - if "-fuse-ld=lld" in argv: - argv.append("-fuse-ld=lld") - - # Add compiler-specific options - if "clang" in compiler: - # This ensures that STL symbols are included. - # See https://github.com/envoyproxy/envoy/issues/1341 - argv.append("-fno-limit-debug-info") - argv.append("-Wthread-safety") - argv.append("-Wgnu-conditional-omitted-operand") - elif "gcc" in compiler or "g++" in compiler: - # -Wmaybe-initialized is warning about many uses of absl::optional. Disable - # to prevent build breakage. This option does not exist in clang, so setting - # it in clang builds causes a build error because of unknown command line - # flag. - # See https://github.com/envoyproxy/envoy/issues/2987 - argv.append("-Wno-maybe-uninitialized") - - return argv - - -def main(): - # Append CXXFLAGS to correctly detect include paths for either libstdc++ or libc++. - if sys.argv[1:5] == ["-E", "-xc++", "-", "-v"]: - os.execv(compiler, [compiler] + sys.argv[1:] + shlex.split(envoy_cxxflags)) - - if sys.argv[1].startswith("@"): - # Read flags from file - flagfile_path = sys.argv[1][1:] - with open(flagfile_path, "r") as fd: - input_driver_flags = fd.read().splitlines() - - # Compute new args - new_driver_args = modify_driver_args(input_driver_flags) - - # Write args to temp file - (new_flagfile_fd, new_flagfile_path) = tempfile.mkstemp(dir="./", suffix=".linker-params") - - with closing_fd(new_flagfile_fd): - for arg in new_driver_args: - os.write(new_flagfile_fd, bytes(str(arg + "\n").encode("utf-8"))) - - # Provide new arguments using the temp file containing the args - new_args = ["@" + new_flagfile_path] - else: - # TODO(https://github.com/bazelbuild/bazel/issues/7687): Remove this branch - # when Bazel 0.27 is released. - new_args = modify_driver_args(sys.argv[1:]) - - os.execv(compiler, [compiler] + new_args) - - -if __name__ == "__main__": - main() diff --git a/bazel/dependency_imports.bzl b/bazel/dependency_imports.bzl new file mode 100644 index 000000000000..3915eb1b553f --- /dev/null +++ b/bazel/dependency_imports.bzl @@ -0,0 +1,12 @@ +load("@rules_foreign_cc//:workspace_definitions.bzl", "rules_foreign_cc_dependencies") +load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") +load("@envoy//bazel/toolchains:rbe_toolchains_config.bzl", "rbe_toolchains_config") + +# go version for rules_go +GO_VERSION = "1.12.5" + +def envoy_dependency_imports(go_version = GO_VERSION): + rules_foreign_cc_dependencies() + go_rules_dependencies() + go_register_toolchains(go_version) + rbe_toolchains_config() diff --git a/bazel/envoy_binary.bzl b/bazel/envoy_binary.bzl index a7a369e8c16b..edcdd09ae03b 100644 --- a/bazel/envoy_binary.bzl +++ b/bazel/envoy_binary.bzl @@ -4,7 +4,6 @@ load( ":envoy_internal.bzl", "envoy_copts", "envoy_external_dep_path", - "envoy_static_link_libstdcpp_linkopts", "tcmalloc_external_dep", ) @@ -50,25 +49,24 @@ def _envoy_select_exported_symbols(xs): # Compute the final linkopts based on various options. def _envoy_linkopts(): return select({ - # The macOS system library transitively links common libraries (e.g., pthread). - "@envoy//bazel:apple": [ - # See note here: https://luajit.org/install.html - "-pagezero_size 10000", - "-image_base 100000000", - ], - "@envoy//bazel:windows_x86_64": [ - "-DEFAULTLIB:advapi32.lib", - "-DEFAULTLIB:ws2_32.lib", - "-WX", - ], - "//conditions:default": [ - "-pthread", - "-lrt", - "-ldl", - "-Wl,--hash-style=gnu", - ], - }) + envoy_static_link_libstdcpp_linkopts() + \ - _envoy_select_exported_symbols(["-Wl,-E"]) + # The macOS system library transitively links common libraries (e.g., pthread). + "@envoy//bazel:apple": [ + # See note here: https://luajit.org/install.html + "-pagezero_size 10000", + "-image_base 100000000", + ], + "@envoy//bazel:windows_x86_64": [ + "-DEFAULTLIB:advapi32.lib", + "-DEFAULTLIB:ws2_32.lib", + "-WX", + ], + "//conditions:default": [ + "-pthread", + "-lrt", + "-ldl", + "-Wl,--hash-style=gnu", + ], + }) + _envoy_select_exported_symbols(["-Wl,-E"]) def _envoy_stamped_deps(): return select({ diff --git a/bazel/envoy_build_system.bzl b/bazel/envoy_build_system.bzl index 1a7ed4e98d57..4dc11e496c20 100644 --- a/bazel/envoy_build_system.bzl +++ b/bazel/envoy_build_system.bzl @@ -129,12 +129,13 @@ def envoy_proto_descriptor(name, out, srcs = [], external_deps = []): include_paths = [".", native.package_name()] if "api_httpbody_protos" in external_deps: - srcs.append("@googleapis//:api_httpbody_protos_src") - include_paths.append("external/googleapis") + srcs.append("@com_google_googleapis//google/api:httpbody.proto") + include_paths.append("external/com_google_googleapis") if "http_api_protos" in external_deps: - srcs.append("@googleapis//:http_api_protos_src") - include_paths.append("external/googleapis") + srcs.append("@com_google_googleapis//google/api:annotations.proto") + srcs.append("@com_google_googleapis//google/api:http.proto") + include_paths.append("external/com_google_googleapis") if "well_known_protos" in external_deps: srcs.append("@com_google_protobuf//:well_known_protos") diff --git a/bazel/envoy_internal.bzl b/bazel/envoy_internal.bzl index 4ea71659d295..325ea94f5596 100644 --- a/bazel/envoy_internal.bzl +++ b/bazel/envoy_internal.bzl @@ -40,6 +40,10 @@ def envoy_copts(repository, test = False): repository + "//bazel:windows_opt_build": [], repository + "//bazel:windows_fastbuild_build": [], repository + "//bazel:windows_dbg_build": [], + }) + select({ + repository + "//bazel:clang_build": ["-fno-limit-debug-info", "-Wgnu-conditional-omitted-operand"], + repository + "//bazel:gcc_build": ["-Wno-maybe-uninitialized"], + "//conditions:default": [], }) + select({ repository + "//bazel:disable_tcmalloc": ["-DABSL_MALLOC_HOOK_MMAP_DISABLE"], "//conditions:default": ["-DTCMALLOC"], @@ -82,12 +86,6 @@ def envoy_select_force_libcpp(if_libcpp, default = None): "//conditions:default": default or [], }) -def envoy_static_link_libstdcpp_linkopts(): - return envoy_select_force_libcpp( - ["-stdlib=libc++", "-l:libc++.a", "-l:libc++abi.a", "-static-libgcc"], - ["-static-libstdc++", "-static-libgcc"], - ) - # Dependencies on tcmalloc_and_profiler should be wrapped with this function. def tcmalloc_external_dep(repository): return select({ diff --git a/bazel/envoy_library.bzl b/bazel/envoy_library.bzl index 33e9e93fc049..b0f54ea64eb4 100644 --- a/bazel/envoy_library.bzl +++ b/bazel/envoy_library.bzl @@ -113,8 +113,8 @@ def envoy_proto_library(name, external_deps = [], **kwargs): external_proto_deps = [] external_cc_proto_deps = [] if "api_httpbody_protos" in external_deps: - external_cc_proto_deps.append("@googleapis//:api_httpbody_protos") - external_proto_deps.append("@googleapis//:api_httpbody_protos_proto") + external_cc_proto_deps.append("@com_google_googleapis//google/api:httpbody_cc_proto") + external_proto_deps.append("@com_google_googleapis//google/api:httpbody_proto") api_proto_library( name, external_cc_proto_deps = external_cc_proto_deps, diff --git a/bazel/envoy_test.bzl b/bazel/envoy_test.bzl index ea564d619fa8..a2d169a4f900 100644 --- a/bazel/envoy_test.bzl +++ b/bazel/envoy_test.bzl @@ -8,7 +8,6 @@ load( "envoy_external_dep_path", "envoy_linkstatic", "envoy_select_force_libcpp", - "envoy_static_link_libstdcpp_linkopts", "tcmalloc_external_dep", ) @@ -144,8 +143,8 @@ def envoy_cc_test( repository = repository, tags = test_lib_tags, copts = copts, - # Restrict only to the code coverage tools. - visibility = ["@envoy//test/coverage:__pkg__"], + # Allow public visibility so these can be consumed in coverage tests in external projects. + visibility = ["//visibility:public"], ) native.cc_test( name = name, @@ -205,7 +204,7 @@ def envoy_cc_test_binary( envoy_cc_binary( name, testonly = 1, - linkopts = _envoy_test_linkopts() + envoy_static_link_libstdcpp_linkopts(), + linkopts = _envoy_test_linkopts(), **kargs ) diff --git a/bazel/external/gcovr.BUILD b/bazel/external/gcovr.BUILD deleted file mode 100644 index 0215a25da848..000000000000 --- a/bazel/external/gcovr.BUILD +++ /dev/null @@ -1,24 +0,0 @@ -licenses(["notice"]) # Apache 2 - -load("@subpar//:subpar.bzl", "par_binary") - -# gcovr is difficult to run from a CI environment because it has hard -# assumptions about its local working directory, which interact poorly -# with `bazel run`. To make gcovr more mobile, we package it into a -# .par file (a mostly-hermetic "Python binary"). -par_binary( - name = "gcovr", - srcs = [":renamed_gcovr.py"], - main = ":renamed_gcovr.py", - python_version = "PY2", - visibility = ["//visibility:public"], -) - -# par_binary expects its `srcs` to contain only *.py files, but gcovr is -# distributed as a script with no filename extension. Rename it here. -genrule( - name = "gcovr_to_exec_py", - srcs = ["scripts/gcovr"], - outs = ["renamed_gcovr.py"], - cmd = "cat $(location scripts/gcovr) > $(location renamed_gcovr.py)", -) diff --git a/bazel/external/quiche.BUILD b/bazel/external/quiche.BUILD index 23276db96e7c..e08d8a5987eb 100644 --- a/bazel/external/quiche.BUILD +++ b/bazel/external/quiche.BUILD @@ -55,6 +55,7 @@ genrule( quiche_copt = [ # Remove these after upstream fix. "-Wno-unused-parameter", + "-Wno-unused-function", "-Wno-type-limits", # quic_inlined_frame.h uses offsetof() to optimize memory usage in frames. "-Wno-invalid-offsetof", @@ -2032,6 +2033,7 @@ envoy_cc_library( copts = quiche_copt, repository = "@envoy", tags = ["nofips"], + visibility = ["//visibility:public"], deps = [ ":quic_core_connection_lib", ":quic_core_crypto_crypto_handshake_lib", @@ -2574,6 +2576,7 @@ envoy_cc_library( copts = quiche_copt, repository = "@envoy", tags = ["nofips"], + visibility = ["//visibility:public"], deps = [ ":quic_core_alarm_factory_interface_lib", ":quic_core_alarm_interface_lib", @@ -2906,6 +2909,186 @@ envoy_cc_library( ], ) +envoy_cc_test_library( + name = "quic_test_tools_config_peer_lib", + srcs = ["quiche/quic/test_tools/quic_config_peer.cc"], + hdrs = ["quiche/quic/test_tools/quic_config_peer.h"], + copts = quiche_copt, + repository = "@envoy", + deps = [ + ":quic_core_config_lib", + ":quic_core_packets_lib", + ":quic_platform_base", + ], +) + +envoy_cc_test_library( + name = "quic_test_tools_framer_peer_lib", + srcs = ["quiche/quic/test_tools/quic_framer_peer.cc"], + hdrs = ["quiche/quic/test_tools/quic_framer_peer.h"], + copts = quiche_copt, + repository = "@envoy", + deps = [ + ":quic_core_crypto_encryption_lib", + ":quic_core_framer_lib", + ":quic_core_packets_lib", + ":quic_platform_base", + ], +) + +envoy_cc_test_library( + name = "quic_test_tools_mock_clock_lib", + srcs = ["quiche/quic/test_tools/mock_clock.cc"], + hdrs = ["quiche/quic/test_tools/mock_clock.h"], + copts = quiche_copt, + repository = "@envoy", + deps = [ + ":quic_core_time_lib", + ":quic_platform", + ], +) + +envoy_cc_test_library( + name = "quic_test_tools_mock_random_lib", + srcs = ["quiche/quic/test_tools/mock_random.cc"], + hdrs = ["quiche/quic/test_tools/mock_random.h"], + copts = quiche_copt, + repository = "@envoy", + deps = [":quic_core_crypto_random_lib"], +) + +envoy_cc_test_library( + name = "quic_test_tools_packet_generator_peer_lib", + srcs = ["quiche/quic/test_tools/quic_packet_generator_peer.cc"], + hdrs = ["quiche/quic/test_tools/quic_packet_generator_peer.h"], + copts = quiche_copt, + repository = "@envoy", + deps = [ + ":quic_core_packet_creator_lib", + ":quic_core_packet_generator_lib", + ":quic_core_packets_lib", + ], +) + +envoy_cc_test_library( + name = "quic_test_tools_sent_packet_manager_peer_lib", + srcs = ["quiche/quic/test_tools/quic_sent_packet_manager_peer.cc"], + hdrs = ["quiche/quic/test_tools/quic_sent_packet_manager_peer.h"], + copts = quiche_copt, + repository = "@envoy", + deps = [ + ":quic_core_congestion_control_congestion_control_interface_lib", + ":quic_core_packets_lib", + ":quic_core_sent_packet_manager_lib", + ":quic_test_tools_unacked_packet_map_peer_lib", + ], +) + +envoy_cc_test_library( + name = "quic_test_tools_simple_quic_framer_lib", + srcs = ["quiche/quic/test_tools/simple_quic_framer.cc"], + hdrs = ["quiche/quic/test_tools/simple_quic_framer.h"], + copts = quiche_copt, + repository = "@envoy", + deps = [ + ":quic_core_crypto_encryption_lib", + ":quic_core_framer_lib", + ":quic_core_packets_lib", + ":quic_platform_base", + ], +) + +envoy_cc_test_library( + name = "quic_test_tools_stream_send_buffer_peer_lib", + srcs = ["quiche/quic/test_tools/quic_stream_send_buffer_peer.cc"], + hdrs = ["quiche/quic/test_tools/quic_stream_send_buffer_peer.h"], + copts = quiche_copt, + repository = "@envoy", + deps = [":quic_core_stream_send_buffer_lib"], +) + +envoy_cc_test_library( + name = "quic_test_tools_stream_peer_lib", + srcs = ["quiche/quic/test_tools/quic_stream_peer.cc"], + hdrs = ["quiche/quic/test_tools/quic_stream_peer.h"], + copts = quiche_copt, + repository = "@envoy", + deps = [ + ":quic_core_packets_lib", + ":quic_core_session_lib", + ":quic_core_stream_send_buffer_lib", + ":quic_platform_base", + ":quic_test_tools_stream_send_buffer_peer_lib", + ], +) + +envoy_cc_test_library( + name = "quic_test_tools_test_utils_interface_lib", + srcs = [ + "quiche/quic/test_tools/crypto_test_utils.cc", + "quiche/quic/test_tools/mock_quic_session_visitor.cc", + "quiche/quic/test_tools/mock_quic_time_wait_list_manager.cc", + "quiche/quic/test_tools/quic_connection_peer.cc", + "quiche/quic/test_tools/quic_dispatcher_peer.cc", + "quiche/quic/test_tools/quic_test_utils.cc", + ], + hdrs = [ + "quiche/quic/test_tools/crypto_test_utils.h", + "quiche/quic/test_tools/mock_quic_session_visitor.h", + "quiche/quic/test_tools/mock_quic_time_wait_list_manager.h", + "quiche/quic/test_tools/quic_connection_peer.h", + "quiche/quic/test_tools/quic_dispatcher_peer.h", + "quiche/quic/test_tools/quic_test_utils.h", + ], + copts = quiche_copt, + external_deps = ["ssl"], + repository = "@envoy", + deps = [ + ":quic_core_buffer_allocator_lib", + ":quic_core_congestion_control_congestion_control_interface_lib", + ":quic_core_connection_lib", + ":quic_core_connection_stats_lib", + ":quic_core_crypto_crypto_handshake_lib", + ":quic_core_crypto_encryption_lib", + ":quic_core_crypto_proof_source_interface_lib", + ":quic_core_crypto_random_lib", + ":quic_core_data_lib", + ":quic_core_framer_lib", + ":quic_core_http_client_lib", + ":quic_core_http_spdy_session_lib", + ":quic_core_packet_creator_lib", + ":quic_core_packet_writer_interface_lib", + ":quic_core_packets_lib", + ":quic_core_received_packet_manager_lib", + ":quic_core_sent_packet_manager_lib", + ":quic_core_server_id_lib", + ":quic_core_server_lib", + ":quic_core_session_lib", + ":quic_core_time_wait_list_manager_lib", + ":quic_core_utils_lib", + ":quic_platform", + ":quic_platform_test", + ":quic_test_tools_config_peer_lib", + ":quic_test_tools_framer_peer_lib", + ":quic_test_tools_mock_clock_lib", + ":quic_test_tools_mock_random_lib", + ":quic_test_tools_packet_generator_peer_lib", + ":quic_test_tools_sent_packet_manager_peer_lib", + ":quic_test_tools_simple_quic_framer_lib", + ":quic_test_tools_stream_peer_lib", + ":spdy_core_framer_lib", + ], +) + +envoy_cc_test_library( + name = "quic_test_tools_unacked_packet_map_peer_lib", + srcs = ["quiche/quic/test_tools/quic_unacked_packet_map_peer.cc"], + hdrs = ["quiche/quic/test_tools/quic_unacked_packet_map_peer.h"], + copts = quiche_copt, + repository = "@envoy", + deps = [":quic_core_unacked_packet_map_lib"], +) + envoy_cc_test_library( name = "epoll_server_platform", hdrs = [ diff --git a/bazel/foreign_cc/BUILD b/bazel/foreign_cc/BUILD index f6049369a9ad..82fcae17b6a6 100644 --- a/bazel/foreign_cc/BUILD +++ b/bazel/foreign_cc/BUILD @@ -52,10 +52,6 @@ envoy_cmake_external( "CARES_SHARED": "no", "CARES_STATIC": "on", "CMAKE_BUILD_TYPE": "RelWithDebInfo", - # Disable ranlib because it is not handled by bazel, and therefore - # doesn't respect custom toolchains such as the Android NDK, - # see https://github.com/bazelbuild/rules_foreign_cc/issues/252 - "CMAKE_RANLIB": "", }, copy_pdb = True, lib_source = "@com_github_c_ares_c_ares//:all", @@ -95,10 +91,6 @@ envoy_cmake_external( "EVENT__DISABLE_TESTS": "on", "EVENT__LIBRARY_TYPE": "STATIC", "CMAKE_BUILD_TYPE": "Release", - # Disable ranlib because it is not handled by bazel, and therefore - # doesn't respect custom toolchains such as the Android NDK, - # see https://github.com/bazelbuild/rules_foreign_cc/issues/252 - "CMAKE_RANLIB": "", # Force _GNU_SOURCE on for Android builds. This would be contained in # a 'select' but the downstream macro uses a select on all of these # options, and they cannot be nested. @@ -126,10 +118,6 @@ envoy_cmake_external( "CMAKE_BUILD_TYPE": "RelWithDebInfo", "CMAKE_INSTALL_LIBDIR": "lib", "CMAKE_CXX_COMPILER_FORCED": "on", - # Disable ranlib because it is not handled by bazel, and therefore - # doesn't respect custom toolchains such as the Android NDK, - # see https://github.com/bazelbuild/rules_foreign_cc/issues/252 - "CMAKE_RANLIB": "", }, cmake_files_dir = "$BUILD_TMPDIR/lib/CMakeFiles", copy_pdb = True, @@ -149,10 +137,6 @@ envoy_cmake_external( "YAML_CPP_BUILD_TOOLS": "off", "CMAKE_BUILD_TYPE": "RelWithDebInfo", "CMAKE_CXX_COMPILER_FORCED": "on", - # Disable ranlib because it is not handled by bazel, and therefore - # doesn't respect custom toolchains such as the Android NDK, - # see https://github.com/bazelbuild/rules_foreign_cc/issues/252 - "CMAKE_RANLIB": "", }, lib_source = "@com_github_jbeder_yaml_cpp//:all", static_libraries = select({ @@ -167,10 +151,6 @@ envoy_cmake_external( name = "zlib", cache_entries = { "CMAKE_BUILD_TYPE": "RelWithDebInfo", - # Disable ranlib because it is not handled by bazel, and therefore - # doesn't respect custom toolchains such as the Android NDK, - # see https://github.com/bazelbuild/rules_foreign_cc/issues/252 - "CMAKE_RANLIB": "", }, copy_pdb = True, lib_source = "@net_zlib//:all", diff --git a/bazel/foreign_cc/com_lightstep_tracer_cpp.patch b/bazel/foreign_cc/com_lightstep_tracer_cpp.patch index c0a4055ae483..88e1a81ad8b2 100644 --- a/bazel/foreign_cc/com_lightstep_tracer_cpp.patch +++ b/bazel/foreign_cc/com_lightstep_tracer_cpp.patch @@ -5,7 +5,7 @@ srcs = ["collector.proto"], deps = [ - "@lightstep_vendored_googleapis//:googleapis_proto", -+ "@googleapis//:http_api_protos_proto", ++ "@com_google_googleapis//google/api:annotations_proto", "@com_google_protobuf//:timestamp_proto", ], visibility = ["//visibility:public"], diff --git a/bazel/foreign_cc/io_opencensus_cpp.patch b/bazel/foreign_cc/io_opencensus_cpp.patch deleted file mode 100644 index f814d6583d81..000000000000 --- a/bazel/foreign_cc/io_opencensus_cpp.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- BUILD 2019-06-03 18:30:58.511651926 -0700 -+++ opencensus/exporters/trace/stackdriver/BUILD 2019-06-03 18:32:38.107571186 -0700 -@@ -28,7 +28,7 @@ - copts = DEFAULT_COPTS, - visibility = ["//visibility:public"], - deps = [ -- "//google/devtools/cloudtrace/v2:tracing_proto", -+ "@googleapis//:tracing_proto", - "//opencensus/common:version", - "//opencensus/common/internal/grpc:status", - "//opencensus/common/internal/grpc:with_user_agent", diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl index ed14486d3a5e..9cb20ae5f0a3 100644 --- a/bazel/repositories.bzl +++ b/bazel/repositories.bzl @@ -2,13 +2,7 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load(":genrule_repository.bzl", "genrule_repository") load("@envoy_api//bazel:envoy_http_archive.bzl", "envoy_http_archive") load(":repository_locations.bzl", "REPOSITORY_LOCATIONS") -load( - "@bazel_tools//tools/cpp:windows_cc_configure.bzl", - "find_vc_path", - "setup_vc_env_vars", -) -load("@bazel_tools//tools/cpp:lib_cc_configure.bzl", "get_env_var") -load("@envoy_api//bazel:repositories.bzl", "api_dependencies") +load("@com_google_googleapis//:repository_rules.bzl", "switched_rules_by_language") # dict of {build recipe name: longform extension name,} PPC_SKIP_TARGETS = {"luajit": "envoy.filters.http.lua"} @@ -21,9 +15,6 @@ NOBORINGSSL_SKIP_TARGETS = { "tls_inspector": "envoy.filters.listener.tls_inspector", } -# go version for rules_go -GO_VERSION = "1.12.5" - # Make all contents of an external repository accessible under a filegroup. Used for external HTTP # archives, e.g. cares. BUILD_ALL_CONTENT = """filegroup(name = "all", srcs = glob(["**"]), visibility = ["//visibility:public"])""" @@ -140,7 +131,6 @@ def envoy_dependencies(skip_targets = []): _com_github_envoyproxy_sqlparser() _com_github_fmtlib_fmt() _com_github_gabime_spdlog() - _com_github_gcovr_gcovr() _com_github_google_benchmark() _com_github_google_jwt_verify() _com_github_google_libprotobuf_mutator() @@ -163,14 +153,21 @@ def envoy_dependencies(skip_targets = []): _com_lightstep_tracer_cpp() _io_opentracing_cpp() _net_zlib() - - # Used for bundling gcovr into a relocatable .par file. - _repository_impl("subpar") + _repository_impl("bazel_toolchains") _python_deps() _cc_deps() _go_deps(skip_targets) - api_dependencies() + + switched_rules_by_language( + name = "com_google_googleapis_imports", + cc = True, + go = True, + grpc = True, + rules_override = { + "py_proto_library": "@envoy_api//bazel:api_build_system.bzl", + }, + ) def _boringssl(): _repository_impl("boringssl") @@ -257,16 +254,6 @@ def _com_github_gabime_spdlog(): actual = "@com_github_gabime_spdlog//:spdlog", ) -def _com_github_gcovr_gcovr(): - _repository_impl( - name = "com_github_gcovr_gcovr", - build_file = "@envoy//bazel/external:gcovr.BUILD", - ) - native.bind( - name = "gcovr", - actual = "@com_github_gcovr_gcovr//:gcovr", - ) - def _com_github_google_benchmark(): location = REPOSITORY_LOCATIONS["com_github_google_benchmark"] http_archive( @@ -535,8 +522,6 @@ def _io_opencensus_cpp(): location = REPOSITORY_LOCATIONS["io_opencensus_cpp"] http_archive( name = "io_opencensus_cpp", - patch_args = ["-p0"], - patches = ["@envoy//bazel/foreign_cc:io_opencensus_cpp.patch"], **location ) native.bind( diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index 383f40e90c60..7c36dec104f3 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -3,6 +3,14 @@ REPOSITORY_LOCATIONS = dict( sha256 = "3c681998538231a2d24d0c07ed5a7658cb72bfb5fd4bf9911157c0e9ac6a2687", urls = ["https://github.com/bazelbuild/bazel-gazelle/releases/download/0.17.0/bazel-gazelle-0.17.0.tar.gz"], ), + bazel_toolchains = dict( + sha256 = "68e7678473090542e679ce7e6aa8a3ba5669577dede2b404f9865d556bd99f10", + strip_prefix = "bazel-toolchains-0.28.0", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/0.28.0.tar.gz", + "https://github.com/bazelbuild/bazel-toolchains/archive/0.28.0.tar.gz", + ], + ), boringssl = dict( # Use commits from branch "chromium-stable-with-bazel" sha256 = "448773376d063b1e9a19e4fd41002d1a31a968a13be20b3b66ecd4aab9cf14a8", @@ -66,11 +74,6 @@ REPOSITORY_LOCATIONS = dict( strip_prefix = "spdlog-1.3.1", urls = ["https://github.com/gabime/spdlog/archive/v1.3.1.tar.gz"], ), - com_github_gcovr_gcovr = dict( - sha256 = "1c52a71f245adfe1b45e30fbe5015337fe66546f17f40038b3969b7b42acceed", - strip_prefix = "gcovr-3.4", - urls = ["https://github.com/gcovr/gcovr/archive/3.4.tar.gz"], - ), com_github_google_libprotobuf_mutator = dict( sha256 = "97b3639630040f41c45f45838ab00b78909e6b4cb69c8028e01302bea5b79495", strip_prefix = "libprotobuf-mutator-c3d2faf04a1070b0b852b0efdef81e1a81ba925e", @@ -117,9 +120,9 @@ REPOSITORY_LOCATIONS = dict( urls = ["https://github.com/lightstep/lightstep-tracer-cpp/archive/v0.8.0.tar.gz"], ), com_github_datadog_dd_opentracing_cpp = dict( - sha256 = "a3d1c03e7af570fa64c01df259e6e9bb78637a6bd9c65c6bf7e8703e466dc22f", - strip_prefix = "dd-opentracing-cpp-0.4.2", - urls = ["https://github.com/DataDog/dd-opentracing-cpp/archive/v0.4.2.tar.gz"], + sha256 = "f7fb2ad541f812c36fd78f9a38e4582d87dadb563ab80bee3f7c3a2132a425c5", + strip_prefix = "dd-opentracing-cpp-1.0.1", + urls = ["https://github.com/DataDog/dd-opentracing-cpp/archive/v1.0.1.tar.gz"], ), com_github_google_benchmark = dict( sha256 = "3c6a165b6ecc948967a1ead710d4a181d7b0fbcaa183ef7ea84604994966221a", @@ -220,26 +223,19 @@ REPOSITORY_LOCATIONS = dict( urls = ["https://github.com/bazelbuild/rules_go/releases/download/0.18.5/rules_go-0.18.5.tar.gz"], ), rules_foreign_cc = dict( - sha256 = "980c1b74f5c18ea099889b0fb0479ee34b8a02845d3d302ecb16b15d73d624c8", - strip_prefix = "rules_foreign_cc-a0dc109915cea85909bef586e2b2a9bbdc6c8ff5", - # 2019-06-04 - urls = ["https://github.com/bazelbuild/rules_foreign_cc/archive/a0dc109915cea85909bef586e2b2a9bbdc6c8ff5.tar.gz"], + sha256 = "c957e6663094a1478c43330c1bbfa71afeaf1ab86b7565233783301240c7a0ab", + strip_prefix = "rules_foreign_cc-a209b642c7687a8894c19b3dd40e43e6d3f38e83", + # 2019-07-17 + urls = ["https://github.com/bazelbuild/rules_foreign_cc/archive/a209b642c7687a8894c19b3dd40e43e6d3f38e83.tar.gz"], ), six_archive = dict( sha256 = "105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a", - urls = ["https://pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz#md5=34eed507548117b2ab523ab14b2f8b55"], - ), - # I'd love to name this `com_github_google_subpar`, but something in the Subpar - # code assumes its repository name is just `subpar`. - subpar = dict( - sha256 = "b80297a1b8d38027a86836dbadc22f55dc3ecad56728175381aa6330705ac10f", - strip_prefix = "subpar-2.0.0", - urls = ["https://github.com/google/subpar/archive/2.0.0.tar.gz"], + urls = ["https://files.pythonhosted.org/packages/b3/b2/238e2590826bfdd113244a40d9d3eb26918bd798fc187e2360a8367068db/six-1.10.0.tar.gz"], ), io_opencensus_cpp = dict( - sha256 = "d6d68704c419a9e892bd1f942e09509ebc5a318499a1abcf2c09734e5dc56e19", - strip_prefix = "opencensus-cpp-1145dd77ffb7a2845c71c8e6ca188ef55e4ff607", - urls = ["https://github.com/census-instrumentation/opencensus-cpp/archive/1145dd77ffb7a2845c71c8e6ca188ef55e4ff607.tar.gz"], + sha256 = "9223b4d54af4151910dede03aa58247e90df72167fcc91d5f75e73a141568036", + strip_prefix = "opencensus-cpp-e292a374fb42c6cb2743f1689234bd409f4fda20", + urls = ["https://github.com/census-instrumentation/opencensus-cpp/archive/e292a374fb42c6cb2743f1689234bd409f4fda20.tar.gz"], ), com_github_curl = dict( sha256 = "821aeb78421375f70e55381c9ad2474bf279fc454b791b7e95fc83562951c690", diff --git a/bazel/toolchains/BUILD b/bazel/toolchains/BUILD new file mode 100644 index 000000000000..e6a683365028 --- /dev/null +++ b/bazel/toolchains/BUILD @@ -0,0 +1,17 @@ +licenses(["notice"]) # Apache 2 + +platform( + name = "rbe_ubuntu_clang_platform", + parents = ["@rbe_ubuntu_clang//config:platform"], + remote_execution_properties = """ + {PARENT_REMOTE_EXECUTION_PROPERTIES} + properties: { + name: "dockerAddCapabilities" + value: "SYS_PTRACE,NET_RAW,NET_ADMIN" + } + properties: { + name: "dockerNetwork" + value: "standard" + } + """, +) diff --git a/bazel/toolchains/README.md b/bazel/toolchains/README.md new file mode 100644 index 000000000000..38e01600e86e --- /dev/null +++ b/bazel/toolchains/README.md @@ -0,0 +1,13 @@ +# Bazel Toolchains + +This directory contains toolchains config generated for Bazel [RBE](https://docs.bazel.build/versions/master/remote-execution.html) and +[Docker sandbox](https://docs.bazel.build/versions/master/remote-execution-sandbox.html). + +To regenerate toolchain configs, update the docker image information in `rbe_toolchains_config.bzl` and run following command in an +environment with the latest Bazel and Docker installed: + +``` +bazel/toolchains/regenerate.sh +``` + +This will generate configs in `bazel/toolchains/configs`, check in those files so they can be used in CI. diff --git a/bazel/toolchains/configs/.gitignore b/bazel/toolchains/configs/.gitignore new file mode 100644 index 000000000000..9683e8aa4d54 --- /dev/null +++ b/bazel/toolchains/configs/.gitignore @@ -0,0 +1,2 @@ +# RBE autoconfig generator will generate a .bazelrc but we don't need it. +.latest.bazelrc diff --git a/bazel/toolchains/configs/clang/bazel_0.28.0/cc/BUILD b/bazel/toolchains/configs/clang/bazel_0.28.0/cc/BUILD new file mode 100755 index 000000000000..7de0f2682246 --- /dev/null +++ b/bazel/toolchains/configs/clang/bazel_0.28.0/cc/BUILD @@ -0,0 +1,148 @@ +# Copyright 2016 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This becomes the BUILD file for @local_config_cc// under non-FreeBSD unixes. + +package(default_visibility = ["//visibility:public"]) + +load(":cc_toolchain_config.bzl", "cc_toolchain_config") +load(":armeabi_cc_toolchain_config.bzl", "armeabi_cc_toolchain_config") + +licenses(["notice"]) # Apache 2.0 + +cc_library( + name = "malloc", +) + +filegroup( + name = "empty", + srcs = [], +) + +filegroup( + name = "cc_wrapper", + srcs = ["cc_wrapper.sh"], +) + +filegroup( + name = "compiler_deps", + srcs = glob(["extra_tools/**"], allow_empty = True) + [":empty"], +) + +# This is the entry point for --crosstool_top. Toolchains are found +# by lopping off the name of --crosstool_top and searching for +# the "${CPU}" entry in the toolchains attribute. +cc_toolchain_suite( + name = "toolchain", + toolchains = { + "k8|clang": ":cc-compiler-k8", + "k8": ":cc-compiler-k8", + "armeabi-v7a|compiler": ":cc-compiler-armeabi-v7a", + "armeabi-v7a": ":cc-compiler-armeabi-v7a", + }, +) + +cc_toolchain( + name = "cc-compiler-k8", + toolchain_identifier = "local", + toolchain_config = ":local", + all_files = ":compiler_deps", + ar_files = ":compiler_deps", + as_files = ":compiler_deps", + compiler_files = ":compiler_deps", + dwp_files = ":empty", + linker_files = ":compiler_deps", + objcopy_files = ":empty", + strip_files = ":empty", + supports_param_files = 1, +) + +cc_toolchain_config( + name = "local", + cpu = "k8", + compiler = "clang", + toolchain_identifier = "local", + host_system_name = "local", + target_system_name = "local", + target_libc = "local", + abi_version = "local", + abi_libc_version = "local", + cxx_builtin_include_directories = ["/usr/local/include", + "/usr/lib/llvm-8/lib/clang/8.0.1/include", + "/usr/include/x86_64-linux-gnu", + "/usr/include", + "/usr/include/c++/7.4.0", + "/usr/include/x86_64-linux-gnu/c++/7.4.0", + "/usr/include/c++/7.4.0/backward", + "/usr/include/clang/8.0.1/include"], + tool_paths = {"ar": "/usr/bin/ar", + "ld": "/usr/bin/ld", + "cpp": "/usr/bin/cpp", + "gcc": "/usr/lib/llvm-8/bin/clang", + "dwp": "/usr/bin/dwp", + "gcov": "/usr/lib/llvm-8/bin/llvm-profdata", + "nm": "/usr/bin/nm", + "objcopy": "/usr/bin/objcopy", + "objdump": "/usr/bin/objdump", + "strip": "/usr/bin/strip"}, + compile_flags = ["-U_FORTIFY_SOURCE", + "-fstack-protector", + "-Wall", + "-Wthread-safety", + "-Wself-assign", + "-fcolor-diagnostics", + "-fno-omit-frame-pointer"], + opt_compile_flags = ["-g0", + "-O2", + "-D_FORTIFY_SOURCE=1", + "-DNDEBUG", + "-ffunction-sections", + "-fdata-sections"], + dbg_compile_flags = ["-g"], + cxx_flags = ["-std=c++0x"], + link_flags = ["-fuse-ld=gold", + "-Wl,-no-as-needed", + "-Wl,-z,relro,-z,now", + "-B/usr/lib/llvm-8/bin", + "-lm", + "-static-libgcc"], + link_libs = ["-l:libstdc++.a"], + opt_link_flags = ["-Wl,--gc-sections"], + unfiltered_compile_flags = ["-no-canonical-prefixes", + "-Wno-builtin-macro-redefined", + "-D__DATE__=\"redacted\"", + "-D__TIMESTAMP__=\"redacted\"", + "-D__TIME__=\"redacted\""], + coverage_compile_flags = ["-fprofile-instr-generate", "-fcoverage-mapping"], + coverage_link_flags = ["-fprofile-instr-generate"], + supports_start_end_lib = True, +) + +# Android tooling requires a default toolchain for the armeabi-v7a cpu. +cc_toolchain( + name = "cc-compiler-armeabi-v7a", + toolchain_identifier = "stub_armeabi-v7a", + toolchain_config = ":stub_armeabi-v7a", + all_files = ":empty", + ar_files = ":empty", + as_files = ":empty", + compiler_files = ":empty", + dwp_files = ":empty", + linker_files = ":empty", + objcopy_files = ":empty", + strip_files = ":empty", + supports_param_files = 1, +) + +armeabi_cc_toolchain_config(name = "stub_armeabi-v7a") diff --git a/bazel/toolchains/configs/clang/bazel_0.28.0/cc/armeabi_cc_toolchain_config.bzl b/bazel/toolchains/configs/clang/bazel_0.28.0/cc/armeabi_cc_toolchain_config.bzl new file mode 100755 index 000000000000..94e0720bf6c9 --- /dev/null +++ b/bazel/toolchains/configs/clang/bazel_0.28.0/cc/armeabi_cc_toolchain_config.bzl @@ -0,0 +1,82 @@ +# Copyright 2019 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""A Starlark cc_toolchain configuration rule""" + +load( + "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", + "feature", + "tool_path", +) + +def _impl(ctx): + toolchain_identifier = "stub_armeabi-v7a" + host_system_name = "armeabi-v7a" + target_system_name = "armeabi-v7a" + target_cpu = "armeabi-v7a" + target_libc = "armeabi-v7a" + compiler = "compiler" + abi_version = "armeabi-v7a" + abi_libc_version = "armeabi-v7a" + cc_target_os = None + builtin_sysroot = None + action_configs = [] + + supports_pic_feature = feature(name = "supports_pic", enabled = True) + supports_dynamic_linker_feature = feature(name = "supports_dynamic_linker", enabled = True) + features = [supports_dynamic_linker_feature, supports_pic_feature] + + cxx_builtin_include_directories = [] + artifact_name_patterns = [] + make_variables = [] + + tool_paths = [ + tool_path(name = "ar", path = "/bin/false"), + tool_path(name = "compat-ld", path = "/bin/false"), + tool_path(name = "cpp", path = "/bin/false"), + tool_path(name = "dwp", path = "/bin/false"), + tool_path(name = "gcc", path = "/bin/false"), + tool_path(name = "gcov", path = "/bin/false"), + tool_path(name = "ld", path = "/bin/false"), + tool_path(name = "nm", path = "/bin/false"), + tool_path(name = "objcopy", path = "/bin/false"), + tool_path(name = "objdump", path = "/bin/false"), + tool_path(name = "strip", path = "/bin/false"), + ] + + return cc_common.create_cc_toolchain_config_info( + ctx = ctx, + features = features, + action_configs = action_configs, + artifact_name_patterns = artifact_name_patterns, + cxx_builtin_include_directories = cxx_builtin_include_directories, + toolchain_identifier = toolchain_identifier, + host_system_name = host_system_name, + target_system_name = target_system_name, + target_cpu = target_cpu, + target_libc = target_libc, + compiler = compiler, + abi_version = abi_version, + abi_libc_version = abi_libc_version, + tool_paths = tool_paths, + make_variables = make_variables, + builtin_sysroot = builtin_sysroot, + cc_target_os = cc_target_os, + ) + +armeabi_cc_toolchain_config = rule( + implementation = _impl, + attrs = {}, + provides = [CcToolchainConfigInfo], +) diff --git a/bazel/toolchains/configs/clang/bazel_0.28.0/cc/cc_toolchain_config.bzl b/bazel/toolchains/configs/clang/bazel_0.28.0/cc/cc_toolchain_config.bzl new file mode 100755 index 000000000000..f2b12d962963 --- /dev/null +++ b/bazel/toolchains/configs/clang/bazel_0.28.0/cc/cc_toolchain_config.bzl @@ -0,0 +1,1202 @@ +# Copyright 2019 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""A Starlark cc_toolchain configuration rule""" + +load( + "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", + "feature", + "feature_set", + "flag_group", + "flag_set", + "tool_path", + "variable_with_value", + "with_feature_set", +) +load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") + +all_compile_actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.clif_match, + ACTION_NAMES.lto_backend, +] + +all_cpp_compile_actions = [ + ACTION_NAMES.cpp_compile, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.clif_match, +] + +preprocessor_compile_actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.clif_match, +] + +codegen_compile_actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.lto_backend, +] + +all_link_actions = [ + ACTION_NAMES.cpp_link_executable, + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, +] + +def _impl(ctx): + tool_paths = [ + tool_path(name = name, path = path) + for name, path in ctx.attr.tool_paths.items() + ] + action_configs = [] + + supports_pic_feature = feature( + name = "supports_pic", + enabled = True, + ) + supports_start_end_lib_feature = feature( + name = "supports_start_end_lib", + enabled = True, + ) + + default_compile_flags_feature = feature( + name = "default_compile_flags", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.lto_backend, + ACTION_NAMES.clif_match, + ], + flag_groups = ([ + flag_group( + flags = ctx.attr.compile_flags, + ), + ] if ctx.attr.compile_flags else []), + ), + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.lto_backend, + ACTION_NAMES.clif_match, + ], + flag_groups = ([ + flag_group( + flags = ctx.attr.dbg_compile_flags, + ), + ] if ctx.attr.dbg_compile_flags else []), + with_features = [with_feature_set(features = ["dbg"])], + ), + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.lto_backend, + ACTION_NAMES.clif_match, + ], + flag_groups = ([ + flag_group( + flags = ctx.attr.opt_compile_flags, + ), + ] if ctx.attr.opt_compile_flags else []), + with_features = [with_feature_set(features = ["opt"])], + ), + flag_set( + actions = [ + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.lto_backend, + ACTION_NAMES.clif_match, + ], + flag_groups = ([ + flag_group( + flags = ctx.attr.cxx_flags, + ), + ] if ctx.attr.cxx_flags else []), + ), + ], + ) + + default_link_flags_feature = feature( + name = "default_link_flags", + enabled = True, + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = ([ + flag_group( + flags = ctx.attr.link_flags, + ), + ] if ctx.attr.link_flags else []), + ), + flag_set( + actions = all_link_actions, + flag_groups = ([ + flag_group( + flags = ctx.attr.opt_link_flags, + ), + ] if ctx.attr.opt_link_flags else []), + with_features = [with_feature_set(features = ["opt"])], + ), + ], + ) + + dbg_feature = feature(name = "dbg") + + opt_feature = feature(name = "opt") + + sysroot_feature = feature( + name = "sysroot", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.lto_backend, + ACTION_NAMES.clif_match, + ACTION_NAMES.cpp_link_executable, + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ], + flag_groups = [ + flag_group( + flags = ["--sysroot=%{sysroot}"], + expand_if_available = "sysroot", + ), + ], + ), + ], + ) + + fdo_optimize_feature = feature( + name = "fdo_optimize", + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], + flag_groups = [ + flag_group( + flags = [ + "-fprofile-use=%{fdo_profile_path}", + "-fprofile-correction", + ], + expand_if_available = "fdo_profile_path", + ), + ], + ), + ], + provides = ["profile"], + ) + + supports_dynamic_linker_feature = feature(name = "supports_dynamic_linker", enabled = True) + + user_compile_flags_feature = feature( + name = "user_compile_flags", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.lto_backend, + ACTION_NAMES.clif_match, + ], + flag_groups = [ + flag_group( + flags = ["%{user_compile_flags}"], + iterate_over = "user_compile_flags", + expand_if_available = "user_compile_flags", + ), + ], + ), + ], + ) + + unfiltered_compile_flags_feature = feature( + name = "unfiltered_compile_flags", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.lto_backend, + ACTION_NAMES.clif_match, + ], + flag_groups = ([ + flag_group( + flags = ctx.attr.unfiltered_compile_flags, + ), + ] if ctx.attr.unfiltered_compile_flags else []), + ), + ], + ) + + library_search_directories_feature = feature( + name = "library_search_directories", + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + flags = ["-L%{library_search_directories}"], + iterate_over = "library_search_directories", + expand_if_available = "library_search_directories", + ), + ], + ), + ], + ) + + static_libgcc_feature = feature( + name = "static_libgcc", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp_link_executable, + ACTION_NAMES.cpp_link_dynamic_library, + ], + flag_groups = [flag_group(flags = ["-static-libgcc"])], + with_features = [ + with_feature_set(features = ["static_link_cpp_runtimes"]), + ], + ), + ], + ) + + pic_feature = feature( + name = "pic", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_compile, + ], + flag_groups = [ + flag_group(flags = ["-fPIC"], expand_if_available = "pic"), + ], + ), + ], + ) + + per_object_debug_info_feature = feature( + name = "per_object_debug_info", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_module_codegen, + ], + flag_groups = [ + flag_group( + flags = ["-gsplit-dwarf"], + expand_if_available = "per_object_debug_info_file", + ), + ], + ), + ], + ) + + preprocessor_defines_feature = feature( + name = "preprocessor_defines", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.clif_match, + ], + flag_groups = [ + flag_group( + flags = ["-D%{preprocessor_defines}"], + iterate_over = "preprocessor_defines", + ), + ], + ), + ], + ) + + cs_fdo_optimize_feature = feature( + name = "cs_fdo_optimize", + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.lto_backend], + flag_groups = [ + flag_group( + flags = [ + "-fprofile-use=%{fdo_profile_path}", + "-Xclang-only=-Wno-profile-instr-unprofiled", + "-Xclang-only=-Wno-profile-instr-out-of-date", + "-fprofile-correction", + ], + expand_if_available = "fdo_profile_path", + ), + ], + ), + ], + provides = ["csprofile"], + ) + + autofdo_feature = feature( + name = "autofdo", + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], + flag_groups = [ + flag_group( + flags = [ + "-fauto-profile=%{fdo_profile_path}", + "-fprofile-correction", + ], + expand_if_available = "fdo_profile_path", + ), + ], + ), + ], + provides = ["profile"], + ) + + runtime_library_search_directories_feature = feature( + name = "runtime_library_search_directories", + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + iterate_over = "runtime_library_search_directories", + flag_groups = [ + flag_group( + flags = [ + "-Wl,-rpath,$EXEC_ORIGIN/%{runtime_library_search_directories}", + ], + expand_if_true = "is_cc_test", + ), + flag_group( + flags = [ + "-Wl,-rpath,$ORIGIN/%{runtime_library_search_directories}", + ], + expand_if_false = "is_cc_test", + ), + ], + expand_if_available = + "runtime_library_search_directories", + ), + ], + with_features = [ + with_feature_set(features = ["static_link_cpp_runtimes"]), + ], + ), + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + iterate_over = "runtime_library_search_directories", + flag_groups = [ + flag_group( + flags = [ + "-Wl,-rpath,$ORIGIN/%{runtime_library_search_directories}", + ], + ), + ], + expand_if_available = + "runtime_library_search_directories", + ), + ], + with_features = [ + with_feature_set( + not_features = ["static_link_cpp_runtimes"], + ), + ], + ), + ], + ) + + fission_support_feature = feature( + name = "fission_support", + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + flags = ["-Wl,--gdb-index"], + expand_if_available = "is_using_fission", + ), + ], + ), + ], + ) + + shared_flag_feature = feature( + name = "shared_flag", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ], + flag_groups = [flag_group(flags = ["-shared"])], + ), + ], + ) + + random_seed_feature = feature( + name = "random_seed", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_compile, + ], + flag_groups = [ + flag_group( + flags = ["-frandom-seed=%{output_file}"], + expand_if_available = "output_file", + ), + ], + ), + ], + ) + + includes_feature = feature( + name = "includes", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.clif_match, + ACTION_NAMES.objc_compile, + ACTION_NAMES.objcpp_compile, + ], + flag_groups = [ + flag_group( + flags = ["-include", "%{includes}"], + iterate_over = "includes", + expand_if_available = "includes", + ), + ], + ), + ], + ) + + fdo_instrument_feature = feature( + name = "fdo_instrument", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ACTION_NAMES.cpp_link_executable, + ], + flag_groups = [ + flag_group( + flags = [ + "-fprofile-generate=%{fdo_instrument_path}", + "-fno-data-sections", + ], + expand_if_available = "fdo_instrument_path", + ), + ], + ), + ], + provides = ["profile"], + ) + + cs_fdo_instrument_feature = feature( + name = "cs_fdo_instrument", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.lto_backend, + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ACTION_NAMES.cpp_link_executable, + ], + flag_groups = [ + flag_group( + flags = [ + "-fcs-profile-generate=%{cs_fdo_instrument_path}", + ], + expand_if_available = "cs_fdo_instrument_path", + ), + ], + ), + ], + provides = ["csprofile"], + ) + + include_paths_feature = feature( + name = "include_paths", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.clif_match, + ACTION_NAMES.objc_compile, + ACTION_NAMES.objcpp_compile, + ], + flag_groups = [ + flag_group( + flags = ["-iquote", "%{quote_include_paths}"], + iterate_over = "quote_include_paths", + ), + flag_group( + flags = ["-I%{include_paths}"], + iterate_over = "include_paths", + ), + flag_group( + flags = ["-isystem", "%{system_include_paths}"], + iterate_over = "system_include_paths", + ), + ], + ), + ], + ) + + symbol_counts_feature = feature( + name = "symbol_counts", + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + flags = [ + "-Wl,--print-symbol-counts=%{symbol_counts_output}", + ], + expand_if_available = "symbol_counts_output", + ), + ], + ), + ], + ) + + llvm_coverage_map_format_feature = feature( + name = "llvm_coverage_map_format", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.objc_compile, + ACTION_NAMES.objcpp_compile, + ], + flag_groups = [ + flag_group( + flags = [ + "-fprofile-instr-generate", + "-fcoverage-mapping", + ], + ), + ], + ), + flag_set( + actions = [ + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ACTION_NAMES.cpp_link_executable, + "objc-executable", + "objc++-executable", + ], + flag_groups = [ + flag_group(flags = ["-fprofile-instr-generate"]), + ], + ), + ], + requires = [feature_set(features = ["coverage"])], + provides = ["profile"], + ) + + strip_debug_symbols_feature = feature( + name = "strip_debug_symbols", + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + flags = ["-Wl,-S"], + expand_if_available = "strip_debug_symbols", + ), + ], + ), + ], + ) + + build_interface_libraries_feature = feature( + name = "build_interface_libraries", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ], + flag_groups = [ + flag_group( + flags = [ + "%{generate_interface_library}", + "%{interface_library_builder_path}", + "%{interface_library_input_path}", + "%{interface_library_output_path}", + ], + expand_if_available = "generate_interface_library", + ), + ], + with_features = [ + with_feature_set( + features = ["supports_interface_shared_libraries"], + ), + ], + ), + ], + ) + + libraries_to_link_feature = feature( + name = "libraries_to_link", + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + iterate_over = "libraries_to_link", + flag_groups = [ + flag_group( + flags = ["-Wl,--start-lib"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "object_file_group", + ), + ), + flag_group( + flags = ["-Wl,-whole-archive"], + expand_if_true = + "libraries_to_link.is_whole_archive", + ), + flag_group( + flags = ["%{libraries_to_link.object_files}"], + iterate_over = "libraries_to_link.object_files", + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "object_file_group", + ), + ), + flag_group( + flags = ["%{libraries_to_link.name}"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "object_file", + ), + ), + flag_group( + flags = ["%{libraries_to_link.name}"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "interface_library", + ), + ), + flag_group( + flags = ["%{libraries_to_link.name}"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "static_library", + ), + ), + flag_group( + flags = ["-l%{libraries_to_link.name}"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "dynamic_library", + ), + ), + flag_group( + flags = ["-l:%{libraries_to_link.name}"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "versioned_dynamic_library", + ), + ), + flag_group( + flags = ["-Wl,-no-whole-archive"], + expand_if_true = "libraries_to_link.is_whole_archive", + ), + flag_group( + flags = ["-Wl,--end-lib"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "object_file_group", + ), + ), + ], + expand_if_available = "libraries_to_link", + ), + flag_group( + flags = ["-Wl,@%{thinlto_param_file}"], + expand_if_true = "thinlto_param_file", + ), + ], + ), + ], + ) + + user_link_flags_feature = feature( + name = "user_link_flags", + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + flags = ["%{user_link_flags}"], + iterate_over = "user_link_flags", + expand_if_available = "user_link_flags", + ), + ] + ([flag_group(flags = ctx.attr.link_libs)] if ctx.attr.link_libs else []), + ), + ], + ) + + fdo_prefetch_hints_feature = feature( + name = "fdo_prefetch_hints", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.lto_backend, + ], + flag_groups = [ + flag_group( + flags = [ + "-Xclang-only=-mllvm", + "-Xclang-only=-prefetch-hints-file=%{fdo_prefetch_hints_path}", + ], + expand_if_available = "fdo_prefetch_hints_path", + ), + ], + ), + ], + ) + + linkstamps_feature = feature( + name = "linkstamps", + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + flags = ["%{linkstamp_paths}"], + iterate_over = "linkstamp_paths", + expand_if_available = "linkstamp_paths", + ), + ], + ), + ], + ) + + gcc_coverage_map_format_feature = feature( + name = "gcc_coverage_map_format", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.objc_compile, + ACTION_NAMES.objcpp_compile, + "objc-executable", + "objc++-executable", + ], + flag_groups = [ + flag_group( + flags = ["-fprofile-arcs", "-ftest-coverage"], + expand_if_available = "gcov_gcno_file", + ), + ], + ), + flag_set( + actions = [ + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ACTION_NAMES.cpp_link_executable, + ], + flag_groups = [flag_group(flags = ["--coverage"])], + ), + ], + requires = [feature_set(features = ["coverage"])], + provides = ["profile"], + ) + + archiver_flags_feature = feature( + name = "archiver_flags", + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.cpp_link_static_library], + flag_groups = [ + flag_group(flags = ["rcsD"]), + flag_group( + flags = ["%{output_execpath}"], + expand_if_available = "output_execpath", + ), + ], + ), + flag_set( + actions = [ACTION_NAMES.cpp_link_static_library], + flag_groups = [ + flag_group( + iterate_over = "libraries_to_link", + flag_groups = [ + flag_group( + flags = ["%{libraries_to_link.name}"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "object_file", + ), + ), + flag_group( + flags = ["%{libraries_to_link.object_files}"], + iterate_over = "libraries_to_link.object_files", + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "object_file_group", + ), + ), + ], + expand_if_available = "libraries_to_link", + ), + ], + ), + ], + ) + + force_pic_flags_feature = feature( + name = "force_pic_flags", + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.cpp_link_executable], + flag_groups = [ + flag_group( + flags = ["-pie"], + expand_if_available = "force_pic", + ), + ], + ), + ], + ) + + dependency_file_feature = feature( + name = "dependency_file", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.objc_compile, + ACTION_NAMES.objcpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.clif_match, + ], + flag_groups = [ + flag_group( + flags = ["-MD", "-MF", "%{dependency_file}"], + expand_if_available = "dependency_file", + ), + ], + ), + ], + ) + + dynamic_library_linker_tool_feature = feature( + name = "dynamic_library_linker_tool", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ], + flag_groups = [ + flag_group( + flags = [" + cppLinkDynamicLibraryToolPath + "], + expand_if_available = "generate_interface_library", + ), + ], + with_features = [ + with_feature_set( + features = ["supports_interface_shared_libraries"], + ), + ], + ), + ], + ) + + output_execpath_flags_feature = feature( + name = "output_execpath_flags", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ACTION_NAMES.cpp_link_executable, + ], + flag_groups = [ + flag_group( + flags = ["-o", "%{output_execpath}"], + expand_if_available = "output_execpath", + ), + ], + ), + ], + ) + + # Note that we also set --coverage for c++-link-nodeps-dynamic-library. The + # generated code contains references to gcov symbols, and the dynamic linker + # can't resolve them unless the library is linked against gcov. + coverage_feature = feature( + name = "coverage", + provides = ["profile"], + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ], + flag_groups = ([ + flag_group(flags = ctx.attr.coverage_compile_flags), + ] if ctx.attr.coverage_compile_flags else []), + ), + flag_set( + actions = [ + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ACTION_NAMES.cpp_link_executable, + ], + flag_groups = ([ + flag_group(flags = ctx.attr.coverage_link_flags), + ] if ctx.attr.coverage_link_flags else []), + ), + ], + ) + + is_linux = ctx.attr.target_libc != "macosx" + + # TODO(#8303): Mac crosstool should also declare every feature. + if is_linux: + features = [ + dependency_file_feature, + random_seed_feature, + pic_feature, + per_object_debug_info_feature, + preprocessor_defines_feature, + includes_feature, + include_paths_feature, + fdo_instrument_feature, + cs_fdo_instrument_feature, + cs_fdo_optimize_feature, + fdo_prefetch_hints_feature, + autofdo_feature, + build_interface_libraries_feature, + dynamic_library_linker_tool_feature, + symbol_counts_feature, + shared_flag_feature, + linkstamps_feature, + output_execpath_flags_feature, + runtime_library_search_directories_feature, + library_search_directories_feature, + archiver_flags_feature, + force_pic_flags_feature, + fission_support_feature, + strip_debug_symbols_feature, + coverage_feature, + supports_pic_feature, + ] + ( + [ + supports_start_end_lib_feature, + ] if ctx.attr.supports_start_end_lib else [] + ) + [ + default_compile_flags_feature, + default_link_flags_feature, + libraries_to_link_feature, + user_link_flags_feature, + static_libgcc_feature, + fdo_optimize_feature, + supports_dynamic_linker_feature, + dbg_feature, + opt_feature, + user_compile_flags_feature, + sysroot_feature, + unfiltered_compile_flags_feature, + ] + else: + features = [ + supports_pic_feature, + ] + ( + [ + supports_start_end_lib_feature, + ] if ctx.attr.supports_start_end_lib else [] + ) + [ + coverage_feature, + default_compile_flags_feature, + default_link_flags_feature, + fdo_optimize_feature, + supports_dynamic_linker_feature, + dbg_feature, + opt_feature, + user_compile_flags_feature, + sysroot_feature, + unfiltered_compile_flags_feature, + ] + + return cc_common.create_cc_toolchain_config_info( + ctx = ctx, + features = features, + action_configs = action_configs, + cxx_builtin_include_directories = ctx.attr.cxx_builtin_include_directories, + toolchain_identifier = ctx.attr.toolchain_identifier, + host_system_name = ctx.attr.host_system_name, + target_system_name = ctx.attr.target_system_name, + target_cpu = ctx.attr.cpu, + target_libc = ctx.attr.target_libc, + compiler = ctx.attr.compiler, + abi_version = ctx.attr.abi_version, + abi_libc_version = ctx.attr.abi_libc_version, + tool_paths = tool_paths, + ) + +cc_toolchain_config = rule( + implementation = _impl, + attrs = { + "cpu": attr.string(mandatory = True), + "compiler": attr.string(mandatory = True), + "toolchain_identifier": attr.string(mandatory = True), + "host_system_name": attr.string(mandatory = True), + "target_system_name": attr.string(mandatory = True), + "target_libc": attr.string(mandatory = True), + "abi_version": attr.string(mandatory = True), + "abi_libc_version": attr.string(mandatory = True), + "cxx_builtin_include_directories": attr.string_list(), + "tool_paths": attr.string_dict(), + "compile_flags": attr.string_list(), + "dbg_compile_flags": attr.string_list(), + "opt_compile_flags": attr.string_list(), + "cxx_flags": attr.string_list(), + "link_flags": attr.string_list(), + "link_libs": attr.string_list(), + "opt_link_flags": attr.string_list(), + "unfiltered_compile_flags": attr.string_list(), + "coverage_compile_flags": attr.string_list(), + "coverage_link_flags": attr.string_list(), + "supports_start_end_lib": attr.bool(), + }, + provides = [CcToolchainConfigInfo], +) diff --git a/bazel/toolchains/configs/clang/bazel_0.28.0/cc/cc_wrapper.sh b/bazel/toolchains/configs/clang/bazel_0.28.0/cc/cc_wrapper.sh new file mode 100755 index 000000000000..b7ff6355883c --- /dev/null +++ b/bazel/toolchains/configs/clang/bazel_0.28.0/cc/cc_wrapper.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# +# Copyright 2015 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Ship the environment to the C++ action +# +set -eu + +# Set-up the environment + + +# Call the C++ compiler +/usr/lib/llvm-8/bin/clang "$@" diff --git a/bazel/toolchains/configs/clang/bazel_0.28.0/config/BUILD b/bazel/toolchains/configs/clang/bazel_0.28.0/config/BUILD new file mode 100644 index 000000000000..ac2d4d5f1c55 --- /dev/null +++ b/bazel/toolchains/configs/clang/bazel_0.28.0/config/BUILD @@ -0,0 +1,53 @@ +# Copyright 2016 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file is auto-generated by an rbe_autoconfig repository rule +# and should not be modified directly. +# See @bazel_toolchains//rules:rbe_repo.bzl + +package(default_visibility = ["//visibility:public"]) + +toolchain( + name = "cc-toolchain", + exec_compatible_with = [ + "@bazel_tools//platforms:x86_64", + "@bazel_tools//platforms:linux", + "@bazel_tools//tools/cpp:clang", + ], + target_compatible_with = [ + "@bazel_tools//platforms:linux", + "@bazel_tools//platforms:x86_64", + ], + toolchain = "//bazel/toolchains/configs/clang/bazel_0.28.0/cc:cc-compiler-k8", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) + +platform( + name = "platform", + constraint_values = [ + "@bazel_tools//platforms:x86_64", + "@bazel_tools//platforms:linux", + "@bazel_tools//tools/cpp:clang", + ], + remote_execution_properties = """ + properties: { + name: "container-image" + value:"docker://gcr.io/envoy-ci/envoy-build@sha256:9dbe1cba2b3340d49a25a1d286c8d49083ec986a6fead27f487e80ca334f065f" + } + properties { + name: "OSFamily" + value: "Linux" + } + """, +) diff --git a/bazel/toolchains/configs/clang/bazel_0.28.0/java/BUILD b/bazel/toolchains/configs/clang/bazel_0.28.0/java/BUILD new file mode 100644 index 000000000000..7c273a5b0e49 --- /dev/null +++ b/bazel/toolchains/configs/clang/bazel_0.28.0/java/BUILD @@ -0,0 +1,25 @@ +# Copyright 2016 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file is auto-generated by an rbe_autoconfig repository rule +# and should not be modified directly. +# See @bazel_toolchains//rules:rbe_repo.bzl + +package(default_visibility = ["//visibility:public"]) + +java_runtime( + name = "jdk", + srcs = [], + java_home = "/usr/lib/jvm/java-8-openjdk-amd64", +) diff --git a/bazel/toolchains/configs/gcc/bazel_0.28.0/cc/BUILD b/bazel/toolchains/configs/gcc/bazel_0.28.0/cc/BUILD new file mode 100755 index 000000000000..eb9ab72263f1 --- /dev/null +++ b/bazel/toolchains/configs/gcc/bazel_0.28.0/cc/BUILD @@ -0,0 +1,148 @@ +# Copyright 2016 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This becomes the BUILD file for @local_config_cc// under non-FreeBSD unixes. + +package(default_visibility = ["//visibility:public"]) + +load(":cc_toolchain_config.bzl", "cc_toolchain_config") +load(":armeabi_cc_toolchain_config.bzl", "armeabi_cc_toolchain_config") + +licenses(["notice"]) # Apache 2.0 + +cc_library( + name = "malloc", +) + +filegroup( + name = "empty", + srcs = [], +) + +filegroup( + name = "cc_wrapper", + srcs = ["cc_wrapper.sh"], +) + +filegroup( + name = "compiler_deps", + srcs = glob(["extra_tools/**"], allow_empty = True) + [":empty"], +) + +# This is the entry point for --crosstool_top. Toolchains are found +# by lopping off the name of --crosstool_top and searching for +# the "${CPU}" entry in the toolchains attribute. +cc_toolchain_suite( + name = "toolchain", + toolchains = { + "k8|gcc": ":cc-compiler-k8", + "k8": ":cc-compiler-k8", + "armeabi-v7a|compiler": ":cc-compiler-armeabi-v7a", + "armeabi-v7a": ":cc-compiler-armeabi-v7a", + }, +) + +cc_toolchain( + name = "cc-compiler-k8", + toolchain_identifier = "local", + toolchain_config = ":local", + all_files = ":compiler_deps", + ar_files = ":compiler_deps", + as_files = ":compiler_deps", + compiler_files = ":compiler_deps", + dwp_files = ":empty", + linker_files = ":compiler_deps", + objcopy_files = ":empty", + strip_files = ":empty", + supports_param_files = 1, +) + +cc_toolchain_config( + name = "local", + cpu = "k8", + compiler = "gcc", + toolchain_identifier = "local", + host_system_name = "local", + target_system_name = "local", + target_libc = "local", + abi_version = "local", + abi_libc_version = "local", + cxx_builtin_include_directories = ["/usr/lib/gcc/x86_64-linux-gnu/7/include", + "/usr/local/include", + "/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed", + "/usr/include/x86_64-linux-gnu", + "/usr/include", + "/usr/include/c++/7", + "/usr/include/x86_64-linux-gnu/c++/7", + "/usr/include/c++/7/backward"], + tool_paths = {"ar": "/usr/bin/ar", + "ld": "/usr/bin/ld", + "cpp": "/usr/bin/cpp", + "gcc": "/usr/bin/gcc", + "dwp": "/usr/bin/dwp", + "gcov": "/usr/bin/gcov", + "nm": "/usr/bin/nm", + "objcopy": "/usr/bin/objcopy", + "objdump": "/usr/bin/objdump", + "strip": "/usr/bin/strip"}, + compile_flags = ["-U_FORTIFY_SOURCE", + "-fstack-protector", + "-Wall", + "-Wunused-but-set-parameter", + "-Wno-free-nonheap-object", + "-fno-omit-frame-pointer"], + opt_compile_flags = ["-g0", + "-O2", + "-D_FORTIFY_SOURCE=1", + "-DNDEBUG", + "-ffunction-sections", + "-fdata-sections"], + dbg_compile_flags = ["-g"], + cxx_flags = ["-std=c++0x"], + link_flags = ["-fuse-ld=gold", + "-Wl,-no-as-needed", + "-Wl,-z,relro,-z,now", + "-B/usr/bin", + "-pass-exit-codes", + "-lm", + "-static-libgcc"], + link_libs = ["-l:libstdc++.a"], + opt_link_flags = ["-Wl,--gc-sections"], + unfiltered_compile_flags = ["-fno-canonical-system-headers", + "-Wno-builtin-macro-redefined", + "-D__DATE__=\"redacted\"", + "-D__TIMESTAMP__=\"redacted\"", + "-D__TIME__=\"redacted\""], + coverage_compile_flags = ["--coverage"], + coverage_link_flags = ["--coverage"], + supports_start_end_lib = True, +) + +# Android tooling requires a default toolchain for the armeabi-v7a cpu. +cc_toolchain( + name = "cc-compiler-armeabi-v7a", + toolchain_identifier = "stub_armeabi-v7a", + toolchain_config = ":stub_armeabi-v7a", + all_files = ":empty", + ar_files = ":empty", + as_files = ":empty", + compiler_files = ":empty", + dwp_files = ":empty", + linker_files = ":empty", + objcopy_files = ":empty", + strip_files = ":empty", + supports_param_files = 1, +) + +armeabi_cc_toolchain_config(name = "stub_armeabi-v7a") diff --git a/bazel/toolchains/configs/gcc/bazel_0.28.0/cc/armeabi_cc_toolchain_config.bzl b/bazel/toolchains/configs/gcc/bazel_0.28.0/cc/armeabi_cc_toolchain_config.bzl new file mode 100755 index 000000000000..94e0720bf6c9 --- /dev/null +++ b/bazel/toolchains/configs/gcc/bazel_0.28.0/cc/armeabi_cc_toolchain_config.bzl @@ -0,0 +1,82 @@ +# Copyright 2019 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""A Starlark cc_toolchain configuration rule""" + +load( + "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", + "feature", + "tool_path", +) + +def _impl(ctx): + toolchain_identifier = "stub_armeabi-v7a" + host_system_name = "armeabi-v7a" + target_system_name = "armeabi-v7a" + target_cpu = "armeabi-v7a" + target_libc = "armeabi-v7a" + compiler = "compiler" + abi_version = "armeabi-v7a" + abi_libc_version = "armeabi-v7a" + cc_target_os = None + builtin_sysroot = None + action_configs = [] + + supports_pic_feature = feature(name = "supports_pic", enabled = True) + supports_dynamic_linker_feature = feature(name = "supports_dynamic_linker", enabled = True) + features = [supports_dynamic_linker_feature, supports_pic_feature] + + cxx_builtin_include_directories = [] + artifact_name_patterns = [] + make_variables = [] + + tool_paths = [ + tool_path(name = "ar", path = "/bin/false"), + tool_path(name = "compat-ld", path = "/bin/false"), + tool_path(name = "cpp", path = "/bin/false"), + tool_path(name = "dwp", path = "/bin/false"), + tool_path(name = "gcc", path = "/bin/false"), + tool_path(name = "gcov", path = "/bin/false"), + tool_path(name = "ld", path = "/bin/false"), + tool_path(name = "nm", path = "/bin/false"), + tool_path(name = "objcopy", path = "/bin/false"), + tool_path(name = "objdump", path = "/bin/false"), + tool_path(name = "strip", path = "/bin/false"), + ] + + return cc_common.create_cc_toolchain_config_info( + ctx = ctx, + features = features, + action_configs = action_configs, + artifact_name_patterns = artifact_name_patterns, + cxx_builtin_include_directories = cxx_builtin_include_directories, + toolchain_identifier = toolchain_identifier, + host_system_name = host_system_name, + target_system_name = target_system_name, + target_cpu = target_cpu, + target_libc = target_libc, + compiler = compiler, + abi_version = abi_version, + abi_libc_version = abi_libc_version, + tool_paths = tool_paths, + make_variables = make_variables, + builtin_sysroot = builtin_sysroot, + cc_target_os = cc_target_os, + ) + +armeabi_cc_toolchain_config = rule( + implementation = _impl, + attrs = {}, + provides = [CcToolchainConfigInfo], +) diff --git a/bazel/toolchains/configs/gcc/bazel_0.28.0/cc/cc_toolchain_config.bzl b/bazel/toolchains/configs/gcc/bazel_0.28.0/cc/cc_toolchain_config.bzl new file mode 100755 index 000000000000..f2b12d962963 --- /dev/null +++ b/bazel/toolchains/configs/gcc/bazel_0.28.0/cc/cc_toolchain_config.bzl @@ -0,0 +1,1202 @@ +# Copyright 2019 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""A Starlark cc_toolchain configuration rule""" + +load( + "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", + "feature", + "feature_set", + "flag_group", + "flag_set", + "tool_path", + "variable_with_value", + "with_feature_set", +) +load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") + +all_compile_actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.clif_match, + ACTION_NAMES.lto_backend, +] + +all_cpp_compile_actions = [ + ACTION_NAMES.cpp_compile, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.clif_match, +] + +preprocessor_compile_actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.clif_match, +] + +codegen_compile_actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.lto_backend, +] + +all_link_actions = [ + ACTION_NAMES.cpp_link_executable, + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, +] + +def _impl(ctx): + tool_paths = [ + tool_path(name = name, path = path) + for name, path in ctx.attr.tool_paths.items() + ] + action_configs = [] + + supports_pic_feature = feature( + name = "supports_pic", + enabled = True, + ) + supports_start_end_lib_feature = feature( + name = "supports_start_end_lib", + enabled = True, + ) + + default_compile_flags_feature = feature( + name = "default_compile_flags", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.lto_backend, + ACTION_NAMES.clif_match, + ], + flag_groups = ([ + flag_group( + flags = ctx.attr.compile_flags, + ), + ] if ctx.attr.compile_flags else []), + ), + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.lto_backend, + ACTION_NAMES.clif_match, + ], + flag_groups = ([ + flag_group( + flags = ctx.attr.dbg_compile_flags, + ), + ] if ctx.attr.dbg_compile_flags else []), + with_features = [with_feature_set(features = ["dbg"])], + ), + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.lto_backend, + ACTION_NAMES.clif_match, + ], + flag_groups = ([ + flag_group( + flags = ctx.attr.opt_compile_flags, + ), + ] if ctx.attr.opt_compile_flags else []), + with_features = [with_feature_set(features = ["opt"])], + ), + flag_set( + actions = [ + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.lto_backend, + ACTION_NAMES.clif_match, + ], + flag_groups = ([ + flag_group( + flags = ctx.attr.cxx_flags, + ), + ] if ctx.attr.cxx_flags else []), + ), + ], + ) + + default_link_flags_feature = feature( + name = "default_link_flags", + enabled = True, + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = ([ + flag_group( + flags = ctx.attr.link_flags, + ), + ] if ctx.attr.link_flags else []), + ), + flag_set( + actions = all_link_actions, + flag_groups = ([ + flag_group( + flags = ctx.attr.opt_link_flags, + ), + ] if ctx.attr.opt_link_flags else []), + with_features = [with_feature_set(features = ["opt"])], + ), + ], + ) + + dbg_feature = feature(name = "dbg") + + opt_feature = feature(name = "opt") + + sysroot_feature = feature( + name = "sysroot", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.lto_backend, + ACTION_NAMES.clif_match, + ACTION_NAMES.cpp_link_executable, + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ], + flag_groups = [ + flag_group( + flags = ["--sysroot=%{sysroot}"], + expand_if_available = "sysroot", + ), + ], + ), + ], + ) + + fdo_optimize_feature = feature( + name = "fdo_optimize", + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], + flag_groups = [ + flag_group( + flags = [ + "-fprofile-use=%{fdo_profile_path}", + "-fprofile-correction", + ], + expand_if_available = "fdo_profile_path", + ), + ], + ), + ], + provides = ["profile"], + ) + + supports_dynamic_linker_feature = feature(name = "supports_dynamic_linker", enabled = True) + + user_compile_flags_feature = feature( + name = "user_compile_flags", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.lto_backend, + ACTION_NAMES.clif_match, + ], + flag_groups = [ + flag_group( + flags = ["%{user_compile_flags}"], + iterate_over = "user_compile_flags", + expand_if_available = "user_compile_flags", + ), + ], + ), + ], + ) + + unfiltered_compile_flags_feature = feature( + name = "unfiltered_compile_flags", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.lto_backend, + ACTION_NAMES.clif_match, + ], + flag_groups = ([ + flag_group( + flags = ctx.attr.unfiltered_compile_flags, + ), + ] if ctx.attr.unfiltered_compile_flags else []), + ), + ], + ) + + library_search_directories_feature = feature( + name = "library_search_directories", + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + flags = ["-L%{library_search_directories}"], + iterate_over = "library_search_directories", + expand_if_available = "library_search_directories", + ), + ], + ), + ], + ) + + static_libgcc_feature = feature( + name = "static_libgcc", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp_link_executable, + ACTION_NAMES.cpp_link_dynamic_library, + ], + flag_groups = [flag_group(flags = ["-static-libgcc"])], + with_features = [ + with_feature_set(features = ["static_link_cpp_runtimes"]), + ], + ), + ], + ) + + pic_feature = feature( + name = "pic", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_compile, + ], + flag_groups = [ + flag_group(flags = ["-fPIC"], expand_if_available = "pic"), + ], + ), + ], + ) + + per_object_debug_info_feature = feature( + name = "per_object_debug_info", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_module_codegen, + ], + flag_groups = [ + flag_group( + flags = ["-gsplit-dwarf"], + expand_if_available = "per_object_debug_info_file", + ), + ], + ), + ], + ) + + preprocessor_defines_feature = feature( + name = "preprocessor_defines", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.clif_match, + ], + flag_groups = [ + flag_group( + flags = ["-D%{preprocessor_defines}"], + iterate_over = "preprocessor_defines", + ), + ], + ), + ], + ) + + cs_fdo_optimize_feature = feature( + name = "cs_fdo_optimize", + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.lto_backend], + flag_groups = [ + flag_group( + flags = [ + "-fprofile-use=%{fdo_profile_path}", + "-Xclang-only=-Wno-profile-instr-unprofiled", + "-Xclang-only=-Wno-profile-instr-out-of-date", + "-fprofile-correction", + ], + expand_if_available = "fdo_profile_path", + ), + ], + ), + ], + provides = ["csprofile"], + ) + + autofdo_feature = feature( + name = "autofdo", + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], + flag_groups = [ + flag_group( + flags = [ + "-fauto-profile=%{fdo_profile_path}", + "-fprofile-correction", + ], + expand_if_available = "fdo_profile_path", + ), + ], + ), + ], + provides = ["profile"], + ) + + runtime_library_search_directories_feature = feature( + name = "runtime_library_search_directories", + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + iterate_over = "runtime_library_search_directories", + flag_groups = [ + flag_group( + flags = [ + "-Wl,-rpath,$EXEC_ORIGIN/%{runtime_library_search_directories}", + ], + expand_if_true = "is_cc_test", + ), + flag_group( + flags = [ + "-Wl,-rpath,$ORIGIN/%{runtime_library_search_directories}", + ], + expand_if_false = "is_cc_test", + ), + ], + expand_if_available = + "runtime_library_search_directories", + ), + ], + with_features = [ + with_feature_set(features = ["static_link_cpp_runtimes"]), + ], + ), + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + iterate_over = "runtime_library_search_directories", + flag_groups = [ + flag_group( + flags = [ + "-Wl,-rpath,$ORIGIN/%{runtime_library_search_directories}", + ], + ), + ], + expand_if_available = + "runtime_library_search_directories", + ), + ], + with_features = [ + with_feature_set( + not_features = ["static_link_cpp_runtimes"], + ), + ], + ), + ], + ) + + fission_support_feature = feature( + name = "fission_support", + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + flags = ["-Wl,--gdb-index"], + expand_if_available = "is_using_fission", + ), + ], + ), + ], + ) + + shared_flag_feature = feature( + name = "shared_flag", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ], + flag_groups = [flag_group(flags = ["-shared"])], + ), + ], + ) + + random_seed_feature = feature( + name = "random_seed", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_compile, + ], + flag_groups = [ + flag_group( + flags = ["-frandom-seed=%{output_file}"], + expand_if_available = "output_file", + ), + ], + ), + ], + ) + + includes_feature = feature( + name = "includes", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.clif_match, + ACTION_NAMES.objc_compile, + ACTION_NAMES.objcpp_compile, + ], + flag_groups = [ + flag_group( + flags = ["-include", "%{includes}"], + iterate_over = "includes", + expand_if_available = "includes", + ), + ], + ), + ], + ) + + fdo_instrument_feature = feature( + name = "fdo_instrument", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ACTION_NAMES.cpp_link_executable, + ], + flag_groups = [ + flag_group( + flags = [ + "-fprofile-generate=%{fdo_instrument_path}", + "-fno-data-sections", + ], + expand_if_available = "fdo_instrument_path", + ), + ], + ), + ], + provides = ["profile"], + ) + + cs_fdo_instrument_feature = feature( + name = "cs_fdo_instrument", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.lto_backend, + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ACTION_NAMES.cpp_link_executable, + ], + flag_groups = [ + flag_group( + flags = [ + "-fcs-profile-generate=%{cs_fdo_instrument_path}", + ], + expand_if_available = "cs_fdo_instrument_path", + ), + ], + ), + ], + provides = ["csprofile"], + ) + + include_paths_feature = feature( + name = "include_paths", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.clif_match, + ACTION_NAMES.objc_compile, + ACTION_NAMES.objcpp_compile, + ], + flag_groups = [ + flag_group( + flags = ["-iquote", "%{quote_include_paths}"], + iterate_over = "quote_include_paths", + ), + flag_group( + flags = ["-I%{include_paths}"], + iterate_over = "include_paths", + ), + flag_group( + flags = ["-isystem", "%{system_include_paths}"], + iterate_over = "system_include_paths", + ), + ], + ), + ], + ) + + symbol_counts_feature = feature( + name = "symbol_counts", + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + flags = [ + "-Wl,--print-symbol-counts=%{symbol_counts_output}", + ], + expand_if_available = "symbol_counts_output", + ), + ], + ), + ], + ) + + llvm_coverage_map_format_feature = feature( + name = "llvm_coverage_map_format", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.objc_compile, + ACTION_NAMES.objcpp_compile, + ], + flag_groups = [ + flag_group( + flags = [ + "-fprofile-instr-generate", + "-fcoverage-mapping", + ], + ), + ], + ), + flag_set( + actions = [ + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ACTION_NAMES.cpp_link_executable, + "objc-executable", + "objc++-executable", + ], + flag_groups = [ + flag_group(flags = ["-fprofile-instr-generate"]), + ], + ), + ], + requires = [feature_set(features = ["coverage"])], + provides = ["profile"], + ) + + strip_debug_symbols_feature = feature( + name = "strip_debug_symbols", + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + flags = ["-Wl,-S"], + expand_if_available = "strip_debug_symbols", + ), + ], + ), + ], + ) + + build_interface_libraries_feature = feature( + name = "build_interface_libraries", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ], + flag_groups = [ + flag_group( + flags = [ + "%{generate_interface_library}", + "%{interface_library_builder_path}", + "%{interface_library_input_path}", + "%{interface_library_output_path}", + ], + expand_if_available = "generate_interface_library", + ), + ], + with_features = [ + with_feature_set( + features = ["supports_interface_shared_libraries"], + ), + ], + ), + ], + ) + + libraries_to_link_feature = feature( + name = "libraries_to_link", + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + iterate_over = "libraries_to_link", + flag_groups = [ + flag_group( + flags = ["-Wl,--start-lib"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "object_file_group", + ), + ), + flag_group( + flags = ["-Wl,-whole-archive"], + expand_if_true = + "libraries_to_link.is_whole_archive", + ), + flag_group( + flags = ["%{libraries_to_link.object_files}"], + iterate_over = "libraries_to_link.object_files", + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "object_file_group", + ), + ), + flag_group( + flags = ["%{libraries_to_link.name}"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "object_file", + ), + ), + flag_group( + flags = ["%{libraries_to_link.name}"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "interface_library", + ), + ), + flag_group( + flags = ["%{libraries_to_link.name}"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "static_library", + ), + ), + flag_group( + flags = ["-l%{libraries_to_link.name}"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "dynamic_library", + ), + ), + flag_group( + flags = ["-l:%{libraries_to_link.name}"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "versioned_dynamic_library", + ), + ), + flag_group( + flags = ["-Wl,-no-whole-archive"], + expand_if_true = "libraries_to_link.is_whole_archive", + ), + flag_group( + flags = ["-Wl,--end-lib"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "object_file_group", + ), + ), + ], + expand_if_available = "libraries_to_link", + ), + flag_group( + flags = ["-Wl,@%{thinlto_param_file}"], + expand_if_true = "thinlto_param_file", + ), + ], + ), + ], + ) + + user_link_flags_feature = feature( + name = "user_link_flags", + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + flags = ["%{user_link_flags}"], + iterate_over = "user_link_flags", + expand_if_available = "user_link_flags", + ), + ] + ([flag_group(flags = ctx.attr.link_libs)] if ctx.attr.link_libs else []), + ), + ], + ) + + fdo_prefetch_hints_feature = feature( + name = "fdo_prefetch_hints", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.lto_backend, + ], + flag_groups = [ + flag_group( + flags = [ + "-Xclang-only=-mllvm", + "-Xclang-only=-prefetch-hints-file=%{fdo_prefetch_hints_path}", + ], + expand_if_available = "fdo_prefetch_hints_path", + ), + ], + ), + ], + ) + + linkstamps_feature = feature( + name = "linkstamps", + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group( + flags = ["%{linkstamp_paths}"], + iterate_over = "linkstamp_paths", + expand_if_available = "linkstamp_paths", + ), + ], + ), + ], + ) + + gcc_coverage_map_format_feature = feature( + name = "gcc_coverage_map_format", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.objc_compile, + ACTION_NAMES.objcpp_compile, + "objc-executable", + "objc++-executable", + ], + flag_groups = [ + flag_group( + flags = ["-fprofile-arcs", "-ftest-coverage"], + expand_if_available = "gcov_gcno_file", + ), + ], + ), + flag_set( + actions = [ + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ACTION_NAMES.cpp_link_executable, + ], + flag_groups = [flag_group(flags = ["--coverage"])], + ), + ], + requires = [feature_set(features = ["coverage"])], + provides = ["profile"], + ) + + archiver_flags_feature = feature( + name = "archiver_flags", + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.cpp_link_static_library], + flag_groups = [ + flag_group(flags = ["rcsD"]), + flag_group( + flags = ["%{output_execpath}"], + expand_if_available = "output_execpath", + ), + ], + ), + flag_set( + actions = [ACTION_NAMES.cpp_link_static_library], + flag_groups = [ + flag_group( + iterate_over = "libraries_to_link", + flag_groups = [ + flag_group( + flags = ["%{libraries_to_link.name}"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "object_file", + ), + ), + flag_group( + flags = ["%{libraries_to_link.object_files}"], + iterate_over = "libraries_to_link.object_files", + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "object_file_group", + ), + ), + ], + expand_if_available = "libraries_to_link", + ), + ], + ), + ], + ) + + force_pic_flags_feature = feature( + name = "force_pic_flags", + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.cpp_link_executable], + flag_groups = [ + flag_group( + flags = ["-pie"], + expand_if_available = "force_pic", + ), + ], + ), + ], + ) + + dependency_file_feature = feature( + name = "dependency_file", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.objc_compile, + ACTION_NAMES.objcpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.clif_match, + ], + flag_groups = [ + flag_group( + flags = ["-MD", "-MF", "%{dependency_file}"], + expand_if_available = "dependency_file", + ), + ], + ), + ], + ) + + dynamic_library_linker_tool_feature = feature( + name = "dynamic_library_linker_tool", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ], + flag_groups = [ + flag_group( + flags = [" + cppLinkDynamicLibraryToolPath + "], + expand_if_available = "generate_interface_library", + ), + ], + with_features = [ + with_feature_set( + features = ["supports_interface_shared_libraries"], + ), + ], + ), + ], + ) + + output_execpath_flags_feature = feature( + name = "output_execpath_flags", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ACTION_NAMES.cpp_link_executable, + ], + flag_groups = [ + flag_group( + flags = ["-o", "%{output_execpath}"], + expand_if_available = "output_execpath", + ), + ], + ), + ], + ) + + # Note that we also set --coverage for c++-link-nodeps-dynamic-library. The + # generated code contains references to gcov symbols, and the dynamic linker + # can't resolve them unless the library is linked against gcov. + coverage_feature = feature( + name = "coverage", + provides = ["profile"], + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ], + flag_groups = ([ + flag_group(flags = ctx.attr.coverage_compile_flags), + ] if ctx.attr.coverage_compile_flags else []), + ), + flag_set( + actions = [ + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ACTION_NAMES.cpp_link_executable, + ], + flag_groups = ([ + flag_group(flags = ctx.attr.coverage_link_flags), + ] if ctx.attr.coverage_link_flags else []), + ), + ], + ) + + is_linux = ctx.attr.target_libc != "macosx" + + # TODO(#8303): Mac crosstool should also declare every feature. + if is_linux: + features = [ + dependency_file_feature, + random_seed_feature, + pic_feature, + per_object_debug_info_feature, + preprocessor_defines_feature, + includes_feature, + include_paths_feature, + fdo_instrument_feature, + cs_fdo_instrument_feature, + cs_fdo_optimize_feature, + fdo_prefetch_hints_feature, + autofdo_feature, + build_interface_libraries_feature, + dynamic_library_linker_tool_feature, + symbol_counts_feature, + shared_flag_feature, + linkstamps_feature, + output_execpath_flags_feature, + runtime_library_search_directories_feature, + library_search_directories_feature, + archiver_flags_feature, + force_pic_flags_feature, + fission_support_feature, + strip_debug_symbols_feature, + coverage_feature, + supports_pic_feature, + ] + ( + [ + supports_start_end_lib_feature, + ] if ctx.attr.supports_start_end_lib else [] + ) + [ + default_compile_flags_feature, + default_link_flags_feature, + libraries_to_link_feature, + user_link_flags_feature, + static_libgcc_feature, + fdo_optimize_feature, + supports_dynamic_linker_feature, + dbg_feature, + opt_feature, + user_compile_flags_feature, + sysroot_feature, + unfiltered_compile_flags_feature, + ] + else: + features = [ + supports_pic_feature, + ] + ( + [ + supports_start_end_lib_feature, + ] if ctx.attr.supports_start_end_lib else [] + ) + [ + coverage_feature, + default_compile_flags_feature, + default_link_flags_feature, + fdo_optimize_feature, + supports_dynamic_linker_feature, + dbg_feature, + opt_feature, + user_compile_flags_feature, + sysroot_feature, + unfiltered_compile_flags_feature, + ] + + return cc_common.create_cc_toolchain_config_info( + ctx = ctx, + features = features, + action_configs = action_configs, + cxx_builtin_include_directories = ctx.attr.cxx_builtin_include_directories, + toolchain_identifier = ctx.attr.toolchain_identifier, + host_system_name = ctx.attr.host_system_name, + target_system_name = ctx.attr.target_system_name, + target_cpu = ctx.attr.cpu, + target_libc = ctx.attr.target_libc, + compiler = ctx.attr.compiler, + abi_version = ctx.attr.abi_version, + abi_libc_version = ctx.attr.abi_libc_version, + tool_paths = tool_paths, + ) + +cc_toolchain_config = rule( + implementation = _impl, + attrs = { + "cpu": attr.string(mandatory = True), + "compiler": attr.string(mandatory = True), + "toolchain_identifier": attr.string(mandatory = True), + "host_system_name": attr.string(mandatory = True), + "target_system_name": attr.string(mandatory = True), + "target_libc": attr.string(mandatory = True), + "abi_version": attr.string(mandatory = True), + "abi_libc_version": attr.string(mandatory = True), + "cxx_builtin_include_directories": attr.string_list(), + "tool_paths": attr.string_dict(), + "compile_flags": attr.string_list(), + "dbg_compile_flags": attr.string_list(), + "opt_compile_flags": attr.string_list(), + "cxx_flags": attr.string_list(), + "link_flags": attr.string_list(), + "link_libs": attr.string_list(), + "opt_link_flags": attr.string_list(), + "unfiltered_compile_flags": attr.string_list(), + "coverage_compile_flags": attr.string_list(), + "coverage_link_flags": attr.string_list(), + "supports_start_end_lib": attr.bool(), + }, + provides = [CcToolchainConfigInfo], +) diff --git a/bazel/toolchains/configs/gcc/bazel_0.28.0/cc/cc_wrapper.sh b/bazel/toolchains/configs/gcc/bazel_0.28.0/cc/cc_wrapper.sh new file mode 100755 index 000000000000..f246528abf2e --- /dev/null +++ b/bazel/toolchains/configs/gcc/bazel_0.28.0/cc/cc_wrapper.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# +# Copyright 2015 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Ship the environment to the C++ action +# +set -eu + +# Set-up the environment + + +# Call the C++ compiler +/usr/bin/gcc "$@" diff --git a/bazel/toolchains/configs/gcc/bazel_0.28.0/config/BUILD b/bazel/toolchains/configs/gcc/bazel_0.28.0/config/BUILD new file mode 100644 index 000000000000..2d431bd2ce03 --- /dev/null +++ b/bazel/toolchains/configs/gcc/bazel_0.28.0/config/BUILD @@ -0,0 +1,53 @@ +# Copyright 2016 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file is auto-generated by an rbe_autoconfig repository rule +# and should not be modified directly. +# See @bazel_toolchains//rules:rbe_repo.bzl + +package(default_visibility = ["//visibility:public"]) + +toolchain( + name = "cc-toolchain", + exec_compatible_with = [ + "@bazel_tools//platforms:x86_64", + "@bazel_tools//platforms:linux", + "@bazel_tools//tools/cpp:clang", + ], + target_compatible_with = [ + "@bazel_tools//platforms:linux", + "@bazel_tools//platforms:x86_64", + ], + toolchain = "//bazel/toolchains/configs/gcc/bazel_0.28.0/cc:cc-compiler-k8", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) + +platform( + name = "platform", + constraint_values = [ + "@bazel_tools//platforms:x86_64", + "@bazel_tools//platforms:linux", + "@bazel_tools//tools/cpp:clang", + ], + remote_execution_properties = """ + properties: { + name: "container-image" + value:"docker://gcr.io/envoy-ci/envoy-build@sha256:9dbe1cba2b3340d49a25a1d286c8d49083ec986a6fead27f487e80ca334f065f" + } + properties { + name: "OSFamily" + value: "Linux" + } + """, +) diff --git a/bazel/toolchains/configs/gcc/bazel_0.28.0/java/BUILD b/bazel/toolchains/configs/gcc/bazel_0.28.0/java/BUILD new file mode 100644 index 000000000000..7c273a5b0e49 --- /dev/null +++ b/bazel/toolchains/configs/gcc/bazel_0.28.0/java/BUILD @@ -0,0 +1,25 @@ +# Copyright 2016 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file is auto-generated by an rbe_autoconfig repository rule +# and should not be modified directly. +# See @bazel_toolchains//rules:rbe_repo.bzl + +package(default_visibility = ["//visibility:public"]) + +java_runtime( + name = "jdk", + srcs = [], + java_home = "/usr/lib/jvm/java-8-openjdk-amd64", +) diff --git a/bazel/toolchains/configs/versions.bzl b/bazel/toolchains/configs/versions.bzl new file mode 100644 index 000000000000..6704b14fa542 --- /dev/null +++ b/bazel/toolchains/configs/versions.bzl @@ -0,0 +1,17 @@ +# Generated file, do not modify by hand +# Generated by 'rbe_ubuntu_gcc_gen' rbe_autoconfig rule +"""Definitions to be used in rbe_repo attr of an rbe_autoconf rule """ +toolchain_config_spec0 = struct(config_repos = [], create_cc_configs = True, create_java_configs = True, env = {"BAZEL_COMPILER": "clang", "BAZEL_LINKLIBS": "-l%:libstdc++.a", "BAZEL_LINKOPTS": "-lm:-static-libgcc", "BAZEL_USE_LLVM_NATIVE_COVERAGE": "1", "GCOV": "llvm-profdata", "CC": "clang", "CXX": "clang++", "PATH": "/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/llvm-8/bin"}, java_home = "/usr/lib/jvm/java-8-openjdk-amd64", name = "clang") +toolchain_config_spec1 = struct(config_repos = [], create_cc_configs = True, create_java_configs = True, env = {"BAZEL_COMPILER": "gcc", "BAZEL_LINKLIBS": "-l%:libstdc++.a", "BAZEL_LINKOPTS": "-lm:-static-libgcc", "CC": "gcc", "CXX": "g++", "PATH": "/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/llvm-8/bin"}, java_home = "/usr/lib/jvm/java-8-openjdk-amd64", name = "gcc") +_TOOLCHAIN_CONFIG_SPECS = [toolchain_config_spec0,toolchain_config_spec1] +_BAZEL_TO_CONFIG_SPEC_NAMES = {"0.28.0": ["clang", "gcc"]} +LATEST = "sha256:9dbe1cba2b3340d49a25a1d286c8d49083ec986a6fead27f487e80ca334f065f" +_CONTAINER_TO_CONFIG_SPEC_NAMES = {"sha256:9dbe1cba2b3340d49a25a1d286c8d49083ec986a6fead27f487e80ca334f065f": ["clang", "gcc"]} +_DEFAULT_TOOLCHAIN_CONFIG_SPEC = toolchain_config_spec0 +TOOLCHAIN_CONFIG_AUTOGEN_SPEC = struct( + bazel_to_config_spec_names_map = _BAZEL_TO_CONFIG_SPEC_NAMES, + container_to_config_spec_names_map = _CONTAINER_TO_CONFIG_SPEC_NAMES, + default_toolchain_config_spec = _DEFAULT_TOOLCHAIN_CONFIG_SPEC, + latest_container = LATEST, + toolchain_config_specs = _TOOLCHAIN_CONFIG_SPECS, + ) \ No newline at end of file diff --git a/bazel/toolchains/empty.bzl b/bazel/toolchains/empty.bzl new file mode 100644 index 000000000000..3fc95e435327 --- /dev/null +++ b/bazel/toolchains/empty.bzl @@ -0,0 +1,18 @@ +_BAZEL_TO_CONFIG_SPEC_NAMES = {} + +# sha256 digest of the latest version of the toolchain container. +LATEST = "" + +_CONTAINER_TO_CONFIG_SPEC_NAMES = {} + +_DEFAULT_TOOLCHAIN_CONFIG_SPEC = "" + +_TOOLCHAIN_CONFIG_SPECS = [] + +TOOLCHAIN_CONFIG_AUTOGEN_SPEC = struct( + bazel_to_config_spec_names_map = _BAZEL_TO_CONFIG_SPEC_NAMES, + container_to_config_spec_names_map = _CONTAINER_TO_CONFIG_SPEC_NAMES, + default_toolchain_config_spec = _DEFAULT_TOOLCHAIN_CONFIG_SPEC, + latest_container = LATEST, + toolchain_config_specs = _TOOLCHAIN_CONFIG_SPECS, +) diff --git a/bazel/toolchains/rbe_toolchains_config.bzl b/bazel/toolchains/rbe_toolchains_config.bzl new file mode 100644 index 000000000000..c1f32be5d78a --- /dev/null +++ b/bazel/toolchains/rbe_toolchains_config.bzl @@ -0,0 +1,80 @@ +load("@bazel_toolchains//rules:rbe_repo.bzl", "rbe_autoconfig") +load("@envoy//bazel/toolchains:configs/versions.bzl", _generated_toolchain_config_suite_autogen_spec = "TOOLCHAIN_CONFIG_AUTOGEN_SPEC") + +_ENVOY_BUILD_IMAGE_REGISTRY = "gcr.io" +_ENVOY_BUILD_IMAGE_REPOSITORY = "envoy-ci/envoy-build" +_ENVOY_BUILD_IMAGE_DIGEST = "sha256:9dbe1cba2b3340d49a25a1d286c8d49083ec986a6fead27f487e80ca334f065f" +_ENVOY_BUILD_IMAGE_JAVA_HOME = "/usr/lib/jvm/java-8-openjdk-amd64" +_CONFIGS_OUTPUT_BASE = "bazel/toolchains/configs" + +_CLANG_ENV = { + "BAZEL_COMPILER": "clang", + "BAZEL_LINKLIBS": "-l%:libstdc++.a", + "BAZEL_LINKOPTS": "-lm:-static-libgcc", + "BAZEL_USE_LLVM_NATIVE_COVERAGE": "1", + "GCOV": "llvm-profdata", + "CC": "clang", + "CXX": "clang++", + "PATH": "/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/llvm-8/bin", +} + +_GCC_ENV = { + "BAZEL_COMPILER": "gcc", + "BAZEL_LINKLIBS": "-l%:libstdc++.a", + "BAZEL_LINKOPTS": "-lm:-static-libgcc", + "CC": "gcc", + "CXX": "g++", + "PATH": "/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/llvm-8/bin", +} + +_TOOLCHAIN_CONFIG_SUITE_SPEC = { + "container_registry": _ENVOY_BUILD_IMAGE_REGISTRY, + "container_repo": _ENVOY_BUILD_IMAGE_REPOSITORY, + "output_base": _CONFIGS_OUTPUT_BASE, + "repo_name": "envoy", + "toolchain_config_suite_autogen_spec": _generated_toolchain_config_suite_autogen_spec, +} + +def _rbe_toolchains_generator(): + rbe_autoconfig( + name = "rbe_ubuntu_clang_gen", + digest = _ENVOY_BUILD_IMAGE_DIGEST, + export_configs = True, + java_home = _ENVOY_BUILD_IMAGE_JAVA_HOME, + registry = _ENVOY_BUILD_IMAGE_REGISTRY, + repository = _ENVOY_BUILD_IMAGE_REPOSITORY, + env = _CLANG_ENV, + toolchain_config_spec_name = "clang", + toolchain_config_suite_spec = _TOOLCHAIN_CONFIG_SUITE_SPEC, + use_checked_in_confs = "False", + ) + + rbe_autoconfig( + name = "rbe_ubuntu_gcc_gen", + digest = _ENVOY_BUILD_IMAGE_DIGEST, + export_configs = True, + java_home = _ENVOY_BUILD_IMAGE_JAVA_HOME, + registry = _ENVOY_BUILD_IMAGE_REGISTRY, + repository = _ENVOY_BUILD_IMAGE_REPOSITORY, + env = _GCC_ENV, + toolchain_config_spec_name = "gcc", + toolchain_config_suite_spec = _TOOLCHAIN_CONFIG_SUITE_SPEC, + use_checked_in_confs = "False", + ) + +def _generated_rbe_toolchains(): + rbe_autoconfig( + name = "rbe_ubuntu_clang", + digest = _ENVOY_BUILD_IMAGE_DIGEST, + export_configs = True, + java_home = _ENVOY_BUILD_IMAGE_JAVA_HOME, + registry = _ENVOY_BUILD_IMAGE_REGISTRY, + repository = _ENVOY_BUILD_IMAGE_REPOSITORY, + toolchain_config_spec_name = "clang", + toolchain_config_suite_spec = _TOOLCHAIN_CONFIG_SUITE_SPEC, + use_checked_in_confs = "Force", + ) + +def rbe_toolchains_config(): + _rbe_toolchains_generator() + _generated_rbe_toolchains() diff --git a/bazel/toolchains/regenerate.sh b/bazel/toolchains/regenerate.sh new file mode 100755 index 000000000000..c71a0506d178 --- /dev/null +++ b/bazel/toolchains/regenerate.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -e + +export RBE_AUTOCONF_ROOT=$(bazel info workspace) + +rm -rf "${RBE_AUTOCONF_ROOT}/bazel/toolchains/configs/*" +cp -vf "${RBE_AUTOCONF_ROOT}/bazel/toolchains/empty.bzl" "${RBE_AUTOCONF_ROOT}/bazel/toolchains/configs/versions.bzl" + +# Bazel query is the right command so bazel won't fail itself. +bazel query "@rbe_ubuntu_clang_gen//..." +bazel query "@rbe_ubuntu_gcc_gen//..." diff --git a/ci/WORKSPACE.filter.example b/ci/WORKSPACE.filter.example index 4eb98345a13f..db20a3146ac9 100644 --- a/ci/WORKSPACE.filter.example +++ b/ci/WORKSPACE.filter.example @@ -2,23 +2,21 @@ workspace(name = "envoy_filter_example") local_repository( name = "envoy", - path = "/source", + path = "{ENVOY_SRCDIR}", ) +load("@envoy//bazel:api_binding.bzl", "envoy_api_binding") + +envoy_api_binding() + load("@envoy//bazel:api_repositories.bzl", "envoy_api_dependencies") + envoy_api_dependencies() -load("@envoy//bazel:repositories.bzl", "envoy_dependencies", "GO_VERSION") -load("@envoy//bazel:cc_configure.bzl", "cc_configure") +load("@envoy//bazel:repositories.bzl", "envoy_dependencies") envoy_dependencies() -# TODO(htuch): Roll this into envoy_dependencies() -load("@rules_foreign_cc//:workspace_definitions.bzl", "rules_foreign_cc_dependencies") -rules_foreign_cc_dependencies() - -cc_configure() +load("@envoy//bazel:dependency_imports.bzl", "envoy_dependency_imports") -load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") -go_rules_dependencies() -go_register_toolchains(go_version = GO_VERSION) +envoy_dependency_imports() diff --git a/ci/build_container/build_container_centos.sh b/ci/build_container/build_container_centos.sh index bf45bcc22a65..b1d15d166db0 100755 --- a/ci/build_container/build_container_centos.sh +++ b/ci/build_container/build_container_centos.sh @@ -12,14 +12,6 @@ yum install -y devtoolset-7-gcc devtoolset-7-gcc-c++ devtoolset-7-binutils java- ln -s /usr/bin/cmake3 /usr/bin/cmake ln -s /usr/bin/ninja-build /usr/bin/ninja -BAZEL_VERSION="$(curl -s https://api.github.com/repos/bazelbuild/bazel/releases/latest | - python -c "import json, sys; print json.load(sys.stdin)['tag_name']")" -BAZEL_INSTALLER="bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh" -curl -OL "https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/${BAZEL_INSTALLER}" -chmod u+x "./${BAZEL_INSTALLER}" -"./${BAZEL_INSTALLER}" -rm "./${BAZEL_INSTALLER}" - # SLES 11 has older glibc than CentOS 7, so pre-built binary for it works on CentOS 7 LLVM_VERSION=8.0.0 LLVM_RELEASE="clang+llvm-${LLVM_VERSION}-x86_64-linux-sles11.3" diff --git a/ci/build_container/build_container_common.sh b/ci/build_container/build_container_common.sh index 4d3218d6482c..a80685ee6ba5 100755 --- a/ci/build_container/build_container_common.sh +++ b/ci/build_container/build_container_common.sh @@ -1,8 +1,17 @@ #!/bin/bash -e -# buildifier -VERSION=0.25.0 -SHA256=6e6aea35b2ea2b4951163f686dfbfe47b49c840c56b873b3a7afe60939772fc1 -curl --location --output /usr/local/bin/buildifier https://github.com/bazelbuild/buildtools/releases/download/"$VERSION"/buildifier \ - && echo "$SHA256" '/usr/local/bin/buildifier' | sha256sum --check \ - && chmod +x /usr/local/bin/buildifier +if [[ "$(uname -m)" == "x86_64" ]]; then + # buildifier + VERSION=0.28.0 + SHA256=3d474be62f8e18190546881daf3c6337d857bf371faf23f508e9b456b0244267 + curl --location --output /usr/local/bin/buildifier https://github.com/bazelbuild/buildtools/releases/download/"$VERSION"/buildifier \ + && echo "$SHA256 /usr/local/bin/buildifier" | sha256sum --check \ + && chmod +x /usr/local/bin/buildifier + + # bazelisk + VERSION=0.0.8 + SHA256=5fced4fec06bf24beb631837fa9497b6698f34041463d9188610dfa7b91f4f8d + curl --location --output /usr/local/bin/bazel https://github.com/bazelbuild/bazelisk/releases/download/v${VERSION}/bazelisk-linux-amd64 \ + && echo "$SHA256 /usr/local/bin/bazel" | sha256sum --check \ + && chmod +x /usr/local/bin/bazel +fi diff --git a/ci/build_container/build_container_ubuntu.sh b/ci/build_container/build_container_ubuntu.sh index 08697220d797..6ca415d11a03 100755 --- a/ci/build_container/build_container_ubuntu.sh +++ b/ci/build_container/build_container_ubuntu.sh @@ -23,7 +23,7 @@ case $ARCH in ldconfig ;; 'x86_64' ) - wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - + wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - apt-add-repository "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main" apt-get update apt-get install -y clang-8 clang-format-8 clang-tidy-8 lld-8 libc++-8-dev libc++abi-8-dev @@ -49,12 +49,6 @@ case $ARCH in -o /usr/local/bin/bazel chmod +x /usr/local/bin/bazel ;; - 'x86_64' ) - echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | tee /etc/apt/sources.list.d/bazel.list - curl https://bazel.build/bazel-release.pub.gpg | apt-key add - - apt-get update - apt-get install -y bazel - ;; esac apt-get install -y aspell rm -rf /var/lib/apt/lists/* diff --git a/ci/build_container/docker_push.sh b/ci/build_container/docker_push.sh index 57d8f1290f96..6edc2c2eeb7b 100755 --- a/ci/build_container/docker_push.sh +++ b/ci/build_container/docker_push.sh @@ -8,45 +8,63 @@ set -e branch_want_push='false' for branch in "master" do - if [ "$CIRCLE_BRANCH" == "$branch" ] - then + if [[ "$CIRCLE_BRANCH" == "$branch" ]]; then branch_want_push='true' fi done -if [ -z "$CIRCLE_PULL_REQUEST" ] && [ "$branch_want_push" == "true" ] -then - diff_want_push='false' - if [[ $(git diff HEAD^ ci/build_container/) ]]; then - echo "There are changes in the ci/build_container directory" - diff_want_push='true' - elif [[ $(git diff HEAD^ bazel/) ]]; then - echo "There are changes in the bazel directory" - diff_want_push='true' - fi - if [ "$diff_want_push" == "true" ]; then - cd ci/build_container - docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" - - for distro in ubuntu centos - do - echo "Updating envoyproxy/envoy-build-${distro} image" - LINUX_DISTRO=$distro ./docker_build.sh - docker push envoyproxy/envoy-build-"${distro}":"$CIRCLE_SHA1" - docker tag envoyproxy/envoy-build-"${distro}":"$CIRCLE_SHA1" envoyproxy/envoy-build-"${distro}":latest - docker push envoyproxy/envoy-build-"${distro}":latest - - if [ "$distro" == "ubuntu" ] - then - echo "Updating envoyproxy/envoy-build image" - docker tag envoyproxy/envoy-build-"${distro}":"$CIRCLE_SHA1" envoyproxy/envoy-build:"$CIRCLE_SHA1" - docker push envoyproxy/envoy-build:"$CIRCLE_SHA1" - docker tag envoyproxy/envoy-build:"$CIRCLE_SHA1" envoyproxy/envoy-build:latest - docker push envoyproxy/envoy-build:latest - fi - done - else - echo "The ci/build_container directory has not changed" + +if [[ -z "${CIRCLE_PR_NUMBER}" && "${branch_want_push}" == "true" ]]; then + diff_base="HEAD^" +else + git fetch https://github.com/envoyproxy/envoy.git master + diff_base="$(git merge-base HEAD FETCH_HEAD)" +fi + +diff_want_build='false' +if [[ ! -z $(git diff --name-only "${diff_base}..HEAD" ci/build_container/) ]]; then + echo "There are changes in the ci/build_container directory" + diff_want_build='true' +fi + +cd ci/build_container +if [ "$diff_want_build" == "true" ]; then + for distro in ubuntu centos + do + echo "Updating envoyproxy/envoy-build-${distro} image" + LINUX_DISTRO=$distro ./docker_build.sh + done +else + echo "The ci/build_container directory has not changed" + exit 0 +fi + +if [[ -z "${CIRCLE_PR_NUMBER}" && "${branch_want_push}" == "true" ]]; then + docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" + + if [[ ! -z "${GCP_SERVICE_ACCOUNT_KEY}" ]]; then + echo ${GCP_SERVICE_ACCOUNT_KEY} | base64 --decode | gcloud auth activate-service-account --key-file=- fi + + for distro in ubuntu centos + do + echo "Updating envoyproxy/envoy-build-${distro} image" + docker push envoyproxy/envoy-build-"${distro}":"$CIRCLE_SHA1" + docker tag envoyproxy/envoy-build-"${distro}":"$CIRCLE_SHA1" envoyproxy/envoy-build-"${distro}":latest + docker push envoyproxy/envoy-build-"${distro}":latest + + if [[ "$distro" == "ubuntu" ]] + then + echo "Updating envoyproxy/envoy-build image" + docker tag envoyproxy/envoy-build-"${distro}":"$CIRCLE_SHA1" envoyproxy/envoy-build:"$CIRCLE_SHA1" + docker push envoyproxy/envoy-build:"$CIRCLE_SHA1" + docker tag envoyproxy/envoy-build:"$CIRCLE_SHA1" envoyproxy/envoy-build:latest + docker push envoyproxy/envoy-build:latest + + echo "Updating gcr.io/envoy-ci/envoy-build image" + docker tag envoyproxy/envoy-build-"${distro}":"$CIRCLE_SHA1" gcr.io/envoy-ci/envoy-build:"$CIRCLE_SHA1" + docker push gcr.io/envoy-ci/envoy-build:"$CIRCLE_SHA1" + fi + done else echo 'Ignoring PR branch for docker push.' fi diff --git a/ci/build_setup.sh b/ci/build_setup.sh index a8069429be0d..d397349da3eb 100755 --- a/ci/build_setup.sh +++ b/ci/build_setup.sh @@ -13,6 +13,7 @@ echo "ENVOY_SRCDIR=${ENVOY_SRCDIR}" function setup_gcc_toolchain() { export CC=gcc export CXX=g++ + export BAZEL_COMPILER=gcc echo "$CC/$CXX toolchain configured" } @@ -20,6 +21,7 @@ function setup_clang_toolchain() { export PATH=/usr/lib/llvm-8/bin:$PATH export CC=clang export CXX=clang++ + export BAZEL_COMPILER=clang export ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-8/bin/llvm-symbolizer echo "$CC/$CXX toolchain configured" } @@ -40,21 +42,6 @@ then fi export ENVOY_FILTER_EXAMPLE_SRCDIR="${BUILD_DIR}/envoy-filter-example" -# Make sure that /source doesn't contain /build on the underlying host -# filesystem, including via hard links or symlinks. We can get into weird -# loops with Bazel symlinking and gcovr's path traversal if this is true, so -# best to keep /source and /build in distinct directories on the host -# filesystem. -SENTINEL="${BUILD_DIR}"/bazel.sentinel -touch "${SENTINEL}" -if [[ -n "$(find -L "${ENVOY_SRCDIR}" -name "$(basename "${SENTINEL}")")" ]] -then - rm -f "${SENTINEL}" - echo "/source mount must not contain /build mount" - exit 1 -fi -rm -f "${SENTINEL}" - # Environment setup. export USER=bazel export TEST_TMPDIR=${BUILD_DIR}/tmp @@ -69,9 +56,8 @@ fi # Not sandboxing, since non-privileged Docker can't do nested namespaces. export BAZEL_QUERY_OPTIONS="${BAZEL_OPTIONS}" -export BAZEL_BUILD_OPTIONS="--strategy=Genrule=standalone --spawn_strategy=standalone \ - --verbose_failures ${BAZEL_OPTIONS} --action_env=HOME --action_env=PYTHONUSERBASE \ - --jobs=${NUM_CPUS} --show_task_finish --experimental_generate_json_trace_profile \ +export BAZEL_BUILD_OPTIONS="--verbose_failures ${BAZEL_OPTIONS} --action_env=HOME --action_env=PYTHONUSERBASE \ + --local_cpu_resources=${NUM_CPUS} --show_task_finish --experimental_generate_json_trace_profile \ --test_env=HOME --test_env=PYTHONUSERBASE --cache_test_results=no --test_output=all \ ${BAZEL_BUILD_EXTRA_OPTIONS} ${BAZEL_EXTRA_TEST_OPTIONS}" @@ -86,7 +72,7 @@ if [ "$1" != "-nofetch" ]; then # This is the hash on https://github.com/envoyproxy/envoy-filter-example.git we pin to. (cd "${ENVOY_FILTER_EXAMPLE_SRCDIR}" && git fetch origin && git checkout -f dcd3374baa9365ab7ab505018232994d6c8a8d81) - cp -f "${ENVOY_SRCDIR}"/ci/WORKSPACE.filter.example "${ENVOY_FILTER_EXAMPLE_SRCDIR}"/WORKSPACE + sed -e "s|{ENVOY_SRCDIR}|${ENVOY_SRCDIR}|" "${ENVOY_SRCDIR}"/ci/WORKSPACE.filter.example > "${ENVOY_FILTER_EXAMPLE_SRCDIR}"/WORKSPACE fi # Also setup some space for building Envoy standalone. diff --git a/ci/coverage_publish.sh b/ci/coverage_publish.sh index a1e08fbc4e95..ad4b05ba3019 100755 --- a/ci/coverage_publish.sh +++ b/ci/coverage_publish.sh @@ -14,7 +14,7 @@ then echo "Uploading coverage report..." [[ -z "${ENVOY_BUILD_DIR}" ]] && ENVOY_BUILD_DIR=/build - COVERAGE_FILE="${ENVOY_BUILD_DIR}/envoy/generated/coverage/coverage.html" + COVERAGE_FILE="${ENVOY_BUILD_DIR}/envoy/generated/coverage/index.html" if [ ! -f "${COVERAGE_FILE}" ]; then echo "ERROR: Coverage file not found." @@ -27,7 +27,7 @@ then pip install awscli --upgrade aws s3 cp "${COVERAGE_DIR}" "s3://${S3_LOCATION}" --recursive --acl public-read --quiet --sse - echo "Coverage report for branch '${BRANCH_NAME}': https://s3.amazonaws.com/${S3_LOCATION}/coverage.html" + echo "Coverage report for branch '${BRANCH_NAME}': https://s3.amazonaws.com/${S3_LOCATION}/index.html" else echo "Coverage report will not be uploaded for this build." fi diff --git a/ci/do_ci.sh b/ci/do_ci.sh index ec4d05496390..867e00c6c2ba 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -97,19 +97,13 @@ if [[ "$CI_TARGET" == "bazel.release" ]]; then # toolchain is kept consistent. This ifdef is checked in # test/common/stats/stat_test_utility.cc when computing # Stats::TestUtil::MemoryTest::mode(). - BAZEL_BUILD_OPTIONS="${BAZEL_BUILD_OPTIONS} --cxxopt=-DMEMORY_TEST_EXACT=1" + BAZEL_BUILD_OPTIONS="${BAZEL_BUILD_OPTIONS} --test_env=ENVOY_MEMORY_TEST_EXACT=true" setup_clang_toolchain echo "bazel release build with tests..." bazel_binary_build release echo "Testing ${TEST_TARGETS}" - if [[ "$TEST_TARGETS" == "//test/..." ]]; then - # We have various test binaries in the test directory such as tools, benchmarks, etc. We - # run a build pass to make sure they compile. - bazel build ${BAZEL_BUILD_OPTIONS} -c opt //include/... //source/exe:envoy-static //test/... - fi - # Now run all of the tests which should already be compiled. bazel_with_collection test ${BAZEL_BUILD_OPTIONS} -c opt ${TEST_TARGETS} exit 0 elif [[ "$CI_TARGET" == "bazel.release.server_only" ]]; then @@ -159,8 +153,8 @@ elif [[ "$CI_TARGET" == "bazel.asan" ]]; then rm -rf "${TAP_TMP}" mkdir -p "${TAP_TMP}" bazel_with_collection test ${BAZEL_BUILD_OPTIONS} -c dbg --config=clang-asan \ - //test/extensions/transport_sockets/tls/integration:ssl_integration_test \ - --test_env=TAP_PATH="${TAP_TMP}/tap" + --strategy=TestRunner=local --test_env=TAP_PATH="${TAP_TMP}/tap" \ + //test/extensions/transport_sockets/tls/integration:ssl_integration_test # Verify that some pb_text files have been created. We can't check for pcap, # since tcpdump is not available in general due to CircleCI lack of support # for privileged Docker executors. @@ -213,25 +207,6 @@ elif [[ "$CI_TARGET" == "bazel.compile_time_options" ]]; then # these tests under "-c opt" to save time in CI. bazel test ${BAZEL_BUILD_OPTIONS} ${COMPILE_TIME_OPTIONS} -c opt //test/common/common:assert_test //test/server:server_test exit 0 -elif [[ "$CI_TARGET" == "bazel.ipv6_tests" ]]; then - # This is around until Circle supports IPv6. We try to run a limited set of IPv6 tests as fast - # as possible for basic sanity testing. - - # Hack to avoid returning IPv6 DNS - sed -i 's_#precedence ::ffff:0:0/96 100_precedence ::ffff:0:0/96 100_' /etc/gai.conf - # Debug IPv6 network issues - apt-get update && apt-get install -y dnsutils net-tools curl && \ - ifconfig && \ - route -A inet -A inet6 && \ - curl -v https://go.googlesource.com && \ - curl -6 -v https://go.googlesource.com && \ - dig go.googlesource.com A go.googlesource.com AAAA - - setup_clang_toolchain - echo "Testing..." - bazel_with_collection test ${BAZEL_BUILD_OPTIONS} --test_env=ENVOY_IP_TEST_VERSIONS=v6only -c fastbuild \ - //test/integration/... //test/common/network/... - exit 0 elif [[ "$CI_TARGET" == "bazel.api" ]]; then setup_clang_toolchain echo "Building API..." @@ -241,22 +216,13 @@ elif [[ "$CI_TARGET" == "bazel.api" ]]; then @envoy_api//tools:tap2pcap_test exit 0 elif [[ "$CI_TARGET" == "bazel.coverage" ]]; then - setup_gcc_toolchain + setup_clang_toolchain echo "bazel coverage build with tests ${TEST_TARGETS}" - # gcovr is a pain to run with `bazel run`, so package it up into a - # relocatable and hermetic-ish .par file. - bazel build --python_version=PY2 @com_github_gcovr_gcovr//:gcovr.par - export GCOVR="/tmp/gcovr.par" - cp -f "${ENVOY_SRCDIR}/bazel-bin/external/com_github_gcovr_gcovr/gcovr.par" ${GCOVR} - - # Reduce the amount of memory and number of cores Bazel tries to use to - # prevent it from launching too many subprocesses. This should prevent the - # system from running out of memory and killing tasks. See discussion on + # Reduce the amount of memory Bazel tries to use to prevent it from launching too many subprocesses. + # This should prevent the system from running out of memory and killing tasks. See discussion on # https://github.com/envoyproxy/envoy/pull/5611. - # TODO(akonradi): use --local_cpu_resources flag once Bazel has a release - # after 0.21. - [ -z "$CIRCLECI" ] || export BAZEL_BUILD_OPTIONS="${BAZEL_BUILD_OPTIONS} --local_resources=12288,4,1" + [ -z "$CIRCLECI" ] || export BAZEL_BUILD_OPTIONS="${BAZEL_BUILD_OPTIONS} --local_ram_resources=12288" test/run_envoy_bazel_coverage.sh ${TEST_TARGETS} collect_build_profile coverage diff --git a/ci/do_circle_ci.sh b/ci/do_circle_ci.sh index c51ee029c3ee..d6e9d214ea63 100755 --- a/ci/do_circle_ci.sh +++ b/ci/do_circle_ci.sh @@ -15,9 +15,8 @@ export ENVOY_SRCDIR="$(pwd)" # hard code this (basically due to how docker works). export NUM_CPUS=8 -# CircleCI doesn't support IPv6 by default, so we run all tests with IPv4, and -# a limited subset with IPv6 using "machine: true" and do_circle_ci_ipv6_tests.sh -# (see https://circleci.com/docs/2.0/executor-types/#using-machine) +# CircleCI doesn't support IPv6 by default, so we run all tests with IPv4 only. +# IPv6 tests are run with Azure Pipelines. export BAZEL_EXTRA_TEST_OPTIONS="--test_env=ENVOY_IP_TEST_VERSIONS=v4only" function finish { diff --git a/ci/do_circle_ci_ipv6_tests.sh b/ci/do_circle_ci_ipv6_tests.sh deleted file mode 100755 index e41d8c6013f6..000000000000 --- a/ci/do_circle_ci_ipv6_tests.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -set -e - -. ./ci/envoy_build_sha.sh - -export ENVOY_SRCDIR="$(pwd)" - -export ENVOY_BUILD_DIR=/tmp/envoy-docker - -export TEST_TYPE="bazel.ipv6_tests" - -function finish { - echo "disk space at end of build:" - df -h -} -trap finish EXIT - -echo "disk space at beginning of build:" -df -h - -docker run -t -i -v "$ENVOY_BUILD_DIR":/build -v "$ENVOY_SRCDIR":/source \ - --env GCP_SERVICE_ACCOUNT_KEY --env BAZEL_REMOTE_CACHE \ - envoyproxy/envoy-build:"$ENVOY_BUILD_SHA" /bin/bash -c "cd /source && ci/do_ci.sh $TEST_TYPE" - diff --git a/ci/filter_example_mirror.sh b/ci/filter_example_mirror.sh index 43949f592121..1d6d5ae05b23 100755 --- a/ci/filter_example_mirror.sh +++ b/ci/filter_example_mirror.sh @@ -2,6 +2,7 @@ set -e +ENVOY_SRCDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/../" && pwd) CHECKOUT_DIR=../envoy-filter-example if [ -z "$CIRCLE_PULL_REQUEST" ] && [ "$CIRCLE_BRANCH" == "master" ] @@ -14,13 +15,17 @@ then git -C "$CHECKOUT_DIR" fetch git -C "$CHECKOUT_DIR" checkout -B master origin/master + echo "Updating Submodule..." # Update submodule to latest Envoy SHA ENVOY_SHA=$(git rev-parse HEAD) git -C "$CHECKOUT_DIR" submodule update --init git -C "$CHECKOUT_DIR/envoy" checkout "$ENVOY_SHA" - git -C "$CHECKOUT_DIR" commit -a -m "Update Envoy submodule to $ENVOY_SHA" - echo "Pushing..." + echo "Updating Workspace file." + sed -e "s|{ENVOY_SRCDIR}|envoy|" "${ENVOY_SRCDIR}"/ci/WORKSPACE.filter.example > "${CHECKOUT_DIR}"/WORKSPACE + + echo "Committing, and Pushing..." + git -C "$CHECKOUT_DIR" commit -a -m "Update Envoy submodule to $ENVOY_SHA" git -C "$CHECKOUT_DIR" push origin master echo "Done" fi diff --git a/ci/mac_ci_setup.sh b/ci/mac_ci_setup.sh index 8e97d63b06a9..42cb7c63faa5 100755 --- a/ci/mac_ci_setup.sh +++ b/ci/mac_ci_setup.sh @@ -5,7 +5,6 @@ # Setup bazelbuild tap brew tap bazelbuild/tap -brew tap-pin bazelbuild/tap function is_installed { brew ls --versions "$1" >/dev/null @@ -25,7 +24,7 @@ if ! brew update; then exit 1 fi -DEPS="automake bazelbuild/tap/bazel cmake coreutils go libtool wget ninja" +DEPS="automake bazelbuild/tap/bazelisk cmake coreutils go libtool wget ninja" for DEP in ${DEPS} do is_installed "${DEP}" || install "${DEP}" diff --git a/ci/mac_ci_steps.sh b/ci/mac_ci_steps.sh index 7d322dafee2a..552f9d7957ad 100755 --- a/ci/mac_ci_steps.sh +++ b/ci/mac_ci_steps.sh @@ -29,5 +29,7 @@ else TEST_TARGETS=//test/... fi -bazel build ${BAZEL_BUILD_OPTIONS} //source/exe:envoy-static ${TEST_TARGETS} +if [[ "$TEST_TARGETS" == "//test/..." ]]; then + bazel build ${BAZEL_BUILD_OPTIONS} //source/exe:envoy-static +fi bazel test ${BAZEL_BUILD_OPTIONS} ${TEST_TARGETS} diff --git a/ci/run_clang_tidy.sh b/ci/run_clang_tidy.sh index dc0e8aead732..9ab612b48d03 100755 --- a/ci/run_clang_tidy.sh +++ b/ci/run_clang_tidy.sh @@ -26,6 +26,13 @@ echo "build ${BAZEL_BUILD_OPTIONS}" >> .bazelrc # by clang-tidy "${ENVOY_SRCDIR}/tools/gen_compilation_database.py" --run_bazel_build --include_headers +# Do not run clang-tidy against win32 impl +# TODO(scw00): We should run clang-tidy against win32 impl. But currently we only have +# linux ci box. +function exclude_win32_impl() { + grep -v source/common/filesystem/win32/ | grep -v source/common/common/win32 | grep -v source/exe/win32 +} + # Do not run incremental clang-tidy on check_format testdata files. function exclude_testdata() { grep -v tools/testdata/check_format/ @@ -38,7 +45,7 @@ function exclude_chromium_url() { } function filter_excludes() { - exclude_testdata | exclude_chromium_url + exclude_testdata | exclude_chromium_url | exclude_win32_impl } if [[ "${RUN_FULL_CLANG_TIDY}" == 1 ]]; then diff --git a/ci/run_envoy_docker.sh b/ci/run_envoy_docker.sh index c6b91fae5f09..af828943fb53 100755 --- a/ci/run_envoy_docker.sh +++ b/ci/run_envoy_docker.sh @@ -18,10 +18,14 @@ USER_GROUP=root [[ -f .git ]] && [[ ! -d .git ]] && GIT_VOLUME_OPTION="-v $(git rev-parse --git-common-dir):$(git rev-parse --git-common-dir)" +[[ -t 1 ]] && DOCKER_TTY_OPTION=-it + mkdir -p "${ENVOY_DOCKER_BUILD_DIR}" # Since we specify an explicit hash, docker-run will pull from the remote repo if missing. -docker run --rm -t -i -e HTTP_PROXY=${http_proxy} -e HTTPS_PROXY=${https_proxy} \ +docker run --rm ${DOCKER_TTY_OPTION} -e HTTP_PROXY=${http_proxy} -e HTTPS_PROXY=${https_proxy} \ -u "${USER}":"${USER_GROUP}" -v "${ENVOY_DOCKER_BUILD_DIR}":/build ${GIT_VOLUME_OPTION} \ - -v "$PWD":/source -e NUM_CPUS --cap-add SYS_PTRACE --cap-add NET_RAW --cap-add NET_ADMIN "${IMAGE_NAME}":"${IMAGE_ID}" \ + -e BAZEL_BUILD_EXTRA_OPTIONS -e BAZEL_EXTRA_TEST_OPTIONS -e BAZEL_REMOTE_CACHE \ + -e BAZEL_REMOTE_INSTANCE -e GCP_SERVICE_ACCOUNT_KEY -e NUM_CPUS \ + -v "$PWD":/source --cap-add SYS_PTRACE --cap-add NET_RAW --cap-add NET_ADMIN "${IMAGE_NAME}":"${IMAGE_ID}" \ /bin/bash -lc "groupadd --gid $(id -g) -f envoygroup && useradd -o --uid $(id -u) --gid $(id -g) --no-create-home \ --home-dir /source envoybuild && usermod -a -G pcap envoybuild && su envoybuild -c \"cd source && $*\"" diff --git a/ci/setup_cache.sh b/ci/setup_cache.sh index f97aa9b34963..699961bbb082 100755 --- a/ci/setup_cache.sh +++ b/ci/setup_cache.sh @@ -17,13 +17,6 @@ if [[ ! -z "${GCP_SERVICE_ACCOUNT_KEY}" ]]; then echo "${GCP_SERVICE_ACCOUNT_KEY}" | base64 --decode > "${GCP_SERVICE_ACCOUNT_KEY_FILE}" fi -if [[ -n "${BAZEL_REMOTE_CACHE}" ]]; then - export BAZEL_BUILD_EXTRA_OPTIONS="${BAZEL_BUILD_EXTRA_OPTIONS} \ - --experimental_inmemory_dotd_files \ - --experimental_inmemory_jdeps_files \ - --experimental_remote_download_outputs=toplevel" -fi - if [[ "${BAZEL_REMOTE_CACHE}" =~ ^http ]]; then if [[ ! -z "${GCP_SERVICE_ACCOUNT_KEY}" ]]; then export BAZEL_BUILD_EXTRA_OPTIONS="${BAZEL_BUILD_EXTRA_OPTIONS} \ @@ -40,7 +33,7 @@ elif [[ ! -z "${BAZEL_REMOTE_CACHE}" ]]; then --remote_cache=${BAZEL_REMOTE_CACHE} \ --remote_instance_name=${BAZEL_REMOTE_INSTANCE} \ --google_credentials=${GCP_SERVICE_ACCOUNT_KEY_FILE} \ - --tls_enabled=true --auth_enabled=true" + --auth_enabled=true" echo "Set up bazel remote read/write cache at ${BAZEL_REMOTE_CACHE} instance: ${BAZEL_REMOTE_INSTANCE}." else echo "No remote cache bucket is set, skipping setup remote cache." diff --git a/configs/configgen.sh b/configs/configgen.sh index 2e82ebff3dd9..cbfa59a79c85 100755 --- a/configs/configgen.sh +++ b/configs/configgen.sh @@ -8,6 +8,7 @@ OUT_DIR="$1" shift mkdir -p "$OUT_DIR/certs" +mkdir -p "$OUT_DIR/lib" "$CONFIGGEN" "$OUT_DIR" for FILE in $*; do @@ -15,6 +16,9 @@ for FILE in $*; do *.pem) cp "$FILE" "$OUT_DIR/certs" ;; + *.lua) + cp "$FILE" "$OUT_DIR/lib" + ;; *) FILENAME="$(echo $FILE | sed -e 's/.*examples\///g')" @@ -25,4 +29,4 @@ for FILE in $*; do done # tar is having issues with -C for some reason so just cd into OUT_DIR. -(cd "$OUT_DIR"; tar -hcvf example_configs.tar *.yaml certs/*.pem) +(cd "$OUT_DIR"; tar -hcvf example_configs.tar *.yaml certs/*.pem lib/*.lua) diff --git a/configs/envoy_double_proxy_v2.template.yaml b/configs/envoy_double_proxy_v2.template.yaml index 2c08332f795d..9cff9a40a6c7 100644 --- a/configs/envoy_double_proxy_v2.template.yaml +++ b/configs/envoy_double_proxy_v2.template.yaml @@ -174,10 +174,19 @@ tracing: "@type": type.googleapis.com/envoy.config.trace.v2.LightstepConfig access_token_file: "/etc/envoy/lightstep_access_token" collector_cluster: lightstep_saas -runtime: - symlink_root: "/srv/runtime_data/current" - subdirectory: envoy - override_subdirectory: envoy_override +layered_runtime: + layers: + - name: root + disk_layer: + symlink_root: /srv/configset/envoydata/current + subdirectory: envoy + - name: override + disk_layer: + symlink_root: /srv/configset/envoydata/current + subdirectory: envoy_override + append_service_cluster: true + - name: admin + admin_layer: {} admin: access_log_path: "/var/log/envoy/admin_access.log" address: diff --git a/configs/envoy_front_proxy_v2.template.yaml b/configs/envoy_front_proxy_v2.template.yaml index 35f734f80ad2..c45bc1e24d0a 100644 --- a/configs/envoy_front_proxy_v2.template.yaml +++ b/configs/envoy_front_proxy_v2.template.yaml @@ -157,10 +157,19 @@ tracing: "@type": type.googleapis.com/envoy.config.trace.v2.LightstepConfig collector_cluster: lightstep_saas access_token_file: "/etc/envoy/lightstep_access_token" -runtime: - symlink_root: /srv/runtime_data/current - subdirectory: envoy - override_subdirectory: envoy_override +layered_runtime: + layers: + - name: root + disk_layer: + symlink_root: /srv/configset/envoydata/current + subdirectory: envoy + - name: override + disk_layer: + symlink_root: /srv/configset/envoydata/current + subdirectory: envoy_override + append_service_cluster: true + - name: admin + admin_layer: {} admin: access_log_path: /var/log/envoy/admin_access.log address: diff --git a/configs/envoy_service_to_service_v2.template.yaml b/configs/envoy_service_to_service_v2.template.yaml index 083a8c39a292..531322b3a14b 100644 --- a/configs/envoy_service_to_service_v2.template.yaml +++ b/configs/envoy_service_to_service_v2.template.yaml @@ -543,10 +543,19 @@ tracing: "@type": type.googleapis.com/envoy.config.trace.v2.LightstepConfig access_token_file: "/etc/envoy/lightstep_access_token" collector_cluster: lightstep_saas -runtime: - symlink_root: "/srv/runtime_data/current" - subdirectory: envoy - override_subdirectory: envoy_override +layered_runtime: + layers: + - name: root + disk_layer: + symlink_root: /srv/configset/envoydata/current + subdirectory: envoy + - name: override + disk_layer: + symlink_root: /srv/configset/envoydata/current + subdirectory: envoy_override + append_service_cluster: true + - name: admin + admin_layer: {} admin: access_log_path: /var/log/envoy/admin_access.log address: diff --git a/docs/build.sh b/docs/build.sh index 8a4c7850908f..acbc73303257 100755 --- a/docs/build.sh +++ b/docs/build.sh @@ -76,6 +76,7 @@ PROTO_RST=" /envoy/api/v2/cds/envoy/api/v2/cds.proto.rst /envoy/api/v2/cluster/outlier_detection/envoy/api/v2/cluster/outlier_detection.proto.rst /envoy/api/v2/cluster/circuit_breaker/envoy/api/v2/cluster/circuit_breaker.proto.rst + /envoy/api/v2/cluster/filter/envoy/api/v2/cluster/filter.proto.rst /envoy/api/v2/rds/envoy/api/v2/rds.proto.rst /envoy/api/v2/route/route/envoy/api/v2/route/route.proto.rst /envoy/api/v2/srds/envoy/api/v2/srds.proto.rst diff --git a/docs/root/api-v2/clusters/clusters.rst b/docs/root/api-v2/clusters/clusters.rst index 8fe24ed0ad24..d84f1020c159 100644 --- a/docs/root/api-v2/clusters/clusters.rst +++ b/docs/root/api-v2/clusters/clusters.rst @@ -8,6 +8,7 @@ Clusters ../api/v2/cds.proto ../api/v2/cluster/outlier_detection.proto ../api/v2/cluster/circuit_breaker.proto + ../api/v2/cluster/filter.proto ../api/v2/endpoint/endpoint.proto ../api/v2/eds.proto ../api/v2/core/health_check.proto diff --git a/docs/root/configuration/http_filters/router_filter.rst b/docs/root/configuration/http_filters/router_filter.rst index 0d416ac86502..e676e267aa4c 100644 --- a/docs/root/configuration/http_filters/router_filter.rst +++ b/docs/root/configuration/http_filters/router_filter.rst @@ -79,6 +79,9 @@ gateway-error This policy is similar to the *5xx* policy but will only retry requests that result in a 502, 503, or 504. +reset + Envoy will attempt a retry if the upstream server does not respond at all (disconnect/reset/read timeout.) + connect-failure Envoy will attempt a retry if a request is failed because of a connection failure to the upstream server (connect timeout, etc.). (Included in *5xx*) @@ -348,7 +351,8 @@ owning HTTP connection manager. rq_redirect, Counter, Total requests that resulted in a redirect response rq_direct_response, Counter, Total requests that resulted in a direct response rq_total, Counter, Total routed requests - rq_reset_after_downstream_response_started, Counter, Total requests that were reset after downstream response had started. + rq_reset_after_downstream_response_started, Counter, Total requests that were reset after downstream response had started + rq_retry_skipped_request_not_complete, Counter, Total retries that were skipped as the request is not yet complete Virtual cluster statistics are output in the *vhost..vcluster..* namespace and include the following diff --git a/docs/root/configuration/listener_filters/http_inspector.rst b/docs/root/configuration/listener_filters/http_inspector.rst new file mode 100644 index 000000000000..5972e0ad89cd --- /dev/null +++ b/docs/root/configuration/listener_filters/http_inspector.rst @@ -0,0 +1,38 @@ +.. _config_listener_filters_http_inspector: + +HTTP Inspector +============== + +HTTP Inspector listener filter allows detecting whether the application protocol appears to be HTTP, +and if it is HTTP, it detects the HTTP protocol (HTTP/1.x or HTTP/2) further. This can be used to select a +:ref:`FilterChain ` via the :ref:`application_protocols ` +of a :ref:`FilterChainMatch `. + +* :ref:`v2 API reference ` +* This filter should be configured with the name *envoy.listener.http_inspector*. + +Example +------- + +A sample filter configuration could be: + +.. code-block:: yaml + + listener_filters: + - name: "envoy.listener.http_inspector" + typed_config: {} + +Statistics +---------- + +This filter has a statistics tree rooted at *http_inspector* with the following statistics: + +.. csv-table:: + :header: Name, Type, Description + :widths: 1, 1, 2 + + read_error, Counter, Total read errors + http10_found, Counter, Total number of times HTTP/1.0 was found + http11_found, Counter, Total number of times HTTP/1.1 was found + http2_found, Counter, Total number of times HTTP/2 was found + http_not_found, Counter, Total number of times HTTP protocol was not found diff --git a/docs/root/configuration/listener_filters/listener_filters.rst b/docs/root/configuration/listener_filters/listener_filters.rst index 7357976c500b..0bed75eb9fc6 100644 --- a/docs/root/configuration/listener_filters/listener_filters.rst +++ b/docs/root/configuration/listener_filters/listener_filters.rst @@ -8,6 +8,7 @@ Envoy has the following builtin listener filters. .. toctree:: :maxdepth: 2 + http_inspector original_dst_filter original_src_filter proxy_protocol diff --git a/docs/root/faq/transient_failures.rst b/docs/root/faq/transient_failures.rst index aadfa0986518..2e31976b5eb4 100644 --- a/docs/root/faq/transient_failures.rst +++ b/docs/root/faq/transient_failures.rst @@ -108,7 +108,7 @@ of times the host has been ejected). .. code-block:: json { - "retry_on": "cancelled,connect-failure,gateway-error,refused-stream,resource-exhausted,unavailable", + "retry_on": "cancelled,connect-failure,gateway-error,refused-stream,reset,resource-exhausted,unavailable", "num_retries": 1, "retry_host_predicate": [ { diff --git a/docs/root/intro/arch_overview/operations/init.rst b/docs/root/intro/arch_overview/operations/init.rst index 2e05c5a75056..4ce245d78f51 100644 --- a/docs/root/intro/arch_overview/operations/init.rst +++ b/docs/root/intro/arch_overview/operations/init.rst @@ -10,20 +10,24 @@ accepting new connections. * During startup, the :ref:`cluster manager ` goes through a multi-phase initialization where it first initializes static/DNS clusters, then predefined :ref:`EDS ` clusters. Then it initializes - :ref:`CDS ` if applicable, waits for one response (or failure), + :ref:`CDS ` if applicable, waits for one response (or failure) + for a :ref:`bounded period of time `, and does the same primary/secondary initialization of CDS provided clusters. * If clusters use :ref:`active health checking `, Envoy also does a single active health check round. * Once cluster manager initialization is done, :ref:`RDS ` and - :ref:`LDS ` initialize (if applicable). The server - doesn't start accepting connections until there has been at least one response (or failure) for - LDS/RDS requests. -* If LDS itself returns a listener that needs an RDS response, Envoy further waits until an RDS + :ref:`LDS ` initialize (if applicable). The server waits + for a :ref:`bounded period of time ` + for at least one response (or failure) for LDS/RDS requests. After which, it starts accepting connections. +* If LDS itself returns a listener that needs an RDS response, Envoy further waits for + a :ref:`bounded period of time ` until an RDS response (or failure) is received. Note that this process takes place on every future listener addition via LDS and is known as :ref:`listener warming `. * After all of the previous steps have taken place, the listeners start accepting new connections. This flow ensures that during hot restart the new process is fully capable of accepting and processing new connections before the draining of the old process begins. -All mentioned "waiting for one response" periods can be limited by setting corresponding -:ref:`initial_fetch_timeout `. +A key design principle of initialization is that an Envoy is always guaranteed to initialize within +:ref:`initial_fetch_timeout `, +with a best effort made to obtain the complete set of xDS configuration within that subject to the +management server availability. diff --git a/docs/root/intro/arch_overview/upstream/load_balancing/panic_threshold.rst b/docs/root/intro/arch_overview/upstream/load_balancing/panic_threshold.rst index 80b062593a29..e24022a8f07b 100644 --- a/docs/root/intro/arch_overview/upstream/load_balancing/panic_threshold.rst +++ b/docs/root/intro/arch_overview/upstream/load_balancing/panic_threshold.rst @@ -66,5 +66,12 @@ priority. | 5% | 65% | 7% | YES | 93% | NO | 98% | +-------------+-------------+----------+--------------+----------+--------------+-------------+ -Note that panic thresholds can be configured *per-priority*. +Panic mode can be disabled by setting the panic threshold to 0%. + +If all hosts become unhealthy normalized total health is 0%, and if the panic threshold is above 0% +all traffic will be redirected to P=0. +However, if the panic threshold is 0% for any priority, that priority will never enter panic mode. +In this case if all hosts are unhealthy, Envoy will fail to select a host and will instead immediately +return error responses with "503 - no healthy upstream". +Note that panic thresholds can be configured *per-priority*. diff --git a/docs/root/intro/arch_overview/upstream/upstream.rst b/docs/root/intro/arch_overview/upstream/upstream.rst index 4c8a12db3137..da1887087bff 100644 --- a/docs/root/intro/arch_overview/upstream/upstream.rst +++ b/docs/root/intro/arch_overview/upstream/upstream.rst @@ -11,3 +11,4 @@ Upstream clusters load_balancing/load_balancing outlier circuit_breaking + upstream_filters diff --git a/docs/root/intro/arch_overview/upstream/upstream_filters.rst b/docs/root/intro/arch_overview/upstream/upstream_filters.rst new file mode 100644 index 000000000000..1fe902dcf919 --- /dev/null +++ b/docs/root/intro/arch_overview/upstream/upstream_filters.rst @@ -0,0 +1,11 @@ +.. _arch_overview_upstream_filters: + +Upstream network filters +======================== + +Upstream clusters provide an ability to inject network level (L3/L4) +:ref:`filters `. The filters apply to the +connection to the upstream hosts, using the same API presented by listeners for +the downstream connections. The write callbacks are invoked for any chunk of +data sent to the upstream host, and the read callbacks are invoked for data +received from the upstream host. diff --git a/docs/root/intro/version_history.rst b/docs/root/intro/version_history.rst index 70e8fe3e8c87..37e4c4ab97e9 100644 --- a/docs/root/intro/version_history.rst +++ b/docs/root/intro/version_history.rst @@ -3,6 +3,18 @@ Version history 1.12.0 (pending) ================ +* admin: added ability to configure listener :ref:`socket options `. +* admin: added config dump support for Secret Discovery Service :ref:`SecretConfigDump `. +* config: async data access for local and remote data source. +* config: changed the default value of :ref:`initial_fetch_timeout ` from 0s to 15s. This is a change in behaviour in the sense that Envoy will move to the next initialization phase, even if the first config is not delivered in 15s. Refer to :ref:`initialization process ` for more details. +* fault: added overrides for default runtime keys in :ref:`HTTPFault ` filter. +* grpc-json: added support for :ref:`ignoring unknown query parameters`. +* http: added the ability to reject HTTP/1.1 requests with invalid HTTP header values, using the runtime feature `envoy.reloadable_features.strict_header_validation`. +* listeners: added :ref:`HTTP inspector listener filter `. +* router: added :ref:`rq_retry_skipped_request_not_complete ` counter stat to router stats. +* tls: added verification of IP address SAN fields in certificates against configured SANs in the + certificate validation context. +* upstream: added network filter chains to upstream connections, see :ref:`filters`. 1.11.0 (July 11, 2019) ====================== diff --git a/docs/root/operations/admin.rst b/docs/root/operations/admin.rst index 62e4a5e67993..f0d1f1d73bc2 100644 --- a/docs/root/operations/admin.rst +++ b/docs/root/operations/admin.rst @@ -179,8 +179,15 @@ modify different aspects of the server: .. http:post:: /logging - Enable/disable different logging levels on different subcomponents. Generally only used during - development. + Enable/disable different logging levels on a particular logger or all loggers. + + - To change the logging level across all loggers, set the query parameter as level=. + - To change a particular logger's level, set the query parameter like so, =. + - To list the loggers, send a POST request to the /logging endpoint without a query parameter. + + .. note:: + + Generally only used during development. .. http:post:: /memory diff --git a/examples/BUILD b/examples/BUILD index a36e43453ad7..cea6483751a4 100644 --- a/examples/BUILD +++ b/examples/BUILD @@ -22,6 +22,7 @@ filegroup( "jaeger-tracing/service1-envoy-jaeger.yaml", "jaeger-tracing/service2-envoy-jaeger.yaml", "lua/envoy.yaml", + "lua/lib/mylibrary.lua", "zipkin-tracing/front-envoy-zipkin.yaml", "zipkin-tracing/service1-envoy-zipkin.yaml", "zipkin-tracing/service2-envoy-zipkin.yaml", diff --git a/examples/lua/Dockerfile-proxy b/examples/lua/Dockerfile-proxy index 92b320ea1487..5ba5c9c33a0d 100644 --- a/examples/lua/Dockerfile-proxy +++ b/examples/lua/Dockerfile-proxy @@ -1,2 +1,3 @@ FROM envoyproxy/envoy-dev:latest +ADD ./lib/mylibrary.lua /lib/mylibrary.lua CMD /usr/local/bin/envoy -c /etc/envoy.yaml -l debug --service-cluster proxy diff --git a/examples/lua/envoy.yaml b/examples/lua/envoy.yaml index aed6f977299b..4f98481091fb 100644 --- a/examples/lua/envoy.yaml +++ b/examples/lua/envoy.yaml @@ -28,8 +28,10 @@ static_resources: typed_config: "@type": type.googleapis.com/envoy.config.filter.http.lua.v2.Lua inline_code: | + local mylibrary = require("lib.mylibrary") + function envoy_on_request(request_handle) - request_handle:headers():add("foo", "bar") + request_handle:headers():add("foo", mylibrary.foobar()) end function envoy_on_response(response_handle) body_size = response_handle:body():length() diff --git a/examples/lua/lib/mylibrary.lua b/examples/lua/lib/mylibrary.lua new file mode 100644 index 000000000000..6b4ffed1b476 --- /dev/null +++ b/examples/lua/lib/mylibrary.lua @@ -0,0 +1,7 @@ +M = {} + +function M.foobar() + return "bar" +end + +return M diff --git a/include/envoy/event/dispatcher.h b/include/envoy/event/dispatcher.h index 4dbe2ab06e16..8c3a8b8a88b7 100644 --- a/include/envoy/event/dispatcher.h +++ b/include/envoy/event/dispatcher.h @@ -211,6 +211,12 @@ class Dispatcher { * @return The previously tracked object or nullptr if there was none. */ virtual const ScopeTrackedObject* setTrackedObject(const ScopeTrackedObject* object) PURE; + + /** + * Validates that an operation is thread-safe with respect to this dispatcher; i.e. that the + * current thread of execution is on the same thread upon which the dispatcher loop is running. + */ + virtual bool isThreadSafe() const PURE; }; using DispatcherPtr = std::unique_ptr; diff --git a/include/envoy/http/BUILD b/include/envoy/http/BUILD index 4f0355015ce3..ce03a17f9624 100644 --- a/include/envoy/http/BUILD +++ b/include/envoy/http/BUILD @@ -62,6 +62,7 @@ envoy_cc_library( ":codec_interface", ":header_map_interface", "//include/envoy/access_log:access_log_interface", + "//include/envoy/common:scope_tracker_interface", "//include/envoy/event:dispatcher_interface", "//include/envoy/grpc:status", "//include/envoy/router:router_interface", diff --git a/include/envoy/http/conn_pool.h b/include/envoy/http/conn_pool.h index 7dc23a943a79..cb2d6a8607bd 100644 --- a/include/envoy/http/conn_pool.h +++ b/include/envoy/http/conn_pool.h @@ -114,6 +114,8 @@ class Instance : public Event::DeferredDeletable { * callbacks is called and the routine returns nullptr. NOTE: Once a callback * is called, the handle is no longer valid and any further cancellation * should be done by resetting the stream. + * @warning Do not call cancel() from the callbacks, as the request is implicitly canceled when + * the callbacks are called. */ virtual Cancellable* newStream(Http::StreamDecoder& response_decoder, Callbacks& callbacks) PURE; diff --git a/include/envoy/http/filter.h b/include/envoy/http/filter.h index e34aeec39a94..609205443d25 100644 --- a/include/envoy/http/filter.h +++ b/include/envoy/http/filter.h @@ -6,6 +6,7 @@ #include #include "envoy/access_log/access_log.h" +#include "envoy/common/scope_tracker.h" #include "envoy/event/dispatcher.h" #include "envoy/grpc/status.h" #include "envoy/http/codec.h" @@ -185,6 +186,11 @@ class StreamFilterCallbacks { * @return tracing configuration. */ virtual const Tracing::Config& tracingConfig() PURE; + + /** + * @return the ScopeTrackedObject for this stream. + */ + virtual const ScopeTrackedObject& scope() PURE; }; /** diff --git a/include/envoy/network/address.h b/include/envoy/network/address.h index c439cecc27af..86d32eca2452 100644 --- a/include/envoy/network/address.h +++ b/include/envoy/network/address.h @@ -13,6 +13,7 @@ #include "envoy/network/io_handle.h" #include "absl/numeric/int128.h" +#include "absl/strings/string_view.h" namespace Envoy { namespace Network { @@ -117,6 +118,11 @@ class Instance { */ virtual const std::string& asString() const PURE; + /** + * @return Similar to asString but returns a string view. + */ + virtual absl::string_view asStringView() const PURE; + /** * @return a human readable string for the address that represents the * logical/unresolved name. diff --git a/include/envoy/router/router.h b/include/envoy/router/router.h index c705a6499300..a14864b4b287 100644 --- a/include/envoy/router/router.h +++ b/include/envoy/router/router.h @@ -163,6 +163,7 @@ class RetryPolicy { static const uint32_t RETRY_ON_GRPC_UNAVAILABLE = 0x100; static const uint32_t RETRY_ON_GRPC_INTERNAL = 0x200; static const uint32_t RETRY_ON_RETRIABLE_STATUS_CODES = 0x400; + static const uint32_t RETRY_ON_RESET = 0x800; // clang-format on virtual ~RetryPolicy() = default; diff --git a/include/envoy/runtime/runtime.h b/include/envoy/runtime/runtime.h index b3e3ebeb468a..f850ec18fde4 100644 --- a/include/envoy/runtime/runtime.h +++ b/include/envoy/runtime/runtime.h @@ -220,11 +220,17 @@ class Loader { virtual void initialize(Upstream::ClusterManager& cm) PURE; /** - * @return Snapshot& the current snapshot. This reference is safe to use for the duration of + * @return const Snapshot& the current snapshot. This reference is safe to use for the duration of * the calling routine, but may be overwritten on a future event loop cycle so should be - * fetched again when needed. + * fetched again when needed. This may only be called from worker threads. */ - virtual Snapshot& snapshot() PURE; + virtual const Snapshot& snapshot() PURE; + + /** + * @return shared_ptr the current snapshot. This function may safely be called + * from non-worker theads. + */ + virtual std::shared_ptr threadsafeSnapshot() PURE; /** * Merge the given map of key-value pairs into the runtime's state. To remove a previous merge for diff --git a/include/envoy/server/BUILD b/include/envoy/server/BUILD index 0180275b9b92..2dbd768aab91 100644 --- a/include/envoy/server/BUILD +++ b/include/envoy/server/BUILD @@ -119,6 +119,7 @@ envoy_cc_library( "//include/envoy/network:address_interface", "//include/envoy/stats:stats_interface", "@envoy_api//envoy/admin/v2alpha:server_info_cc", + "@envoy_api//envoy/config/bootstrap/v2:bootstrap_cc", ], ) diff --git a/include/envoy/server/admin.h b/include/envoy/server/admin.h index 7e5a4b5f33c2..56cabe8ab462 100644 --- a/include/envoy/server/admin.h +++ b/include/envoy/server/admin.h @@ -124,6 +124,7 @@ class Admin { virtual void startHttpListener(const std::string& access_log_path_, const std::string& address_out_path, Network::Address::InstanceConstSharedPtr address, + const Network::Socket::OptionsSharedPtr& socket_options, Stats::ScopePtr&& listener_scope) PURE; /** diff --git a/include/envoy/server/configuration.h b/include/envoy/server/configuration.h index df2022ba9cee..21a2e583fbad 100644 --- a/include/envoy/server/configuration.h +++ b/include/envoy/server/configuration.h @@ -92,6 +92,11 @@ class Admin { * @return Network::Address::InstanceConstSharedPtr the server address. */ virtual Network::Address::InstanceConstSharedPtr address() PURE; + + /** + * @return Network::Address::OptionsSharedPtr the list of listener socket options. + */ + virtual Network::Socket::OptionsSharedPtr socketOptions() PURE; }; /** diff --git a/include/envoy/server/filter_config.h b/include/envoy/server/filter_config.h index cf99d734ad49..12ea149f517b 100644 --- a/include/envoy/server/filter_config.h +++ b/include/envoy/server/filter_config.h @@ -32,18 +32,11 @@ namespace Server { namespace Configuration { /** - * Context passed to network and HTTP filters to access server resources. - * TODO(mattklein123): When we lock down visibility of the rest of the code, filters should only - * access the rest of the server via interfaces exposed here. + * Common interface for downstream and upstream network filters. */ -class FactoryContext { +class CommonFactoryContext { public: - virtual ~FactoryContext() = default; - - /** - * @return AccessLogManager for use by the entire server. - */ - virtual AccessLog::AccessLogManager& accessLogManager() PURE; + virtual ~CommonFactoryContext() = default; /** * @return Upstream::ClusterManager& singleton for use by the entire server. @@ -56,37 +49,6 @@ class FactoryContext { */ virtual Event::Dispatcher& dispatcher() PURE; - /** - * @return const Network::DrainDecision& a drain decision that filters can use to determine if - * they should be doing graceful closes on connections when possible. - */ - virtual const Network::DrainDecision& drainDecision() PURE; - - /** - * @return whether external healthchecks are currently failed or not. - */ - virtual bool healthCheckFailed() PURE; - - /** - * @return the server-wide http tracer. - */ - virtual Tracing::HttpTracer& httpTracer() PURE; - - /** - * @return the server's init manager. This can be used for extensions that need to initialize - * after cluster manager init but before the server starts listening. All extensions - * should register themselves during configuration load. initialize() will be called on - * each registered target after cluster manager init but before the server starts - * listening. Once all targets have initialized and invoked their callbacks, the server - * will start listening. - */ - virtual Init::Manager& initManager() PURE; - - /** - * @return ServerLifecycleNotifier& the lifecycle notifier for the server. - */ - virtual ServerLifecycleNotifier& lifecycleNotifier() PURE; - /** * @return information about the local environment the server is running in. */ @@ -123,6 +85,68 @@ class FactoryContext { */ virtual Server::Admin& admin() PURE; + /** + * @return TimeSource& a reference to the time source. + */ + virtual TimeSource& timeSource() PURE; + + /** + * @return ProtobufMessage::ValidationVisitor& validation visitor for filter configuration + * messages. + */ + virtual ProtobufMessage::ValidationVisitor& messageValidationVisitor() PURE; + + /** + * @return Api::Api& a reference to the api object. + */ + virtual Api::Api& api() PURE; +}; + +/** + * Context passed to network and HTTP filters to access server resources. + * TODO(mattklein123): When we lock down visibility of the rest of the code, filters should only + * access the rest of the server via interfaces exposed here. + */ +class FactoryContext : public virtual CommonFactoryContext { +public: + ~FactoryContext() override = default; + + /** + * @return AccessLogManager for use by the entire server. + */ + virtual AccessLog::AccessLogManager& accessLogManager() PURE; + + /** + * @return const Network::DrainDecision& a drain decision that filters can use to determine if + * they should be doing graceful closes on connections when possible. + */ + virtual const Network::DrainDecision& drainDecision() PURE; + + /** + * @return whether external healthchecks are currently failed or not. + */ + virtual bool healthCheckFailed() PURE; + + /** + * @return the server-wide http tracer. + */ + virtual Tracing::HttpTracer& httpTracer() PURE; + + /** + * @return the server's init manager. This can be used for extensions that need to initialize + * after cluster manager init but before the server starts listening. All extensions + * should register themselves during configuration load. initialize() will be called on + * each registered target after cluster manager init but before the server starts + * listening. Once all targets have initialized and invoked their callbacks, the server + * will start listening. + */ + virtual Init::Manager& initManager() PURE; + + /** + * @return ServerLifecycleNotifier& the lifecycle notifier for the server. + */ + virtual ServerLifecycleNotifier& lifecycleNotifier() PURE; + /** * @return Stats::Scope& the listener's stats scope. */ @@ -134,11 +158,6 @@ class FactoryContext { */ virtual const envoy::api::v2::core::Metadata& listenerMetadata() const PURE; - /** - * @return TimeSource& a reference to the time source. - */ - virtual TimeSource& timeSource() PURE; - /** * @return OverloadManager& the overload manager for the server. */ @@ -158,28 +177,10 @@ class FactoryContext { * @return ProcessContext& a reference to the process context. */ virtual ProcessContext& processContext() PURE; - - /** - * @return ProtobufMessage::ValidationVisitor& validation visitor for filter configuration - * messages. - */ - virtual ProtobufMessage::ValidationVisitor& messageValidationVisitor() PURE; - - /** - * @return Api::Api& a reference to the api object. - */ - virtual Api::Api& api() PURE; }; class ListenerFactoryContext : public virtual FactoryContext { public: - /** - * Store socket options to be set on the listen socket before listening. - */ - virtual void addListenSocketOption(const Network::Socket::OptionConstSharedPtr& option) PURE; - - virtual void addListenSocketOptions(const Network::Socket::OptionsSharedPtr& options) PURE; - /** * Give access to the listener configuration */ @@ -323,6 +324,34 @@ class NamedNetworkFilterConfigFactory : public ProtocolOptionsFactory { virtual std::string name() PURE; }; +/** + * Implemented by each upstream cluster network filter and registered via + * Registry::registerFactory() or the convenience class RegisterFactory. + */ +class NamedUpstreamNetworkFilterConfigFactory : public ProtocolOptionsFactory { +public: + ~NamedUpstreamNetworkFilterConfigFactory() override = default; + + /** + * Create a particular upstream network filter factory implementation. If the implementation is + * unable to produce a factory with the provided parameters, it should throw an EnvoyException in + * the case of general error. The returned callback should always be initialized. + */ + virtual Network::FilterFactoryCb createFilterFactoryFromProto(const Protobuf::Message& config, + CommonFactoryContext& context) PURE; + + /** + * @return ProtobufTypes::MessagePtr create empty config proto message for v2. + */ + virtual ProtobufTypes::MessagePtr createEmptyConfigProto() PURE; + + /** + * @return std::string the identifying name for a particular implementation of a network filter + * produced by the factory. + */ + virtual std::string name() PURE; +}; + /** * Implemented by each HTTP filter and registered via Registry::registerFactory or the * convenience class RegisterFactory. diff --git a/include/envoy/server/hot_restart.h b/include/envoy/server/hot_restart.h index 916646f5c087..16c182c8da3c 100644 --- a/include/envoy/server/hot_restart.h +++ b/include/envoy/server/hot_restart.h @@ -5,7 +5,7 @@ #include "envoy/common/pure.h" #include "envoy/event/dispatcher.h" -#include "envoy/stats/stat_data_allocator.h" +#include "envoy/stats/allocator.h" #include "envoy/stats/store.h" #include "envoy/thread/thread.h" diff --git a/include/envoy/server/lifecycle_notifier.h b/include/envoy/server/lifecycle_notifier.h index cd829f61b991..dbda0e2e0055 100644 --- a/include/envoy/server/lifecycle_notifier.h +++ b/include/envoy/server/lifecycle_notifier.h @@ -26,6 +26,9 @@ class ServerLifecycleNotifier { * This provides listeners a last chance to run a callback on the main dispatcher. * Note: the server will wait for callbacks that registered to take a completion * before exiting the dispatcher loop. + * Note: callbacks that registered with a completion will only be notified for this + * stage if the server did not prematurely shutdown before fully starting up (specifically + * if the server shutdown before worker threads were started). */ ShutdownExit }; diff --git a/include/envoy/server/options.h b/include/envoy/server/options.h index e78b499a7f3e..8904925f28e9 100644 --- a/include/envoy/server/options.h +++ b/include/envoy/server/options.h @@ -6,6 +6,7 @@ #include "envoy/admin/v2alpha/server_info.pb.h" #include "envoy/common/pure.h" +#include "envoy/config/bootstrap/v2/bootstrap.pb.h" #include "envoy/network/address.h" #include "spdlog/spdlog.h" @@ -78,6 +79,12 @@ class Options { */ virtual const std::string& configYaml() const PURE; + /** + * @return const envoy::config::bootstrap::v2::Bootstrap& a bootstrap proto object + * that merges into the config last, after configYaml and configPath. + */ + virtual const envoy::config::bootstrap::v2::Bootstrap& configProto() const PURE; + /** * @return bool allow unknown fields in the configuration? */ diff --git a/include/envoy/stats/BUILD b/include/envoy/stats/BUILD index 2dcf68988def..b6a0389265fa 100644 --- a/include/envoy/stats/BUILD +++ b/include/envoy/stats/BUILD @@ -18,10 +18,10 @@ envoy_cc_library( envoy_cc_library( name = "stats_interface", hdrs = [ + "allocator.h", "histogram.h", "scope.h", "sink.h", - "stat_data_allocator.h", "stats.h", "stats_matcher.h", "store.h", diff --git a/include/envoy/stats/stat_data_allocator.h b/include/envoy/stats/allocator.h similarity index 92% rename from include/envoy/stats/stat_data_allocator.h rename to include/envoy/stats/allocator.h index 2fc94861828d..f05f6df4f89a 100644 --- a/include/envoy/stats/stat_data_allocator.h +++ b/include/envoy/stats/allocator.h @@ -23,11 +23,10 @@ namespace Stats { * be created utilizing a single fixed-size block suitable for * shared-memory, or in the heap, allowing for pointers and sharing of * substrings, with an opportunity for reduced memory consumption. - * TODO(fredlas) this interface can be deleted now that the shared memory version is gone. */ -class StatDataAllocator { +class Allocator { public: - virtual ~StatDataAllocator() = default; + virtual ~Allocator() = default; /** * @param name the full name of the stat. diff --git a/include/envoy/stats/scope.h b/include/envoy/stats/scope.h index ef01045374f1..1d122ddf6544 100644 --- a/include/envoy/stats/scope.h +++ b/include/envoy/stats/scope.h @@ -19,6 +19,9 @@ class Histogram; class Scope; class NullGaugeImpl; +using OptionalCounter = absl::optional>; +using OptionalGauge = absl::optional>; +using OptionalHistogram = absl::optional>; using ScopePtr = std::unique_ptr; using ScopeSharedPtr = std::shared_ptr; @@ -93,22 +96,20 @@ class Scope { * @param The name of the stat, obtained from the SymbolTable. * @return a reference to a counter within the scope's namespace, if it exists. */ - virtual absl::optional> - findCounter(StatName name) const PURE; + virtual OptionalCounter findCounter(StatName name) const PURE; /** * @param The name of the stat, obtained from the SymbolTable. * @return a reference to a gauge within the scope's namespace, if it exists. */ - virtual absl::optional> findGauge(StatName name) const PURE; + virtual OptionalGauge findGauge(StatName name) const PURE; /** * @param The name of the stat, obtained from the SymbolTable. * @return a reference to a histogram within the scope's namespace, if it * exists. */ - virtual absl::optional> - findHistogram(StatName name) const PURE; + virtual OptionalHistogram findHistogram(StatName name) const PURE; /** * @return a reference to the symbol table. diff --git a/include/envoy/stats/stats.h b/include/envoy/stats/stats.h index a61249ba6e50..f92715d9406b 100644 --- a/include/envoy/stats/stats.h +++ b/include/envoy/stats/stats.h @@ -10,12 +10,11 @@ #include "envoy/stats/symbol_table.h" #include "absl/strings/string_view.h" -#include "absl/types/optional.h" namespace Envoy { namespace Stats { -class StatDataAllocator; +class Allocator; struct Tag; /** @@ -23,7 +22,7 @@ struct Tag; */ class Metric : public RefcountInterface { public: - virtual ~Metric() = default; + ~Metric() override = default; /** * Returns the full name of the Metric. This is intended for most uses, such * as streaming out the name to a stats sink or admin request, or comparing diff --git a/include/envoy/thread_local/thread_local.h b/include/envoy/thread_local/thread_local.h index 14fac5cd5e22..6f082a4607f5 100644 --- a/include/envoy/thread_local/thread_local.h +++ b/include/envoy/thread_local/thread_local.h @@ -28,6 +28,16 @@ class Slot { public: virtual ~Slot() = default; + /** + * Returns if there is thread local data for this thread. + * + * This should return true for Envoy worker threads and false for threads which do not have thread + * local storage allocated. + * + * @return true if registerThread has been called for this thread, false otherwise. + */ + virtual bool currentThreadRegistered() PURE; + /** * @return ThreadLocalObjectSharedPtr a thread local object stored in the slot. */ diff --git a/include/envoy/upstream/upstream.h b/include/envoy/upstream/upstream.h index 567466c18ebc..b627bc9be358 100644 --- a/include/envoy/upstream/upstream.h +++ b/include/envoy/upstream/upstream.h @@ -843,6 +843,11 @@ class ClusterInfo { */ virtual absl::optional eds_service_name() const PURE; + /** + * Create network filters on a new upstream connection. + */ + virtual void createNetworkFilterChain(Network::Connection& connection) const PURE; + protected: /** * Invoked by extensionProtocolOptionsTyped. diff --git a/repokitteh.star b/repokitteh.star index 9c90e4986673..b39ebd0dc130 100644 --- a/repokitteh.star +++ b/repokitteh.star @@ -2,5 +2,12 @@ use("github.com/repokitteh/modules/assign.star") use("github.com/repokitteh/modules/review.star") use("github.com/repokitteh/modules/wait.star") use("github.com/repokitteh/modules/circleci.star", secret_token=get_secret('circle_token')) +use( + "github.com/repokitteh/modules/ownerscheck.star", + paths=[ + ("envoyproxy/api-shepherds!", "api/"), + ("envoyproxy/udpa-wg", "api/udpa/"), + ], +) alias('retest', 'retry-circle') diff --git a/security/email-templates.md b/security/email-templates.md index 99175d1f64e8..b4281894e26f 100644 --- a/security/email-templates.md +++ b/security/email-templates.md @@ -36,14 +36,14 @@ Hello Envoy Distributors, The Envoy security team would like to provide advanced notice to the Envoy Private Distributors List of some details on the pending Envoy $VERSION security release, following the process described at -https://github.com/envoyproxy/envoy/blob/master/SECURITY_RELEASE_PROCESS.md. +https://github.com/envoyproxy/envoy/blob/master/SECURITY.md. This release will be made available on the $ORDINALDAY of $MONTH $YEAR at $PDTHOUR PDT ($GMTHOUR GMT). This release will fix $NUMDEFECTS security defect(s). The highest rated security defect is considered $SEVERITY severity. Below we provide details of these vulnerabilities under our embargo policy -(https://github.com/envoyproxy/envoy/blob/master/SECURITY_RELEASE_PROCESS.md#embargo-policy). +(https://github.com/envoyproxy/envoy/blob/master/SECURITY.md#embargo-policy). This information should be treated as confidential until public release by the Envoy maintainers on the Envoy GitHub. diff --git a/source/common/access_log/BUILD b/source/common/access_log/BUILD index 2de71c912d53..8506985f2676 100644 --- a/source/common/access_log/BUILD +++ b/source/common/access_log/BUILD @@ -8,33 +8,6 @@ load( envoy_package() -envoy_cc_library( - name = "access_log_formatter_lib", - srcs = ["access_log_formatter.cc"], - hdrs = ["access_log_formatter.h"], - deps = [ - "//include/envoy/access_log:access_log_interface", - "//include/envoy/stream_info:stream_info_interface", - "//source/common/common:assert_lib", - "//source/common/common:utility_lib", - "//source/common/config:metadata_lib", - "//source/common/http:utility_lib", - "//source/common/stream_info:utility_lib", - ], -) - -envoy_cc_library( - name = "access_log_manager_lib", - srcs = ["access_log_manager_impl.cc"], - hdrs = ["access_log_manager_impl.h"], - deps = [ - "//include/envoy/access_log:access_log_interface", - "//include/envoy/api:api_interface", - "//source/common/buffer:buffer_lib", - "//source/common/common:thread_lib", - ], -) - envoy_cc_library( name = "access_log_lib", srcs = ["access_log_impl.cc"], @@ -61,3 +34,30 @@ envoy_cc_library( "@envoy_api//envoy/config/filter/accesslog/v2:accesslog_cc", ], ) + +envoy_cc_library( + name = "access_log_formatter_lib", + srcs = ["access_log_formatter.cc"], + hdrs = ["access_log_formatter.h"], + deps = [ + "//include/envoy/access_log:access_log_interface", + "//include/envoy/stream_info:stream_info_interface", + "//source/common/common:assert_lib", + "//source/common/common:utility_lib", + "//source/common/config:metadata_lib", + "//source/common/http:utility_lib", + "//source/common/stream_info:utility_lib", + ], +) + +envoy_cc_library( + name = "access_log_manager_lib", + srcs = ["access_log_manager_impl.cc"], + hdrs = ["access_log_manager_impl.h"], + deps = [ + "//include/envoy/access_log:access_log_interface", + "//include/envoy/api:api_interface", + "//source/common/buffer:buffer_lib", + "//source/common/common:thread_lib", + ], +) diff --git a/source/common/access_log/access_log_impl.cc b/source/common/access_log/access_log_impl.cc index aac76ae28817..33fcd5485d04 100644 --- a/source/common/access_log/access_log_impl.cc +++ b/source/common/access_log/access_log_impl.cc @@ -114,9 +114,9 @@ RuntimeFilter::RuntimeFilter(const envoy::config::filter::accesslog::v2::Runtime percent_(config.percent_sampled()), use_independent_randomness_(config.use_independent_randomness()) {} -bool RuntimeFilter::evaluate(const StreamInfo::StreamInfo&, const Http::HeaderMap& request_header, +bool RuntimeFilter::evaluate(const StreamInfo::StreamInfo&, const Http::HeaderMap& request_headers, const Http::HeaderMap&, const Http::HeaderMap&) { - const Http::HeaderEntry* uuid = request_header.RequestId(); + const Http::HeaderEntry* uuid = request_headers.RequestId(); uint64_t random_value; // TODO(dnoe): Migrate uuidModBy to take string_view (#6580) if (use_independent_randomness_ || uuid == nullptr || diff --git a/source/common/access_log/access_log_impl.h b/source/common/access_log/access_log_impl.h index 3635957aa95f..0941602a30b0 100644 --- a/source/common/access_log/access_log_impl.h +++ b/source/common/access_log/access_log_impl.h @@ -121,7 +121,7 @@ class OrFilter : public OperatorFilter { */ class NotHealthCheckFilter : public Filter { public: - NotHealthCheckFilter() {} + NotHealthCheckFilter() = default; // AccessLog::Filter bool evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers, diff --git a/source/common/access_log/access_log_manager_impl.h b/source/common/access_log/access_log_manager_impl.h index df09d2ad7863..4a8dedcdf367 100644 --- a/source/common/access_log/access_log_manager_impl.h +++ b/source/common/access_log/access_log_manager_impl.h @@ -64,7 +64,7 @@ class AccessLogFileImpl : public AccessLogFile { Thread::BasicLockable& lock, AccessLogFileStats& stats_, std::chrono::milliseconds flush_interval_msec, Thread::ThreadFactory& thread_factory); - ~AccessLogFileImpl(); + ~AccessLogFileImpl() override; // AccessLog::AccessLogFile void write(absl::string_view data) override; diff --git a/source/common/api/BUILD b/source/common/api/BUILD index 8c7909899c6c..b8b60aab6134 100644 --- a/source/common/api/BUILD +++ b/source/common/api/BUILD @@ -26,12 +26,14 @@ envoy_cc_library( "//bazel:linux_x86_64": ["os_sys_calls_impl_linux.cc"], "//bazel:linux_aarch64": ["os_sys_calls_impl_linux.cc"], "//bazel:linux_ppc": ["os_sys_calls_impl_linux.cc"], + "//bazel:linux_mips64": ["os_sys_calls_impl_linux.cc"], "//conditions:default": [], }) + envoy_select_hot_restart(["os_sys_calls_impl_hot_restart.cc"]), hdrs = ["os_sys_calls_impl.h"] + select({ "//bazel:linux_x86_64": ["os_sys_calls_impl_linux.h"], "//bazel:linux_aarch64": ["os_sys_calls_impl_linux.h"], "//bazel:linux_ppc": ["os_sys_calls_impl_linux.h"], + "//bazel:linux_mips64": ["os_sys_calls_impl_linux.h"], "//conditions:default": [], }) + envoy_select_hot_restart(["os_sys_calls_impl_hot_restart.h"]), deps = [ diff --git a/source/common/common/assert.cc b/source/common/common/assert.cc index cb01008c121e..ab4b1b8776a4 100644 --- a/source/common/common/assert.cc +++ b/source/common/common/assert.cc @@ -10,7 +10,7 @@ class ActionRegistrationImpl : public ActionRegistration { debug_assertion_failure_record_action_ = action; } - ~ActionRegistrationImpl() { + ~ActionRegistrationImpl() override { ASSERT(debug_assertion_failure_record_action_ != nullptr); debug_assertion_failure_record_action_ = nullptr; } diff --git a/source/common/common/logger.h b/source/common/common/logger.h index dcc83627ac07..42360c572b39 100644 --- a/source/common/common/logger.h +++ b/source/common/common/logger.h @@ -41,6 +41,7 @@ namespace Logger { FUNCTION(hystrix) \ FUNCTION(init) \ FUNCTION(io) \ + FUNCTION(jwt) \ FUNCTION(kafka) \ FUNCTION(lua) \ FUNCTION(main) \ diff --git a/source/common/config/BUILD b/source/common/config/BUILD index c7fb5b067410..378512d4df5f 100644 --- a/source/common/config/BUILD +++ b/source/common/config/BUILD @@ -31,27 +31,6 @@ envoy_cc_library( ], ) -envoy_cc_library( - name = "cds_json_lib", - srcs = ["cds_json.cc"], - hdrs = ["cds_json.h"], - external_deps = ["abseil_optional"], - deps = [ - ":address_json_lib", - ":json_utility_lib", - ":protocol_json_lib", - ":tls_context_json_lib", - ":utility_lib", - "//include/envoy/json:json_object_interface", - "//include/envoy/upstream:cluster_manager_interface", - "//source/common/common:assert_lib", - "//source/common/json:config_schemas_lib", - "//source/common/network:utility_lib", - "@envoy_api//envoy/api/v2:cds_cc", - "@envoy_api//envoy/api/v2/cluster:circuit_breaker_cc", - ], -) - envoy_cc_library( name = "filesystem_subscription_lib", srcs = ["filesystem_subscription_impl.cc"], @@ -73,8 +52,15 @@ envoy_cc_library( srcs = ["datasource.cc"], hdrs = ["datasource.h"], deps = [ + ":remote_data_fetcher_lib", "//include/envoy/api:api_interface", + "//include/envoy/init:manager_interface", + "//include/envoy/upstream:cluster_manager_interface", + "//source/common/common:empty_string", + "//source/common/init:target_lib", + "//source/common/protobuf:utility_lib", "@envoy_api//envoy/api/v2/core:base_cc", + "@envoy_api//envoy/api/v2/core:http_uri_cc", ], ) @@ -329,18 +315,6 @@ envoy_cc_library( ], ) -envoy_cc_library( - name = "tls_context_json_lib", - srcs = ["tls_context_json.cc"], - hdrs = ["tls_context_json.h"], - deps = [ - ":json_utility_lib", - "//include/envoy/json:json_object_interface", - "//source/common/common:utility_lib", - "@envoy_api//envoy/api/v2/auth:cert_cc", - ], -) - envoy_cc_library( name = "type_to_endpoint_lib", srcs = ["type_to_endpoint.cc"], @@ -413,3 +387,16 @@ envoy_cc_library( "//source/common/protobuf", ], ) + +envoy_cc_library( + name = "remote_data_fetcher_lib", + srcs = ["remote_data_fetcher.cc"], + hdrs = ["remote_data_fetcher.h"], + deps = [ + "//include/envoy/upstream:cluster_manager_interface", + "//source/common/common:hex_lib", + "//source/common/crypto:utility_lib", + "//source/common/http:utility_lib", + "@envoy_api//envoy/api/v2/core:http_uri_cc", + ], +) diff --git a/source/common/config/address_json.cc b/source/common/config/address_json.cc index 7206e7a3d879..f309c0d121a7 100644 --- a/source/common/config/address_json.cc +++ b/source/common/config/address_json.cc @@ -7,32 +7,6 @@ namespace Envoy { namespace Config { -void AddressJson::translateAddress(const std::string& json_address, bool url, bool resolved, - envoy::api::v2::core::Address& address) { - if (resolved) { - Network::Address::InstanceConstSharedPtr instance = - url ? Network::Utility::resolveUrl(json_address) - : Network::Utility::parseInternetAddressAndPort(json_address); - if (instance->type() == Network::Address::Type::Ip) { - address.mutable_socket_address()->set_address(instance->ip()->addressAsString()); - address.mutable_socket_address()->set_port_value(instance->ip()->port()); - } else { - ASSERT(instance->type() == Network::Address::Type::Pipe); - address.mutable_pipe()->set_path(instance->asString()); - } - return; - } - - // We don't have v1 JSON with unresolved addresses in non-URL form. - ASSERT(url); - // Non-TCP scheme (e.g. Unix scheme) is not supported with unresolved address. - if (!Network::Utility::urlIsTcpScheme(json_address)) { - throw EnvoyException(fmt::format("unresolved URL must be TCP scheme, got: {}", json_address)); - } - address.mutable_socket_address()->set_address(Network::Utility::hostFromTcpUrl(json_address)); - address.mutable_socket_address()->set_port_value(Network::Utility::portFromTcpUrl(json_address)); -} - void AddressJson::translateCidrRangeList( const std::vector& json_ip_list, Protobuf::RepeatedPtrField& range_list) { diff --git a/source/common/config/address_json.h b/source/common/config/address_json.h index 9dd890480113..2e35b466ad06 100644 --- a/source/common/config/address_json.h +++ b/source/common/config/address_json.h @@ -10,17 +10,6 @@ namespace Config { class AddressJson { public: - /** - * Translate a v1 JSON address to v2 envoy::api::v2::core::Address. - * @param json_address source address. - * @param url is json_address a URL? E.g. tcp://:. If not, it is - * treated as :. - * @param resolved is json_address a concrete IP/pipe or unresolved hostname? - * @param address destination envoy::api::v2::core::Address. - */ - static void translateAddress(const std::string& json_address, bool url, bool resolved, - envoy::api::v2::core::Address& address); - /** * Translate a v1 JSON array of IP ranges to v2 * Protobuf::RepeatedPtrField. diff --git a/source/common/config/cds_json.cc b/source/common/config/cds_json.cc deleted file mode 100644 index 95fede2e33c4..000000000000 --- a/source/common/config/cds_json.cc +++ /dev/null @@ -1,223 +0,0 @@ -#include "common/config/cds_json.h" - -#include "common/common/assert.h" -#include "common/config/address_json.h" -#include "common/config/json_utility.h" -#include "common/config/protocol_json.h" -#include "common/config/tls_context_json.h" -#include "common/config/utility.h" -#include "common/json/config_schemas.h" - -namespace Envoy { -namespace Config { - -void CdsJson::translateRingHashLbConfig( - const Json::Object& json_ring_hash_lb_config, - envoy::api::v2::Cluster::RingHashLbConfig& ring_hash_lb_config) { - JSON_UTIL_SET_INTEGER(json_ring_hash_lb_config, ring_hash_lb_config, minimum_ring_size); -} - -void CdsJson::translateHealthCheck(const Json::Object& json_health_check, - envoy::api::v2::core::HealthCheck& health_check) { - json_health_check.validateSchema(Json::Schema::CLUSTER_HEALTH_CHECK_SCHEMA); - - JSON_UTIL_SET_DURATION(json_health_check, health_check, timeout); - JSON_UTIL_SET_DURATION(json_health_check, health_check, interval); - JSON_UTIL_SET_DURATION(json_health_check, health_check, interval_jitter); - JSON_UTIL_SET_INTEGER(json_health_check, health_check, unhealthy_threshold); - JSON_UTIL_SET_INTEGER(json_health_check, health_check, healthy_threshold); - JSON_UTIL_SET_BOOL(json_health_check, health_check, reuse_connection); - - const std::string health_check_type = json_health_check.getString("type"); - if (health_check_type == "http") { - health_check.mutable_http_health_check()->set_path(json_health_check.getString("path")); - if (json_health_check.hasObject("service_name")) { - health_check.mutable_http_health_check()->set_service_name( - json_health_check.getString("service_name")); - } - } else if (health_check_type == "tcp") { - auto* tcp_health_check = health_check.mutable_tcp_health_check(); - std::string send_text; - for (const Json::ObjectSharedPtr& entry : json_health_check.getObjectArray("send")) { - const std::string hex_string = entry->getString("binary"); - send_text += hex_string; - } - if (!send_text.empty()) { - tcp_health_check->mutable_send()->set_text(send_text); - } - for (const Json::ObjectSharedPtr& entry : json_health_check.getObjectArray("receive")) { - const std::string hex_string = entry->getString("binary"); - tcp_health_check->mutable_receive()->Add()->set_text(hex_string); - } - } else { - ASSERT(health_check_type == "redis"); - auto* redis_health_check = health_check.mutable_custom_health_check(); - redis_health_check->set_name("envoy.health_checkers.redis"); - if (json_health_check.hasObject("redis_key")) { - redis_health_check->mutable_config()->MergeFrom( - MessageUtil::keyValueStruct("key", json_health_check.getString("redis_key"))); - } - } -} - -void CdsJson::translateThresholds( - const Json::Object& json_thresholds, const envoy::api::v2::core::RoutingPriority& priority, - envoy::api::v2::cluster::CircuitBreakers::Thresholds& thresholds) { - thresholds.set_priority(priority); - JSON_UTIL_SET_INTEGER(json_thresholds, thresholds, max_connections); - JSON_UTIL_SET_INTEGER(json_thresholds, thresholds, max_pending_requests); - JSON_UTIL_SET_INTEGER(json_thresholds, thresholds, max_requests); - JSON_UTIL_SET_INTEGER(json_thresholds, thresholds, max_retries); -} - -void CdsJson::translateCircuitBreakers(const Json::Object& json_circuit_breakers, - envoy::api::v2::cluster::CircuitBreakers& circuit_breakers) { - translateThresholds(*json_circuit_breakers.getObject("default", true), - envoy::api::v2::core::RoutingPriority::DEFAULT, - *circuit_breakers.mutable_thresholds()->Add()); - translateThresholds(*json_circuit_breakers.getObject("high", true), - envoy::api::v2::core::RoutingPriority::HIGH, - *circuit_breakers.mutable_thresholds()->Add()); -} - -void CdsJson::translateOutlierDetection( - const Json::Object& json_outlier_detection, - envoy::api::v2::cluster::OutlierDetection& outlier_detection) { - JSON_UTIL_SET_DURATION(json_outlier_detection, outlier_detection, interval); - JSON_UTIL_SET_DURATION(json_outlier_detection, outlier_detection, base_ejection_time); - JSON_UTIL_SET_INTEGER(json_outlier_detection, outlier_detection, consecutive_5xx); - JSON_UTIL_SET_INTEGER(json_outlier_detection, outlier_detection, consecutive_gateway_failure); - JSON_UTIL_SET_INTEGER(json_outlier_detection, outlier_detection, max_ejection_percent); - JSON_UTIL_SET_INTEGER(json_outlier_detection, outlier_detection, enforcing_consecutive_5xx); - JSON_UTIL_SET_INTEGER(json_outlier_detection, outlier_detection, - enforcing_consecutive_gateway_failure); - JSON_UTIL_SET_INTEGER(json_outlier_detection, outlier_detection, enforcing_success_rate); - JSON_UTIL_SET_INTEGER(json_outlier_detection, outlier_detection, success_rate_minimum_hosts); - JSON_UTIL_SET_INTEGER(json_outlier_detection, outlier_detection, success_rate_request_volume); - JSON_UTIL_SET_INTEGER(json_outlier_detection, outlier_detection, success_rate_stdev_factor); -} - -void CdsJson::translateCluster(const Json::Object& json_cluster, - const absl::optional& eds_config, - envoy::api::v2::Cluster& cluster) { - json_cluster.validateSchema(Json::Schema::CLUSTER_SCHEMA); - - const std::string name = json_cluster.getString("name"); - cluster.set_name(name); - - const std::string string_type = json_cluster.getString("type"); - auto set_dns_hosts = [&json_cluster, &cluster] { - const auto hosts = json_cluster.getObjectArray("hosts"); - std::transform(hosts.cbegin(), hosts.cend(), - Protobuf::RepeatedPtrFieldBackInserter(cluster.mutable_hosts()), - [](const Json::ObjectSharedPtr& host) { - envoy::api::v2::core::Address address; - AddressJson::translateAddress(host->getString("url"), true, false, address); - return address; - }); - }; - if (string_type == "static") { - cluster.set_type(envoy::api::v2::Cluster::STATIC); - const auto hosts = json_cluster.getObjectArray("hosts"); - std::transform(hosts.cbegin(), hosts.cend(), - Protobuf::RepeatedPtrFieldBackInserter(cluster.mutable_hosts()), - [](const Json::ObjectSharedPtr& host) { - envoy::api::v2::core::Address address; - AddressJson::translateAddress(host->getString("url"), true, true, address); - return address; - }); - } else if (string_type == "strict_dns") { - cluster.set_type(envoy::api::v2::Cluster::STRICT_DNS); - set_dns_hosts(); - } else if (string_type == "logical_dns") { - cluster.set_type(envoy::api::v2::Cluster::LOGICAL_DNS); - set_dns_hosts(); - } else if (string_type == "original_dst") { - if (json_cluster.hasObject("hosts")) { - throw EnvoyException("original_dst clusters must have no hosts configured"); - } - cluster.set_type(envoy::api::v2::Cluster::ORIGINAL_DST); - } else { - ASSERT(string_type == "sds"); - if (!eds_config) { - throw EnvoyException("cannot create sds cluster with no sds config"); - } - cluster.set_type(envoy::api::v2::Cluster::EDS); - cluster.mutable_eds_cluster_config()->mutable_eds_config()->CopyFrom(eds_config.value()); - JSON_UTIL_SET_STRING(json_cluster, *cluster.mutable_eds_cluster_config(), service_name); - } - - JSON_UTIL_SET_DURATION(json_cluster, cluster, cleanup_interval); - JSON_UTIL_SET_DURATION(json_cluster, cluster, connect_timeout); - JSON_UTIL_SET_INTEGER(json_cluster, cluster, per_connection_buffer_limit_bytes); - - const std::string lb_type = json_cluster.getString("lb_type"); - if (lb_type == "round_robin") { - cluster.set_lb_policy(envoy::api::v2::Cluster::ROUND_ROBIN); - } else if (lb_type == "least_request") { - cluster.set_lb_policy(envoy::api::v2::Cluster::LEAST_REQUEST); - } else if (lb_type == "random") { - cluster.set_lb_policy(envoy::api::v2::Cluster::RANDOM); - } else if (lb_type == "original_dst_lb") { - cluster.set_lb_policy(envoy::api::v2::Cluster::ORIGINAL_DST_LB); - } else { - ASSERT(lb_type == "ring_hash"); - cluster.set_lb_policy(envoy::api::v2::Cluster::RING_HASH); - } - - if (json_cluster.hasObject("ring_hash_lb_config")) { - translateRingHashLbConfig(*json_cluster.getObject("ring_hash_lb_config"), - *cluster.mutable_ring_hash_lb_config()); - } - - if (json_cluster.hasObject("health_check")) { - translateHealthCheck(*json_cluster.getObject("health_check"), - *cluster.mutable_health_checks()->Add()); - } - - JSON_UTIL_SET_INTEGER(json_cluster, cluster, max_requests_per_connection); - if (json_cluster.hasObject("circuit_breakers")) { - translateCircuitBreakers(*json_cluster.getObject("circuit_breakers"), - *cluster.mutable_circuit_breakers()); - } - - if (json_cluster.hasObject("ssl_context")) { - TlsContextJson::translateUpstreamTlsContext(*json_cluster.getObject("ssl_context"), - *cluster.mutable_tls_context()); - } - - if (json_cluster.getString("features", "") == "http2" || - json_cluster.hasObject("http2_settings")) { - ProtocolJson::translateHttp2ProtocolOptions(*json_cluster.getObject("http2_settings", true), - *cluster.mutable_http2_protocol_options()); - } - - JSON_UTIL_SET_DURATION(json_cluster, cluster, dns_refresh_rate); - const std::string dns_lookup_family = json_cluster.getString("dns_lookup_family", "v4_only"); - if (dns_lookup_family == "auto") { - cluster.set_dns_lookup_family(envoy::api::v2::Cluster::AUTO); - } else if (dns_lookup_family == "v6_only") { - cluster.set_dns_lookup_family(envoy::api::v2::Cluster::V6_ONLY); - } else { - ASSERT(dns_lookup_family == "v4_only"); - cluster.set_dns_lookup_family(envoy::api::v2::Cluster::V4_ONLY); - } - if (json_cluster.hasObject("dns_resolvers")) { - const auto dns_resolvers = json_cluster.getStringArray("dns_resolvers"); - std::transform(dns_resolvers.cbegin(), dns_resolvers.cend(), - Protobuf::RepeatedPtrFieldBackInserter(cluster.mutable_dns_resolvers()), - [](const std::string& json_address) { - envoy::api::v2::core::Address address; - AddressJson::translateAddress(json_address, false, true, address); - return address; - }); - } - - if (json_cluster.hasObject("outlier_detection")) { - translateOutlierDetection(*json_cluster.getObject("outlier_detection"), - *cluster.mutable_outlier_detection()); - } -} - -} // namespace Config -} // namespace Envoy diff --git a/source/common/config/cds_json.h b/source/common/config/cds_json.h deleted file mode 100644 index f2995074f79a..000000000000 --- a/source/common/config/cds_json.h +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - -#include "envoy/api/v2/cds.pb.h" -#include "envoy/api/v2/cluster/circuit_breaker.pb.h" -#include "envoy/json/json_object.h" -#include "envoy/upstream/cluster_manager.h" - -#include "absl/types/optional.h" - -namespace Envoy { -namespace Config { - -class CdsJson { -public: - /** - * Translate a v1 JSON ring hash config to envoy::api::v2::Cluster::RingHashLbConfig. - * @param json_ring_hash_lb_config source v1 JSON ring hash config object. - * @param ring_hash_lb_config destination v2 envoy::api::v2::Cluster::RingHashLbConfig. - */ - static void - translateRingHashLbConfig(const Json::Object& json_ring_hash_lb_config, - envoy::api::v2::Cluster::RingHashLbConfig& ring_hash_lb_config); - - /** - * Translate a v1 JSON health check object to v2 envoy::api::v2::core::HealthCheck. - * @param json_health_check source v1 JSON health check object. - * @param health_check destination v2 envoy::api::v2::core::HealthCheck. - */ - static void translateHealthCheck(const Json::Object& json_health_check, - envoy::api::v2::core::HealthCheck& health_check); - - /** - * Translate a v1 JSON thresholds object to v2 envoy::api::v2::Thresholds. - * @param json_thresholds source v1 JSON thresholds object. - * @param priority priority for thresholds. - * @param thresholds destination v2 envoy::api::v2::Thresholds. - */ - static void translateThresholds(const Json::Object& json_thresholds, - const envoy::api::v2::core::RoutingPriority& priority, - envoy::api::v2::cluster::CircuitBreakers::Thresholds& thresholds); - - /** - * Translate a v1 JSON circuit breakers object to v2 envoy::api::v2::cluster::CircuitBreakers. - * @param json_circuit_breakers source v1 JSON circuit breakers object. - * @param circuit_breakers destination v2 envoy::api::v2::cluster::CircuitBreakers. - */ - static void translateCircuitBreakers(const Json::Object& json_circuit_breakers, - envoy::api::v2::cluster::CircuitBreakers& circuit_breakers); - - /** - * Translate a v1 JSON outlier detection object to v2 envoy::api::v2::OutlierDetection. - * @param json_outlier_detection source v1 JSON outlier detection object. - * @param outlier_detection destination v2 envoy::api::v2::OutlierDetection. - */ - static void - translateOutlierDetection(const Json::Object& json_outlier_detection, - envoy::api::v2::cluster::OutlierDetection& outlier_detection); - - /** - * Translate a v1 JSON Cluster to v2 envoy::api::v2::Cluster. - * @param json_cluster source v1 JSON Cluster object. - * @param eds_config SDS config if 'sds' discovery type. - * @param cluster destination v2 envoy::api::v2::Cluster. - */ - static void translateCluster(const Json::Object& json_cluster, - const absl::optional& eds_config, - envoy::api::v2::Cluster& cluster); -}; - -} // namespace Config -} // namespace Envoy diff --git a/source/common/config/config_provider_impl.h b/source/common/config/config_provider_impl.h index 5e808aff067f..561170388eed 100644 --- a/source/common/config/config_provider_impl.h +++ b/source/common/config/config_provider_impl.h @@ -192,7 +192,7 @@ class ConfigSubscriptionCommonBase protected: struct ThreadLocalConfig : public ThreadLocal::ThreadLocalObject { - ThreadLocalConfig(ConfigProvider::ConfigConstSharedPtr initial_config) + explicit ThreadLocalConfig(ConfigProvider::ConfigConstSharedPtr initial_config) : config_(std::move(initial_config)) {} ConfigProvider::ConfigConstSharedPtr config_; @@ -227,7 +227,10 @@ class ConfigSubscriptionCommonBase [this, update_fn]() { tls_->getTyped().config_ = update_fn(this->getConfig()); }, - /*Make sure this subscription will not be teared down during the update propagation.*/ + /*During the update propagation, a subscription may get teared down in main thread due to + all owners/providers destructed in a xDS update (e.g. LDS demolishes RouteConfigProvider and + its subscription). Hold a reference to the shared subscription instance to make sure the + update can be safely pushed to workers in such an event.*/ [shared_this, complete_cb]() { complete_cb(); }); } diff --git a/source/common/config/datasource.h b/source/common/config/datasource.h index 8c1312165f92..991f7c2e6034 100644 --- a/source/common/config/datasource.h +++ b/source/common/config/datasource.h @@ -2,6 +2,13 @@ #include "envoy/api/api.h" #include "envoy/api/v2/core/base.pb.h" +#include "envoy/init/manager.h" +#include "envoy/upstream/cluster_manager.h" + +#include "common/common/empty_string.h" +#include "common/common/enum_to_int.h" +#include "common/config/remote_data_fetcher.h" +#include "common/init/target_impl.h" #include "absl/types/optional.h" @@ -25,6 +32,72 @@ std::string read(const envoy::api::v2::core::DataSource& source, bool allow_empt */ absl::optional getPath(const envoy::api::v2::core::DataSource& source); +/** + * Callback for async data source. + */ +using AsyncDataSourceCb = std::function; + +class LocalAsyncDataProvider { +public: + LocalAsyncDataProvider(Init::Manager& manager, const envoy::api::v2::core::DataSource& source, + bool allow_empty, Api::Api& api, AsyncDataSourceCb&& callback) + : init_target_("LocalAsyncDataProvider", [this, &source, allow_empty, &api, callback]() { + callback(DataSource::read(source, allow_empty, api)); + init_target_.ready(); + }) { + manager.add(init_target_); + } + + ~LocalAsyncDataProvider() { init_target_.ready(); } + +private: + Init::TargetImpl init_target_; +}; + +using LocalAsyncDataProviderPtr = std::unique_ptr; + +class RemoteAsyncDataProvider : public Config::DataFetcher::RemoteDataFetcherCallback { +public: + RemoteAsyncDataProvider(Upstream::ClusterManager& cm, Init::Manager& manager, + const envoy::api::v2::core::RemoteDataSource& source, bool allow_empty, + AsyncDataSourceCb&& callback) + : allow_empty_(allow_empty), callback_(std::move(callback)), + fetcher_(std::make_unique(cm, source.http_uri(), + source.sha256(), *this)), + init_target_("RemoteAsyncDataProvider", [this]() { start(); }) { + manager.add(init_target_); + } + + ~RemoteAsyncDataProvider() override { init_target_.ready(); } + + // Config::DataFetcher::RemoteDataFetcherCallback + void onSuccess(const std::string& data) override { + callback_(data); + init_target_.ready(); + } + + // Config::DataFetcher::RemoteDataFetcherCallback + void onFailure(Config::DataFetcher::FailureReason failure) override { + if (allow_empty_) { + callback_(EMPTY_STRING); + init_target_.ready(); + } else { + throw EnvoyException( + fmt::format("Failed to fetch remote data. Failure reason: {}", enumToInt(failure))); + } + } + +private: + void start() { fetcher_->fetch(); } + + bool allow_empty_; + AsyncDataSourceCb callback_; + const Config::DataFetcher::RemoteDataFetcherPtr fetcher_; + Init::TargetImpl init_target_; +}; + +using RemoteAsyncDataProviderPtr = std::unique_ptr; + } // namespace DataSource } // namespace Config } // namespace Envoy diff --git a/source/common/config/delta_subscription_state.h b/source/common/config/delta_subscription_state.h index 5fbb6f79f5a1..f21e0b895b9e 100644 --- a/source/common/config/delta_subscription_state.h +++ b/source/common/config/delta_subscription_state.h @@ -56,7 +56,7 @@ class DeltaSubscriptionState : public Logger::Loggable { public: explicit ResourceVersion(absl::string_view version) : version_(version) {} // Builds a ResourceVersion in the waitingForServer state. - ResourceVersion() {} + ResourceVersion() = default; // If true, we currently have no version of this resource - we are waiting for the server to // provide us with one. diff --git a/source/common/config/grpc_mux_impl.h b/source/common/config/grpc_mux_impl.h index 1181ef0dfec5..33ef94150822 100644 --- a/source/common/config/grpc_mux_impl.h +++ b/source/common/config/grpc_mux_impl.h @@ -29,7 +29,7 @@ class GrpcMuxImpl : public GrpcMux, Event::Dispatcher& dispatcher, const Protobuf::MethodDescriptor& service_method, Runtime::RandomGenerator& random, Stats::Scope& scope, const RateLimitSettings& rate_limit_settings); - ~GrpcMuxImpl(); + ~GrpcMuxImpl() override; void start() override; GrpcMuxWatchPtr subscribe(const std::string& type_url, const std::set& resources, diff --git a/source/common/config/remote_data_fetcher.cc b/source/common/config/remote_data_fetcher.cc new file mode 100644 index 000000000000..8e79e35fc8d9 --- /dev/null +++ b/source/common/config/remote_data_fetcher.cc @@ -0,0 +1,75 @@ +#include "common/config/remote_data_fetcher.h" + +#include "common/common/enum_to_int.h" +#include "common/common/hex.h" +#include "common/crypto/utility.h" +#include "common/http/headers.h" +#include "common/http/utility.h" + +namespace Envoy { +namespace Config { +namespace DataFetcher { + +RemoteDataFetcher::RemoteDataFetcher(Upstream::ClusterManager& cm, + const ::envoy::api::v2::core::HttpUri& uri, + const std::string& content_hash, + RemoteDataFetcherCallback& callback) + : cm_(cm), uri_(uri), content_hash_(content_hash), callback_(callback) {} + +RemoteDataFetcher::~RemoteDataFetcher() { cancel(); } + +void RemoteDataFetcher::cancel() { + if (request_) { + request_->cancel(); + ENVOY_LOG(debug, "fetch remote data [uri = {}]: canceled", uri_.uri()); + } + + request_ = nullptr; +} + +void RemoteDataFetcher::fetch() { + Http::MessagePtr message = Http::Utility::prepareHeaders(uri_); + message->headers().insertMethod().value().setReference(Http::Headers::get().MethodValues.Get); + ENVOY_LOG(debug, "fetch remote data from [uri = {}]: start", uri_.uri()); + request_ = cm_.httpAsyncClientForCluster(uri_.cluster()) + .send(std::move(message), *this, + Http::AsyncClient::RequestOptions().setTimeout(std::chrono::milliseconds( + DurationUtil::durationToMilliseconds(uri_.timeout())))); +} + +void RemoteDataFetcher::onSuccess(Http::MessagePtr&& response) { + const uint64_t status_code = Http::Utility::getResponseStatus(response->headers()); + if (status_code == enumToInt(Http::Code::OK)) { + ENVOY_LOG(debug, "fetch remote data [uri = {}]: success", uri_.uri()); + if (response->body()) { + const auto content_hash = + Hex::encode(Envoy::Common::Crypto::Utility::getSha256Digest(*response->body())); + + if (content_hash_ != content_hash) { + ENVOY_LOG(debug, "fetch remote data [uri = {}]: data is invalid", uri_.uri()); + callback_.onFailure(FailureReason::InvalidData); + } else { + callback_.onSuccess(response->body()->toString()); + } + } else { + ENVOY_LOG(debug, "fetch remote data [uri = {}]: body is empty", uri_.uri()); + callback_.onFailure(FailureReason::Network); + } + } else { + ENVOY_LOG(debug, "fetch remote data [uri = {}]: response status code {}", uri_.uri(), + status_code); + callback_.onFailure(FailureReason::Network); + } + + request_ = nullptr; +} + +void RemoteDataFetcher::onFailure(Http::AsyncClient::FailureReason reason) { + ENVOY_LOG(debug, "fetch remote data [uri = {}]: network error {}", uri_.uri(), enumToInt(reason)); + request_ = nullptr; + callback_.onFailure(FailureReason::Network); +} + +} // namespace DataFetcher +} // namespace Config +} // namespace Envoy \ No newline at end of file diff --git a/source/common/config/remote_data_fetcher.h b/source/common/config/remote_data_fetcher.h new file mode 100644 index 000000000000..6455e44abf1b --- /dev/null +++ b/source/common/config/remote_data_fetcher.h @@ -0,0 +1,82 @@ +#pragma once + +#include "envoy/api/v2/core/http_uri.pb.h" +#include "envoy/common/pure.h" +#include "envoy/upstream/cluster_manager.h" + +namespace Envoy { +namespace Config { +namespace DataFetcher { + +/** + * Failure reason. + */ +enum class FailureReason { + /* A network error occurred causing remote data retrieval failure. */ + Network, + /* A failure occurred when trying to verify remote data using sha256. */ + InvalidData, +}; + +/** + * Callback used by remote data fetcher. + */ +class RemoteDataFetcherCallback { +public: + virtual ~RemoteDataFetcherCallback() = default; + + /** + * This function will be called when data is fetched successfully from remote. + * @param data remote data + */ + virtual void onSuccess(const std::string& data) PURE; + + /** + * This function is called when error happens during fetching data. + * @param reason failure reason. + */ + virtual void onFailure(FailureReason reason) PURE; +}; + +/** + * Remote data fetcher. + */ +class RemoteDataFetcher : public Logger::Loggable, + public Http::AsyncClient::Callbacks { +public: + RemoteDataFetcher(Upstream::ClusterManager& cm, const ::envoy::api::v2::core::HttpUri& uri, + const std::string& content_hash, RemoteDataFetcherCallback& callback); + + ~RemoteDataFetcher() override; + + // Http::AsyncClient::Callbacks + void onSuccess(Http::MessagePtr&& response) override; + void onFailure(Http::AsyncClient::FailureReason reason) override; + + /** + * Fetch data from remote. + * @param uri remote URI + * @param content_hash for verifying data integrity + * @param callback callback when fetch is done. + */ + void fetch(); + + /** + * Cancel the fetch. + */ + void cancel(); + +private: + Upstream::ClusterManager& cm_; + const envoy::api::v2::core::HttpUri& uri_; + const std::string content_hash_; + RemoteDataFetcherCallback& callback_; + + Http::AsyncClient::Request* request_{}; +}; + +using RemoteDataFetcherPtr = std::unique_ptr; + +} // namespace DataFetcher +} // namespace Config +} // namespace Envoy \ No newline at end of file diff --git a/source/common/config/tls_context_json.cc b/source/common/config/tls_context_json.cc deleted file mode 100644 index fece59b47676..000000000000 --- a/source/common/config/tls_context_json.cc +++ /dev/null @@ -1,70 +0,0 @@ -#include "common/config/tls_context_json.h" - -#include "envoy/api/v2/auth/cert.pb.validate.h" - -#include "common/common/utility.h" -#include "common/config/json_utility.h" -#include "common/protobuf/utility.h" - -namespace Envoy { -namespace Config { - -void TlsContextJson::translateUpstreamTlsContext( - const Json::Object& json_tls_context, - envoy::api::v2::auth::UpstreamTlsContext& upstream_tls_context) { - translateCommonTlsContext(json_tls_context, *upstream_tls_context.mutable_common_tls_context()); - upstream_tls_context.set_sni(json_tls_context.getString("sni", "")); - MessageUtil::validate(upstream_tls_context); -} - -void TlsContextJson::translateCommonTlsContext( - const Json::Object& json_tls_context, - envoy::api::v2::auth::CommonTlsContext& common_tls_context) { - const std::string alpn_protocols_str{json_tls_context.getString("alpn_protocols", "")}; - for (auto alpn_protocol : StringUtil::splitToken(alpn_protocols_str, ",")) { - common_tls_context.add_alpn_protocols(std::string{alpn_protocol}); - } - - translateTlsCertificate(json_tls_context, *common_tls_context.mutable_tls_certificates()->Add()); - - auto* validation_context = common_tls_context.mutable_validation_context(); - if (json_tls_context.hasObject("ca_cert_file")) { - validation_context->mutable_trusted_ca()->set_filename( - json_tls_context.getString("ca_cert_file", "")); - } - if (json_tls_context.hasObject("crl_file")) { - validation_context->mutable_crl()->set_filename(json_tls_context.getString("crl_file", "")); - } - if (json_tls_context.hasObject("verify_certificate_hash")) { - validation_context->add_verify_certificate_hash( - json_tls_context.getString("verify_certificate_hash")); - } - for (const auto& san : json_tls_context.getStringArray("verify_subject_alt_name", true)) { - validation_context->add_verify_subject_alt_name(san); - } - - const std::string cipher_suites_str{json_tls_context.getString("cipher_suites", "")}; - for (auto cipher_suite : StringUtil::splitToken(cipher_suites_str, ":")) { - common_tls_context.mutable_tls_params()->add_cipher_suites(std::string{cipher_suite}); - } - - const std::string ecdh_curves_str{json_tls_context.getString("ecdh_curves", "")}; - for (auto ecdh_curve : StringUtil::splitToken(ecdh_curves_str, ":")) { - common_tls_context.mutable_tls_params()->add_ecdh_curves(std::string{ecdh_curve}); - } -} - -void TlsContextJson::translateTlsCertificate( - const Json::Object& json_tls_context, envoy::api::v2::auth::TlsCertificate& tls_certificate) { - if (json_tls_context.hasObject("cert_chain_file")) { - tls_certificate.mutable_certificate_chain()->set_filename( - json_tls_context.getString("cert_chain_file", "")); - } - if (json_tls_context.hasObject("private_key_file")) { - tls_certificate.mutable_private_key()->set_filename( - json_tls_context.getString("private_key_file", "")); - } -} - -} // namespace Config -} // namespace Envoy diff --git a/source/common/config/tls_context_json.h b/source/common/config/tls_context_json.h deleted file mode 100644 index 1eb9cbc1139d..000000000000 --- a/source/common/config/tls_context_json.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "envoy/api/v2/auth/cert.pb.h" -#include "envoy/json/json_object.h" - -namespace Envoy { -namespace Config { - -class TlsContextJson { -public: - /** - * Translate a v1 JSON TLS context to v2 envoy::api::v2::auth::UpstreamTlsContext. - * @param json_tls_context source v1 JSON TLS context object. - * @param upstream_tls_context destination v2 envoy::api::v2::Cluster. - */ - static void - translateUpstreamTlsContext(const Json::Object& json_tls_context, - envoy::api::v2::auth::UpstreamTlsContext& upstream_tls_context); - /** - * Translate a v1 JSON TLS context to v2 envoy::api::v2::auth::CommonTlsContext. - * @param json_tls_context source v1 JSON TLS context object. - * @param common_tls_context destination v2 envoy::api::v2::Cluster. - */ - static void translateCommonTlsContext(const Json::Object& json_tls_context, - envoy::api::v2::auth::CommonTlsContext& common_tls_context); - - /** - * Translate a v1 JSON TLS context to v2 envoy::api::v2::auth::TlsCertificate. - * @param json_tls_context source v1 JSON TLS context object. - * @param common_tls_context destination v2 envoy::api::v2::auth::TlsCertificate. - */ - static void translateTlsCertificate(const Json::Object& json_tls_context, - envoy::api::v2::auth::TlsCertificate& tls_certificate); -}; - -} // namespace Config -} // namespace Envoy diff --git a/source/common/config/utility.cc b/source/common/config/utility.cc index d22cc0a4cca6..84dedbcda38f 100644 --- a/source/common/config/utility.cc +++ b/source/common/config/utility.cc @@ -180,7 +180,7 @@ std::chrono::milliseconds Utility::apiConfigSourceRequestTimeout( std::chrono::milliseconds Utility::configSourceInitialFetchTimeout(const envoy::api::v2::core::ConfigSource& config_source) { return std::chrono::milliseconds( - PROTOBUF_GET_MS_OR_DEFAULT(config_source, initial_fetch_timeout, 0)); + PROTOBUF_GET_MS_OR_DEFAULT(config_source, initial_fetch_timeout, 15000)); } void Utility::translateRdsConfig( diff --git a/source/common/event/dispatcher_impl.h b/source/common/event/dispatcher_impl.h index 51f71e8ad807..5cbccddb66e0 100644 --- a/source/common/event/dispatcher_impl.h +++ b/source/common/event/dispatcher_impl.h @@ -33,7 +33,7 @@ class DispatcherImpl : Logger::Loggable, DispatcherImpl(Api::Api& api, Event::TimeSystem& time_system); DispatcherImpl(Buffer::WatermarkFactoryPtr&& factory, Api::Api& api, Event::TimeSystem& time_system); - ~DispatcherImpl(); + ~DispatcherImpl() override; /** * @return event_base& the libevent base. @@ -91,9 +91,9 @@ class DispatcherImpl : Logger::Loggable, void runPostCallbacks(); // Validate that an operation is thread safe, i.e. it's invoked on the same thread that the - // dispatcher run loop is executing on. We allow run_tid_ == nullptr for tests where we don't + // dispatcher run loop is executing on. We allow run_tid_ to be empty for tests where we don't // invoke run(). - bool isThreadSafe() const { + bool isThreadSafe() const override { return run_tid_.isEmpty() || run_tid_ == api_.threadFactory().currentThreadId(); } diff --git a/source/common/filesystem/posix/directory_iterator_impl.h b/source/common/filesystem/posix/directory_iterator_impl.h index 513b5f98406d..ed5460dba673 100644 --- a/source/common/filesystem/posix/directory_iterator_impl.h +++ b/source/common/filesystem/posix/directory_iterator_impl.h @@ -12,10 +12,9 @@ namespace Filesystem { class DirectoryIteratorImpl : public DirectoryIterator { public: DirectoryIteratorImpl(const std::string& directory_path); - DirectoryIteratorImpl() - : directory_path_(""), dir_(nullptr), os_sys_calls_(Api::OsSysCallsSingleton::get()) {} + DirectoryIteratorImpl() : directory_path_(""), os_sys_calls_(Api::OsSysCallsSingleton::get()) {} - ~DirectoryIteratorImpl(); + ~DirectoryIteratorImpl() override; DirectoryIteratorImpl& operator++() override; @@ -32,7 +31,7 @@ class DirectoryIteratorImpl : public DirectoryIterator { FileType fileType(const std::string& name) const; std::string directory_path_; - DIR* dir_; + DIR* dir_{nullptr}; Api::OsSysCallsImpl& os_sys_calls_; }; diff --git a/source/common/grpc/codec.cc b/source/common/grpc/codec.cc index 94a0666a17e6..3362bf736061 100644 --- a/source/common/grpc/codec.cc +++ b/source/common/grpc/codec.cc @@ -11,7 +11,7 @@ namespace Envoy { namespace Grpc { -Encoder::Encoder() {} +Encoder::Encoder() = default; void Encoder::newFrame(uint8_t flags, uint64_t length, std::array& output) { output[0] = flags; diff --git a/source/common/grpc/google_async_client_impl.h b/source/common/grpc/google_async_client_impl.h index b14456235b21..da834f1b82a9 100644 --- a/source/common/grpc/google_async_client_impl.h +++ b/source/common/grpc/google_async_client_impl.h @@ -66,7 +66,7 @@ class GoogleAsyncClientThreadLocal : public ThreadLocal::ThreadLocalObject, Logger::Loggable { public: GoogleAsyncClientThreadLocal(Api::Api& api); - ~GoogleAsyncClientThreadLocal(); + ~GoogleAsyncClientThreadLocal() override; grpc::CompletionQueue& completionQueue() { return cq_; } @@ -199,7 +199,7 @@ class GoogleAsyncStreamImpl : public RawAsyncStream, GoogleAsyncStreamImpl(GoogleAsyncClientImpl& parent, absl::string_view service_full_name, absl::string_view method_name, RawAsyncStreamCallbacks& callbacks, const absl::optional& timeout); - ~GoogleAsyncStreamImpl(); + ~GoogleAsyncStreamImpl() override; virtual void initialize(bool buffer_body_for_retry); @@ -237,10 +237,10 @@ class GoogleAsyncStreamImpl : public RawAsyncStream, struct PendingMessage { PendingMessage(Buffer::InstancePtr request, bool end_stream); // End-of-stream with no additional message. - PendingMessage() : end_stream_(true) {} + PendingMessage() = default; const absl::optional buf_; - const bool end_stream_; + const bool end_stream_{true}; }; GoogleAsyncTag init_tag_{*this, GoogleAsyncTag::Operation::Init}; diff --git a/source/common/grpc/typed_async_client.h b/source/common/grpc/typed_async_client.h index 910ba7c5731f..48ad6d06df70 100644 --- a/source/common/grpc/typed_async_client.h +++ b/source/common/grpc/typed_async_client.h @@ -29,7 +29,7 @@ AsyncRequest* sendUntyped(RawAsyncClient* client, const Protobuf::MethodDescript */ template class AsyncStream /* : public RawAsyncStream */ { public: - AsyncStream() {} + AsyncStream() = default; AsyncStream(RawAsyncStream* stream) : stream_(stream) {} AsyncStream(const AsyncStream& other) = default; void sendMessage(const Request& request, bool end_stream) { @@ -93,7 +93,7 @@ template class AsyncStreamCallbacks : public RawAsyncStreamC template class AsyncClient /* : public RawAsyncClient )*/ { public: - AsyncClient() {} + AsyncClient() = default; AsyncClient(RawAsyncClientPtr&& client) : client_(std::move(client)) {} virtual ~AsyncClient() = default; diff --git a/source/common/http/BUILD b/source/common/http/BUILD index 88ff9675e93c..1dcf5045fa26 100644 --- a/source/common/http/BUILD +++ b/source/common/http/BUILD @@ -142,6 +142,7 @@ envoy_cc_library( ":conn_manager_config_interface", ":exception_lib", ":header_map_lib", + ":header_utility_lib", ":headers_lib", ":path_utility_lib", ":user_agent_lib", @@ -313,6 +314,9 @@ envoy_cc_library( name = "header_utility_lib", srcs = ["header_utility.cc"], hdrs = ["header_utility.h"], + external_deps = [ + "nghttp2", + ], deps = [ "//include/envoy/http:header_map_interface", "//include/envoy/json:json_object_interface", diff --git a/source/common/http/async_client_impl.h b/source/common/http/async_client_impl.h index e0a079dddf73..b5374c455f1a 100644 --- a/source/common/http/async_client_impl.h +++ b/source/common/http/async_client_impl.h @@ -9,6 +9,7 @@ #include #include +#include "envoy/common/scope_tracker.h" #include "envoy/config/typed_metadata.h" #include "envoy/event/dispatcher.h" #include "envoy/http/async_client.h" @@ -73,7 +74,8 @@ class AsyncStreamImpl : public AsyncClient::Stream, public StreamDecoderFilterCallbacks, public Event::DeferredDeletable, Logger::Loggable, - LinkedObject { + LinkedObject, + public ScopeTrackedObject { public: AsyncStreamImpl(AsyncClientImpl& parent, AsyncClient::StreamCallbacks& callbacks, const AsyncClient::StreamOptions& options); @@ -340,9 +342,17 @@ class AsyncStreamImpl : public AsyncClient::Stream, void setDecoderBufferLimit(uint32_t) override {} uint32_t decoderBufferLimit() override { return 0; } bool recreateStream() override { return false; } + const ScopeTrackedObject& scope() override { return *this; } void addUpstreamSocketOptions(const Network::Socket::OptionsSharedPtr&) override {} Network::Socket::OptionsSharedPtr getUpstreamSocketOptions() const override { return {}; } + // ScopeTrackedObject + void dumpState(std::ostream& os, int indent_level) const override { + const char* spaces = spacesForLevel(indent_level); + os << spaces << "AsyncClient " << this << DUMP_MEMBER(stream_id_) << "\n"; + DUMP_DETAILS(&stream_info_); + } + AsyncClient::StreamCallbacks& stream_callbacks_; const uint64_t stream_id_; Router::ProdFilter router_; diff --git a/source/common/http/codec_client.h b/source/common/http/codec_client.h index 4fa085d2e4fc..b9cf3482dce5 100644 --- a/source/common/http/codec_client.h +++ b/source/common/http/codec_client.h @@ -53,7 +53,7 @@ class CodecClient : Logger::Loggable, */ enum class Type { HTTP1, HTTP2 }; - ~CodecClient(); + ~CodecClient() override; /** * Add a connection callback to the underlying network connection. diff --git a/source/common/http/conn_manager_impl.cc b/source/common/http/conn_manager_impl.cc index cf3e4f90ded6..398abbf306d3 100644 --- a/source/common/http/conn_manager_impl.cc +++ b/source/common/http/conn_manager_impl.cc @@ -33,6 +33,7 @@ #include "common/http/path_utility.h" #include "common/http/utility.h" #include "common/network/utility.h" +#include "common/runtime/runtime_impl.h" #include "absl/strings/escaping.h" #include "absl/strings/match.h" @@ -857,7 +858,6 @@ void ConnectionManagerImpl::ActiveStream::decodeHeaders(ActiveStreamDecoderFilte static_cast((*entry).get()), static_cast(status)); const bool new_metadata_added = processNewlyAddedMetadata(); - // If end_stream is set in headers, and a filter adds new metadata, we need to delay end_stream // in headers by inserting an empty data frame with end_stream set. The empty data frame is sent // after the new metadata. @@ -1767,16 +1767,8 @@ void ConnectionManagerImpl::ActiveStreamFilterBase::commonContinue() { doMetadata(); - // Make sure we handle filters returning StopIterationNoBuffer and then commonContinue by flushing - // the terminal fin. - const bool end_stream_with_data = complete() && !trailers(); - if (bufferedData() || end_stream_with_data) { - if (end_stream_with_data && !bufferedData()) { - // In the StopIterationNoBuffer case the ConnectionManagerImpl will not have created a - // buffer but encode/decodeData expects the buffer to exist, so create one. - bufferedData() = createBuffer(); - } - doData(end_stream_with_data); + if (bufferedData()) { + doData(complete() && !trailers()); } if (trailers()) { @@ -1866,6 +1858,12 @@ bool ConnectionManagerImpl::ActiveStreamFilterBase::commonHandleAfterDataCallbac status == FilterDataStatus::StopIterationAndWatermark) { buffer_was_streaming = status == FilterDataStatus::StopIterationAndWatermark; commonHandleBufferData(provided_data); + } else if (complete() && !trailers() && !bufferedData()) { + // If this filter is doing StopIterationNoBuffer and this stream is terminated with a zero + // byte data frame, we need to create an empty buffer to make sure that when commonContinue + // is called, the pipeline resumes with an empty data frame with end_stream = true + ASSERT(end_stream_); + bufferedData() = createBuffer(); } return false; diff --git a/source/common/http/conn_manager_impl.h b/source/common/http/conn_manager_impl.h index 0a7139a40f12..a72dab9069cd 100644 --- a/source/common/http/conn_manager_impl.h +++ b/source/common/http/conn_manager_impl.h @@ -144,6 +144,7 @@ class ConnectionManagerImpl : Logger::Loggable, StreamInfo::StreamInfo& streamInfo() override; Tracing::Span& activeSpan() override; Tracing::Config& tracingConfig() override; + const ScopeTrackedObject& scope() override { return parent_; } // Functions to set or get iteration state. bool canIterate() { return iteration_state_ == IterationState::Continue; } diff --git a/source/common/http/conn_pool_base.cc b/source/common/http/conn_pool_base.cc index fbc930ff4083..1cec3f6a74dc 100644 --- a/source/common/http/conn_pool_base.cc +++ b/source/common/http/conn_pool_base.cc @@ -28,10 +28,10 @@ void ConnPoolImplBase::purgePendingRequests( absl::string_view failure_reason) { // NOTE: We move the existing pending requests to a temporary list. This is done so that // if retry logic submits a new request to the pool, we don't fail it inline. - std::list pending_requests_to_purge(std::move(pending_requests_)); - while (!pending_requests_to_purge.empty()) { + pending_requests_to_purge_ = std::move(pending_requests_); + while (!pending_requests_to_purge_.empty()) { PendingRequestPtr request = - pending_requests_to_purge.front()->removeFromList(pending_requests_to_purge); + pending_requests_to_purge_.front()->removeFromList(pending_requests_to_purge_); host_->cluster().stats().upstream_rq_pending_failure_eject_.inc(); request->callbacks_.onPoolFailure(ConnectionPool::PoolFailureReason::ConnectionFailure, failure_reason, host_description); @@ -40,7 +40,16 @@ void ConnPoolImplBase::purgePendingRequests( void ConnPoolImplBase::onPendingRequestCancel(PendingRequest& request) { ENVOY_LOG(debug, "cancelling pending request"); - request.removeFromList(pending_requests_); + if (!pending_requests_to_purge_.empty()) { + // If pending_requests_to_purge_ is not empty, it means that we are called from + // with-in a onPoolFailure callback invoked in purgePendingRequests (i.e. purgePendingRequests + // is down in the call stack). Remove this request from the list as it is cancelled, + // and there is no need to call its onPoolFailure callback. + request.removeFromList(pending_requests_to_purge_); + } else { + request.removeFromList(pending_requests_); + } + host_->cluster().stats().upstream_rq_cancelled_.inc(); checkForDrained(); } diff --git a/source/common/http/conn_pool_base.h b/source/common/http/conn_pool_base.h index ab4ea2de8255..0910cadea1a5 100644 --- a/source/common/http/conn_pool_base.h +++ b/source/common/http/conn_pool_base.h @@ -48,6 +48,9 @@ class ConnPoolImplBase : protected Logger::Loggable { const Upstream::HostConstSharedPtr host_; const Upstream::ResourcePriority priority_; std::list pending_requests_; + // When calling purgePendingRequests, this list will be used to hold the requests we are about + // to purge. We need this if one cancelled requests cancels a different pending request + std::list pending_requests_to_purge_; }; } // namespace Http } // namespace Envoy diff --git a/source/common/http/header_utility.cc b/source/common/http/header_utility.cc index 396fdb624f17..b6af8ab75f00 100644 --- a/source/common/http/header_utility.cc +++ b/source/common/http/header_utility.cc @@ -6,6 +6,7 @@ #include "common/protobuf/utility.h" #include "absl/strings/match.h" +#include "nghttp2/nghttp2.h" namespace Envoy { namespace Http { @@ -64,6 +65,22 @@ HeaderUtility::HeaderData::HeaderData(const Json::Object& config) return header_matcher; }()) {} +void HeaderUtility::getAllOfHeader(const Http::HeaderMap& headers, absl::string_view key, + std::vector& out) { + auto args = std::make_pair(LowerCaseString(std::string(key)), &out); + + headers.iterate( + [](const HeaderEntry& header, void* context) -> Envoy::Http::HeaderMap::Iterate { + auto key_ret = + static_cast*>*>(context); + if (header.key() == key_ret->first.get().c_str()) { + key_ret->second->emplace_back(header.value().getStringView()); + } + return Envoy::Http::HeaderMap::Iterate::Continue; + }, + &args); +} + bool HeaderUtility::matchHeaders(const Http::HeaderMap& request_headers, const std::vector& config_headers) { // No headers to match is considered a match. @@ -117,6 +134,11 @@ bool HeaderUtility::matchHeaders(const Http::HeaderMap& request_headers, return match != header_data.invert_match_; } +bool HeaderUtility::headerIsValid(const absl::string_view header_value) { + return (nghttp2_check_header_value(reinterpret_cast(header_value.data()), + header_value.size()) != 0); +} + void HeaderUtility::addHeaders(Http::HeaderMap& headers, const Http::HeaderMap& headers_to_add) { headers_to_add.iterate( [](const Http::HeaderEntry& header, void* context) -> Http::HeaderMap::Iterate { diff --git a/source/common/http/header_utility.h b/source/common/http/header_utility.h index 1e328691bf4c..7d3e13853059 100644 --- a/source/common/http/header_utility.h +++ b/source/common/http/header_utility.h @@ -18,6 +18,17 @@ class HeaderUtility { public: enum class HeaderMatchType { Value, Regex, Range, Present, Prefix, Suffix }; + /* Get all instances of the header key specified, and return the values in the vector provided. + * + * This should not be used for inline headers, as it turns a constant time lookup into O(n). + * + * @param headers the headers to return keys from + * @param key the header key to return values for + * @param out the vector to return values in + */ + static void getAllOfHeader(const Http::HeaderMap& headers, absl::string_view key, + std::vector& out); + // A HeaderData specifies one of exact value or regex or range element // to match in a request's header, specified in the header_match_type_ member. // It is the runtime equivalent of the HeaderMatchSpecifier proto in RDS API. @@ -45,6 +56,13 @@ class HeaderUtility { static bool matchHeaders(const Http::HeaderMap& request_headers, const HeaderData& config_header); + /** + * Validates that a header value is valid, according to RFC 7230, section 3.2. + * http://tools.ietf.org/html/rfc7230#section-3.2 + * @return bool true if the header values are valid, according to the aforementioned RFC. + */ + static bool headerIsValid(const absl::string_view header_value); + /** * Add headers from one HeaderMap to another * @param headers target where headers will be added diff --git a/source/common/http/headers.h b/source/common/http/headers.h index f5a458ff04d6..b711fb4b142a 100644 --- a/source/common/http/headers.h +++ b/source/common/http/headers.h @@ -204,6 +204,7 @@ class HeaderValues { const std::string RefusedStream{"refused-stream"}; const std::string Retriable4xx{"retriable-4xx"}; const std::string RetriableStatusCodes{"retriable-status-codes"}; + const std::string Reset{"reset"}; } EnvoyRetryOnValues; struct { diff --git a/source/common/http/http1/BUILD b/source/common/http/http1/BUILD index edd4dff03073..98ddb6edb484 100644 --- a/source/common/http/http1/BUILD +++ b/source/common/http/http1/BUILD @@ -27,8 +27,10 @@ envoy_cc_library( "//source/common/http:codes_lib", "//source/common/http:exception_lib", "//source/common/http:header_map_lib", + "//source/common/http:header_utility_lib", "//source/common/http:headers_lib", "//source/common/http:utility_lib", + "//source/common/runtime:runtime_lib", ], ) @@ -55,6 +57,7 @@ envoy_cc_library( "//source/common/http:conn_pool_base_lib", "//source/common/http:headers_lib", "//source/common/network:utility_lib", + "//source/common/runtime:runtime_lib", "//source/common/upstream:upstream_lib", ], ) diff --git a/source/common/http/http1/codec_impl.cc b/source/common/http/http1/codec_impl.cc index edab3707018e..255de29a6a1e 100644 --- a/source/common/http/http1/codec_impl.cc +++ b/source/common/http/http1/codec_impl.cc @@ -13,8 +13,10 @@ #include "common/common/stack_array.h" #include "common/common/utility.h" #include "common/http/exception.h" +#include "common/http/header_utility.h" #include "common/http/headers.h" #include "common/http/utility.h" +#include "common/runtime/runtime_impl.h" namespace Envoy { namespace Http { @@ -323,7 +325,8 @@ ConnectionImpl::ConnectionImpl(Network::Connection& connection, http_parser_type uint32_t max_headers_kb) : connection_(connection), output_buffer_([&]() -> void { this->onBelowLowWatermark(); }, [&]() -> void { this->onAboveHighWatermark(); }), - max_headers_kb_(max_headers_kb) { + max_headers_kb_(max_headers_kb), strict_header_validation_(Runtime::runtimeFeatureEnabled( + "envoy.reloadable_features.strict_header_validation")) { output_buffer_.setWatermarks(connection.bufferLimit()); http_parser_init(&parser_, type); parser_.data = this; @@ -421,11 +424,21 @@ void ConnectionImpl::onHeaderValue(const char* data, size_t length) { // Ignore trailers. return; } - // http-parser should filter for this - // (https://tools.ietf.org/html/rfc7230#section-3.2.6), but it doesn't today. HeaderStrings - // have an invariant that they must not contain embedded zero characters - // (NUL, ASCII 0x0). - if (absl::string_view(data, length).find('\0') != absl::string_view::npos) { + + const absl::string_view header_value = absl::string_view(data, length); + + if (strict_header_validation_) { + if (!Http::HeaderUtility::headerIsValid(header_value)) { + ENVOY_CONN_LOG(debug, "invalid header value: {}", connection_, header_value); + error_code_ = Http::Code::BadRequest; + sendProtocolError(); + throw CodecProtocolException("http/1.1 protocol error: header value contains invalid chars"); + } + } else if (header_value.find('\0') != absl::string_view::npos) { + // http-parser should filter for this + // (https://tools.ietf.org/html/rfc7230#section-3.2.6), but it doesn't today. HeaderStrings + // have an invariant that they must not contain embedded zero characters + // (NUL, ASCII 0x0). throw CodecProtocolException("http/1.1 protocol error: header value contains NUL"); } diff --git a/source/common/http/http1/codec_impl.h b/source/common/http/http1/codec_impl.h index 27b80e5e5b81..c1a9fa5d7e93 100644 --- a/source/common/http/http1/codec_impl.h +++ b/source/common/http/http1/codec_impl.h @@ -282,6 +282,8 @@ class ConnectionImpl : public virtual Connection, protected Logger::Loggable { */ bool onMetadataFrameComplete(bool end_metadata); - /** - * @return payload_. - */ - Buffer::OwnedImpl& payload() { return payload_; } - - MetadataMap& getMetadataMap() { return *metadata_map_; } - private: friend class MetadataEncoderDecoderTest_VerifyEncoderDecoderOnMultipleMetadataMaps_Test; friend class MetadataEncoderDecoderTest_VerifyEncoderDecoderMultipleMetadataReachSizeLimit_Test; diff --git a/source/common/json/BUILD b/source/common/json/BUILD index 2fdeb38e270f..b21eab655757 100644 --- a/source/common/json/BUILD +++ b/source/common/json/BUILD @@ -30,9 +30,3 @@ envoy_cc_library( "//source/common/common:utility_lib", ], ) - -envoy_cc_library( - name = "json_validator_lib", - hdrs = ["json_validator.h"], - deps = ["//include/envoy/json:json_object_interface"], -) diff --git a/source/common/json/json_validator.h b/source/common/json/json_validator.h deleted file mode 100644 index b906eb23b3cd..000000000000 --- a/source/common/json/json_validator.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - -#include "envoy/json/json_object.h" - -namespace Envoy { -namespace Json { - -/** - * Base class to inherit from to validate config schema before initializing member variables. - */ -class Validator { -public: - Validator(const Json::Object& config, const std::string& schema) { - config.validateSchema(schema); - } -}; - -} // namespace Json -} // namespace Envoy diff --git a/source/common/memory/BUILD b/source/common/memory/BUILD index 2b22e25f9f28..83a46fa4fcc2 100644 --- a/source/common/memory/BUILD +++ b/source/common/memory/BUILD @@ -34,5 +34,6 @@ envoy_cc_library( "//include/envoy/event:dispatcher_interface", "//include/envoy/server:overload_manager_interface", "//include/envoy/stats:stats_interface", + "//source/common/stats:symbol_table_lib", ], ) diff --git a/source/common/memory/heap_shrinker.cc b/source/common/memory/heap_shrinker.cc index 2582cfe76c84..da0413bbfce3 100644 --- a/source/common/memory/heap_shrinker.cc +++ b/source/common/memory/heap_shrinker.cc @@ -1,6 +1,7 @@ #include "common/memory/heap_shrinker.h" #include "common/memory/utils.h" +#include "common/stats/symbol_table_impl.h" #include "absl/strings/str_cat.h" @@ -18,7 +19,9 @@ HeapShrinker::HeapShrinker(Event::Dispatcher& dispatcher, Server::OverloadManage [this](Server::OverloadActionState state) { active_ = (state == Server::OverloadActionState::Active); })) { - shrink_counter_ = &stats.counter(absl::StrCat("overload.", action_name, ".shrink_count")); + Envoy::Stats::StatNameManagedStorage stat_name( + absl::StrCat("overload.", action_name, ".shrink_count"), stats.symbolTable()); + shrink_counter_ = &stats.counterFromStatName(stat_name.statName()); timer_ = dispatcher.createTimer([this] { shrinkHeap(); timer_->enableTimer(kTimerInterval); diff --git a/source/common/network/address_impl.h b/source/common/network/address_impl.h index 2c0b0112edfd..63e0566ffaaa 100644 --- a/source/common/network/address_impl.h +++ b/source/common/network/address_impl.h @@ -56,6 +56,7 @@ class InstanceBase : public Instance { public: // Network::Address::Instance const std::string& asString() const override { return friendly_name_; } + absl::string_view asStringView() const override { return friendly_name_; } // Default logical name is the human-readable name. const std::string& logicalName() const override { return asString(); } Type type() const override { return type_; } diff --git a/source/common/network/cidr_range.cc b/source/common/network/cidr_range.cc index e8ee2c7d6537..50b33dccbd64 100644 --- a/source/common/network/cidr_range.cc +++ b/source/common/network/cidr_range.cc @@ -34,13 +34,9 @@ CidrRange::CidrRange(InstanceConstSharedPtr address, int length) } } -CidrRange::CidrRange(const CidrRange& other) : address_(other.address_), length_(other.length_) {} +CidrRange::CidrRange(const CidrRange& other) = default; -CidrRange& CidrRange::operator=(const CidrRange& other) { - address_ = other.address_; - length_ = other.length_; - return *this; -} +CidrRange& CidrRange::operator=(const CidrRange& other) = default; bool CidrRange::operator==(const CidrRange& other) const { // Lengths must be the same, and must be valid (i.e. not -1). diff --git a/source/common/network/io_socket_error_impl.h b/source/common/network/io_socket_error_impl.h index a28e5c841eec..aa8f362dc8ca 100644 --- a/source/common/network/io_socket_error_impl.h +++ b/source/common/network/io_socket_error_impl.h @@ -11,7 +11,7 @@ class IoSocketError : public Api::IoError { public: explicit IoSocketError(int sys_errno) : errno_(sys_errno) {} - ~IoSocketError() override {} + ~IoSocketError() override = default; Api::IoError::IoErrorCode getErrorCode() const override; std::string getErrorDetails() const override; diff --git a/source/common/network/io_socket_handle_impl.cc b/source/common/network/io_socket_handle_impl.cc index f2442973bd11..cce957655380 100644 --- a/source/common/network/io_socket_handle_impl.cc +++ b/source/common/network/io_socket_handle_impl.cc @@ -1,7 +1,6 @@ #include "common/network/io_socket_handle_impl.h" -#include - +#include #include #include "envoy/buffer/buffer.h" diff --git a/source/common/network/listen_socket_impl.h b/source/common/network/listen_socket_impl.h index 5ff5a35267ab..1ef7d60d8b40 100644 --- a/source/common/network/listen_socket_impl.h +++ b/source/common/network/listen_socket_impl.h @@ -16,7 +16,7 @@ namespace Network { class SocketImpl : public virtual Socket { public: - ~SocketImpl() { close(); } + ~SocketImpl() override { close(); } // Network::Socket const Address::InstanceConstSharedPtr& localAddress() const override { return local_address_; } diff --git a/source/common/protobuf/utility.h b/source/common/protobuf/utility.h index 5adba55f0f66..a05587338e26 100644 --- a/source/common/protobuf/utility.h +++ b/source/common/protobuf/utility.h @@ -32,6 +32,10 @@ ((message).has_##field_name() ? DurationUtil::durationToMilliseconds((message).field_name()) \ : (default_value)) +// Obtain the string value if the field is set. Otherwise, return the default value. +#define PROTOBUF_GET_STRING_OR_DEFAULT(message, field_name, default_value) \ + (!(message).field_name().empty() ? (message).field_name() : (default_value)) + // Obtain the milliseconds value of a google.protobuf.Duration field if set. Otherwise, return // absl::nullopt. #define PROTOBUF_GET_OPTIONAL_MS(message, field_name) \ @@ -374,7 +378,7 @@ class ValueUtil { class HashedValue { public: HashedValue(const ProtobufWkt::Value& value) : value_(value), hash_(ValueUtil::hash(value)){}; - HashedValue(const HashedValue& v) : value_(v.value_), hash_(v.hash_){}; + HashedValue(const HashedValue& v) = default; const ProtobufWkt::Value& value() const { return value_; } std::size_t hash() const { return hash_; } diff --git a/source/common/router/BUILD b/source/common/router/BUILD index b08e7c763fbb..31d354477d5e 100644 --- a/source/common/router/BUILD +++ b/source/common/router/BUILD @@ -241,6 +241,7 @@ envoy_cc_library( "//source/common/common:hex_lib", "//source/common/common:linked_object", "//source/common/common:minimal_logger_lib", + "//source/common/common:scope_tracker", "//source/common/common:utility_lib", "//source/common/grpc:common_lib", "//source/common/http:codes_lib", diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index dc11c7bde57b..a589af954269 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -146,21 +146,19 @@ Upstream::RetryPrioritySharedPtr RetryPolicyImpl::retryPriority() const { CorsPolicyImpl::CorsPolicyImpl(const envoy::api::v2::route::CorsPolicy& config, Runtime::Loader& loader) - : config_(config), loader_(loader) { + : config_(config), loader_(loader), allow_methods_(config.allow_methods()), + allow_headers_(config.allow_headers()), expose_headers_(config.expose_headers()), + max_age_(config.max_age()), + legacy_enabled_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, enabled, true)) { for (const auto& origin : config.allow_origin()) { allow_origin_.push_back(origin); } for (const auto& regex : config.allow_origin_regex()) { allow_origin_regex_.push_back(RegexUtil::parseRegex(regex)); } - allow_methods_ = config.allow_methods(); - allow_headers_ = config.allow_headers(); - expose_headers_ = config.expose_headers(); - max_age_ = config.max_age(); if (config.has_allow_credentials()) { allow_credentials_ = PROTOBUF_GET_WRAPPED_REQUIRED(config, allow_credentials); } - legacy_enabled_ = PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, enabled, true); } ShadowPolicyImpl::ShadowPolicyImpl(const envoy::api::v2::route::RouteAction& config) { @@ -181,7 +179,7 @@ ShadowPolicyImpl::ShadowPolicyImpl(const envoy::api::v2::route::RouteAction& con class HashMethodImplBase : public HashPolicyImpl::HashMethod { public: - HashMethodImplBase(bool terminal) : terminal_(terminal) {} + explicit HashMethodImplBase(bool terminal) : terminal_(terminal) {} bool terminal() const override { return terminal_; } @@ -428,8 +426,8 @@ RouteEntryImplBase::RouteEntryImplBase(const VirtualHostImpl& vhost, const std::string& runtime_key_prefix = route.route().weighted_clusters().runtime_key_prefix(); for (const auto& cluster : route.route().weighted_clusters().clusters()) { - std::unique_ptr cluster_entry(new WeightedClusterEntry( - this, runtime_key_prefix + "." + cluster.name(), factory_context, cluster)); + auto cluster_entry = std::make_unique( + this, runtime_key_prefix + "." + cluster.name(), factory_context, cluster); weighted_clusters_.emplace_back(std::move(cluster_entry)); total_weight += weighted_clusters_.back()->clusterWeight(); } diff --git a/source/common/router/config_impl.h b/source/common/router/config_impl.h index 8ec35a02330c..22ed8ae088a6 100644 --- a/source/common/router/config_impl.h +++ b/source/common/router/config_impl.h @@ -133,12 +133,12 @@ class CorsPolicyImpl : public CorsPolicy { Runtime::Loader& loader_; std::list allow_origin_; std::list allow_origin_regex_; - std::string allow_methods_; - std::string allow_headers_; - std::string expose_headers_; - std::string max_age_{}; + const std::string allow_methods_; + const std::string allow_headers_; + const std::string expose_headers_; + const std::string max_age_; absl::optional allow_credentials_{}; - bool legacy_enabled_; + const bool legacy_enabled_; }; class ConfigImpl; @@ -228,7 +228,7 @@ class RetryPolicyImpl : public RetryPolicy { public: RetryPolicyImpl(const envoy::api::v2::route::RetryPolicy& retry_policy, ProtobufMessage::ValidationVisitor& validation_visitor); - RetryPolicyImpl() {} + RetryPolicyImpl() = default; // Router::RetryPolicy std::chrono::milliseconds perTryTimeout() const override { return per_try_timeout_; } @@ -265,7 +265,7 @@ class RetryPolicyImpl : public RetryPolicy { */ class ShadowPolicyImpl : public ShadowPolicy { public: - ShadowPolicyImpl(const envoy::api::v2::route::RouteAction& config); + explicit ShadowPolicyImpl(const envoy::api::v2::route::RouteAction& config); // Router::ShadowPolicy const std::string& cluster() const override { return cluster_; } @@ -284,8 +284,9 @@ class ShadowPolicyImpl : public ShadowPolicy { */ class HashPolicyImpl : public HashPolicy { public: - HashPolicyImpl(const Protobuf::RepeatedPtrField& - hash_policy); + explicit HashPolicyImpl( + const Protobuf::RepeatedPtrField& + hash_policy); // Router::HashPolicy absl::optional generateHash(const Network::Address::Instance* downstream_addr, @@ -336,7 +337,7 @@ class HedgePolicyImpl : public HedgePolicy { */ class DecoratorImpl : public Decorator { public: - DecoratorImpl(const envoy::api::v2::route::Decorator& decorator); + explicit DecoratorImpl(const envoy::api::v2::route::Decorator& decorator); // Decorator::apply void apply(Tracing::Span& span) const override; @@ -353,7 +354,7 @@ class DecoratorImpl : public Decorator { */ class RouteTracingImpl : public RouteTracing { public: - RouteTracingImpl(const envoy::api::v2::route::Tracing& tracing); + explicit RouteTracingImpl(const envoy::api::v2::route::Tracing& tracing); // Tracing::getClientSampling const envoy::type::FractionalPercent& getClientSampling() const override; diff --git a/source/common/router/config_utility.h b/source/common/router/config_utility.h index adfb1e9d2818..4a753964059f 100644 --- a/source/common/router/config_utility.h +++ b/source/common/router/config_utility.h @@ -1,7 +1,6 @@ #pragma once -#include - +#include #include #include #include diff --git a/source/common/router/header_parser.cc b/source/common/router/header_parser.cc index 05022605347c..e5d71aa9ef1f 100644 --- a/source/common/router/header_parser.cc +++ b/source/common/router/header_parser.cc @@ -1,7 +1,6 @@ #include "common/router/header_parser.h" -#include - +#include #include #include diff --git a/source/common/router/header_parser.h b/source/common/router/header_parser.h index b64ebd169c4b..725f78a5e97c 100644 --- a/source/common/router/header_parser.h +++ b/source/common/router/header_parser.h @@ -42,7 +42,7 @@ class HeaderParser { void evaluateHeaders(Http::HeaderMap& headers, const StreamInfo::StreamInfo& stream_info) const; protected: - HeaderParser() {} + HeaderParser() = default; private: std::vector> headers_to_add_; diff --git a/source/common/router/rds_impl.h b/source/common/router/rds_impl.h index ee311b63a163..1b627cab2711 100644 --- a/source/common/router/rds_impl.h +++ b/source/common/router/rds_impl.h @@ -57,7 +57,7 @@ class StaticRouteConfigProviderImpl : public RouteConfigProvider { StaticRouteConfigProviderImpl(const envoy::api::v2::RouteConfiguration& config, Server::Configuration::FactoryContext& factory_context, RouteConfigProviderManagerImpl& route_config_provider_manager); - ~StaticRouteConfigProviderImpl(); + ~StaticRouteConfigProviderImpl() override; // Router::RouteConfigProvider Router::ConfigConstSharedPtr config() override { return config_; } diff --git a/source/common/router/retry_state_impl.cc b/source/common/router/retry_state_impl.cc index c09f485a1c7a..e7674bd9ba93 100644 --- a/source/common/router/retry_state_impl.cc +++ b/source/common/router/retry_state_impl.cc @@ -22,6 +22,7 @@ const uint32_t RetryPolicy::RETRY_ON_GATEWAY_ERROR; const uint32_t RetryPolicy::RETRY_ON_CONNECT_FAILURE; const uint32_t RetryPolicy::RETRY_ON_RETRIABLE_4XX; const uint32_t RetryPolicy::RETRY_ON_RETRIABLE_STATUS_CODES; +const uint32_t RetryPolicy::RETRY_ON_RESET; const uint32_t RetryPolicy::RETRY_ON_GRPC_CANCELLED; const uint32_t RetryPolicy::RETRY_ON_GRPC_DEADLINE_EXCEEDED; const uint32_t RetryPolicy::RETRY_ON_GRPC_RESOURCE_EXHAUSTED; @@ -130,6 +131,8 @@ std::pair RetryStateImpl::parseRetryOn(absl::string_view config) ret |= RetryPolicy::RETRY_ON_REFUSED_STREAM; } else if (retry_on == Http::Headers::get().EnvoyRetryOnValues.RetriableStatusCodes) { ret |= RetryPolicy::RETRY_ON_RETRIABLE_STATUS_CODES; + } else if (retry_on == Http::Headers::get().EnvoyRetryOnValues.Reset) { + ret |= RetryPolicy::RETRY_ON_RESET; } else { all_fields_valid = false; } @@ -293,10 +296,13 @@ bool RetryStateImpl::wouldRetryFromReset(const Http::StreamResetReason reset_rea return false; } + if (retry_on_ & RetryPolicy::RETRY_ON_RESET) { + return true; + } + if (retry_on_ & (RetryPolicy::RETRY_ON_5XX | RetryPolicy::RETRY_ON_GATEWAY_ERROR)) { // Currently we count an upstream reset as a "5xx" (since it will result in - // one). We may eventually split this out into its own type. I.e., - // RETRY_ON_RESET. + // one). With RETRY_ON_RESET we may eventually remove these policies. return true; } diff --git a/source/common/router/retry_state_impl.h b/source/common/router/retry_state_impl.h index 7177a3f2909f..fdc7f0d79396 100644 --- a/source/common/router/retry_state_impl.h +++ b/source/common/router/retry_state_impl.h @@ -27,7 +27,7 @@ class RetryStateImpl : public RetryState { const Upstream::ClusterInfo& cluster, Runtime::Loader& runtime, Runtime::RandomGenerator& random, Event::Dispatcher& dispatcher, Upstream::ResourcePriority priority); - ~RetryStateImpl(); + ~RetryStateImpl() override; /** * Returns the RetryPolicy extracted from the x-envoy-retry-on header. diff --git a/source/common/router/router.cc b/source/common/router/router.cc index d01fae5bf5a7..5ad636479afc 100644 --- a/source/common/router/router.cc +++ b/source/common/router/router.cc @@ -16,6 +16,7 @@ #include "common/common/assert.h" #include "common/common/empty_string.h" #include "common/common/enum_to_int.h" +#include "common/common/scope_tracker.h" #include "common/common/utility.h" #include "common/grpc/common.h" #include "common/http/codes.h" @@ -1216,6 +1217,7 @@ bool Filter::setupRetry() { // this filter which will make this a non-issue. The implementation of supporting retry in cases // where the request is not complete is more complicated so we will start with this for now. if (!downstream_end_stream_) { + config_.stats_.rq_retry_skipped_request_not_complete_.inc(); return false; } pending_retries_++; @@ -1339,11 +1341,15 @@ Filter::UpstreamRequest::~UpstreamRequest() { } void Filter::UpstreamRequest::decode100ContinueHeaders(Http::HeaderMapPtr&& headers) { + ScopeTrackerScopeState scope(&parent_.callbacks_->scope(), parent_.callbacks_->dispatcher()); + ASSERT(100 == Http::Utility::getResponseStatus(*headers)); parent_.onUpstream100ContinueHeaders(std::move(headers), *this); } void Filter::UpstreamRequest::decodeHeaders(Http::HeaderMapPtr&& headers, bool end_stream) { + ScopeTrackerScopeState scope(&parent_.callbacks_->scope(), parent_.callbacks_->dispatcher()); + // TODO(rodaine): This is actually measuring after the headers are parsed and not the first byte. upstream_timing_.onFirstUpstreamRxByteReceived(parent_.callbacks_->dispatcher().timeSource()); maybeEndDecode(end_stream); @@ -1358,12 +1364,16 @@ void Filter::UpstreamRequest::decodeHeaders(Http::HeaderMapPtr&& headers, bool e } void Filter::UpstreamRequest::decodeData(Buffer::Instance& data, bool end_stream) { + ScopeTrackerScopeState scope(&parent_.callbacks_->scope(), parent_.callbacks_->dispatcher()); + maybeEndDecode(end_stream); stream_info_.addBytesReceived(data.length()); parent_.onUpstreamData(data, *this, end_stream); } void Filter::UpstreamRequest::decodeTrailers(Http::HeaderMapPtr&& trailers) { + ScopeTrackerScopeState scope(&parent_.callbacks_->scope(), parent_.callbacks_->dispatcher()); + maybeEndDecode(true); if (!parent_.config_.upstream_logs_.empty()) { upstream_trailers_ = std::make_unique(*trailers); @@ -1452,6 +1462,8 @@ void Filter::UpstreamRequest::encodeMetadata(Http::MetadataMapPtr&& metadata_map void Filter::UpstreamRequest::onResetStream(Http::StreamResetReason reason, absl::string_view transport_failure_reason) { + ScopeTrackerScopeState scope(&parent_.callbacks_->scope(), parent_.callbacks_->dispatcher()); + clearRequestEncoder(); awaiting_headers_ = false; if (!calling_encode_headers_) { diff --git a/source/common/router/router.h b/source/common/router/router.h index 2767db0a2921..fac9bbb07ee0 100644 --- a/source/common/router/router.h +++ b/source/common/router/router.h @@ -43,7 +43,8 @@ namespace Router { COUNTER(rq_redirect) \ COUNTER(rq_direct_response) \ COUNTER(rq_total) \ - COUNTER(rq_reset_after_downstream_response_started) + COUNTER(rq_reset_after_downstream_response_started) \ + COUNTER(rq_retry_skipped_request_not_complete) // clang-format on /** @@ -234,7 +235,7 @@ class Filter : Logger::Loggable, downstream_end_stream_(false), do_shadowing_(false), is_retry_(false), attempting_internal_redirect_with_complete_stream_(false) {} - ~Filter(); + ~Filter() override; // Http::StreamFilterBase void onDestroy() override; @@ -357,7 +358,7 @@ class Filter : Logger::Loggable, public Http::ConnectionPool::Callbacks, public LinkedObject { UpstreamRequest(Filter& parent, Http::ConnectionPool::Instance& pool); - ~UpstreamRequest(); + ~UpstreamRequest() override; void encodeHeaders(bool end_stream); void encodeData(Buffer::Instance& data, bool end_stream); diff --git a/source/common/runtime/runtime_features.cc b/source/common/runtime/runtime_features.cc index bb1800a1b198..0b7c7fea2025 100644 --- a/source/common/runtime/runtime_features.cc +++ b/source/common/runtime/runtime_features.cc @@ -42,11 +42,19 @@ constexpr const char* disallowed_features[] = { // Acts as both a test entry for deprecated.proto and a marker for the Envoy // deprecation scripts. "envoy.deprecated_features.deprecated.proto:is_deprecated_fatal", + // 1.10.0 "envoy.deprecated_features.config_source.proto:UNSUPPORTED_REST_LEGACY", "envoy.deprecated_features.ext_authz.proto:use_alpha", - "envoy.deprecated_features.route.proto:enabled", "envoy.deprecated_features.fault.proto:type", + "envoy.deprecated_features.route.proto:enabled", "envoy.deprecated_features.route.proto:runtime_key", + // 1.11.0 + "envoy.deprecated_features.bootstrap.proto:runtime", + "envoy.deprecated_features.redis_proxy.proto:catch_all_cluster", + "envoy.deprecated_features.redis_proxy.proto:cluster", + "envoy.deprecated_features.server_info.proto:max_obj_name_len", + "envoy.deprecated_features.server_info.proto:max_stats", + "envoy.deprecated_features.v1_filter_json_config", }; RuntimeFeatures::RuntimeFeatures() { diff --git a/source/common/runtime/runtime_impl.cc b/source/common/runtime/runtime_impl.cc index a1369e6ab141..6ed82c39a37d 100644 --- a/source/common/runtime/runtime_impl.cc +++ b/source/common/runtime/runtime_impl.cc @@ -27,7 +27,8 @@ namespace Runtime { bool runtimeFeatureEnabled(absl::string_view feature) { ASSERT(absl::StartsWith(feature, "envoy.reloadable_features")); if (Runtime::LoaderSingleton::getExisting()) { - return Runtime::LoaderSingleton::getExisting()->snapshot().runtimeFeatureEnabled(feature); + return Runtime::LoaderSingleton::getExisting()->threadsafeSnapshot()->runtimeFeatureEnabled( + feature); } ENVOY_LOG_TO_LOGGER(Envoy::Logger::Registry::getLog(Envoy::Logger::Id::runtime), warn, "Unable to use runtime singleton for feature {}", feature); @@ -551,13 +552,32 @@ void RtdsSubscription::validateUpdateSize(uint32_t num_resources) { } void LoaderImpl::loadNewSnapshot() { - ThreadLocal::ThreadLocalObjectSharedPtr ptr = createNewSnapshot(); - tls_->set([ptr = std::move(ptr)](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { - return ptr; + std::shared_ptr ptr = createNewSnapshot(); + tls_->set([ptr](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { + return std::static_pointer_cast(ptr); }); + + { + absl::MutexLock lock(&snapshot_mutex_); + thread_safe_snapshot_ = ptr; + } +} + +const Snapshot& LoaderImpl::snapshot() { + ASSERT(tls_->currentThreadRegistered(), "snapshot can only be called from a worker thread"); + return tls_->getTyped(); } -Snapshot& LoaderImpl::snapshot() { return tls_->getTyped(); } +std::shared_ptr LoaderImpl::threadsafeSnapshot() { + if (tls_->currentThreadRegistered()) { + return std::dynamic_pointer_cast(tls_->get()); + } + + { + absl::ReaderMutexLock lock(&snapshot_mutex_); + return thread_safe_snapshot_; + } +} void LoaderImpl::mergeValues(const std::unordered_map& values) { if (admin_layer_ == nullptr) { diff --git a/source/common/runtime/runtime_impl.h b/source/common/runtime/runtime_impl.h index 855dc1ea370e..a41260eca02f 100644 --- a/source/common/runtime/runtime_impl.h +++ b/source/common/runtime/runtime_impl.h @@ -243,7 +243,8 @@ class LoaderImpl : public Loader, Logger::Loggable { // Runtime::Loader void initialize(Upstream::ClusterManager& cm) override; - Snapshot& snapshot() override; + const Snapshot& snapshot() override; + std::shared_ptr threadsafeSnapshot() override; void mergeValues(const std::unordered_map& values) override; private: @@ -265,6 +266,9 @@ class LoaderImpl : public Loader, Logger::Loggable { Api::Api& api_; std::vector subscriptions_; Upstream::ClusterManager* cm_{}; + + absl::Mutex snapshot_mutex_; + std::shared_ptr thread_safe_snapshot_ GUARDED_BY(snapshot_mutex_); }; } // namespace Runtime diff --git a/source/common/secret/BUILD b/source/common/secret/BUILD index ca30d94ddfb3..b584cd57c7da 100644 --- a/source/common/secret/BUILD +++ b/source/common/secret/BUILD @@ -19,6 +19,7 @@ envoy_cc_library( "//include/envoy/server:transport_socket_config_interface", "//source/common/common:assert_lib", "//source/common/common:minimal_logger_lib", + "@envoy_api//envoy/admin/v2alpha:config_dump_cc", "@envoy_api//envoy/api/v2/auth:cert_cc", ], ) diff --git a/source/common/secret/sds_api.cc b/source/common/secret/sds_api.cc index aa4d4442747c..7626433b9a25 100644 --- a/source/common/secret/sds_api.cc +++ b/source/common/secret/sds_api.cc @@ -11,13 +11,15 @@ namespace Envoy { namespace Secret { SdsApi::SdsApi(envoy::api::v2::core::ConfigSource sds_config, absl::string_view sds_config_name, - Config::SubscriptionFactory& subscription_factory, + Config::SubscriptionFactory& subscription_factory, TimeSource& time_source, ProtobufMessage::ValidationVisitor& validation_visitor, Stats::Store& stats, Init::Manager& init_manager, std::function destructor_cb) : init_target_(fmt::format("SdsApi {}", sds_config_name), [this] { initialize(); }), stats_(stats), sds_config_(std::move(sds_config)), sds_config_name_(sds_config_name), secret_hash_(0), clean_up_(std::move(destructor_cb)), validation_visitor_(validation_visitor), - subscription_factory_(subscription_factory) { + subscription_factory_(subscription_factory), + time_source_(time_source), secret_data_{sds_config_name_, "uninitialized", + time_source_.systemTime()} { // TODO(JimmyCYJ): Implement chained_init_manager, so that multiple init_manager // can be chained together to behave as one init_manager. In that way, we let // two listeners which share same SdsApi to register at separate init managers, and @@ -26,7 +28,7 @@ SdsApi::SdsApi(envoy::api::v2::core::ConfigSource sds_config, absl::string_view } void SdsApi::onConfigUpdate(const Protobuf::RepeatedPtrField& resources, - const std::string&) { + const std::string& version_info) { validateUpdateSize(resources.size()); auto secret = MessageUtil::anyConvert(resources[0], validation_visitor_); @@ -44,7 +46,8 @@ void SdsApi::onConfigUpdate(const Protobuf::RepeatedPtrField& setSecret(secret); update_callback_manager_.runCallbacks(); } - + secret_data_.last_updated_ = time_source_.systemTime(); + secret_data_.version_info_ = version_info; init_target_.ready(); } @@ -79,5 +82,7 @@ void SdsApi::initialize() { subscription_->start({sds_config_name_}); } +SdsApi::SecretData SdsApi::secretData() { return secret_data_; } + } // namespace Secret } // namespace Envoy diff --git a/source/common/secret/sds_api.h b/source/common/secret/sds_api.h index e05e3e5c0302..a99fafb6c812 100644 --- a/source/common/secret/sds_api.h +++ b/source/common/secret/sds_api.h @@ -32,11 +32,19 @@ namespace Secret { */ class SdsApi : public Config::SubscriptionCallbacks { public: + struct SecretData { + const std::string resource_name_; + std::string version_info_; + SystemTime last_updated_; + }; + SdsApi(envoy::api::v2::core::ConfigSource sds_config, absl::string_view sds_config_name, - Config::SubscriptionFactory& subscription_factory, + Config::SubscriptionFactory& subscription_factory, TimeSource& time_source, ProtobufMessage::ValidationVisitor& validation_visitor, Stats::Store& stats, Init::Manager& init_manager, std::function destructor_cb); + SecretData secretData(); + protected: // Creates new secrets. virtual void setSecret(const envoy::api::v2::auth::Secret&) PURE; @@ -68,6 +76,8 @@ class SdsApi : public Config::SubscriptionCallbacks { Cleanup clean_up_; ProtobufMessage::ValidationVisitor& validation_visitor_; Config::SubscriptionFactory& subscription_factory_; + TimeSource& time_source_; + SecretData secret_data_; }; class TlsCertificateSdsApi; @@ -90,17 +100,18 @@ class TlsCertificateSdsApi : public SdsApi, public TlsCertificateConfigProvider Config::Utility::checkLocalInfo("TlsCertificateSdsApi", secret_provider_context.localInfo()); return std::make_shared( sds_config, sds_config_name, secret_provider_context.clusterManager().subscriptionFactory(), + secret_provider_context.dispatcher().timeSource(), secret_provider_context.messageValidationVisitor(), secret_provider_context.stats(), *secret_provider_context.initManager(), destructor_cb); } TlsCertificateSdsApi(const envoy::api::v2::core::ConfigSource& sds_config, const std::string& sds_config_name, - Config::SubscriptionFactory& subscription_factory, + Config::SubscriptionFactory& subscription_factory, TimeSource& time_source, ProtobufMessage::ValidationVisitor& validation_visitor, Stats::Store& stats, Init::Manager& init_manager, std::function destructor_cb) - : SdsApi(sds_config, sds_config_name, subscription_factory, validation_visitor, stats, - init_manager, std::move(destructor_cb)) {} + : SdsApi(sds_config, sds_config_name, subscription_factory, time_source, validation_visitor, + stats, init_manager, std::move(destructor_cb)) {} // SecretProvider const envoy::api::v2::auth::TlsCertificate* secret() const override { @@ -138,17 +149,19 @@ class CertificateValidationContextSdsApi : public SdsApi, secret_provider_context.localInfo()); return std::make_shared( sds_config, sds_config_name, secret_provider_context.clusterManager().subscriptionFactory(), + secret_provider_context.dispatcher().timeSource(), secret_provider_context.messageValidationVisitor(), secret_provider_context.stats(), *secret_provider_context.initManager(), destructor_cb); } CertificateValidationContextSdsApi(const envoy::api::v2::core::ConfigSource& sds_config, const std::string& sds_config_name, Config::SubscriptionFactory& subscription_factory, + TimeSource& time_source, ProtobufMessage::ValidationVisitor& validation_visitor, Stats::Store& stats, Init::Manager& init_manager, std::function destructor_cb) - : SdsApi(sds_config, sds_config_name, subscription_factory, validation_visitor, stats, - init_manager, std::move(destructor_cb)) {} + : SdsApi(sds_config, sds_config_name, subscription_factory, time_source, validation_visitor, + stats, init_manager, std::move(destructor_cb)) {} // SecretProvider const envoy::api::v2::auth::CertificateValidationContext* secret() const override { diff --git a/source/common/secret/secret_manager_impl.cc b/source/common/secret/secret_manager_impl.cc index aed0c374255c..411f71ae6d0b 100644 --- a/source/common/secret/secret_manager_impl.cc +++ b/source/common/secret/secret_manager_impl.cc @@ -1,8 +1,10 @@ #include "common/secret/secret_manager_impl.h" +#include "envoy/admin/v2alpha/config_dump.pb.h" #include "envoy/common/exception.h" #include "common/common/assert.h" +#include "common/common/logger.h" #include "common/secret/sds_api.h" #include "common/secret/secret_provider_impl.h" #include "common/ssl/certificate_validation_context_config_impl.h" @@ -11,6 +13,9 @@ namespace Envoy { namespace Secret { +SecretManagerImpl::SecretManagerImpl(Server::ConfigTracker& config_tracker) + : config_tracker_entry_(config_tracker.add("secrets", [this] { return dumpSecretConfigs(); })) { +} void SecretManagerImpl::addStaticSecret(const envoy::api::v2::auth::Secret& secret) { switch (secret.type_case()) { case envoy::api::v2::auth::Secret::TypeCase::kTlsCertificate: { @@ -79,5 +84,99 @@ SecretManagerImpl::findOrCreateCertificateValidationContextProvider( secret_provider_context); } +// We clear private key and password to avoid information leaking. +// TODO(incfly): switch to more generic scrubbing mechanism once +// https://github.com/envoyproxy/envoy/issues/4757 is resolved. +void redactSecret(::envoy::api::v2::auth::Secret* secret) { + if (secret && secret->type_case() == envoy::api::v2::auth::Secret::TypeCase::kTlsCertificate) { + auto tls_certificate = secret->mutable_tls_certificate(); + if (tls_certificate->has_private_key() && tls_certificate->private_key().specifier_case() != + envoy::api::v2::core::DataSource::kFilename) { + tls_certificate->mutable_private_key()->set_inline_string("[redacted]"); + } + if (tls_certificate->has_password() && tls_certificate->password().specifier_case() != + envoy::api::v2::core::DataSource::kFilename) { + tls_certificate->mutable_password()->set_inline_string("[redacted]"); + } + } +} + +ProtobufTypes::MessagePtr SecretManagerImpl::dumpSecretConfigs() { + auto config_dump = std::make_unique(); + // Handle static tls key/cert providers. + for (const auto& cert_iter : static_tls_certificate_providers_) { + const auto& tls_cert = cert_iter.second; + auto static_secret = config_dump->mutable_static_secrets()->Add(); + static_secret->set_name(cert_iter.first); + ASSERT(tls_cert != nullptr); + auto dump_secret = static_secret->mutable_secret(); + dump_secret->set_name(cert_iter.first); + dump_secret->mutable_tls_certificate()->MergeFrom(*tls_cert->secret()); + redactSecret(dump_secret); + } + + // Handle static certificate validation context providers. + for (const auto& context_iter : static_certificate_validation_context_providers_) { + const auto& validation_context = context_iter.second; + auto static_secret = config_dump->mutable_static_secrets()->Add(); + static_secret->set_name(context_iter.first); + ASSERT(validation_context != nullptr); + auto dump_secret = static_secret->mutable_secret(); + dump_secret->set_name(context_iter.first); + dump_secret->mutable_validation_context()->MergeFrom(*validation_context->secret()); + } + + // Handle dynamic tls_certificate providers. + const auto providers = certificate_providers_.allSecretProviders(); + for (const auto& cert_secrets : providers) { + const auto& secret_data = cert_secrets->secretData(); + const auto& tls_cert = cert_secrets->secret(); + ::envoy::admin::v2alpha::SecretsConfigDump_DynamicSecret* dump_secret; + const bool secret_ready = tls_cert != nullptr; + if (secret_ready) { + dump_secret = config_dump->mutable_dynamic_active_secrets()->Add(); + } else { + dump_secret = config_dump->mutable_dynamic_warming_secrets()->Add(); + } + dump_secret->set_name(secret_data.resource_name_); + auto secret = dump_secret->mutable_secret(); + secret->set_name(secret_data.resource_name_); + ProtobufWkt::Timestamp last_updated_ts; + TimestampUtil::systemClockToTimestamp(secret_data.last_updated_, last_updated_ts); + dump_secret->set_version_info(secret_data.version_info_); + *dump_secret->mutable_last_updated() = last_updated_ts; + secret->set_name(secret_data.resource_name_); + if (secret_ready) { + secret->mutable_tls_certificate()->MergeFrom(*tls_cert); + } + redactSecret(secret); + } + + // Handling dynamic cert validation context providers. + const auto context_secret_provider = validation_context_providers_.allSecretProviders(); + for (const auto& validation_context_secret : context_secret_provider) { + const auto& secret_data = validation_context_secret->secretData(); + const auto& validation_context = validation_context_secret->secret(); + ::envoy::admin::v2alpha::SecretsConfigDump_DynamicSecret* dump_secret; + const bool secret_ready = validation_context != nullptr; + if (secret_ready) { + dump_secret = config_dump->mutable_dynamic_active_secrets()->Add(); + } else { + dump_secret = config_dump->mutable_dynamic_warming_secrets()->Add(); + } + dump_secret->set_name(secret_data.resource_name_); + auto secret = dump_secret->mutable_secret(); + secret->set_name(secret_data.resource_name_); + ProtobufWkt::Timestamp last_updated_ts; + TimestampUtil::systemClockToTimestamp(secret_data.last_updated_, last_updated_ts); + dump_secret->set_version_info(secret_data.version_info_); + *dump_secret->mutable_last_updated() = last_updated_ts; + if (secret_ready) { + secret->mutable_validation_context()->MergeFrom(*validation_context); + } + } + return config_dump; +} + } // namespace Secret } // namespace Envoy diff --git a/source/common/secret/secret_manager_impl.h b/source/common/secret/secret_manager_impl.h index aa7ee6e4b215..7e3da018ecc8 100644 --- a/source/common/secret/secret_manager_impl.h +++ b/source/common/secret/secret_manager_impl.h @@ -16,6 +16,7 @@ namespace Secret { class SecretManagerImpl : public SecretManager { public: + SecretManagerImpl(Server::ConfigTracker& config_tracker); void addStaticSecret(const envoy::api::v2::auth::Secret& secret) override; TlsCertificateConfigProviderSharedPtr @@ -42,6 +43,8 @@ class SecretManagerImpl : public SecretManager { Server::Configuration::TransportSocketFactoryContext& secret_provider_context) override; private: + ProtobufTypes::MessagePtr dumpSecretConfigs(); + template class DynamicSecretProviders : public Logger::Loggable { public: @@ -68,6 +71,17 @@ class SecretManagerImpl : public SecretManager { return secret_provider; } + std::vector> allSecretProviders() { + std::vector> providers; + for (const auto& secret_entry : dynamic_secret_providers_) { + std::shared_ptr secret_provider = secret_entry.second.lock(); + if (secret_provider) { + providers.push_back(std::move(secret_provider)); + } + } + return providers; + } + private: // Removes dynamic secret provider which has been deleted. void removeDynamicSecretProvider(const std::string& map_key) { @@ -91,6 +105,8 @@ class SecretManagerImpl : public SecretManager { // map hash code of SDS config source and SdsApi object. DynamicSecretProviders certificate_providers_; DynamicSecretProviders validation_context_providers_; + + Server::ConfigTracker::EntryOwnerPtr config_tracker_entry_; }; } // namespace Secret diff --git a/source/common/signal/signal_action.h b/source/common/signal/signal_action.h index 12fcb1805a7b..afe0690d00fd 100644 --- a/source/common/signal/signal_action.h +++ b/source/common/signal/signal_action.h @@ -1,9 +1,9 @@ #pragma once -#include #include #include +#include #include #include "common/common/non_copyable.h" @@ -53,7 +53,7 @@ class SignalAction : NonCopyable { public: SignalAction() : guard_size_(sysconf(_SC_PAGE_SIZE)), - altstack_size_(std::max(guard_size_ * 4, static_cast(MINSIGSTKSZ))), altstack_() { + altstack_size_(std::max(guard_size_ * 4, static_cast(MINSIGSTKSZ))) { mapAndProtectStackMemory(); installSigHandlers(); } diff --git a/source/common/stats/BUILD b/source/common/stats/BUILD index 16c0174eaab0..cb88ed2dc976 100644 --- a/source/common/stats/BUILD +++ b/source/common/stats/BUILD @@ -9,9 +9,9 @@ load( envoy_package() envoy_cc_library( - name = "heap_stat_data_lib", - srcs = ["heap_stat_data.cc"], - hdrs = ["heap_stat_data.h"], + name = "allocator_lib", + srcs = ["allocator_impl.cc"], + hdrs = ["allocator_impl.h"], deps = [ ":metric_impl_lib", ":stat_merger_lib", @@ -51,7 +51,7 @@ envoy_cc_library( ":stats_lib", ":store_impl_lib", "//include/envoy/stats:stats_macros", - "//source/common/stats:heap_stat_data_lib", + "//source/common/stats:allocator_lib", ], ) @@ -202,7 +202,7 @@ envoy_cc_library( srcs = ["thread_local_store.cc"], hdrs = ["thread_local_store.h"], deps = [ - ":heap_stat_data_lib", + ":allocator_lib", ":null_counter_lib", ":null_gauge_lib", ":scope_prefixer_lib", diff --git a/source/common/stats/heap_stat_data.cc b/source/common/stats/allocator_impl.cc similarity index 86% rename from source/common/stats/heap_stat_data.cc rename to source/common/stats/allocator_impl.cc index 2bb3d7646db8..6fbf0da19a0b 100644 --- a/source/common/stats/heap_stat_data.cc +++ b/source/common/stats/allocator_impl.cc @@ -1,4 +1,4 @@ -#include "common/stats/heap_stat_data.h" +#include "common/stats/allocator_impl.h" #include @@ -20,25 +20,25 @@ namespace Envoy { namespace Stats { -HeapStatDataAllocator::~HeapStatDataAllocator() { +AllocatorImpl::~AllocatorImpl() { ASSERT(counters_.empty()); ASSERT(gauges_.empty()); } -void HeapStatDataAllocator::removeCounterFromSet(Counter* counter) { +void AllocatorImpl::removeCounterFromSet(Counter* counter) { Thread::LockGuard lock(mutex_); const size_t count = counters_.erase(counter->statName()); ASSERT(count == 1); } -void HeapStatDataAllocator::removeGaugeFromSet(Gauge* gauge) { +void AllocatorImpl::removeGaugeFromSet(Gauge* gauge) { Thread::LockGuard lock(mutex_); const size_t count = gauges_.erase(gauge->statName()); ASSERT(count == 1); } #ifndef ENVOY_CONFIG_COVERAGE -void HeapStatDataAllocator::debugPrint() { +void AllocatorImpl::debugPrint() { Thread::LockGuard lock(mutex_); for (Counter* counter : counters_) { ENVOY_LOG_MISC(info, "counter: {}", symbolTable().toString(counter->statName())); @@ -59,7 +59,7 @@ void HeapStatDataAllocator::debugPrint() { // wasted in the alignment padding next to flags_. template class StatsSharedImpl : public MetricImpl { public: - StatsSharedImpl(StatName name, HeapStatDataAllocator& alloc, absl::string_view tag_extracted_name, + StatsSharedImpl(StatName name, AllocatorImpl& alloc, absl::string_view tag_extracted_name, const std::vector& tags) : MetricImpl(name, tag_extracted_name, tags, alloc.symbolTable()), alloc_(alloc) {} @@ -84,7 +84,7 @@ template class StatsSharedImpl : public MetricImpl uint32_t use_count() const override { return ref_count_; } protected: - HeapStatDataAllocator& alloc_; + AllocatorImpl& alloc_; // Holds backing store shared by both CounterImpl and GaugeImpl. CounterImpl // adds another field, pending_increment_, that is not used in Gauge. @@ -95,7 +95,7 @@ template class StatsSharedImpl : public MetricImpl class CounterImpl : public StatsSharedImpl { public: - CounterImpl(StatName name, HeapStatDataAllocator& alloc, absl::string_view tag_extracted_name, + CounterImpl(StatName name, AllocatorImpl& alloc, absl::string_view tag_extracted_name, const std::vector& tags) : StatsSharedImpl(name, alloc, tag_extracted_name, tags) {} ~CounterImpl() override { alloc_.removeCounterFromSet(this); } @@ -119,7 +119,7 @@ class CounterImpl : public StatsSharedImpl { class GaugeImpl : public StatsSharedImpl { public: - GaugeImpl(StatName name, HeapStatDataAllocator& alloc, absl::string_view tag_extracted_name, + GaugeImpl(StatName name, AllocatorImpl& alloc, absl::string_view tag_extracted_name, const std::vector& tags, ImportMode import_mode) : StatsSharedImpl(name, alloc, tag_extracted_name, tags) { switch (import_mode) { @@ -194,9 +194,8 @@ class GaugeImpl : public StatsSharedImpl { } }; -CounterSharedPtr HeapStatDataAllocator::makeCounter(StatName name, - absl::string_view tag_extracted_name, - const std::vector& tags) { +CounterSharedPtr AllocatorImpl::makeCounter(StatName name, absl::string_view tag_extracted_name, + const std::vector& tags) { Thread::LockGuard lock(mutex_); ASSERT(gauges_.find(name) == gauges_.end()); auto iter = counters_.find(name); @@ -208,9 +207,9 @@ CounterSharedPtr HeapStatDataAllocator::makeCounter(StatName name, return counter; } -GaugeSharedPtr HeapStatDataAllocator::makeGauge(StatName name, absl::string_view tag_extracted_name, - const std::vector& tags, - Gauge::ImportMode import_mode) { +GaugeSharedPtr AllocatorImpl::makeGauge(StatName name, absl::string_view tag_extracted_name, + const std::vector& tags, + Gauge::ImportMode import_mode) { Thread::LockGuard lock(mutex_); ASSERT(counters_.find(name) == counters_.end()); auto iter = gauges_.find(name); diff --git a/source/common/stats/heap_stat_data.h b/source/common/stats/allocator_impl.h similarity index 88% rename from source/common/stats/heap_stat_data.h rename to source/common/stats/allocator_impl.h index c15f37a59958..5d5e82721b6d 100644 --- a/source/common/stats/heap_stat_data.h +++ b/source/common/stats/allocator_impl.h @@ -1,10 +1,8 @@ -// TODO(jmarantz): rename this file and class to heap_allocator.h. - #pragma once #include -#include "envoy/stats/stat_data_allocator.h" +#include "envoy/stats/allocator.h" #include "envoy/stats/stats.h" #include "envoy/stats/symbol_table.h" @@ -16,15 +14,15 @@ namespace Envoy { namespace Stats { -class HeapStatDataAllocator : public StatDataAllocator { +class AllocatorImpl : public Allocator { public: - HeapStatDataAllocator(SymbolTable& symbol_table) : symbol_table_(symbol_table) {} - ~HeapStatDataAllocator() override; + AllocatorImpl(SymbolTable& symbol_table) : symbol_table_(symbol_table) {} + ~AllocatorImpl() override; void removeCounterFromSet(Counter* counter); void removeGaugeFromSet(Gauge* gauge); - // StatDataAllocator + // Allocator CounterSharedPtr makeCounter(StatName name, absl::string_view tag_extracted_name, const std::vector& tags) override; GaugeSharedPtr makeGauge(StatName name, absl::string_view tag_extracted_name, diff --git a/source/common/stats/histogram_impl.h b/source/common/stats/histogram_impl.h index 926b3496d2b0..0177d9f3317e 100644 --- a/source/common/stats/histogram_impl.h +++ b/source/common/stats/histogram_impl.h @@ -72,7 +72,7 @@ class HistogramImpl : public HistogramImplHelper { const std::vector& tags) : HistogramImplHelper(name, tag_extracted_name, tags, parent.symbolTable()), parent_(parent) { } - ~HistogramImpl() { + ~HistogramImpl() override { // We must explicitly free the StatName here in order to supply the // SymbolTable reference. An RAII alternative would be to store a // reference to the SymbolTable in MetricImpl, which would cost 8 bytes @@ -99,7 +99,7 @@ class NullHistogramImpl : public HistogramImplHelper { public: explicit NullHistogramImpl(SymbolTable& symbol_table) : HistogramImplHelper(symbol_table), symbol_table_(symbol_table) {} - ~NullHistogramImpl() { MetricImpl::clear(symbol_table_); } + ~NullHistogramImpl() override { MetricImpl::clear(symbol_table_); } bool used() const override { return false; } SymbolTable& symbolTable() override { return symbol_table_; } diff --git a/source/common/stats/isolated_store_impl.cc b/source/common/stats/isolated_store_impl.cc index 83a99379c587..6f2da0f899af 100644 --- a/source/common/stats/isolated_store_impl.cc +++ b/source/common/stats/isolated_store_impl.cc @@ -1,8 +1,7 @@ #include "common/stats/isolated_store_impl.h" -#include - #include +#include #include #include "common/common/utility.h" diff --git a/source/common/stats/isolated_store_impl.h b/source/common/stats/isolated_store_impl.h index ba492db0c040..6a11ceec2a7c 100644 --- a/source/common/stats/isolated_store_impl.h +++ b/source/common/stats/isolated_store_impl.h @@ -1,15 +1,14 @@ #pragma once -#include - #include +#include #include #include "envoy/stats/stats.h" #include "envoy/stats/store.h" #include "common/common/utility.h" -#include "common/stats/heap_stat_data.h" +#include "common/stats/allocator_impl.h" #include "common/stats/null_counter.h" #include "common/stats/null_gauge.h" #include "common/stats/store_impl.h" @@ -100,16 +99,9 @@ class IsolatedStoreImpl : public StoreImpl { Histogram& histogram = histograms_.get(name); return histogram; } - absl::optional> findCounter(StatName name) const override { - return counters_.find(name); - } - absl::optional> findGauge(StatName name) const override { - return gauges_.find(name); - } - absl::optional> - findHistogram(StatName name) const override { - return histograms_.find(name); - } + OptionalCounter findCounter(StatName name) const override { return counters_.find(name); } + OptionalGauge findGauge(StatName name) const override { return gauges_.find(name); } + OptionalHistogram findHistogram(StatName name) const override { return histograms_.find(name); } // Stats::Store std::vector counters() const override { return counters_.toVector(); } @@ -142,7 +134,7 @@ class IsolatedStoreImpl : public StoreImpl { IsolatedStoreImpl(std::unique_ptr&& symbol_table); std::unique_ptr symbol_table_storage_; - HeapStatDataAllocator alloc_; + AllocatorImpl alloc_; IsolatedStatsCache counters_; IsolatedStatsCache gauges_; IsolatedStatsCache histograms_; diff --git a/source/common/stats/metric_impl.h b/source/common/stats/metric_impl.h index 60e121976fad..2caf82f1863f 100644 --- a/source/common/stats/metric_impl.h +++ b/source/common/stats/metric_impl.h @@ -3,7 +3,7 @@ #include #include -#include "envoy/stats/stat_data_allocator.h" +#include "envoy/stats/allocator.h" #include "envoy/stats/stats.h" #include "envoy/stats/tag.h" diff --git a/source/common/stats/scope_prefixer.cc b/source/common/stats/scope_prefixer.cc index 4efb49058909..f83265b0511e 100644 --- a/source/common/stats/scope_prefixer.cc +++ b/source/common/stats/scope_prefixer.cc @@ -44,17 +44,11 @@ Histogram& ScopePrefixer::histogramFromStatName(StatName name) { return scope_.histogramFromStatName(StatName(stat_name_storage.get())); } -absl::optional> -ScopePrefixer::findCounter(StatName name) const { - return scope_.findCounter(name); -} +OptionalCounter ScopePrefixer::findCounter(StatName name) const { return scope_.findCounter(name); } -absl::optional> ScopePrefixer::findGauge(StatName name) const { - return scope_.findGauge(name); -} +OptionalGauge ScopePrefixer::findGauge(StatName name) const { return scope_.findGauge(name); } -absl::optional> -ScopePrefixer::findHistogram(StatName name) const { +OptionalHistogram ScopePrefixer::findHistogram(StatName name) const { return scope_.findHistogram(name); } diff --git a/source/common/stats/scope_prefixer.h b/source/common/stats/scope_prefixer.h index 5d775c539b2e..f85cfc3ff098 100644 --- a/source/common/stats/scope_prefixer.h +++ b/source/common/stats/scope_prefixer.h @@ -35,13 +35,12 @@ class ScopePrefixer : public Scope { return histogramFromStatName(storage.statName()); } - absl::optional> findCounter(StatName name) const override; - absl::optional> findGauge(StatName name) const override; - absl::optional> - findHistogram(StatName name) const override; + OptionalCounter findCounter(StatName name) const override; + OptionalGauge findGauge(StatName name) const override; + OptionalHistogram findHistogram(StatName name) const override; const SymbolTable& constSymbolTable() const override { return scope_.constSymbolTable(); } - virtual SymbolTable& symbolTable() override { return scope_.symbolTable(); } + SymbolTable& symbolTable() override { return scope_.symbolTable(); } NullGaugeImpl& nullGauge(const std::string& str) override { return scope_.nullGauge(str); } diff --git a/source/common/stats/stat_merger.cc b/source/common/stats/stat_merger.cc index db2e7d49a319..a53e32d93fbc 100644 --- a/source/common/stats/stat_merger.cc +++ b/source/common/stats/stat_merger.cc @@ -35,8 +35,7 @@ void StatMerger::mergeGauges(const Protobuf::Map& gauges) StatNameManagedStorage storage(gauge.first, temp_scope_->symbolTable()); StatName stat_name = storage.statName(); - absl::optional> gauge_opt = - temp_scope_->findGauge(stat_name); + OptionalGauge gauge_opt = temp_scope_->findGauge(stat_name); Gauge::ImportMode import_mode = Gauge::ImportMode::Uninitialized; if (gauge_opt) { diff --git a/source/common/stats/stats_matcher_impl.h b/source/common/stats/stats_matcher_impl.h index 10658fd87e57..3712a466d3f6 100644 --- a/source/common/stats/stats_matcher_impl.h +++ b/source/common/stats/stats_matcher_impl.h @@ -21,7 +21,7 @@ class StatsMatcherImpl : public StatsMatcher { explicit StatsMatcherImpl(const envoy::config::metrics::v2::StatsConfig& config); // Default constructor simply allows everything. - StatsMatcherImpl() : is_inclusive_(true) {} + StatsMatcherImpl() = default; // StatsMatcher bool rejects(const std::string& name) const override; @@ -31,7 +31,7 @@ class StatsMatcherImpl : public StatsMatcher { private: // Bool indicating whether or not the StatsMatcher is including or excluding stats by default. See // StatsMatcherImpl::rejects() for much more detail. - bool is_inclusive_; + bool is_inclusive_{true}; std::vector matchers_; }; diff --git a/source/common/stats/symbol_table_impl.h b/source/common/stats/symbol_table_impl.h index 259e011f6b41..8860980017e2 100644 --- a/source/common/stats/symbol_table_impl.h +++ b/source/common/stats/symbol_table_impl.h @@ -310,7 +310,7 @@ class StatName { explicit StatName(const SymbolTable::Storage size_and_data) : size_and_data_(size_and_data) {} // Constructs an empty StatName object. - StatName() : size_and_data_(nullptr) {} + StatName() = default; // Constructs a StatName object with new storage, which must be of size // src.size(). This is used in the a flow where we first construct a StatName @@ -365,7 +365,7 @@ class StatName { bool empty() const { return size_and_data_ == nullptr || dataSize() == 0; } private: - const uint8_t* size_and_data_; + const uint8_t* size_and_data_{nullptr}; }; StatName StatNameStorage::statName() const { return StatName(bytes_.get()); } diff --git a/source/common/stats/tag_extractor_impl.cc b/source/common/stats/tag_extractor_impl.cc index acf440fa695e..7bb02e6f53e1 100644 --- a/source/common/stats/tag_extractor_impl.cc +++ b/source/common/stats/tag_extractor_impl.cc @@ -1,7 +1,6 @@ #include "common/stats/tag_extractor_impl.h" -#include - +#include #include #include "envoy/common/exception.h" diff --git a/source/common/stats/tag_producer_impl.h b/source/common/stats/tag_producer_impl.h index 505cb71929aa..6a4fcb07a6ef 100644 --- a/source/common/stats/tag_producer_impl.h +++ b/source/common/stats/tag_producer_impl.h @@ -29,7 +29,7 @@ namespace Stats { class TagProducerImpl : public TagProducer { public: TagProducerImpl(const envoy::config::metrics::v2::StatsConfig& config); - TagProducerImpl() {} + TagProducerImpl() = default; /** * Take a metric name and a vector then add proper tags into the vector and diff --git a/source/common/stats/thread_local_store.cc b/source/common/stats/thread_local_store.cc index 6de61634cd10..9ae746cb2c04 100644 --- a/source/common/stats/thread_local_store.cc +++ b/source/common/stats/thread_local_store.cc @@ -6,9 +6,9 @@ #include #include +#include "envoy/stats/allocator.h" #include "envoy/stats/histogram.h" #include "envoy/stats/sink.h" -#include "envoy/stats/stat_data_allocator.h" #include "envoy/stats/stats.h" #include "common/common/lock_guard.h" @@ -20,7 +20,7 @@ namespace Envoy { namespace Stats { -ThreadLocalStoreImpl::ThreadLocalStoreImpl(StatDataAllocator& alloc) +ThreadLocalStoreImpl::ThreadLocalStoreImpl(Allocator& alloc) : alloc_(alloc), default_scope_(createScope("")), tag_producer_(std::make_unique()), stats_matcher_(std::make_unique()), heap_allocator_(alloc.symbolTable()), @@ -400,7 +400,7 @@ Counter& ThreadLocalStoreImpl::ScopeImpl::counterFromStatName(StatName name) { return safeMakeStat( final_stat_name, central_cache_.counters_, central_cache_.rejected_stats_, - [](StatDataAllocator& allocator, StatName name, absl::string_view tag_extracted_name, + [](Allocator& allocator, StatName name, absl::string_view tag_extracted_name, const std::vector& tags) -> CounterSharedPtr { return allocator.makeCounter(name, tag_extracted_name, tags); }, @@ -450,8 +450,7 @@ Gauge& ThreadLocalStoreImpl::ScopeImpl::gaugeFromStatName(StatName name, Gauge& gauge = safeMakeStat( final_stat_name, central_cache_.gauges_, central_cache_.rejected_stats_, - [import_mode](StatDataAllocator& allocator, StatName name, - absl::string_view tag_extracted_name, + [import_mode](Allocator& allocator, StatName name, absl::string_view tag_extracted_name, const std::vector& tags) -> GaugeSharedPtr { return allocator.makeGauge(name, tag_extracted_name, tags, import_mode); }, @@ -514,18 +513,15 @@ Histogram& ThreadLocalStoreImpl::ScopeImpl::histogramFromStatName(StatName name) return **central_ref; } -absl::optional> -ThreadLocalStoreImpl::ScopeImpl::findCounter(StatName name) const { +OptionalCounter ThreadLocalStoreImpl::ScopeImpl::findCounter(StatName name) const { return findStatLockHeld(name, central_cache_.counters_); } -absl::optional> -ThreadLocalStoreImpl::ScopeImpl::findGauge(StatName name) const { +OptionalGauge ThreadLocalStoreImpl::ScopeImpl::findGauge(StatName name) const { return findStatLockHeld(name, central_cache_.gauges_); } -absl::optional> -ThreadLocalStoreImpl::ScopeImpl::findHistogram(StatName name) const { +OptionalHistogram ThreadLocalStoreImpl::ScopeImpl::findHistogram(StatName name) const { auto iter = central_cache_.histograms_.find(name); if (iter == central_cache_.histograms_.end()) { return absl::nullopt; diff --git a/source/common/stats/thread_local_store.h b/source/common/stats/thread_local_store.h index 95babe5efafe..b4bd9766f9a4 100644 --- a/source/common/stats/thread_local_store.h +++ b/source/common/stats/thread_local_store.h @@ -9,7 +9,7 @@ #include "envoy/thread_local/thread_local.h" #include "common/common/hash.h" -#include "common/stats/heap_stat_data.h" +#include "common/stats/allocator_impl.h" #include "common/stats/histogram_impl.h" #include "common/stats/null_counter.h" #include "common/stats/null_gauge.h" @@ -140,7 +140,7 @@ class TlsScope : public Scope { */ class ThreadLocalStoreImpl : Logger::Loggable, public StoreRoot { public: - ThreadLocalStoreImpl(StatDataAllocator& alloc); + ThreadLocalStoreImpl(Allocator& alloc); ~ThreadLocalStoreImpl() override; // Stats::Scope @@ -166,8 +166,8 @@ class ThreadLocalStoreImpl : Logger::Loggable, public StoreRo const SymbolTable& constSymbolTable() const override { return alloc_.constSymbolTable(); } SymbolTable& symbolTable() override { return alloc_.symbolTable(); } const TagProducer& tagProducer() const { return *tag_producer_; } - absl::optional> findCounter(StatName name) const override { - absl::optional> found_counter; + OptionalCounter findCounter(StatName name) const override { + OptionalCounter found_counter; Thread::LockGuard lock(lock_); for (ScopeImpl* scope : scopes_) { found_counter = scope->findCounter(name); @@ -177,8 +177,8 @@ class ThreadLocalStoreImpl : Logger::Loggable, public StoreRo } return absl::nullopt; } - absl::optional> findGauge(StatName name) const override { - absl::optional> found_gauge; + OptionalGauge findGauge(StatName name) const override { + OptionalGauge found_gauge; Thread::LockGuard lock(lock_); for (ScopeImpl* scope : scopes_) { found_gauge = scope->findGauge(name); @@ -188,9 +188,8 @@ class ThreadLocalStoreImpl : Logger::Loggable, public StoreRo } return absl::nullopt; } - absl::optional> - findHistogram(StatName name) const override { - absl::optional> found_histogram; + OptionalHistogram findHistogram(StatName name) const override { + OptionalHistogram found_histogram; Thread::LockGuard lock(lock_); for (ScopeImpl* scope : scopes_) { found_histogram = scope->findHistogram(name); @@ -274,13 +273,12 @@ class ThreadLocalStoreImpl : Logger::Loggable, public StoreRo // NOTE: The find methods assume that `name` is fully-qualified. // Implementations will not add the scope prefix. - absl::optional> findCounter(StatName name) const override; - absl::optional> findGauge(StatName name) const override; - absl::optional> - findHistogram(StatName name) const override; + OptionalCounter findCounter(StatName name) const override; + OptionalGauge findGauge(StatName name) const override; + OptionalHistogram findHistogram(StatName name) const override; template - using MakeStatFn = std::function(StatDataAllocator&, StatName name, + using MakeStatFn = std::function(Allocator&, StatName name, absl::string_view tag_extracted_name, const std::vector& tags)>; @@ -349,7 +347,7 @@ class ThreadLocalStoreImpl : Logger::Loggable, public StoreRo bool checkAndRememberRejection(StatName name, StatNameStorageSet& central_rejected_stats, StatNameHashSet* tls_rejected_stats); - StatDataAllocator& alloc_; + Allocator& alloc_; Event::Dispatcher* main_thread_dispatcher_{}; ThreadLocal::SlotPtr tls_; mutable Thread::MutexBasicLockable lock_; @@ -361,7 +359,7 @@ class ThreadLocalStoreImpl : Logger::Loggable, public StoreRo std::atomic threading_ever_initialized_{}; std::atomic shutting_down_{}; std::atomic merge_in_progress_{}; - HeapStatDataAllocator heap_allocator_; + AllocatorImpl heap_allocator_; NullCounterImpl null_counter_; NullGaugeImpl null_gauge_; diff --git a/source/common/tcp/conn_pool.h b/source/common/tcp/conn_pool.h index ff28802476cf..217b79cfdfbb 100644 --- a/source/common/tcp/conn_pool.h +++ b/source/common/tcp/conn_pool.h @@ -25,7 +25,7 @@ class ConnPoolImpl : Logger::Loggable, public ConnectionPool:: const Network::ConnectionSocket::OptionsSharedPtr& options, Network::TransportSocketOptionsSharedPtr transport_socket_options); - ~ConnPoolImpl(); + ~ConnPoolImpl() override; // ConnectionPool::Instance void addDrainedCallback(DrainedCb cb) override; @@ -59,7 +59,7 @@ class ConnPoolImpl : Logger::Loggable, public ConnectionPool:: struct ConnectionDataImpl : public ConnectionPool::ConnectionData { ConnectionDataImpl(ConnectionWrapperSharedPtr wrapper) : wrapper_(std::move(wrapper)) {} - ~ConnectionDataImpl() { wrapper_->release(false); } + ~ConnectionDataImpl() override { wrapper_->release(false); } // ConnectionPool::ConnectionData Network::ClientConnection& connection() override { return wrapper_->connection(); } @@ -80,7 +80,7 @@ class ConnPoolImpl : Logger::Loggable, public ConnectionPool:: ConnReadFilter(ActiveConn& parent) : parent_(parent) {} // Network::ReadFilter - Network::FilterStatus onData(Buffer::Instance& data, bool end_stream) { + Network::FilterStatus onData(Buffer::Instance& data, bool end_stream) override { parent_.onUpstreamData(data, end_stream); return Network::FilterStatus::StopIteration; } @@ -92,7 +92,7 @@ class ConnPoolImpl : Logger::Loggable, public ConnectionPool:: public Network::ConnectionCallbacks, public Event::DeferredDeletable { ActiveConn(ConnPoolImpl& parent); - ~ActiveConn(); + ~ActiveConn() override; void onConnectTimeout(); void onUpstreamData(Buffer::Instance& data, bool end_stream); @@ -122,7 +122,7 @@ class ConnPoolImpl : Logger::Loggable, public ConnectionPool:: struct PendingRequest : LinkedObject, public ConnectionPool::Cancellable { PendingRequest(ConnPoolImpl& parent, ConnectionPool::Callbacks& callbacks); - ~PendingRequest(); + ~PendingRequest() override; // ConnectionPool::Cancellable void cancel(ConnectionPool::CancelPolicy cancel_policy) override { diff --git a/source/common/tcp_proxy/tcp_proxy.h b/source/common/tcp_proxy/tcp_proxy.h index 44cdd35aeacf..5a8534a56287 100644 --- a/source/common/tcp_proxy/tcp_proxy.h +++ b/source/common/tcp_proxy/tcp_proxy.h @@ -178,7 +178,7 @@ class Filter : public Network::ReadFilter, public: Filter(ConfigSharedPtr config, Upstream::ClusterManager& cluster_manager, TimeSource& time_source); - ~Filter(); + ~Filter() override; // Network::ReadFilter Network::FilterStatus onData(Buffer::Instance& data, bool end_stream) override; @@ -315,7 +315,7 @@ using DrainerPtr = std::unique_ptr; class UpstreamDrainManager : public ThreadLocal::ThreadLocalObject { public: - ~UpstreamDrainManager(); + ~UpstreamDrainManager() override; void add(const Config::SharedConfigSharedPtr& config, Tcp::ConnectionPool::ConnectionDataPtr&& upstream_conn_data, const std::shared_ptr& callbacks, diff --git a/source/common/thread_local/thread_local_impl.cc b/source/common/thread_local/thread_local_impl.cc index 6884aae42d9a..4e8c32fed776 100644 --- a/source/common/thread_local/thread_local_impl.cc +++ b/source/common/thread_local/thread_local_impl.cc @@ -37,8 +37,12 @@ SlotPtr InstanceImpl::allocateSlot() { return slot; } +bool InstanceImpl::SlotImpl::currentThreadRegistered() { + return thread_local_data_.data_.size() > index_; +} + ThreadLocalObjectSharedPtr InstanceImpl::SlotImpl::get() { - ASSERT(thread_local_data_.data_.size() > index_); + ASSERT(currentThreadRegistered()); return thread_local_data_.data_[index_]; } diff --git a/source/common/thread_local/thread_local_impl.h b/source/common/thread_local/thread_local_impl.h index 820cd1504a95..3e8e39c8fa89 100644 --- a/source/common/thread_local/thread_local_impl.h +++ b/source/common/thread_local/thread_local_impl.h @@ -18,7 +18,7 @@ namespace ThreadLocal { class InstanceImpl : Logger::Loggable, public Instance { public: InstanceImpl() : main_thread_id_(std::this_thread::get_id()) {} - ~InstanceImpl(); + ~InstanceImpl() override; // ThreadLocal::Instance SlotPtr allocateSlot() override; @@ -30,10 +30,11 @@ class InstanceImpl : Logger::Loggable, public Instance { private: struct SlotImpl : public Slot { SlotImpl(InstanceImpl& parent, uint64_t index) : parent_(parent), index_(index) {} - ~SlotImpl() { parent_.removeSlot(*this); } + ~SlotImpl() override { parent_.removeSlot(*this); } // ThreadLocal::Slot ThreadLocalObjectSharedPtr get() override; + bool currentThreadRegistered() override; void runOnAllThreads(Event::PostCb cb) override { parent_.runOnAllThreads(cb); } void runOnAllThreads(Event::PostCb cb, Event::PostCb main_callback) override { parent_.runOnAllThreads(cb, main_callback); diff --git a/source/common/upstream/BUILD b/source/common/upstream/BUILD index 5177da76ddb4..e11007731ec6 100644 --- a/source/common/upstream/BUILD +++ b/source/common/upstream/BUILD @@ -48,7 +48,6 @@ envoy_cc_library( "//source/common/common:cleanup_lib", "//source/common/common:enum_to_int", "//source/common/common:utility_lib", - "//source/common/config:cds_json_lib", "//source/common/config:grpc_mux_lib", "//source/common/config:subscription_factory_lib", "//source/common/config:utility_lib", @@ -381,7 +380,6 @@ envoy_cc_library( "//source/common/common:enum_to_int", "//source/common/common:utility_lib", "//source/common/config:protocol_json_lib", - "//source/common/config:tls_context_json_lib", "//source/common/http:utility_lib", "//source/common/network:address_lib", "//source/common/network:resolver_lib", @@ -427,6 +425,7 @@ envoy_cc_library( "//include/envoy/local_info:local_info_interface", "//include/envoy/network:dns_interface", "//include/envoy/runtime:runtime_interface", + "//include/envoy/server:filter_config_interface", "//include/envoy/server:transport_socket_config_interface", "//include/envoy/ssl:context_manager_interface", "//include/envoy/thread_local:thread_local_interface", @@ -465,7 +464,6 @@ envoy_cc_library( "//source/common/common:enum_to_int", "//source/common/common:utility_lib", "//source/common/config:protocol_json_lib", - "//source/common/config:tls_context_json_lib", "//source/common/http:utility_lib", "//source/common/network:address_lib", "//source/common/network:resolver_lib", diff --git a/source/common/upstream/cluster_factory_impl.h b/source/common/upstream/cluster_factory_impl.h index cb5128a53763..ae709eb094c2 100644 --- a/source/common/upstream/cluster_factory_impl.h +++ b/source/common/upstream/cluster_factory_impl.h @@ -169,7 +169,7 @@ template class ConfigurableClusterFactoryBase : public Clust ConfigurableClusterFactoryBase(const std::string& name) : ClusterFactoryImplBase(name) {} private: - virtual std::pair + std::pair createClusterImpl(const envoy::api::v2::Cluster& cluster, ClusterFactoryContext& context, Server::Configuration::TransportSocketFactoryContext& socket_factory_context, Stats::ScopePtr&& stats_scope) override { diff --git a/source/common/upstream/cluster_manager_impl.cc b/source/common/upstream/cluster_manager_impl.cc index d4a666f97af4..4c29bf9a70a6 100644 --- a/source/common/upstream/cluster_manager_impl.cc +++ b/source/common/upstream/cluster_manager_impl.cc @@ -18,7 +18,6 @@ #include "common/common/enum_to_int.h" #include "common/common/fmt.h" #include "common/common/utility.h" -#include "common/config/cds_json.h" #include "common/config/resources.h" #include "common/config/utility.h" #include "common/grpc/async_client_manager_impl.h" diff --git a/source/common/upstream/cluster_manager_impl.h b/source/common/upstream/cluster_manager_impl.h index abe595033747..055cb9fd2cce 100644 --- a/source/common/upstream/cluster_manager_impl.h +++ b/source/common/upstream/cluster_manager_impl.h @@ -293,7 +293,7 @@ class ClusterManagerImpl : public ClusterManager, Logger::Loggable& local_cluster_name); - ~ThreadLocalClusterManagerImpl(); + ~ThreadLocalClusterManagerImpl() override; void drainConnPools(const HostVector& hosts); void drainConnPools(HostSharedPtr old_host, ConnPoolsContainer& container); void clearContainer(HostSharedPtr old_host, ConnPoolsContainer& container); diff --git a/source/common/upstream/health_checker_base_impl.h b/source/common/upstream/health_checker_base_impl.h index 39aa9a8687aa..5008cf9d3907 100644 --- a/source/common/upstream/health_checker_base_impl.h +++ b/source/common/upstream/health_checker_base_impl.h @@ -46,7 +46,7 @@ class HealthCheckerImplBase : public HealthChecker, protected: class ActiveHealthCheckSession : public Event::DeferredDeletable { public: - virtual ~ActiveHealthCheckSession(); + ~ActiveHealthCheckSession() override; HealthTransition setUnhealthy(envoy::data::core::v2alpha::HealthCheckFailureType type); void onDeferredDeleteBase(); void start() { onInitialInterval(); } diff --git a/source/common/upstream/health_checker_impl.cc b/source/common/upstream/health_checker_impl.cc index 1490dced8594..708f5e132981 100644 --- a/source/common/upstream/health_checker_impl.cc +++ b/source/common/upstream/health_checker_impl.cc @@ -12,6 +12,7 @@ #include "common/http/header_map_impl.h" #include "common/network/address_impl.h" #include "common/router/router.h" +#include "common/runtime/runtime_impl.h" #include "common/upstream/host_utility.h" // TODO(dio): Remove dependency to extension health checkers when redis_health_check is removed. @@ -186,6 +187,7 @@ void HttpHealthCheckerImpl::HttpActiveHealthCheckSession::onEvent(Network::Conne // For the raw disconnect event, we are either between intervals in which case we already have // a timer setup, or we did the close or got a reset, in which case we already setup a new // timer. There is nothing to do here other than blow away the client. + response_headers_.reset(); parent_.dispatcher_.deferredDelete(std::move(client_)); } } diff --git a/source/common/upstream/health_discovery_service.cc b/source/common/upstream/health_discovery_service.cc index 07e960fbdfed..8fb6f44b1f15 100644 --- a/source/common/upstream/health_discovery_service.cc +++ b/source/common/upstream/health_discovery_service.cc @@ -236,9 +236,9 @@ ProdClusterInfoFactory::createClusterInfo(const CreateClusterInfoParams& params) Network::TransportSocketFactoryPtr socket_factory = Upstream::createTransportSocketFactory(params.cluster_, factory_context); - return std::make_unique(params.cluster_, params.bind_config_, params.runtime_, - std::move(socket_factory), std::move(scope), - params.added_via_api_, params.validation_visitor_); + return std::make_unique( + params.cluster_, params.bind_config_, params.runtime_, std::move(socket_factory), + std::move(scope), params.added_via_api_, params.validation_visitor_, factory_context); } void HdsCluster::startHealthchecks(AccessLog::AccessLogManager& access_log_manager, diff --git a/source/common/upstream/load_balancer_impl.cc b/source/common/upstream/load_balancer_impl.cc index 3969ed5dc308..e4b653d928dc 100644 --- a/source/common/upstream/load_balancer_impl.cc +++ b/source/common/upstream/load_balancer_impl.cc @@ -117,8 +117,8 @@ LoadBalancerBase::LoadBalancerBase(const PrioritySet& priority_set, ClusterStats // - normalized total health is < 100%. There are not enough healthy hosts to handle the load. // Continue distributing the load among priority sets, but turn on panic mode for a given priority // if # of healthy hosts in priority set is low. -// - normalized total health is 0%. All hosts are down. Redirect 100% of traffic to P=0 and enable -// panic mode. +// - normalized total health is 0%. All hosts are down. Redirect 100% of traffic to P=0. +// And if panic threshold > 0% then enable panic mode for P=0, otherwise disable. void LoadBalancerBase::recalculatePerPriorityState(uint32_t priority, const PrioritySet& priority_set, @@ -219,7 +219,11 @@ void LoadBalancerBase::recalculatePerPriorityPanic() { const uint32_t normalized_total_availability = calculateNormalizedTotalAvailability(per_priority_health_, per_priority_degraded_); - if (normalized_total_availability == 0) { + const uint64_t panic_threshold = std::min( + 100, runtime_.snapshot().getInteger(RuntimePanicThreshold, default_healthy_panic_percent_)); + + // Panic mode is disabled only when panic_threshold is 0%. + if (panic_threshold > 0 && normalized_total_availability == 0) { // Everything is terrible. All load should be to P=0. Turn on panic mode. ASSERT(per_priority_load_.healthy_priority_load_.get()[0] == 100); per_priority_panic_[0] = true; diff --git a/source/common/upstream/load_balancer_impl.h b/source/common/upstream/load_balancer_impl.h index 1ee7e2b02672..518ea5071121 100644 --- a/source/common/upstream/load_balancer_impl.h +++ b/source/common/upstream/load_balancer_impl.h @@ -162,7 +162,7 @@ class ZoneAwareLoadBalancerBase : public LoadBalancerBase { ClusterStats& stats, Runtime::Loader& runtime, Runtime::RandomGenerator& random, const envoy::api::v2::Cluster::CommonLbConfig& common_config); - ~ZoneAwareLoadBalancerBase(); + ~ZoneAwareLoadBalancerBase() override; // When deciding which hosts to use on an LB decision, we need to know how to index into the // priority_set. This priority_set cursor is used by ZoneAwareLoadBalancerBase subclasses, e.g. @@ -182,7 +182,7 @@ class ZoneAwareLoadBalancerBase : public LoadBalancerBase { LocalityDegradedHosts, }; - HostsSource() {} + HostsSource() = default; HostsSource(uint32_t priority, SourceType source_type) : priority_(priority), source_type_(source_type) { diff --git a/source/common/upstream/original_dst_cluster.cc b/source/common/upstream/original_dst_cluster.cc index e061a7c390cc..9cb8414aa166 100644 --- a/source/common/upstream/original_dst_cluster.cc +++ b/source/common/upstream/original_dst_cluster.cc @@ -196,7 +196,10 @@ OriginalDstClusterFactory::createClusterImpl( Stats::ScopePtr&& stats_scope) { if (cluster.lb_policy() != envoy::api::v2::Cluster::ORIGINAL_DST_LB) { throw EnvoyException(fmt::format( - "cluster: cluster type 'original_dst' may only be used with LB type 'original_dst_lb'")); + "cluster: LB policy {} is not valid for Cluster type {}. Only 'original_dst_lb' " + "is allowed with cluster type 'original_dst'", + envoy::api::v2::Cluster_LbPolicy_Name(cluster.lb_policy()), + envoy::api::v2::Cluster_DiscoveryType_Name(cluster.type()))); } if (cluster.has_lb_subset_config() && cluster.lb_subset_config().subset_selectors_size() != 0) { throw EnvoyException( diff --git a/source/common/upstream/outlier_detection_impl.h b/source/common/upstream/outlier_detection_impl.h index 3a03a7556c00..2b703c2adba4 100644 --- a/source/common/upstream/outlier_detection_impl.h +++ b/source/common/upstream/outlier_detection_impl.h @@ -290,7 +290,7 @@ class DetectorImpl : public Detector, public std::enable_shared_from_thissetBufferLimits(cluster.perConnectionBufferLimitBytes()); + cluster.createNetworkFilterChain(*connection); return connection; } @@ -543,12 +543,53 @@ ClusterLoadReportStats ClusterInfoImpl::generateLoadReportStats(Stats::Scope& sc return {ALL_CLUSTER_LOAD_REPORT_STATS(POOL_COUNTER(scope))}; } -ClusterInfoImpl::ClusterInfoImpl(const envoy::api::v2::Cluster& config, - const envoy::api::v2::core::BindConfig& bind_config, - Runtime::Loader& runtime, - Network::TransportSocketFactoryPtr&& socket_factory, - Stats::ScopePtr&& stats_scope, bool added_via_api, - ProtobufMessage::ValidationVisitor& validation_visitor) +// Implements the FactoryContext interface required by network filters. +class FactoryContextImpl : public Server::Configuration::CommonFactoryContext { +public: + // Create from a TransportSocketFactoryContext using parent stats_scope and runtime + // other contexts taken from TransportSocketFactoryContext. + FactoryContextImpl(Stats::Scope& stats_scope, Envoy::Runtime::Loader& runtime, + Server::Configuration::TransportSocketFactoryContext& c) + : admin_(c.admin()), stats_scope_(stats_scope), cluster_manager_(c.clusterManager()), + local_info_(c.localInfo()), dispatcher_(c.dispatcher()), random_(c.random()), + runtime_(runtime), singleton_manager_(c.singletonManager()), tls_(c.threadLocal()), + validation_visitor_(c.messageValidationVisitor()), api_(c.api()) {} + + Upstream::ClusterManager& clusterManager() override { return cluster_manager_; } + Event::Dispatcher& dispatcher() override { return dispatcher_; } + const LocalInfo::LocalInfo& localInfo() const override { return local_info_; } + Envoy::Runtime::RandomGenerator& random() override { return random_; } + Envoy::Runtime::Loader& runtime() override { return runtime_; } + Stats::Scope& scope() override { return stats_scope_; } + Singleton::Manager& singletonManager() override { return singleton_manager_; } + ThreadLocal::SlotAllocator& threadLocal() override { return tls_; } + Server::Admin& admin() override { return admin_; } + TimeSource& timeSource() override { return api().timeSource(); } + ProtobufMessage::ValidationVisitor& messageValidationVisitor() override { + return validation_visitor_; + } + Api::Api& api() override { return api_; } + +private: + Server::Admin& admin_; + Stats::Scope& stats_scope_; + Upstream::ClusterManager& cluster_manager_; + const LocalInfo::LocalInfo& local_info_; + Event::Dispatcher& dispatcher_; + Envoy::Runtime::RandomGenerator& random_; + Envoy::Runtime::Loader& runtime_; + Singleton::Manager& singleton_manager_; + ThreadLocal::SlotAllocator& tls_; + ProtobufMessage::ValidationVisitor& validation_visitor_; + Api::Api& api_; +}; + +ClusterInfoImpl::ClusterInfoImpl( + const envoy::api::v2::Cluster& config, const envoy::api::v2::core::BindConfig& bind_config, + Runtime::Loader& runtime, Network::TransportSocketFactoryPtr&& socket_factory, + Stats::ScopePtr&& stats_scope, bool added_via_api, + ProtobufMessage::ValidationVisitor& validation_visitor, + Server::Configuration::TransportSocketFactoryContext& factory_context) : runtime_(runtime), name_(config.name()), type_(config.type()), max_requests_per_connection_( PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, max_requests_per_connection, 0)), @@ -578,7 +619,9 @@ ClusterInfoImpl::ClusterInfoImpl(const envoy::api::v2::Cluster& config, cluster_type_(config.has_cluster_type() ? absl::make_optional( config.cluster_type()) - : absl::nullopt) { + : absl::nullopt), + factory_context_( + std::make_unique(*stats_scope_, runtime, factory_context)) { switch (config.lb_policy()) { case envoy::api::v2::Cluster::ROUND_ROBIN: lb_type_ = LoadBalancerType::RoundRobin; @@ -595,7 +638,10 @@ ClusterInfoImpl::ClusterInfoImpl(const envoy::api::v2::Cluster& config, case envoy::api::v2::Cluster::ORIGINAL_DST_LB: if (config.type() != envoy::api::v2::Cluster::ORIGINAL_DST) { throw EnvoyException(fmt::format( - "cluster: LB type 'original_dst_lb' may only be used with cluster type 'original_dst'")); + "cluster: LB policy {} is not valid for Cluster type {}. Only 'original_dst_lb' " + "is allowed with cluster type 'original_dst'", + envoy::api::v2::Cluster_LbPolicy_Name(config.lb_policy()), + envoy::api::v2::Cluster_DiscoveryType_Name(config.type()))); } lb_type_ = LoadBalancerType::OriginalDst; break; @@ -639,6 +685,24 @@ ClusterInfoImpl::ClusterInfoImpl(const envoy::api::v2::Cluster& config, // https://github.com/lyft/protoc-gen-validate/issues/97 resolved. This just provides early // validation of sanity of fields that we should catch at config ingestion. DurationUtil::durationToMilliseconds(common_lb_config_.update_merge_window()); + + // Create upstream filter factories + auto filters = config.filters(); + for (ssize_t i = 0; i < filters.size(); i++) { + const auto& proto_config = filters[i]; + const std::string& string_name = proto_config.name(); + ENVOY_LOG(debug, " upstream filter #{}:", i); + ENVOY_LOG(debug, " name: {}", string_name); + auto& factory = Config::Utility::getAndCheckFactory< + Server::Configuration::NamedUpstreamNetworkFilterConfigFactory>(string_name); + auto message = factory.createEmptyConfigProto(); + if (!proto_config.typed_config().value().empty()) { + proto_config.typed_config().UnpackTo(message.get()); + } + Network::FilterFactoryCb callback = + factory.createFilterFactoryFromProto(*message, *factory_context_); + filter_factories_.push_back(callback); + } } ProtocolOptionsConfigConstSharedPtr @@ -675,6 +739,12 @@ Network::TransportSocketFactoryPtr createTransportSocketFactory( return config_factory.createTransportSocketFactory(*message, factory_context); } +void ClusterInfoImpl::createNetworkFilterChain(Network::Connection& connection) const { + for (const auto& factory : filter_factories_) { + factory(connection); + } +} + ClusterImplBase::ClusterImplBase( const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, Server::Configuration::TransportSocketFactoryContext& factory_context, @@ -686,7 +756,8 @@ ClusterImplBase::ClusterImplBase( auto socket_factory = createTransportSocketFactory(cluster, factory_context); info_ = std::make_unique( cluster, factory_context.clusterManager().bindConfig(), runtime, std::move(socket_factory), - std::move(stats_scope), added_via_api, factory_context.messageValidationVisitor()); + std::move(stats_scope), added_via_api, factory_context.messageValidationVisitor(), + factory_context); // Create the default (empty) priority set before registering callbacks to // avoid getting an update the first time it is accessed. priority_set_.getOrCreateHostSet(0); diff --git a/source/common/upstream/upstream_impl.h b/source/common/upstream/upstream_impl.h index 5d07e9a1673f..110b08bc955e 100644 --- a/source/common/upstream/upstream_impl.h +++ b/source/common/upstream/upstream_impl.h @@ -17,8 +17,10 @@ #include "envoy/event/timer.h" #include "envoy/local_info/local_info.h" #include "envoy/network/dns.h" +#include "envoy/network/filter.h" #include "envoy/runtime/runtime.h" #include "envoy/secret/secret_manager.h" +#include "envoy/server/filter_config.h" #include "envoy/server/transport_socket_config.h" #include "envoy/ssl/context_manager.h" #include "envoy/stats/scope.h" @@ -105,7 +107,7 @@ class HostDescriptionImpl : virtual public HostDescription { absl::ReaderMutexLock lock(&metadata_mutex_); return metadata_; } - virtual void metadata(const envoy::api::v2::core::Metadata& new_metadata) override { + void metadata(const envoy::api::v2::core::Metadata& new_metadata) override { absl::WriterMutexLock lock(&metadata_mutex_); metadata_ = std::make_shared(new_metadata); } @@ -483,13 +485,12 @@ class PrioritySetImpl : public PrioritySet { ASSERT(!parent_.batch_update_); parent_.batch_update_ = true; } - ~BatchUpdateScope() { parent_.batch_update_ = false; } + ~BatchUpdateScope() override { parent_.batch_update_ = false; } - virtual void updateHosts(uint32_t priority, - PrioritySet::UpdateHostsParams&& update_hosts_params, - LocalityWeightsConstSharedPtr locality_weights, - const HostVector& hosts_added, const HostVector& hosts_removed, - absl::optional overprovisioning_factor) override; + void updateHosts(uint32_t priority, PrioritySet::UpdateHostsParams&& update_hosts_params, + LocalityWeightsConstSharedPtr locality_weights, const HostVector& hosts_added, + const HostVector& hosts_removed, + absl::optional overprovisioning_factor) override; std::unordered_set all_hosts_added_; std::unordered_set all_hosts_removed_; @@ -503,13 +504,14 @@ class PrioritySetImpl : public PrioritySet { /** * Implementation of ClusterInfo that reads from JSON. */ -class ClusterInfoImpl : public ClusterInfo { +class ClusterInfoImpl : public ClusterInfo, protected Logger::Loggable { public: ClusterInfoImpl(const envoy::api::v2::Cluster& config, const envoy::api::v2::core::BindConfig& bind_config, Runtime::Loader& runtime, Network::TransportSocketFactoryPtr&& socket_factory, Stats::ScopePtr&& stats_scope, bool added_via_api, - ProtobufMessage::ValidationVisitor& validation_visitor); + ProtobufMessage::ValidationVisitor& validation_visitor, + Server::Configuration::TransportSocketFactoryContext&); static ClusterStats generateStats(Stats::Scope& scope); static ClusterLoadReportStats generateLoadReportStats(Stats::Scope& scope); @@ -576,6 +578,8 @@ class ClusterInfoImpl : public ClusterInfo { absl::optional eds_service_name() const override { return eds_service_name_; } + void createNetworkFilterChain(Network::Connection&) const override; + private: struct ResourceManagers { ResourceManagers(const envoy::api::v2::Cluster& config, Runtime::Loader& runtime, @@ -621,6 +625,8 @@ class ClusterInfoImpl : public ClusterInfo { const bool warm_hosts_; absl::optional eds_service_name_; const absl::optional cluster_type_; + const std::unique_ptr factory_context_; + std::vector filter_factories_; }; /** diff --git a/source/exe/main_common.h b/source/exe/main_common.h index a8944fd69b34..5faf31b547cc 100644 --- a/source/exe/main_common.h +++ b/source/exe/main_common.h @@ -71,7 +71,7 @@ class MainCommonBase { Server::ComponentFactory& component_factory_; Thread::ThreadFactory& thread_factory_; Filesystem::Instance& file_system_; - Stats::HeapStatDataAllocator stats_allocator_; + Stats::AllocatorImpl stats_allocator_; std::unique_ptr tls_; std::unique_ptr restarter_; diff --git a/source/extensions/access_loggers/common/BUILD b/source/extensions/access_loggers/common/BUILD new file mode 100644 index 000000000000..daa8a198e578 --- /dev/null +++ b/source/extensions/access_loggers/common/BUILD @@ -0,0 +1,23 @@ +licenses(["notice"]) # Apache 2 + +# Base class for implementations of AccessLog::Instance. + +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_package", +) + +envoy_package() + +envoy_cc_library( + name = "access_log_base", + srcs = ["access_log_base.cc"], + hdrs = ["access_log_base.h"], + deps = [ + "//include/envoy/access_log:access_log_interface", + "//source/common/access_log:access_log_lib", + "//source/common/http:header_map_lib", + "//source/common/singleton:const_singleton", + ], +) diff --git a/source/extensions/access_loggers/common/access_log_base.cc b/source/extensions/access_loggers/common/access_log_base.cc new file mode 100644 index 000000000000..77b10388537a --- /dev/null +++ b/source/extensions/access_loggers/common/access_log_base.cc @@ -0,0 +1,34 @@ +#include "extensions/access_loggers/common/access_log_base.h" + +#include "common/http/header_map_impl.h" +#include "common/singleton/const_singleton.h" + +namespace Envoy { +namespace Extensions { +namespace AccessLoggers { +namespace Common { + +void ImplBase::log(const Http::HeaderMap* request_headers, const Http::HeaderMap* response_headers, + const Http::HeaderMap* response_trailers, + const StreamInfo::StreamInfo& stream_info) { + ConstSingleton empty_headers; + if (!request_headers) { + request_headers = &empty_headers.get(); + } + if (!response_headers) { + response_headers = &empty_headers.get(); + } + if (!response_trailers) { + response_trailers = &empty_headers.get(); + } + if (filter_ && + !filter_->evaluate(stream_info, *request_headers, *response_headers, *response_trailers)) { + return; + } + return emitLog(*request_headers, *response_headers, *response_trailers, stream_info); +} + +} // namespace Common +} // namespace AccessLoggers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/access_loggers/common/access_log_base.h b/source/extensions/access_loggers/common/access_log_base.h new file mode 100644 index 000000000000..9a6d6caa6668 --- /dev/null +++ b/source/extensions/access_loggers/common/access_log_base.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include +#include + +#include "envoy/access_log/access_log.h" +#include "envoy/config/filter/accesslog/v2/accesslog.pb.h" +#include "envoy/runtime/runtime.h" +#include "envoy/server/access_log_config.h" + +#include "common/http/header_utility.h" +#include "common/protobuf/protobuf.h" + +namespace Envoy { +namespace Extensions { +namespace AccessLoggers { +namespace Common { + +/** + * Base implementation of Accesslog::Instance handles common filter logic. + */ +class ImplBase : public AccessLog::Instance { +public: + ImplBase(AccessLog::FilterPtr filter) : filter_(std::move(filter)) {} + + /** + * Log a completed request if the underlying AccessLog `filter_` allows it. + */ + void log(const Http::HeaderMap* request_headers, const Http::HeaderMap* response_headers, + const Http::HeaderMap* response_trailers, + const StreamInfo::StreamInfo& stream_info) override; + +private: + /** + * Log a completed request. + * @param request_headers supplies the incoming request headers after filtering. + * @param response_headers supplies response headers. + * @param response_trailers supplies response trailers. + * @param stream_info supplies additional information about the request not + * contained in the request headers. + */ + virtual void emitLog(const Http::HeaderMap& request_headers, + const Http::HeaderMap& response_headers, + const Http::HeaderMap& response_trailers, + const StreamInfo::StreamInfo& stream_info) PURE; + + AccessLog::FilterPtr filter_; +}; + +} // namespace Common +} // namespace AccessLoggers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/access_loggers/file/BUILD b/source/extensions/access_loggers/file/BUILD index e83a33f02a9f..3ea8c8819c30 100644 --- a/source/extensions/access_loggers/file/BUILD +++ b/source/extensions/access_loggers/file/BUILD @@ -16,8 +16,7 @@ envoy_cc_library( srcs = ["file_access_log_impl.cc"], hdrs = ["file_access_log_impl.h"], deps = [ - "//include/envoy/access_log:access_log_interface", - "//source/common/http:header_map_lib", + "//source/extensions/access_loggers/common:access_log_base", ], ) diff --git a/source/extensions/access_loggers/file/file_access_log_impl.cc b/source/extensions/access_loggers/file/file_access_log_impl.cc index 75409f34dadc..410204d3ad86 100644 --- a/source/extensions/access_loggers/file/file_access_log_impl.cc +++ b/source/extensions/access_loggers/file/file_access_log_impl.cc @@ -1,7 +1,5 @@ #include "extensions/access_loggers/file/file_access_log_impl.h" -#include "common/http/header_map_impl.h" - namespace Envoy { namespace Extensions { namespace AccessLoggers { @@ -10,33 +8,16 @@ namespace File { FileAccessLog::FileAccessLog(const std::string& access_log_path, AccessLog::FilterPtr&& filter, AccessLog::FormatterPtr&& formatter, AccessLog::AccessLogManager& log_manager) - : filter_(std::move(filter)), formatter_(std::move(formatter)) { + : ImplBase(std::move(filter)), formatter_(std::move(formatter)) { log_file_ = log_manager.createAccessLog(access_log_path); } -void FileAccessLog::log(const Http::HeaderMap* request_headers, - const Http::HeaderMap* response_headers, - const Http::HeaderMap* response_trailers, - const StreamInfo::StreamInfo& stream_info) { - static Http::HeaderMapImpl empty_headers; - if (!request_headers) { - request_headers = &empty_headers; - } - if (!response_headers) { - response_headers = &empty_headers; - } - if (!response_trailers) { - response_trailers = &empty_headers; - } - - if (filter_) { - if (!filter_->evaluate(stream_info, *request_headers, *response_headers, *response_trailers)) { - return; - } - } - +void FileAccessLog::emitLog(const Http::HeaderMap& request_headers, + const Http::HeaderMap& response_headers, + const Http::HeaderMap& response_trailers, + const StreamInfo::StreamInfo& stream_info) { log_file_->write( - formatter_->format(*request_headers, *response_headers, *response_trailers, stream_info)); + formatter_->format(request_headers, response_headers, response_trailers, stream_info)); } } // namespace File diff --git a/source/extensions/access_loggers/file/file_access_log_impl.h b/source/extensions/access_loggers/file/file_access_log_impl.h index b14b396befd8..06546d6aba9a 100644 --- a/source/extensions/access_loggers/file/file_access_log_impl.h +++ b/source/extensions/access_loggers/file/file_access_log_impl.h @@ -1,6 +1,6 @@ #pragma once -#include "envoy/access_log/access_log.h" +#include "extensions/access_loggers/common/access_log_base.h" namespace Envoy { namespace Extensions { @@ -10,19 +10,18 @@ namespace File { /** * Access log Instance that writes logs to a file. */ -class FileAccessLog : public AccessLog::Instance { +class FileAccessLog : public Common::ImplBase { public: FileAccessLog(const std::string& access_log_path, AccessLog::FilterPtr&& filter, AccessLog::FormatterPtr&& formatter, AccessLog::AccessLogManager& log_manager); - // AccessLog::Instance - void log(const Http::HeaderMap* request_headers, const Http::HeaderMap* response_headers, - const Http::HeaderMap* response_trailers, - const StreamInfo::StreamInfo& stream_info) override; - private: + // Common::ImplBase + void emitLog(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, + const Http::HeaderMap& response_trailers, + const StreamInfo::StreamInfo& stream_info) override; + AccessLog::AccessLogFileSharedPtr log_file_; - AccessLog::FilterPtr filter_; AccessLog::FormatterPtr formatter_; }; diff --git a/source/extensions/access_loggers/http_grpc/BUILD b/source/extensions/access_loggers/http_grpc/BUILD index d57adbd547ef..941d950ff9c4 100644 --- a/source/extensions/access_loggers/http_grpc/BUILD +++ b/source/extensions/access_loggers/http_grpc/BUILD @@ -16,7 +16,6 @@ envoy_cc_library( srcs = ["grpc_access_log_impl.cc"], hdrs = ["grpc_access_log_impl.h"], deps = [ - "//include/envoy/access_log:access_log_interface", "//include/envoy/grpc:async_client_interface", "//include/envoy/grpc:async_client_manager_interface", "//include/envoy/singleton:instance_interface", @@ -26,6 +25,7 @@ envoy_cc_library( "//source/common/grpc:async_client_lib", "//source/common/grpc:typed_async_client_lib", "//source/common/network:utility_lib", + "//source/extensions/access_loggers/common:access_log_base", "@envoy_api//envoy/config/accesslog/v2:als_cc", "@envoy_api//envoy/config/filter/accesslog/v2:accesslog_cc", "@envoy_api//envoy/service/accesslog/v2:als_cc", diff --git a/source/extensions/access_loggers/http_grpc/config.cc b/source/extensions/access_loggers/http_grpc/config.cc index 9e4d4f2d2dd8..a58327004da5 100644 --- a/source/extensions/access_loggers/http_grpc/config.cc +++ b/source/extensions/access_loggers/http_grpc/config.cc @@ -20,7 +20,7 @@ namespace AccessLoggers { namespace HttpGrpc { // Singleton registration via macro defined in envoy/singleton/manager.h -SINGLETON_MANAGER_REGISTRATION(grpc_access_log_streamer); +SINGLETON_MANAGER_REGISTRATION(grpc_access_logger_cache); AccessLog::InstanceSharedPtr HttpGrpcAccessLogFactory::createAccessLogInstance(const Protobuf::Message& config, @@ -30,18 +30,16 @@ HttpGrpcAccessLogFactory::createAccessLogInstance(const Protobuf::Message& confi const auto& proto_config = MessageUtil::downcastAndValidate< const envoy::config::accesslog::v2::HttpGrpcAccessLogConfig&>(config); - std::shared_ptr grpc_access_log_streamer = - context.singletonManager().getTyped( - SINGLETON_MANAGER_REGISTERED_NAME(grpc_access_log_streamer), - [&context, grpc_service = proto_config.common_config().grpc_service()] { - return std::make_shared( - context.clusterManager().grpcAsyncClientManager().factoryForGrpcService( - grpc_service, context.scope(), false), + std::shared_ptr grpc_access_logger_cache = + context.singletonManager().getTyped( + SINGLETON_MANAGER_REGISTERED_NAME(grpc_access_logger_cache), [&context] { + return std::make_shared( + context.clusterManager().grpcAsyncClientManager(), context.scope(), context.threadLocal(), context.localInfo()); }); - return std::make_shared(std::move(filter), proto_config, - grpc_access_log_streamer); + return std::make_shared(std::move(filter), proto_config, context.threadLocal(), + grpc_access_logger_cache); } ProtobufTypes::MessagePtr HttpGrpcAccessLogFactory::createEmptyConfigProto() { diff --git a/source/extensions/access_loggers/http_grpc/grpc_access_log_impl.cc b/source/extensions/access_loggers/http_grpc/grpc_access_log_impl.cc index c9c94146ef9c..928d3699c637 100644 --- a/source/extensions/access_loggers/http_grpc/grpc_access_log_impl.cc +++ b/source/extensions/access_loggers/http_grpc/grpc_access_log_impl.cc @@ -3,7 +3,6 @@ #include "envoy/upstream/upstream.h" #include "common/common/assert.h" -#include "common/http/header_map_impl.h" #include "common/network/utility.h" #include "common/stream_info/utility.h" @@ -33,64 +32,83 @@ TLSProperties_TLSVersion tlsVersionStringToEnum(const std::string& tls_version) } }; // namespace -GrpcAccessLogStreamerImpl::GrpcAccessLogStreamerImpl(Grpc::AsyncClientFactoryPtr&& factory, - ThreadLocal::SlotAllocator& tls, - const LocalInfo::LocalInfo& local_info) - : tls_slot_(tls.allocateSlot()) { - SharedStateSharedPtr shared_state = std::make_shared(std::move(factory), local_info); - tls_slot_->set([shared_state](Event::Dispatcher&) { - return ThreadLocal::ThreadLocalObjectSharedPtr{new ThreadLocalStreamer(shared_state)}; - }); -} - -void GrpcAccessLogStreamerImpl::ThreadLocalStream::onRemoteClose(Grpc::Status::GrpcStatus, - const std::string&) { - auto it = parent_.stream_map_.find(log_name_); - ASSERT(it != parent_.stream_map_.end()); - if (it->second.stream_ != nullptr) { - // Only erase if we have a stream. Otherwise we had an inline failure and we will clear the +void GrpcAccessLoggerImpl::LocalStream::onRemoteClose(Grpc::Status::GrpcStatus, + const std::string&) { + ASSERT(parent_.stream_ != absl::nullopt); + if (parent_.stream_->stream_ != nullptr) { + // Only reset if we have a stream. Otherwise we had an inline failure and we will clear the // stream data in send(). - parent_.stream_map_.erase(it); + parent_.stream_.reset(); } } -GrpcAccessLogStreamerImpl::ThreadLocalStreamer::ThreadLocalStreamer( - const SharedStateSharedPtr& shared_state) - : client_(shared_state->factory_->create()), shared_state_(shared_state) {} +GrpcAccessLoggerImpl::GrpcAccessLoggerImpl(Grpc::RawAsyncClientPtr&& client, std::string log_name, + const LocalInfo::LocalInfo& local_info) + : client_(std::move(client)), log_name_(std::move(log_name)), local_info_(local_info) {} + +void GrpcAccessLoggerImpl::log(envoy::data::accesslog::v2::HTTPAccessLogEntry&& entry) { + // TODO(euroelessar): Add batching and flushing. + envoy::service::accesslog::v2::StreamAccessLogsMessage message; + message.mutable_http_logs()->add_log_entry()->Swap(&entry); -void GrpcAccessLogStreamerImpl::ThreadLocalStreamer::send( - envoy::service::accesslog::v2::StreamAccessLogsMessage& message, const std::string& log_name) { - auto stream_it = stream_map_.find(log_name); - if (stream_it == stream_map_.end()) { - stream_it = stream_map_.emplace(log_name, ThreadLocalStream(*this, log_name)).first; + if (stream_ == absl::nullopt) { + stream_.emplace(*this); } - auto& stream_entry = stream_it->second; - if (stream_entry.stream_ == nullptr) { - stream_entry.stream_ = + if (stream_->stream_ == nullptr) { + stream_->stream_ = client_->start(*Protobuf::DescriptorPool::generated_pool()->FindMethodByName( "envoy.service.accesslog.v2.AccessLogService.StreamAccessLogs"), - stream_entry); + *stream_); auto* identifier = message.mutable_identifier(); - *identifier->mutable_node() = shared_state_->local_info_.node(); - identifier->set_log_name(log_name); + *identifier->mutable_node() = local_info_.node(); + identifier->set_log_name(log_name_); } - if (stream_entry.stream_ != nullptr) { - stream_entry.stream_->sendMessage(message, false); + if (stream_->stream_ != nullptr) { + stream_->stream_->sendMessage(message, false); } else { // Clear out the stream data due to stream creation failure. - stream_map_.erase(stream_it); + stream_.reset(); } } -HttpGrpcAccessLog::HttpGrpcAccessLog( - AccessLog::FilterPtr&& filter, - const envoy::config::accesslog::v2::HttpGrpcAccessLogConfig& config, - GrpcAccessLogStreamerSharedPtr grpc_access_log_streamer) - : filter_(std::move(filter)), config_(config), - grpc_access_log_streamer_(grpc_access_log_streamer) { +GrpcAccessLoggerCacheImpl::GrpcAccessLoggerCacheImpl(Grpc::AsyncClientManager& async_client_manager, + Stats::Scope& scope, + ThreadLocal::SlotAllocator& tls, + const LocalInfo::LocalInfo& local_info) + : async_client_manager_(async_client_manager), scope_(scope), tls_slot_(tls.allocateSlot()), + local_info_(local_info) { + tls_slot_->set([](Event::Dispatcher&) { return std::make_shared(); }); +} + +GrpcAccessLoggerSharedPtr GrpcAccessLoggerCacheImpl::getOrCreateLogger( + const envoy::config::accesslog::v2::CommonGrpcAccessLogConfig& config) { + // TODO(euroelessar): Consider cleaning up loggers. + auto& cache = tls_slot_->getTyped(); + const std::size_t cache_key = MessageUtil::hash(config); + const auto it = cache.access_loggers_.find(cache_key); + if (it != cache.access_loggers_.end()) { + return it->second; + } + const Grpc::AsyncClientFactoryPtr factory = + async_client_manager_.factoryForGrpcService(config.grpc_service(), scope_, false); + const GrpcAccessLoggerSharedPtr logger = + std::make_shared(factory->create(), config.log_name(), local_info_); + cache.access_loggers_.emplace(cache_key, logger); + return logger; +} + +HttpGrpcAccessLog::ThreadLocalLogger::ThreadLocalLogger(GrpcAccessLoggerSharedPtr logger) + : logger_(std::move(logger)) {} + +HttpGrpcAccessLog::HttpGrpcAccessLog(AccessLog::FilterPtr&& filter, + envoy::config::accesslog::v2::HttpGrpcAccessLogConfig config, + ThreadLocal::SlotAllocator& tls, + GrpcAccessLoggerCacheSharedPtr access_logger_cache) + : Common::ImplBase(std::move(filter)), config_(std::move(config)), + tls_slot_(tls.allocateSlot()), access_logger_cache_(std::move(access_logger_cache)) { for (const auto& header : config_.additional_request_headers_to_log()) { request_headers_to_log_.emplace_back(header); } @@ -102,6 +120,11 @@ HttpGrpcAccessLog::HttpGrpcAccessLog( for (const auto& header : config_.additional_response_trailers_to_log()) { response_trailers_to_log_.emplace_back(header); } + + tls_slot_->set([this](Event::Dispatcher&) { + return std::make_shared( + access_logger_cache_->getOrCreateLogger(config_.common_config())); + }); } void HttpGrpcAccessLog::responseFlagsToAccessLogResponseFlags( @@ -186,33 +209,14 @@ void HttpGrpcAccessLog::responseFlagsToAccessLogResponseFlags( } } -void HttpGrpcAccessLog::log(const Http::HeaderMap* request_headers, - const Http::HeaderMap* response_headers, - const Http::HeaderMap* response_trailers, - const StreamInfo::StreamInfo& stream_info) { - static Http::HeaderMapImpl empty_headers; - if (!request_headers) { - request_headers = &empty_headers; - } - if (!response_headers) { - response_headers = &empty_headers; - } - if (!response_trailers) { - response_trailers = &empty_headers; - } - - if (filter_) { - if (!filter_->evaluate(stream_info, *request_headers, *response_headers, *response_trailers)) { - return; - } - } - - envoy::service::accesslog::v2::StreamAccessLogsMessage message; - auto* log_entry = message.mutable_http_logs()->add_log_entry(); - +void HttpGrpcAccessLog::emitLog(const Http::HeaderMap& request_headers, + const Http::HeaderMap& response_headers, + const Http::HeaderMap& response_trailers, + const StreamInfo::StreamInfo& stream_info) { // Common log properties. // TODO(mattklein123): Populate sample_rate field. - auto* common_properties = log_entry->mutable_common_properties(); + envoy::data::accesslog::v2::HTTPAccessLogEntry log_entry; + auto* common_properties = log_entry.mutable_common_properties(); if (stream_info.downstreamRemoteAddress() != nullptr) { Network::Utility::addressToProtobufAddress( @@ -326,64 +330,63 @@ void HttpGrpcAccessLog::log(const Http::HeaderMap* request_headers, if (stream_info.protocol()) { switch (stream_info.protocol().value()) { case Http::Protocol::Http10: - log_entry->set_protocol_version(envoy::data::accesslog::v2::HTTPAccessLogEntry::HTTP10); + log_entry.set_protocol_version(envoy::data::accesslog::v2::HTTPAccessLogEntry::HTTP10); break; case Http::Protocol::Http11: - log_entry->set_protocol_version(envoy::data::accesslog::v2::HTTPAccessLogEntry::HTTP11); + log_entry.set_protocol_version(envoy::data::accesslog::v2::HTTPAccessLogEntry::HTTP11); break; case Http::Protocol::Http2: - log_entry->set_protocol_version(envoy::data::accesslog::v2::HTTPAccessLogEntry::HTTP2); + log_entry.set_protocol_version(envoy::data::accesslog::v2::HTTPAccessLogEntry::HTTP2); break; } } // HTTP request properties. // TODO(mattklein123): Populate port field. - auto* request_properties = log_entry->mutable_request(); - if (request_headers->Scheme() != nullptr) { - request_properties->set_scheme(std::string(request_headers->Scheme()->value().getStringView())); + auto* request_properties = log_entry.mutable_request(); + if (request_headers.Scheme() != nullptr) { + request_properties->set_scheme(std::string(request_headers.Scheme()->value().getStringView())); } - if (request_headers->Host() != nullptr) { - request_properties->set_authority( - std::string(request_headers->Host()->value().getStringView())); + if (request_headers.Host() != nullptr) { + request_properties->set_authority(std::string(request_headers.Host()->value().getStringView())); } - if (request_headers->Path() != nullptr) { - request_properties->set_path(std::string(request_headers->Path()->value().getStringView())); + if (request_headers.Path() != nullptr) { + request_properties->set_path(std::string(request_headers.Path()->value().getStringView())); } - if (request_headers->UserAgent() != nullptr) { + if (request_headers.UserAgent() != nullptr) { request_properties->set_user_agent( - std::string(request_headers->UserAgent()->value().getStringView())); + std::string(request_headers.UserAgent()->value().getStringView())); } - if (request_headers->Referer() != nullptr) { + if (request_headers.Referer() != nullptr) { request_properties->set_referer( - std::string(request_headers->Referer()->value().getStringView())); + std::string(request_headers.Referer()->value().getStringView())); } - if (request_headers->ForwardedFor() != nullptr) { + if (request_headers.ForwardedFor() != nullptr) { request_properties->set_forwarded_for( - std::string(request_headers->ForwardedFor()->value().getStringView())); + std::string(request_headers.ForwardedFor()->value().getStringView())); } - if (request_headers->RequestId() != nullptr) { + if (request_headers.RequestId() != nullptr) { request_properties->set_request_id( - std::string(request_headers->RequestId()->value().getStringView())); + std::string(request_headers.RequestId()->value().getStringView())); } - if (request_headers->EnvoyOriginalPath() != nullptr) { + if (request_headers.EnvoyOriginalPath() != nullptr) { request_properties->set_original_path( - std::string(request_headers->EnvoyOriginalPath()->value().getStringView())); + std::string(request_headers.EnvoyOriginalPath()->value().getStringView())); } - request_properties->set_request_headers_bytes(request_headers->byteSize()); + request_properties->set_request_headers_bytes(request_headers.byteSize()); request_properties->set_request_body_bytes(stream_info.bytesReceived()); - if (request_headers->Method() != nullptr) { + if (request_headers.Method() != nullptr) { envoy::api::v2::core::RequestMethod method = envoy::api::v2::core::RequestMethod::METHOD_UNSPECIFIED; envoy::api::v2::core::RequestMethod_Parse( - std::string(request_headers->Method()->value().getStringView()), &method); + std::string(request_headers.Method()->value().getStringView()), &method); request_properties->set_request_method(method); } if (!request_headers_to_log_.empty()) { auto* logged_headers = request_properties->mutable_request_headers(); for (const auto& header : request_headers_to_log_) { - const Http::HeaderEntry* entry = request_headers->get(header); + const Http::HeaderEntry* entry = request_headers.get(header); if (entry != nullptr) { logged_headers->insert({header.get(), std::string(entry->value().getStringView())}); } @@ -391,20 +394,20 @@ void HttpGrpcAccessLog::log(const Http::HeaderMap* request_headers, } // HTTP response properties. - auto* response_properties = log_entry->mutable_response(); + auto* response_properties = log_entry.mutable_response(); if (stream_info.responseCode()) { response_properties->mutable_response_code()->set_value(stream_info.responseCode().value()); } if (stream_info.responseCodeDetails()) { response_properties->set_response_code_details(stream_info.responseCodeDetails().value()); } - response_properties->set_response_headers_bytes(response_headers->byteSize()); + response_properties->set_response_headers_bytes(response_headers.byteSize()); response_properties->set_response_body_bytes(stream_info.bytesSent()); if (!response_headers_to_log_.empty()) { auto* logged_headers = response_properties->mutable_response_headers(); for (const auto& header : response_headers_to_log_) { - const Http::HeaderEntry* entry = response_headers->get(header); + const Http::HeaderEntry* entry = response_headers.get(header); if (entry != nullptr) { logged_headers->insert({header.get(), std::string(entry->value().getStringView())}); } @@ -415,15 +418,14 @@ void HttpGrpcAccessLog::log(const Http::HeaderMap* request_headers, auto* logged_headers = response_properties->mutable_response_trailers(); for (const auto& header : response_trailers_to_log_) { - const Http::HeaderEntry* entry = response_trailers->get(header); + const Http::HeaderEntry* entry = response_trailers.get(header); if (entry != nullptr) { logged_headers->insert({header.get(), std::string(entry->value().getStringView())}); } } } - // TODO(mattklein123): Consider batching multiple logs and flushing. - grpc_access_log_streamer_->send(message, config_.common_config().log_name()); + tls_slot_->getTyped().logger_->log(std::move(log_entry)); } } // namespace HttpGrpc diff --git a/source/extensions/access_loggers/http_grpc/grpc_access_log_impl.h b/source/extensions/access_loggers/http_grpc/grpc_access_log_impl.h index e8c6acde5e19..c846be0ca171 100644 --- a/source/extensions/access_loggers/http_grpc/grpc_access_log_impl.h +++ b/source/extensions/access_loggers/http_grpc/grpc_access_log_impl.h @@ -3,7 +3,6 @@ #include #include -#include "envoy/access_log/access_log.h" #include "envoy/config/accesslog/v2/als.pb.h" #include "envoy/config/filter/accesslog/v2/accesslog.pb.h" #include "envoy/grpc/async_client.h" @@ -15,6 +14,8 @@ #include "common/grpc/typed_async_client.h" +#include "extensions/access_loggers/common/access_log_base.h" + namespace Envoy { namespace Extensions { namespace AccessLoggers { @@ -23,63 +24,52 @@ namespace HttpGrpc { // TODO(mattklein123): Stats /** - * Interface for an access log streamer. The streamer deals with threading and sends access logs - * on the correct stream. + * Interface for an access logger. The logger provides abstraction on top of gRPC stream, deals with + * reconnects and performs batching. */ -class GrpcAccessLogStreamer { +class GrpcAccessLogger { public: - virtual ~GrpcAccessLogStreamer() = default; + virtual ~GrpcAccessLogger() = default; /** - * Send an access log. - * @param message supplies the access log to send. - * @param log_name supplies the name of the log stream to send on. + * Log http access entry. + * @param entry supplies the access log to send. */ - virtual void send(envoy::service::accesslog::v2::StreamAccessLogsMessage& message, - const std::string& log_name) PURE; + virtual void log(envoy::data::accesslog::v2::HTTPAccessLogEntry&& entry) PURE; }; -using GrpcAccessLogStreamerSharedPtr = std::shared_ptr; +using GrpcAccessLoggerSharedPtr = std::shared_ptr; /** - * Production implementation of GrpcAccessLogStreamer that supports per-thread and per-log - * streams. + * Interface for an access logger cache. The cache deals with threading and de-duplicates loggers + * for the same configuration. */ -class GrpcAccessLogStreamerImpl : public Singleton::Instance, public GrpcAccessLogStreamer { +class GrpcAccessLoggerCache { public: - GrpcAccessLogStreamerImpl(Grpc::AsyncClientFactoryPtr&& factory, ThreadLocal::SlotAllocator& tls, - const LocalInfo::LocalInfo& local_info); - - // GrpcAccessLogStreamer - void send(envoy::service::accesslog::v2::StreamAccessLogsMessage& message, - const std::string& log_name) override { - tls_slot_->getTyped().send(message, log_name); - } + virtual ~GrpcAccessLoggerCache() = default; -private: /** - * Shared state that is owned by the per-thread streamers. This allows the main streamer/TLS - * slot to be destroyed while the streamers hold onto the shared state. + * Get existing logger or create a new one for the given configuration. + * @param config supplies the configuration for the logger. + * @return GrpcAccessLoggerSharedPtr ready for logging requests. */ - struct SharedState { - SharedState(Grpc::AsyncClientFactoryPtr&& factory, const LocalInfo::LocalInfo& local_info) - : factory_(std::move(factory)), local_info_(local_info) {} + virtual GrpcAccessLoggerSharedPtr + getOrCreateLogger(const ::envoy::config::accesslog::v2::CommonGrpcAccessLogConfig& config) PURE; +}; - Grpc::AsyncClientFactoryPtr factory_; - const LocalInfo::LocalInfo& local_info_; - }; +using GrpcAccessLoggerCacheSharedPtr = std::shared_ptr; - using SharedStateSharedPtr = std::shared_ptr; +class GrpcAccessLoggerImpl : public GrpcAccessLogger { +public: + GrpcAccessLoggerImpl(Grpc::RawAsyncClientPtr&& client, std::string log_name, + const LocalInfo::LocalInfo& local_info); - struct ThreadLocalStreamer; + void log(envoy::data::accesslog::v2::HTTPAccessLogEntry&& entry) override; - /** - * Per-thread stream state. - */ - struct ThreadLocalStream +private: + struct LocalStream : public Grpc::AsyncStreamCallbacks { - ThreadLocalStream(ThreadLocalStreamer& parent, const std::string& log_name) - : parent_(parent), log_name_(log_name) {} + LocalStream(GrpcAccessLoggerImpl& parent) : parent_(parent) {} // Grpc::AsyncStreamCallbacks void onCreateInitialMetadata(Http::HeaderMap&) override {} @@ -89,51 +79,74 @@ class GrpcAccessLogStreamerImpl : public Singleton::Instance, public GrpcAccessL void onReceiveTrailingMetadata(Http::HeaderMapPtr&&) override {} void onRemoteClose(Grpc::Status::GrpcStatus status, const std::string& message) override; - ThreadLocalStreamer& parent_; - const std::string log_name_; + GrpcAccessLoggerImpl& parent_; Grpc::AsyncStream stream_{}; }; + Grpc::AsyncClient + client_; + const std::string log_name_; + absl::optional stream_; + const LocalInfo::LocalInfo& local_info_; +}; + +class GrpcAccessLoggerCacheImpl : public Singleton::Instance, public GrpcAccessLoggerCache { +public: + GrpcAccessLoggerCacheImpl(Grpc::AsyncClientManager& async_client_manager, Stats::Scope& scope, + ThreadLocal::SlotAllocator& tls, + const LocalInfo::LocalInfo& local_info); + + GrpcAccessLoggerSharedPtr getOrCreateLogger( + const ::envoy::config::accesslog::v2::CommonGrpcAccessLogConfig& config) override; + +private: /** - * Per-thread multi-stream state. + * Per-thread cache. */ - struct ThreadLocalStreamer : public ThreadLocal::ThreadLocalObject { - ThreadLocalStreamer(const SharedStateSharedPtr& shared_state); - void send(envoy::service::accesslog::v2::StreamAccessLogsMessage& message, - const std::string& log_name); - - Grpc::AsyncClient - client_; - std::unordered_map stream_map_; - SharedStateSharedPtr shared_state_; + struct ThreadLocalCache : public ThreadLocal::ThreadLocalObject { + // Access loggers indexed by the hash of logger's configuration. + absl::flat_hash_map access_loggers_; }; + Grpc::AsyncClientManager& async_client_manager_; + Stats::Scope& scope_; ThreadLocal::SlotPtr tls_slot_; + const LocalInfo::LocalInfo& local_info_; }; /** * Access log Instance that streams HTTP logs over gRPC. */ -class HttpGrpcAccessLog : public AccessLog::Instance { +class HttpGrpcAccessLog : public Common::ImplBase { public: HttpGrpcAccessLog(AccessLog::FilterPtr&& filter, - const envoy::config::accesslog::v2::HttpGrpcAccessLogConfig& config, - GrpcAccessLogStreamerSharedPtr grpc_access_log_streamer); + envoy::config::accesslog::v2::HttpGrpcAccessLogConfig config, + ThreadLocal::SlotAllocator& tls, + GrpcAccessLoggerCacheSharedPtr access_logger_cache); static void responseFlagsToAccessLogResponseFlags( envoy::data::accesslog::v2::AccessLogCommon& common_access_log, const StreamInfo::StreamInfo& stream_info); - // AccessLog::Instance - void log(const Http::HeaderMap* request_headers, const Http::HeaderMap* response_headers, - const Http::HeaderMap* response_trailers, - const StreamInfo::StreamInfo& stream_info) override; - private: - AccessLog::FilterPtr filter_; + /** + * Per-thread cached logger. + */ + struct ThreadLocalLogger : public ThreadLocal::ThreadLocalObject { + ThreadLocalLogger(GrpcAccessLoggerSharedPtr logger); + + const GrpcAccessLoggerSharedPtr logger_; + }; + + // Common::ImplBase + void emitLog(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, + const Http::HeaderMap& response_trailers, + const StreamInfo::StreamInfo& stream_info) override; + const envoy::config::accesslog::v2::HttpGrpcAccessLogConfig config_; - GrpcAccessLogStreamerSharedPtr grpc_access_log_streamer_; + const ThreadLocal::SlotPtr tls_slot_; + const GrpcAccessLoggerCacheSharedPtr access_logger_cache_; std::vector request_headers_to_log_; std::vector response_headers_to_log_; std::vector response_trailers_to_log_; diff --git a/source/extensions/clusters/dynamic_forward_proxy/cluster.cc b/source/extensions/clusters/dynamic_forward_proxy/cluster.cc index 37bfa8f6f5b5..44efc1b24f31 100644 --- a/source/extensions/clusters/dynamic_forward_proxy/cluster.cc +++ b/source/extensions/clusters/dynamic_forward_proxy/cluster.cc @@ -84,10 +84,10 @@ void Cluster::onDnsHostAddOrUpdate( // Create an override transport socket options that automatically provides both SNI as well as // SAN verification for the resolved host if the cluster has been configured with TLS. - // TODO(mattklein123): If the host is an IP address we should not set SNI. Network::TransportSocketOptionsSharedPtr transport_socket_options = std::make_shared( - host_info->resolvedHost(), std::vector{host_info->resolvedHost()}); + !host_info->isIpAddress() ? host_info->resolvedHost() : "", + std::vector{host_info->resolvedHost()}); const auto new_host_map = std::make_shared(*current_map); const auto emplaced = diff --git a/source/extensions/common/dynamic_forward_proxy/dns_cache.h b/source/extensions/common/dynamic_forward_proxy/dns_cache.h index 3a0fb4580ef3..b01cc478f660 100644 --- a/source/extensions/common/dynamic_forward_proxy/dns_cache.h +++ b/source/extensions/common/dynamic_forward_proxy/dns_cache.h @@ -29,6 +29,11 @@ class DnsHostInfo { */ virtual const std::string& resolvedHost() PURE; + /** + * Returns whether the original host is an IP address. + */ + virtual bool isIpAddress() PURE; + /** * Indicates that the host has been used and should not be purged depending on any configured * TTL policy diff --git a/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.cc b/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.cc index 0e9a978ff40f..bd206039920d 100644 --- a/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.cc +++ b/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.cc @@ -79,34 +79,54 @@ void DnsCacheImpl::startCacheLoad(const std::string& host, uint16_t default_port return; } - // TODO(mattklein123): Figure out if we want to support addresses of the form :. This - // seems unlikely to be useful in TLS scenarios, but it is technically - // supported. We might want to block this form for now. - const auto colon_pos = host.find(':'); + // First try to see if there is a port included. This also checks to see that there is not a ']' + // as the last character which is indicative of an IPv6 address without a port. This is a best + // effort attempt. + const auto colon_pos = host.rfind(':'); absl::string_view host_to_resolve = host; - if (colon_pos != absl::string_view::npos) { + if (colon_pos != absl::string_view::npos && host_to_resolve.back() != ']') { const absl::string_view string_view_host = host; host_to_resolve = string_view_host.substr(0, colon_pos); const auto port_str = string_view_host.substr(colon_pos + 1); uint64_t port64; if (port_str.empty() || !absl::SimpleAtoi(port_str, &port64) || port64 > 65535) { // Just attempt to resolve whatever we were given. This will very likely fail. - // TODO(mattklein123): Should we actually fail here or do something different? host_to_resolve = host; } else { default_port = port64; } } + // Now see if this is an IP address. We need to know this because some things (such as setting + // SNI) are special cased if this is an IP address. Either way, we still go through the normal + // resolver flow. We could short-circuit the DNS resolver in this case, but the extra code to do + // so is not worth it since the DNS resolver should handle it for us. + bool is_ip_address = false; + try { + absl::string_view potential_ip_address = host_to_resolve; + // TODO(mattklein123): Optimally we would support bracket parsing in parseInternetAddress(), + // but we still need to trim the brackets to send the IPv6 address into the DNS resolver. For + // now, just do all the trimming here, but in the future we should consider whether we can + // have unified [] handling as low as possible in the stack. + if (potential_ip_address.front() == '[' && potential_ip_address.back() == ']') { + potential_ip_address.remove_prefix(1); + potential_ip_address.remove_suffix(1); + } + Network::Utility::parseInternetAddress(std::string(potential_ip_address)); + is_ip_address = true; + host_to_resolve = potential_ip_address; + } catch (const EnvoyException&) { + } + // TODO(mattklein123): Right now, the same host with different ports will become two // independent primary hosts with independent DNS resolutions. I'm not sure how much this will // matter, but we could consider collapsing these down and sharing the underlying DNS resolution. auto& primary_host = *primary_hosts_ // try_emplace() is used here for direct argument forwarding. - .try_emplace(host, - std::make_unique(*this, host_to_resolve, default_port, - [this, host]() { onReResolve(host); })) + .try_emplace(host, std::make_unique( + *this, host_to_resolve, default_port, is_ip_address, + [this, host]() { onReResolve(host); })) .first->second; startResolve(host, primary_host); } @@ -244,11 +264,11 @@ void DnsCacheImpl::ThreadLocalHostInfo::updateHostMap(const TlsHostMapSharedPtr& DnsCacheImpl::PrimaryHostInfo::PrimaryHostInfo(DnsCacheImpl& parent, absl::string_view host_to_resolve, uint16_t port, - const Event::TimerCb& timer_cb) + bool is_ip_address, const Event::TimerCb& timer_cb) : parent_(parent), port_(port), refresh_timer_(parent.main_thread_dispatcher_.createTimer(timer_cb)), host_info_(std::make_shared(parent.main_thread_dispatcher_.timeSource(), - host_to_resolve)) { + host_to_resolve, is_ip_address)) { parent_.stats_.host_added_.inc(); parent_.stats_.num_hosts_.inc(); } diff --git a/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.h b/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.h index 440617b61c70..32c887f2284e 100644 --- a/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.h +++ b/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.h @@ -39,7 +39,7 @@ class DnsCacheImpl : public DnsCache, Logger::Loggable& timeout, bool use_alpha); - ~GrpcClientImpl(); + ~GrpcClientImpl() override; // ExtAuthz::Client void cancel() override; diff --git a/source/extensions/filters/common/ext_authz/ext_authz_http_impl.h b/source/extensions/filters/common/ext_authz/ext_authz_http_impl.h index 376ccdc64c70..a26d5e4532f4 100644 --- a/source/extensions/filters/common/ext_authz/ext_authz_http_impl.h +++ b/source/extensions/filters/common/ext_authz/ext_authz_http_impl.h @@ -129,7 +129,7 @@ class RawHttpClientImpl : public Client, Logger::Loggable { public: explicit RawHttpClientImpl(Upstream::ClusterManager& cm, ClientConfigSharedPtr config); - ~RawHttpClientImpl(); + ~RawHttpClientImpl() override; // ExtAuthz::Client void cancel() override; diff --git a/source/extensions/filters/common/original_src/original_src_socket_option.h b/source/extensions/filters/common/original_src/original_src_socket_option.h index 2659354d8598..3e428bf9b329 100644 --- a/source/extensions/filters/common/original_src/original_src_socket_option.h +++ b/source/extensions/filters/common/original_src/original_src_socket_option.h @@ -18,7 +18,7 @@ class OriginalSrcSocketOption : public Network::Socket::Option { * Constructs a socket option which will set the socket to use source @c src_address */ OriginalSrcSocketOption(Network::Address::InstanceConstSharedPtr src_address); - ~OriginalSrcSocketOption() {} + ~OriginalSrcSocketOption() override = default; /** * Updates the source address of the socket to match `src_address_`. diff --git a/source/extensions/filters/common/ratelimit/BUILD b/source/extensions/filters/common/ratelimit/BUILD index 6b0c197a810d..9d39e1980093 100644 --- a/source/extensions/filters/common/ratelimit/BUILD +++ b/source/extensions/filters/common/ratelimit/BUILD @@ -39,6 +39,15 @@ envoy_cc_library( "//include/envoy/ratelimit:ratelimit_interface", "//include/envoy/singleton:manager_interface", "//include/envoy/tracing:http_tracer_interface", + "//source/common/stats:symbol_table_lib", "@envoy_api//envoy/config/ratelimit/v2:rls_cc", ], ) + +envoy_cc_library( + name = "stat_names_lib", + hdrs = ["stat_names.h"], + deps = [ + "//source/common/stats:symbol_table_lib", + ], +) diff --git a/source/extensions/filters/common/ratelimit/ratelimit_impl.h b/source/extensions/filters/common/ratelimit/ratelimit_impl.h index 11ca4c4396b0..fcd4cb520b1d 100644 --- a/source/extensions/filters/common/ratelimit/ratelimit_impl.h +++ b/source/extensions/filters/common/ratelimit/ratelimit_impl.h @@ -47,7 +47,7 @@ class GrpcClientImpl : public Client, public: GrpcClientImpl(Grpc::RawAsyncClientPtr&& async_client, const absl::optional& timeout); - ~GrpcClientImpl(); + ~GrpcClientImpl() override; static void createRequest(envoy::service::ratelimit::v2::RateLimitRequest& request, const std::string& domain, diff --git a/source/extensions/filters/common/ratelimit/stat_names.h b/source/extensions/filters/common/ratelimit/stat_names.h new file mode 100644 index 000000000000..33dd13a188b3 --- /dev/null +++ b/source/extensions/filters/common/ratelimit/stat_names.h @@ -0,0 +1,30 @@ +#pragma once + +#include "common/stats/symbol_table_impl.h" + +namespace Envoy { +namespace Extensions { +namespace Filters { +namespace Common { +namespace RateLimit { + +// Captures a set of stat-names needed for recording during rate-limit +// filters. These should generally be initialized once per process, and +// not per-request, to avoid lock contention. +struct StatNames { + explicit StatNames(Stats::SymbolTable& symbol_table) + : pool_(symbol_table), ok_(pool_.add("ratelimit.ok")), error_(pool_.add("ratelimit.error")), + failure_mode_allowed_(pool_.add("ratelimit.failure_mode_allowed")), + over_limit_(pool_.add("ratelimit.over_limit")) {} + Stats::StatNamePool pool_; + Stats::StatName ok_; + Stats::StatName error_; + Stats::StatName failure_mode_allowed_; + Stats::StatName over_limit_; +}; + +} // namespace RateLimit +} // namespace Common +} // namespace Filters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/http/common/aws/credentials_provider_impl.h b/source/extensions/filters/http/common/aws/credentials_provider_impl.h index 31e4d25d5d87..5f9b3816cfe0 100644 --- a/source/extensions/filters/http/common/aws/credentials_provider_impl.h +++ b/source/extensions/filters/http/common/aws/credentials_provider_impl.h @@ -98,7 +98,7 @@ class TaskRoleCredentialsProvider : public MetadataCredentialsProviderBase { class CredentialsProviderChain : public CredentialsProvider, public Logger::Loggable { public: - virtual ~CredentialsProviderChain() = default; + ~CredentialsProviderChain() override = default; void add(const CredentialsProviderSharedPtr& credentials_provider) { providers_.emplace_back(credentials_provider); diff --git a/source/extensions/filters/http/common/jwks_fetcher.cc b/source/extensions/filters/http/common/jwks_fetcher.cc index d5c7a6c26d90..0eba021cf41e 100644 --- a/source/extensions/filters/http/common/jwks_fetcher.cc +++ b/source/extensions/filters/http/common/jwks_fetcher.cc @@ -18,9 +18,9 @@ class JwksFetcherImpl : public JwksFetcher, public: JwksFetcherImpl(Upstream::ClusterManager& cm) : cm_(cm) { ENVOY_LOG(trace, "{}", __func__); } - ~JwksFetcherImpl() { cancel(); } + ~JwksFetcherImpl() override { cancel(); } - void cancel() { + void cancel() override { if (request_ && !complete_) { request_->cancel(); ENVOY_LOG(debug, "fetch pubkey [uri = {}]: canceled", uri_->uri()); @@ -28,7 +28,8 @@ class JwksFetcherImpl : public JwksFetcher, reset(); } - void fetch(const ::envoy::api::v2::core::HttpUri& uri, JwksFetcher::JwksReceiver& receiver) { + void fetch(const ::envoy::api::v2::core::HttpUri& uri, + JwksFetcher::JwksReceiver& receiver) override { ENVOY_LOG(trace, "{}", __func__); ASSERT(!receiver_); complete_ = false; @@ -44,7 +45,7 @@ class JwksFetcherImpl : public JwksFetcher, } // HTTP async receive methods - void onSuccess(Http::MessagePtr&& response) { + void onSuccess(Http::MessagePtr&& response) override { ENVOY_LOG(trace, "{}", __func__); complete_ = true; const uint64_t status_code = Http::Utility::getResponseStatus(response->headers()); @@ -74,7 +75,7 @@ class JwksFetcherImpl : public JwksFetcher, reset(); } - void onFailure(Http::AsyncClient::FailureReason reason) { + void onFailure(Http::AsyncClient::FailureReason reason) override { ENVOY_LOG(debug, "{}: fetch pubkey [uri = {}]: network error {}", __func__, uri_->uri(), enumToInt(reason)); complete_ = true; diff --git a/source/extensions/filters/http/dynamo/BUILD b/source/extensions/filters/http/dynamo/BUILD index e1ba97728475..048be9323395 100644 --- a/source/extensions/filters/http/dynamo/BUILD +++ b/source/extensions/filters/http/dynamo/BUILD @@ -17,7 +17,7 @@ envoy_cc_library( hdrs = ["dynamo_filter.h"], deps = [ ":dynamo_request_parser_lib", - ":dynamo_utility_lib", + ":dynamo_stats_lib", "//include/envoy/http:filter_interface", "//include/envoy/runtime:runtime_interface", "//source/common/buffer:buffer_lib", @@ -37,16 +37,6 @@ envoy_cc_library( ], ) -envoy_cc_library( - name = "dynamo_utility_lib", - srcs = ["dynamo_utility.cc"], - hdrs = ["dynamo_utility.h"], - deps = [ - "//include/envoy/stats:stats_interface", - "//source/common/stats:stats_lib", - ], -) - envoy_cc_library( name = "config", srcs = ["config.cc"], @@ -59,3 +49,14 @@ envoy_cc_library( "//source/extensions/filters/http/common:empty_http_filter_config_lib", ], ) + +envoy_cc_library( + name = "dynamo_stats_lib", + srcs = ["dynamo_stats.cc"], + hdrs = ["dynamo_stats.h"], + deps = [ + ":dynamo_request_parser_lib", + "//include/envoy/stats:stats_interface", + "//source/common/stats:symbol_table_lib", + ], +) diff --git a/source/extensions/filters/http/dynamo/config.cc b/source/extensions/filters/http/dynamo/config.cc index 7355e46760f6..77dde48be63c 100644 --- a/source/extensions/filters/http/dynamo/config.cc +++ b/source/extensions/filters/http/dynamo/config.cc @@ -5,6 +5,7 @@ #include "envoy/registry/registry.h" #include "extensions/filters/http/dynamo/dynamo_filter.h" +#include "extensions/filters/http/dynamo/dynamo_stats.h" namespace Envoy { namespace Extensions { @@ -14,9 +15,10 @@ namespace Dynamo { Http::FilterFactoryCb DynamoFilterConfig::createFilter(const std::string& stat_prefix, Server::Configuration::FactoryContext& context) { - return [&context, stat_prefix](Http::FilterChainFactoryCallbacks& callbacks) -> void { - callbacks.addStreamFilter(Http::StreamFilterSharedPtr{new Dynamo::DynamoFilter( - context.runtime(), stat_prefix, context.scope(), context.dispatcher().timeSource())}); + auto stats = std::make_shared(context.scope(), stat_prefix); + return [&context, stat_prefix, stats](Http::FilterChainFactoryCallbacks& callbacks) -> void { + callbacks.addStreamFilter(std::make_shared( + context.runtime(), stats, context.dispatcher().timeSource())); }; } diff --git a/source/extensions/filters/http/dynamo/dynamo_filter.cc b/source/extensions/filters/http/dynamo/dynamo_filter.cc index cb7ee4c35702..c9072aaf5b1a 100644 --- a/source/extensions/filters/http/dynamo/dynamo_filter.cc +++ b/source/extensions/filters/http/dynamo/dynamo_filter.cc @@ -15,7 +15,7 @@ #include "common/json/json_loader.h" #include "extensions/filters/http/dynamo/dynamo_request_parser.h" -#include "extensions/filters/http/dynamo/dynamo_utility.h" +#include "extensions/filters/http/dynamo/dynamo_stats.h" namespace Envoy { namespace Extensions { @@ -62,7 +62,7 @@ void DynamoFilter::onDecodeComplete(const Buffer::Instance& data) { table_descriptor_ = RequestParser::parseTable(operation_, *json_body); } catch (const Json::Exception& jsonEx) { // Body parsing failed. This should not happen, just put a stat for that. - scope_.counter(fmt::format("{}invalid_req_body", stat_prefix_)).inc(); + stats_->counter({stats_->invalid_req_body_}).inc(); } } } @@ -89,7 +89,7 @@ void DynamoFilter::onEncodeComplete(const Buffer::Instance& data) { } } catch (const Json::Exception&) { // Body parsing failed. This should not happen, just put a stat for that. - scope_.counter(fmt::format("{}invalid_resp_body", stat_prefix_)).inc(); + stats_->counter({stats_->invalid_resp_body_}).inc(); } } } @@ -158,15 +158,15 @@ void DynamoFilter::chargeBasicStats(uint64_t status) { if (!operation_.empty()) { chargeStatsPerEntity(operation_, "operation", status); } else { - scope_.counter(fmt::format("{}operation_missing", stat_prefix_)).inc(); + stats_->counter({stats_->operation_missing_}).inc(); } if (!table_descriptor_.table_name.empty()) { chargeStatsPerEntity(table_descriptor_.table_name, "table", status); } else if (table_descriptor_.is_single_table) { - scope_.counter(fmt::format("{}table_missing", stat_prefix_)).inc(); + stats_->counter({stats_->table_missing_}).inc(); } else { - scope_.counter(fmt::format("{}multiple_tables", stat_prefix_)).inc(); + stats_->counter({stats_->multiple_tables_}).inc(); } } @@ -175,29 +175,23 @@ void DynamoFilter::chargeStatsPerEntity(const std::string& entity, const std::st std::chrono::milliseconds latency = std::chrono::duration_cast( time_source_.monotonicTime() - start_decode_); - std::string group_string = - Http::CodeUtility::groupStringForResponseCode(static_cast(status)); + size_t group_index = DynamoStats::groupIndex(status); + const Stats::StatName entity_type_name = stats_->getStatName(entity_type); + const Stats::StatName entity_name = stats_->getStatName(entity); + const Stats::StatName total_name = + stats_->getStatName(absl::StrCat("upstream_rq_total_", status)); + const Stats::StatName time_name = stats_->getStatName(absl::StrCat("upstream_rq_time_", status)); - scope_.counter(fmt::format("{}{}.{}.upstream_rq_total", stat_prefix_, entity_type, entity)).inc(); - scope_ - .counter(fmt::format("{}{}.{}.upstream_rq_total_{}", stat_prefix_, entity_type, entity, - group_string)) - .inc(); - scope_ - .counter(fmt::format("{}{}.{}.upstream_rq_total_{}", stat_prefix_, entity_type, entity, - std::to_string(status))) - .inc(); + stats_->counter({entity_type_name, entity_name, stats_->upstream_rq_total_}).inc(); + const Stats::StatName total_group = stats_->upstream_rq_total_groups_[group_index]; + stats_->counter({entity_type_name, entity_name, total_group}).inc(); + stats_->counter({entity_type_name, entity_name, total_name}).inc(); - scope_.histogram(fmt::format("{}{}.{}.upstream_rq_time", stat_prefix_, entity_type, entity)) - .recordValue(latency.count()); - scope_ - .histogram(fmt::format("{}{}.{}.upstream_rq_time_{}", stat_prefix_, entity_type, entity, - group_string)) - .recordValue(latency.count()); - scope_ - .histogram(fmt::format("{}{}.{}.upstream_rq_time_{}", stat_prefix_, entity_type, entity, - std::to_string(status))) + stats_->histogram({entity_type_name, entity_name, stats_->upstream_rq_time_}) .recordValue(latency.count()); + const Stats::StatName time_group = stats_->upstream_rq_time_groups_[group_index]; + stats_->histogram({entity_type_name, entity_name, time_group}).recordValue(latency.count()); + stats_->histogram({entity_type_name, entity_name, time_name}).recordValue(latency.count()); } void DynamoFilter::chargeUnProcessedKeysStats(const Json::Object& json_body) { @@ -205,9 +199,9 @@ void DynamoFilter::chargeUnProcessedKeysStats(const Json::Object& json_body) { // complete apart of the batch operation. Only the table names will be logged for errors. std::vector unprocessed_tables = RequestParser::parseBatchUnProcessedKeys(json_body); for (const std::string& unprocessed_table : unprocessed_tables) { - scope_ - .counter( - fmt::format("{}error.{}.BatchFailureUnprocessedKeys", stat_prefix_, unprocessed_table)) + stats_ + ->counter({stats_->error_, stats_->getStatName(unprocessed_table), + stats_->batch_failure_unprocessed_keys_}) .inc(); } } @@ -217,15 +211,15 @@ void DynamoFilter::chargeFailureSpecificStats(const Json::Object& json_body) { if (!error_type.empty()) { if (table_descriptor_.table_name.empty()) { - scope_.counter(fmt::format("{}error.no_table.{}", stat_prefix_, error_type)).inc(); + stats_->counter({stats_->error_, stats_->no_table_, stats_->getStatName(error_type)}).inc(); } else { - scope_ - .counter( - fmt::format("{}error.{}.{}", stat_prefix_, table_descriptor_.table_name, error_type)) + stats_ + ->counter({stats_->error_, stats_->getStatName(table_descriptor_.table_name), + stats_->getStatName(error_type)}) .inc(); } } else { - scope_.counter(fmt::format("{}empty_response_body", stat_prefix_)).inc(); + stats_->counter({stats_->empty_response_body_}).inc(); } } @@ -237,9 +231,10 @@ void DynamoFilter::chargeTablePartitionIdStats(const Json::Object& json_body) { std::vector partitions = RequestParser::parsePartitions(json_body); for (const RequestParser::PartitionDescriptor& partition : partitions) { - std::string scope_string = Utility::buildPartitionStatString( - stat_prefix_, table_descriptor_.table_name, operation_, partition.partition_id_); - scope_.counter(scope_string).add(partition.capacity_); + stats_ + ->buildPartitionStatCounter(table_descriptor_.table_name, operation_, + partition.partition_id_) + .add(partition.capacity_); } } diff --git a/source/extensions/filters/http/dynamo/dynamo_filter.h b/source/extensions/filters/http/dynamo/dynamo_filter.h index 3de6e378db1f..8702444a1150 100644 --- a/source/extensions/filters/http/dynamo/dynamo_filter.h +++ b/source/extensions/filters/http/dynamo/dynamo_filter.h @@ -10,6 +10,7 @@ #include "common/json/json_loader.h" #include "extensions/filters/http/dynamo/dynamo_request_parser.h" +#include "extensions/filters/http/dynamo/dynamo_stats.h" namespace Envoy { namespace Extensions { @@ -24,10 +25,8 @@ namespace Dynamo { */ class DynamoFilter : public Http::StreamFilter { public: - DynamoFilter(Runtime::Loader& runtime, const std::string& stat_prefix, Stats::Scope& scope, - TimeSource& time_system) - : runtime_(runtime), stat_prefix_(stat_prefix + "dynamodb."), scope_(scope), - time_source_(time_system) { + DynamoFilter(Runtime::Loader& runtime, const DynamoStatsSharedPtr& stats, TimeSource& time_source) + : runtime_(runtime), stats_(stats), time_source_(time_source) { enabled_ = runtime_.snapshot().featureEnabled("dynamodb.filter_enabled", 100); } @@ -68,8 +67,7 @@ class DynamoFilter : public Http::StreamFilter { void chargeTablePartitionIdStats(const Json::Object& json_body); Runtime::Loader& runtime_; - std::string stat_prefix_; - Stats::Scope& scope_; + const DynamoStatsSharedPtr stats_; bool enabled_{}; std::string operation_{}; diff --git a/source/extensions/filters/http/dynamo/dynamo_request_parser.cc b/source/extensions/filters/http/dynamo/dynamo_request_parser.cc index 3ec282c78428..357357f067eb 100644 --- a/source/extensions/filters/http/dynamo/dynamo_request_parser.cc +++ b/source/extensions/filters/http/dynamo/dynamo_request_parser.cc @@ -186,6 +186,24 @@ RequestParser::parsePartitions(const Json::Object& json_data) { return partition_descriptors; } +void RequestParser::forEachStatString(const StringFn& fn) { + for (const std::string& str : SINGLE_TABLE_OPERATIONS) { + fn(str); + } + for (const std::string& str : SUPPORTED_ERROR_TYPES) { + fn(str); + } + for (const std::string& str : BATCH_OPERATIONS) { + fn(str); + } + for (const std::string& str : TRANSACT_OPERATIONS) { + fn(str); + } + for (const std::string& str : TRANSACT_ITEM_OPERATIONS) { + fn(str); + } +} + } // namespace Dynamo } // namespace HttpFilters } // namespace Extensions diff --git a/source/extensions/filters/http/dynamo/dynamo_request_parser.h b/source/extensions/filters/http/dynamo/dynamo_request_parser.h index e913e740e2b5..8c63b32fd641 100644 --- a/source/extensions/filters/http/dynamo/dynamo_request_parser.h +++ b/source/extensions/filters/http/dynamo/dynamo_request_parser.h @@ -97,6 +97,17 @@ class RequestParser { */ static std::vector parsePartitions(const Json::Object& json_data); + using StringFn = std::function; + + /** + * Calls a function for every string that is likely to be included as a token + * in a stat. This is not functionally necessary, but can reduce potentially + * contented access to create entries in the symbol table in the hot path. + * + * @param fn the function to call for every potential stat name. + */ + static void forEachStatString(const StringFn& fn); + private: static const Http::LowerCaseString X_AMZ_TARGET; static const std::vector SINGLE_TABLE_OPERATIONS; @@ -107,7 +118,7 @@ class RequestParser { // http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.Errors.html static const std::vector SUPPORTED_ERROR_TYPES; - RequestParser() {} + RequestParser() = default; }; } // namespace Dynamo diff --git a/source/extensions/filters/http/dynamo/dynamo_stats.cc b/source/extensions/filters/http/dynamo/dynamo_stats.cc new file mode 100644 index 000000000000..51e12d96d452 --- /dev/null +++ b/source/extensions/filters/http/dynamo/dynamo_stats.cc @@ -0,0 +1,109 @@ +#include "extensions/filters/http/dynamo/dynamo_stats.h" + +#include +#include +#include + +#include "envoy/stats/scope.h" + +#include "common/stats/symbol_table_impl.h" + +#include "extensions/filters/http/dynamo/dynamo_request_parser.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace Dynamo { + +DynamoStats::DynamoStats(Stats::Scope& scope, const std::string& prefix) + : scope_(scope), pool_(scope.symbolTable()), prefix_(pool_.add(prefix + "dynamodb")), + batch_failure_unprocessed_keys_(pool_.add("BatchFailureUnprocessedKeys")), + capacity_(pool_.add("capacity")), empty_response_body_(pool_.add("empty_response_body")), + error_(pool_.add("error")), invalid_req_body_(pool_.add("invalid_req_body")), + invalid_resp_body_(pool_.add("invalid_resp_body")), + multiple_tables_(pool_.add("multiple_tables")), no_table_(pool_.add("no_table")), + operation_missing_(pool_.add("operation_missing")), table_(pool_.add("table")), + table_missing_(pool_.add("table_missing")), upstream_rq_time_(pool_.add("upstream_rq_time")), + upstream_rq_total_(pool_.add("upstream_rq_total")) { + upstream_rq_total_groups_[0] = pool_.add("upstream_rq_total_unknown"); + upstream_rq_time_groups_[0] = pool_.add("upstream_rq_time_unknown"); + for (size_t i = 1; i < DynamoStats::NumGroupEntries; ++i) { + upstream_rq_total_groups_[i] = pool_.add(fmt::format("upstream_rq_total_{}xx", i)); + upstream_rq_time_groups_[i] = pool_.add(fmt::format("upstream_rq_time_{}xx", i)); + } + RequestParser::forEachStatString([this](const std::string& str) { + // Thread annotation does not realize this function is only called from the + // constructor, so we need to lock the mutex. It's easier to just do that + // and it's no real penalty. + absl::MutexLock lock(&mutex_); + builtin_stat_names_[str] = pool_.add(str); + }); + builtin_stat_names_[""] = Stats::StatName(); +} + +Stats::SymbolTable::StoragePtr DynamoStats::addPrefix(const std::vector& names) { + std::vector names_with_prefix{prefix_}; + names_with_prefix.reserve(names.end() - names.begin()); + names_with_prefix.insert(names_with_prefix.end(), names.begin(), names.end()); + return scope_.symbolTable().join(names_with_prefix); +} + +Stats::Counter& DynamoStats::counter(const std::vector& names) { + const Stats::SymbolTable::StoragePtr stat_name_storage = addPrefix(names); + return scope_.counterFromStatName(Stats::StatName(stat_name_storage.get())); +} + +Stats::Histogram& DynamoStats::histogram(const std::vector& names) { + const Stats::SymbolTable::StoragePtr stat_name_storage = addPrefix(names); + return scope_.histogramFromStatName(Stats::StatName(stat_name_storage.get())); +} + +Stats::Counter& DynamoStats::buildPartitionStatCounter(const std::string& table_name, + const std::string& operation, + const std::string& partition_id) { + // Use the last 7 characters of the partition id. + absl::string_view id_last_7 = absl::string_view(partition_id).substr(partition_id.size() - 7); + const Stats::SymbolTable::StoragePtr stat_name_storage = + addPrefix({table_, getStatName(table_name), capacity_, getStatName(operation), + getStatName(absl::StrCat("__partition_id=", id_last_7))}); + return scope_.counterFromStatName(Stats::StatName(stat_name_storage.get())); +} + +size_t DynamoStats::groupIndex(uint64_t status) { + size_t index = status / 100; + if (index >= NumGroupEntries) { + index = 0; // status-code 600 or higher is unknown. + } + return index; +} + +Stats::StatName DynamoStats::getStatName(const std::string& token) { + // The Dynamo system has a few well-known tokens that we have stored during + // construction, and we can access StatNames for those without a lock. Note + // that we only mutate builtin_stat_names_ during construction. + auto iter = builtin_stat_names_.find(token); + if (iter != builtin_stat_names_.end()) { + return iter->second; + } + + // However, some of the tokens come from json data received during requests, + // so we need to store these in a mutex-protected map. Once we hold the mutex, + // we can check dynamic_stat_names_. If it's missing we'll have to add it + // to the symbol table, whose mutex is more likely to be contended, and then + // store it in dynamic_stat_names. + // + // TODO(jmarantz): Potential perf issue here with contention, both on this + // mutex and also the SymbolTable mutex which must be taken during + // StatNamePool::add(). + absl::MutexLock lock(&mutex_); + Stats::StatName& stat_name = dynamic_stat_names_[token]; + if (stat_name.empty()) { // Note that builtin_stat_names_ already has one for "". + stat_name = pool_.add(token); + } + return stat_name; +} + +} // namespace Dynamo +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/http/dynamo/dynamo_stats.h b/source/extensions/filters/http/dynamo/dynamo_stats.h new file mode 100644 index 000000000000..57671514e581 --- /dev/null +++ b/source/extensions/filters/http/dynamo/dynamo_stats.h @@ -0,0 +1,73 @@ +#pragma once + +#include +#include + +#include "envoy/stats/scope.h" + +#include "common/stats/symbol_table_impl.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace Dynamo { + +class DynamoStats { +public: + DynamoStats(Stats::Scope& scope, const std::string& prefix); + + Stats::Counter& counter(const std::vector& names); + Stats::Histogram& histogram(const std::vector& names); + + /** + * Creates the partition id stats string. The stats format is + * "table..capacity..__partition_id=". + * Partition ids and dynamodb table names can be long. To satisfy the string + * length, we truncate, taking only the last 7 characters of the partition id. + */ + Stats::Counter& buildPartitionStatCounter(const std::string& table_name, + const std::string& operation, + const std::string& partition_id); + + static size_t groupIndex(uint64_t status); + + Stats::StatName getStatName(const std::string& str); + +private: + Stats::SymbolTable::StoragePtr addPrefix(const std::vector& names); + + Stats::Scope& scope_; + Stats::StatNamePool pool_ GUARDED_BY(mutex_); + const Stats::StatName prefix_; + absl::Mutex mutex_; + using StringStatNameMap = absl::flat_hash_map; + StringStatNameMap builtin_stat_names_; + StringStatNameMap dynamic_stat_names_ GUARDED_BY(mutex_); + +public: + const Stats::StatName batch_failure_unprocessed_keys_; + const Stats::StatName capacity_; + const Stats::StatName empty_response_body_; + const Stats::StatName error_; + const Stats::StatName invalid_req_body_; + const Stats::StatName invalid_resp_body_; + const Stats::StatName multiple_tables_; + const Stats::StatName no_table_; + const Stats::StatName operation_missing_; + const Stats::StatName table_; + const Stats::StatName table_missing_; + const Stats::StatName upstream_rq_time_; + const Stats::StatName upstream_rq_total_; + const Stats::StatName upstream_rq_unknown_; + + // Keep group codes for HTTP status codes through the 500s. + static constexpr size_t NumGroupEntries = 6; + Stats::StatName upstream_rq_total_groups_[NumGroupEntries]; + Stats::StatName upstream_rq_time_groups_[NumGroupEntries]; +}; +using DynamoStatsSharedPtr = std::shared_ptr; + +} // namespace Dynamo +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/http/dynamo/dynamo_utility.cc b/source/extensions/filters/http/dynamo/dynamo_utility.cc deleted file mode 100644 index a71408439fc3..000000000000 --- a/source/extensions/filters/http/dynamo/dynamo_utility.cc +++ /dev/null @@ -1,27 +0,0 @@ -#include "extensions/filters/http/dynamo/dynamo_utility.h" - -#include - -#include "common/common/fmt.h" - -namespace Envoy { -namespace Extensions { -namespace HttpFilters { -namespace Dynamo { - -std::string Utility::buildPartitionStatString(const std::string& stat_prefix, - const std::string& table_name, - const std::string& operation, - const std::string& partition_id) { - // Use the last 7 characters of the partition id. - std::string stats_partition_postfix = - fmt::format(".capacity.{}.__partition_id={}", operation, - partition_id.substr(partition_id.size() - 7, partition_id.size())); - std::string stats_table_prefix = fmt::format("{}table.{}", stat_prefix, table_name); - return fmt::format("{}{}", stats_table_prefix, stats_partition_postfix); -} - -} // namespace Dynamo -} // namespace HttpFilters -} // namespace Extensions -} // namespace Envoy diff --git a/source/extensions/filters/http/dynamo/dynamo_utility.h b/source/extensions/filters/http/dynamo/dynamo_utility.h deleted file mode 100644 index 87b4bd0bc119..000000000000 --- a/source/extensions/filters/http/dynamo/dynamo_utility.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include - -namespace Envoy { -namespace Extensions { -namespace HttpFilters { -namespace Dynamo { - -class Utility { -public: - /** - * Creates the partition id stats string. - * The stats format is - * "table..capacity..__partition_id=". - * Partition ids and dynamodb table names can be long. To satisfy the string length, - * we truncate in two ways: - * 1. We only take the last 7 characters of the partition id. - * 2. If the stats string with is longer than the stats MAX_NAME_SIZE, we will - * truncate the table name to - * fit the size requirements. - */ - static std::string buildPartitionStatString(const std::string& stat_prefix, - const std::string& table_name, - const std::string& operation, - const std::string& partition_id); -}; - -} // namespace Dynamo -} // namespace HttpFilters -} // namespace Extensions -} // namespace Envoy diff --git a/source/extensions/filters/http/fault/fault_filter.cc b/source/extensions/filters/http/fault/fault_filter.cc index 4c7a73c3f43d..7d914f553c2c 100644 --- a/source/extensions/filters/http/fault/fault_filter.cc +++ b/source/extensions/filters/http/fault/fault_filter.cc @@ -32,7 +32,20 @@ struct RcDetailsValues { }; using RcDetails = ConstSingleton; -FaultSettings::FaultSettings(const envoy::config::filter::http::fault::v2::HTTPFault& fault) { +FaultSettings::FaultSettings(const envoy::config::filter::http::fault::v2::HTTPFault& fault) + : delay_percent_runtime_(PROTOBUF_GET_STRING_OR_DEFAULT(fault, delay_percent_runtime, + RuntimeKeys::get().DelayPercentKey)), + abort_percent_runtime_(PROTOBUF_GET_STRING_OR_DEFAULT(fault, abort_percent_runtime, + RuntimeKeys::get().AbortPercentKey)), + delay_duration_runtime_(PROTOBUF_GET_STRING_OR_DEFAULT(fault, delay_duration_runtime, + RuntimeKeys::get().DelayDurationKey)), + abort_http_status_runtime_(PROTOBUF_GET_STRING_OR_DEFAULT( + fault, abort_http_status_runtime, RuntimeKeys::get().AbortHttpStatusKey)), + max_active_faults_runtime_(PROTOBUF_GET_STRING_OR_DEFAULT( + fault, max_active_faults_runtime, RuntimeKeys::get().MaxActiveFaultsKey)), + response_rate_limit_percent_runtime_( + PROTOBUF_GET_STRING_OR_DEFAULT(fault, response_rate_limit_percent_runtime, + RuntimeKeys::get().ResponseRateLimitPercentKey)) { if (fault.has_abort()) { const auto& abort = fault.abort(); abort_percentage_ = abort.percentage(); @@ -162,7 +175,7 @@ void FaultFilter::maybeSetupResponseRateLimit(const Http::HeaderMap& request_hea // TODO(mattklein123): Allow runtime override via downstream cluster similar to the other keys. if (!config_->runtime().snapshot().featureEnabled( - RuntimeKeys::get().ResponseRateLimitPercentKey, + fault_settings_->responseRateLimitPercentRuntime(), fault_settings_->responseRateLimit()->percentage())) { return; } @@ -184,9 +197,9 @@ void FaultFilter::maybeSetupResponseRateLimit(const Http::HeaderMap& request_hea bool FaultFilter::faultOverflow() { const uint64_t max_faults = config_->runtime().snapshot().getInteger( - RuntimeKeys::get().MaxActiveFaultsKey, fault_settings_->maxActiveFaults().has_value() - ? fault_settings_->maxActiveFaults().value() - : std::numeric_limits::max()); + fault_settings_->maxActiveFaultsRuntime(), fault_settings_->maxActiveFaults().has_value() + ? fault_settings_->maxActiveFaults().value() + : std::numeric_limits::max()); // Note: Since we don't compare/swap here this is a fuzzy limit which is similar to how the // other circuit breakers work. if (config_->stats().active_faults_.value() >= max_faults) { @@ -203,7 +216,7 @@ bool FaultFilter::isDelayEnabled() { } bool enabled = config_->runtime().snapshot().featureEnabled( - RuntimeKeys::get().DelayPercentKey, fault_settings_->requestDelay()->percentage()); + fault_settings_->delayPercentRuntime(), fault_settings_->requestDelay()->percentage()); if (!downstream_cluster_delay_percent_key_.empty()) { enabled |= config_->runtime().snapshot().featureEnabled( downstream_cluster_delay_percent_key_, fault_settings_->requestDelay()->percentage()); @@ -212,8 +225,8 @@ bool FaultFilter::isDelayEnabled() { } bool FaultFilter::isAbortEnabled() { - bool enabled = config_->runtime().snapshot().featureEnabled(RuntimeKeys::get().AbortPercentKey, - fault_settings_->abortPercentage()); + bool enabled = config_->runtime().snapshot().featureEnabled( + fault_settings_->abortPercentRuntime(), fault_settings_->abortPercentage()); if (!downstream_cluster_abort_percent_key_.empty()) { enabled |= config_->runtime().snapshot().featureEnabled(downstream_cluster_abort_percent_key_, fault_settings_->abortPercentage()); @@ -239,7 +252,7 @@ FaultFilter::delayDuration(const Http::HeaderMap& request_headers) { std::chrono::milliseconds duration = std::chrono::milliseconds(config_->runtime().snapshot().getInteger( - RuntimeKeys::get().DelayDurationKey, config_duration.value().count())); + fault_settings_->delayDurationRuntime(), config_duration.value().count())); if (!downstream_cluster_delay_duration_key_.empty()) { duration = std::chrono::milliseconds(config_->runtime().snapshot().getInteger( downstream_cluster_delay_duration_key_, duration.count())); @@ -256,7 +269,7 @@ FaultFilter::delayDuration(const Http::HeaderMap& request_headers) { uint64_t FaultFilter::abortHttpStatus() { // TODO(mattklein123): check http status codes obtained from runtime. uint64_t http_status = config_->runtime().snapshot().getInteger( - RuntimeKeys::get().AbortHttpStatusKey, fault_settings_->abortCode()); + fault_settings_->abortHttpStatusRuntime(), fault_settings_->abortCode()); if (!downstream_cluster_abort_http_status_key_.empty()) { http_status = config_->runtime().snapshot().getInteger( diff --git a/source/extensions/filters/http/fault/fault_filter.h b/source/extensions/filters/http/fault/fault_filter.h index b350ce61ce64..824fecd64ea1 100644 --- a/source/extensions/filters/http/fault/fault_filter.h +++ b/source/extensions/filters/http/fault/fault_filter.h @@ -62,8 +62,28 @@ class FaultSettings : public Router::RouteSpecificFilterConfig { const Filters::Common::Fault::FaultRateLimitConfig* responseRateLimit() const { return response_rate_limit_.get(); } + const std::string& abortPercentRuntime() const { return abort_percent_runtime_; } + const std::string& delayPercentRuntime() const { return delay_percent_runtime_; } + const std::string& abortHttpStatusRuntime() const { return abort_http_status_runtime_; } + const std::string& delayDurationRuntime() const { return delay_duration_runtime_; } + const std::string& maxActiveFaultsRuntime() const { return max_active_faults_runtime_; } + const std::string& responseRateLimitPercentRuntime() const { + return response_rate_limit_percent_runtime_; + } private: + class RuntimeKeyValues { + public: + const std::string DelayPercentKey = "fault.http.delay.fixed_delay_percent"; + const std::string AbortPercentKey = "fault.http.abort.abort_percent"; + const std::string DelayDurationKey = "fault.http.delay.fixed_duration_ms"; + const std::string AbortHttpStatusKey = "fault.http.abort.http_status"; + const std::string MaxActiveFaultsKey = "fault.http.max_active_faults"; + const std::string ResponseRateLimitPercentKey = "fault.http.rate_limit.response_percent"; + }; + + using RuntimeKeys = ConstSingleton; + envoy::type::FractionalPercent abort_percentage_; uint64_t http_status_{}; // HTTP or gRPC return codes Filters::Common::Fault::FaultDelayConfigPtr request_delay_config_; @@ -72,6 +92,12 @@ class FaultSettings : public Router::RouteSpecificFilterConfig { absl::flat_hash_set downstream_nodes_{}; // Inject failures for specific downstream absl::optional max_active_faults_; Filters::Common::Fault::FaultRateLimitConfigPtr response_rate_limit_; + const std::string delay_percent_runtime_; + const std::string abort_percent_runtime_; + const std::string delay_duration_runtime_; + const std::string abort_http_status_runtime_; + const std::string max_active_faults_runtime_; + const std::string response_rate_limit_percent_runtime_; }; /** @@ -168,7 +194,7 @@ class StreamRateLimiter : Logger::Loggable { class FaultFilter : public Http::StreamFilter, Logger::Loggable { public: FaultFilter(FaultFilterConfigSharedPtr config); - ~FaultFilter(); + ~FaultFilter() override; // Http::StreamFilterBase void onDestroy() override; @@ -198,18 +224,6 @@ class FaultFilter : public Http::StreamFilter, Logger::Loggable; - bool faultOverflow(); void recordAbortsInjectedStats(); void recordDelaysInjectedStats(); diff --git a/source/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter.cc b/source/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter.cc index 7b00de163760..fb26f1f39c0d 100644 --- a/source/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter.cc +++ b/source/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter.cc @@ -161,6 +161,7 @@ JsonTranscoderConfig::JsonTranscoderConfig( print_options_.preserve_proto_field_names = print_config.preserve_proto_field_names(); match_incoming_request_route_ = proto_config.match_incoming_request_route(); + ignore_unknown_query_parameters_ = proto_config.ignore_unknown_query_parameters(); } bool JsonTranscoderConfig::matchIncomingRequestInfo() const { @@ -203,6 +204,9 @@ ProtobufUtil::Status JsonTranscoderConfig::createTranscoder( status = type_helper_->ResolveFieldPath(*request_info.message_type, binding.field_path, &resolved_binding.field_path); if (!status.ok()) { + if (ignore_unknown_query_parameters_) { + continue; + } return status; } diff --git a/source/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter.h b/source/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter.h index 0b7f3b7ff301..21976ef9b760 100644 --- a/source/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter.h +++ b/source/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter.h @@ -89,6 +89,7 @@ class JsonTranscoderConfig : public Logger::Loggable { Protobuf::util::JsonPrintOptions print_options_; bool match_incoming_request_route_{false}; + bool ignore_unknown_query_parameters_{false}; }; using JsonTranscoderConfigSharedPtr = std::shared_ptr; diff --git a/source/extensions/filters/http/grpc_json_transcoder/transcoder_input_stream_impl.h b/source/extensions/filters/http/grpc_json_transcoder/transcoder_input_stream_impl.h index 7c4dfa4dc3f9..f5b4159be0d1 100644 --- a/source/extensions/filters/http/grpc_json_transcoder/transcoder_input_stream_impl.h +++ b/source/extensions/filters/http/grpc_json_transcoder/transcoder_input_stream_impl.h @@ -13,8 +13,8 @@ class TranscoderInputStreamImpl : public Buffer::ZeroCopyInputStreamImpl, public google::grpc::transcoding::TranscoderInputStream { public: // TranscoderInputStream - virtual int64_t BytesAvailable() const override; - virtual bool Finished() const override; + int64_t BytesAvailable() const override; + bool Finished() const override; }; } // namespace GrpcJsonTranscoder diff --git a/source/extensions/filters/http/gzip/BUILD b/source/extensions/filters/http/gzip/BUILD index 91efd5965891..6a1df0f1dd12 100644 --- a/source/extensions/filters/http/gzip/BUILD +++ b/source/extensions/filters/http/gzip/BUILD @@ -23,8 +23,6 @@ envoy_cc_library( "//source/common/compressor:compressor_lib", "//source/common/http:header_map_lib", "//source/common/http:headers_lib", - "//source/common/json:config_schemas_lib", - "//source/common/json:json_validator_lib", "//source/common/protobuf", "@envoy_api//envoy/config/filter/http/gzip/v2:gzip_cc", ], diff --git a/source/extensions/filters/http/gzip/gzip_filter.h b/source/extensions/filters/http/gzip/gzip_filter.h index 2346157070bb..99b3eaf3336e 100644 --- a/source/extensions/filters/http/gzip/gzip_filter.h +++ b/source/extensions/filters/http/gzip/gzip_filter.h @@ -11,8 +11,6 @@ #include "common/buffer/buffer_impl.h" #include "common/compressor/zlib_compressor_impl.h" #include "common/http/header_map_impl.h" -#include "common/json/config_schemas.h" -#include "common/json/json_validator.h" #include "common/protobuf/protobuf.h" namespace Envoy { diff --git a/source/extensions/filters/http/header_to_metadata/header_to_metadata_filter.h b/source/extensions/filters/http/header_to_metadata/header_to_metadata_filter.h index 188124e9d16f..e10da6e3eba9 100644 --- a/source/extensions/filters/http/header_to_metadata/header_to_metadata_filter.h +++ b/source/extensions/filters/http/header_to_metadata/header_to_metadata_filter.h @@ -66,7 +66,7 @@ class HeaderToMetadataFilter : public Http::StreamFilter, public Logger::Loggable { public: HeaderToMetadataFilter(const ConfigSharedPtr config); - ~HeaderToMetadataFilter(); + ~HeaderToMetadataFilter() override; // Http::StreamFilterBase void onDestroy() override {} diff --git a/source/extensions/filters/http/ip_tagging/ip_tagging_filter.cc b/source/extensions/filters/http/ip_tagging/ip_tagging_filter.cc index 9b43ab02a121..1d82239c7dfd 100644 --- a/source/extensions/filters/http/ip_tagging/ip_tagging_filter.cc +++ b/source/extensions/filters/http/ip_tagging/ip_tagging_filter.cc @@ -12,7 +12,7 @@ namespace IpTagging { IpTaggingFilter::IpTaggingFilter(IpTaggingFilterConfigSharedPtr config) : config_(config) {} -IpTaggingFilter::~IpTaggingFilter() {} +IpTaggingFilter::~IpTaggingFilter() = default; void IpTaggingFilter::onDestroy() {} diff --git a/source/extensions/filters/http/ip_tagging/ip_tagging_filter.h b/source/extensions/filters/http/ip_tagging/ip_tagging_filter.h index 14a35a9a914b..3eaa7f22c841 100644 --- a/source/extensions/filters/http/ip_tagging/ip_tagging_filter.h +++ b/source/extensions/filters/http/ip_tagging/ip_tagging_filter.h @@ -107,7 +107,7 @@ using IpTaggingFilterConfigSharedPtr = std::shared_ptr; class IpTaggingFilter : public Http::StreamDecoderFilter { public: IpTaggingFilter(IpTaggingFilterConfigSharedPtr config); - ~IpTaggingFilter(); + ~IpTaggingFilter() override; // Http::StreamFilterBase void onDestroy() override; diff --git a/source/extensions/filters/http/jwt_authn/BUILD b/source/extensions/filters/http/jwt_authn/BUILD index b566159039b3..feede1f772fe 100644 --- a/source/extensions/filters/http/jwt_authn/BUILD +++ b/source/extensions/filters/http/jwt_authn/BUILD @@ -51,6 +51,9 @@ envoy_cc_library( name = "filter_lib", srcs = ["filter.cc"], hdrs = ["filter.h"], + external_deps = [ + "jwt_verify_lib", + ], deps = [ ":filter_config_interface", ":matchers_lib", diff --git a/source/extensions/filters/http/jwt_authn/authenticator.cc b/source/extensions/filters/http/jwt_authn/authenticator.cc index c81ec50cfb56..fa361f90a237 100644 --- a/source/extensions/filters/http/jwt_authn/authenticator.cc +++ b/source/extensions/filters/http/jwt_authn/authenticator.cc @@ -25,7 +25,7 @@ namespace { /** * Object to implement Authenticator interface. */ -class AuthenticatorImpl : public Logger::Loggable, +class AuthenticatorImpl : public Logger::Loggable, public Authenticator, public Common::JwksFetcher::JwksReceiver { public: @@ -99,7 +99,7 @@ void AuthenticatorImpl::verify(Http::HeaderMap& headers, std::vectoriss_); // Check if token extracted from the location contains the issuer specified by config. if (!curr_token_->isIssuerSpecified(jwt_->iss_)) { - ENVOY_LOG(debug, "Jwt issuer {} does not match required", jwt_->iss_); doneWithStatus(Status::JwtUnknownIssuer); return; } @@ -236,11 +236,11 @@ void AuthenticatorImpl::verifyKey() { } void AuthenticatorImpl::doneWithStatus(const Status& status) { + ENVOY_LOG(debug, "JWT token verification completed with: {}", + ::google::jwt_verify::getStatusString(status)); // if on allow missing or failed this should verify all tokens, otherwise stop on ok. if ((Status::Ok == status && !is_allow_failed_) || tokens_.empty()) { tokens_.clear(); - ENVOY_LOG(debug, "Jwt authentication completed with: {}", - ::google::jwt_verify::getStatusString(status)); callback_(is_allow_failed_ ? Status::Ok : status); callback_ = nullptr; return; diff --git a/source/extensions/filters/http/jwt_authn/filter.cc b/source/extensions/filters/http/jwt_authn/filter.cc index 02576892a517..9c758605c3ee 100644 --- a/source/extensions/filters/http/jwt_authn/filter.cc +++ b/source/extensions/filters/http/jwt_authn/filter.cc @@ -4,6 +4,8 @@ #include "extensions/filters/http/well_known_names.h" +#include "jwt_verify_lib/status.h" + using ::google::jwt_verify::Status; namespace Envoy { @@ -55,7 +57,8 @@ void Filter::setPayload(const ProtobufWkt::Struct& payload) { } void Filter::onComplete(const Status& status) { - ENVOY_LOG(debug, "Called Filter : check complete {}", int(status)); + ENVOY_LOG(debug, "Called Filter : check complete {}", + ::google::jwt_verify::getStatusString(status)); // This stream has been reset, abort the callback. if (state_ == Responded) { return; @@ -64,7 +67,8 @@ void Filter::onComplete(const Status& status) { stats_.denied_.inc(); state_ = Responded; // verification failed - Http::Code code = Http::Code::Unauthorized; + Http::Code code = + status == Status::JwtAudienceNotAllowed ? Http::Code::Forbidden : Http::Code::Unauthorized; // return failure reason as message body decoder_callbacks_->sendLocalReply(code, ::google::jwt_verify::getStatusString(status), nullptr, absl::nullopt, RcDetails::get().JwtAuthnAccessDenied); diff --git a/source/extensions/filters/http/jwt_authn/filter.h b/source/extensions/filters/http/jwt_authn/filter.h index 6e9cef2609ac..67572114623c 100644 --- a/source/extensions/filters/http/jwt_authn/filter.h +++ b/source/extensions/filters/http/jwt_authn/filter.h @@ -17,7 +17,7 @@ namespace JwtAuthn { // The Envoy filter to process JWT auth. class Filter : public Http::StreamDecoderFilter, public Verifier::Callbacks, - public Logger::Loggable { + public Logger::Loggable { public: Filter(FilterConfigSharedPtr config); diff --git a/source/extensions/filters/http/jwt_authn/filter_config.h b/source/extensions/filters/http/jwt_authn/filter_config.h index 454fa9b1314c..adac32edb149 100644 --- a/source/extensions/filters/http/jwt_authn/filter_config.h +++ b/source/extensions/filters/http/jwt_authn/filter_config.h @@ -59,7 +59,7 @@ struct JwtAuthnFilterStats { /** * The filter config object to hold config and relevant objects. */ -class FilterConfig : public Logger::Loggable, public AuthFactory { +class FilterConfig : public Logger::Loggable, public AuthFactory { public: ~FilterConfig() override = default; @@ -93,12 +93,6 @@ class FilterConfig : public Logger::Loggable, public AuthFac JwtAuthnFilterStats& stats() { return stats_; } - // Get the Config. - const ::envoy::config::filter::http::jwt_authn::v2alpha::JwtAuthentication& - getProtoConfig() const { - return proto_config_; - } - // Get per-thread cache object. ThreadLocalCache& getCache() const { return tls_->getTyped(); } diff --git a/source/extensions/filters/http/jwt_authn/jwks_cache.cc b/source/extensions/filters/http/jwt_authn/jwks_cache.cc index cfb3faea3409..425bef1b4959 100644 --- a/source/extensions/filters/http/jwt_authn/jwks_cache.cc +++ b/source/extensions/filters/http/jwt_authn/jwks_cache.cc @@ -25,7 +25,7 @@ namespace { // Default cache expiration time in 5 minutes. constexpr int PubkeyCacheExpirationSec = 600; -class JwksDataImpl : public JwksCache::JwksData, public Logger::Loggable { +class JwksDataImpl : public JwksCache::JwksData, public Logger::Loggable { public: JwksDataImpl(const JwtProvider& jwt_provider, TimeSource& time_source, Api::Api& api) : jwt_provider_(jwt_provider), time_source_(time_source) { diff --git a/source/extensions/filters/http/jwt_authn/matcher.cc b/source/extensions/filters/http/jwt_authn/matcher.cc index 123e590a7e72..0a187c3eb451 100644 --- a/source/extensions/filters/http/jwt_authn/matcher.cc +++ b/source/extensions/filters/http/jwt_authn/matcher.cc @@ -19,7 +19,7 @@ namespace { /** * Perform a match against any HTTP header or pseudo-header. */ -class BaseMatcherImpl : public Matcher, public Logger::Loggable { +class BaseMatcherImpl : public Matcher, public Logger::Loggable { public: BaseMatcherImpl(const RequirementRule& rule) : case_sensitive_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(rule.match(), case_sensitive, true)) { diff --git a/source/extensions/filters/http/ratelimit/BUILD b/source/extensions/filters/http/ratelimit/BUILD index 45e8abef7c78..22b8e4bba0b6 100644 --- a/source/extensions/filters/http/ratelimit/BUILD +++ b/source/extensions/filters/http/ratelimit/BUILD @@ -24,6 +24,7 @@ envoy_cc_library( "//source/common/http:codes_lib", "//source/common/router:config_lib", "//source/extensions/filters/common/ratelimit:ratelimit_client_interface", + "//source/extensions/filters/common/ratelimit:stat_names_lib", "@envoy_api//envoy/config/filter/http/rate_limit/v2:rate_limit_cc", ], ) diff --git a/source/extensions/filters/http/ratelimit/ratelimit.cc b/source/extensions/filters/http/ratelimit/ratelimit.cc index 2a5761c6b612..6bd65be54811 100644 --- a/source/extensions/filters/http/ratelimit/ratelimit.cc +++ b/source/extensions/filters/http/ratelimit/ratelimit.cc @@ -130,16 +130,17 @@ void Filter::complete(Filters::Common::RateLimit::LimitStatus status, state_ = State::Complete; headers_to_add_ = std::move(headers); Stats::StatName empty_stat_name; + Filters::Common::RateLimit::StatNames& stat_names = config_->statNames(); switch (status) { case Filters::Common::RateLimit::LimitStatus::OK: - cluster_->statsScope().counter("ratelimit.ok").inc(); + cluster_->statsScope().counterFromStatName(stat_names.ok_).inc(); break; case Filters::Common::RateLimit::LimitStatus::Error: - cluster_->statsScope().counter("ratelimit.error").inc(); + cluster_->statsScope().counterFromStatName(stat_names.error_).inc(); break; case Filters::Common::RateLimit::LimitStatus::OverLimit: - cluster_->statsScope().counter("ratelimit.over_limit").inc(); + cluster_->statsScope().counterFromStatName(stat_names.over_limit_).inc(); Http::CodeStats::ResponseStatInfo info{config_->scope(), cluster_->statsScope(), empty_stat_name, @@ -165,7 +166,7 @@ void Filter::complete(Filters::Common::RateLimit::LimitStatus status, callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::RateLimited); } else if (status == Filters::Common::RateLimit::LimitStatus::Error) { if (config_->failureModeAllow()) { - cluster_->statsScope().counter("ratelimit.failure_mode_allowed").inc(); + cluster_->statsScope().counterFromStatName(stat_names.failure_mode_allowed_).inc(); if (!initiating_call_) { callbacks_->continueDecoding(); } diff --git a/source/extensions/filters/http/ratelimit/ratelimit.h b/source/extensions/filters/http/ratelimit/ratelimit.h index 1103f9e9763b..dfda9883ee2d 100644 --- a/source/extensions/filters/http/ratelimit/ratelimit.h +++ b/source/extensions/filters/http/ratelimit/ratelimit.h @@ -18,6 +18,7 @@ #include "common/http/header_map_impl.h" #include "extensions/filters/common/ratelimit/ratelimit.h" +#include "extensions/filters/common/ratelimit/stat_names.h" namespace Envoy { namespace Extensions { @@ -46,7 +47,7 @@ class FilterConfig { config.rate_limited_as_resource_exhausted() ? absl::make_optional(Grpc::Status::GrpcStatus::ResourceExhausted) : absl::nullopt), - http_context_(http_context) {} + http_context_(http_context), stat_names_(scope.symbolTable()) {} const std::string& domain() const { return domain_; } const LocalInfo::LocalInfo& localInfo() const { return local_info_; } uint64_t stage() const { return stage_; } @@ -58,6 +59,7 @@ class FilterConfig { return rate_limited_grpc_status_; } Http::Context& httpContext() { return http_context_; } + Filters::Common::RateLimit::StatNames& statNames() { return stat_names_; } private: static FilterRequestType stringToType(const std::string& request_type) { @@ -80,6 +82,7 @@ class FilterConfig { const bool failure_mode_deny_; const absl::optional rate_limited_grpc_status_; Http::Context& http_context_; + Filters::Common::RateLimit::StatNames stat_names_; }; using FilterConfigSharedPtr = std::shared_ptr; diff --git a/source/extensions/filters/http/squash/squash_filter.cc b/source/extensions/filters/http/squash/squash_filter.cc index be4d4e095c9b..5a3b7d7b12cc 100644 --- a/source/extensions/filters/http/squash/squash_filter.cc +++ b/source/extensions/filters/http/squash/squash_filter.cc @@ -129,7 +129,7 @@ SquashFilter::SquashFilter(SquashFilterConfigSharedPtr config, Upstream::Cluster std::bind(&SquashFilter::onGetAttachmentFailure, this, _1)), cm_(cm), decoder_callbacks_(nullptr) {} -SquashFilter::~SquashFilter() {} +SquashFilter::~SquashFilter() = default; void SquashFilter::onDestroy() { cleanup(); } diff --git a/source/extensions/filters/http/tap/BUILD b/source/extensions/filters/http/tap/BUILD index 40e7a1f8f6ac..0581a9f7d2c6 100644 --- a/source/extensions/filters/http/tap/BUILD +++ b/source/extensions/filters/http/tap/BUILD @@ -39,6 +39,7 @@ envoy_cc_library( hdrs = ["tap_filter.h"], deps = [ ":tap_config_interface", + "//include/envoy/access_log:access_log_interface", "//include/envoy/http:filter_interface", "//source/extensions/common/tap:extension_config_base", "@envoy_api//envoy/config/filter/http/tap/v2alpha:tap_cc", diff --git a/source/extensions/filters/http/tap/tap_filter.h b/source/extensions/filters/http/tap/tap_filter.h index a8c5d0d7f5d7..79058b0a244a 100644 --- a/source/extensions/filters/http/tap/tap_filter.h +++ b/source/extensions/filters/http/tap/tap_filter.h @@ -1,5 +1,6 @@ #pragma once +#include "envoy/access_log/access_log.h" #include "envoy/config/filter/http/tap/v2alpha/tap.pb.h" #include "envoy/http/filter.h" #include "envoy/stats/scope.h" diff --git a/source/extensions/filters/listener/http_inspector/BUILD b/source/extensions/filters/listener/http_inspector/BUILD new file mode 100644 index 000000000000..e9d3307bc848 --- /dev/null +++ b/source/extensions/filters/listener/http_inspector/BUILD @@ -0,0 +1,41 @@ +licenses(["notice"]) # Apache 2 + +# HTTP inspector filter for sniffing HTTP protocol and setting HTTP version to a FilterChain. + +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_package", +) + +envoy_package() + +envoy_cc_library( + name = "http_inspector_lib", + srcs = ["http_inspector.cc"], + hdrs = [ + "http_inspector.h", + "http_protocol_header.h", + ], + deps = [ + "//include/envoy/event:dispatcher_interface", + "//include/envoy/event:timer_interface", + "//include/envoy/network:filter_interface", + "//include/envoy/network:listen_socket_interface", + "//source/common/api:os_sys_calls_lib", + "//source/common/common:minimal_logger_lib", + "//source/common/http:headers_lib", + "//source/extensions/transport_sockets:well_known_names", + ], +) + +envoy_cc_library( + name = "config", + srcs = ["config.cc"], + deps = [ + ":http_inspector_lib", + "//include/envoy/registry", + "//include/envoy/server:filter_config_interface", + "//source/extensions/filters/listener:well_known_names", + ], +) diff --git a/source/extensions/filters/listener/http_inspector/config.cc b/source/extensions/filters/listener/http_inspector/config.cc new file mode 100644 index 000000000000..3a0833d6721f --- /dev/null +++ b/source/extensions/filters/listener/http_inspector/config.cc @@ -0,0 +1,43 @@ +#include "envoy/registry/registry.h" +#include "envoy/server/filter_config.h" + +#include "extensions/filters/listener/http_inspector/http_inspector.h" +#include "extensions/filters/listener/well_known_names.h" + +namespace Envoy { +namespace Extensions { +namespace ListenerFilters { +namespace HttpInspector { + +/** + * Config registration for the Http inspector filter. @see NamedNetworkFilterConfigFactory. + */ +class HttpInspectorConfigFactory : public Server::Configuration::NamedListenerFilterConfigFactory { +public: + // NamedListenerFilterConfigFactory + Network::ListenerFilterFactoryCb + createFilterFactoryFromProto(const Protobuf::Message&, + Server::Configuration::ListenerFactoryContext& context) override { + ConfigSharedPtr config(std::make_shared(context.scope())); + return [config](Network::ListenerFilterManager& filter_manager) -> void { + filter_manager.addAcceptFilter(std::make_unique(config)); + }; + } + + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); + } + + std::string name() override { return ListenerFilterNames::get().HttpInspector; } +}; + +/** + * Static registration for the http inspector filter. @see RegisterFactory. + */ +REGISTER_FACTORY(HttpInspectorConfigFactory, + Server::Configuration::NamedListenerFilterConfigFactory); + +} // namespace HttpInspector +} // namespace ListenerFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/listener/http_inspector/http_inspector.cc b/source/extensions/filters/listener/http_inspector/http_inspector.cc new file mode 100644 index 000000000000..4a31065b71f8 --- /dev/null +++ b/source/extensions/filters/listener/http_inspector/http_inspector.cc @@ -0,0 +1,189 @@ +#include "extensions/filters/listener/http_inspector/http_inspector.h" + +#include "envoy/event/dispatcher.h" +#include "envoy/network/listen_socket.h" +#include "envoy/stats/scope.h" + +#include "common/api/os_sys_calls_impl.h" +#include "common/common/assert.h" +#include "common/common/macros.h" +#include "common/http/headers.h" + +#include "extensions/filters/listener/http_inspector/http_protocol_header.h" +#include "extensions/transport_sockets/well_known_names.h" + +#include "absl/strings/match.h" +#include "absl/strings/str_split.h" + +namespace Envoy { +namespace Extensions { +namespace ListenerFilters { +namespace HttpInspector { + +Config::Config(Stats::Scope& scope) + : stats_{ALL_HTTP_INSPECTOR_STATS(POOL_COUNTER_PREFIX(scope, "http_inspector."))} {} + +const absl::string_view Filter::HTTP2_CONNECTION_PREFACE = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"; +thread_local uint8_t Filter::buf_[Config::MAX_INSPECT_SIZE]; + +Filter::Filter(const ConfigSharedPtr config) : config_(config) {} + +Network::FilterStatus Filter::onAccept(Network::ListenerFilterCallbacks& cb) { + ENVOY_LOG(debug, "http inspector: new connection accepted"); + + const Network::ConnectionSocket& socket = cb.socket(); + + const absl::string_view transport_protocol = socket.detectedTransportProtocol(); + if (!transport_protocol.empty() && + transport_protocol != TransportSockets::TransportSocketNames::get().RawBuffer) { + ENVOY_LOG(trace, "http inspector: cannot inspect http protocol with transport socket {}", + transport_protocol); + return Network::FilterStatus::Continue; + } + + ASSERT(file_event_ == nullptr); + + file_event_ = cb.dispatcher().createFileEvent( + socket.ioHandle().fd(), + [this](uint32_t events) { + ASSERT(events == Event::FileReadyType::Read); + onRead(); + }, + Event::FileTriggerType::Edge, Event::FileReadyType::Read); + + cb_ = &cb; + return Network::FilterStatus::StopIteration; +} + +void Filter::onRead() { + auto& os_syscalls = Api::OsSysCallsSingleton::get(); + const Network::ConnectionSocket& socket = cb_->socket(); + const Api::SysCallSizeResult result = + os_syscalls.recv(socket.ioHandle().fd(), buf_, Config::MAX_INSPECT_SIZE, MSG_PEEK); + ENVOY_LOG(trace, "http inspector: recv: {}", result.rc_); + if (result.rc_ == -1 && result.errno_ == EAGAIN) { + return; + } else if (result.rc_ < 0) { + config_->stats().read_error_.inc(); + return done(false); + } + + parseHttpHeader(absl::string_view(reinterpret_cast(buf_), result.rc_)); +} + +void Filter::parseHttpHeader(absl::string_view data) { + const size_t len = std::min(data.length(), Filter::HTTP2_CONNECTION_PREFACE.length()); + if (Filter::HTTP2_CONNECTION_PREFACE.compare(0, len, data, 0, len) == 0) { + if (data.length() < Filter::HTTP2_CONNECTION_PREFACE.length()) { + return; + } + ENVOY_LOG(trace, "http inspector: http2 connection preface found"); + protocol_ = "HTTP/2"; + done(true); + } else { + const size_t pos = data.find_first_of("\r\n"); + if (pos != absl::string_view::npos) { + const absl::string_view request_line = data.substr(0, pos); + const std::vector fields = + absl::StrSplit(request_line, absl::MaxSplits(' ', 4)); + + // Method SP Request-URI SP HTTP-Version + if (fields.size() != 3) { + ENVOY_LOG(trace, "http inspector: invalid http1x request line"); + return done(false); + } + + if (http1xMethods().count(fields[0]) == 0 || httpProtocols().count(fields[2]) == 0) { + ENVOY_LOG(trace, "http inspector: method: {} or protocol: {} not valid", fields[0], + fields[2]); + return done(false); + } + + ENVOY_LOG(trace, "http inspector: method: {}, request uri: {}, protocol: {}", fields[0], + fields[1], fields[2]); + + protocol_ = fields[2]; + return done(true); + } + } +} + +void Filter::done(bool success) { + ENVOY_LOG(trace, "http inspector: done: {}", success); + + if (success) { + absl::string_view protocol; + if (protocol_ == Http::Headers::get().ProtocolStrings.Http10String) { + config_->stats().http10_found_.inc(); + protocol = "http/1.0"; + } else if (protocol_ == Http::Headers::get().ProtocolStrings.Http11String) { + config_->stats().http11_found_.inc(); + protocol = "http/1.1"; + } else { + ASSERT(protocol_ == "HTTP/2"); + config_->stats().http2_found_.inc(); + protocol = "h2"; + } + + cb_->socket().setRequestedApplicationProtocols({protocol}); + } else { + config_->stats().http_not_found_.inc(); + } + + file_event_.reset(); + // Do not skip following listener filters. + cb_->continueFilterChain(true); +} + +const absl::flat_hash_set& Filter::httpProtocols() const { + CONSTRUCT_ON_FIRST_USE(absl::flat_hash_set, + Http::Headers::get().ProtocolStrings.Http10String, + Http::Headers::get().ProtocolStrings.Http11String); +} + +const absl::flat_hash_set& Filter::http1xMethods() const { + CONSTRUCT_ON_FIRST_USE(absl::flat_hash_set, + {HttpInspector::ExtendedHeader::get().MethodValues.Acl, + HttpInspector::ExtendedHeader::get().MethodValues.Baseline_Control, + HttpInspector::ExtendedHeader::get().MethodValues.Bind, + HttpInspector::ExtendedHeader::get().MethodValues.Checkin, + HttpInspector::ExtendedHeader::get().MethodValues.Checkout, + HttpInspector::ExtendedHeader::get().MethodValues.Connect, + HttpInspector::ExtendedHeader::get().MethodValues.Copy, + HttpInspector::ExtendedHeader::get().MethodValues.Delete, + HttpInspector::ExtendedHeader::get().MethodValues.Get, + HttpInspector::ExtendedHeader::get().MethodValues.Head, + HttpInspector::ExtendedHeader::get().MethodValues.Label, + HttpInspector::ExtendedHeader::get().MethodValues.Link, + HttpInspector::ExtendedHeader::get().MethodValues.Lock, + HttpInspector::ExtendedHeader::get().MethodValues.Merge, + HttpInspector::ExtendedHeader::get().MethodValues.Mkactivity, + HttpInspector::ExtendedHeader::get().MethodValues.Mkcalendar, + HttpInspector::ExtendedHeader::get().MethodValues.Mkcol, + HttpInspector::ExtendedHeader::get().MethodValues.Mkredirectref, + HttpInspector::ExtendedHeader::get().MethodValues.Mkworkspace, + HttpInspector::ExtendedHeader::get().MethodValues.Move, + HttpInspector::ExtendedHeader::get().MethodValues.Options, + HttpInspector::ExtendedHeader::get().MethodValues.Orderpatch, + HttpInspector::ExtendedHeader::get().MethodValues.Patch, + HttpInspector::ExtendedHeader::get().MethodValues.Post, + HttpInspector::ExtendedHeader::get().MethodValues.Proppatch, + HttpInspector::ExtendedHeader::get().MethodValues.Purge, + HttpInspector::ExtendedHeader::get().MethodValues.Put, + HttpInspector::ExtendedHeader::get().MethodValues.Rebind, + HttpInspector::ExtendedHeader::get().MethodValues.Report, + HttpInspector::ExtendedHeader::get().MethodValues.Search, + HttpInspector::ExtendedHeader::get().MethodValues.Trace, + HttpInspector::ExtendedHeader::get().MethodValues.Unbind, + HttpInspector::ExtendedHeader::get().MethodValues.Uncheckout, + HttpInspector::ExtendedHeader::get().MethodValues.Unlink, + HttpInspector::ExtendedHeader::get().MethodValues.Unlock, + HttpInspector::ExtendedHeader::get().MethodValues.Update, + HttpInspector::ExtendedHeader::get().MethodValues.Updateredirectref, + HttpInspector::ExtendedHeader::get().MethodValues.Version_Control}); +} + +} // namespace HttpInspector +} // namespace ListenerFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/listener/http_inspector/http_inspector.h b/source/extensions/filters/listener/http_inspector/http_inspector.h new file mode 100644 index 000000000000..affd419ca6e2 --- /dev/null +++ b/source/extensions/filters/listener/http_inspector/http_inspector.h @@ -0,0 +1,84 @@ +#pragma once + +#include "envoy/event/file_event.h" +#include "envoy/event/timer.h" +#include "envoy/network/filter.h" +#include "envoy/stats/scope.h" +#include "envoy/stats/stats_macros.h" + +#include "common/common/logger.h" + +#include "absl/container/flat_hash_set.h" + +namespace Envoy { +namespace Extensions { +namespace ListenerFilters { +namespace HttpInspector { + +/** + * All stats for the http inspector. @see stats_macros.h + */ +#define ALL_HTTP_INSPECTOR_STATS(COUNTER) \ + COUNTER(read_error) \ + COUNTER(http10_found) \ + COUNTER(http11_found) \ + COUNTER(http2_found) \ + COUNTER(http_not_found) + +/** + * Definition of all stats for the Http inspector. @see stats_macros.h + */ +struct HttpInspectorStats { + ALL_HTTP_INSPECTOR_STATS(GENERATE_COUNTER_STRUCT) +}; + +/** + * Global configuration for http inspector. + */ +class Config { +public: + Config(Stats::Scope& scope); + + const HttpInspectorStats& stats() const { return stats_; } + + static constexpr uint32_t MAX_INSPECT_SIZE = 8192; + +private: + HttpInspectorStats stats_; +}; + +using ConfigSharedPtr = std::shared_ptr; + +/** + * Http inspector listener filter. + */ +class Filter : public Network::ListenerFilter, Logger::Loggable { +public: + Filter(const ConfigSharedPtr config); + + // Network::ListenerFilter + Network::FilterStatus onAccept(Network::ListenerFilterCallbacks& cb) override; + +private: + static const absl::string_view HTTP2_CONNECTION_PREFACE; + + void onRead(); + void done(bool success); + void parseHttpHeader(absl::string_view data); + + const absl::flat_hash_set& httpProtocols() const; + const absl::flat_hash_set& http1xMethods() const; + + ConfigSharedPtr config_; + Network::ListenerFilterCallbacks* cb_{nullptr}; + Event::FileEventPtr file_event_; + absl::string_view protocol_; + + // Use static thread_local to avoid allocating buffer over and over again. + static thread_local uint8_t buf_[Config::MAX_INSPECT_SIZE]; +}; + +} // namespace HttpInspector +} // namespace ListenerFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/listener/http_inspector/http_protocol_header.h b/source/extensions/filters/listener/http_inspector/http_protocol_header.h new file mode 100644 index 000000000000..ddf2ff517f57 --- /dev/null +++ b/source/extensions/filters/listener/http_inspector/http_protocol_header.h @@ -0,0 +1,65 @@ +#pragma once + +#include + +#include "common/singleton/const_singleton.h" + +namespace Envoy { +namespace Extensions { +namespace ListenerFilters { +namespace HttpInspector { + +/** + * Class including extended methods. + */ +class ExtendedHeaderValues { +public: + struct { + const std::string Acl{"ACL"}; + const std::string Baseline_Control{"BASELINE-CONTROL"}; + const std::string Bind{"BIND"}; + const std::string Checkin{"CHECKIN"}; + const std::string Checkout{"CHECKOUT"}; + const std::string Connect{"CONNECT"}; + const std::string Copy{"COPY"}; + const std::string Delete{"DELETE"}; + const std::string Get{"GET"}; + const std::string Head{"HEAD"}; + const std::string Label{"LABEL"}; + const std::string Link{"LINK"}; + const std::string Lock{"LOCK"}; + const std::string Merge{"Merge"}; + const std::string Mkactivity{"MKACTIVITY"}; + const std::string Mkcalendar{"MKCALENDAR"}; + const std::string Mkcol{"MKCOL"}; + const std::string Mkredirectref{"MKREDIRECTREF"}; + const std::string Mkworkspace{"MKWORKSPACE"}; + const std::string Move{"MOVE"}; + const std::string Options{"OPTIONS"}; + const std::string Orderpatch{"ORDERPATCH"}; + const std::string Patch{"PATCH"}; + const std::string Post{"POST"}; + const std::string Pri{"PRI"}; + const std::string Proppatch{"PROPPATCH"}; + const std::string Purge{"PURGE"}; + const std::string Put{"PUT"}; + const std::string Rebind{"REBIND"}; + const std::string Report{"REPORT"}; + const std::string Search{"SEARCH"}; + const std::string Trace{"TRACE"}; + const std::string Unbind{"UNBIND"}; + const std::string Uncheckout{"UNCHECKOUT"}; + const std::string Unlink{"UNLINK"}; + const std::string Unlock{"UNLOCK"}; + const std::string Update{"UPDATE"}; + const std::string Updateredirectref{"UPDATEREDIRECTREF"}; + const std::string Version_Control{"VERSION-CONTROL"}; + } MethodValues; +}; + +using ExtendedHeader = ConstSingleton; + +} // namespace HttpInspector +} // namespace ListenerFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/listener/proxy_protocol/proxy_protocol.cc b/source/extensions/filters/listener/proxy_protocol/proxy_protocol.cc index 9c6fb7b93997..f4dce6138b9c 100644 --- a/source/extensions/filters/listener/proxy_protocol/proxy_protocol.cc +++ b/source/extensions/filters/listener/proxy_protocol/proxy_protocol.cc @@ -1,11 +1,11 @@ #include "extensions/filters/listener/proxy_protocol/proxy_protocol.h" -#include #include #include #include #include +#include #include #include diff --git a/source/extensions/filters/listener/well_known_names.h b/source/extensions/filters/listener/well_known_names.h index f7745ed2bba8..fa12272c598e 100644 --- a/source/extensions/filters/listener/well_known_names.h +++ b/source/extensions/filters/listener/well_known_names.h @@ -14,6 +14,8 @@ namespace ListenerFilters { */ class ListenerFilterNameValues { public: + // HTTP Inspector listener filter + const std::string HttpInspector = "envoy.listener.http_inspector"; // Original destination listener filter const std::string OriginalDst = "envoy.listener.original_dst"; // Original source listener filter diff --git a/source/extensions/filters/network/common/redis/client_impl.h b/source/extensions/filters/network/common/redis/client_impl.h index d88fc4c93e23..ffeb0ee458d8 100644 --- a/source/extensions/filters/network/common/redis/client_impl.h +++ b/source/extensions/filters/network/common/redis/client_impl.h @@ -65,7 +65,7 @@ class ClientImpl : public Client, public DecoderCallbacks, public Network::Conne EncoderPtr&& encoder, DecoderFactory& decoder_factory, const Config& config); - ~ClientImpl(); + ~ClientImpl() override; // Client void addConnectionCallbacks(Network::ConnectionCallbacks& callbacks) override { @@ -93,7 +93,7 @@ class ClientImpl : public Client, public DecoderCallbacks, public Network::Conne struct PendingRequest : public PoolRequest { PendingRequest(ClientImpl& parent, PoolCallbacks& callbacks); - ~PendingRequest(); + ~PendingRequest() override; // PoolRequest void cancel() override; diff --git a/source/extensions/filters/network/dubbo_proxy/BUILD b/source/extensions/filters/network/dubbo_proxy/BUILD index 88c33334bca7..9ac6ff1e40d7 100644 --- a/source/extensions/filters/network/dubbo_proxy/BUILD +++ b/source/extensions/filters/network/dubbo_proxy/BUILD @@ -36,6 +36,7 @@ envoy_cc_library( ":buffer_helper_lib", ":message_lib", ":metadata_lib", + ":serializer_interface", "//source/common/common:assert_lib", "//source/common/config:utility_lib", "//source/common/singleton:const_singleton", @@ -54,11 +55,12 @@ envoy_cc_library( ) envoy_cc_library( - name = "deserializer_interface", - srcs = ["deserializer_impl.cc"], + name = "serializer_interface", + srcs = ["serializer_impl.cc"], hdrs = [ - "deserializer.h", - "deserializer_impl.h", + "protocol_constants.h", + "serializer.h", + "serializer_impl.h", ], deps = [ ":message_lib", @@ -71,15 +73,15 @@ envoy_cc_library( ) envoy_cc_library( - name = "hessian_deserializer_impl_lib", - srcs = ["hessian_deserializer_impl.cc"], + name = "dubbo_hessian2_serializer_impl_lib", + srcs = ["dubbo_hessian2_serializer_impl.cc"], hdrs = [ - "hessian_deserializer_impl.h", + "dubbo_hessian2_serializer_impl.h", ], deps = [ ":buffer_helper_lib", - ":deserializer_interface", ":hessian_utils_lib", + ":serializer_interface", "//source/common/singleton:const_singleton", ], ) @@ -90,9 +92,8 @@ envoy_cc_library( hdrs = ["decoder.h"], deps = [ ":decoder_events_lib", + ":dubbo_hessian2_serializer_impl_lib", ":dubbo_protocol_impl_lib", - ":heartbeat_response_lib", - ":hessian_deserializer_impl_lib", "//source/common/buffer:buffer_lib", "//source/common/common:logger_lib", ], @@ -127,13 +128,20 @@ envoy_cc_library( external_deps = ["abseil_optional"], deps = [ ":message_lib", + "//source/common/buffer:buffer_lib", "//source/common/http:header_map_lib", ], ) envoy_cc_library( name = "message_lib", - hdrs = ["message.h"], + hdrs = [ + "message.h", + "message_impl.h", + ], + deps = [ + "//source/common/buffer:buffer_lib", + ], ) envoy_cc_library( @@ -161,10 +169,10 @@ envoy_cc_library( srcs = ["app_exception.cc"], hdrs = ["app_exception.h"], deps = [ - ":deserializer_interface", ":message_lib", ":metadata_lib", ":protocol_interface", + ":serializer_interface", "//include/envoy/buffer:buffer_interface", "//source/common/buffer:buffer_lib", "//source/extensions/filters/network/dubbo_proxy/filters:filter_interface", @@ -176,9 +184,9 @@ envoy_cc_library( srcs = ["heartbeat_response.cc"], hdrs = ["heartbeat_response.h"], deps = [ - ":deserializer_interface", ":metadata_lib", ":protocol_interface", + ":serializer_interface", "//include/envoy/buffer:buffer_interface", "//source/extensions/filters/network/dubbo_proxy/filters:filter_interface", ], @@ -198,9 +206,9 @@ envoy_cc_library( ":app_exception_lib", ":decoder_events_lib", ":decoder_lib", + ":dubbo_hessian2_serializer_impl_lib", ":dubbo_protocol_impl_lib", ":heartbeat_response_lib", - ":hessian_deserializer_impl_lib", ":stats_lib", "//include/envoy/event:deferred_deletable", "//include/envoy/event:dispatcher_interface", diff --git a/source/extensions/filters/network/dubbo_proxy/active_message.cc b/source/extensions/filters/network/dubbo_proxy/active_message.cc index 179c6852b370..4f44e3a9f638 100644 --- a/source/extensions/filters/network/dubbo_proxy/active_message.cc +++ b/source/extensions/filters/network/dubbo_proxy/active_message.cc @@ -8,94 +8,134 @@ namespace Extensions { namespace NetworkFilters { namespace DubboProxy { -// class ResponseDecoder -ResponseDecoder::ResponseDecoder(Buffer::Instance& buffer, DubboFilterStats& stats, - Network::Connection& connection, Deserializer& deserializer, - Protocol& protocol) - : response_buffer_(buffer), stats_(stats), response_connection_(connection), - decoder_(std::make_unique(protocol, deserializer, *this)), complete_(false) {} - -bool ResponseDecoder::onData(Buffer::Instance& data) { +// class ActiveResponseDecoder +ActiveResponseDecoder::ActiveResponseDecoder(ActiveMessage& parent, DubboFilterStats& stats, + Network::Connection& connection, + ProtocolPtr&& protocol) + : parent_(parent), stats_(stats), response_connection_(connection), + protocol_(std::move(protocol)), + decoder_(std::make_unique(*protocol_, *this)), complete_(false), + response_status_(DubboFilters::UpstreamResponseStatus::MoreData) {} + +DubboFilters::UpstreamResponseStatus ActiveResponseDecoder::onData(Buffer::Instance& data) { ENVOY_LOG(debug, "dubbo response: the received reply data length is {}", data.length()); bool underflow = false; decoder_->onData(data, underflow); ASSERT(complete_ || underflow); - return complete_; + + return response_status_; } -Network::FilterStatus ResponseDecoder::transportBegin() { - stats_.response_.inc(); - response_buffer_.drain(response_buffer_.length()); - ProtocolDataPassthroughConverter::initProtocolConverter(response_buffer_); +void ActiveResponseDecoder::onStreamDecoded(MessageMetadataSharedPtr metadata, + ContextSharedPtr ctx) { + ASSERT(metadata->message_type() == MessageType::Response || + metadata->message_type() == MessageType::Exception); + ASSERT(metadata->hasResponseStatus()); - return Network::FilterStatus::Continue; -} + if (applyMessageEncodedFilters(metadata, ctx) != FilterStatus::Continue) { + return; + } -Network::FilterStatus ResponseDecoder::transportEnd() { if (response_connection_.state() != Network::Connection::State::Open) { throw DownstreamConnectionCloseException("Downstream has closed or closing"); } - response_connection_.write(response_buffer_, false); + response_connection_.write(ctx->message_origin_data(), false); ENVOY_LOG(debug, "dubbo response: the upstream response message has been forwarded to the downstream"); - return Network::FilterStatus::Continue; -} - -Network::FilterStatus ResponseDecoder::messageBegin(MessageType, int64_t, SerializationType) { - return Network::FilterStatus::Continue; -} - -Network::FilterStatus ResponseDecoder::messageEnd(MessageMetadataSharedPtr metadata) { - ASSERT(metadata->message_type() == MessageType::Response || - metadata->message_type() == MessageType::Exception); - ASSERT(metadata->response_status().has_value()); + stats_.response_.inc(); stats_.response_decoding_success_.inc(); if (metadata->message_type() == MessageType::Exception) { stats_.response_business_exception_.inc(); } metadata_ = metadata; - switch (metadata->response_status().value()) { + switch (metadata->response_status()) { case ResponseStatus::Ok: stats_.response_success_.inc(); break; default: stats_.response_error_.inc(); ENVOY_LOG(error, "dubbo response status: {}", - static_cast(metadata->response_status().value())); + static_cast(metadata->response_status())); break; } complete_ = true; + response_status_ = DubboFilters::UpstreamResponseStatus::Complete; + ENVOY_LOG(debug, "dubbo response: complete processing of upstream response messages, id is {}", metadata->request_id()); - - return Network::FilterStatus::Continue; } -DecoderEventHandler* ResponseDecoder::newDecoderEventHandler() { return this; } +FilterStatus ActiveResponseDecoder::applyMessageEncodedFilters(MessageMetadataSharedPtr metadata, + ContextSharedPtr ctx) { + parent_.encoder_filter_action_ = [metadata, + ctx](DubboFilters::EncoderFilter* filter) -> FilterStatus { + return filter->onMessageEncoded(metadata, ctx); + }; -// class ActiveMessageDecoderFilter -ActiveMessageDecoderFilter::ActiveMessageDecoderFilter(ActiveMessage& parent, - DubboFilters::DecoderFilterSharedPtr filter) - : parent_(parent), handle_(filter) {} + auto status = parent_.applyEncoderFilters( + nullptr, ActiveMessage::FilterIterationStartState::CanStartFromCurrent); + switch (status) { + case FilterStatus::StopIteration: + break; + case FilterStatus::Retry: + response_status_ = DubboFilters::UpstreamResponseStatus::Retry; + decoder_->reset(); + break; + default: + ASSERT(FilterStatus::Continue == status); + break; + } -uint64_t ActiveMessageDecoderFilter::requestId() const { return parent_.requestId(); } + return status; +} + +// class ActiveMessageFilterBase +uint64_t ActiveMessageFilterBase::requestId() const { return parent_.requestId(); } -uint64_t ActiveMessageDecoderFilter::streamId() const { return parent_.streamId(); } +uint64_t ActiveMessageFilterBase::streamId() const { return parent_.streamId(); } -const Network::Connection* ActiveMessageDecoderFilter::connection() const { +const Network::Connection* ActiveMessageFilterBase::connection() const { return parent_.connection(); } +Router::RouteConstSharedPtr ActiveMessageFilterBase::route() { return parent_.route(); } + +SerializationType ActiveMessageFilterBase::serializationType() const { + return parent_.serializationType(); +} + +ProtocolType ActiveMessageFilterBase::protocolType() const { return parent_.protocolType(); } + +Event::Dispatcher& ActiveMessageFilterBase::dispatcher() { return parent_.dispatcher(); } + +void ActiveMessageFilterBase::resetStream() { parent_.resetStream(); } + +StreamInfo::StreamInfo& ActiveMessageFilterBase::streamInfo() { return parent_.streamInfo(); } + +// class ActiveMessageDecoderFilter +ActiveMessageDecoderFilter::ActiveMessageDecoderFilter(ActiveMessage& parent, + DubboFilters::DecoderFilterSharedPtr filter, + bool dual_filter) + : ActiveMessageFilterBase(parent, dual_filter), handle_(filter) {} + void ActiveMessageDecoderFilter::continueDecoding() { - const Network::FilterStatus status = parent_.applyDecoderFilters(this); - if (status == Network::FilterStatus::Continue) { + ASSERT(parent_.context()); + auto state = ActiveMessage::FilterIterationStartState::AlwaysStartFromNext; + if (0 != parent_.context()->message_origin_data().length()) { + state = ActiveMessage::FilterIterationStartState::CanStartFromCurrent; + ENVOY_LOG(warn, "The original message data is not consumed, triggering the decoder filter from " + "the current location"); + } + const FilterStatus status = parent_.applyDecoderFilters(this, state); + if (status == FilterStatus::Continue) { + ENVOY_LOG(debug, "dubbo response: start upstream"); // All filters have been executed for the current decoder state. - if (parent_.pending_transport_end()) { + if (parent_.pending_stream_decoded()) { // If the filter stack was paused during messageEnd, handle end-of-request details. parent_.finalizeRequest(); } @@ -103,25 +143,12 @@ void ActiveMessageDecoderFilter::continueDecoding() { } } -Router::RouteConstSharedPtr ActiveMessageDecoderFilter::route() { return parent_.route(); } - -SerializationType ActiveMessageDecoderFilter::downstreamSerializationType() const { - return parent_.downstreamSerializationType(); -} - -ProtocolType ActiveMessageDecoderFilter::downstreamProtocolType() const { - return parent_.downstreamProtocolType(); -} - void ActiveMessageDecoderFilter::sendLocalReply(const DubboFilters::DirectResponse& response, bool end_stream) { parent_.sendLocalReply(response, end_stream); } -void ActiveMessageDecoderFilter::startUpstreamResponse(Deserializer& deserializer, - Protocol& protocol) { - parent_.startUpstreamResponse(deserializer, protocol); -} +void ActiveMessageDecoderFilter::startUpstreamResponse() { parent_.startUpstreamResponse(); } DubboFilters::UpstreamResponseStatus ActiveMessageDecoderFilter::upstreamData(Buffer::Instance& buffer) { @@ -132,16 +159,32 @@ void ActiveMessageDecoderFilter::resetDownstreamConnection() { parent_.resetDownstreamConnection(); } -void ActiveMessageDecoderFilter::resetStream() { parent_.resetStream(); } +// class ActiveMessageEncoderFilter +ActiveMessageEncoderFilter::ActiveMessageEncoderFilter(ActiveMessage& parent, + DubboFilters::EncoderFilterSharedPtr filter, + bool dual_filter) + : ActiveMessageFilterBase(parent, dual_filter), handle_(filter) {} -StreamInfo::StreamInfo& ActiveMessageDecoderFilter::streamInfo() { return parent_.streamInfo(); } +void ActiveMessageEncoderFilter::continueEncoding() { + ASSERT(parent_.context()); + auto state = ActiveMessage::FilterIterationStartState::AlwaysStartFromNext; + if (0 != parent_.context()->message_origin_data().length()) { + state = ActiveMessage::FilterIterationStartState::CanStartFromCurrent; + ENVOY_LOG(warn, "The original message data is not consumed, triggering the encoder filter from " + "the current location"); + } + const FilterStatus status = parent_.applyEncoderFilters(this, state); + if (FilterStatus::Continue == status) { + ENVOY_LOG(debug, "All encoding filters have been executed"); + } +} // class ActiveMessage ActiveMessage::ActiveMessage(ConnectionManager& parent) : parent_(parent), request_timer_(std::make_unique( parent_.stats().request_time_ms_, parent.time_system())), request_id_(-1), stream_id_(parent.random_generator().random()), - stream_info_(parent.time_system()), pending_transport_end_(false), + stream_info_(parent.time_system()), pending_stream_decoded_(false), local_response_sent_(false) { parent_.stats().request_active_.inc(); stream_info_.setDownstreamLocalAddress(parent_.connection().localAddress()); @@ -157,95 +200,64 @@ ActiveMessage::~ActiveMessage() { ENVOY_LOG(debug, "ActiveMessage::~ActiveMessage()"); } -Network::FilterStatus ActiveMessage::transportBegin() { - filter_action_ = [](DubboFilters::DecoderFilter* filter) -> Network::FilterStatus { - return filter->transportBegin(); - }; - - return this->applyDecoderFilters(nullptr); -} - -Network::FilterStatus ActiveMessage::transportEnd() { - filter_action_ = [](DubboFilters::DecoderFilter* filter) -> Network::FilterStatus { - return filter->transportEnd(); - }; - - Network::FilterStatus status = applyDecoderFilters(nullptr); - if (status == Network::FilterStatus::StopIteration) { - pending_transport_end_ = true; - return status; +std::list::iterator +ActiveMessage::commonEncodePrefix(ActiveMessageEncoderFilter* filter, + FilterIterationStartState state) { + // Only do base state setting on the initial call. Subsequent calls for filtering do not touch + // the base state. + if (filter == nullptr) { + // ASSERT(!state_.local_complete_); + // state_.local_complete_ = end_stream; + return encoder_filters_.begin(); } - finalizeRequest(); - - ENVOY_LOG(debug, "dubbo request: complete processing of downstream request messages, id is {}", - request_id_); - - return status; + if (state == FilterIterationStartState::CanStartFromCurrent) { + // The filter iteration has been stopped for all frame types, and now the iteration continues. + // The current filter's encoding callback has not be called. Call it now. + return filter->entry(); + } + return std::next(filter->entry()); } -Network::FilterStatus ActiveMessage::messageBegin(MessageType type, int64_t message_id, - SerializationType serialization_type) { - request_id_ = message_id; - filter_action_ = [type, message_id, serialization_type]( - DubboFilters::DecoderFilter* filter) -> Network::FilterStatus { - return filter->messageBegin(type, message_id, serialization_type); - }; - - return applyDecoderFilters(nullptr); +std::list::iterator +ActiveMessage::commonDecodePrefix(ActiveMessageDecoderFilter* filter, + FilterIterationStartState state) { + if (!filter) { + return decoder_filters_.begin(); + } + if (state == FilterIterationStartState::CanStartFromCurrent) { + // The filter iteration has been stopped for all frame types, and now the iteration continues. + // The current filter's callback function has not been called. Call it now. + return filter->entry(); + } + return std::next(filter->entry()); } -Network::FilterStatus ActiveMessage::messageEnd(MessageMetadataSharedPtr metadata) { - ASSERT(metadata->message_type() == MessageType::Request || - metadata->message_type() == MessageType::Oneway); - - // Currently only hessian serialization is implemented. - ASSERT(metadata->serialization_type() == SerializationType::Hessian); - - ENVOY_LOG(debug, "dubbo request: start processing downstream request messages, id is {}", - metadata->request_id()); - +void ActiveMessage::onStreamDecoded(MessageMetadataSharedPtr metadata, ContextSharedPtr ctx) { parent_.stats().request_decoding_success_.inc(); metadata_ = metadata; - filter_action_ = [metadata](DubboFilters::DecoderFilter* filter) -> Network::FilterStatus { - return filter->messageEnd(metadata); + context_ = ctx; + filter_action_ = [metadata, ctx](DubboFilters::DecoderFilter* filter) -> FilterStatus { + return filter->onMessageDecoded(metadata, ctx); }; - return applyDecoderFilters(nullptr); -} - -Network::FilterStatus ActiveMessage::transferHeaderTo(Buffer::Instance& header_buf, size_t size) { - filter_action_ = [&header_buf, - size](DubboFilters::DecoderFilter* filter) -> Network::FilterStatus { - return filter->transferHeaderTo(header_buf, size); - }; - - // If a local reply is generated, the filter callback is skipped and - // the buffer data needs to be actively released. - if (local_response_sent_) { - header_buf.drain(size); + auto status = applyDecoderFilters(nullptr, FilterIterationStartState::CanStartFromCurrent); + if (status == FilterStatus::StopIteration) { + ENVOY_LOG(debug, "dubbo request: stop calling decoder filter, id is {}", + metadata->request_id()); + pending_stream_decoded_ = true; + return; } - return applyDecoderFilters(nullptr); -} - -Network::FilterStatus ActiveMessage::transferBodyTo(Buffer::Instance& body_buf, size_t size) { - filter_action_ = [&body_buf, size](DubboFilters::DecoderFilter* filter) -> Network::FilterStatus { - return filter->transferBodyTo(body_buf, size); - }; - - // If a local reply is generated, the filter callback is skipped and - // the buffer data needs to be actively released. - if (local_response_sent_) { - body_buf.drain(size); - } + finalizeRequest(); - return applyDecoderFilters(nullptr); + ENVOY_LOG(debug, "dubbo request: complete processing of downstream request messages, id is {}", + metadata->request_id()); } void ActiveMessage::finalizeRequest() { - pending_transport_end_ = false; + pending_stream_decoded_ = false; parent_.stats().request_.inc(); bool is_one_way = false; switch (metadata_->message_type()) { @@ -284,32 +296,47 @@ DubboProxy::Router::RouteConstSharedPtr ActiveMessage::route() { return nullptr; } -Network::FilterStatus ActiveMessage::applyDecoderFilters(ActiveMessageDecoderFilter* filter) { +FilterStatus ActiveMessage::applyDecoderFilters(ActiveMessageDecoderFilter* filter, + FilterIterationStartState state) { ASSERT(filter_action_ != nullptr); - if (!local_response_sent_) { - std::list::iterator entry; - if (!filter) { - entry = decoder_filters_.begin(); - } else { - entry = std::next(filter->entry()); + for (auto entry = commonDecodePrefix(filter, state); entry != decoder_filters_.end(); entry++) { + const FilterStatus status = filter_action_((*entry)->handler().get()); + if (local_response_sent_) { + break; + } + + if (status != FilterStatus::Continue) { + return status; + } } + } + + filter_action_ = nullptr; - for (; entry != decoder_filters_.end(); entry++) { - const Network::FilterStatus status = filter_action_((*entry)->handler().get()); + return FilterStatus::Continue; +} + +FilterStatus ActiveMessage::applyEncoderFilters(ActiveMessageEncoderFilter* filter, + FilterIterationStartState state) { + ASSERT(encoder_filter_action_ != nullptr); + + if (!local_response_sent_) { + for (auto entry = commonEncodePrefix(filter, state); entry != encoder_filters_.end(); entry++) { + const FilterStatus status = encoder_filter_action_((*entry)->handler().get()); if (local_response_sent_) { break; } - if (status != Network::FilterStatus::Continue) { + if (status != FilterStatus::Continue) { return status; } } } - filter_action_ = nullptr; + encoder_filter_action_ = nullptr; - return Network::FilterStatus::Continue; + return FilterStatus::Continue; } void ActiveMessage::sendLocalReply(const DubboFilters::DirectResponse& response, bool end_stream) { @@ -328,21 +355,25 @@ void ActiveMessage::sendLocalReply(const DubboFilters::DirectResponse& response, local_response_sent_ = true; } -void ActiveMessage::startUpstreamResponse(Deserializer& deserializer, Protocol& protocol) { +void ActiveMessage::startUpstreamResponse() { ENVOY_LOG(debug, "dubbo response: start upstream"); ASSERT(response_decoder_ == nullptr); + auto protocol = + NamedProtocolConfigFactory::getFactory(protocolType()).createProtocol(serializationType()); + // Create a response message decoder. - response_decoder_ = std::make_unique( - response_buffer_, parent_.stats(), parent_.connection(), deserializer, protocol); + response_decoder_ = std::make_unique( + *this, parent_.stats(), parent_.connection(), std::move(protocol)); } DubboFilters::UpstreamResponseStatus ActiveMessage::upstreamData(Buffer::Instance& buffer) { ASSERT(response_decoder_ != nullptr); try { - if (response_decoder_->onData(buffer)) { + auto status = response_decoder_->onData(buffer); + if (status == DubboFilters::UpstreamResponseStatus::Complete) { if (requestId() != response_decoder_->requestId()) { throw EnvoyException(fmt::format("dubbo response: request ID is not equal, {}:{}", requestId(), response_decoder_->requestId())); @@ -350,9 +381,11 @@ DubboFilters::UpstreamResponseStatus ActiveMessage::upstreamData(Buffer::Instanc // Completed upstream response. parent_.deferredMessage(*this); - return DubboFilters::UpstreamResponseStatus::Complete; + } else if (status == DubboFilters::UpstreamResponseStatus::Retry) { + response_decoder_.reset(); } - return DubboFilters::UpstreamResponseStatus::MoreData; + + return status; } catch (const DownstreamConnectionCloseException& ex) { ENVOY_CONN_LOG(error, "dubbo response: exception ({})", parent_.connection(), ex.what()); onReset(); @@ -381,24 +414,45 @@ uint64_t ActiveMessage::streamId() const { return stream_id_; } void ActiveMessage::continueDecoding() { parent_.continueDecoding(); } -SerializationType ActiveMessage::downstreamSerializationType() const { +SerializationType ActiveMessage::serializationType() const { return parent_.downstreamSerializationType(); } -ProtocolType ActiveMessage::downstreamProtocolType() const { - return parent_.downstreamProtocolType(); -} +ProtocolType ActiveMessage::protocolType() const { return parent_.downstreamProtocolType(); } StreamInfo::StreamInfo& ActiveMessage::streamInfo() { return stream_info_; } +Event::Dispatcher& ActiveMessage::dispatcher() { return parent_.connection().dispatcher(); } + const Network::Connection* ActiveMessage::connection() const { return &parent_.connection(); } void ActiveMessage::addDecoderFilter(DubboFilters::DecoderFilterSharedPtr filter) { + addDecoderFilterWorker(filter, false); +} + +void ActiveMessage::addEncoderFilter(DubboFilters::EncoderFilterSharedPtr filter) { + addEncoderFilterWorker(filter, false); +} + +void ActiveMessage::addFilter(DubboFilters::CodecFilterSharedPtr filter) { + addDecoderFilterWorker(filter, true); + addEncoderFilterWorker(filter, true); +} + +void ActiveMessage::addDecoderFilterWorker(DubboFilters::DecoderFilterSharedPtr filter, + bool dual_filter) { ActiveMessageDecoderFilterPtr wrapper = - std::make_unique(*this, filter); + std::make_unique(*this, filter, dual_filter); filter->setDecoderFilterCallbacks(*wrapper); wrapper->moveIntoListBack(std::move(wrapper), decoder_filters_); } +void ActiveMessage::addEncoderFilterWorker(DubboFilters::EncoderFilterSharedPtr filter, + bool dual_filter) { + ActiveMessageEncoderFilterPtr wrapper = + std::make_unique(*this, filter, dual_filter); + filter->setEncoderFilterCallbacks(*wrapper); + wrapper->moveIntoListBack(std::move(wrapper), encoder_filters_); +} void ActiveMessage::onReset() { parent_.deferredMessage(*this); } diff --git a/source/extensions/filters/network/dubbo_proxy/active_message.h b/source/extensions/filters/network/dubbo_proxy/active_message.h index 712651ce9a77..6dca717c577d 100644 --- a/source/extensions/filters/network/dubbo_proxy/active_message.h +++ b/source/extensions/filters/network/dubbo_proxy/active_message.h @@ -27,75 +27,111 @@ namespace DubboProxy { class ConnectionManager; class ActiveMessage; -class ResponseDecoder : public DecoderCallbacks, - public DecoderEventHandler, - Logger::Loggable { +class ActiveResponseDecoder : public ResponseDecoderCallbacks, + public StreamHandler, + Logger::Loggable { public: - ResponseDecoder(Buffer::Instance& buffer, DubboFilterStats& stats, - Network::Connection& connection, Deserializer& deserializer, Protocol& protocol); - ~ResponseDecoder() override = default; + ActiveResponseDecoder(ActiveMessage& parent, DubboFilterStats& stats, + Network::Connection& connection, ProtocolPtr&& protocol); + ~ActiveResponseDecoder() override = default; - bool onData(Buffer::Instance& data); + DubboFilters::UpstreamResponseStatus onData(Buffer::Instance& data); - // DecoderEventHandler - Network::FilterStatus transportBegin() override; - Network::FilterStatus transportEnd() override; - Network::FilterStatus messageBegin(MessageType type, int64_t message_id, - SerializationType serialization_type) override; - Network::FilterStatus messageEnd(MessageMetadataSharedPtr metadata) override; + // StreamHandler + void onStreamDecoded(MessageMetadataSharedPtr metadata, ContextSharedPtr ctx) override; - // DecoderCallbacks - DecoderEventHandler* newDecoderEventHandler() override; + // ResponseDecoderCallbacks + StreamHandler& newStream() override { return *this; } + void onHeartbeat(MessageMetadataSharedPtr) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } uint64_t requestId() const { return metadata_ ? metadata_->request_id() : 0; } private: - Buffer::Instance& response_buffer_; + FilterStatus applyMessageEncodedFilters(MessageMetadataSharedPtr metadata, ContextSharedPtr ctx); + + ActiveMessage& parent_; DubboFilterStats& stats_; Network::Connection& response_connection_; - DecoderPtr decoder_; + ProtocolPtr protocol_; + ResponseDecoderPtr decoder_; MessageMetadataSharedPtr metadata_; bool complete_ : 1; + DubboFilters::UpstreamResponseStatus response_status_; }; -using ResponseDecoderPtr = std::unique_ptr; +using ActiveResponseDecoderPtr = std::unique_ptr; + +class ActiveMessageFilterBase : public virtual DubboFilters::FilterCallbacksBase { +public: + ActiveMessageFilterBase(ActiveMessage& parent, bool dual_filter) + : parent_(parent), dual_filter_(dual_filter) {} + ~ActiveMessageFilterBase() override = default; + + // DubboFilters::FilterCallbacksBase + uint64_t requestId() const override; + uint64_t streamId() const override; + const Network::Connection* connection() const override; + DubboProxy::Router::RouteConstSharedPtr route() override; + SerializationType serializationType() const override; + ProtocolType protocolType() const override; + StreamInfo::StreamInfo& streamInfo() override; + Event::Dispatcher& dispatcher() override; + void resetStream() override; + +protected: + ActiveMessage& parent_; + const bool dual_filter_ : 1; +}; // Wraps a DecoderFilter and acts as the DecoderFilterCallbacks for the filter, enabling filter // chain continuation. class ActiveMessageDecoderFilter : public DubboFilters::DecoderFilterCallbacks, - public LinkedObject { + public ActiveMessageFilterBase, + public LinkedObject, + Logger::Loggable { public: - ActiveMessageDecoderFilter(ActiveMessage& parent, DubboFilters::DecoderFilterSharedPtr filter); + ActiveMessageDecoderFilter(ActiveMessage& parent, DubboFilters::DecoderFilterSharedPtr filter, + bool dual_filter); ~ActiveMessageDecoderFilter() override = default; - // DubboFilters::DecoderFilterCallbacks - uint64_t requestId() const override; - uint64_t streamId() const override; - const Network::Connection* connection() const override; void continueDecoding() override; - DubboProxy::Router::RouteConstSharedPtr route() override; - SerializationType downstreamSerializationType() const override; - ProtocolType downstreamProtocolType() const override; void sendLocalReply(const DubboFilters::DirectResponse& response, bool end_stream) override; - void startUpstreamResponse(Deserializer& deserializer, Protocol& protocol) override; + void startUpstreamResponse() override; DubboFilters::UpstreamResponseStatus upstreamData(Buffer::Instance& buffer) override; void resetDownstreamConnection() override; - StreamInfo::StreamInfo& streamInfo() override; - void resetStream() override; DubboFilters::DecoderFilterSharedPtr handler() { return handle_; } private: - ActiveMessage& parent_; DubboFilters::DecoderFilterSharedPtr handle_; }; using ActiveMessageDecoderFilterPtr = std::unique_ptr; +// Wraps a EncoderFilter and acts as the EncoderFilterCallbacks for the filter, enabling filter +// chain continuation. +class ActiveMessageEncoderFilter : public ActiveMessageFilterBase, + public DubboFilters::EncoderFilterCallbacks, + public LinkedObject, + Logger::Loggable { +public: + ActiveMessageEncoderFilter(ActiveMessage& parent, DubboFilters::EncoderFilterSharedPtr filter, + bool dual_filter); + ~ActiveMessageEncoderFilter() override = default; + + void continueEncoding() override; + DubboFilters::EncoderFilterSharedPtr handler() { return handle_; } + +private: + DubboFilters::EncoderFilterSharedPtr handle_; +}; + +using ActiveMessageEncoderFilterPtr = std::unique_ptr; + // ActiveMessage tracks downstream requests for which no response has been received. class ActiveMessage : public LinkedObject, public Event::DeferredDeletable, - public DecoderEventHandler, + public StreamHandler, public DubboFilters::DecoderFilterCallbacks, public DubboFilters::FilterChainFactoryCallbacks, Logger::Loggable { @@ -103,52 +139,70 @@ class ActiveMessage : public LinkedObject, ActiveMessage(ConnectionManager& parent); ~ActiveMessage() override; + // Indicates which filter to start the iteration with. + enum class FilterIterationStartState { AlwaysStartFromNext, CanStartFromCurrent }; + + // Returns the encoder filter to start iteration with. + std::list::iterator + commonEncodePrefix(ActiveMessageEncoderFilter* filter, FilterIterationStartState state); + // Returns the decoder filter to start iteration with. + std::list::iterator + commonDecodePrefix(ActiveMessageDecoderFilter* filter, FilterIterationStartState state); + // Dubbo::FilterChainFactoryCallbacks void addDecoderFilter(DubboFilters::DecoderFilterSharedPtr filter) override; + void addEncoderFilter(DubboFilters::EncoderFilterSharedPtr filter) override; + void addFilter(DubboFilters::CodecFilterSharedPtr filter) override; - // DecoderEventHandler - Network::FilterStatus transportBegin() override; - Network::FilterStatus transportEnd() override; - Network::FilterStatus messageBegin(MessageType type, int64_t message_id, - SerializationType serialization_type) override; - Network::FilterStatus messageEnd(MessageMetadataSharedPtr metadata) override; - Network::FilterStatus transferHeaderTo(Buffer::Instance& header_buf, size_t size) override; - Network::FilterStatus transferBodyTo(Buffer::Instance& body_buf, size_t size) override; + // StreamHandler + void onStreamDecoded(MessageMetadataSharedPtr metadata, ContextSharedPtr ctx) override; // DubboFilters::DecoderFilterCallbacks uint64_t requestId() const override; uint64_t streamId() const override; const Network::Connection* connection() const override; void continueDecoding() override; - SerializationType downstreamSerializationType() const override; - ProtocolType downstreamProtocolType() const override; + SerializationType serializationType() const override; + ProtocolType protocolType() const override; StreamInfo::StreamInfo& streamInfo() override; Router::RouteConstSharedPtr route() override; void sendLocalReply(const DubboFilters::DirectResponse& response, bool end_stream) override; - void startUpstreamResponse(Deserializer& deserializer, Protocol& protocol) override; + void startUpstreamResponse() override; DubboFilters::UpstreamResponseStatus upstreamData(Buffer::Instance& buffer) override; void resetDownstreamConnection() override; + Event::Dispatcher& dispatcher() override; void resetStream() override; void createFilterChain(); - Network::FilterStatus applyDecoderFilters(ActiveMessageDecoderFilter* filter); + FilterStatus applyDecoderFilters(ActiveMessageDecoderFilter* filter, + FilterIterationStartState state); + FilterStatus applyEncoderFilters(ActiveMessageEncoderFilter* filter, + FilterIterationStartState state); void finalizeRequest(); void onReset(); void onError(const std::string& what); MessageMetadataSharedPtr metadata() const { return metadata_; } - bool pending_transport_end() const { return pending_transport_end_; } + ContextSharedPtr context() const { return context_; } + bool pending_stream_decoded() const { return pending_stream_decoded_; } private: + void addDecoderFilterWorker(DubboFilters::DecoderFilterSharedPtr filter, bool dual_filter); + void addEncoderFilterWorker(DubboFilters::EncoderFilterSharedPtr, bool dual_filter); + ConnectionManager& parent_; + ContextSharedPtr context_; MessageMetadataSharedPtr metadata_; Stats::TimespanPtr request_timer_; - ResponseDecoderPtr response_decoder_; + ActiveResponseDecoderPtr response_decoder_; absl::optional cached_route_; std::list decoder_filters_; - std::function filter_action_; + std::function filter_action_; + + std::list encoder_filters_; + std::function encoder_filter_action_; int32_t request_id_; @@ -158,8 +212,10 @@ class ActiveMessage : public LinkedObject, Buffer::OwnedImpl response_buffer_; - bool pending_transport_end_ : 1; + bool pending_stream_decoded_ : 1; bool local_response_sent_ : 1; + + friend class ActiveResponseDecoder; }; using ActiveMessagePtr = std::unique_ptr; diff --git a/source/extensions/filters/network/dubbo_proxy/app_exception.cc b/source/extensions/filters/network/dubbo_proxy/app_exception.cc index 8c35ce60c492..dc5a8a083012 100644 --- a/source/extensions/filters/network/dubbo_proxy/app_exception.cc +++ b/source/extensions/filters/network/dubbo_proxy/app_exception.cc @@ -9,35 +9,6 @@ namespace Extensions { namespace NetworkFilters { namespace DubboProxy { -AppException::AppException(ResponseStatus status, const std::string& what) - : EnvoyException(what), status_(status), - response_type_(RpcResponseType::ResponseWithException) {} - -AppException::ResponseType AppException::encode(MessageMetadata& metadata, - DubboProxy::Protocol& protocol, - Deserializer& deserializer, - Buffer::Instance& buffer) const { - ASSERT(buffer.length() == 0); - - ENVOY_LOG(debug, "err {}", what()); - - // Serialize the response content to get the serialized response length. - const std::string& response = what(); - size_t serialized_body_size = deserializer.serializeRpcResult(buffer, response, response_type_); - - metadata.setResponseStatus(status_); - metadata.setMessageType(MessageType::Response); - - Buffer::OwnedImpl protocol_buffer; - if (!protocol.encode(protocol_buffer, serialized_body_size, metadata)) { - throw EnvoyException("failed to encode local reply message"); - } - - buffer.prepend(protocol_buffer); - - return DirectResponse::ResponseType::Exception; -} - DownstreamConnectionCloseException::DownstreamConnectionCloseException(const std::string& what) : EnvoyException(what) {} diff --git a/source/extensions/filters/network/dubbo_proxy/app_exception.h b/source/extensions/filters/network/dubbo_proxy/app_exception.h index ae68fb47d593..f7415018d654 100644 --- a/source/extensions/filters/network/dubbo_proxy/app_exception.h +++ b/source/extensions/filters/network/dubbo_proxy/app_exception.h @@ -2,30 +2,48 @@ #include "envoy/common/exception.h" -#include "extensions/filters/network/dubbo_proxy/deserializer.h" #include "extensions/filters/network/dubbo_proxy/filters/filter.h" #include "extensions/filters/network/dubbo_proxy/metadata.h" #include "extensions/filters/network/dubbo_proxy/protocol.h" +#include "extensions/filters/network/dubbo_proxy/serializer.h" namespace Envoy { namespace Extensions { namespace NetworkFilters { namespace DubboProxy { -struct AppException : public EnvoyException, - public DubboFilters::DirectResponse, - Logger::Loggable { - AppException(ResponseStatus status, const std::string& what); - AppException(const AppException& ex) = default; +using ResponseType = DubboFilters::DirectResponse::ResponseType; - using ResponseType = DubboFilters::DirectResponse::ResponseType; - ResponseType encode(MessageMetadata& metadata, Protocol& protocol, Deserializer& deserializer, - Buffer::Instance& buffer) const override; +template +struct AppExceptionBase : public EnvoyException, + public DubboFilters::DirectResponse, + Logger::Loggable { + AppExceptionBase(const AppExceptionBase& ex) = default; + AppExceptionBase(T status, const std::string& what) + : EnvoyException(what), status_(status), + response_type_(RpcResponseType::ResponseWithException) {} - const ResponseStatus status_; + ResponseType encode(MessageMetadata& metadata, DubboProxy::Protocol& protocol, + Buffer::Instance& buffer) const override { + ASSERT(buffer.length() == 0); + + ENVOY_LOG(debug, "Exception information: {}", what()); + + metadata.setResponseStatus(status_); + metadata.setMessageType(MessageType::Response); + if (!protocol.encode(buffer, metadata, what(), response_type_)) { + throw EnvoyException("Failed to encode local reply message"); + } + + return ResponseType::Exception; + } + + const T status_; const RpcResponseType response_type_; }; +using AppException = AppExceptionBase<>; + struct DownstreamConnectionCloseException : public EnvoyException { DownstreamConnectionCloseException(const std::string& what); }; diff --git a/source/extensions/filters/network/dubbo_proxy/config.cc b/source/extensions/filters/network/dubbo_proxy/config.cc index 1c145d590acd..92ea0c534aac 100644 --- a/source/extensions/filters/network/dubbo_proxy/config.cc +++ b/source/extensions/filters/network/dubbo_proxy/config.cc @@ -9,6 +9,8 @@ #include "extensions/filters/network/dubbo_proxy/filters/well_known_names.h" #include "extensions/filters/network/dubbo_proxy/stats.h" +#include "absl/container/flat_hash_map.h" + namespace Envoy { namespace Extensions { namespace NetworkFilters { @@ -66,7 +68,27 @@ class SerializationTypeMapper { static const SerializationTypeMap& serializationTypeMap() { CONSTRUCT_ON_FIRST_USE(SerializationTypeMap, { - {ConfigSerializationType::Hessian2, SerializationType::Hessian}, + {ConfigSerializationType::Hessian2, SerializationType::Hessian2}, + }); + } +}; + +class RouteMatcherTypeMapper { +public: + using ConfigProtocolType = envoy::config::filter::network::dubbo_proxy::v2alpha1::ProtocolType; + using RouteMatcherTypeMap = absl::flat_hash_map; + + static Router::RouteMatcherType lookupRouteMatcherType(ConfigProtocolType type) { + const auto& iter = routeMatcherTypeMap().find(type); + ASSERT(iter != routeMatcherTypeMap().end()); + return iter->second; + } + +private: + static const RouteMatcherTypeMap& routeMatcherTypeMap() { + CONSTRUCT_ON_FIRST_USE(RouteMatcherTypeMap, + { + {ConfigProtocolType::Dubbo, Router::RouteMatcherType::Default}, }); } }; @@ -78,8 +100,10 @@ ConfigImpl::ConfigImpl(const DubboProxyConfig& config, stats_(DubboFilterStats::generateStats(stats_prefix_, context_.scope())), serialization_type_( SerializationTypeMapper::lookupSerializationType(config.serialization_type())), - protocol_type_(ProtocolTypeMapper::lookupProtocolType(config.protocol_type())), - route_matcher_(std::make_unique(config.route_config())) { + protocol_type_(ProtocolTypeMapper::lookupProtocolType(config.protocol_type())) { + auto type = RouteMatcherTypeMapper::lookupRouteMatcherType(config.protocol_type()); + route_matcher_ = Router::NamedRouteMatcherConfigFactory::getFactory(type).createRouteMatcher( + config.route_config(), context); if (config.dubbo_filters().empty()) { ENVOY_LOG(debug, "using default router filter"); @@ -105,11 +129,7 @@ Router::RouteConstSharedPtr ConfigImpl::route(const MessageMetadata& metadata, } ProtocolPtr ConfigImpl::createProtocol() { - return NamedProtocolConfigFactory::getFactory(protocol_type_).createProtocol(); -} - -DeserializerPtr ConfigImpl::createDeserializer() { - return NamedDeserializerConfigFactory::getFactory(serialization_type_).createDeserializer(); + return NamedProtocolConfigFactory::getFactory(protocol_type_).createProtocol(serialization_type_); } void ConfigImpl::registerFilter(const DubboFilterConfig& proto_config) { diff --git a/source/extensions/filters/network/dubbo_proxy/config.h b/source/extensions/filters/network/dubbo_proxy/config.h index 076298217bf8..c0c09967b95a 100644 --- a/source/extensions/filters/network/dubbo_proxy/config.h +++ b/source/extensions/filters/network/dubbo_proxy/config.h @@ -55,7 +55,6 @@ class ConfigImpl : public Config, DubboFilters::FilterChainFactory& filterFactory() override { return *this; } Router::Config& routerConfig() override { return *this; } ProtocolPtr createProtocol() override; - DeserializerPtr createDeserializer() override; private: void registerFilter(const DubboFilterConfig& proto_config); @@ -65,7 +64,7 @@ class ConfigImpl : public Config, DubboFilterStats stats_; const SerializationType serialization_type_; const ProtocolType protocol_type_; - std::unique_ptr route_matcher_; + Router::RouteMatcherPtr route_matcher_; std::list filter_factories_; }; diff --git a/source/extensions/filters/network/dubbo_proxy/conn_manager.cc b/source/extensions/filters/network/dubbo_proxy/conn_manager.cc index 94f935df3ca6..b9a5f27d278f 100644 --- a/source/extensions/filters/network/dubbo_proxy/conn_manager.cc +++ b/source/extensions/filters/network/dubbo_proxy/conn_manager.cc @@ -1,15 +1,15 @@ #include "extensions/filters/network/dubbo_proxy/conn_manager.h" -#include +#include #include "envoy/common/exception.h" #include "common/common/fmt.h" #include "extensions/filters/network/dubbo_proxy/app_exception.h" +#include "extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.h" #include "extensions/filters/network/dubbo_proxy/dubbo_protocol_impl.h" #include "extensions/filters/network/dubbo_proxy/heartbeat_response.h" -#include "extensions/filters/network/dubbo_proxy/hessian_deserializer_impl.h" namespace Envoy { namespace Extensions { @@ -21,9 +21,8 @@ constexpr uint32_t BufferLimit = UINT32_MAX; ConnectionManager::ConnectionManager(Config& config, Runtime::RandomGenerator& random_generator, TimeSource& time_system) : config_(config), time_system_(time_system), stats_(config_.stats()), - random_generator_(random_generator), deserializer_(config.createDeserializer()), - protocol_(config.createProtocol()), - decoder_(std::make_unique(*protocol_.get(), *deserializer_.get(), *this)) {} + random_generator_(random_generator), protocol_(config.createProtocol()), + decoder_(std::make_unique(*protocol_, *this)) {} Network::FilterStatus ConnectionManager::onData(Buffer::Instance& data, bool end_stream) { ENVOY_LOG(trace, "dubbo: read {} bytes", data.length()); @@ -79,13 +78,13 @@ void ConnectionManager::onBelowWriteBufferLowWatermark() { read_callbacks_->connection().readDisable(false); } -DecoderEventHandler* ConnectionManager::newDecoderEventHandler() { +StreamHandler& ConnectionManager::newStream() { ENVOY_LOG(debug, "dubbo: create the new docoder event handler"); ActiveMessagePtr new_message(std::make_unique(*this)); new_message->createFilterChain(); new_message->moveIntoList(std::move(new_message), active_message_list_); - return (*active_message_list_.begin()).get(); + return **active_message_list_.begin(); } void ConnectionManager::onHeartbeat(MessageMetadataSharedPtr metadata) { @@ -97,12 +96,11 @@ void ConnectionManager::onHeartbeat(MessageMetadataSharedPtr metadata) { } metadata->setResponseStatus(ResponseStatus::Ok); - metadata->setMessageType(MessageType::Response); - metadata->setEventFlag(true); + metadata->setMessageType(MessageType::HeartbeatResponse); HeartbeatResponse heartbeat; Buffer::OwnedImpl response_buffer; - heartbeat.encode(*metadata, *protocol_, *deserializer_, response_buffer); + heartbeat.encode(*metadata, *protocol_, response_buffer); read_callbacks_->connection().write(response_buffer, false); } @@ -121,11 +119,7 @@ void ConnectionManager::dispatch() { try { bool underflow = false; while (!underflow) { - Network::FilterStatus status = decoder_->onData(request_buffer_, underflow); - if (status == Network::FilterStatus::StopIteration) { - stopped_ = true; - break; - } + decoder_->onData(request_buffer_, underflow); } return; } catch (const EnvoyException& ex) { @@ -143,10 +137,16 @@ void ConnectionManager::sendLocalReply(MessageMetadata& metadata, return; } - Buffer::OwnedImpl buffer; - const DubboFilters::DirectResponse::ResponseType result = - response.encode(metadata, *protocol_, *deserializer_, buffer); - read_callbacks_->connection().write(buffer, end_stream); + DubboFilters::DirectResponse::ResponseType result = + DubboFilters::DirectResponse::ResponseType::ErrorReply; + + try { + Buffer::OwnedImpl buffer; + result = response.encode(metadata, *protocol_, buffer); + read_callbacks_->connection().write(buffer, end_stream); + } catch (const EnvoyException& ex) { + ENVOY_CONN_LOG(error, "dubbo error: {}", read_callbacks_->connection(), ex.what()); + } if (end_stream) { read_callbacks_->connection().close(Network::ConnectionCloseType::FlushWrite); diff --git a/source/extensions/filters/network/dubbo_proxy/conn_manager.h b/source/extensions/filters/network/dubbo_proxy/conn_manager.h index c46417862b8c..b274c61a867a 100644 --- a/source/extensions/filters/network/dubbo_proxy/conn_manager.h +++ b/source/extensions/filters/network/dubbo_proxy/conn_manager.h @@ -15,9 +15,9 @@ #include "extensions/filters/network/dubbo_proxy/active_message.h" #include "extensions/filters/network/dubbo_proxy/decoder.h" #include "extensions/filters/network/dubbo_proxy/decoder_event_handler.h" -#include "extensions/filters/network/dubbo_proxy/deserializer.h" #include "extensions/filters/network/dubbo_proxy/filters/filter.h" #include "extensions/filters/network/dubbo_proxy/protocol.h" +#include "extensions/filters/network/dubbo_proxy/serializer.h" #include "extensions/filters/network/dubbo_proxy/stats.h" namespace Envoy { @@ -35,14 +35,13 @@ class Config { virtual DubboFilters::FilterChainFactory& filterFactory() PURE; virtual DubboFilterStats& stats() PURE; virtual ProtocolPtr createProtocol() PURE; - virtual DeserializerPtr createDeserializer() PURE; virtual Router::Config& routerConfig() PURE; }; // class ActiveMessagePtr; class ConnectionManager : public Network::ReadFilter, public Network::ConnectionCallbacks, - public DecoderCallbacks, + public RequestDecoderCallbacks, Logger::Loggable { public: using ConfigProtocolType = envoy::config::filter::network::dubbo_proxy::v2alpha1::ProtocolType; @@ -63,8 +62,8 @@ class ConnectionManager : public Network::ReadFilter, void onAboveWriteBufferHighWatermark() override; void onBelowWriteBufferLowWatermark() override; - // DecoderCallbacks - DecoderEventHandler* newDecoderEventHandler() override; + // RequestDecoderCallbacks + StreamHandler& newStream() override; void onHeartbeat(MessageMetadataSharedPtr metadata) override; DubboFilterStats& stats() const { return stats_; } @@ -72,7 +71,7 @@ class ConnectionManager : public Network::ReadFilter, TimeSource& time_system() const { return time_system_; } Runtime::RandomGenerator& random_generator() const { return random_generator_; } Config& config() const { return config_; } - SerializationType downstreamSerializationType() const { return deserializer_->type(); } + SerializationType downstreamSerializationType() const { return protocol_->serializer()->type(); } ProtocolType downstreamProtocolType() const { return protocol_->type(); } void continueDecoding(); @@ -95,9 +94,9 @@ class ConnectionManager : public Network::ReadFilter, DubboFilterStats& stats_; Runtime::RandomGenerator& random_generator_; - DeserializerPtr deserializer_; + SerializerPtr serializer_; ProtocolPtr protocol_; - DecoderPtr decoder_; + RequestDecoderPtr decoder_; Network::ReadFilterCallbacks* read_callbacks_{}; }; diff --git a/source/extensions/filters/network/dubbo_proxy/decoder.cc b/source/extensions/filters/network/dubbo_proxy/decoder.cc index 6d7538c7ec6c..f7e9cfc84a24 100644 --- a/source/extensions/filters/network/dubbo_proxy/decoder.cc +++ b/source/extensions/filters/network/dubbo_proxy/decoder.cc @@ -2,102 +2,64 @@ #include "common/common/macros.h" -#include "extensions/filters/network/dubbo_proxy/heartbeat_response.h" - namespace Envoy { namespace Extensions { namespace NetworkFilters { namespace DubboProxy { DecoderStateMachine::DecoderStatus -DecoderStateMachine::onTransportBegin(Buffer::Instance& buffer, Protocol::Context& context) { - if (!protocol_.decode(buffer, &context, metadata_)) { +DecoderStateMachine::onDecodeStreamHeader(Buffer::Instance& buffer) { + ASSERT(!active_stream_); + + auto metadata = std::make_shared(); + auto ret = protocol_.decodeHeader(buffer, metadata); + if (!ret.second) { ENVOY_LOG(debug, "dubbo decoder: need more data for {} protocol", protocol_.name()); return {ProtocolState::WaitForData}; } - if (context.is_heartbeat_) { + // The heartbeat message has no body. + auto context = ret.first; + if (metadata->message_type() == MessageType::HeartbeatRequest || + metadata->message_type() == MessageType::HeartbeatResponse) { ENVOY_LOG(debug, "dubbo decoder: this is the {} heartbeat message", protocol_.name()); - buffer.drain(context.header_size_); - decoder_callbacks_.onHeartbeat(metadata_); - return {ProtocolState::Done, Network::FilterStatus::Continue}; - } else { - handler_ = decoder_callbacks_.newDecoderEventHandler(); + buffer.drain(context->header_size()); + delegate_.onHeartbeat(metadata); + return {ProtocolState::Done}; } - return {ProtocolState::OnTransferHeaderTo, handler_->transportBegin()}; -} - -DecoderStateMachine::DecoderStatus DecoderStateMachine::onTransportEnd() { - ENVOY_LOG(debug, "dubbo decoder: complete protocol processing"); - return {ProtocolState::Done, handler_->transportEnd()}; -} -DecoderStateMachine::DecoderStatus DecoderStateMachine::onTransferHeaderTo(Buffer::Instance& buffer, - size_t length) { - ENVOY_LOG(debug, "dubbo decoder: transfer protocol header, buffer size {}, header size {}", - buffer.length(), length); - return {ProtocolState::OnMessageBegin, handler_->transferHeaderTo(buffer, length)}; -} - -DecoderStateMachine::DecoderStatus DecoderStateMachine::onTransferBodyTo(Buffer::Instance& buffer, - int32_t length) { - ENVOY_LOG(debug, "dubbo decoder: transfer protocol body, buffer size {}, body size {}", - buffer.length(), length); - return {ProtocolState::OnTransportEnd, handler_->transferBodyTo(buffer, length)}; -} + active_stream_ = delegate_.newStream(metadata, context); + ASSERT(active_stream_); + context->message_origin_data().move(buffer, context->header_size()); -DecoderStateMachine::DecoderStatus DecoderStateMachine::onMessageBegin() { - ENVOY_LOG(debug, "dubbo decoder: start deserializing messages, deserializer name {}", - deserializer_.name()); - return {ProtocolState::OnMessageEnd, - handler_->messageBegin(metadata_->message_type(), metadata_->request_id(), - metadata_->serialization_type())}; + return {ProtocolState::OnDecodeStreamData}; } -DecoderStateMachine::DecoderStatus DecoderStateMachine::onMessageEnd(Buffer::Instance& buffer, - int32_t message_size) { - ENVOY_LOG(debug, "dubbo decoder: expected body size is {}", message_size); +DecoderStateMachine::DecoderStatus +DecoderStateMachine::onDecodeStreamData(Buffer::Instance& buffer) { + ASSERT(active_stream_); - if (buffer.length() < static_cast(message_size)) { - ENVOY_LOG(debug, "dubbo decoder: need more data for {} deserialization, current size {}", - deserializer_.name(), buffer.length()); + if (!protocol_.decodeData(buffer, active_stream_->context_, active_stream_->metadata_)) { + ENVOY_LOG(debug, "dubbo decoder: need more data for {} serialization, current size {}", + protocol_.serializer()->name(), buffer.length()); return {ProtocolState::WaitForData}; } - switch (metadata_->message_type()) { - case MessageType::Oneway: - case MessageType::Request: - deserializer_.deserializeRpcInvocation(buffer, message_size, metadata_); - break; - case MessageType::Response: { - auto info = deserializer_.deserializeRpcResult(buffer, message_size); - if (info->hasException()) { - metadata_->setMessageType(MessageType::Exception); - } - break; - } - default: - NOT_REACHED_GCOVR_EXCL_LINE; - } + active_stream_->context_->message_origin_data().move(buffer, + active_stream_->context_->body_size()); + active_stream_->onStreamDecoded(); + active_stream_ = nullptr; ENVOY_LOG(debug, "dubbo decoder: ends the deserialization of the message"); - return {ProtocolState::OnTransferBodyTo, handler_->messageEnd(metadata_)}; + return {ProtocolState::Done}; } DecoderStateMachine::DecoderStatus DecoderStateMachine::handleState(Buffer::Instance& buffer) { switch (state_) { - case ProtocolState::OnTransportBegin: - return onTransportBegin(buffer, context_); - case ProtocolState::OnTransferHeaderTo: - return onTransferHeaderTo(buffer, context_.header_size_); - case ProtocolState::OnMessageBegin: - return onMessageBegin(); - case ProtocolState::OnMessageEnd: - return onMessageEnd(buffer, context_.body_size_); - case ProtocolState::OnTransferBodyTo: - return onTransferBodyTo(buffer, context_.body_size_); - case ProtocolState::OnTransportEnd: - return onTransportEnd(); + case ProtocolState::OnDecodeStreamHeader: + return onDecodeStreamHeader(buffer); + case ProtocolState::OnDecodeStreamData: + return onDecodeStreamData(buffer); default: NOT_REACHED_GCOVR_EXCL_LINE; } @@ -114,11 +76,6 @@ ProtocolState DecoderStateMachine::run(Buffer::Instance& buffer) { } state_ = s.next_state_; - - ASSERT(s.filter_status_.has_value()); - if (s.filter_status_.value() == Network::FilterStatus::StopIteration) { - return ProtocolState::StopIteration; - } } return state_; @@ -126,11 +83,11 @@ ProtocolState DecoderStateMachine::run(Buffer::Instance& buffer) { using DecoderStateMachinePtr = std::unique_ptr; -Decoder::Decoder(Protocol& protocol, Deserializer& deserializer, - DecoderCallbacks& decoder_callbacks) - : deserializer_(deserializer), protocol_(protocol), decoder_callbacks_(decoder_callbacks) {} +DecoderBase::DecoderBase(Protocol& protocol) : protocol_(protocol) {} -Network::FilterStatus Decoder::onData(Buffer::Instance& data, bool& buffer_underflow) { +DecoderBase::~DecoderBase() { complete(); } + +FilterStatus DecoderBase::onData(Buffer::Instance& data, bool& buffer_underflow) { ENVOY_LOG(debug, "dubbo decoder: {} bytes available", data.length()); buffer_underflow = false; @@ -148,10 +105,7 @@ Network::FilterStatus Decoder::onData(Buffer::Instance& data, bool& buffer_under case ProtocolState::WaitForData: ENVOY_LOG(debug, "dubbo decoder: wait for data"); buffer_underflow = true; - return Network::FilterStatus::Continue; - case ProtocolState::StopIteration: - ENVOY_LOG(debug, "dubbo decoder: wait for continuation"); - return Network::FilterStatus::StopIteration; + return FilterStatus::Continue; default: break; } @@ -161,22 +115,22 @@ Network::FilterStatus Decoder::onData(Buffer::Instance& data, bool& buffer_under complete(); buffer_underflow = (data.length() == 0); ENVOY_LOG(debug, "dubbo decoder: data length {}", data.length()); - return Network::FilterStatus::Continue; + return FilterStatus::Continue; } -void Decoder::start() { - metadata_ = std::make_shared(); - state_machine_ = std::make_unique(protocol_, deserializer_, metadata_, - decoder_callbacks_); +void DecoderBase::start() { + state_machine_ = std::make_unique(protocol_, *this); decode_started_ = true; } -void Decoder::complete() { - metadata_.reset(); +void DecoderBase::complete() { state_machine_.reset(); + stream_.reset(); decode_started_ = false; } +void DecoderBase::reset() { complete(); } + } // namespace DubboProxy } // namespace NetworkFilters } // namespace Extensions diff --git a/source/extensions/filters/network/dubbo_proxy/decoder.h b/source/extensions/filters/network/dubbo_proxy/decoder.h index 982b9dd31b9d..2723633c79a6 100644 --- a/source/extensions/filters/network/dubbo_proxy/decoder.h +++ b/source/extensions/filters/network/dubbo_proxy/decoder.h @@ -6,8 +6,8 @@ #include "common/common/logger.h" #include "extensions/filters/network/dubbo_proxy/decoder_event_handler.h" -#include "extensions/filters/network/dubbo_proxy/deserializer.h" #include "extensions/filters/network/dubbo_proxy/protocol.h" +#include "extensions/filters/network/dubbo_proxy/serializer.h" namespace Envoy { namespace Extensions { @@ -17,12 +17,8 @@ namespace DubboProxy { #define ALL_PROTOCOL_STATES(FUNCTION) \ FUNCTION(StopIteration) \ FUNCTION(WaitForData) \ - FUNCTION(OnTransportBegin) \ - FUNCTION(OnTransportEnd) \ - FUNCTION(OnMessageBegin) \ - FUNCTION(OnMessageEnd) \ - FUNCTION(OnTransferHeaderTo) \ - FUNCTION(OnTransferBodyTo) \ + FUNCTION(OnDecodeStreamHeader) \ + FUNCTION(OnDecodeStreamData) \ FUNCTION(Done) /** @@ -45,12 +41,38 @@ class ProtocolStateNameValues { } }; +struct ActiveStream { + ActiveStream(StreamHandler& handler, MessageMetadataSharedPtr metadata, ContextSharedPtr context) + : handler_(handler), metadata_(metadata), context_(context) {} + ~ActiveStream() { + metadata_.reset(); + context_.reset(); + } + + void onStreamDecoded() { + ASSERT(metadata_ && context_); + handler_.onStreamDecoded(metadata_, context_); + } + + StreamHandler& handler_; + MessageMetadataSharedPtr metadata_; + ContextSharedPtr context_; +}; + +using ActiveStreamPtr = std::unique_ptr; + class DecoderStateMachine : public Logger::Loggable { public: - DecoderStateMachine(Protocol& protocol, Deserializer& deserializer, - MessageMetadataSharedPtr& metadata, DecoderCallbacks& decoder_callbacks) - : protocol_(protocol), deserializer_(deserializer), metadata_(metadata), - decoder_callbacks_(decoder_callbacks), state_(ProtocolState::OnTransportBegin) {} + class Delegate { + public: + virtual ~Delegate() = default; + virtual ActiveStream* newStream(MessageMetadataSharedPtr metadata, + ContextSharedPtr context) PURE; + virtual void onHeartbeat(MessageMetadataSharedPtr metadata) PURE; + }; + + DecoderStateMachine(Protocol& protocol, Delegate& delegate) + : protocol_(protocol), delegate_(delegate), state_(ProtocolState::OnDecodeStreamHeader) {} /** * Consumes as much data from the configured Buffer as possible and executes the decoding state @@ -78,44 +100,35 @@ class DecoderStateMachine : public Logger::Loggable { struct DecoderStatus { DecoderStatus() = default; DecoderStatus(ProtocolState next_state) : next_state_(next_state){}; - DecoderStatus(ProtocolState next_state, Network::FilterStatus filter_status) + DecoderStatus(ProtocolState next_state, FilterStatus filter_status) : next_state_(next_state), filter_status_(filter_status){}; ProtocolState next_state_; - absl::optional filter_status_; + absl::optional filter_status_; }; // These functions map directly to the matching ProtocolState values. Each returns the next state // or ProtocolState::WaitForData if more data is required. - DecoderStatus onTransportBegin(Buffer::Instance& buffer, Protocol::Context& context); - DecoderStatus onTransportEnd(); - DecoderStatus onTransferHeaderTo(Buffer::Instance& buffer, size_t length); - DecoderStatus onTransferBodyTo(Buffer::Instance& buffer, int32_t length); - DecoderStatus onMessageBegin(); - DecoderStatus onMessageEnd(Buffer::Instance& buffer, int32_t message_size); + DecoderStatus onDecodeStreamHeader(Buffer::Instance& buffer); + DecoderStatus onDecodeStreamData(Buffer::Instance& buffer); // handleState delegates to the appropriate method based on state_. DecoderStatus handleState(Buffer::Instance& buffer); Protocol& protocol_; - Deserializer& deserializer_; - MessageMetadataSharedPtr metadata_; - DecoderCallbacks& decoder_callbacks_; + Delegate& delegate_; ProtocolState state_; - Protocol::Context context_; - - DecoderEventHandler* handler_; + ActiveStream* active_stream_{nullptr}; }; using DecoderStateMachinePtr = std::unique_ptr; -/** - * Decoder encapsulates a configured and ProtocolPtr and SerializationPtr. - */ -class Decoder : public Logger::Loggable { +class DecoderBase : public DecoderStateMachine::Delegate, + public Logger::Loggable { public: - Decoder(Protocol& protocol, Deserializer& deserializer, DecoderCallbacks& decoder_callbacks); + DecoderBase(Protocol& protocol); + ~DecoderBase() override; /** * Drains data from the given buffer @@ -123,24 +136,60 @@ class Decoder : public Logger::Loggable { * @param data a Buffer containing Dubbo protocol data * @throw EnvoyException on Dubbo protocol errors */ - Network::FilterStatus onData(Buffer::Instance& data, bool& buffer_underflow); + FilterStatus onData(Buffer::Instance& data, bool& buffer_underflow); - const Deserializer& serializer() { return deserializer_; } const Protocol& protocol() { return protocol_; } -private: + // It is assumed that all of the protocol parsing are stateless, + // if there is a state of the need to provide the reset interface call here. + void reset(); + +protected: void start(); void complete(); - MessageMetadataSharedPtr metadata_; - Deserializer& deserializer_; Protocol& protocol_; + + ActiveStreamPtr stream_; DecoderStateMachinePtr state_machine_; - bool decode_started_ = false; - DecoderCallbacks& decoder_callbacks_; + + bool decode_started_{false}; +}; + +/** + * Decoder encapsulates a configured and ProtocolPtr and SerializationPtr. + */ +template class Decoder : public DecoderBase { +public: + Decoder(Protocol& protocol, T& callbacks) : DecoderBase(protocol), callbacks_(callbacks) {} + + ActiveStream* newStream(MessageMetadataSharedPtr metadata, ContextSharedPtr context) override { + ASSERT(!stream_); + stream_ = std::make_unique(callbacks_.newStream(), metadata, context); + return stream_.get(); + } + + void onHeartbeat(MessageMetadataSharedPtr metadata) override { callbacks_.onHeartbeat(metadata); } + +private: + T& callbacks_; +}; + +class RequestDecoder : public Decoder { +public: + RequestDecoder(Protocol& protocol, RequestDecoderCallbacks& callbacks) + : Decoder(protocol, callbacks) {} +}; + +using RequestDecoderPtr = std::unique_ptr; + +class ResponseDecoder : public Decoder { +public: + ResponseDecoder(Protocol& protocol, ResponseDecoderCallbacks& callbacks) + : Decoder(protocol, callbacks) {} }; -using DecoderPtr = std::unique_ptr; +using ResponseDecoderPtr = std::unique_ptr; } // namespace DubboProxy } // namespace NetworkFilters diff --git a/source/extensions/filters/network/dubbo_proxy/decoder_event_handler.h b/source/extensions/filters/network/dubbo_proxy/decoder_event_handler.h index 35b2caed3b01..0da2344ac123 100644 --- a/source/extensions/filters/network/dubbo_proxy/decoder_event_handler.h +++ b/source/extensions/filters/network/dubbo_proxy/decoder_event_handler.h @@ -1,7 +1,6 @@ #pragma once #include "envoy/common/pure.h" -#include "envoy/network/connection.h" #include "envoy/network/filter.h" #include "common/buffer/buffer_impl.h" @@ -14,101 +13,81 @@ namespace Extensions { namespace NetworkFilters { namespace DubboProxy { -/** - * This class provides the pass-through capability of the original data of - * the Dubbo protocol to improve the forwarding efficiency - * when no modification of the original data is required. - * Note: If the custom filter does not care about data transfer, - * then it does not need to care about this interface, - * which is currently used by router filter. - */ -class ProtocolDataPassthroughConverter { -public: - ProtocolDataPassthroughConverter() = default; - virtual ~ProtocolDataPassthroughConverter() = default; - - void initProtocolConverter(Buffer::Instance& buffer) { buffer_ = &buffer; } +enum class FilterStatus : uint8_t { + // Continue filter chain iteration. + Continue, + // Do not iterate to any of the remaining filters in the chain. Returning + // FilterDataStatus::Continue from decodeData()/encodeData() or calling + // continueDecoding()/continueEncoding() MUST be called if continued filter iteration is desired. + StopIteration, + // Indicates that a retry is required for the reply message received. + Retry, +}; - /** - * Transfer the original header data of the Dubbo protocol, - * it's called after the protocol's header data is parsed. - * @param header_buf raw header data - * @param size The size of the head. - */ - virtual Network::FilterStatus transferHeaderTo(Buffer::Instance& header_buf, size_t size) { - if (buffer_ != nullptr) { - buffer_->move(header_buf, size); - } - return Network::FilterStatus::Continue; - } +class StreamDecoder { +public: + virtual ~StreamDecoder() = default; /** - * Transfer the original body data of the Dubbo protocol - * it's called after the protocol's body data is parsed. - * @param header_buf raw body data - * @param size The size of the body. + * Indicates that the message had been decoded. + * @param metadata MessageMetadataSharedPtr describing the message + * @param ctx the message context information + * @return FilterStatus to indicate if filter chain iteration should continue */ - virtual Network::FilterStatus transferBodyTo(Buffer::Instance& body_buf, size_t size) { - if (buffer_ != nullptr) { - buffer_->move(body_buf, size); - } - return Network::FilterStatus::Continue; - } - -protected: - Buffer::Instance* buffer_{nullptr}; + virtual FilterStatus onMessageDecoded(MessageMetadataSharedPtr metadata, + ContextSharedPtr ctx) PURE; }; -class DecoderEventHandler : public ProtocolDataPassthroughConverter { +using StreamDecoderSharedPtr = std::shared_ptr; + +class StreamEncoder { public: - ~DecoderEventHandler() override = default; + virtual ~StreamEncoder() = default; /** - * Indicates the start of a Dubbo transport data was detected. Unframed transports generate - * simulated start messages. + * Indicates that the message had been encoded. + * @param metadata MessageMetadataSharedPtr describing the message + * @param ctx the message context information + * @return FilterStatus to indicate if filter chain iteration should continue */ - virtual Network::FilterStatus transportBegin() PURE; + virtual FilterStatus onMessageEncoded(MessageMetadataSharedPtr metadata, + ContextSharedPtr ctx) PURE; +}; - /** - * Indicates the end of a Dubbo transport data was detected. Unframed transport generate - * simulated complete messages. - */ - virtual Network::FilterStatus transportEnd() PURE; +using StreamEncoderSharedPtr = std::shared_ptr; - /** - * Indicates that the start of a Dubbo protocol message was detected. - * @param type the message type - * @param message_id the message identifier - * @param serialization_type the serialization type of the message - * @return FilterStatus to indicate if filter chain iteration should continue - */ - virtual Network::FilterStatus messageBegin(MessageType type, int64_t message_id, - SerializationType serialization_type) PURE; +class StreamHandler { +public: + virtual ~StreamHandler() = default; /** - * Indicates that the end of a Dubbo protocol message was detected. + * Indicates that the message had been decoded. * @param metadata MessageMetadataSharedPtr describing the message + * @param ctx the message context information * @return FilterStatus to indicate if filter chain iteration should continue */ - virtual Network::FilterStatus messageEnd(MessageMetadataSharedPtr metadata) PURE; + virtual void onStreamDecoded(MessageMetadataSharedPtr metadata, ContextSharedPtr ctx) PURE; }; -class DecoderCallbacks { +using StreamDecoderSharedPtr = std::shared_ptr; + +class DecoderCallbacksBase { public: - virtual ~DecoderCallbacks() = default; + virtual ~DecoderCallbacksBase() = default; /** - * @return DecoderEventHandler& a new DecoderEventHandler for a message. + * @return StreamDecoder* a new StreamDecoder for a message. */ - virtual DecoderEventHandler* newDecoderEventHandler() PURE; + virtual StreamHandler& newStream() PURE; /** * Indicates that the message is a heartbeat. */ - virtual void onHeartbeat(MessageMetadataSharedPtr) {} + virtual void onHeartbeat(MessageMetadataSharedPtr) PURE; }; -using DecoderEventHandlerSharedPtr = std::shared_ptr; +class RequestDecoderCallbacks : public DecoderCallbacksBase {}; +class ResponseDecoderCallbacks : public DecoderCallbacksBase {}; } // namespace DubboProxy } // namespace NetworkFilters diff --git a/source/extensions/filters/network/dubbo_proxy/deserializer_impl.cc b/source/extensions/filters/network/dubbo_proxy/deserializer_impl.cc deleted file mode 100644 index 985c0d32fd97..000000000000 --- a/source/extensions/filters/network/dubbo_proxy/deserializer_impl.cc +++ /dev/null @@ -1,9 +0,0 @@ -#include "extensions/filters/network/dubbo_proxy/deserializer_impl.h" - -namespace Envoy { -namespace Extensions { -namespace NetworkFilters { -namespace DubboProxy {} // namespace DubboProxy -} // namespace NetworkFilters -} // namespace Extensions -} // namespace Envoy \ No newline at end of file diff --git a/source/extensions/filters/network/dubbo_proxy/deserializer_impl.h b/source/extensions/filters/network/dubbo_proxy/deserializer_impl.h deleted file mode 100644 index 252143c3454c..000000000000 --- a/source/extensions/filters/network/dubbo_proxy/deserializer_impl.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "extensions/filters/network/dubbo_proxy/deserializer.h" - -namespace Envoy { -namespace Extensions { -namespace NetworkFilters { -namespace DubboProxy { - -class RpcResultImpl : public RpcResult { -public: - RpcResultImpl() {} - RpcResultImpl(bool has_exception) : has_exception_(has_exception) {} - virtual bool hasException() const override { return has_exception_; } - -private: - bool has_exception_ = false; -}; - -} // namespace DubboProxy -} // namespace NetworkFilters -} // namespace Extensions -} // namespace Envoy \ No newline at end of file diff --git a/source/extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.cc b/source/extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.cc new file mode 100644 index 000000000000..19e40d284808 --- /dev/null +++ b/source/extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.cc @@ -0,0 +1,118 @@ +#include "extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.h" + +#include "envoy/common/exception.h" + +#include "common/common/assert.h" +#include "common/common/macros.h" + +#include "extensions/filters/network/dubbo_proxy/hessian_utils.h" +#include "extensions/filters/network/dubbo_proxy/message_impl.h" +#include "extensions/filters/network/dubbo_proxy/serializer.h" +#include "extensions/filters/network/dubbo_proxy/serializer_impl.h" + +namespace Envoy { +namespace Extensions { +namespace NetworkFilters { +namespace DubboProxy { + +std::pair +DubboHessian2SerializerImpl::deserializeRpcInvocation(Buffer::Instance& buffer, + ContextSharedPtr context) { + size_t total_size = 0, size; + // TODO(zyfjeff): Add format checker + std::string dubbo_version = HessianUtils::peekString(buffer, &size); + total_size += size; + std::string service_name = HessianUtils::peekString(buffer, &size, total_size); + total_size += size; + std::string service_version = HessianUtils::peekString(buffer, &size, total_size); + total_size += size; + std::string method_name = HessianUtils::peekString(buffer, &size, total_size); + total_size += size; + + if (static_cast(context->body_size()) < total_size) { + throw EnvoyException(fmt::format("RpcInvocation size({}) large than body size({})", total_size, + context->body_size())); + } + + auto invo = std::make_shared(); + invo->setServiceName(service_name); + invo->setServiceVersion(service_version); + invo->setMethodName(method_name); + + return std::pair(invo, true); +} + +std::pair +DubboHessian2SerializerImpl::deserializeRpcResult(Buffer::Instance& buffer, + ContextSharedPtr context) { + ASSERT(buffer.length() >= context->body_size()); + size_t total_size = 0; + bool has_value = true; + + auto result = std::make_shared(); + RpcResponseType type = static_cast(HessianUtils::peekInt(buffer, &total_size)); + + switch (type) { + case RpcResponseType::ResponseWithException: + case RpcResponseType::ResponseWithExceptionWithAttachments: + case RpcResponseType::ResponseWithValue: + result->setException(true); + break; + case RpcResponseType::ResponseWithNullValue: + has_value = false; + FALLTHRU; + case RpcResponseType::ResponseValueWithAttachments: + case RpcResponseType::ResponseNullValueWithAttachments: + result->setException(false); + break; + default: + throw EnvoyException(fmt::format("not supported return type {}", static_cast(type))); + } + + if (context->body_size() < total_size) { + throw EnvoyException(fmt::format("RpcResult size({}) large than body size({})", total_size, + context->body_size())); + } + + if (!has_value && context->body_size() != total_size) { + throw EnvoyException( + fmt::format("RpcResult is no value, but the rest of the body size({}) not equal 0", + (context->body_size() - total_size))); + } + + return std::pair(result, true); +} + +size_t DubboHessian2SerializerImpl::serializeRpcResult(Buffer::Instance& output_buffer, + const std::string& content, + RpcResponseType type) { + size_t origin_length = output_buffer.length(); + + // The serialized response type is compact int. + size_t serialized_size = HessianUtils::writeInt( + output_buffer, static_cast::type>(type)); + + // Serialized response content. + serialized_size += HessianUtils::writeString(output_buffer, content); + + ASSERT((output_buffer.length() - origin_length) == serialized_size); + + return serialized_size; +} + +class DubboHessian2SerializerConfigFactory + : public SerializerFactoryBase { +public: + DubboHessian2SerializerConfigFactory() + : SerializerFactoryBase(ProtocolType::Dubbo, SerializationType::Hessian2) {} +}; + +/** + * Static registration for the Hessian protocol. @see RegisterFactory. + */ +REGISTER_FACTORY(DubboHessian2SerializerConfigFactory, NamedSerializerConfigFactory); + +} // namespace DubboProxy +} // namespace NetworkFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.h b/source/extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.h new file mode 100644 index 000000000000..5af5e5d59622 --- /dev/null +++ b/source/extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.h @@ -0,0 +1,30 @@ +#pragma once + +#include "extensions/filters/network/dubbo_proxy/serializer.h" + +namespace Envoy { +namespace Extensions { +namespace NetworkFilters { +namespace DubboProxy { +class DubboHessian2SerializerImpl : public Serializer { +public: + ~DubboHessian2SerializerImpl() override = default; + const std::string& name() const override { + return ProtocolSerializerNames::get().fromType(ProtocolType::Dubbo, type()); + } + SerializationType type() const override { return SerializationType::Hessian2; } + + std::pair + deserializeRpcInvocation(Buffer::Instance& buffer, ContextSharedPtr context) override; + + std::pair deserializeRpcResult(Buffer::Instance& buffer, + ContextSharedPtr context) override; + + size_t serializeRpcResult(Buffer::Instance& output_buffer, const std::string& content, + RpcResponseType type) override; +}; + +} // namespace DubboProxy +} // namespace NetworkFilters +} // namespace Extensions +} // namespace Envoy \ No newline at end of file diff --git a/source/extensions/filters/network/dubbo_proxy/dubbo_protocol_impl.cc b/source/extensions/filters/network/dubbo_proxy/dubbo_protocol_impl.cc index f7b6f20a73f7..ff6531cff9cf 100644 --- a/source/extensions/filters/network/dubbo_proxy/dubbo_protocol_impl.cc +++ b/source/extensions/filters/network/dubbo_proxy/dubbo_protocol_impl.cc @@ -4,6 +4,9 @@ #include "common/common/assert.h" +#include "extensions/filters/network/dubbo_proxy/message_impl.h" +#include "extensions/filters/network/dubbo_proxy/serializer_impl.h" + namespace Envoy { namespace Extensions { namespace NetworkFilters { @@ -25,8 +28,7 @@ constexpr uint64_t BodySizeOffset = 12; // Consistent with the SerializationType bool isValidSerializationType(SerializationType type) { switch (type) { - case SerializationType::Hessian: - case SerializationType::Json: + case SerializationType::Hessian2: break; default: return false; @@ -64,7 +66,7 @@ void parseRequestInfoFromBuffer(Buffer::Instance& data, MessageMetadataSharedPtr static_cast::type>(type))); } - if (!is_two_way) { + if (!is_two_way && metadata->message_type() != MessageType::HeartbeatRequest) { metadata->setMessageType(MessageType::Oneway); } @@ -83,14 +85,14 @@ void parseResponseInfoFromBuffer(Buffer::Instance& buffer, MessageMetadataShared metadata->setResponseStatus(status); } -bool DubboProtocolImpl::decode(Buffer::Instance& buffer, Protocol::Context* context, - MessageMetadataSharedPtr metadata) { +std::pair +DubboProtocolImpl::decodeHeader(Buffer::Instance& buffer, MessageMetadataSharedPtr metadata) { if (!metadata) { throw EnvoyException("invalid metadata parameter"); } if (buffer.length() < DubboProtocolImpl::MessageSize) { - return false; + return std::pair(nullptr, false); } uint16_t magic_number = buffer.peekBEInt(); @@ -110,42 +112,101 @@ bool DubboProtocolImpl::decode(Buffer::Instance& buffer, Protocol::Context* cont throw EnvoyException(fmt::format("invalid dubbo message size {}", body_size)); } - metadata->setMessageType(type); metadata->setRequestId(request_id); if (type == MessageType::Request) { + if (is_event) { + type = MessageType::HeartbeatRequest; + } + metadata->setMessageType(type); parseRequestInfoFromBuffer(buffer, metadata); } else { + if (is_event) { + type = MessageType::HeartbeatResponse; + } + metadata->setMessageType(type); parseResponseInfoFromBuffer(buffer, metadata); } - context->header_size_ = DubboProtocolImpl::MessageSize; - context->body_size_ = body_size; - context->is_heartbeat_ = is_event; + auto context = std::make_shared(); + context->set_header_size(DubboProtocolImpl::MessageSize); + context->set_body_size(body_size); + context->set_heartbeat(is_event); + + return std::pair(context, true); +} + +bool DubboProtocolImpl::decodeData(Buffer::Instance& buffer, ContextSharedPtr context, + MessageMetadataSharedPtr metadata) { + ASSERT(serializer_); + + if ((buffer.length()) < static_cast(context->body_size())) { + return false; + } + + switch (metadata->message_type()) { + case MessageType::Oneway: + case MessageType::Request: { + auto ret = serializer_->deserializeRpcInvocation(buffer, context); + if (!ret.second) { + return false; + } + metadata->setInvocationInfo(ret.first); + break; + } + case MessageType::Response: { + auto ret = serializer_->deserializeRpcResult(buffer, context); + if (!ret.second) { + return false; + } + if (ret.first->hasException()) { + metadata->setMessageType(MessageType::Exception); + } + break; + } + default: + NOT_REACHED_GCOVR_EXCL_LINE; + } return true; } -bool DubboProtocolImpl::encode(Buffer::Instance& buffer, int32_t body_size, - const MessageMetadata& metadata) { +bool DubboProtocolImpl::encode(Buffer::Instance& buffer, const MessageMetadata& metadata, + const std::string& content, RpcResponseType type) { + ASSERT(serializer_); + switch (metadata.message_type()) { - case MessageType::Response: { - ASSERT(metadata.response_status().has_value()); + case MessageType::HeartbeatResponse: { + ASSERT(metadata.hasResponseStatus()); + ASSERT(content.empty()); buffer.writeBEInt(MagicNumber); uint8_t flag = static_cast(metadata.serialization_type()); - if (metadata.is_event()) { - ASSERT(0 == body_size); - flag = flag ^ EventMask; - } + flag = flag ^ EventMask; buffer.writeByte(flag); - buffer.writeByte(static_cast(metadata.response_status().value())); + buffer.writeByte(static_cast(metadata.response_status())); buffer.writeBEInt(metadata.request_id()); - buffer.writeBEInt(body_size); + buffer.writeBEInt(0); return true; } - case MessageType::Request: { - NOT_IMPLEMENTED_GCOVR_EXCL_LINE; + case MessageType::Response: { + ASSERT(metadata.hasResponseStatus()); + ASSERT(!content.empty()); + Buffer::OwnedImpl body_buffer; + size_t serialized_body_size = serializer_->serializeRpcResult(body_buffer, content, type); + + buffer.writeBEInt(MagicNumber); + buffer.writeByte(static_cast(metadata.serialization_type())); + buffer.writeByte(static_cast(metadata.response_status())); + buffer.writeBEInt(metadata.request_id()); + buffer.writeBEInt(serialized_body_size); + + buffer.move(body_buffer, serialized_body_size); + return true; } + case MessageType::Request: + case MessageType::Oneway: + case MessageType::Exception: + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; default: NOT_REACHED_GCOVR_EXCL_LINE; } diff --git a/source/extensions/filters/network/dubbo_proxy/dubbo_protocol_impl.h b/source/extensions/filters/network/dubbo_proxy/dubbo_protocol_impl.h index 6146df34f511..47d4bb0062f2 100644 --- a/source/extensions/filters/network/dubbo_proxy/dubbo_protocol_impl.h +++ b/source/extensions/filters/network/dubbo_proxy/dubbo_protocol_impl.h @@ -10,12 +10,18 @@ namespace DubboProxy { class DubboProtocolImpl : public Protocol { public: DubboProtocolImpl() = default; + ~DubboProtocolImpl() override = default; + const std::string& name() const override { return ProtocolNames::get().fromType(type()); } ProtocolType type() const override { return ProtocolType::Dubbo; } - bool decode(Buffer::Instance& buffer, Protocol::Context* context, - MessageMetadataSharedPtr metadata) override; - bool encode(Buffer::Instance& buffer, int32_t body_size, - const MessageMetadata& metadata) override; + + std::pair decodeHeader(Buffer::Instance& buffer, + MessageMetadataSharedPtr metadata) override; + bool decodeData(Buffer::Instance& buffer, ContextSharedPtr context, + MessageMetadataSharedPtr metadata) override; + + bool encode(Buffer::Instance& buffer, const MessageMetadata& metadata, const std::string& content, + RpcResponseType type) override; static constexpr uint8_t MessageSize = 16; static constexpr int32_t MaxBodySize = 16 * 1024 * 1024; diff --git a/source/extensions/filters/network/dubbo_proxy/filters/BUILD b/source/extensions/filters/network/dubbo_proxy/filters/BUILD index e9e5a42b7f40..253738c08779 100644 --- a/source/extensions/filters/network/dubbo_proxy/filters/BUILD +++ b/source/extensions/filters/network/dubbo_proxy/filters/BUILD @@ -16,9 +16,9 @@ envoy_cc_library( "//include/envoy/network:connection_interface", "//include/envoy/stream_info:stream_info_interface", "//source/extensions/filters/network/dubbo_proxy:decoder_events_lib", - "//source/extensions/filters/network/dubbo_proxy:deserializer_interface", "//source/extensions/filters/network/dubbo_proxy:metadata_lib", "//source/extensions/filters/network/dubbo_proxy:protocol_interface", + "//source/extensions/filters/network/dubbo_proxy:serializer_interface", "//source/extensions/filters/network/dubbo_proxy/router:router_interface", ], ) diff --git a/source/extensions/filters/network/dubbo_proxy/filters/filter.h b/source/extensions/filters/network/dubbo_proxy/filters/filter.h index 5d73624d1a0a..7ff4cbf5a030 100644 --- a/source/extensions/filters/network/dubbo_proxy/filters/filter.h +++ b/source/extensions/filters/network/dubbo_proxy/filters/filter.h @@ -9,11 +9,11 @@ #include "envoy/stream_info/stream_info.h" #include "extensions/filters/network/dubbo_proxy/decoder_event_handler.h" -#include "extensions/filters/network/dubbo_proxy/deserializer.h" #include "extensions/filters/network/dubbo_proxy/message.h" #include "extensions/filters/network/dubbo_proxy/metadata.h" #include "extensions/filters/network/dubbo_proxy/protocol.h" #include "extensions/filters/network/dubbo_proxy/router/router.h" +#include "extensions/filters/network/dubbo_proxy/serializer.h" namespace Envoy { namespace Extensions { @@ -25,6 +25,7 @@ enum class UpstreamResponseStatus : uint8_t { MoreData = 0, // The upstream response requires more data. Complete = 1, // The upstream response is complete. Reset = 2, // The upstream response is invalid and its connection must be reset. + Retry = 3, // The upstream response is failure need to retry. }; class DirectResponse { @@ -51,7 +52,7 @@ class DirectResponse { * exception */ virtual ResponseType encode(MessageMetadata& metadata, Protocol& protocol, - Deserializer& deserializer, Buffer::Instance& buffer) const PURE; + Buffer::Instance& buffer) const PURE; }; using DirectResponsePtr = std::unique_ptr; @@ -59,9 +60,9 @@ using DirectResponsePtr = std::unique_ptr; /** * Decoder filter callbacks add additional callbacks. */ -class DecoderFilterCallbacks { +class FilterCallbacksBase { public: - virtual ~DecoderFilterCallbacks() = default; + virtual ~FilterCallbacksBase() = default; /** * @return uint64_t the ID of the originating request for logging purposes. @@ -78,15 +79,6 @@ class DecoderFilterCallbacks { */ virtual const Network::Connection* connection() const PURE; - /** - * Continue iterating through the filter chain with buffered data. This routine can only be - * called if the filter has previously returned StopIteration from one of the DecoderFilter - * methods. The connection manager will callbacks to the next filter in the chain. Further note - * that if the request is not complete, the calling filter may receive further callbacks and must - * return an appropriate status code depending on what the filter needs to do. - */ - virtual void continueDecoding() PURE; - /** * @return RouteConstSharedPtr the route for the current request. */ @@ -95,12 +87,44 @@ class DecoderFilterCallbacks { /** * @return SerializationType the originating protocol. */ - virtual SerializationType downstreamSerializationType() const PURE; + virtual SerializationType serializationType() const PURE; /** * @return ProtocolType the originating protocol. */ - virtual ProtocolType downstreamProtocolType() const PURE; + virtual ProtocolType protocolType() const PURE; + + /** + * @return StreamInfo for logging purposes. + */ + virtual StreamInfo::StreamInfo& streamInfo() PURE; + + /** + * @return Event::Dispatcher& the thread local dispatcher for allocating timers, etc. + */ + virtual Event::Dispatcher& dispatcher() PURE; + + /** + * Reset the underlying stream. + */ + virtual void resetStream() PURE; +}; + +/** + * Decoder filter callbacks add additional callbacks. + */ +class DecoderFilterCallbacks : public virtual FilterCallbacksBase { +public: + ~DecoderFilterCallbacks() override = default; + + /** + * Continue iterating through the filter chain with buffered data. This routine can only be + * called if the filter has previously returned StopIteration from one of the DecoderFilter + * methods. The connection manager will callbacks to the next filter in the chain. Further note + * that if the request is not complete, the calling filter may receive further callbacks and must + * return an appropriate status code depending on what the filter needs to do. + */ + virtual void continueDecoding() PURE; /** * Create a locally generated response using the provided response object. @@ -113,7 +137,7 @@ class DecoderFilterCallbacks { * @param transport_type TransportType the upstream is using * @param protocol_type ProtocolType the upstream is using */ - virtual void startUpstreamResponse(Deserializer& deserializer, Protocol& protocol) PURE; + virtual void startUpstreamResponse() PURE; /** * Called with upstream response data. @@ -127,24 +151,31 @@ class DecoderFilterCallbacks { * Reset the downstream connection. */ virtual void resetDownstreamConnection() PURE; +}; - /** - * @return StreamInfo for logging purposes. - */ - virtual StreamInfo::StreamInfo& streamInfo() PURE; +/** + * Encoder filter callbacks add additional callbacks. + */ +class EncoderFilterCallbacks : public virtual FilterCallbacksBase { +public: + ~EncoderFilterCallbacks() override = default; /** - * Reset the underlying stream. + * Continue iterating through the filter chain with buffered data. This routine can only be + * called if the filter has previously returned StopIteration from one of the DecoderFilter + * methods. The connection manager will callbacks to the next filter in the chain. Further note + * that if the request is not complete, the calling filter may receive further callbacks and must + * return an appropriate status code depending on what the filter needs to do. */ - virtual void resetStream() PURE; + virtual void continueEncoding() PURE; }; /** - * Decoder filter interface. + * Common base class for both decoder and encoder filters. */ -class DecoderFilter : public DecoderEventHandler { +class FilterBase { public: - virtual ~DecoderFilter() = default; + virtual ~FilterBase() = default; /** * This routine is called prior to a filter being destroyed. This may happen after normal stream @@ -156,6 +187,14 @@ class DecoderFilter : public DecoderEventHandler { * onDestroy() invoked. */ virtual void onDestroy() PURE; +}; + +/** + * Decoder filter interface. + */ +class DecoderFilter : public StreamDecoder, public FilterBase { +public: + ~DecoderFilter() override = default; /** * Called by the connection manager once to initialize the filter decoder callbacks that the @@ -166,6 +205,29 @@ class DecoderFilter : public DecoderEventHandler { using DecoderFilterSharedPtr = std::shared_ptr; +/** + * Encoder filter interface. + */ +class EncoderFilter : public StreamEncoder, public FilterBase { +public: + ~EncoderFilter() override = default; + + /** + * Called by the connection manager once to initialize the filter encoder callbacks that the + * filter should use. Callbacks will not be invoked by the filter after onDestroy() is called. + */ + virtual void setEncoderFilterCallbacks(EncoderFilterCallbacks& callbacks) PURE; +}; + +using EncoderFilterSharedPtr = std::shared_ptr; + +/** + * A filter that handles both encoding and decoding. + */ +class CodecFilter : public virtual DecoderFilter, public virtual EncoderFilter {}; + +using CodecFilterSharedPtr = std::shared_ptr; + /** * These callbacks are provided by the connection manager to the factory so that the factory can * build the filter chain in an application specific way. @@ -179,6 +241,18 @@ class FilterChainFactoryCallbacks { * @param filter supplies the filter to add. */ virtual void addDecoderFilter(DecoderFilterSharedPtr filter) PURE; + + /** + * Add a encoder filter that is used when writing connection data. + * @param filter supplies the filter to add. + */ + virtual void addEncoderFilter(EncoderFilterSharedPtr filter) PURE; + + /** + * Add a decoder/encoder filter that is used both when reading and writing connection data. + * @param filter supplies the filter to add. + */ + virtual void addFilter(CodecFilterSharedPtr filter) PURE; }; /** diff --git a/source/extensions/filters/network/dubbo_proxy/heartbeat_response.cc b/source/extensions/filters/network/dubbo_proxy/heartbeat_response.cc index f966f9f86f8d..3d9f7a648844 100644 --- a/source/extensions/filters/network/dubbo_proxy/heartbeat_response.cc +++ b/source/extensions/filters/network/dubbo_proxy/heartbeat_response.cc @@ -6,14 +6,12 @@ namespace NetworkFilters { namespace DubboProxy { DubboFilters::DirectResponse::ResponseType -HeartbeatResponse::encode(MessageMetadata& metadata, DubboProxy::Protocol& protocol, Deserializer&, +HeartbeatResponse::encode(MessageMetadata& metadata, DubboProxy::Protocol& protocol, Buffer::Instance& buffer) const { - ASSERT(metadata.response_status().value() == ResponseStatus::Ok); - ASSERT(metadata.message_type() == MessageType::Response); - ASSERT(metadata.is_event()); + ASSERT(metadata.response_status() == ResponseStatus::Ok); + ASSERT(metadata.message_type() == MessageType::HeartbeatResponse); - const size_t serialized_body_size = 0; - if (!protocol.encode(buffer, serialized_body_size, metadata)) { + if (!protocol.encode(buffer, metadata, "")) { throw EnvoyException("failed to encode heartbeat message"); } diff --git a/source/extensions/filters/network/dubbo_proxy/heartbeat_response.h b/source/extensions/filters/network/dubbo_proxy/heartbeat_response.h index 4f53691c7f9b..7c76f6c0d674 100644 --- a/source/extensions/filters/network/dubbo_proxy/heartbeat_response.h +++ b/source/extensions/filters/network/dubbo_proxy/heartbeat_response.h @@ -1,9 +1,9 @@ #pragma once -#include "extensions/filters/network/dubbo_proxy/deserializer.h" #include "extensions/filters/network/dubbo_proxy/filters/filter.h" #include "extensions/filters/network/dubbo_proxy/metadata.h" #include "extensions/filters/network/dubbo_proxy/protocol.h" +#include "extensions/filters/network/dubbo_proxy/serializer.h" namespace Envoy { namespace Extensions { @@ -16,7 +16,7 @@ struct HeartbeatResponse : public DubboFilters::DirectResponse, ~HeartbeatResponse() override = default; using ResponseType = DubboFilters::DirectResponse::ResponseType; - ResponseType encode(MessageMetadata& metadata, Protocol& protocol, Deserializer& deserializer, + ResponseType encode(MessageMetadata& metadata, Protocol& protocol, Buffer::Instance& buffer) const override; }; diff --git a/source/extensions/filters/network/dubbo_proxy/hessian_deserializer_impl.cc b/source/extensions/filters/network/dubbo_proxy/hessian_deserializer_impl.cc deleted file mode 100644 index e095ee4fe9bb..000000000000 --- a/source/extensions/filters/network/dubbo_proxy/hessian_deserializer_impl.cc +++ /dev/null @@ -1,111 +0,0 @@ -#include "extensions/filters/network/dubbo_proxy/hessian_deserializer_impl.h" - -#include "envoy/common/exception.h" - -#include "common/common/assert.h" -#include "common/common/macros.h" - -#include "extensions/filters/network/dubbo_proxy/deserializer.h" -#include "extensions/filters/network/dubbo_proxy/deserializer_impl.h" -#include "extensions/filters/network/dubbo_proxy/hessian_utils.h" - -namespace Envoy { -namespace Extensions { -namespace NetworkFilters { -namespace DubboProxy { - -void HessianDeserializerImpl::deserializeRpcInvocation(Buffer::Instance& buffer, size_t body_size, - MessageMetadataSharedPtr metadata) { - ASSERT(buffer.length() >= static_cast(body_size)); - size_t total_size = 0, size; - // TODO(zyfjeff): Add format checker - std::string dubbo_version = HessianUtils::peekString(buffer, &size); - total_size = total_size + size; - std::string service_name = HessianUtils::peekString(buffer, &size, total_size); - total_size = total_size + size; - std::string service_version = HessianUtils::peekString(buffer, &size, total_size); - total_size = total_size + size; - std::string method_name = HessianUtils::peekString(buffer, &size, total_size); - total_size = total_size + size; - - if (static_cast(body_size) < total_size) { - throw EnvoyException( - fmt::format("RpcInvocation size({}) large than body size({})", total_size, body_size)); - } - - metadata->setServiceName(service_name); - metadata->setServiceVersion(service_version); - metadata->setMethodName(method_name); -} - -RpcResultPtr HessianDeserializerImpl::deserializeRpcResult(Buffer::Instance& buffer, - size_t body_size) { - ASSERT(buffer.length() >= body_size); - size_t total_size = 0; - bool has_value = true; - - RpcResultPtr result; - RpcResponseType type = static_cast(HessianUtils::peekInt(buffer, &total_size)); - - switch (type) { - case RpcResponseType::ResponseWithException: - case RpcResponseType::ResponseWithExceptionWithAttachments: - case RpcResponseType::ResponseWithValue: - result = std::make_unique(true); - break; - case RpcResponseType::ResponseWithNullValue: - has_value = false; - FALLTHRU; - case RpcResponseType::ResponseValueWithAttachments: - case RpcResponseType::ResponseNullValueWithAttachments: - result = std::make_unique(); - break; - default: - throw EnvoyException(fmt::format("not supported return type {}", static_cast(type))); - } - - if (body_size < total_size) { - throw EnvoyException( - fmt::format("RpcResult size({}) large than body size({})", total_size, body_size)); - } - - if (!has_value && body_size != total_size) { - throw EnvoyException( - fmt::format("RpcResult is no value, but the rest of the body size({}) not equal 0", - (body_size - total_size))); - } - - return result; -} - -size_t HessianDeserializerImpl::serializeRpcResult(Buffer::Instance& output_buffer, - const std::string& content, - RpcResponseType type) { - size_t origin_length = output_buffer.length(); - - // The serialized response type is compact int. - size_t serialized_size = HessianUtils::writeInt( - output_buffer, static_cast::type>(type)); - - // Serialized response content. - serialized_size += HessianUtils::writeString(output_buffer, content); - - ASSERT((output_buffer.length() - origin_length) == serialized_size); - - return serialized_size; -} - -class HessianDeserializerConfigFactory : public DeserializerFactoryBase { -public: - HessianDeserializerConfigFactory() : DeserializerFactoryBase(SerializationType::Hessian) {} -}; - -/** - * Static registration for the Hessian protocol. @see RegisterFactory. - */ -REGISTER_FACTORY(HessianDeserializerConfigFactory, NamedDeserializerConfigFactory); - -} // namespace DubboProxy -} // namespace NetworkFilters -} // namespace Extensions -} // namespace Envoy diff --git a/source/extensions/filters/network/dubbo_proxy/hessian_deserializer_impl.h b/source/extensions/filters/network/dubbo_proxy/hessian_deserializer_impl.h deleted file mode 100644 index 0e3dbe363f9a..000000000000 --- a/source/extensions/filters/network/dubbo_proxy/hessian_deserializer_impl.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "extensions/filters/network/dubbo_proxy/deserializer.h" - -namespace Envoy { -namespace Extensions { -namespace NetworkFilters { -namespace DubboProxy { -class HessianDeserializerImpl : public Deserializer { -public: - HessianDeserializerImpl() {} - ~HessianDeserializerImpl() {} - virtual const std::string& name() const override { - return DeserializerNames::get().fromType(type()); - } - virtual SerializationType type() const override { return SerializationType::Hessian; } - virtual void deserializeRpcInvocation(Buffer::Instance& buffer, size_t body_size, - MessageMetadataSharedPtr metadata) override; - virtual RpcResultPtr deserializeRpcResult(Buffer::Instance& buffer, size_t body_size) override; - virtual size_t serializeRpcResult(Buffer::Instance& output_buffer, const std::string& content, - RpcResponseType type) override; -}; - -} // namespace DubboProxy -} // namespace NetworkFilters -} // namespace Extensions -} // namespace Envoy \ No newline at end of file diff --git a/source/extensions/filters/network/dubbo_proxy/message.h b/source/extensions/filters/network/dubbo_proxy/message.h index 30c5673fe309..95a435f5798d 100644 --- a/source/extensions/filters/network/dubbo_proxy/message.h +++ b/source/extensions/filters/network/dubbo_proxy/message.h @@ -5,15 +5,46 @@ #include "envoy/common/pure.h" +#include "common/buffer/buffer_impl.h" + +#include "absl/types/optional.h" + namespace Envoy { namespace Extensions { namespace NetworkFilters { namespace DubboProxy { +/** + * Stream reset reasons. + */ +enum class StreamResetReason : uint8_t { + // If a local codec level reset was sent on the stream. + LocalReset, + // If a local codec level refused stream reset was sent on the stream (allowing for retry). + LocalRefusedStreamReset, + // If a remote codec level reset was received on the stream. + RemoteReset, + // If a remote codec level refused stream reset was received on the stream (allowing for retry). + RemoteRefusedStreamReset, + // If the stream was locally reset by a connection pool due to an initial connection failure. + ConnectionFailure, + // If the stream was locally reset due to connection termination. + ConnectionTermination, + // The stream was reset because of a resource overflow. + Overflow +}; + +// Supported protocol type +enum class ProtocolType : uint8_t { + Dubbo = 1, + + // ATTENTION: MAKE SURE THIS REMAINS EQUAL TO THE LAST PROTOCOL TYPE + LastProtocolType = Dubbo, +}; + // Supported serialization type enum class SerializationType : uint8_t { - Hessian = 2, - Json = 6, + Hessian2 = 2, }; // Message Type @@ -22,9 +53,11 @@ enum class MessageType : uint8_t { Request = 1, Oneway = 2, Exception = 3, + HeartbeatRequest = 4, + HeartbeatResponse = 5, // ATTENTION: MAKE SURE THIS REMAINS EQUAL TO THE LAST MESSAGE TYPE - LastMessageType = Exception, + LastMessageType = HeartbeatResponse, }; /** @@ -53,32 +86,58 @@ enum class RpcResponseType : uint8_t { ResponseNullValueWithAttachments = 5, }; -class Message { +class Context { public: - virtual ~Message() = default; - virtual MessageType messageType() const PURE; - virtual int32_t bodySize() const PURE; - virtual bool isEvent() const PURE; - virtual int64_t requestId() const PURE; - virtual std::string toString() const PURE; + using AttachmentMap = std::unordered_map; + + bool hasAttachments() const { return attachments_.empty(); } + const AttachmentMap& attachments() const { return attachments_; } + + Buffer::Instance& message_origin_data() { return message_origin_buffer_; } + size_t message_size() const { return header_size() + body_size(); } + + virtual size_t body_size() const PURE; + virtual size_t header_size() const PURE; + +protected: + Context() = default; + virtual ~Context() { attachments_.clear(); } + + AttachmentMap attachments_; + Buffer::OwnedImpl message_origin_buffer_; }; -class RequestMessage : public virtual Message { +using ContextSharedPtr = std::shared_ptr; + +/** + * RpcInvocation represent an rpc call + * See + * https://github.com/apache/incubator-dubbo/blob/master/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcInvocation.java + */ +class RpcInvocation { public: - ~RequestMessage() override = default; - virtual SerializationType serializationType() const PURE; - virtual bool isTwoWay() const PURE; + virtual ~RpcInvocation() = default; + + virtual const std::string& service_name() const PURE; + virtual const std::string& method_name() const PURE; + virtual const absl::optional& service_version() const PURE; + virtual const absl::optional& service_group() const PURE; }; -using RequestMessagePtr = std::unique_ptr; +using RpcInvocationSharedPtr = std::shared_ptr; -class ResponseMessage : public virtual Message { +/** + * RpcResult represent the result of an rpc call + * See + * https://github.com/apache/incubator-dubbo/blob/master/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcResult.java + */ +class RpcResult { public: - ~ResponseMessage() override = default; - virtual ResponseStatus responseStatus() const PURE; + virtual ~RpcResult() = default; + virtual bool hasException() const PURE; }; -using ResponseMessagePtr = std::unique_ptr; +using RpcResultSharedPtr = std::shared_ptr; } // namespace DubboProxy } // namespace NetworkFilters diff --git a/source/extensions/filters/network/dubbo_proxy/message_impl.h b/source/extensions/filters/network/dubbo_proxy/message_impl.h new file mode 100644 index 000000000000..1fc20c5f7a11 --- /dev/null +++ b/source/extensions/filters/network/dubbo_proxy/message_impl.h @@ -0,0 +1,65 @@ +#pragma once + +#include "extensions/filters/network/dubbo_proxy/message.h" + +namespace Envoy { +namespace Extensions { +namespace NetworkFilters { +namespace DubboProxy { + +class ContextBase : public Context { +public: + ContextBase() = default; + ~ContextBase() override = default; + + // Override from Context + size_t body_size() const override { return body_size_; } + size_t header_size() const override { return header_size_; } + + void set_body_size(size_t size) { body_size_ = size; } + void set_header_size(size_t size) { header_size_ = size; } + +protected: + size_t body_size_{0}; + size_t header_size_{0}; +}; + +class ContextImpl : public ContextBase { +public: + ContextImpl() = default; + ~ContextImpl() override = default; + + bool is_heartbeat() const { return is_heartbeat_; } + void set_heartbeat(bool is_heartbeat) { is_heartbeat_ = is_heartbeat; } + +private: + bool is_heartbeat_{false}; +}; + +class RpcInvocationBase : public RpcInvocation { +public: + ~RpcInvocationBase() override = default; + + void setServiceName(const std::string& name) { service_name_ = name; } + const std::string& service_name() const override { return service_name_; } + + void setMethodName(const std::string& name) { method_name_ = name; } + const std::string& method_name() const override { return method_name_; } + + void setServiceVersion(const std::string& version) { service_version_ = version; } + const absl::optional& service_version() const override { return service_version_; } + + void setServiceGroup(const std::string& group) { group_ = group; } + const absl::optional& service_group() const override { return group_; } + +protected: + std::string service_name_; + std::string method_name_; + absl::optional service_version_; + absl::optional group_; +}; + +} // namespace DubboProxy +} // namespace NetworkFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/network/dubbo_proxy/metadata.h b/source/extensions/filters/network/dubbo_proxy/metadata.h index a8251c75c021..41a7f3976f4d 100644 --- a/source/extensions/filters/network/dubbo_proxy/metadata.h +++ b/source/extensions/filters/network/dubbo_proxy/metadata.h @@ -19,23 +19,17 @@ namespace DubboProxy { class MessageMetadata { public: - // TODO(gengleilei) Add parameter data types and implement Dubbo data type mapping. - using ParameterValueMap = std::unordered_map; - using ParameterValueMapPtr = std::unique_ptr; - - using HeaderMapPtr = std::unique_ptr; - - void setServiceName(const std::string& name) { service_name_ = name; } - const std::string& service_name() const { return service_name_; } - - void setMethodName(const std::string& name) { method_name_ = name; } - const absl::optional& method_name() const { return method_name_; } + void setInvocationInfo(RpcInvocationSharedPtr invocation_info) { + invocation_info_ = invocation_info; + } + bool hasInvocationInfo() const { return invocation_info_ != nullptr; } + const RpcInvocation& invocation_info() const { return *invocation_info_; } - void setServiceVersion(const std::string& version) { service_version_ = version; } - const absl::optional& service_version() const { return service_version_; } + void setProtocolType(ProtocolType type) { proto_type_ = type; } + ProtocolType protocol_type() const { return proto_type_; } - void setServiceGroup(const std::string& group) { group_ = group; } - const absl::optional& service_group() const { return group_; } + void setProtocolVersion(uint8_t version) { protocol_version_ = version; } + uint8_t protocol_version() const { return protocol_version_; } void setMessageType(MessageType type) { message_type_ = type; } MessageType message_type() const { return message_type_; } @@ -43,80 +37,45 @@ class MessageMetadata { void setRequestId(int64_t id) { request_id_ = id; } int64_t request_id() const { return request_id_; } - void setSerializationType(SerializationType type) { serialization_type_ = type; } - SerializationType serialization_type() const { return serialization_type_; } + void setTimeout(uint32_t timeout) { timeout_ = timeout; } + absl::optional timeout() const { return timeout_; } void setTwoWayFlag(bool two_way) { is_two_way_ = two_way; } bool is_two_way() const { return is_two_way_; } - void setEventFlag(bool is_event) { is_event_ = is_event; } - bool is_event() const { return is_event_; } - - void setResponseStatus(ResponseStatus status) { response_status_ = status; } - const absl::optional& response_status() const { return response_status_; } - - void addParameterValue(uint32_t index, const std::string& value) { - assignParameterIfNeed(); - parameter_map_->emplace(index, value); - } - const std::string& getParameterValue(uint32_t index) const { - if (parameter_map_) { - auto itor = parameter_map_->find(index); - if (itor != parameter_map_->end()) { - return itor->second; - } - } - - return EMPTY_STRING; + template void setSerializationType(T type) { + ASSERT((std::is_same::type>::value)); + serialization_type_ = static_cast(type); } - bool hasParameters() const { return parameter_map_ != nullptr; } - const ParameterValueMap& parameters() { - ASSERT(hasParameters()); - return *parameter_map_; + template T serialization_type() const { + ASSERT((std::is_same::type>::value)); + return static_cast(serialization_type_); } - bool hasHeaders() const { return headers_ != nullptr; } - const Http::HeaderMap& headers() const { - ASSERT(hasHeaders()); - return *headers_; + template void setResponseStatus(T status) { + ASSERT((std::is_same::type>::value)); + response_status_ = static_cast(status); } - void addHeader(const std::string& key, const std::string& value) { - assignHeaderIfNeed(); - headers_->addCopy(Http::LowerCaseString(key), value); - } - void addHeaderReference(const Http::LowerCaseString& key, const std::string& value) { - assignHeaderIfNeed(); - headers_->addReference(key, value); + template T response_status() const { + ASSERT((std::is_same::type>::value)); + return static_cast(response_status_.value()); } + bool hasResponseStatus() const { return response_status_.has_value(); } private: - inline void assignHeaderIfNeed() { - if (!headers_) { - headers_ = std::make_unique(); - } - } - inline void assignParameterIfNeed() { - if (!parameter_map_) { - parameter_map_ = std::make_unique(); - } - } - bool is_two_way_{false}; - bool is_event_{false}; MessageType message_type_{MessageType::Request}; - SerializationType serialization_type_{SerializationType::Hessian}; - absl::optional response_status_; + ProtocolType proto_type_{ProtocolType::Dubbo}; - int64_t request_id_ = 0; + absl::optional response_status_; + absl::optional timeout_; + + RpcInvocationSharedPtr invocation_info_; - // Routing metadata. - std::string service_name_; - absl::optional method_name_; - absl::optional service_version_; - absl::optional group_; - ParameterValueMapPtr parameter_map_; - HeaderMapPtr headers_; // attachment + uint8_t serialization_type_{static_cast(SerializationType::Hessian2)}; + uint8_t protocol_version_{1}; + int64_t request_id_ = 0; }; using MessageMetadataSharedPtr = std::shared_ptr; diff --git a/source/extensions/filters/network/dubbo_proxy/protocol.h b/source/extensions/filters/network/dubbo_proxy/protocol.h index 85efff09249d..92f9584e3126 100644 --- a/source/extensions/filters/network/dubbo_proxy/protocol.h +++ b/source/extensions/filters/network/dubbo_proxy/protocol.h @@ -12,69 +12,33 @@ #include "extensions/filters/network/dubbo_proxy/message.h" #include "extensions/filters/network/dubbo_proxy/metadata.h" +#include "extensions/filters/network/dubbo_proxy/serializer.h" namespace Envoy { namespace Extensions { namespace NetworkFilters { namespace DubboProxy { -enum class ProtocolType : uint8_t { - Dubbo = 0, - - // ATTENTION: MAKE SURE THIS REMAINS EQUAL TO THE LAST PROTOCOL TYPE - LastProtocolType = Dubbo, -}; - -/** - * Names of available Protocol implementations. - */ -class ProtocolNameValues { -public: - struct ProtocolTypeHash { - template std::size_t operator()(T t) const { return static_cast(t); } - }; - - using ProtocolTypeNameMap = std::unordered_map; - - const ProtocolTypeNameMap protocolTypeNameMap = { - {ProtocolType::Dubbo, "dubbo"}, - }; - - const std::string& fromType(ProtocolType type) const { - const auto& itor = protocolTypeNameMap.find(type); - if (itor != protocolTypeNameMap.end()) { - return itor->second; - } - - NOT_REACHED_GCOVR_EXCL_LINE; - } -}; - -using ProtocolNames = ConstSingleton; - -/** - * ProtocolCallbacks are Dubbo protocol-level callbacks. - */ -class ProtocolCallbacks { -public: - virtual ~ProtocolCallbacks() = default; - virtual void onRequestMessage(RequestMessagePtr&& req) PURE; - virtual void onResponseMessage(ResponseMessagePtr&& res) PURE; -}; - /** * See https://dubbo.incubator.apache.org/en-us/docs/dev/implementation.html */ class Protocol { public: - struct Context { - bool is_request_ = false; - size_t body_size_ = 0; - size_t header_size_ = 0; - bool is_heartbeat_ = false; - }; virtual ~Protocol() = default; Protocol() = default; + + /** + * @return Initializes the serializer used by the protocol codec + */ + void initSerializer(SerializationType type) { + serializer_ = NamedSerializerConfigFactory::getFactory(this->type(), type).createSerializer(); + } + + /** + * @return Serializer the protocol Serializer + */ + virtual Serializer* serializer() const { return serializer_.get(); } + virtual const std::string& name() const PURE; /** @@ -83,7 +47,21 @@ class Protocol { virtual ProtocolType type() const PURE; /* - * decodes the dubbo protocol message, potentially invoking callbacks. + * decodes the dubbo protocol message header. + * + * @param buffer the currently buffered dubbo data. + * @param metadata the meta data of current messages + * @return ContextSharedPtr save the context data of current messages, + * nullptr if more data is required. + * bool true if a complete message was successfully consumed, false if more data + * is required. + * @throws EnvoyException if the data is not valid for this protocol. + */ + virtual std::pair decodeHeader(Buffer::Instance& buffer, + MessageMetadataSharedPtr metadata) PURE; + + /* + * decodes the dubbo protocol message body, potentially invoking callbacks. * If successful, the message is removed from the buffer. * * @param buffer the currently buffered dubbo data. @@ -93,18 +71,24 @@ class Protocol { * is required. * @throws EnvoyException if the data is not valid for this protocol. */ - virtual bool decode(Buffer::Instance& buffer, Context* context, - MessageMetadataSharedPtr metadata) PURE; + virtual bool decodeData(Buffer::Instance& buffer, ContextSharedPtr context, + MessageMetadataSharedPtr metadata) PURE; /* * encodes the dubbo protocol message. * * @param buffer save the currently buffered dubbo data. * @param metadata the meta data of dubbo protocol + * @param content the body of dubbo protocol message + * @param type the type of dubbo protocol response message * @return bool true if the protocol coding succeeds. */ - virtual bool encode(Buffer::Instance& buffer, int32_t body_size, - const MessageMetadata& metadata) PURE; + virtual bool encode(Buffer::Instance& buffer, const MessageMetadata& metadata, + const std::string& content, + RpcResponseType type = RpcResponseType::ResponseWithValue) PURE; + +protected: + SerializerPtr serializer_; }; using ProtocolPtr = std::unique_ptr; @@ -119,9 +103,10 @@ class NamedProtocolConfigFactory { /** * Create a particular Dubbo protocol. + * @param serialization_type the serialization type of the protocol body. * @return protocol instance pointer. */ - virtual ProtocolPtr createProtocol() PURE; + virtual ProtocolPtr createProtocol(SerializationType serialization_type) PURE; /** * @return std::string the identifying name for a particular implementation of Dubbo protocol @@ -144,7 +129,11 @@ class NamedProtocolConfigFactory { * ProtocolFactoryBase provides a template for a trivial NamedProtocolConfigFactory. */ template class ProtocolFactoryBase : public NamedProtocolConfigFactory { - ProtocolPtr createProtocol() override { return std::make_unique(); } + ProtocolPtr createProtocol(SerializationType serialization_type) override { + auto protocol = std::make_unique(); + protocol->initSerializer(serialization_type); + return protocol; + } std::string name() override { return name_; } diff --git a/source/extensions/filters/network/dubbo_proxy/protocol_constants.h b/source/extensions/filters/network/dubbo_proxy/protocol_constants.h new file mode 100644 index 000000000000..138905d22c1e --- /dev/null +++ b/source/extensions/filters/network/dubbo_proxy/protocol_constants.h @@ -0,0 +1,98 @@ +#pragma once + +#include + +#include "common/common/assert.h" +#include "common/common/fmt.h" +#include "common/singleton/const_singleton.h" + +#include "extensions/filters/network/dubbo_proxy/message.h" + +namespace Envoy { +namespace Extensions { +namespace NetworkFilters { +namespace DubboProxy { + +/** + * Names of available Protocol implementations. + */ +class ProtocolNameValues { +public: + struct ProtocolTypeHash { + template std::size_t operator()(T t) const { return static_cast(t); } + }; + + using ProtocolTypeNameMap = std::unordered_map; + + const ProtocolTypeNameMap protocolTypeNameMap = { + {ProtocolType::Dubbo, "dubbo"}, + }; + + const std::string& fromType(ProtocolType type) const { + const auto& itor = protocolTypeNameMap.find(type); + ASSERT(itor != protocolTypeNameMap.end()); + return itor->second; + } +}; + +using ProtocolNames = ConstSingleton; + +/** + * Names of available serializer implementations. + */ +class SerializerNameValues { +public: + struct SerializationTypeHash { + template std::size_t operator()(T t) const { return static_cast(t); } + }; + + using SerializerTypeNameMap = + std::unordered_map; + + const SerializerTypeNameMap serializerTypeNameMap = { + {SerializationType::Hessian2, "hessian2"}, + }; + + const std::string& fromType(SerializationType type) const { + const auto& itor = serializerTypeNameMap.find(type); + ASSERT(itor != serializerTypeNameMap.end()); + return itor->second; + } +}; + +using SerializerNames = ConstSingleton; + +class ProtocolSerializerNameValues { +public: + inline uint8_t generateKey(ProtocolType protocol_type, + SerializationType serialization_type) const { + return static_cast(serialization_type) ^ static_cast(protocol_type); + } + + inline std::string generateValue(ProtocolType protocol_type, + SerializationType serialization_type) const { + return fmt::format("{}.{}", ProtocolNames::get().fromType(protocol_type), + SerializerNames::get().fromType(serialization_type)); + } + +#define GENERATE_PAIR(X, Y) generateKey(X, Y), generateValue(X, Y) + + using ProtocolSerializerTypeNameMap = std::unordered_map; + + const ProtocolSerializerTypeNameMap protocolSerializerTypeNameMap = { + {GENERATE_PAIR(ProtocolType::Dubbo, SerializationType::Hessian2)}, + }; + + const std::string& fromType(ProtocolType protocol_type, SerializationType type) const { + const auto& itor = protocolSerializerTypeNameMap.find(generateKey(protocol_type, type)); + ASSERT(itor != protocolSerializerTypeNameMap.end()); + return itor->second; + } +}; + +using ProtocolSerializerNames = ConstSingleton; + +} // namespace DubboProxy +} // namespace NetworkFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/network/dubbo_proxy/router/BUILD b/source/extensions/filters/network/dubbo_proxy/router/BUILD index 790e94d00e3a..0256ac5cdb31 100644 --- a/source/extensions/filters/network/dubbo_proxy/router/BUILD +++ b/source/extensions/filters/network/dubbo_proxy/router/BUILD @@ -17,11 +17,25 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "route_matcher_interface", + hdrs = ["route.h"], + deps = [ + ":router_interface", + "//include/envoy/server:filter_config_interface", + "//source/common/config:utility_lib", + "//source/common/singleton:const_singleton", + "//source/extensions/filters/network/dubbo_proxy:metadata_lib", + "@envoy_api//envoy/config/filter/network/dubbo_proxy/v2alpha1:dubbo_proxy_cc", + ], +) + envoy_cc_library( name = "route_matcher", srcs = ["route_matcher.cc"], hdrs = ["route_matcher.h"], deps = [ + ":route_matcher_interface", ":router_interface", "//include/envoy/router:router_interface", "//source/common/common:logger_lib", @@ -29,6 +43,7 @@ envoy_cc_library( "//source/common/http:header_utility_lib", "//source/common/protobuf:utility_lib", "//source/extensions/filters/network/dubbo_proxy:metadata_lib", + "//source/extensions/filters/network/dubbo_proxy:serializer_interface", "@envoy_api//envoy/config/filter/network/dubbo_proxy/v2alpha1:dubbo_proxy_cc", ], ) @@ -62,8 +77,8 @@ envoy_cc_library( "//source/common/router:metadatamatchcriteria_lib", "//source/common/upstream:load_balancer_lib", "//source/extensions/filters/network/dubbo_proxy:app_exception_lib", - "//source/extensions/filters/network/dubbo_proxy:deserializer_interface", "//source/extensions/filters/network/dubbo_proxy:protocol_interface", + "//source/extensions/filters/network/dubbo_proxy:serializer_interface", "//source/extensions/filters/network/dubbo_proxy/filters:filter_interface", "@envoy_api//envoy/config/filter/network/dubbo_proxy/v2alpha1:dubbo_proxy_cc", ], diff --git a/source/extensions/filters/network/dubbo_proxy/router/config.cc b/source/extensions/filters/network/dubbo_proxy/router/config.cc index 4e4382a61bc3..a362dc7c86f3 100644 --- a/source/extensions/filters/network/dubbo_proxy/router/config.cc +++ b/source/extensions/filters/network/dubbo_proxy/router/config.cc @@ -21,8 +21,7 @@ DubboFilters::FilterFactoryCb RouterFilterConfig::createFilterFactoryFromProtoTy /** * Static registration for the router filter. @see RegisterFactory. */ -static Registry::RegisterFactory - register_; +REGISTER_FACTORY(RouterFilterConfig, DubboFilters::NamedDubboFilterConfigFactory); } // namespace Router } // namespace DubboProxy diff --git a/source/extensions/filters/network/dubbo_proxy/router/route.h b/source/extensions/filters/network/dubbo_proxy/router/route.h new file mode 100644 index 000000000000..61844ce6a2bc --- /dev/null +++ b/source/extensions/filters/network/dubbo_proxy/router/route.h @@ -0,0 +1,121 @@ +#pragma once + +#include +#include + +#include "envoy/config/filter/network/dubbo_proxy/v2alpha1/route.pb.h" +#include "envoy/router/router.h" +#include "envoy/server/filter_config.h" + +#include "common/config/utility.h" +#include "common/singleton/const_singleton.h" + +#include "extensions/filters/network/dubbo_proxy/metadata.h" +#include "extensions/filters/network/dubbo_proxy/router/router.h" + +namespace Envoy { +namespace Extensions { +namespace NetworkFilters { +namespace DubboProxy { +namespace Router { + +using RouteConfigurations = Protobuf::RepeatedPtrField< + ::envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteConfiguration>; + +enum class RouteMatcherType : uint8_t { + Default, +}; + +/** + * Names of available Protocol implementations. + */ +class RouteMatcherNameValues { +public: + struct RouteMatcherTypeHash { + template std::size_t operator()(T t) const { return static_cast(t); } + }; + + using RouteMatcherNameMap = + std::unordered_map; + + const RouteMatcherNameMap routeMatcherNameMap = { + {RouteMatcherType::Default, "default"}, + }; + + const std::string& fromType(RouteMatcherType type) const { + const auto& itor = routeMatcherNameMap.find(type); + ASSERT(itor != routeMatcherNameMap.end()); + return itor->second; + } +}; + +using RouteMatcherNames = ConstSingleton; + +class RouteMatcher { +public: + virtual ~RouteMatcher() = default; + + virtual RouteConstSharedPtr route(const MessageMetadata& metadata, + uint64_t random_value) const PURE; +}; + +using RouteMatcherPtr = std::unique_ptr; +using RouteMatcherConstSharedPtr = std::shared_ptr; + +/** + * Implemented by each Dubbo protocol and registered via Registry::registerFactory or the + * convenience class RegisterFactory. + */ +class NamedRouteMatcherConfigFactory { +public: + virtual ~NamedRouteMatcherConfigFactory() = default; + + /** + * Create a particular Dubbo protocol. + * @param serialization_type the serialization type of the protocol body. + * @return protocol instance pointer. + */ + virtual RouteMatcherPtr createRouteMatcher(const RouteConfigurations& route_configs, + Server::Configuration::FactoryContext& context) PURE; + + /** + * @return std::string the identifying name for a particular implementation of Dubbo protocol + * produced by the factory. + */ + virtual std::string name() PURE; + + /** + * Convenience method to lookup a factory by type. + * @param RouteMatcherType the protocol type. + * @return NamedRouteMatcherConfigFactory& for the RouteMatcherType. + */ + static NamedRouteMatcherConfigFactory& getFactory(RouteMatcherType type) { + const std::string& name = RouteMatcherNames::get().fromType(type); + return Envoy::Config::Utility::getAndCheckFactory(name); + } +}; + +/** + * RouteMatcherFactoryBase provides a template for a trivial NamedProtocolConfigFactory. + */ +template +class RouteMatcherFactoryBase : public NamedRouteMatcherConfigFactory { + RouteMatcherPtr createRouteMatcher(const RouteConfigurations& route_configs, + Server::Configuration::FactoryContext& context) override { + return std::make_unique(route_configs, context); + } + + std::string name() override { return name_; } + +protected: + RouteMatcherFactoryBase(RouteMatcherType type) : name_(RouteMatcherNames::get().fromType(type)) {} + +private: + const std::string name_; +}; + +} // namespace Router +} // namespace DubboProxy +} // namespace NetworkFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/network/dubbo_proxy/router/route_matcher.cc b/source/extensions/filters/network/dubbo_proxy/router/route_matcher.cc index 512b38e43398..81eac5f0f396 100644 --- a/source/extensions/filters/network/dubbo_proxy/router/route_matcher.cc +++ b/source/extensions/filters/network/dubbo_proxy/router/route_matcher.cc @@ -5,6 +5,8 @@ #include "common/protobuf/utility.h" +#include "extensions/filters/network/dubbo_proxy/serializer_impl.h" + namespace Envoy { namespace Extensions { namespace NetworkFilters { @@ -62,7 +64,7 @@ ParameterRouteEntryImpl::ParameterRouteEntryImpl( } } -ParameterRouteEntryImpl::~ParameterRouteEntryImpl() {} +ParameterRouteEntryImpl::~ParameterRouteEntryImpl() = default; bool ParameterRouteEntryImpl::matchParameter(absl::string_view request_data, const ParameterData& config_data) const { @@ -81,13 +83,16 @@ bool ParameterRouteEntryImpl::matchParameter(absl::string_view request_data, RouteConstSharedPtr ParameterRouteEntryImpl::matches(const MessageMetadata& metadata, uint64_t random_value) const { - if (!metadata.hasParameters()) { + ASSERT(metadata.hasInvocationInfo()); + const auto invocation = dynamic_cast(&metadata.invocation_info()); + ASSERT(invocation); + if (!invocation->hasParameters()) { return nullptr; } ENVOY_LOG(debug, "dubbo route matcher: parameter name match"); for (auto& config_data : parameter_data_list_) { - const std::string& data = metadata.getParameterValue(config_data.index_); + const std::string& data = invocation->getParameterValue(config_data.index_); if (data.empty()) { ENVOY_LOG(debug, "dubbo route matcher: parameter matching failed, there are no parameters in the " @@ -133,23 +138,27 @@ MethodRouteEntryImpl::MethodRouteEntryImpl( } } -MethodRouteEntryImpl::~MethodRouteEntryImpl() {} +MethodRouteEntryImpl::~MethodRouteEntryImpl() = default; RouteConstSharedPtr MethodRouteEntryImpl::matches(const MessageMetadata& metadata, uint64_t random_value) const { - if (metadata.hasHeaders() && !RouteEntryImplBase::headersMatch(metadata.headers())) { + ASSERT(metadata.hasInvocationInfo()); + const auto invocation = dynamic_cast(&metadata.invocation_info()); + ASSERT(invocation); + + if (invocation->hasHeaders() && !RouteEntryImplBase::headersMatch(invocation->headers())) { ENVOY_LOG(error, "dubbo route matcher: headers not match"); return nullptr; } - if (!metadata.method_name().has_value()) { + if (invocation->method_name().empty()) { ENVOY_LOG(error, "dubbo route matcher: there is no method name in the metadata"); return nullptr; } - if (!method_name_.match(metadata.method_name().value())) { + if (!method_name_.match(invocation->method_name())) { ENVOY_LOG(debug, "dubbo route matcher: method matching failed, input method '{}'", - metadata.method_name().value()); + invocation->method_name()); return nullptr; } @@ -161,7 +170,8 @@ RouteConstSharedPtr MethodRouteEntryImpl::matches(const MessageMetadata& metadat return clusterEntry(random_value); } -RouteMatcher::RouteMatcher(const RouteConfig& config) +SignleRouteMatcherImpl::SignleRouteMatcherImpl(const RouteConfig& config, + Server::Configuration::FactoryContext&) : service_name_(config.interface()), group_(config.group()), version_(config.version()) { using envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteMatch; @@ -171,13 +181,16 @@ RouteMatcher::RouteMatcher(const RouteConfig& config) ENVOY_LOG(debug, "dubbo route matcher: routes list size {}", routes_.size()); } -RouteConstSharedPtr RouteMatcher::route(const MessageMetadata& metadata, - uint64_t random_value) const { - if (service_name_ == metadata.service_name() && +RouteConstSharedPtr SignleRouteMatcherImpl::route(const MessageMetadata& metadata, + uint64_t random_value) const { + ASSERT(metadata.hasInvocationInfo()); + const auto& invocation = metadata.invocation_info(); + + if (service_name_ == invocation.service_name() && (group_.value().empty() || - (metadata.service_group().has_value() && metadata.service_group().value() == group_)) && - (version_.value().empty() || (metadata.service_version().has_value() && - metadata.service_version().value() == version_))) { + (invocation.service_group().has_value() && invocation.service_group().value() == group_)) && + (version_.value().empty() || (invocation.service_version().has_value() && + invocation.service_version().value() == version_))) { for (const auto& route : routes_) { RouteConstSharedPtr route_entry = route->matches(metadata, random_value); if (nullptr != route_entry) { @@ -191,9 +204,11 @@ RouteConstSharedPtr RouteMatcher::route(const MessageMetadata& metadata, return nullptr; } -MultiRouteMatcher::MultiRouteMatcher(const RouteConfigList& route_config_list) { +MultiRouteMatcher::MultiRouteMatcher(const RouteConfigList& route_config_list, + Server::Configuration::FactoryContext& context) { for (const auto& route_config : route_config_list) { - route_matcher_list_.emplace_back(std::make_unique(route_config)); + route_matcher_list_.emplace_back( + std::make_unique(route_config, context)); } ENVOY_LOG(debug, "route matcher list size {}", route_matcher_list_.size()); } @@ -210,6 +225,16 @@ RouteConstSharedPtr MultiRouteMatcher::route(const MessageMetadata& metadata, return nullptr; } +class DefaultRouteMatcherConfigFactory : public RouteMatcherFactoryBase { +public: + DefaultRouteMatcherConfigFactory() : RouteMatcherFactoryBase(RouteMatcherType::Default) {} +}; + +/** + * Static registration for the Dubbo protocol. @see RegisterFactory. + */ +REGISTER_FACTORY(DefaultRouteMatcherConfigFactory, NamedRouteMatcherConfigFactory); + } // namespace Router } // namespace DubboProxy } // namespace NetworkFilters diff --git a/source/extensions/filters/network/dubbo_proxy/router/route_matcher.h b/source/extensions/filters/network/dubbo_proxy/router/route_matcher.h index cf01e91c9e28..caa8b9ca3112 100644 --- a/source/extensions/filters/network/dubbo_proxy/router/route_matcher.h +++ b/source/extensions/filters/network/dubbo_proxy/router/route_matcher.h @@ -13,6 +13,7 @@ #include "common/protobuf/protobuf.h" #include "extensions/filters/network/dubbo_proxy/metadata.h" +#include "extensions/filters/network/dubbo_proxy/router/route.h" #include "extensions/filters/network/dubbo_proxy/router/router.h" #include "absl/types/optional.h" @@ -29,7 +30,7 @@ class RouteEntryImplBase : public RouteEntry, public Logger::Loggable { public: RouteEntryImplBase(const envoy::config::filter::network::dubbo_proxy::v2alpha1::Route& route); - virtual ~RouteEntryImplBase() = default; + ~RouteEntryImplBase() override = default; // Router::RouteEntry const std::string& clusterName() const override; @@ -126,12 +127,12 @@ class MethodRouteEntryImpl : public RouteEntryImplBase { std::shared_ptr parameter_route_; }; -class RouteMatcher : public Logger::Loggable { +class SignleRouteMatcherImpl : public RouteMatcher, public Logger::Loggable { public: using RouteConfig = envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteConfiguration; - RouteMatcher(const RouteConfig& config); + SignleRouteMatcherImpl(const RouteConfig& config, Server::Configuration::FactoryContext& context); - RouteConstSharedPtr route(const MessageMetadata& metadata, uint64_t random_value) const; + RouteConstSharedPtr route(const MessageMetadata& metadata, uint64_t random_value) const override; private: std::vector routes_; @@ -140,16 +141,14 @@ class RouteMatcher : public Logger::Loggable { const absl::optional version_; }; -using RouteMatcherConstSharedPtr = std::shared_ptr; -using RouteMatcherPtr = std::unique_ptr; - -class MultiRouteMatcher : public Logger::Loggable { +class MultiRouteMatcher : public RouteMatcher, public Logger::Loggable { public: using RouteConfigList = Envoy::Protobuf::RepeatedPtrField< ::envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteConfiguration>; - MultiRouteMatcher(const RouteConfigList& route_config_list); + MultiRouteMatcher(const RouteConfigList& route_config_list, + Server::Configuration::FactoryContext& context); - RouteConstSharedPtr route(const MessageMetadata& metadata, uint64_t random_value) const; + RouteConstSharedPtr route(const MessageMetadata& metadata, uint64_t random_value) const override; private: std::vector route_matcher_list_; diff --git a/source/extensions/filters/network/dubbo_proxy/router/router.h b/source/extensions/filters/network/dubbo_proxy/router/router.h index 790abe825d5e..37887be6058d 100644 --- a/source/extensions/filters/network/dubbo_proxy/router/router.h +++ b/source/extensions/filters/network/dubbo_proxy/router/router.h @@ -32,6 +32,8 @@ class RouteEntry { virtual const Envoy::Router::MetadataMatchCriteria* metadataMatchCriteria() const PURE; }; +using RouteEntryPtr = std::shared_ptr; + /** * Route holds the RouteEntry for a request. */ @@ -46,6 +48,7 @@ class Route { }; using RouteConstSharedPtr = std::shared_ptr; +using RouteSharedPtr = std::shared_ptr; /** * The router configuration. diff --git a/source/extensions/filters/network/dubbo_proxy/router/router_impl.cc b/source/extensions/filters/network/dubbo_proxy/router/router_impl.cc index 7788ed82befc..7e985e71a59d 100644 --- a/source/extensions/filters/network/dubbo_proxy/router/router_impl.cc +++ b/source/extensions/filters/network/dubbo_proxy/router/router_impl.cc @@ -23,47 +23,19 @@ void Router::setDecoderFilterCallbacks(DubboFilters::DecoderFilterCallbacks& cal callbacks_ = &callbacks; } -Network::FilterStatus Router::transportBegin() { - upstream_request_buffer_.drain(upstream_request_buffer_.length()); - ProtocolDataPassthroughConverter::initProtocolConverter(upstream_request_buffer_); - return Network::FilterStatus::Continue; -} - -Network::FilterStatus Router::transportEnd() { - // If the connection fails, the callback of the filter will be suspended, - // so it is impossible to call the transportEnd interface. - // the encodeData function will be called only if the connection is successful. - ASSERT(upstream_request_); - ASSERT(upstream_request_->conn_data_); - - upstream_request_->encodeData(upstream_request_buffer_); - - if (upstream_request_->metadata_->message_type() == MessageType::Oneway) { - // No response expected - upstream_request_->onResponseComplete(); - cleanup(); - ENVOY_LOG(debug, "dubbo upstream request: the message is one-way and no response is required"); - } - - filter_complete_ = true; - - return Network::FilterStatus::Continue; -} - -Network::FilterStatus Router::messageBegin(MessageType, int64_t, SerializationType) { - return Network::FilterStatus::Continue; -} +FilterStatus Router::onMessageDecoded(MessageMetadataSharedPtr metadata, ContextSharedPtr ctx) { + ASSERT(metadata->hasInvocationInfo()); + const auto& invocation = metadata->invocation_info(); -Network::FilterStatus Router::messageEnd(MessageMetadataSharedPtr metadata) { route_ = callbacks_->route(); if (!route_) { ENVOY_STREAM_LOG(debug, "dubbo router: no cluster match for interface '{}'", *callbacks_, - metadata->service_name()); + invocation.service_name()); callbacks_->sendLocalReply(AppException(ResponseStatus::ServiceNotFound, fmt::format("dubbo router: no route for interface '{}'", - metadata->service_name())), + invocation.service_name())), false); - return Network::FilterStatus::StopIteration; + return FilterStatus::StopIteration; } route_entry_ = route_->routeEntry(); @@ -76,12 +48,12 @@ Network::FilterStatus Router::messageEnd(MessageMetadataSharedPtr metadata) { AppException(ResponseStatus::ServerError, fmt::format("dubbo router: unknown cluster '{}'", route_entry_->clusterName())), false); - return Network::FilterStatus::StopIteration; + return FilterStatus::StopIteration; } cluster_ = cluster->info(); ENVOY_STREAM_LOG(debug, "dubbo router: cluster '{}' match for interface '{}'", *callbacks_, - route_entry_->clusterName(), metadata->service_name()); + route_entry_->clusterName(), invocation.service_name()); if (cluster_->maintenanceMode()) { callbacks_->sendLocalReply( @@ -89,7 +61,7 @@ Network::FilterStatus Router::messageEnd(MessageMetadataSharedPtr metadata) { fmt::format("dubbo router: maintenance mode for cluster '{}'", route_entry_->clusterName())), false); - return Network::FilterStatus::StopIteration; + return FilterStatus::StopIteration; } Tcp::ConnectionPool::Instance* conn_pool = cluster_manager_.tcpConnPoolForCluster( @@ -100,14 +72,14 @@ Network::FilterStatus Router::messageEnd(MessageMetadataSharedPtr metadata) { ResponseStatus::ServerError, fmt::format("dubbo router: no healthy upstream for '{}'", route_entry_->clusterName())), false); - return Network::FilterStatus::StopIteration; + return FilterStatus::StopIteration; } ENVOY_STREAM_LOG(debug, "dubbo router: decoding request", *callbacks_); + upstream_request_buffer_.move(ctx->message_origin_data(), ctx->message_size()); - upstream_request_ = std::make_unique(*this, *conn_pool, metadata, - callbacks_->downstreamSerializationType(), - callbacks_->downstreamProtocolType()); + upstream_request_ = std::make_unique( + *this, *conn_pool, metadata, callbacks_->serializationType(), callbacks_->protocolType()); return upstream_request_->start(); } @@ -118,8 +90,7 @@ void Router::onUpstreamData(Buffer::Instance& data, bool end_stream) { // Handle normal response. if (!upstream_request_->response_started_) { - callbacks_->startUpstreamResponse(*upstream_request_->deserializer_.get(), - *upstream_request_->protocol_.get()); + callbacks_->startUpstreamResponse(); upstream_request_->response_started_ = true; } @@ -191,23 +162,22 @@ Router::UpstreamRequest::UpstreamRequest(Router& parent, Tcp::ConnectionPool::In SerializationType serialization_type, ProtocolType protocol_type) : parent_(parent), conn_pool_(pool), metadata_(metadata), - deserializer_( - NamedDeserializerConfigFactory::getFactory(serialization_type).createDeserializer()), - protocol_(NamedProtocolConfigFactory::getFactory(protocol_type).createProtocol()), + protocol_( + NamedProtocolConfigFactory::getFactory(protocol_type).createProtocol(serialization_type)), request_complete_(false), response_started_(false), response_complete_(false), stream_reset_(false) {} -Router::UpstreamRequest::~UpstreamRequest() {} +Router::UpstreamRequest::~UpstreamRequest() = default; -Network::FilterStatus Router::UpstreamRequest::start() { +FilterStatus Router::UpstreamRequest::start() { Tcp::ConnectionPool::Cancellable* handle = conn_pool_.newConnection(*this); if (handle) { // Pause while we wait for a connection. conn_pool_handle_ = handle; - return Network::FilterStatus::StopIteration; + return FilterStatus::StopIteration; } - return Network::FilterStatus::Continue; + return FilterStatus::Continue; } void Router::UpstreamRequest::resetStream() { @@ -270,6 +240,7 @@ void Router::UpstreamRequest::onPoolReady(Tcp::ConnectionPool::ConnectionDataPtr conn_pool_handle_ = nullptr; onRequestStart(continue_decoding); + encodeData(parent_.upstream_request_buffer_); } void Router::UpstreamRequest::onRequestStart(bool continue_decoding) { diff --git a/source/extensions/filters/network/dubbo_proxy/router/router_impl.h b/source/extensions/filters/network/dubbo_proxy/router/router_impl.h index 63bcfa0e4ae4..9fc078a5aa4b 100644 --- a/source/extensions/filters/network/dubbo_proxy/router/router_impl.h +++ b/source/extensions/filters/network/dubbo_proxy/router/router_impl.h @@ -24,16 +24,13 @@ class Router : public Tcp::ConnectionPool::UpstreamCallbacks, Logger::Loggable { public: Router(Upstream::ClusterManager& cluster_manager) : cluster_manager_(cluster_manager) {} - ~Router() {} + ~Router() override = default; // DubboFilters::DecoderFilter void onDestroy() override; void setDecoderFilterCallbacks(DubboFilters::DecoderFilterCallbacks& callbacks) override; - Network::FilterStatus transportBegin() override; - Network::FilterStatus transportEnd() override; - Network::FilterStatus messageBegin(MessageType type, int64_t message_id, - SerializationType serialization_type) override; - Network::FilterStatus messageEnd(MessageMetadataSharedPtr metadata) override; + + FilterStatus onMessageDecoded(MessageMetadataSharedPtr metadata, ContextSharedPtr ctx) override; // Upstream::LoadBalancerContextBase const Envoy::Router::MetadataMatchCriteria* metadataMatchCriteria() override { return nullptr; } @@ -50,9 +47,9 @@ class Router : public Tcp::ConnectionPool::UpstreamCallbacks, UpstreamRequest(Router& parent, Tcp::ConnectionPool::Instance& pool, MessageMetadataSharedPtr& metadata, SerializationType serialization_type, ProtocolType protocol_type); - ~UpstreamRequest(); + ~UpstreamRequest() override; - Network::FilterStatus start(); + FilterStatus start(); void resetStream(); void encodeData(Buffer::Instance& data); @@ -75,7 +72,7 @@ class Router : public Tcp::ConnectionPool::UpstreamCallbacks, Tcp::ConnectionPool::Cancellable* conn_pool_handle_{}; Tcp::ConnectionPool::ConnectionDataPtr conn_data_; Upstream::HostDescriptionConstSharedPtr upstream_host_; - DeserializerPtr deserializer_; + SerializerPtr serializer_; ProtocolPtr protocol_; bool request_complete_ : 1; diff --git a/source/extensions/filters/network/dubbo_proxy/serializer.h b/source/extensions/filters/network/dubbo_proxy/serializer.h new file mode 100644 index 000000000000..13b5dc8f0b3e --- /dev/null +++ b/source/extensions/filters/network/dubbo_proxy/serializer.h @@ -0,0 +1,128 @@ +#pragma once + +#include +#include + +#include "envoy/buffer/buffer.h" + +#include "common/common/assert.h" +#include "common/config/utility.h" +#include "common/singleton/const_singleton.h" + +#include "extensions/filters/network/dubbo_proxy/message.h" +#include "extensions/filters/network/dubbo_proxy/metadata.h" +#include "extensions/filters/network/dubbo_proxy/protocol_constants.h" + +namespace Envoy { +namespace Extensions { +namespace NetworkFilters { +namespace DubboProxy { + +class Serializer { +public: + virtual ~Serializer() = default; + + /** + * Return this Serializer's name + * + * @return std::string containing the serialization name. + */ + virtual const std::string& name() const PURE; + + /** + * @return SerializationType the serializer type + */ + virtual SerializationType type() const PURE; + + /** + * deserialize an rpc call + * If successful, the RpcInvocation removed from the buffer + * + * @param buffer the currently buffered dubbo data + * @param context context information for RPC messages + * @return a pair containing the deserialized result of the message and the deserialized + * invocation information. + * @throws EnvoyException if the data is not valid for this serialization + */ + virtual std::pair + deserializeRpcInvocation(Buffer::Instance& buffer, ContextSharedPtr context) PURE; + + /** + * deserialize result of an rpc call + * + * @param buffer the currently buffered dubbo data + * @param context context information for RPC messages + * @return a pair containing the deserialized result of the message and the deserialized + * result information. + * @throws EnvoyException if the data is not valid for this serialization + */ + virtual std::pair deserializeRpcResult(Buffer::Instance& buffer, + ContextSharedPtr context) PURE; + + /** + * serialize result of an rpc call + * If successful, the output_buffer is written to the serialized data + * + * @param output_buffer store the serialized data + * @param content the rpc response content + * @param type the rpc response type + * @return size_t the length of the serialized content + */ + virtual size_t serializeRpcResult(Buffer::Instance& output_buffer, const std::string& content, + RpcResponseType type) PURE; +}; + +using SerializerPtr = std::unique_ptr; + +/** + * Implemented by each Dubbo serialize and registered via Registry::registerFactory or the + * convenience class RegisterFactory. + */ +class NamedSerializerConfigFactory { +public: + virtual ~NamedSerializerConfigFactory() = default; + + /** + * Create a particular Dubbo serializer. + * @return SerializerPtr the transport + */ + virtual SerializerPtr createSerializer() PURE; + + /** + * @return std::string the identifying name for a particular implementation of Dubbo serializer + * produced by the factory. + */ + virtual std::string name() PURE; + + /** + * Convenience method to lookup a factory by type. + * @param TransportType the transport type + * @return NamedSerializerConfigFactory& for the TransportType + */ + static NamedSerializerConfigFactory& getFactory(ProtocolType protocol_type, + SerializationType type) { + const std::string& name = ProtocolSerializerNames::get().fromType(protocol_type, type); + return Envoy::Config::Utility::getAndCheckFactory(name); + } +}; + +/** + * SerializerFactoryBase provides a template for a trivial NamedSerializerConfigFactory. + */ +template class SerializerFactoryBase : public NamedSerializerConfigFactory { + SerializerPtr createSerializer() override { return std::make_unique(); } + + std::string name() override { return name_; } + +protected: + SerializerFactoryBase(ProtocolType protocol_type, SerializationType type) + : name_(ProtocolSerializerNames::get().fromType(protocol_type, type)) {} + +private: + const std::string name_; +}; + +} // namespace DubboProxy +} // namespace NetworkFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/network/dubbo_proxy/serializer_impl.cc b/source/extensions/filters/network/dubbo_proxy/serializer_impl.cc new file mode 100644 index 000000000000..550e847cc4d2 --- /dev/null +++ b/source/extensions/filters/network/dubbo_proxy/serializer_impl.cc @@ -0,0 +1,48 @@ +#include "extensions/filters/network/dubbo_proxy/serializer_impl.h" + +namespace Envoy { +namespace Extensions { +namespace NetworkFilters { +namespace DubboProxy { + +void RpcInvocationImpl::addParameterValue(uint32_t index, const std::string& value) { + assignParameterIfNeed(); + parameter_map_->emplace(index, value); +} + +const std::string& RpcInvocationImpl::getParameterValue(uint32_t index) const { + if (parameter_map_) { + auto itor = parameter_map_->find(index); + if (itor != parameter_map_->end()) { + return itor->second; + } + } + + return EMPTY_STRING; +} + +const RpcInvocationImpl::ParameterValueMap& RpcInvocationImpl::parameters() { + ASSERT(hasParameters()); + return *parameter_map_; +} + +const Http::HeaderMap& RpcInvocationImpl::headers() const { + ASSERT(hasHeaders()); + return *headers_; +} + +void RpcInvocationImpl::addHeader(const std::string& key, const std::string& value) { + assignHeaderIfNeed(); + headers_->addCopy(Http::LowerCaseString(key), value); +} + +void RpcInvocationImpl::addHeaderReference(const Http::LowerCaseString& key, + const std::string& value) { + assignHeaderIfNeed(); + headers_->addReference(key, value); +} + +} // namespace DubboProxy +} // namespace NetworkFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/network/dubbo_proxy/serializer_impl.h b/source/extensions/filters/network/dubbo_proxy/serializer_impl.h new file mode 100644 index 000000000000..e5ddae675dc8 --- /dev/null +++ b/source/extensions/filters/network/dubbo_proxy/serializer_impl.h @@ -0,0 +1,64 @@ +#pragma once + +#include "extensions/filters/network/dubbo_proxy/message_impl.h" +#include "extensions/filters/network/dubbo_proxy/serializer.h" + +namespace Envoy { +namespace Extensions { +namespace NetworkFilters { +namespace DubboProxy { + +class RpcInvocationImpl : public RpcInvocationBase { +public: + // TODO(gengleilei) Add parameter data types and implement Dubbo data type mapping. + using ParameterValueMap = std::unordered_map; + using ParameterValueMapPtr = std::unique_ptr; + + using HeaderMapPtr = std::unique_ptr; + + RpcInvocationImpl() = default; + ~RpcInvocationImpl() override = default; + + void addParameterValue(uint32_t index, const std::string& value); + const ParameterValueMap& parameters(); + const std::string& getParameterValue(uint32_t index) const; + bool hasParameters() const { return parameter_map_ != nullptr; } + + void addHeader(const std::string& key, const std::string& value); + void addHeaderReference(const Http::LowerCaseString& key, const std::string& value); + const Http::HeaderMap& headers() const; + bool hasHeaders() const { return headers_ != nullptr; } + +private: + inline void assignHeaderIfNeed() { + if (!headers_) { + headers_ = std::make_unique(); + } + } + + inline void assignParameterIfNeed() { + if (!parameter_map_) { + parameter_map_ = std::make_unique(); + } + } + + ParameterValueMapPtr parameter_map_; + HeaderMapPtr headers_; // attachment +}; + +class RpcResultImpl : public RpcResult { +public: + RpcResultImpl() = default; + ~RpcResultImpl() override = default; + + bool hasException() const override { return has_exception_; } + void setException(bool has_exception) { has_exception_ = has_exception; } + +private: + bool has_exception_ = false; +}; + +} // namespace DubboProxy +} // namespace NetworkFilters +} // namespace Extensions +} // namespace Envoy \ No newline at end of file diff --git a/source/extensions/filters/network/ext_authz/ext_authz.h b/source/extensions/filters/network/ext_authz/ext_authz.h index b259c62f2f3d..a0a963750be1 100644 --- a/source/extensions/filters/network/ext_authz/ext_authz.h +++ b/source/extensions/filters/network/ext_authz/ext_authz.h @@ -73,7 +73,7 @@ class Filter : public Network::ReadFilter, public: Filter(ConfigSharedPtr config, Filters::Common::ExtAuthz::ClientPtr&& client) : config_(config), client_(std::move(client)) {} - ~Filter() {} + ~Filter() override = default; // Network::ReadFilter Network::FilterStatus onData(Buffer::Instance& data, bool end_stream) override; diff --git a/source/extensions/filters/network/kafka/codec.h b/source/extensions/filters/network/kafka/codec.h index 6dfe638d31d0..54e5709981be 100644 --- a/source/extensions/filters/network/kafka/codec.h +++ b/source/extensions/filters/network/kafka/codec.h @@ -48,7 +48,7 @@ template class MessageCallback template class AbstractMessageDecoder : public MessageDecoder { public: - virtual ~AbstractMessageDecoder() = default; + ~AbstractMessageDecoder() override = default; /** * Creates a decoder that will invoke given callbacks when a message has been parsed. diff --git a/source/extensions/filters/network/kafka/serialization.h b/source/extensions/filters/network/kafka/serialization.h index 430cbe29e706..3e7fdc8e2ec6 100644 --- a/source/extensions/filters/network/kafka/serialization.h +++ b/source/extensions/filters/network/kafka/serialization.h @@ -60,7 +60,7 @@ template class Deserializer { */ template class IntDeserializer : public Deserializer { public: - IntDeserializer() : written_{0}, ready_(false){}; + IntDeserializer() : written_{0} {}; uint32_t feed(absl::string_view& data) override { const uint32_t available = std::min(sizeof(buf_) - written_, data.size()); @@ -153,7 +153,7 @@ class Int64Deserializer : public IntDeserializer { */ class BooleanDeserializer : public Deserializer { public: - BooleanDeserializer(){}; + BooleanDeserializer() = default; uint32_t feed(absl::string_view& data) override { return buffer_.feed(data); } diff --git a/source/extensions/filters/network/mongo_proxy/bson_impl.h b/source/extensions/filters/network/mongo_proxy/bson_impl.h index f929c6f4e45b..18d8ddc9ab9f 100644 --- a/source/extensions/filters/network/mongo_proxy/bson_impl.h +++ b/source/extensions/filters/network/mongo_proxy/bson_impl.h @@ -268,7 +268,7 @@ class DocumentImpl : public Document, const std::list& values() const override { return fields_; } private: - DocumentImpl() {} + DocumentImpl() = default; void fromBuffer(Buffer::Instance& data); diff --git a/source/extensions/filters/network/mongo_proxy/proxy.h b/source/extensions/filters/network/mongo_proxy/proxy.h index 35cdc29c17d1..f81ef86017ef 100644 --- a/source/extensions/filters/network/mongo_proxy/proxy.h +++ b/source/extensions/filters/network/mongo_proxy/proxy.h @@ -111,7 +111,7 @@ class ProxyFilter : public Network::Filter, const Filters::Common::Fault::FaultDelayConfigSharedPtr& fault_config, const Network::DrainDecision& drain_decision, TimeSource& time_system, bool emit_dynamic_metadata); - ~ProxyFilter(); + ~ProxyFilter() override; virtual DecoderPtr createDecoder(DecoderCallbacks& callbacks) PURE; diff --git a/source/extensions/filters/network/rbac/rbac_filter.h b/source/extensions/filters/network/rbac/rbac_filter.h index 8d9402e99680..b548424c63de 100644 --- a/source/extensions/filters/network/rbac/rbac_filter.h +++ b/source/extensions/filters/network/rbac/rbac_filter.h @@ -55,7 +55,7 @@ class RoleBasedAccessControlFilter : public Network::ReadFilter, public: RoleBasedAccessControlFilter(RoleBasedAccessControlFilterConfigSharedPtr config) : config_(config) {} - ~RoleBasedAccessControlFilter() {} + ~RoleBasedAccessControlFilter() override = default; // Network::ReadFilter Network::FilterStatus onData(Buffer::Instance& data, bool end_stream) override; diff --git a/source/extensions/filters/network/redis_proxy/command_splitter_impl.h b/source/extensions/filters/network/redis_proxy/command_splitter_impl.h index e530fe8d3fdf..f4ee4c6f79d4 100644 --- a/source/extensions/filters/network/redis_proxy/command_splitter_impl.h +++ b/source/extensions/filters/network/redis_proxy/command_splitter_impl.h @@ -100,7 +100,7 @@ class SplitRequestBase : public SplitRequest { */ class SingleServerRequest : public SplitRequestBase, public Common::Redis::Client::PoolCallbacks { public: - ~SingleServerRequest(); + ~SingleServerRequest() override; // Common::Redis::Client::PoolCallbacks void onResponse(Common::Redis::RespValuePtr&& response) override; @@ -158,7 +158,7 @@ class EvalRequest : public SingleServerRequest { */ class FragmentedRequest : public SplitRequestBase { public: - ~FragmentedRequest(); + ~FragmentedRequest() override; // RedisProxy::CommandSplitter::SplitRequest void cancel() override; @@ -277,7 +277,7 @@ class CommandHandlerFactory : public CommandHandler, CommandHandlerBase { CommandHandlerFactory(Router& router) : CommandHandlerBase(router) {} SplitRequestPtr startRequest(Common::Redis::RespValuePtr&& request, SplitCallbacks& callbacks, CommandStats& command_stats, TimeSource& time_source, - bool latency_in_micros) { + bool latency_in_micros) override { return RequestClass::create(router_, std::move(request), callbacks, command_stats, time_source, latency_in_micros); } diff --git a/source/extensions/filters/network/redis_proxy/conn_pool_impl.h b/source/extensions/filters/network/redis_proxy/conn_pool_impl.h index ff5b52ed5067..91ea51f3e752 100644 --- a/source/extensions/filters/network/redis_proxy/conn_pool_impl.h +++ b/source/extensions/filters/network/redis_proxy/conn_pool_impl.h @@ -84,7 +84,7 @@ class InstanceImpl : public Instance { struct ThreadLocalPool : public ThreadLocal::ThreadLocalObject, public Upstream::ClusterUpdateCallbacks { ThreadLocalPool(InstanceImpl& parent, Event::Dispatcher& dispatcher, std::string cluster_name); - ~ThreadLocalPool(); + ~ThreadLocalPool() override; ThreadLocalActiveClientPtr& threadLocalActiveClient(Upstream::HostConstSharedPtr host); Common::Redis::Client::PoolRequest* makeRequest(const std::string& key, const Common::Redis::RespValue& request, diff --git a/source/extensions/filters/network/redis_proxy/proxy_filter.h b/source/extensions/filters/network/redis_proxy/proxy_filter.h index d916a97f6fad..aefa3b9a7efa 100644 --- a/source/extensions/filters/network/redis_proxy/proxy_filter.h +++ b/source/extensions/filters/network/redis_proxy/proxy_filter.h @@ -75,7 +75,7 @@ class ProxyFilter : public Network::ReadFilter, public: ProxyFilter(Common::Redis::DecoderFactory& factory, Common::Redis::EncoderPtr&& encoder, CommandSplitter::Instance& splitter, ProxyFilterConfigSharedPtr config); - ~ProxyFilter(); + ~ProxyFilter() override; // Network::ReadFilter void initializeReadFilterCallbacks(Network::ReadFilterCallbacks& callbacks) override; @@ -95,7 +95,7 @@ class ProxyFilter : public Network::ReadFilter, private: struct PendingRequest : public CommandSplitter::SplitCallbacks { PendingRequest(ProxyFilter& parent); - ~PendingRequest(); + ~PendingRequest() override; // RedisProxy::CommandSplitter::SplitCallbacks bool connectionAllowed() override { return parent_.connectionAllowed(); } diff --git a/source/extensions/filters/network/thrift_proxy/compact_protocol_impl.h b/source/extensions/filters/network/thrift_proxy/compact_protocol_impl.h index fa88a0c98d80..5d69037d68e2 100644 --- a/source/extensions/filters/network/thrift_proxy/compact_protocol_impl.h +++ b/source/extensions/filters/network/thrift_proxy/compact_protocol_impl.h @@ -21,7 +21,7 @@ namespace ThriftProxy { */ class CompactProtocolImpl : public Protocol { public: - CompactProtocolImpl() {} + CompactProtocolImpl() = default; // Protocol const std::string& name() const override { return ProtocolNames::get().COMPACT; } diff --git a/source/extensions/filters/network/thrift_proxy/conn_manager.cc b/source/extensions/filters/network/thrift_proxy/conn_manager.cc index 0edb3d6cbb04..509d2f42d3e1 100644 --- a/source/extensions/filters/network/thrift_proxy/conn_manager.cc +++ b/source/extensions/filters/network/thrift_proxy/conn_manager.cc @@ -19,7 +19,7 @@ ConnectionManager::ConnectionManager(Config& config, Runtime::RandomGenerator& r decoder_(std::make_unique(*transport_, *protocol_, *this)), random_generator_(random_generator), time_source_(time_source) {} -ConnectionManager::~ConnectionManager() {} +ConnectionManager::~ConnectionManager() = default; Network::FilterStatus ConnectionManager::onData(Buffer::Instance& data, bool end_stream) { request_buffer_.move(data); diff --git a/source/extensions/filters/network/thrift_proxy/conn_manager.h b/source/extensions/filters/network/thrift_proxy/conn_manager.h index afdcbcc8ff34..2188ad7ee9eb 100644 --- a/source/extensions/filters/network/thrift_proxy/conn_manager.h +++ b/source/extensions/filters/network/thrift_proxy/conn_manager.h @@ -61,7 +61,7 @@ class ConnectionManager : public Network::ReadFilter, public: ConnectionManager(Config& config, Runtime::RandomGenerator& random_generator, TimeSource& time_system); - ~ConnectionManager(); + ~ConnectionManager() override; // Network::ReadFilter Network::FilterStatus onData(Buffer::Instance& data, bool end_stream) override; @@ -164,7 +164,7 @@ class ConnectionManager : public Network::ReadFilter, stream_info_.setDownstreamRemoteAddress( parent_.read_callbacks_->connection().remoteAddress()); } - ~ActiveRpc() { + ~ActiveRpc() override { request_timer_->complete(); parent_.stats_.request_active_.dec(); diff --git a/source/extensions/filters/network/thrift_proxy/filters/ratelimit/BUILD b/source/extensions/filters/network/thrift_proxy/filters/ratelimit/BUILD index 8796cbcc7400..1d6128fda8fb 100644 --- a/source/extensions/filters/network/thrift_proxy/filters/ratelimit/BUILD +++ b/source/extensions/filters/network/thrift_proxy/filters/ratelimit/BUILD @@ -18,6 +18,7 @@ envoy_cc_library( "//source/common/tracing:http_tracer_lib", "//source/extensions/filters/common/ratelimit:ratelimit_client_interface", "//source/extensions/filters/common/ratelimit:ratelimit_lib", + "//source/extensions/filters/common/ratelimit:stat_names_lib", "//source/extensions/filters/network/thrift_proxy:app_exception_lib", "//source/extensions/filters/network/thrift_proxy/filters:filter_interface", "//source/extensions/filters/network/thrift_proxy/router:router_ratelimit_interface", diff --git a/source/extensions/filters/network/thrift_proxy/filters/ratelimit/ratelimit.cc b/source/extensions/filters/network/thrift_proxy/filters/ratelimit/ratelimit.cc index 6131bb77b8b9..d4e5dc70f5d0 100644 --- a/source/extensions/filters/network/thrift_proxy/filters/ratelimit/ratelimit.cc +++ b/source/extensions/filters/network/thrift_proxy/filters/ratelimit/ratelimit.cc @@ -65,13 +65,14 @@ void Filter::complete(Filters::Common::RateLimit::LimitStatus status, UNREFERENCED_PARAMETER(headers); state_ = State::Complete; + Filters::Common::RateLimit::StatNames& stat_names = config_->statNames(); switch (status) { case Filters::Common::RateLimit::LimitStatus::OK: - cluster_->statsScope().counter("ratelimit.ok").inc(); + cluster_->statsScope().counterFromStatName(stat_names.ok_).inc(); break; case Filters::Common::RateLimit::LimitStatus::Error: - cluster_->statsScope().counter("ratelimit.error").inc(); + cluster_->statsScope().counterFromStatName(stat_names.error_).inc(); if (!config_->failureModeAllow()) { state_ = State::Responded; callbacks_->sendLocalReply( @@ -80,10 +81,10 @@ void Filter::complete(Filters::Common::RateLimit::LimitStatus status, callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::RateLimitServiceError); return; } - cluster_->statsScope().counter("ratelimit.failure_mode_allowed").inc(); + cluster_->statsScope().counterFromStatName(stat_names.failure_mode_allowed_).inc(); break; case Filters::Common::RateLimit::LimitStatus::OverLimit: - cluster_->statsScope().counter("ratelimit.over_limit").inc(); + cluster_->statsScope().counterFromStatName(stat_names.over_limit_).inc(); if (config_->runtime().snapshot().featureEnabled("ratelimit.thrift_filter_enforcing", 100)) { state_ = State::Responded; callbacks_->sendLocalReply( diff --git a/source/extensions/filters/network/thrift_proxy/filters/ratelimit/ratelimit.h b/source/extensions/filters/network/thrift_proxy/filters/ratelimit/ratelimit.h index eb9e60dbb5f0..2b68090bc8c9 100644 --- a/source/extensions/filters/network/thrift_proxy/filters/ratelimit/ratelimit.h +++ b/source/extensions/filters/network/thrift_proxy/filters/ratelimit/ratelimit.h @@ -9,7 +9,10 @@ #include "envoy/stats/scope.h" #include "envoy/stats/stats_macros.h" +#include "common/stats/symbol_table_impl.h" + #include "extensions/filters/common/ratelimit/ratelimit.h" +#include "extensions/filters/common/ratelimit/stat_names.h" #include "extensions/filters/network/thrift_proxy/filters/filter.h" namespace Envoy { @@ -28,7 +31,8 @@ class Config { const LocalInfo::LocalInfo& local_info, Stats::Scope& scope, Runtime::Loader& runtime, Upstream::ClusterManager& cm) : domain_(config.domain()), stage_(config.stage()), local_info_(local_info), scope_(scope), - runtime_(runtime), cm_(cm), failure_mode_deny_(config.failure_mode_deny()) {} + runtime_(runtime), cm_(cm), failure_mode_deny_(config.failure_mode_deny()), + stat_names_(scope_.symbolTable()) {} const std::string& domain() const { return domain_; } const LocalInfo::LocalInfo& localInfo() const { return local_info_; } @@ -36,8 +40,8 @@ class Config { Stats::Scope& scope() { return scope_; } Runtime::Loader& runtime() { return runtime_; } Upstream::ClusterManager& cm() { return cm_; } - bool failureModeAllow() const { return !failure_mode_deny_; }; + Filters::Common::RateLimit::StatNames& statNames() { return stat_names_; } private: const std::string domain_; @@ -47,6 +51,7 @@ class Config { Runtime::Loader& runtime_; Upstream::ClusterManager& cm_; const bool failure_mode_deny_; + Filters::Common::RateLimit::StatNames stat_names_; }; using ConfigSharedPtr = std::shared_ptr; diff --git a/source/extensions/filters/network/thrift_proxy/framed_transport_impl.h b/source/extensions/filters/network/thrift_proxy/framed_transport_impl.h index 5adf153a1f0e..786bfce0680b 100644 --- a/source/extensions/filters/network/thrift_proxy/framed_transport_impl.h +++ b/source/extensions/filters/network/thrift_proxy/framed_transport_impl.h @@ -17,7 +17,7 @@ namespace ThriftProxy { */ class FramedTransportImpl : public Transport { public: - FramedTransportImpl() {} + FramedTransportImpl() = default; // Transport const std::string& name() const override { return TransportNames::get().FRAMED; } diff --git a/source/extensions/filters/network/thrift_proxy/metadata.h b/source/extensions/filters/network/thrift_proxy/metadata.h index 5c1469e86e3f..7ee3e68f297f 100644 --- a/source/extensions/filters/network/thrift_proxy/metadata.h +++ b/source/extensions/filters/network/thrift_proxy/metadata.h @@ -1,8 +1,7 @@ #pragma once -#include - #include +#include #include #include #include @@ -30,7 +29,7 @@ namespace ThriftProxy { */ class MessageMetadata { public: - MessageMetadata() {} + MessageMetadata() = default; bool hasFrameSize() const { return frame_size_.has_value(); } uint32_t frameSize() const { return frame_size_.value(); } diff --git a/source/extensions/filters/network/thrift_proxy/router/router_impl.cc b/source/extensions/filters/network/thrift_proxy/router/router_impl.cc index a5112e9a0cc2..1fc44b5f78ae 100644 --- a/source/extensions/filters/network/thrift_proxy/router/router_impl.cc +++ b/source/extensions/filters/network/thrift_proxy/router/router_impl.cc @@ -368,7 +368,7 @@ Router::UpstreamRequest::UpstreamRequest(Router& parent, Tcp::ConnectionPool::In protocol_(NamedProtocolConfigFactory::getFactory(protocol_type).createProtocol()), request_complete_(false), response_started_(false), response_complete_(false) {} -Router::UpstreamRequest::~UpstreamRequest() {} +Router::UpstreamRequest::~UpstreamRequest() = default; FilterStatus Router::UpstreamRequest::start() { Tcp::ConnectionPool::Cancellable* handle = conn_pool_.newConnection(*this); diff --git a/source/extensions/filters/network/thrift_proxy/thrift_object_impl.h b/source/extensions/filters/network/thrift_proxy/thrift_object_impl.h index 8c87c6c8b040..d6961ce87357 100644 --- a/source/extensions/filters/network/thrift_proxy/thrift_object_impl.h +++ b/source/extensions/filters/network/thrift_proxy/thrift_object_impl.h @@ -18,7 +18,7 @@ namespace ThriftProxy { class ThriftBase : public DecoderEventHandler { public: ThriftBase(ThriftBase* parent); - ~ThriftBase() {} + ~ThriftBase() override = default; // DecoderEventHandler FilterStatus transportBegin(MessageMetadataSharedPtr) override { return FilterStatus::Continue; } @@ -61,7 +61,7 @@ class ThriftValueBase : public ThriftValue, public ThriftBase { public: ThriftValueBase(ThriftBase* parent, FieldType value_type) : ThriftBase(parent), value_type_(value_type) {} - ~ThriftValueBase() {} + ~ThriftValueBase() override = default; // ThriftValue FieldType type() const override { return value_type_; } diff --git a/source/extensions/filters/network/thrift_proxy/tracing.h b/source/extensions/filters/network/thrift_proxy/tracing.h index da0f1d52fc5c..e5f26a51e24a 100644 --- a/source/extensions/filters/network/thrift_proxy/tracing.h +++ b/source/extensions/filters/network/thrift_proxy/tracing.h @@ -17,7 +17,7 @@ class Endpoint { public: Endpoint(int32_t ipv4, int16_t port, const std::string& service_name) : ipv4_(ipv4), port_(port), service_name_(service_name) {} - Endpoint() {} + Endpoint() = default; int32_t ipv4_{0}; int16_t port_{0}; @@ -31,7 +31,7 @@ class Annotation { public: Annotation(int64_t timestamp, const std::string& value, absl::optional host) : timestamp_(timestamp), value_(value), host_(host) {} - Annotation() {} + Annotation() = default; int64_t timestamp_{0}; std::string value_; @@ -60,7 +60,7 @@ class BinaryAnnotation { BinaryAnnotation(const std::string& key, const std::string& value, AnnotationType annotation_type, absl::optional host) : key_(key), value_(value), annotation_type_(annotation_type), host_(host) {} - BinaryAnnotation() {} + BinaryAnnotation() = default; std::string key_; std::string value_; @@ -80,7 +80,7 @@ class Span { : trace_id_(trace_id), name_(name), span_id_(span_id), parent_span_id_(parent_span_id), annotations_(std::move(annotations)), binary_annotations_(std::move(binary_annotations)), debug_(debug) {} - Span() {} + Span() = default; int64_t trace_id_{0}; std::string name_; diff --git a/source/extensions/filters/network/thrift_proxy/twitter_protocol_impl.cc b/source/extensions/filters/network/thrift_proxy/twitter_protocol_impl.cc index 77e6862dac14..37a2961f891e 100644 --- a/source/extensions/filters/network/thrift_proxy/twitter_protocol_impl.cc +++ b/source/extensions/filters/network/thrift_proxy/twitter_protocol_impl.cc @@ -166,7 +166,7 @@ class ClientId { */ class UpgradeReply : public DirectResponse, public ThriftObject { public: - UpgradeReply() {} + UpgradeReply() = default; UpgradeReply(Transport& transport) : thrift_obj_(std::make_unique(transport, protocol_)) {} diff --git a/source/extensions/filters/network/thrift_proxy/unframed_transport_impl.h b/source/extensions/filters/network/thrift_proxy/unframed_transport_impl.h index e3d5556fadf9..5266d1eaad7e 100644 --- a/source/extensions/filters/network/thrift_proxy/unframed_transport_impl.h +++ b/source/extensions/filters/network/thrift_proxy/unframed_transport_impl.h @@ -17,7 +17,7 @@ namespace ThriftProxy { */ class UnframedTransportImpl : public Transport { public: - UnframedTransportImpl() {} + UnframedTransportImpl() = default; // Transport const std::string& name() const override { return TransportNames::get().UNFRAMED; } diff --git a/source/extensions/grpc_credentials/example/config.h b/source/extensions/grpc_credentials/example/config.h index 06f2d2f2b498..f10557a30a55 100644 --- a/source/extensions/grpc_credentials/example/config.h +++ b/source/extensions/grpc_credentials/example/config.h @@ -27,7 +27,7 @@ namespace Example { */ class AccessTokenExampleGrpcCredentialsFactory : public Grpc::GoogleGrpcCredentialsFactory { public: - virtual std::shared_ptr + std::shared_ptr getChannelCredentials(const envoy::api::v2::core::GrpcService& grpc_service_config, Api::Api& api) override; diff --git a/source/extensions/health_checkers/redis/redis.h b/source/extensions/health_checkers/redis/redis.h index 63f9dd0de0d5..346b27e9b951 100644 --- a/source/extensions/health_checkers/redis/redis.h +++ b/source/extensions/health_checkers/redis/redis.h @@ -51,7 +51,7 @@ class RedisHealthChecker : public Upstream::HealthCheckerImplBase { public Extensions::NetworkFilters::Common::Redis::Client::PoolCallbacks, public Network::ConnectionCallbacks { RedisActiveHealthCheckSession(RedisHealthChecker& parent, const Upstream::HostSharedPtr& host); - ~RedisActiveHealthCheckSession(); + ~RedisActiveHealthCheckSession() override; // ActiveHealthCheckSession void onInterval() override; diff --git a/source/extensions/quic_listeners/quiche/BUILD b/source/extensions/quic_listeners/quiche/BUILD index 93b9f31ff664..b4b3369fe9bf 100644 --- a/source/extensions/quic_listeners/quiche/BUILD +++ b/source/extensions/quic_listeners/quiche/BUILD @@ -15,6 +15,7 @@ envoy_cc_library( external_deps = ["quiche_quic_platform"], tags = ["nofips"], deps = [ + "//include/envoy/event:dispatcher_interface", "//include/envoy/event:timer_interface", "@com_googlesource_quiche//:quic_core_alarm_interface_lib", ], diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_alarm.cc b/source/extensions/quic_listeners/quiche/envoy_quic_alarm.cc index 695a525777ce..b490aff8b955 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_alarm.cc +++ b/source/extensions/quic_listeners/quiche/envoy_quic_alarm.cc @@ -3,10 +3,10 @@ namespace Envoy { namespace Quic { -EnvoyQuicAlarm::EnvoyQuicAlarm(Event::Scheduler& scheduler, quic::QuicClock& clock, +EnvoyQuicAlarm::EnvoyQuicAlarm(Event::Dispatcher& dispatcher, const quic::QuicClock& clock, quic::QuicArenaScopedPtr delegate) - : QuicAlarm(std::move(delegate)), scheduler_(scheduler), - timer_(scheduler_.createTimer([this]() { Fire(); })), clock_(clock) {} + : QuicAlarm(std::move(delegate)), dispatcher_(dispatcher), + timer_(dispatcher_.createTimer([this]() { Fire(); })), clock_(clock) {} void EnvoyQuicAlarm::CancelImpl() { timer_->disableTimer(); } diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_alarm.h b/source/extensions/quic_listeners/quiche/envoy_quic_alarm.h index e50b4afc05ce..4152f4c101c3 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_alarm.h +++ b/source/extensions/quic_listeners/quiche/envoy_quic_alarm.h @@ -1,5 +1,6 @@ #pragma once +#include "envoy/event/dispatcher.h" #include "envoy/event/timer.h" #include "common/common/assert.h" @@ -16,7 +17,7 @@ namespace Quic { // wraps an Event::Timer object and provide interface for QUIC to interact with the timer. class EnvoyQuicAlarm : public quic::QuicAlarm { public: - EnvoyQuicAlarm(Event::Scheduler& scheduler, quic::QuicClock& clock, + EnvoyQuicAlarm(Event::Dispatcher& dispatcher, const quic::QuicClock& clock, quic::QuicArenaScopedPtr delegate); ~EnvoyQuicAlarm() override { ASSERT(!IsSet()); }; @@ -30,9 +31,9 @@ class EnvoyQuicAlarm : public quic::QuicAlarm { private: quic::QuicTime::Delta getDurationBeforeDeadline(); - Event::Scheduler& scheduler_; + Event::Dispatcher& dispatcher_; Event::TimerPtr timer_; - quic::QuicClock& clock_; + const quic::QuicClock& clock_; }; } // namespace Quic diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_alarm_factory.cc b/source/extensions/quic_listeners/quiche/envoy_quic_alarm_factory.cc index 5595c9c308e9..cdea1ed16ff6 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_alarm_factory.cc +++ b/source/extensions/quic_listeners/quiche/envoy_quic_alarm_factory.cc @@ -4,7 +4,7 @@ namespace Envoy { namespace Quic { quic::QuicAlarm* EnvoyQuicAlarmFactory::CreateAlarm(quic::QuicAlarm::Delegate* delegate) { - return new EnvoyQuicAlarm(scheduler_, clock_, + return new EnvoyQuicAlarm(dispatcher_, clock_, quic::QuicArenaScopedPtr(delegate)); } @@ -12,10 +12,10 @@ quic::QuicArenaScopedPtr EnvoyQuicAlarmFactory::CreateAlarm(quic::QuicArenaScopedPtr delegate, quic::QuicConnectionArena* arena) { if (arena != nullptr) { - return arena->New(scheduler_, clock_, std::move(delegate)); + return arena->New(dispatcher_, clock_, std::move(delegate)); } return quic::QuicArenaScopedPtr( - new EnvoyQuicAlarm(scheduler_, clock_, std::move(delegate))); + new EnvoyQuicAlarm(dispatcher_, clock_, std::move(delegate))); } } // namespace Quic diff --git a/source/extensions/quic_listeners/quiche/envoy_quic_alarm_factory.h b/source/extensions/quic_listeners/quiche/envoy_quic_alarm_factory.h index f70b953fab71..c373ed42298f 100644 --- a/source/extensions/quic_listeners/quiche/envoy_quic_alarm_factory.h +++ b/source/extensions/quic_listeners/quiche/envoy_quic_alarm_factory.h @@ -19,8 +19,8 @@ namespace Quic { class EnvoyQuicAlarmFactory : public quic::QuicAlarmFactory, NonCopyable { public: - EnvoyQuicAlarmFactory(Event::Scheduler& scheduler, quic::QuicClock& clock) - : scheduler_(scheduler), clock_(clock) {} + EnvoyQuicAlarmFactory(Event::Dispatcher& dispatcher, const quic::QuicClock& clock) + : dispatcher_(dispatcher), clock_(clock) {} ~EnvoyQuicAlarmFactory() override = default; @@ -31,8 +31,8 @@ class EnvoyQuicAlarmFactory : public quic::QuicAlarmFactory, NonCopyable { quic::QuicConnectionArena* arena) override; private: - Event::Scheduler& scheduler_; - quic::QuicClock& clock_; + Event::Dispatcher& dispatcher_; + const quic::QuicClock& clock_; }; } // namespace Quic diff --git a/source/extensions/quic_listeners/quiche/platform/BUILD b/source/extensions/quic_listeners/quiche/platform/BUILD index e30ad336b9e8..08c42a1364a8 100644 --- a/source/extensions/quic_listeners/quiche/platform/BUILD +++ b/source/extensions/quic_listeners/quiche/platform/BUILD @@ -243,7 +243,7 @@ envoy_cc_library( hdrs = ["envoy_quic_clock.h"], visibility = ["//visibility:public"], deps = [ - "//include/envoy/event:timer_interface", + "//include/envoy/event:dispatcher_interface", "@com_googlesource_quiche//:quic_platform", ], ) diff --git a/source/extensions/quic_listeners/quiche/platform/envoy_quic_clock.cc b/source/extensions/quic_listeners/quiche/platform/envoy_quic_clock.cc index b582956751da..b134827cc38d 100644 --- a/source/extensions/quic_listeners/quiche/platform/envoy_quic_clock.cc +++ b/source/extensions/quic_listeners/quiche/platform/envoy_quic_clock.cc @@ -9,13 +9,13 @@ quic::QuicTime EnvoyQuicClock::ApproximateNow() const { } quic::QuicTime EnvoyQuicClock::Now() const { - return quic::QuicTime::Zero() + quic::QuicTime::Delta::FromMicroseconds( - microsecondsSinceEpoch(time_system_.monotonicTime())); + return quic::QuicTime::Zero() + quic::QuicTime::Delta::FromMicroseconds(microsecondsSinceEpoch( + dispatcher_.timeSource().monotonicTime())); } quic::QuicWallTime EnvoyQuicClock::WallNow() const { return quic::QuicWallTime::FromUNIXMicroseconds( - microsecondsSinceEpoch(time_system_.systemTime())); + microsecondsSinceEpoch(dispatcher_.timeSource().systemTime())); } } // namespace Quic diff --git a/source/extensions/quic_listeners/quiche/platform/envoy_quic_clock.h b/source/extensions/quic_listeners/quiche/platform/envoy_quic_clock.h index eb90a1db1b94..5a85ebf932cc 100644 --- a/source/extensions/quic_listeners/quiche/platform/envoy_quic_clock.h +++ b/source/extensions/quic_listeners/quiche/platform/envoy_quic_clock.h @@ -2,7 +2,7 @@ #include -#include "envoy/event/timer.h" +#include "envoy/event/dispatcher.h" #include "quiche/quic/platform/api/quic_clock.h" @@ -11,7 +11,7 @@ namespace Quic { class EnvoyQuicClock : public quic::QuicClock { public: - EnvoyQuicClock(Event::TimeSystem& time_system) : time_system_(time_system) {} + EnvoyQuicClock(Event::Dispatcher& dispatcher) : dispatcher_(dispatcher) {} // quic::QuicClock quic::QuicTime ApproximateNow() const override; @@ -23,7 +23,7 @@ class EnvoyQuicClock : public quic::QuicClock { return std::chrono::duration_cast(time.time_since_epoch()).count(); } - Event::TimeSystem& time_system_; + Event::Dispatcher& dispatcher_; }; } // namespace Quic diff --git a/source/extensions/quic_listeners/quiche/platform/quic_logging_impl.cc b/source/extensions/quic_listeners/quiche/platform/quic_logging_impl.cc index 895f1bbcb8d3..60870a742fdd 100644 --- a/source/extensions/quic_listeners/quiche/platform/quic_logging_impl.cc +++ b/source/extensions/quic_listeners/quiche/platform/quic_logging_impl.cc @@ -28,14 +28,20 @@ QuicLogEmitter::~QuicLogEmitter() { // TODO(wub): Change to a thread-safe version of strerror. stream_ << ": " << strerror(saved_errno_) << " [" << saved_errno_ << "]"; } - GetLogger().log(level_, "{}", stream_.str().c_str()); + std::string content = stream_.str(); + if (!content.empty() && content.back() == '\n') { + // strip the last trailing '\n' because spd log will add a trailing '\n' to + // the output. + content.back() = '\0'; + } + GetLogger().log(level_, "{}", content.c_str()); // Normally there is no log sink and we can avoid acquiring the lock. if (g_quic_log_sink.load(std::memory_order_relaxed) != nullptr) { absl::MutexLock lock(&g_quic_log_sink_mutex); QuicLogSink* sink = g_quic_log_sink.load(std::memory_order_relaxed); if (sink != nullptr) { - sink->Log(level_, stream_.str()); + sink->Log(level_, content); } } diff --git a/source/extensions/quic_listeners/quiche/platform/quic_logging_impl.h b/source/extensions/quic_listeners/quiche/platform/quic_logging_impl.h index 13fa6dc81031..43dfe6661363 100644 --- a/source/extensions/quic_listeners/quiche/platform/quic_logging_impl.h +++ b/source/extensions/quic_listeners/quiche/platform/quic_logging_impl.h @@ -144,7 +144,7 @@ class QuicLogEmitter { std::ostringstream stream_; }; -class NullLogStream { +class NullLogStream : public std::ostream { public: NullLogStream& stream() { return *this; } }; diff --git a/source/extensions/stat_sinks/common/statsd/statsd.h b/source/extensions/stat_sinks/common/statsd/statsd.h index a13cd0a730bc..a6eb91a62750 100644 --- a/source/extensions/stat_sinks/common/statsd/statsd.h +++ b/source/extensions/stat_sinks/common/statsd/statsd.h @@ -30,7 +30,7 @@ class Writer : public ThreadLocal::ThreadLocalObject { Writer(Network::Address::InstanceConstSharedPtr address); // For testing. Writer() : io_handle_(std::make_unique()) {} - virtual ~Writer(); + ~Writer() override; virtual void write(const std::string& message); // Called in unit test to validate address. @@ -98,7 +98,7 @@ class TcpStatsdSink : public Stats::Sink { private: struct TlsSink : public ThreadLocal::ThreadLocalObject, public Network::ConnectionCallbacks { TlsSink(TcpStatsdSink& parent, Event::Dispatcher& dispatcher); - ~TlsSink(); + ~TlsSink() override; void beginFlush(bool expect_empty_buffer); void checkSize(); diff --git a/source/extensions/tracers/common/factory_base.h b/source/extensions/tracers/common/factory_base.h index 67191834c65b..6b57de7b3c35 100644 --- a/source/extensions/tracers/common/factory_base.h +++ b/source/extensions/tracers/common/factory_base.h @@ -15,8 +15,8 @@ namespace Common { template class FactoryBase : public Server::Configuration::TracerFactory { public: // Server::Configuration::TracerFactory - virtual Tracing::HttpTracerPtr createHttpTracer(const Protobuf::Message& config, - Server::Instance& server) override { + Tracing::HttpTracerPtr createHttpTracer(const Protobuf::Message& config, + Server::Instance& server) override { return createHttpTracerTyped(MessageUtil::downcastAndValidate(config), server); } diff --git a/source/extensions/tracers/datadog/datadog_tracer_impl.cc b/source/extensions/tracers/datadog/datadog_tracer_impl.cc index 660c3add42a8..a2117dc4749d 100644 --- a/source/extensions/tracers/datadog/datadog_tracer_impl.cc +++ b/source/extensions/tracers/datadog/datadog_tracer_impl.cc @@ -80,8 +80,8 @@ void TraceReporter::enableTimer() { void TraceReporter::flushTraces() { auto pendingTraces = encoder_->pendingTraces(); - ENVOY_LOG(debug, "flushing traces: {} traces", pendingTraces); if (pendingTraces) { + ENVOY_LOG(debug, "flushing traces: {} traces", pendingTraces); driver_.tracerStats().traces_sent_.add(pendingTraces); Http::MessagePtr message(new Http::RequestMessageImpl()); @@ -95,7 +95,7 @@ void TraceReporter::flushTraces() { Buffer::InstancePtr body(new Buffer::OwnedImpl()); body->add(encoder_->payload()); message->body() = std::move(body); - ENVOY_LOG(debug, "submitting {} trace(s) to {} with payload {}", pendingTraces, + ENVOY_LOG(debug, "submitting {} trace(s) to {} with payload size {}", pendingTraces, encoder_->path(), encoder_->payload().size()); driver_.clusterManager() diff --git a/source/extensions/tracers/lightstep/lightstep_tracer_impl.h b/source/extensions/tracers/lightstep/lightstep_tracer_impl.h index d6046ccd4e40..6988ce504bcc 100644 --- a/source/extensions/tracers/lightstep/lightstep_tracer_impl.h +++ b/source/extensions/tracers/lightstep/lightstep_tracer_impl.h @@ -74,7 +74,7 @@ class LightStepDriver : public Common::Ot::OpenTracingDriver { public: explicit LightStepTransporter(LightStepDriver& driver); - ~LightStepTransporter(); + ~LightStepTransporter() override; // lightstep::AsyncTransporter void Send(const Protobuf::Message& request, Protobuf::Message& response, diff --git a/source/extensions/tracers/opencensus/config.cc b/source/extensions/tracers/opencensus/config.cc index 038c329aff18..ec0e766e532d 100644 --- a/source/extensions/tracers/opencensus/config.cc +++ b/source/extensions/tracers/opencensus/config.cc @@ -16,7 +16,7 @@ OpenCensusTracerFactory::OpenCensusTracerFactory() : FactoryBase(TracerNames::ge Tracing::HttpTracerPtr OpenCensusTracerFactory::createHttpTracerTyped( const envoy::config::trace::v2::OpenCensusConfig& proto_config, Server::Instance& server) { - Tracing::DriverPtr driver = std::make_unique(proto_config); + Tracing::DriverPtr driver = std::make_unique(proto_config, server.localInfo()); return std::make_unique(std::move(driver), server.localInfo()); } diff --git a/source/extensions/tracers/opencensus/opencensus_tracer_impl.cc b/source/extensions/tracers/opencensus/opencensus_tracer_impl.cc index 6a93dbbffd90..154e5903fe83 100644 --- a/source/extensions/tracers/opencensus/opencensus_tracer_impl.cc +++ b/source/extensions/tracers/opencensus/opencensus_tracer_impl.cc @@ -135,9 +135,7 @@ Span::Span(const envoy::config::trace::v2::OpenCensusConfig& oc_config, ::opencensus::trace::Span&& span) : span_(std::move(span)), oc_config_(oc_config) {} -void Span::setOperation(absl::string_view operation) { - span_.AddAnnotation("setOperation", {{"operation", operation}}); -} +void Span::setOperation(absl::string_view operation) { span_.SetName(operation); } void Span::setTag(absl::string_view name, absl::string_view value) { span_.AddAttribute(name, value); @@ -187,8 +185,9 @@ void Span::setSampled(bool sampled) { span_.AddAnnotation("setSampled", {{"sampl } // namespace -Driver::Driver(const envoy::config::trace::v2::OpenCensusConfig& oc_config) - : oc_config_(oc_config) { +Driver::Driver(const envoy::config::trace::v2::OpenCensusConfig& oc_config, + const LocalInfo::LocalInfo& localinfo) + : oc_config_(oc_config), local_info_(localinfo) { if (oc_config.has_trace_config()) { applyTraceConfig(oc_config.trace_config()); } @@ -202,7 +201,7 @@ Driver::Driver(const envoy::config::trace::v2::OpenCensusConfig& oc_config) } if (oc_config.zipkin_exporter_enabled()) { ::opencensus::exporters::trace::ZipkinExporterOptions opts(oc_config.zipkin_url()); - opts.service_name = oc_config.zipkin_service_name(); + opts.service_name = local_info_.clusterName(); ::opencensus::exporters::trace::ZipkinExporter::Register(opts); } } diff --git a/source/extensions/tracers/opencensus/opencensus_tracer_impl.h b/source/extensions/tracers/opencensus/opencensus_tracer_impl.h index cb5990bd763a..1b334e928172 100644 --- a/source/extensions/tracers/opencensus/opencensus_tracer_impl.h +++ b/source/extensions/tracers/opencensus/opencensus_tracer_impl.h @@ -1,6 +1,7 @@ #pragma once #include "envoy/config/trace/v2/trace.pb.validate.h" +#include "envoy/local_info/local_info.h" #include "envoy/tracing/http_tracer.h" #include "common/common/logger.h" @@ -15,7 +16,8 @@ namespace OpenCensus { */ class Driver : public Tracing::Driver, Logger::Loggable { public: - Driver(const envoy::config::trace::v2::OpenCensusConfig& oc_config); + Driver(const envoy::config::trace::v2::OpenCensusConfig& oc_config, + const LocalInfo::LocalInfo& localinfo); /** * Implements the abstract Driver's startSpan operation. @@ -28,6 +30,7 @@ class Driver : public Tracing::Driver, Logger::Loggable { void applyTraceConfig(const opencensus::proto::trace::v1::TraceConfig& config); const envoy::config::trace::v2::OpenCensusConfig oc_config_; + const LocalInfo::LocalInfo& local_info_; }; } // namespace OpenCensus diff --git a/source/extensions/tracers/zipkin/span_buffer.h b/source/extensions/tracers/zipkin/span_buffer.h index 2e9f6b90a69f..a67479c644a4 100644 --- a/source/extensions/tracers/zipkin/span_buffer.h +++ b/source/extensions/tracers/zipkin/span_buffer.h @@ -17,7 +17,7 @@ class SpanBuffer { * Constructor that creates an empty buffer. Space needs to be allocated by invoking * the method allocateBuffer(size). */ - SpanBuffer() {} + SpanBuffer() = default; /** * Constructor that initializes a buffer with the given size. diff --git a/source/extensions/tracers/zipkin/span_context.h b/source/extensions/tracers/zipkin/span_context.h index 78eaa5b5d1c3..6dd08c3b291b 100644 --- a/source/extensions/tracers/zipkin/span_context.h +++ b/source/extensions/tracers/zipkin/span_context.h @@ -20,7 +20,7 @@ class SpanContext { /** * Default constructor. Creates an empty context. */ - SpanContext() : trace_id_high_(0), trace_id_(0), id_(0), parent_id_(0), sampled_(false) {} + SpanContext() = default; /** * Constructor that creates a context object from the supplied trace, span and @@ -75,11 +75,11 @@ class SpanContext { bool sampled() const { return sampled_; } private: - const uint64_t trace_id_high_; - const uint64_t trace_id_; - const uint64_t id_; - const uint64_t parent_id_; - const bool sampled_; + const uint64_t trace_id_high_{0}; + const uint64_t trace_id_{0}; + const uint64_t id_{0}; + const uint64_t parent_id_{0}; + const bool sampled_{false}; }; } // namespace Zipkin diff --git a/source/extensions/tracers/zipkin/span_context_extractor.cc b/source/extensions/tracers/zipkin/span_context_extractor.cc index 50a057ae45af..747efc999525 100644 --- a/source/extensions/tracers/zipkin/span_context_extractor.cc +++ b/source/extensions/tracers/zipkin/span_context_extractor.cc @@ -32,7 +32,7 @@ bool getSamplingFlags(char c, const Tracing::Decision tracing_decision) { SpanContextExtractor::SpanContextExtractor(Http::HeaderMap& request_headers) : request_headers_(request_headers) {} -SpanContextExtractor::~SpanContextExtractor() {} +SpanContextExtractor::~SpanContextExtractor() = default; bool SpanContextExtractor::extractSampled(const Tracing::Decision tracing_decision) { bool sampled(false); diff --git a/source/extensions/tracers/zipkin/zipkin_core_types.h b/source/extensions/tracers/zipkin/zipkin_core_types.h index d9b5f10fc2d8..8c9ff909241f 100644 --- a/source/extensions/tracers/zipkin/zipkin_core_types.h +++ b/source/extensions/tracers/zipkin/zipkin_core_types.h @@ -118,7 +118,7 @@ class Annotation : public ZipkinBase { /** * Default constructor. Creates an empty annotation. */ - Annotation() : timestamp_(0) {} + Annotation() = default; /** * Constructor that creates an annotation based on the given parameters. @@ -187,7 +187,7 @@ class Annotation : public ZipkinBase { const std::string toJson() override; private: - uint64_t timestamp_; + uint64_t timestamp_{0}; std::string value_; absl::optional endpoint_; }; diff --git a/source/extensions/transport_sockets/alts/config.cc b/source/extensions/transport_sockets/alts/config.cc index 1549a2a33d77..a85bb9d7fa85 100644 --- a/source/extensions/transport_sockets/alts/config.cc +++ b/source/extensions/transport_sockets/alts/config.cc @@ -64,7 +64,7 @@ class AltsSharedState : public Singleton::Instance { public: AltsSharedState() { grpc_alts_shared_resource_dedicated_init(); } - ~AltsSharedState() { grpc_alts_shared_resource_dedicated_shutdown(); } + ~AltsSharedState() override { grpc_alts_shared_resource_dedicated_shutdown(); } }; SINGLETON_MANAGER_REGISTRATION(alts_shared_state); diff --git a/source/extensions/transport_sockets/alts/tsi_handshaker.h b/source/extensions/transport_sockets/alts/tsi_handshaker.h index d578493573ec..71cd6989e71a 100644 --- a/source/extensions/transport_sockets/alts/tsi_handshaker.h +++ b/source/extensions/transport_sockets/alts/tsi_handshaker.h @@ -51,7 +51,7 @@ class TsiHandshakerCallbacks { class TsiHandshaker final : public Event::DeferredDeletable { public: explicit TsiHandshaker(CHandshakerPtr&& handshaker, Event::Dispatcher& dispatcher); - ~TsiHandshaker(); + ~TsiHandshaker() override; /** * Conduct next step of handshake, see diff --git a/source/extensions/transport_sockets/alts/tsi_socket.h b/source/extensions/transport_sockets/alts/tsi_socket.h index 31b4571db096..bbd7b19fadcb 100644 --- a/source/extensions/transport_sockets/alts/tsi_socket.h +++ b/source/extensions/transport_sockets/alts/tsi_socket.h @@ -51,7 +51,7 @@ class TsiSocket : public Network::TransportSocket, * The connection will be closed immediately if it returns false. */ TsiSocket(HandshakerFactory handshaker_factory, HandshakeValidator handshake_validator); - virtual ~TsiSocket(); + ~TsiSocket() override; // Network::TransportSocket void setTransportSocketCallbacks(Envoy::Network::TransportSocketCallbacks& callbacks) override; diff --git a/source/extensions/transport_sockets/tls/BUILD b/source/extensions/transport_sockets/tls/BUILD index 4f07d1e5dea0..2d9526cfcd7b 100644 --- a/source/extensions/transport_sockets/tls/BUILD +++ b/source/extensions/transport_sockets/tls/BUILD @@ -62,7 +62,6 @@ envoy_cc_library( "//source/common/common:assert_lib", "//source/common/common:empty_string", "//source/common/config:datasource_lib", - "//source/common/config:tls_context_json_lib", "//source/common/json:json_loader_lib", "//source/common/protobuf:utility_lib", "//source/common/secret:sds_api_lib", @@ -97,6 +96,7 @@ envoy_cc_library( "//source/common/common:base64_lib", "//source/common/common:hex_lib", "//source/common/common:utility_lib", + "//source/common/network:address_lib", "//source/common/protobuf:utility_lib", "@envoy_api//envoy/admin/v2alpha:certs_cc", ], diff --git a/source/extensions/transport_sockets/tls/context_config_impl.cc b/source/extensions/transport_sockets/tls/context_config_impl.cc index 3b8f32d27a0e..424e08ae2d59 100644 --- a/source/extensions/transport_sockets/tls/context_config_impl.cc +++ b/source/extensions/transport_sockets/tls/context_config_impl.cc @@ -6,7 +6,6 @@ #include "common/common/assert.h" #include "common/common/empty_string.h" #include "common/config/datasource.h" -#include "common/config/tls_context_json.h" #include "common/protobuf/utility.h" #include "common/secret/sds_api.h" #include "common/ssl/certificate_validation_context_config_impl.h" @@ -288,17 +287,6 @@ ClientContextConfigImpl::ClientContextConfigImpl( } } -ClientContextConfigImpl::ClientContextConfigImpl( - const Json::Object& config, - Server::Configuration::TransportSocketFactoryContext& factory_context) - : ClientContextConfigImpl( - [&config] { - envoy::api::v2::auth::UpstreamTlsContext upstream_tls_context; - Config::TlsContextJson::translateUpstreamTlsContext(config, upstream_tls_context); - return upstream_tls_context; - }(), - factory_context) {} - const unsigned ServerContextConfigImpl::DEFAULT_MIN_VERSION = TLS1_VERSION; const unsigned ServerContextConfigImpl::DEFAULT_MAX_VERSION = #ifndef BORINGSSL_FIPS diff --git a/source/extensions/transport_sockets/tls/context_config_impl.h b/source/extensions/transport_sockets/tls/context_config_impl.h index e1b0024ce906..fa48b9815f08 100644 --- a/source/extensions/transport_sockets/tls/context_config_impl.h +++ b/source/extensions/transport_sockets/tls/context_config_impl.h @@ -103,9 +103,6 @@ class ClientContextConfigImpl : public ContextConfigImpl, public Envoy::Ssl::Cli const envoy::api::v2::auth::UpstreamTlsContext& config, Server::Configuration::TransportSocketFactoryContext& secret_provider_context) : ClientContextConfigImpl(config, "", secret_provider_context) {} - ClientContextConfigImpl( - const Json::Object& config, - Server::Configuration::TransportSocketFactoryContext& secret_provider_context); // Ssl::ClientContextConfig const std::string& serverNameIndication() const override { return server_name_indication_; } diff --git a/source/extensions/transport_sockets/tls/context_impl.cc b/source/extensions/transport_sockets/tls/context_impl.cc index 7ef9bd33051c..03d247c489cc 100644 --- a/source/extensions/transport_sockets/tls/context_impl.cc +++ b/source/extensions/transport_sockets/tls/context_impl.cc @@ -1,5 +1,7 @@ #include "extensions/transport_sockets/tls/context_impl.h" +#include + #include #include #include @@ -13,6 +15,7 @@ #include "common/common/fmt.h" #include "common/common/hex.h" #include "common/common/utility.h" +#include "common/network/address_impl.h" #include "common/protobuf/utility.h" #include "extensions/transport_sockets/tls/utility.h" @@ -491,7 +494,8 @@ bool ContextImpl::verifySubjectAltName(X509* cert, return false; } for (const GENERAL_NAME* san : san_names.get()) { - if (san->type == GEN_DNS) { + switch (san->type) { + case GEN_DNS: { ASN1_STRING* str = san->d.dNSName; const char* dns_name = reinterpret_cast(ASN1_STRING_data(str)); for (auto& config_san : subject_alt_names) { @@ -499,7 +503,9 @@ bool ContextImpl::verifySubjectAltName(X509* cert, return true; } } - } else if (san->type == GEN_URI) { + break; + } + case GEN_URI: { ASN1_STRING* str = san->d.uniformResourceIdentifier; const char* uri = reinterpret_cast(ASN1_STRING_data(str)); for (auto& config_san : subject_alt_names) { @@ -507,6 +513,34 @@ bool ContextImpl::verifySubjectAltName(X509* cert, return true; } } + break; + } + case GEN_IPADD: { + if (san->d.ip->length == 4) { + sockaddr_in sin; + sin.sin_port = 0; + sin.sin_family = AF_INET; + memcpy(&sin.sin_addr, san->d.ip->data, sizeof(sin.sin_addr)); + Network::Address::Ipv4Instance addr(&sin); + for (auto& config_san : subject_alt_names) { + if (config_san == addr.ip()->addressAsString()) { + return true; + } + } + } else if (san->d.ip->length == 16) { + sockaddr_in6 sin6; + sin6.sin6_port = 0; + sin6.sin6_family = AF_INET6; + memcpy(&sin6.sin6_addr, san->d.ip->data, sizeof(sin6.sin6_addr)); + Network::Address::Ipv6Instance addr(sin6); + for (auto& config_san : subject_alt_names) { + if (config_san == addr.ip()->addressAsString()) { + return true; + } + } + } + break; + } } } return false; diff --git a/source/extensions/transport_sockets/tls/context_manager_impl.h b/source/extensions/transport_sockets/tls/context_manager_impl.h index 2bb82342940c..88ef9e67d546 100644 --- a/source/extensions/transport_sockets/tls/context_manager_impl.h +++ b/source/extensions/transport_sockets/tls/context_manager_impl.h @@ -22,7 +22,7 @@ namespace Tls { class ContextManagerImpl final : public Envoy::Ssl::ContextManager { public: ContextManagerImpl(TimeSource& time_source) : time_source_(time_source) {} - ~ContextManagerImpl(); + ~ContextManagerImpl() override; // Ssl::ContextManager Ssl::ClientContextSharedPtr diff --git a/source/server/BUILD b/source/server/BUILD index 9eb61a7fca69..2e83ab4671c6 100644 --- a/source/server/BUILD +++ b/source/server/BUILD @@ -41,6 +41,7 @@ envoy_cc_library( "//source/common/config:runtime_utility_lib", "//source/common/config:utility_lib", "//source/common/network:resolver_lib", + "//source/common/network:socket_option_factory_lib", "//source/common/network:utility_lib", "//source/common/protobuf:utility_lib", "//source/common/tracing:http_tracer_lib", @@ -167,7 +168,7 @@ envoy_cc_library( "//include/envoy/server:options_interface", "//source/common/api:os_sys_calls_lib", "//source/common/common:assert_lib", - "//source/common/stats:heap_stat_data_lib", + "//source/common/stats:allocator_lib", ], ) @@ -176,7 +177,7 @@ envoy_cc_library( hdrs = ["hot_restart_nop_impl.h"], deps = [ "//include/envoy/server:hot_restart_interface", - "//source/common/stats:heap_stat_data_lib", + "//source/common/stats:allocator_lib", ], ) @@ -186,6 +187,7 @@ envoy_cc_library( "//bazel:linux_x86_64": ["options_impl_platform_linux.cc"], "//bazel:linux_aarch64": ["options_impl_platform_linux.cc"], "//bazel:linux_ppc": ["options_impl_platform_linux.cc"], + "//bazel:linux_mips64": ["options_impl_platform_linux.cc"], "//conditions:default": ["options_impl_platform_default.cc"], }), hdrs = [ @@ -195,6 +197,7 @@ envoy_cc_library( "//bazel:linux_x86_64": ["options_impl_platform_linux.h"], "//bazel:linux_aarch64": ["options_impl_platform_linux.h"], "//bazel:linux_ppc": ["options_impl_platform_linux.h"], + "//bazel:linux_mips64": ["options_impl_platform_linux.h"], "//conditions:default": [], }), # TCLAP command line parser needs this to support int64_t/uint64_t in several build environments. @@ -210,6 +213,7 @@ envoy_cc_library( "//source/common/common:version_lib", "//source/common/protobuf:utility_lib", "//source/common/stats:stats_lib", + "@envoy_api//envoy/config/bootstrap/v2:bootstrap_cc", ], ) diff --git a/source/server/config_validation/admin.cc b/source/server/config_validation/admin.cc index 8535122d2eca..365309c17427 100644 --- a/source/server/config_validation/admin.cc +++ b/source/server/config_validation/admin.cc @@ -15,6 +15,7 @@ ConfigTracker& ValidationAdmin::getConfigTracker() { return config_tracker_; } void ValidationAdmin::startHttpListener(const std::string&, const std::string&, Network::Address::InstanceConstSharedPtr, + const Network::Socket::OptionsSharedPtr&, Stats::ScopePtr&&) { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } diff --git a/source/server/config_validation/admin.h b/source/server/config_validation/admin.h index 44863e2dfff3..8ff101dce813 100644 --- a/source/server/config_validation/admin.h +++ b/source/server/config_validation/admin.h @@ -22,6 +22,7 @@ class ValidationAdmin : public Admin { ConfigTracker& getConfigTracker() override; void startHttpListener(const std::string& access_log_path, const std::string& address_out_path, Network::Address::InstanceConstSharedPtr address, + const Network::Socket::OptionsSharedPtr&, Stats::ScopePtr&& listener_scope) override; Http::Code request(absl::string_view path_and_query, absl::string_view method, Http::HeaderMap& response_headers, std::string& body) override; diff --git a/source/server/config_validation/connection.h b/source/server/config_validation/connection.h index 7c6d5b6db062..6fb9839ff890 100644 --- a/source/server/config_validation/connection.h +++ b/source/server/config_validation/connection.h @@ -24,7 +24,7 @@ class ConfigValidateConnection : public Network::ClientConnectionImpl { // Unit tests may instantiate it without proper event machine and leave opened sockets. // Do some cleanup before invoking base class's destructor. - virtual ~ConfigValidateConnection() { close(ConnectionCloseType::NoFlush); } + ~ConfigValidateConnection() override { close(ConnectionCloseType::NoFlush); } // connect may be called in config verification mode. // It is redefined as no-op. Calling parent's method triggers connection to upstream host. diff --git a/source/server/config_validation/server.cc b/source/server/config_validation/server.cc index 3b225808daff..9e32616d7124 100644 --- a/source/server/config_validation/server.cc +++ b/source/server/config_validation/server.cc @@ -92,7 +92,7 @@ void ValidationInstance::initialize(const Options& options, listener_manager_ = std::make_unique(*this, *this, *this, false); thread_local_.registerThread(*dispatcher_, true); runtime_loader_ = component_factory.createRuntime(*this, initial_config); - secret_manager_ = std::make_unique(); + secret_manager_ = std::make_unique(admin().getConfigTracker()); ssl_context_manager_ = createContextManager(Ssl::ContextManagerFactory::name(), api_->timeSource()); cluster_manager_factory_ = std::make_unique( diff --git a/source/server/configuration_impl.cc b/source/server/configuration_impl.cc index 6f53db07d801..20c87a41e039 100644 --- a/source/server/configuration_impl.cc +++ b/source/server/configuration_impl.cc @@ -17,6 +17,7 @@ #include "common/common/utility.h" #include "common/config/runtime_utility.h" #include "common/config/utility.h" +#include "common/network/socket_option_factory.h" #include "common/protobuf/utility.h" #include "common/runtime/runtime_impl.h" #include "common/tracing/http_tracer_impl.h" @@ -133,6 +134,12 @@ InitialImpl::InitialImpl(const envoy::config::bootstrap::v2::Bootstrap& bootstra if (admin.has_address()) { admin_.address_ = Network::Address::resolveProtoAddress(admin.address()); } + admin_.socket_options_ = std::make_shared>(); + if (!admin.socket_options().empty()) { + Network::Socket::appendOptions( + admin_.socket_options_, + Network::SocketOptionFactory::buildLiteralOptions(admin.socket_options())); + } if (!bootstrap.flags_path().empty()) { flags_path_ = bootstrap.flags_path(); diff --git a/source/server/configuration_impl.h b/source/server/configuration_impl.h index 772c3c332546..4aa4852eb0ca 100644 --- a/source/server/configuration_impl.h +++ b/source/server/configuration_impl.h @@ -159,10 +159,12 @@ class InitialImpl : public Initial { const std::string& accessLogPath() override { return access_log_path_; } const std::string& profilePath() override { return profile_path_; } Network::Address::InstanceConstSharedPtr address() override { return address_; } + Network::Socket::OptionsSharedPtr socketOptions() override { return socket_options_; } std::string access_log_path_; std::string profile_path_; Network::Address::InstanceConstSharedPtr address_; + Network::Socket::OptionsSharedPtr socket_options_; }; AdminImpl admin_; diff --git a/source/server/hot_restart_impl.h b/source/server/hot_restart_impl.h index 0244c20f6927..b8cb4c636e22 100644 --- a/source/server/hot_restart_impl.h +++ b/source/server/hot_restart_impl.h @@ -12,7 +12,7 @@ #include "envoy/server/hot_restart.h" #include "common/common/assert.h" -#include "common/stats/heap_stat_data.h" +#include "common/stats/allocator_impl.h" #include "server/hot_restarting_child.h" #include "server/hot_restarting_parent.h" diff --git a/source/server/hot_restart_nop_impl.h b/source/server/hot_restart_nop_impl.h index dc4e0662270d..205097649b81 100644 --- a/source/server/hot_restart_nop_impl.h +++ b/source/server/hot_restart_nop_impl.h @@ -5,7 +5,7 @@ #include "envoy/server/hot_restart.h" #include "common/common/thread.h" -#include "common/stats/heap_stat_data.h" +#include "common/stats/allocator_impl.h" namespace Envoy { namespace Server { diff --git a/source/server/http/admin.cc b/source/server/http/admin.cc index 6537b978123b..b7e8a22cebbb 100644 --- a/source/server/http/admin.cc +++ b/source/server/http/admin.cc @@ -1167,13 +1167,14 @@ AdminImpl::NullRouteConfigProvider::NullRouteConfigProvider(TimeSource& time_sou void AdminImpl::startHttpListener(const std::string& access_log_path, const std::string& address_out_path, Network::Address::InstanceConstSharedPtr address, + const Network::Socket::OptionsSharedPtr& socket_options, Stats::ScopePtr&& listener_scope) { // TODO(mattklein123): Allow admin to use normal access logger extension loading and avoid the // hard dependency here. access_logs_.emplace_back(new Extensions::AccessLoggers::File::FileAccessLog( access_log_path, {}, AccessLog::AccessLogFormatUtils::defaultAccessLogFormatter(), server_.accessLogManager())); - socket_ = std::make_unique(address, nullptr, true); + socket_ = std::make_unique(address, socket_options, true); listener_ = std::make_unique(*this, std::move(listener_scope)); if (!address_out_path.empty()) { std::ofstream address_out_file(address_out_path); diff --git a/source/server/http/admin.h b/source/server/http/admin.h index 6fc5d3a6e254..ac0f6af807bb 100644 --- a/source/server/http/admin.h +++ b/source/server/http/admin.h @@ -76,6 +76,7 @@ class AdminImpl : public Admin, void startHttpListener(const std::string& access_log_path, const std::string& address_out_path, Network::Address::InstanceConstSharedPtr address, + const Network::Socket::OptionsSharedPtr& socket_options, Stats::ScopePtr&& listener_scope) override; // Network::FilterChainManager @@ -326,7 +327,9 @@ class AdminImpl : public Admin, class AdminFilterChain : public Network::FilterChain { public: - AdminFilterChain() {} + // We can't use the default constructor because transport_socket_factory_ doesn't have a + // default constructor. + AdminFilterChain() {} // NOLINT(modernize-use-equals-default) // Network::FilterChain const Network::TransportSocketFactory& transportSocketFactory() const override { diff --git a/source/server/http/config_tracker_impl.h b/source/server/http/config_tracker_impl.h index 0bcb840b7478..3c8ab1c156bf 100644 --- a/source/server/http/config_tracker_impl.h +++ b/source/server/http/config_tracker_impl.h @@ -22,7 +22,7 @@ class ConfigTrackerImpl : public ConfigTracker { class EntryOwnerImpl : public ConfigTracker::EntryOwner { public: EntryOwnerImpl(const std::shared_ptr& map, const std::string& key); - ~EntryOwnerImpl(); + ~EntryOwnerImpl() override; private: std::shared_ptr map_; diff --git a/source/server/listener_manager_impl.h b/source/server/listener_manager_impl.h index f302ff7391db..43edef1e2f3e 100644 --- a/source/server/listener_manager_impl.h +++ b/source/server/listener_manager_impl.h @@ -226,7 +226,7 @@ class ListenerImpl : public Network::ListenerConfig, ListenerImpl(const envoy::api::v2::Listener& config, const std::string& version_info, ListenerManagerImpl& parent, const std::string& name, bool modifiable, bool workers_started, uint64_t hash); - ~ListenerImpl(); + ~ListenerImpl() override; /** * Helper functions to determine whether a listener is blocked for update or remove. @@ -305,14 +305,6 @@ class ListenerImpl : public Network::ListenerConfig, std::make_shared>(); } } - void addListenSocketOption(const Network::Socket::OptionConstSharedPtr& option) override { - ensureSocketOptions(); - listen_socket_options_->emplace_back(std::move(option)); - } - void addListenSocketOptions(const Network::Socket::OptionsSharedPtr& options) override { - ensureSocketOptions(); - Network::Socket::appendOptions(listen_socket_options_, options); - } const Network::ListenerConfig& listenerConfig() const override { return *this; } ProtobufMessage::ValidationVisitor& messageValidationVisitor() override { return parent_.server_.messageValidationVisitor(); @@ -336,6 +328,15 @@ class ListenerImpl : public Network::ListenerConfig, SystemTime last_updated_; private: + void addListenSocketOption(const Network::Socket::OptionConstSharedPtr& option) { + ensureSocketOptions(); + listen_socket_options_->emplace_back(std::move(option)); + } + void addListenSocketOptions(const Network::Socket::OptionsSharedPtr& options) { + ensureSocketOptions(); + Network::Socket::appendOptions(listen_socket_options_, options); + } + ListenerManagerImpl& parent_; Network::Address::InstanceConstSharedPtr address_; FilterChainManagerImpl filter_chain_manager_; diff --git a/source/server/options_impl.h b/source/server/options_impl.h index cddf660f79f4..e9663953aa99 100644 --- a/source/server/options_impl.h +++ b/source/server/options_impl.h @@ -5,6 +5,7 @@ #include #include "envoy/common/exception.h" +#include "envoy/config/bootstrap/v2/bootstrap.pb.h" #include "envoy/server/options.h" #include "common/common/logger.h" @@ -40,6 +41,9 @@ class OptionsImpl : public Server::Options, protected Logger::Loggable= threshold_; } + bool isFired() const override { return value_.has_value() && value_ >= threshold_; } private: const double threshold_; diff --git a/source/server/server.cc b/source/server/server.cc index 072a7612ec2b..b948a32c1384 100644 --- a/source/server/server.cc +++ b/source/server/server.cc @@ -1,8 +1,7 @@ #include "server/server.h" -#include - #include +#include #include #include #include @@ -57,10 +56,10 @@ InstanceImpl::InstanceImpl(const Options& options, Event::TimeSystem& time_syste ThreadLocal::Instance& tls, Thread::ThreadFactory& thread_factory, Filesystem::Instance& file_system, std::unique_ptr process_context) - : secret_manager_(std::make_unique()), shutdown_(false), - options_(options), time_source_(time_system), restarter_(restarter), - start_time_(time(nullptr)), original_start_time_(start_time_), stats_store_(store), - thread_local_(tls), api_(new Api::Impl(thread_factory, store, time_system, file_system)), + : workers_started_(false), shutdown_(false), options_(options), time_source_(time_system), + restarter_(restarter), start_time_(time(nullptr)), original_start_time_(start_time_), + stats_store_(store), thread_local_(tls), + api_(new Api::Impl(thread_factory, store, time_system, file_system)), dispatcher_(api_->allocateDispatcher()), singleton_manager_(new Singleton::ManagerImpl(api_->threadFactory())), handler_(new ConnectionHandlerImpl(ENVOY_LOGGER(), *dispatcher_)), @@ -211,12 +210,12 @@ InstanceUtil::BootstrapVersion InstanceUtil::loadBootstrapConfig( ProtobufMessage::ValidationVisitor& validation_visitor, Api::Api& api) { const std::string& config_path = options.configPath(); const std::string& config_yaml = options.configYaml(); + const envoy::config::bootstrap::v2::Bootstrap& config_proto = options.configProto(); // Exactly one of config_path and config_yaml should be specified. - if (config_path.empty() && config_yaml.empty()) { - const std::string message = - "At least one of --config-path and --config-yaml should be non-empty"; - throw EnvoyException(message); + if (config_path.empty() && config_yaml.empty() && config_proto.ByteSize() == 0) { + throw EnvoyException("At least one of --config-path or --config-yaml or Options::configProto() " + "should be non-empty"); } if (!config_path.empty()) { @@ -227,6 +226,9 @@ InstanceUtil::BootstrapVersion InstanceUtil::loadBootstrapConfig( MessageUtil::loadFromYaml(config_yaml, bootstrap_override, validation_visitor); bootstrap.MergeFrom(bootstrap_override); } + if (config_proto.ByteSize() != 0) { + bootstrap.MergeFrom(config_proto); + } MessageUtil::validate(bootstrap); return BootstrapVersion::V2; } @@ -322,6 +324,7 @@ void InstanceImpl::initialize(const Options& options, ENVOY_LOG(info, "admin address: {}", initial_config.admin().address()->asString()); admin_->startHttpListener(initial_config.admin().accessLogPath(), options.adminAddressPath(), initial_config.admin().address(), + initial_config.admin().socketOptions(), stats_store_.createScope("listener.admin.")); } else { ENVOY_LOG(warn, "No admin address given, so no admin HTTP server started."); @@ -334,6 +337,8 @@ void InstanceImpl::initialize(const Options& options, loadServerFlags(initial_config.flagsPath()); + secret_manager_ = std::make_unique(admin_->getConfigTracker()); + // Initialize the overload manager early so other modules can register for actions. overload_manager_ = std::make_unique( *dispatcher_, stats_store_, thread_local_, bootstrap_.overload_manager(), @@ -421,6 +426,7 @@ void InstanceImpl::initialize(const Options& options, void InstanceImpl::startWorkers() { listener_manager_->startWorkers(*guard_dog_); initialization_timer_->complete(); + workers_started_ = true; // At this point we are ready to take traffic and all listening ports are up. Notify our parent // if applicable that they can stop listening and drain. restarter_.drainParentListeners(); @@ -509,8 +515,9 @@ RunHelper::RunHelper(Instance& instance, const Options& options, Event::Dispatch void InstanceImpl::run() { // RunHelper exists primarily to facilitate testing of how we respond to early shutdown during // startup (see RunHelperTest in server_test.cc). - auto run_helper = RunHelper(*this, options_, *dispatcher_, clusterManager(), access_log_manager_, - init_manager_, overloadManager(), [this] { startWorkers(); }); + const auto run_helper = + RunHelper(*this, options_, *dispatcher_, clusterManager(), access_log_manager_, init_manager_, + overloadManager(), [this] { startWorkers(); }); // Run the main dispatch loop waiting to exit. ENVOY_LOG(info, "starting main dispatch loop"); @@ -597,7 +604,7 @@ InstanceImpl::registerCallback(Stage stage, StageCallbackWithCompletion callback void InstanceImpl::notifyCallbacksForStage(Stage stage, Event::PostCb completion_cb) { ASSERT(std::this_thread::get_id() == main_thread_id_); - auto it = stage_callbacks_.find(stage); + const auto it = stage_callbacks_.find(stage); if (it != stage_callbacks_.end()) { for (const StageCallback& callback : it->second) { callback(); @@ -613,11 +620,17 @@ void InstanceImpl::notifyCallbacksForStage(Stage stage, Event::PostCb completion delete cb; }); - auto it2 = stage_completable_callbacks_.find(stage); - if (it2 != stage_completable_callbacks_.end()) { - ENVOY_LOG(info, "Notifying {} callback(s) with completion.", it2->second.size()); - for (const StageCallbackWithCompletion& callback : it2->second) { - callback([cb_guard] { (*cb_guard)(); }); + // Registrations which take a completion callback are typically implemented by executing a + // callback on all worker threads using Slot::runOnAllThreads which will hang indefinitely if + // worker threads have not been started so we need to skip notifications if envoy is shutdown + // early before workers have started. + if (workers_started_) { + const auto it2 = stage_completable_callbacks_.find(stage); + if (it2 != stage_completable_callbacks_.end()) { + ENVOY_LOG(info, "Notifying {} callback(s) with completion.", it2->second.size()); + for (const StageCallbackWithCompletion& callback : it2->second) { + callback([cb_guard] { (*cb_guard)(); }); + } } } } diff --git a/source/server/server.h b/source/server/server.h index fba73e1b2e58..90128e9b2deb 100644 --- a/source/server/server.h +++ b/source/server/server.h @@ -233,6 +233,7 @@ class InstanceImpl : Logger::Loggable, // - There may be active clusters referencing it in config_.cluster_manager_. // - There may be active connections referencing it. std::unique_ptr secret_manager_; + bool workers_started_; bool shutdown_; const Options& options_; TimeSource& time_source_; diff --git a/test/common/common/lock_guard_test.cc b/test/common/common/lock_guard_test.cc index 55f505f9ab58..163b535378b2 100644 --- a/test/common/common/lock_guard_test.cc +++ b/test/common/common/lock_guard_test.cc @@ -8,10 +8,10 @@ namespace Thread { class ThreadTest : public testing::Test { protected: - ThreadTest() : a_(0), b_(0) {} - int a_ GUARDED_BY(a_mutex_); + ThreadTest() = default; + int a_ GUARDED_BY(a_mutex_){0}; MutexBasicLockable a_mutex_; - int b_; + int b_{0}; }; TEST_F(ThreadTest, TestLockGuard) { diff --git a/test/common/compressor/zlib_compressor_impl_test.cc b/test/common/compressor/zlib_compressor_impl_test.cc index 0d0c4457cb89..112325f6e377 100644 --- a/test/common/compressor/zlib_compressor_impl_test.cc +++ b/test/common/compressor/zlib_compressor_impl_test.cc @@ -70,7 +70,7 @@ class ZlibCompressorImplTest : public testing::Test { class ZlibCompressorImplTester : public ZlibCompressorImpl { public: - ZlibCompressorImplTester() {} + ZlibCompressorImplTester() = default; ZlibCompressorImplTester(uint64_t chunk_size) : ZlibCompressorImpl(chunk_size) {} void compressThenFlush(Buffer::OwnedImpl& buffer) { compress(buffer, State::Flush); } void finish(Buffer::OwnedImpl& buffer) { compress(buffer, State::Finish); } diff --git a/test/common/config/BUILD b/test/common/config/BUILD index 7e254c5ee8c7..509d423919a9 100644 --- a/test/common/config/BUILD +++ b/test/common/config/BUILD @@ -260,8 +260,6 @@ envoy_cc_test( name = "utility_test", srcs = ["utility_test.cc"], deps = [ - "//source/common/config:cds_json_lib", - "//source/common/config:rds_json_lib", "//source/common/config:utility_lib", "//source/common/config:well_known_names", "//source/common/stats:stats_lib", @@ -301,3 +299,17 @@ envoy_cc_test( "//test/test_common:simulated_time_system_lib", ], ) + +envoy_cc_test( + name = "datasource_test", + srcs = ["datasource_test.cc"], + deps = [ + "//source/common/common:empty_string", + "//source/common/config:datasource_lib", + "//source/common/protobuf:utility_lib", + "//test/mocks/server:server_mocks", + "//test/mocks/upstream:upstream_mocks", + "//test/test_common:utility_lib", + "@envoy_api//envoy/api/v2/core:base_cc", + ], +) diff --git a/test/common/config/config_provider_impl_test.cc b/test/common/config/config_provider_impl_test.cc index f75e1b06dadc..a989cc6e8dca 100644 --- a/test/common/config/config_provider_impl_test.cc +++ b/test/common/config/config_provider_impl_test.cc @@ -22,7 +22,7 @@ class DummyConfigProviderManager; class DummyConfig : public Envoy::Config::ConfigProvider::Config { public: DummyConfig() {} - DummyConfig(const test::common::config::DummyConfig& config_proto) { + explicit DummyConfig(const test::common::config::DummyConfig& config_proto) { protos_.push_back(config_proto); } void addProto(const test::common::config::DummyConfig& config_proto) { @@ -107,7 +107,7 @@ using DummyConfigSubscriptionSharedPtr = std::shared_ptr( MutableConfigProviderCommonBase::subscription_.get())) {} @@ -132,7 +132,7 @@ class DummyDynamicConfigProvider : public MutableConfigProviderCommonBase { class DummyConfigProviderManager : public ConfigProviderManagerImplBase { public: - DummyConfigProviderManager(Server::Admin& admin) + explicit DummyConfigProviderManager(Server::Admin& admin) : ConfigProviderManagerImplBase(admin, "dummy") {} ~DummyConfigProviderManager() override = default; @@ -628,7 +628,6 @@ class DeltaDummyConfigProviderManager : public ConfigProviderManagerImplBase { const std::string&, const Envoy::Config::ConfigProviderManager::OptionalArg&) override { DeltaDummyConfigSubscriptionSharedPtr subscription = - getSubscription( config_source_proto, factory_context.initManager(), [&factory_context](const uint64_t manager_identifier, diff --git a/test/common/config/datasource_test.cc b/test/common/config/datasource_test.cc new file mode 100644 index 000000000000..4621c2e521db --- /dev/null +++ b/test/common/config/datasource_test.cc @@ -0,0 +1,379 @@ +#include "envoy/api/v2/core/base.pb.h" +#include "envoy/api/v2/core/base.pb.validate.h" + +#include "common/common/empty_string.h" +#include "common/config/datasource.h" +#include "common/protobuf/protobuf.h" + +#include "test/mocks/server/mocks.h" +#include "test/mocks/upstream/mocks.h" +#include "test/test_common/utility.h" + +#include "gtest/gtest.h" + +using testing::NiceMock; +using testing::Return; + +namespace Envoy { +namespace Config { +namespace { + +class AsyncDataSourceTest : public testing::Test { +protected: + AsyncDataSourceTest() : api_(Api::createApiForTest()) {} + + using AsyncDataSourcePb = envoy::api::v2::core::AsyncDataSource; + + NiceMock cm_; + Init::MockManager init_manager_; + Init::ExpectableWatcherImpl init_watcher_; + Init::TargetHandlePtr init_target_handle_; + Api::ApiPtr api_; +}; + +TEST_F(AsyncDataSourceTest, loadLocalDataSource) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + local: + inline_string: + xxxxxx + )EOF"; + TestUtility::loadFromYaml(yaml, config); + EXPECT_TRUE(config.has_local()); + + std::string async_data; + + EXPECT_CALL(init_manager_, add(_)).WillOnce(Invoke([this](const Init::Target& target) { + init_target_handle_ = target.createHandle("test"); + })); + + auto provider = std::make_unique( + init_manager_, config.local(), true, *api_, [&](const std::string& data) { + EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); + EXPECT_EQ(data, "xxxxxx"); + async_data = data; + }); + + EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); + EXPECT_CALL(init_watcher_, ready()); + + init_target_handle_->initialize(init_watcher_); + + EXPECT_EQ(async_data, "xxxxxx"); + EXPECT_NE(nullptr, provider.get()); +} + +TEST_F(AsyncDataSourceTest, loadRemoteDataSourceReturnFailure) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + sha256: + xxxxxx + )EOF"; + TestUtility::loadFromYaml(yaml, config); + EXPECT_TRUE(config.has_remote()); + + EXPECT_CALL(cm_, httpAsyncClientForCluster("cluster_1")).WillOnce(ReturnRef(cm_.async_client_)); + EXPECT_CALL(cm_.async_client_, send_(_, _, _)) + .WillOnce( + Invoke([&](Http::MessagePtr&, Http::AsyncClient::Callbacks& callbacks, + const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { + callbacks.onFailure(Envoy::Http::AsyncClient::FailureReason::Reset); + return nullptr; + })); + + EXPECT_CALL(init_manager_, add(_)).WillOnce(Invoke([this](const Init::Target& target) { + init_target_handle_ = target.createHandle("test"); + })); + + std::string async_data = "non-empty"; + auto provider = std::make_unique( + cm_, init_manager_, config.remote(), true, [&](const std::string& data) { + EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); + EXPECT_EQ(data, EMPTY_STRING); + async_data = data; + }); + + EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); + EXPECT_CALL(init_watcher_, ready()); + + init_target_handle_->initialize(init_watcher_); + + EXPECT_EQ(async_data, EMPTY_STRING); + EXPECT_NE(nullptr, provider.get()); +} + +TEST_F(AsyncDataSourceTest, loadRemoteDataSourceSuccessWith503) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + sha256: + xxxxxx + )EOF"; + TestUtility::loadFromYaml(yaml, config); + EXPECT_TRUE(config.has_remote()); + + EXPECT_CALL(cm_, httpAsyncClientForCluster("cluster_1")).WillOnce(ReturnRef(cm_.async_client_)); + EXPECT_CALL(cm_.async_client_, send_(_, _, _)) + .WillOnce( + Invoke([&](Http::MessagePtr&, Http::AsyncClient::Callbacks& callbacks, + const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { + callbacks.onSuccess(Http::MessagePtr{new Http::ResponseMessageImpl( + Http::HeaderMapPtr{new Http::TestHeaderMapImpl{{":status", "503"}}})}); + return nullptr; + })); + + EXPECT_CALL(init_manager_, add(_)).WillOnce(Invoke([this](const Init::Target& target) { + init_target_handle_ = target.createHandle("test"); + })); + + std::string async_data = "non-empty"; + auto provider = std::make_unique( + cm_, init_manager_, config.remote(), true, [&](const std::string& data) { + EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); + EXPECT_EQ(data, EMPTY_STRING); + async_data = data; + }); + + EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); + EXPECT_CALL(init_watcher_, ready()); + + init_target_handle_->initialize(init_watcher_); + EXPECT_EQ(async_data, EMPTY_STRING); + EXPECT_NE(nullptr, provider.get()); +} + +TEST_F(AsyncDataSourceTest, loadRemoteDataSourceSuccessWithEmptyBody) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + sha256: + xxxxxx + )EOF"; + TestUtility::loadFromYaml(yaml, config); + EXPECT_TRUE(config.has_remote()); + + EXPECT_CALL(cm_, httpAsyncClientForCluster("cluster_1")).WillOnce(ReturnRef(cm_.async_client_)); + EXPECT_CALL(cm_.async_client_, send_(_, _, _)) + .WillOnce( + Invoke([&](Http::MessagePtr&, Http::AsyncClient::Callbacks& callbacks, + const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { + callbacks.onSuccess(Http::MessagePtr{new Http::ResponseMessageImpl( + Http::HeaderMapPtr{new Http::TestHeaderMapImpl{{":status", "200"}}})}); + return nullptr; + })); + + EXPECT_CALL(init_manager_, add(_)).WillOnce(Invoke([this](const Init::Target& target) { + init_target_handle_ = target.createHandle("test"); + })); + + std::string async_data = "non-empty"; + auto provider = std::make_unique( + cm_, init_manager_, config.remote(), true, [&](const std::string& data) { + EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); + EXPECT_EQ(data, EMPTY_STRING); + async_data = data; + }); + + EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); + EXPECT_CALL(init_watcher_, ready()); + + init_target_handle_->initialize(init_watcher_); + + EXPECT_EQ(async_data, EMPTY_STRING); + EXPECT_NE(nullptr, provider.get()); +} + +TEST_F(AsyncDataSourceTest, loadRemoteDataSourceSuccessIncorrectSha256) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + sha256: + xxxxxx + )EOF"; + TestUtility::loadFromYaml(yaml, config); + EXPECT_TRUE(config.has_remote()); + + const std::string body = "hello world"; + + EXPECT_CALL(cm_, httpAsyncClientForCluster("cluster_1")).WillOnce(ReturnRef(cm_.async_client_)); + EXPECT_CALL(cm_.async_client_, send_(_, _, _)) + .WillOnce( + Invoke([&](Http::MessagePtr&, Http::AsyncClient::Callbacks& callbacks, + const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { + Http::MessagePtr response(new Http::ResponseMessageImpl( + Http::HeaderMapPtr{new Http::TestHeaderMapImpl{{":status", "200"}}})); + response->body() = std::make_unique(body); + + callbacks.onSuccess(std::move(response)); + return nullptr; + })); + + EXPECT_CALL(init_manager_, add(_)).WillOnce(Invoke([this](const Init::Target& target) { + init_target_handle_ = target.createHandle("test"); + })); + + std::string async_data = "non-empty"; + auto provider = std::make_unique( + cm_, init_manager_, config.remote(), true, [&](const std::string& data) { + EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); + EXPECT_EQ(data, EMPTY_STRING); + async_data = data; + }); + + EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); + EXPECT_CALL(init_watcher_, ready()); + + init_target_handle_->initialize(init_watcher_); + EXPECT_EQ(async_data, EMPTY_STRING); + EXPECT_NE(nullptr, provider.get()); +} + +TEST_F(AsyncDataSourceTest, loadRemoteDataSourceSuccess) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + sha256: + b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 + )EOF"; + TestUtility::loadFromYaml(yaml, config); + EXPECT_TRUE(config.has_remote()); + + const std::string body = "hello world"; + + EXPECT_CALL(cm_, httpAsyncClientForCluster("cluster_1")).WillOnce(ReturnRef(cm_.async_client_)); + EXPECT_CALL(cm_.async_client_, send_(_, _, _)) + .WillOnce( + Invoke([&](Http::MessagePtr&, Http::AsyncClient::Callbacks& callbacks, + const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { + Http::MessagePtr response(new Http::ResponseMessageImpl( + Http::HeaderMapPtr{new Http::TestHeaderMapImpl{{":status", "200"}}})); + response->body() = std::make_unique(body); + + callbacks.onSuccess(std::move(response)); + return nullptr; + })); + + EXPECT_CALL(init_manager_, add(_)).WillOnce(Invoke([this](const Init::Target& target) { + init_target_handle_ = target.createHandle("test"); + })); + + std::string async_data = "non-empty"; + auto provider = std::make_unique( + cm_, init_manager_, config.remote(), true, [&](const std::string& data) { + EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); + EXPECT_EQ(data, body); + async_data = data; + }); + + EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); + EXPECT_CALL(init_watcher_, ready()); + + init_target_handle_->initialize(init_watcher_); + EXPECT_EQ(async_data, body); + EXPECT_NE(nullptr, provider.get()); +} + +TEST_F(AsyncDataSourceTest, loadRemoteDataSourceExpectNetworkFailure) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + sha256: + xxxxxx + )EOF"; + TestUtility::loadFromYaml(yaml, config); + EXPECT_TRUE(config.has_remote()); + + EXPECT_CALL(cm_, httpAsyncClientForCluster("cluster_1")).WillOnce(ReturnRef(cm_.async_client_)); + EXPECT_CALL(cm_.async_client_, send_(_, _, _)) + .WillOnce( + Invoke([&](Http::MessagePtr&, Http::AsyncClient::Callbacks& callbacks, + const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { + callbacks.onSuccess(Http::MessagePtr{new Http::ResponseMessageImpl( + Http::HeaderMapPtr{new Http::TestHeaderMapImpl{{":status", "503"}}})}); + return nullptr; + })); + + EXPECT_CALL(init_manager_, add(_)).WillOnce(Invoke([this](const Init::Target& target) { + init_target_handle_ = target.createHandle("test"); + })); + + auto provider = std::make_unique( + cm_, init_manager_, config.remote(), false, [](const std::string&) {}); + + EXPECT_THROW_WITH_MESSAGE(init_target_handle_->initialize(init_watcher_), EnvoyException, + "Failed to fetch remote data. Failure reason: 0"); + EXPECT_NE(nullptr, provider.get()); + EXPECT_CALL(init_watcher_, ready()); +} + +TEST_F(AsyncDataSourceTest, loadRemoteDataSourceExpectInvalidData) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + sha256: + xxxxxx + )EOF"; + TestUtility::loadFromYaml(yaml, config); + EXPECT_TRUE(config.has_remote()); + + const std::string body = "hello world"; + + EXPECT_CALL(cm_, httpAsyncClientForCluster("cluster_1")).WillOnce(ReturnRef(cm_.async_client_)); + EXPECT_CALL(cm_.async_client_, send_(_, _, _)) + .WillOnce( + Invoke([&](Http::MessagePtr&, Http::AsyncClient::Callbacks& callbacks, + const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { + Http::MessagePtr response(new Http::ResponseMessageImpl( + Http::HeaderMapPtr{new Http::TestHeaderMapImpl{{":status", "200"}}})); + response->body() = std::make_unique(body); + + callbacks.onSuccess(std::move(response)); + return nullptr; + })); + + EXPECT_CALL(init_manager_, add(_)).WillOnce(Invoke([this](const Init::Target& target) { + init_target_handle_ = target.createHandle("test"); + })); + + auto provider = std::make_unique( + cm_, init_manager_, config.remote(), false, [](const std::string&) {}); + + EXPECT_THROW_WITH_MESSAGE(init_target_handle_->initialize(init_watcher_), EnvoyException, + "Failed to fetch remote data. Failure reason: 1"); + EXPECT_NE(nullptr, provider.get()); + EXPECT_CALL(init_watcher_, ready()); +} + +} // namespace +} // namespace Config +} // namespace Envoy \ No newline at end of file diff --git a/test/common/config/delta_subscription_impl_test.cc b/test/common/config/delta_subscription_impl_test.cc index 55731c26a88a..26d7daca0df3 100644 --- a/test/common/config/delta_subscription_impl_test.cc +++ b/test/common/config/delta_subscription_impl_test.cc @@ -8,7 +8,7 @@ namespace { class DeltaSubscriptionImplTest : public DeltaSubscriptionTestHarness, public testing::Test { protected: - DeltaSubscriptionImplTest() {} + DeltaSubscriptionImplTest() = default; }; TEST_F(DeltaSubscriptionImplTest, UpdateResourcesCausesRequest) { diff --git a/test/common/config/delta_subscription_test_harness.h b/test/common/config/delta_subscription_test_harness.h index e14599210884..a2431c154bc8 100644 --- a/test/common/config/delta_subscription_test_harness.h +++ b/test/common/config/delta_subscription_test_harness.h @@ -38,7 +38,7 @@ class DeltaSubscriptionTestHarness : public SubscriptionTestHarness { rate_limit_settings_, callbacks_, stats_, init_fetch_timeout); } - ~DeltaSubscriptionTestHarness() { + ~DeltaSubscriptionTestHarness() override { while (!nonce_acks_required_.empty()) { EXPECT_FALSE(nonce_acks_sent_.empty()); EXPECT_EQ(nonce_acks_required_.front(), nonce_acks_sent_.front()); diff --git a/test/common/config/filesystem_subscription_impl_test.cc b/test/common/config/filesystem_subscription_impl_test.cc index 51efbd9a9e00..36c9815d1bf0 100644 --- a/test/common/config/filesystem_subscription_impl_test.cc +++ b/test/common/config/filesystem_subscription_impl_test.cc @@ -18,19 +18,19 @@ class FilesystemSubscriptionImplTest : public testing::Test, // Validate that the client can recover from bad JSON responses. TEST_F(FilesystemSubscriptionImplTest, BadJsonRecovery) { startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0, 0); + EXPECT_TRUE(statsAre(1, 0, 0, 0, 0)); EXPECT_CALL(callbacks_, onConfigUpdateFailed(_)); updateFile(";!@#badjso n"); - verifyStats(2, 0, 0, 1, 0); + EXPECT_TRUE(statsAre(2, 0, 0, 1, 0)); deliverConfigUpdate({"cluster0", "cluster1"}, "0", true); - verifyStats(3, 1, 0, 1, 7148434200721666028); + EXPECT_TRUE(statsAre(3, 1, 0, 1, 7148434200721666028)); } // Validate that a file that is initially available results in a successful update. TEST_F(FilesystemSubscriptionImplTest, InitialFile) { updateFile("{\"versionInfo\": \"0\", \"resources\": []}", false); startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 1, 0, 0, 7148434200721666028); + EXPECT_TRUE(statsAre(1, 1, 0, 0, 7148434200721666028)); } // Validate that if we fail to set a watch, we get a sensible warning. diff --git a/test/common/config/filesystem_subscription_test_harness.h b/test/common/config/filesystem_subscription_test_harness.h index 9a14fc73dd5c..b34028e40b53 100644 --- a/test/common/config/filesystem_subscription_test_harness.h +++ b/test/common/config/filesystem_subscription_test_harness.h @@ -32,7 +32,7 @@ class FilesystemSubscriptionTestHarness : public SubscriptionTestHarness { api_(Api::createApiForTest(stats_store_)), dispatcher_(api_->allocateDispatcher()), subscription_(*dispatcher_, path_, callbacks_, stats_, validation_visitor_, *api_) {} - ~FilesystemSubscriptionTestHarness() { + ~FilesystemSubscriptionTestHarness() override { if (::access(path_.c_str(), F_OK) != -1) { EXPECT_EQ(0, ::unlink(path_.c_str())); } @@ -86,11 +86,11 @@ class FilesystemSubscriptionTestHarness : public SubscriptionTestHarness { updateFile(file_json); } - void verifyStats(uint32_t attempt, uint32_t success, uint32_t rejected, uint32_t failure, - uint64_t version) override { + AssertionResult statsAre(uint32_t attempt, uint32_t success, uint32_t rejected, uint32_t failure, + uint64_t version) override { // The first attempt always fail unless there was a file there to begin with. - SubscriptionTestHarness::verifyStats(attempt, success, rejected, - failure + (file_at_start_ ? 0 : 1), version); + return SubscriptionTestHarness::statsAre(attempt, success, rejected, + failure + (file_at_start_ ? 0 : 1), version); } void expectConfigUpdateFailed() override { diff --git a/test/common/config/grpc_subscription_impl_test.cc b/test/common/config/grpc_subscription_impl_test.cc index ed62b3b61599..35991e88717d 100644 --- a/test/common/config/grpc_subscription_impl_test.cc +++ b/test/common/config/grpc_subscription_impl_test.cc @@ -19,7 +19,7 @@ TEST_F(GrpcSubscriptionImplTest, StreamCreationFailure) { EXPECT_CALL(random_, random()); EXPECT_CALL(*timer_, enableTimer(_)); subscription_->start({"cluster0", "cluster1"}); - verifyStats(2, 0, 0, 1, 0); + EXPECT_TRUE(statsAre(2, 0, 0, 1, 0)); // Ensure this doesn't cause an issue by sending a request, since we don't // have a gRPC stream. subscription_->updateResources({"cluster2"}); @@ -29,27 +29,27 @@ TEST_F(GrpcSubscriptionImplTest, StreamCreationFailure) { expectSendMessage({"cluster2"}, ""); timer_cb_(); - verifyStats(3, 0, 0, 1, 0); + EXPECT_TRUE(statsAre(3, 0, 0, 1, 0)); verifyControlPlaneStats(1); } // Validate that the client can recover from a remote stream closure via retry. TEST_F(GrpcSubscriptionImplTest, RemoteStreamClose) { startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0, 0); + EXPECT_TRUE(statsAre(1, 0, 0, 0, 0)); EXPECT_CALL(callbacks_, onConfigUpdateFailed(_)); EXPECT_CALL(*timer_, enableTimer(_)); EXPECT_CALL(random_, random()); subscription_->grpcMux().grpcStreamForTest().onRemoteClose(Grpc::Status::GrpcStatus::Canceled, ""); - verifyStats(2, 0, 0, 1, 0); + EXPECT_TRUE(statsAre(2, 0, 0, 1, 0)); verifyControlPlaneStats(0); // Retry and succeed. EXPECT_CALL(*async_client_, startRaw(_, _, _)).WillOnce(Return(&async_stream_)); expectSendMessage({"cluster0", "cluster1"}, ""); timer_cb_(); - verifyStats(2, 0, 0, 1, 0); + EXPECT_TRUE(statsAre(2, 0, 0, 1, 0)); } // Validate that When the management server gets multiple requests for the same version, it can @@ -57,21 +57,21 @@ TEST_F(GrpcSubscriptionImplTest, RemoteStreamClose) { TEST_F(GrpcSubscriptionImplTest, RepeatedNonce) { InSequence s; startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0, 0); + EXPECT_TRUE(statsAre(1, 0, 0, 0, 0)); // First with the initial, empty version update to "0". updateResources({"cluster2"}); - verifyStats(2, 0, 0, 0, 0); + EXPECT_TRUE(statsAre(2, 0, 0, 0, 0)); deliverConfigUpdate({"cluster0", "cluster2"}, "0", false); - verifyStats(3, 0, 1, 0, 0); + EXPECT_TRUE(statsAre(3, 0, 1, 0, 0)); deliverConfigUpdate({"cluster0", "cluster2"}, "0", true); - verifyStats(4, 1, 1, 0, 7148434200721666028); + EXPECT_TRUE(statsAre(4, 1, 1, 0, 7148434200721666028)); // Now with version "0" update to "1". updateResources({"cluster3"}); - verifyStats(5, 1, 1, 0, 7148434200721666028); + EXPECT_TRUE(statsAre(5, 1, 1, 0, 7148434200721666028)); deliverConfigUpdate({"cluster3"}, "1", false); - verifyStats(6, 1, 2, 0, 7148434200721666028); + EXPECT_TRUE(statsAre(6, 1, 2, 0, 7148434200721666028)); deliverConfigUpdate({"cluster3"}, "1", true); - verifyStats(7, 2, 2, 0, 13237225503670494420U); + EXPECT_TRUE(statsAre(7, 2, 2, 0, 13237225503670494420U)); } } // namespace diff --git a/test/common/config/http_subscription_impl_test.cc b/test/common/config/http_subscription_impl_test.cc index a8aaed17f7a1..6cc81becb889 100644 --- a/test/common/config/http_subscription_impl_test.cc +++ b/test/common/config/http_subscription_impl_test.cc @@ -17,11 +17,11 @@ TEST_F(HttpSubscriptionImplTest, OnRequestReset) { EXPECT_CALL(*timer_, enableTimer(_)); EXPECT_CALL(callbacks_, onConfigUpdateFailed(_)); http_callbacks_->onFailure(Http::AsyncClient::FailureReason::Reset); - verifyStats(1, 0, 0, 1, 0); + EXPECT_TRUE(statsAre(1, 0, 0, 1, 0)); timerTick(); - verifyStats(2, 0, 0, 1, 0); + EXPECT_TRUE(statsAre(2, 0, 0, 1, 0)); deliverConfigUpdate({"cluster0", "cluster1"}, "0", true); - verifyStats(3, 1, 0, 1, 7148434200721666028); + EXPECT_TRUE(statsAre(3, 1, 0, 1, 7148434200721666028)); } // Validate that the client can recover from bad JSON responses. @@ -34,28 +34,28 @@ TEST_F(HttpSubscriptionImplTest, BadJsonRecovery) { EXPECT_CALL(*timer_, enableTimer(_)); EXPECT_CALL(callbacks_, onConfigUpdateFailed(_)); http_callbacks_->onSuccess(std::move(message)); - verifyStats(1, 0, 0, 1, 0); + EXPECT_TRUE(statsAre(1, 0, 0, 1, 0)); request_in_progress_ = false; timerTick(); - verifyStats(2, 0, 0, 1, 0); + EXPECT_TRUE(statsAre(2, 0, 0, 1, 0)); deliverConfigUpdate({"cluster0", "cluster1"}, "0", true); - verifyStats(3, 1, 0, 1, 7148434200721666028); + EXPECT_TRUE(statsAre(3, 1, 0, 1, 7148434200721666028)); } TEST_F(HttpSubscriptionImplTest, ConfigNotModified) { startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0, 0); + EXPECT_TRUE(statsAre(1, 0, 0, 0, 0)); timerTick(); - verifyStats(2, 0, 0, 0, 0); + EXPECT_TRUE(statsAre(2, 0, 0, 0, 0)); // accept and modify. deliverConfigUpdate({"cluster0", "cluster1"}, "0", true, true, "200"); - verifyStats(3, 1, 0, 0, 7148434200721666028); + EXPECT_TRUE(statsAre(3, 1, 0, 0, 7148434200721666028)); // accept and does not modify. deliverConfigUpdate({"cluster0", "cluster1"}, "0", true, false, "304"); - verifyStats(4, 1, 0, 0, 7148434200721666028); + EXPECT_TRUE(statsAre(4, 1, 0, 0, 7148434200721666028)); } } // namespace diff --git a/test/common/config/http_subscription_test_harness.h b/test/common/config/http_subscription_test_harness.h index c769a40cc4ff..ecf5c056950e 100644 --- a/test/common/config/http_subscription_test_harness.h +++ b/test/common/config/http_subscription_test_harness.h @@ -51,7 +51,7 @@ class HttpSubscriptionTestHarness : public SubscriptionTestHarness { init_fetch_timeout, validation_visitor_); } - ~HttpSubscriptionTestHarness() { + ~HttpSubscriptionTestHarness() override { // Stop subscribing on the way out. if (request_in_progress_) { EXPECT_CALL(http_request_, cancel()); diff --git a/test/common/config/metadata_test.cc b/test/common/config/metadata_test.cc index 28d5cb67b4a8..885d69f82117 100644 --- a/test/common/config/metadata_test.cc +++ b/test/common/config/metadata_test.cc @@ -61,9 +61,10 @@ class TypedMetadataTest : public testing::Test { class FooFactory : public TypedMetadataFactory::TypedMetadataFactory { public: - const std::string name() const { return "foo"; } + const std::string name() const override { return "foo"; } // Throws EnvoyException (conversion failure) if d is empty. - std::unique_ptr parse(const ProtobufWkt::Struct& d) const { + std::unique_ptr + parse(const ProtobufWkt::Struct& d) const override { if (d.fields().find("name") != d.fields().end()) { return std::make_unique(d.fields().at("name").string_value()); } diff --git a/test/common/config/subscription_factory_impl_test.cc b/test/common/config/subscription_factory_impl_test.cc index 9c10b7dad282..c72b02d14608 100644 --- a/test/common/config/subscription_factory_impl_test.cc +++ b/test/common/config/subscription_factory_impl_test.cc @@ -226,7 +226,7 @@ TEST_F(SubscriptionFactoryTest, HttpSubscriptionCustomRequestTimeout) { EXPECT_CALL(cm_, clusters()).WillOnce(Return(cluster_map)); EXPECT_CALL(cluster, info()).Times(2); EXPECT_CALL(*cluster.info_, addedViaApi()); - EXPECT_CALL(dispatcher_, createTimer_(_)); + EXPECT_CALL(dispatcher_, createTimer_(_)).Times(2); EXPECT_CALL(cm_, httpAsyncClientForCluster("static_cluster")); EXPECT_CALL( cm_.async_client_, @@ -246,7 +246,7 @@ TEST_F(SubscriptionFactoryTest, HttpSubscription) { EXPECT_CALL(cm_, clusters()).WillOnce(Return(cluster_map)); EXPECT_CALL(cluster, info()).Times(2); EXPECT_CALL(*cluster.info_, addedViaApi()); - EXPECT_CALL(dispatcher_, createTimer_(_)); + EXPECT_CALL(dispatcher_, createTimer_(_)).Times(2); EXPECT_CALL(cm_, httpAsyncClientForCluster("static_cluster")); EXPECT_CALL(cm_.async_client_, send_(_, _, _)) .WillOnce(Invoke([this](Http::MessagePtr& request, Http::AsyncClient::Callbacks&, @@ -301,7 +301,7 @@ TEST_F(SubscriptionFactoryTest, GrpcSubscription) { return async_client_factory; })); EXPECT_CALL(random_, random()); - EXPECT_CALL(dispatcher_, createTimer_(_)); + EXPECT_CALL(dispatcher_, createTimer_(_)).Times(2); EXPECT_CALL(callbacks_, onConfigUpdateFailed(_)); subscriptionFromConfigSource(config)->start({"static_cluster"}); } diff --git a/test/common/config/subscription_impl_test.cc b/test/common/config/subscription_impl_test.cc index 67a9566619c2..094c2dbf76b2 100644 --- a/test/common/config/subscription_impl_test.cc +++ b/test/common/config/subscription_impl_test.cc @@ -51,9 +51,9 @@ class SubscriptionImplTest : public testing::TestWithParam { test_harness_->expectSendMessage(cluster_names, version); } - void verifyStats(uint32_t attempt, uint32_t success, uint32_t rejected, uint32_t failure, - uint64_t version) { - test_harness_->verifyStats(attempt, success, rejected, failure, version); + AssertionResult statsAre(uint32_t attempt, uint32_t success, uint32_t rejected, uint32_t failure, + uint64_t version) { + return test_harness_->statsAre(attempt, success, rejected, failure, version); } void deliverConfigUpdate(const std::vector cluster_names, const std::string& version, @@ -88,57 +88,57 @@ INSTANTIATE_TEST_SUITE_P(SubscriptionImplTest, SubscriptionImplInitFetchTimeoutT // Validate basic request-response succeeds. TEST_P(SubscriptionImplTest, InitialRequestResponse) { startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0, 0); + statsAre(1, 0, 0, 0, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "0", true); - verifyStats(2, 1, 0, 0, 7148434200721666028); + statsAre(2, 1, 0, 0, 7148434200721666028); } // Validate that multiple streamed updates succeed. TEST_P(SubscriptionImplTest, ResponseStream) { startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0, 0); + statsAre(1, 0, 0, 0, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "0", true); - verifyStats(2, 1, 0, 0, 7148434200721666028); + statsAre(2, 1, 0, 0, 7148434200721666028); deliverConfigUpdate({"cluster0", "cluster1"}, "1", true); - verifyStats(3, 2, 0, 0, 13237225503670494420U); + statsAre(3, 2, 0, 0, 13237225503670494420U); } // Validate that the client can reject a config. TEST_P(SubscriptionImplTest, RejectConfig) { startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0, 0); + statsAre(1, 0, 0, 0, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "0", false); - verifyStats(2, 0, 1, 0, 0); + statsAre(2, 0, 1, 0, 0); } // Validate that the client can reject a config and accept the same config later. TEST_P(SubscriptionImplTest, RejectAcceptConfig) { startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0, 0); + statsAre(1, 0, 0, 0, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "0", false); - verifyStats(2, 0, 1, 0, 0); + statsAre(2, 0, 1, 0, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "0", true); - verifyStats(3, 1, 1, 0, 7148434200721666028); + statsAre(3, 1, 1, 0, 7148434200721666028); } // Validate that the client can reject a config and accept another config later. TEST_P(SubscriptionImplTest, RejectAcceptNextConfig) { startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0, 0); + statsAre(1, 0, 0, 0, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "0", false); - verifyStats(2, 0, 1, 0, 0); + statsAre(2, 0, 1, 0, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "1", true); - verifyStats(3, 1, 1, 0, 13237225503670494420U); + statsAre(3, 1, 1, 0, 13237225503670494420U); } // Validate that stream updates send a message with the updated resources. TEST_P(SubscriptionImplTest, UpdateResources) { startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0, 0); + statsAre(1, 0, 0, 0, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "0", true); - verifyStats(2, 1, 0, 0, 7148434200721666028); + statsAre(2, 1, 0, 0, 7148434200721666028); updateResources({"cluster2"}); - verifyStats(3, 1, 0, 0, 7148434200721666028); + statsAre(3, 1, 0, 0, 7148434200721666028); } // Validate that initial fetch timer is created and calls callback on timeout @@ -146,10 +146,10 @@ TEST_P(SubscriptionImplInitFetchTimeoutTest, InitialFetchTimeout) { InSequence s; expectEnableInitFetchTimeoutTimer(std::chrono::milliseconds(1000)); startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0, 0); + statsAre(1, 0, 0, 0, 0); expectConfigUpdateFailed(); callInitFetchTimeoutCb(); - verifyStats(1, 0, 0, 0, 0); + statsAre(1, 0, 0, 0, 0); } // Validate that initial fetch timer is disabled on config update @@ -157,7 +157,7 @@ TEST_P(SubscriptionImplInitFetchTimeoutTest, DisableInitTimeoutOnSuccess) { InSequence s; expectEnableInitFetchTimeoutTimer(std::chrono::milliseconds(1000)); startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0, 0); + statsAre(1, 0, 0, 0, 0); expectDisableInitFetchTimeoutTimer(); deliverConfigUpdate({"cluster0", "cluster1"}, "0", true); } @@ -167,7 +167,7 @@ TEST_P(SubscriptionImplInitFetchTimeoutTest, DisableInitTimeoutOnFail) { InSequence s; expectEnableInitFetchTimeoutTimer(std::chrono::milliseconds(1000)); startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0, 0); + statsAre(1, 0, 0, 0, 0); expectDisableInitFetchTimeoutTimer(); deliverConfigUpdate({"cluster0", "cluster1"}, "0", false); } diff --git a/test/common/config/subscription_test_harness.h b/test/common/config/subscription_test_harness.h index 5e12ab8c4180..510d550ff9be 100644 --- a/test/common/config/subscription_test_harness.h +++ b/test/common/config/subscription_test_harness.h @@ -49,15 +49,28 @@ class SubscriptionTestHarness { virtual void deliverConfigUpdate(const std::vector& cluster_names, const std::string& version, bool accept) PURE; - virtual void verifyStats(uint32_t attempt, uint32_t success, uint32_t rejected, uint32_t failure, - uint64_t version) { + virtual testing::AssertionResult statsAre(uint32_t attempt, uint32_t success, uint32_t rejected, + uint32_t failure, uint64_t version) { // TODO(fredlas) rework update_success_ to make sense across all xDS carriers. Its value in - // verifyStats() calls in many tests will probably have to be changed. + // statsAre() calls in many tests will probably have to be changed. UNREFERENCED_PARAMETER(attempt); - EXPECT_EQ(success, stats_.update_success_.value()); - EXPECT_EQ(rejected, stats_.update_rejected_.value()); - EXPECT_EQ(failure, stats_.update_failure_.value()); - EXPECT_EQ(version, stats_.version_.value()); + if (success != stats_.update_success_.value()) { + return testing::AssertionFailure() << "update_success: expected " << success << ", got " + << stats_.update_success_.value(); + } + if (rejected != stats_.update_rejected_.value()) { + return testing::AssertionFailure() << "update_rejected: expected " << rejected << ", got " + << stats_.update_rejected_.value(); + } + if (failure != stats_.update_failure_.value()) { + return testing::AssertionFailure() << "update_failure: expected " << failure << ", got " + << stats_.update_failure_.value(); + } + if (version != stats_.version_.value()) { + return testing::AssertionFailure() + << "version: expected " << version << ", got " << stats_.version_.value(); + } + return testing::AssertionSuccess(); } virtual void verifyControlPlaneStats(uint32_t connected_state) { diff --git a/test/common/config/utility_test.cc b/test/common/config/utility_test.cc index 30d8fa8b3f3b..dea04ddb1fd6 100644 --- a/test/common/config/utility_test.cc +++ b/test/common/config/utility_test.cc @@ -2,8 +2,6 @@ #include "envoy/common/exception.h" #include "common/common/fmt.h" -#include "common/config/cds_json.h" -#include "common/config/rds_json.h" #include "common/config/utility.h" #include "common/config/well_known_names.h" #include "common/protobuf/protobuf.h" @@ -55,7 +53,7 @@ TEST(UtilityTest, ApiConfigSourceRequestTimeout) { TEST(UtilityTest, ConfigSourceDefaultInitFetchTimeout) { envoy::api::v2::core::ConfigSource config_source; - EXPECT_EQ(0, Utility::configSourceInitialFetchTimeout(config_source).count()); + EXPECT_EQ(15000, Utility::configSourceInitialFetchTimeout(config_source).count()); } TEST(UtilityTest, ConfigSourceInitFetchTimeout) { @@ -102,35 +100,6 @@ TEST(UtilityTest, createTagProducer) { ASSERT_EQ(tags.size(), 1); } -TEST(UtilityTest, UnixClusterDns) { - - std::string cluster_type; - cluster_type = "strict_dns"; - std::string json = - R"EOF({ "name": "test", "type": ")EOF" + cluster_type + - R"EOF(", "lb_type": "random", "connect_timeout_ms" : 1, "hosts": [{"url": "unix:///test.sock"}]})EOF"; - auto json_object_ptr = Json::Factory::loadFromString(json); - envoy::api::v2::Cluster cluster; - envoy::api::v2::core::ConfigSource eds_config; - EXPECT_THROW_WITH_MESSAGE( - Config::CdsJson::translateCluster(*json_object_ptr, eds_config, cluster), EnvoyException, - "unresolved URL must be TCP scheme, got: unix:///test.sock"); -} - -TEST(UtilityTest, UnixClusterStatic) { - - std::string cluster_type; - cluster_type = "static"; - std::string json = - R"EOF({ "name": "test", "type": ")EOF" + cluster_type + - R"EOF(", "lb_type": "random", "connect_timeout_ms" : 1, "hosts": [{"url": "unix:///test.sock"}]})EOF"; - auto json_object_ptr = Json::Factory::loadFromString(json); - envoy::api::v2::Cluster cluster; - envoy::api::v2::core::ConfigSource eds_config; - Config::CdsJson::translateCluster(*json_object_ptr, eds_config, cluster); - EXPECT_EQ("/test.sock", cluster.hosts(0).pipe().path()); -} - TEST(UtilityTest, CheckFilesystemSubscriptionBackingPath) { Api::ApiPtr api = Api::createApiForTest(); diff --git a/test/common/event/dispatcher_impl_test.cc b/test/common/event/dispatcher_impl_test.cc index 97a36cc43c03..c0605a70c3ca 100644 --- a/test/common/event/dispatcher_impl_test.cc +++ b/test/common/event/dispatcher_impl_test.cc @@ -28,7 +28,7 @@ namespace { class TestDeferredDeletable : public DeferredDeletable { public: TestDeferredDeletable(std::function on_destroy) : on_destroy_(on_destroy) {} - ~TestDeferredDeletable() { on_destroy_(); } + ~TestDeferredDeletable() override { on_destroy_(); } private: std::function on_destroy_; @@ -67,9 +67,7 @@ TEST(DeferredDeleteTest, DeferredDelete) { class DispatcherImplTest : public testing::Test { protected: - DispatcherImplTest() - : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher()), - work_finished_(false) { + DispatcherImplTest() : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher()) { dispatcher_thread_ = api_->threadFactory().createThread([this]() { // Must create a keepalive timer to keep the dispatcher from exiting. std::chrono::milliseconds time_interval(500); @@ -93,7 +91,7 @@ class DispatcherImplTest : public testing::Test { Thread::MutexBasicLockable mu_; Thread::CondVar cv_; - bool work_finished_; + bool work_finished_{false}; TimerPtr keepalive_timer_; }; @@ -187,6 +185,40 @@ TEST_F(DispatcherImplTest, Timer) { } } +TEST_F(DispatcherImplTest, IsThreadSafe) { + dispatcher_->post([this]() { + { + Thread::LockGuard lock(mu_); + // Thread safe because it is called within the dispatcher thread's context. + EXPECT_TRUE(dispatcher_->isThreadSafe()); + work_finished_ = true; + } + cv_.notifyOne(); + }); + + Thread::LockGuard lock(mu_); + while (!work_finished_) { + cv_.wait(mu_); + } + // Not thread safe because it is not called within the dispatcher thread's context. + EXPECT_FALSE(dispatcher_->isThreadSafe()); +} + +class NotStartedDispatcherImplTest : public testing::Test { +protected: + NotStartedDispatcherImplTest() + : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher()) {} + + Api::ApiPtr api_; + DispatcherPtr dispatcher_; +}; + +TEST_F(NotStartedDispatcherImplTest, IsThreadSafe) { + // Thread safe because the dispatcher has not started. + // Therefore, no thread id has been assigned. + EXPECT_TRUE(dispatcher_->isThreadSafe()); +} + TEST(TimerImplTest, TimerEnabledDisabled) { Api::ApiPtr api = Api::createApiForTest(); DispatcherPtr dispatcher(api->allocateDispatcher()); diff --git a/test/common/grpc/grpc_client_integration_test.cc b/test/common/grpc/grpc_client_integration_test.cc index 5044cace4d40..f7b7505b4ad8 100644 --- a/test/common/grpc/grpc_client_integration_test.cc +++ b/test/common/grpc/grpc_client_integration_test.cc @@ -406,7 +406,7 @@ class GrpcAccessTokenClientIntegrationTest : public GrpcSslClientIntegrationTest } } - virtual envoy::api::v2::core::GrpcService createGoogleGrpcConfig() override { + envoy::api::v2::core::GrpcService createGoogleGrpcConfig() override { auto config = GrpcClientIntegrationTest::createGoogleGrpcConfig(); auto* google_grpc = config.mutable_google_grpc(); google_grpc->set_credentials_factory_name(credentials_factory_name_); diff --git a/test/common/grpc/grpc_client_integration_test_harness.h b/test/common/grpc/grpc_client_integration_test_harness.h index ad8a997d770b..997bae8b6bb8 100644 --- a/test/common/grpc/grpc_client_integration_test_harness.h +++ b/test/common/grpc/grpc_client_integration_test_harness.h @@ -471,7 +471,7 @@ class GrpcSslClientIntegrationTest : public GrpcClientIntegrationTest { mock_cluster_info_->transport_socket_factory_.reset(); } - virtual envoy::api::v2::core::GrpcService createGoogleGrpcConfig() override { + envoy::api::v2::core::GrpcService createGoogleGrpcConfig() override { auto config = GrpcClientIntegrationTest::createGoogleGrpcConfig(); TestUtility::setTestSslGoogleGrpcConfig(config, use_client_cert_); return config; diff --git a/test/common/http/BUILD b/test/common/http/BUILD index 4f5ac9cad9f9..5cfeaff671fa 100644 --- a/test/common/http/BUILD +++ b/test/common/http/BUILD @@ -252,6 +252,7 @@ envoy_cc_test( srcs = ["header_map_impl_test.cc"], deps = [ "//source/common/http:header_map_lib", + "//source/common/http:header_utility_lib", "//test/test_common:utility_lib", ], ) diff --git a/test/common/http/async_client_impl_test.cc b/test/common/http/async_client_impl_test.cc index 60fdcf67b4d3..9a58c3f4f83d 100644 --- a/test/common/http/async_client_impl_test.cc +++ b/test/common/http/async_client_impl_test.cc @@ -908,6 +908,21 @@ TEST_F(AsyncClientImplTest, RdsGettersTest) { EXPECT_CALL(stream_callbacks_, onReset()); } +TEST_F(AsyncClientImplTest, DumpState) { + TestHeaderMapImpl headers; + HttpTestUtility::addDefaultHeaders(headers); + AsyncClient::Stream* stream = client_.start(stream_callbacks_, AsyncClient::StreamOptions()); + Http::StreamDecoderFilterCallbacks* filter_callbacks = + static_cast(stream); + + std::stringstream out; + filter_callbacks->scope().dumpState(out); + std::string state = out.str(); + EXPECT_THAT(state, testing::HasSubstr("protocol_: 1")); + + EXPECT_CALL(stream_callbacks_, onReset()); +} + } // namespace // Must not be in anonymous namespace for friend to work. diff --git a/test/common/http/codec_client_test.cc b/test/common/http/codec_client_test.cc index 911b8a64c55f..7fc083eba090 100644 --- a/test/common/http/codec_client_test.cc +++ b/test/common/http/codec_client_test.cc @@ -58,7 +58,7 @@ class CodecClientTest : public testing::Test { dispatcher_); } - ~CodecClientTest() { EXPECT_EQ(0U, client_->numActiveRequests()); } + ~CodecClientTest() override { EXPECT_EQ(0U, client_->numActiveRequests()); } Event::MockDispatcher dispatcher_; Network::MockClientConnection* connection_; diff --git a/test/common/http/codec_impl_corpus/clusterfuzz-testcase-minimized-codec_impl_fuzz_test-5107763548520448 b/test/common/http/codec_impl_corpus/clusterfuzz-testcase-minimized-codec_impl_fuzz_test-5107763548520448 new file mode 100644 index 000000000000..f45f1e08127d --- /dev/null +++ b/test/common/http/codec_impl_corpus/clusterfuzz-testcase-minimized-codec_impl_fuzz_test-5107763548520448 @@ -0,0 +1 @@ +h2_settings { server { max_concurrent_streams: 3 initial_connection_window_size: 1 } } actions { new_stream { } } actions { new_stream { } } actions { new_stream { } } actions { new_stream { } } actions { new_stream { } } actions { new_stream { } } actions { new_stream { } } actions { new_stream { } } actions { new_stream { } } actions { new_stream { } } actions { new_stream { } } actions { new_stream { } } actions { client_drain { } } actions { new_stream { } } actions { new_stream { } } actions { new_stream { } } actions { new_stream { } } actions { mutate { buffer: 1 offset: 1 value: 1 server: true } } actions { mutate { buffer: 1 offset: 3 value: 7 server: true } } actions { new_stream { } } actions { new_stream { } } actions { new_stream { } } actions { quiesce_drain { } } actions { new_stream { } } \ No newline at end of file diff --git a/test/common/http/codec_impl_fuzz_test.cc b/test/common/http/codec_impl_fuzz_test.cc index 7d51f36665e9..4a56733f710f 100644 --- a/test/common/http/codec_impl_fuzz_test.cc +++ b/test/common/http/codec_impl_fuzz_test.cc @@ -150,10 +150,10 @@ class HttpStream : public LinkedObject { ON_CALL(response_.decoder_, decodeTrailers_(_)).WillByDefault(InvokeWithoutArgs([this] { response_.closeRemote(); })); - request_.encoder_->encodeHeaders(request_headers, end_stream); if (!end_stream) { request_.encoder_->getStream().addCallbacks(request_.stream_callbacks_); } + request_.encoder_->encodeHeaders(request_headers, end_stream); request_.stream_state_ = end_stream ? StreamState::Closed : StreamState::PendingDataOrTrailers; response_.stream_state_ = StreamState::PendingHeaders; } diff --git a/test/common/http/common.h b/test/common/http/common.h index e2c4d4a5e12c..9aa57ef87c8e 100644 --- a/test/common/http/common.h +++ b/test/common/http/common.h @@ -24,7 +24,7 @@ class CodecClientForTest : public Http::CodecClient { destroy_cb_(destroy_cb) { codec_.reset(codec); } - ~CodecClientForTest() { + ~CodecClientForTest() override { if (destroy_cb_) { destroy_cb_(this); } diff --git a/test/common/http/conn_manager_impl_test.cc b/test/common/http/conn_manager_impl_test.cc index ce4e8af46284..c635e59c6928 100644 --- a/test/common/http/conn_manager_impl_test.cc +++ b/test/common/http/conn_manager_impl_test.cc @@ -89,7 +89,7 @@ class HttpConnectionManagerImplTest : public testing::Test, public ConnectionMan EXPECT_CALL(response_encoder_, getStream()).Times(AtLeast(0)); } - ~HttpConnectionManagerImplTest() { + ~HttpConnectionManagerImplTest() override { filter_callbacks_.connection_.dispatcher_.clearDeferredDeleteList(); } diff --git a/test/common/http/header_map_impl_test.cc b/test/common/http/header_map_impl_test.cc index da9dc1cccf7b..5ec8f8ab5f28 100644 --- a/test/common/http/header_map_impl_test.cc +++ b/test/common/http/header_map_impl_test.cc @@ -2,6 +2,7 @@ #include #include "common/http/header_map_impl.h" +#include "common/http/header_utility.h" #include "test/test_common/printers.h" #include "test/test_common/utility.h" @@ -557,6 +558,24 @@ TEST(HeaderMapImplTest, DoubleInlineAdd) { } } +// Per https://github.com/envoyproxy/envoy/issues/7488 make sure we don't +// combine set-cookie headers +TEST(HeaderMapImplTest, DoubleCookieAdd) { + HeaderMapImpl headers; + const std::string foo("foo"); + const std::string bar("bar"); + const LowerCaseString& set_cookie = Http::Headers::get().SetCookie; + headers.addReference(set_cookie, foo); + headers.addReference(set_cookie, bar); + EXPECT_EQ(2UL, headers.size()); + + std::vector out; + Http::HeaderUtility::getAllOfHeader(headers, "set-cookie", out); + ASSERT_EQ(out.size(), 2); + ASSERT_EQ(out[0], "foo"); + ASSERT_EQ(out[1], "bar"); +} + TEST(HeaderMapImplTest, DoubleInlineSet) { HeaderMapImpl headers; headers.setReferenceKey(Headers::get().ContentType, "blah"); diff --git a/test/common/http/header_utility_test.cc b/test/common/http/header_utility_test.cc index b2fe1de01cd8..97f6b95b34b6 100644 --- a/test/common/http/header_utility_test.cc +++ b/test/common/http/header_utility_test.cc @@ -147,6 +147,26 @@ invert_match: true EXPECT_EQ(true, header_data.invert_match_); } +TEST(HeaderDataConstructorTest, GetAllOfHeader) { + TestHeaderMapImpl headers{{"foo", "val1"}, {"bar", "bar2"}, {"foo", "eep, bar"}, {"foo", ""}}; + + std::vector foo_out; + Http::HeaderUtility::getAllOfHeader(headers, "foo", foo_out); + ASSERT_EQ(foo_out.size(), 3); + ASSERT_EQ(foo_out[0], "val1"); + ASSERT_EQ(foo_out[1], "eep, bar"); + ASSERT_EQ(foo_out[2], ""); + + std::vector bar_out; + Http::HeaderUtility::getAllOfHeader(headers, "bar", bar_out); + ASSERT_EQ(bar_out.size(), 1); + ASSERT_EQ(bar_out[0], "bar2"); + + std::vector eep_out; + Http::HeaderUtility::getAllOfHeader(headers, "eep", eep_out); + ASSERT_EQ(eep_out.size(), 0); +} + TEST(MatchHeadersTest, MayMatchOneOrMoreRequestHeader) { TestHeaderMapImpl headers{{"some-header", "a"}, {"other-header", "b"}}; @@ -403,6 +423,25 @@ invert_match: true EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } +TEST(HeaderIsValidTest, InvalidHeaderValuesAreRejected) { + // ASCII values 1-31 are control characters (with the exception of ASCII + // values 9, 10, and 13 which are a horizontal tab, line feed, and carriage + // return, respectively), and are not valid in an HTTP header, per + // RFC 7230, section 3.2 + for (uint i = 0; i < 32; i++) { + if (i == 9) { + continue; + } + + EXPECT_FALSE(HeaderUtility::headerIsValid(std::string(1, i))); + } +} + +TEST(HeaderIsValidTest, ValidHeaderValuesAreAccepted) { + EXPECT_TRUE(HeaderUtility::headerIsValid("some-value")); + EXPECT_TRUE(HeaderUtility::headerIsValid("Some Other Value")); +} + TEST(HeaderAddTest, HeaderAdd) { TestHeaderMapImpl headers{{"myheader1", "123value"}}; TestHeaderMapImpl headers_to_add{{"myheader2", "456value"}}; diff --git a/test/common/http/http1/BUILD b/test/common/http/http1/BUILD index e685bff6f328..efee73f47d1b 100644 --- a/test/common/http/http1/BUILD +++ b/test/common/http/http1/BUILD @@ -21,7 +21,11 @@ envoy_cc_test( "//source/common/http/http1:codec_lib", "//test/mocks/buffer:buffer_mocks", "//test/mocks/http:http_mocks", + "//test/mocks/init:init_mocks", + "//test/mocks/local_info:local_info_mocks", "//test/mocks/network:network_mocks", + "//test/mocks/protobuf:protobuf_mocks", + "//test/mocks/thread_local:thread_local_mocks", "//test/mocks/upstream:upstream_mocks", ], ) diff --git a/test/common/http/http1/codec_impl_test.cc b/test/common/http/http1/codec_impl_test.cc index c65d0ba18cb3..fec552d6f3f8 100644 --- a/test/common/http/http1/codec_impl_test.cc +++ b/test/common/http/http1/codec_impl_test.cc @@ -8,11 +8,18 @@ #include "common/http/exception.h" #include "common/http/header_map_impl.h" #include "common/http/http1/codec_impl.h" +#include "common/runtime/runtime_impl.h" #include "test/mocks/buffer/mocks.h" #include "test/mocks/http/mocks.h" +#include "test/mocks/init/mocks.h" +#include "test/mocks/local_info/mocks.h" #include "test/mocks/network/mocks.h" +#include "test/mocks/protobuf/mocks.h" +#include "test/mocks/runtime/mocks.h" +#include "test/mocks/thread_local/mocks.h" #include "test/test_common/printers.h" +#include "test/test_common/utility.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -30,6 +37,17 @@ namespace Http1 { class Http1ServerConnectionImplTest : public testing::Test { public: + Http1ServerConnectionImplTest() : api_(Api::createApiForTest()) { + envoy::config::bootstrap::v2::LayeredRuntime config; + config.add_layers()->mutable_admin_layer(); + + // Create a runtime loader, so that tests can manually manipulate runtime + // guarded features. + loader_ = std::make_unique(Runtime::LoaderPtr{ + new Runtime::LoaderImpl(dispatcher_, tls_, config, local_info_, init_manager_, store_, + generator_, validation_visitor_, *api_)}); + } + void initialize() { codec_ = std::make_unique(connection_, callbacks_, codec_settings_, max_request_headers_kb_); @@ -46,6 +64,15 @@ class Http1ServerConnectionImplTest : public testing::Test { protected: uint32_t max_request_headers_kb_{Http::DEFAULT_MAX_REQUEST_HEADERS_KB}; + Event::MockDispatcher dispatcher_; + NiceMock tls_; + Stats::IsolatedStoreImpl store_; + Runtime::MockRandomGenerator generator_; + Api::ApiPtr api_; + NiceMock local_info_; + Init::MockManager init_manager_; + NiceMock validation_visitor_; + std::unique_ptr loader_; }; void Http1ServerConnectionImplTest::expect400(Protocol p, bool allow_absolute_url, @@ -208,6 +235,8 @@ TEST_F(Http1ServerConnectionImplTest, Http11AbsolutePath2) { } TEST_F(Http1ServerConnectionImplTest, Http11AbsolutePathWithPort) { + initialize(); + TestHeaderMapImpl expected_headers{ {":authority", "www.somewhere.com:4532"}, {":path", "/foo/bar"}, {":method", "GET"}}; Buffer::OwnedImpl buffer( @@ -333,6 +362,43 @@ TEST_F(Http1ServerConnectionImplTest, HostHeaderTranslation) { EXPECT_EQ(0U, buffer.length()); } +// Ensures that requests with invalid HTTP header values are not rejected +// when the runtime guard is not enabled for the feature. +TEST_F(Http1ServerConnectionImplTest, HeaderInvalidCharsRuntimeGuard) { + // When the runtime-guarded feature is NOT enabled, invalid header values + // should be accepted by the codec. + Runtime::LoaderSingleton::getExisting()->mergeValues( + {{"envoy.reloadable_features.strict_header_validation", "false"}}); + + initialize(); + + Http::MockStreamDecoder decoder; + EXPECT_CALL(callbacks_, newStream(_, _)).WillOnce(ReturnRef(decoder)); + + Buffer::OwnedImpl buffer( + absl::StrCat("GET / HTTP/1.1\r\nHOST: h.com\r\nfoo: ", std::string(1, 3), "\r\n")); + codec_->dispatch(buffer); +} + +// Ensures that requests with invalid HTTP header values are properly rejected +// when the runtime guard is enabled for the feature. +TEST_F(Http1ServerConnectionImplTest, HeaderInvalidCharsRejection) { + // When the runtime-guarded feature is enabled, invalid header values + // should result in a rejection. + Runtime::LoaderSingleton::getExisting()->mergeValues( + {{"envoy.reloadable_features.strict_header_validation", "true"}}); + + initialize(); + + Http::MockStreamDecoder decoder; + EXPECT_CALL(callbacks_, newStream(_, _)).WillOnce(ReturnRef(decoder)); + + Buffer::OwnedImpl buffer( + absl::StrCat("GET / HTTP/1.1\r\nHOST: h.com\r\nfoo: ", std::string(1, 3), "\r\n")); + EXPECT_THROW_WITH_MESSAGE(codec_->dispatch(buffer), CodecProtocolException, + "http/1.1 protocol error: header value contains invalid chars"); +} + // Regression test for http-parser allowing embedded NULs in header values, // verify we reject them. TEST_F(Http1ServerConnectionImplTest, HeaderEmbeddedNulRejection) { @@ -784,11 +850,32 @@ TEST_F(Http1ServerConnectionImplTest, WatermarkTest) { class Http1ClientConnectionImplTest : public testing::Test { public: + Http1ClientConnectionImplTest() : api_(Api::createApiForTest()) { + envoy::config::bootstrap::v2::LayeredRuntime config; + + // Create a runtime loader, so that tests can manually manipulate runtime + // guarded features. + loader_ = std::make_unique(Runtime::LoaderPtr{ + new Runtime::LoaderImpl(dispatcher_, tls_, config, local_info_, init_manager_, store_, + generator_, validation_visitor_, *api_)}); + } + void initialize() { codec_ = std::make_unique(connection_, callbacks_); } NiceMock connection_; NiceMock callbacks_; std::unique_ptr codec_; + +protected: + Event::MockDispatcher dispatcher_; + NiceMock tls_; + Stats::IsolatedStoreImpl store_; + Runtime::MockRandomGenerator generator_; + Api::ApiPtr api_; + NiceMock local_info_; + Init::MockManager init_manager_; + NiceMock validation_visitor_; + std::unique_ptr loader_; }; TEST_F(Http1ClientConnectionImplTest, SimpleGet) { diff --git a/test/common/http/http1/conn_pool_test.cc b/test/common/http/http1/conn_pool_test.cc index 002aecc3ce52..adc3e10472f9 100644 --- a/test/common/http/http1/conn_pool_test.cc +++ b/test/common/http/http1/conn_pool_test.cc @@ -50,7 +50,7 @@ class ConnPoolImplForTest : public ConnPoolImpl { api_(Api::createApiForTest()), mock_dispatcher_(dispatcher), mock_upstream_ready_timer_(upstream_ready_timer) {} - ~ConnPoolImplForTest() { + ~ConnPoolImplForTest() override { EXPECT_EQ(0U, ready_clients_.size()); EXPECT_EQ(0U, busy_clients_.size()); EXPECT_EQ(0U, pending_requests_.size()); @@ -128,7 +128,7 @@ class Http1ConnPoolImplTest : public testing::Test { : upstream_ready_timer_(new NiceMock(&dispatcher_)), conn_pool_(dispatcher_, cluster_, upstream_ready_timer_) {} - ~Http1ConnPoolImplTest() { + ~Http1ConnPoolImplTest() override { EXPECT_TRUE(TestUtility::gaugesZeroed(cluster_->stats_store_.gauges())); } @@ -271,6 +271,38 @@ TEST_F(Http1ConnPoolImplTest, VerifyBufferLimits) { dispatcher_.clearDeferredDeleteList(); } +/** + * Verify that canceling pending connections within the callback works. + */ +TEST_F(Http1ConnPoolImplTest, VerifyCancelInCallback) { + Http::ConnectionPool::Cancellable* handle1{}; + // In this scenario, all connections must succeed, so when + // one fails, the others are canceled. + // Note: We rely on the fact that the implementation cancels the second request first, + // to simplify the test. + ConnPoolCallbacks callbacks1; + EXPECT_CALL(callbacks1.pool_failure_, ready()).Times(0); + ConnPoolCallbacks callbacks2; + EXPECT_CALL(callbacks2.pool_failure_, ready()).WillOnce(Invoke([&]() -> void { + handle1->cancel(); + })); + + NiceMock outer_decoder; + // Create the first client. + conn_pool_.expectClientCreate(); + handle1 = conn_pool_.newStream(outer_decoder, callbacks1); + ASSERT_NE(nullptr, handle1); + + // Create the second client. + Http::ConnectionPool::Cancellable* handle2 = conn_pool_.newStream(outer_decoder, callbacks2); + ASSERT_NE(nullptr, handle2); + + // Simulate connection failure. + EXPECT_CALL(conn_pool_, onClientDestroy()); + conn_pool_.test_clients_[0].connection_->raiseEvent(Network::ConnectionEvent::RemoteClose); + dispatcher_.clearDeferredDeleteList(); +} + /** * Tests a request that generates a new connection, completes, and then a second request that uses * the same connection. diff --git a/test/common/http/http2/conn_pool_test.cc b/test/common/http/http2/conn_pool_test.cc index b63d04c9afa5..9a17581301c7 100644 --- a/test/common/http/http2/conn_pool_test.cc +++ b/test/common/http/http2/conn_pool_test.cc @@ -67,7 +67,7 @@ class Http2ConnPoolImplTest : public testing::Test { : api_(Api::createApiForTest(stats_store_)), pool_(dispatcher_, host_, Upstream::ResourcePriority::Default, nullptr) {} - ~Http2ConnPoolImplTest() { + ~Http2ConnPoolImplTest() override { EXPECT_TRUE(TestUtility::gaugesZeroed(cluster_->stats_store_.gauges())); } diff --git a/test/common/network/address_impl_test.cc b/test/common/network/address_impl_test.cc index 27298c383d9d..fe4b75217a3d 100644 --- a/test/common/network/address_impl_test.cc +++ b/test/common/network/address_impl_test.cc @@ -144,6 +144,7 @@ TEST(Ipv4InstanceTest, SocketAddress) { Ipv4Instance address(&addr4); EXPECT_EQ("1.2.3.4:6502", address.asString()); + EXPECT_EQ("1.2.3.4:6502", address.asStringView()); EXPECT_EQ("1.2.3.4:6502", address.logicalName()); EXPECT_EQ(Type::Ip, address.type()); EXPECT_EQ("1.2.3.4", address.ip()->addressAsString()); @@ -157,6 +158,7 @@ TEST(Ipv4InstanceTest, SocketAddress) { TEST(Ipv4InstanceTest, AddressOnly) { Ipv4Instance address("3.4.5.6"); EXPECT_EQ("3.4.5.6:0", address.asString()); + EXPECT_EQ("3.4.5.6:0", address.asStringView()); EXPECT_EQ(Type::Ip, address.type()); EXPECT_EQ("3.4.5.6", address.ip()->addressAsString()); EXPECT_EQ(0U, address.ip()->port()); @@ -168,6 +170,7 @@ TEST(Ipv4InstanceTest, AddressOnly) { TEST(Ipv4InstanceTest, AddressAndPort) { Ipv4Instance address("127.0.0.1", 80); EXPECT_EQ("127.0.0.1:80", address.asString()); + EXPECT_EQ("127.0.0.1:80", address.asStringView()); EXPECT_EQ(Type::Ip, address.type()); EXPECT_EQ("127.0.0.1", address.ip()->addressAsString()); EXPECT_FALSE(address.ip()->isAnyAddress()); @@ -180,6 +183,7 @@ TEST(Ipv4InstanceTest, AddressAndPort) { TEST(Ipv4InstanceTest, PortOnly) { Ipv4Instance address(443); EXPECT_EQ("0.0.0.0:443", address.asString()); + EXPECT_EQ("0.0.0.0:443", address.asStringView()); EXPECT_EQ(Type::Ip, address.type()); EXPECT_EQ("0.0.0.0", address.ip()->addressAsString()); EXPECT_TRUE(address.ip()->isAnyAddress()); @@ -192,6 +196,7 @@ TEST(Ipv4InstanceTest, PortOnly) { TEST(Ipv4InstanceTest, Multicast) { Ipv4Instance address("230.0.0.1"); EXPECT_EQ("230.0.0.1:0", address.asString()); + EXPECT_EQ("230.0.0.1:0", address.asStringView()); EXPECT_EQ(Type::Ip, address.type()); EXPECT_EQ("230.0.0.1", address.ip()->addressAsString()); EXPECT_FALSE(address.ip()->isAnyAddress()); @@ -204,6 +209,7 @@ TEST(Ipv4InstanceTest, Multicast) { TEST(Ipv4InstanceTest, Broadcast) { Ipv4Instance address("255.255.255.255"); EXPECT_EQ("255.255.255.255:0", address.asString()); + EXPECT_EQ("255.255.255.255:0", address.asStringView()); EXPECT_EQ(Type::Ip, address.type()); EXPECT_EQ("255.255.255.255", address.ip()->addressAsString()); EXPECT_EQ(0U, address.ip()->port()); @@ -225,6 +231,7 @@ TEST(Ipv6InstanceTest, SocketAddress) { Ipv6Instance address(addr6); EXPECT_EQ("[1:23::ef]:32000", address.asString()); + EXPECT_EQ("[1:23::ef]:32000", address.asStringView()); EXPECT_EQ(Type::Ip, address.type()); EXPECT_EQ("1:23::ef", address.ip()->addressAsString()); EXPECT_FALSE(address.ip()->isAnyAddress()); @@ -238,6 +245,7 @@ TEST(Ipv6InstanceTest, SocketAddress) { TEST(Ipv6InstanceTest, AddressOnly) { Ipv6Instance address("2001:0db8:85a3:0000:0000:8a2e:0370:7334"); EXPECT_EQ("[2001:db8:85a3::8a2e:370:7334]:0", address.asString()); + EXPECT_EQ("[2001:db8:85a3::8a2e:370:7334]:0", address.asStringView()); EXPECT_EQ(Type::Ip, address.type()); EXPECT_EQ("2001:db8:85a3::8a2e:370:7334", address.ip()->addressAsString()); EXPECT_EQ(0U, address.ip()->port()); @@ -250,6 +258,7 @@ TEST(Ipv6InstanceTest, AddressOnly) { TEST(Ipv6InstanceTest, AddressAndPort) { Ipv6Instance address("::0001", 80); EXPECT_EQ("[::1]:80", address.asString()); + EXPECT_EQ("[::1]:80", address.asStringView()); EXPECT_EQ(Type::Ip, address.type()); EXPECT_EQ("::1", address.ip()->addressAsString()); EXPECT_EQ(80U, address.ip()->port()); @@ -261,6 +270,7 @@ TEST(Ipv6InstanceTest, AddressAndPort) { TEST(Ipv6InstanceTest, PortOnly) { Ipv6Instance address(443); EXPECT_EQ("[::]:443", address.asString()); + EXPECT_EQ("[::]:443", address.asStringView()); EXPECT_EQ(Type::Ip, address.type()); EXPECT_EQ("::", address.ip()->addressAsString()); EXPECT_TRUE(address.ip()->isAnyAddress()); @@ -273,6 +283,7 @@ TEST(Ipv6InstanceTest, PortOnly) { TEST(Ipv6InstanceTest, Multicast) { Ipv6Instance address("FF00::"); EXPECT_EQ("[ff00::]:0", address.asString()); + EXPECT_EQ("[ff00::]:0", address.asStringView()); EXPECT_EQ(Type::Ip, address.type()); EXPECT_EQ("ff00::", address.ip()->addressAsString()); EXPECT_FALSE(address.ip()->isAnyAddress()); @@ -311,6 +322,7 @@ TEST(PipeInstanceTest, AbstractNamespace) { #if defined(__linux__) PipeInstance address("@/foo"); EXPECT_EQ("@/foo", address.asString()); + EXPECT_EQ("@/foo", address.asStringView()); EXPECT_EQ(Type::Pipe, address.type()); EXPECT_EQ(nullptr, address.ip()); #else @@ -415,7 +427,7 @@ struct TestCase { TestCase() = default; TestCase(enum InstanceType type, const std::string& address, uint32_t port) : address_(address), type_(type), port_(port) {} - TestCase(const TestCase& rhs) : address_(rhs.address_), type_(rhs.type_), port_(rhs.port_) {} + TestCase(const TestCase& rhs) = default; bool operator==(const TestCase& rhs) { return (type_ == rhs.type_ && address_ == rhs.address_ && port_ == rhs.port_); diff --git a/test/common/network/connection_impl_test.cc b/test/common/network/connection_impl_test.cc index 8ddfb9f31535..0526b0ec97dc 100644 --- a/test/common/network/connection_impl_test.cc +++ b/test/common/network/connection_impl_test.cc @@ -1335,22 +1335,24 @@ TEST_P(ConnectionImplTest, DelayedCloseTimeoutNullStats) { class FakeReadFilter : public Network::ReadFilter { public: - FakeReadFilter() {} - ~FakeReadFilter() { + FakeReadFilter() = default; + ~FakeReadFilter() override { EXPECT_TRUE(callbacks_ != nullptr); // The purpose is to verify that when FilterManger is destructed, ConnectionSocketImpl is not // destructed, and ConnectionSocketImpl can still be accessed via ReadFilterCallbacks. EXPECT_TRUE(callbacks_->connection().state() != Network::Connection::State::Open); } - Network::FilterStatus onData(Buffer::Instance& data, bool) { + Network::FilterStatus onData(Buffer::Instance& data, bool) override { data.drain(data.length()); return Network::FilterStatus::Continue; } - Network::FilterStatus onNewConnection() { return Network::FilterStatus::Continue; } + Network::FilterStatus onNewConnection() override { return Network::FilterStatus::Continue; } - void initializeReadFilterCallbacks(ReadFilterCallbacks& callbacks) { callbacks_ = &callbacks; } + void initializeReadFilterCallbacks(ReadFilterCallbacks& callbacks) override { + callbacks_ = &callbacks; + } private: ReadFilterCallbacks* callbacks_{nullptr}; @@ -1380,7 +1382,7 @@ class MockTransportConnectionImplTest : public testing::Test { connection_->addConnectionCallbacks(callbacks_); } - ~MockTransportConnectionImplTest() { connection_->close(ConnectionCloseType::NoFlush); } + ~MockTransportConnectionImplTest() override { connection_->close(ConnectionCloseType::NoFlush); } // This may be invoked for doWrite() on the transport to simulate all the data // being written. diff --git a/test/common/network/dns_impl_test.cc b/test/common/network/dns_impl_test.cc index 2909bcb7f85f..eaa925b9e06a 100644 --- a/test/common/network/dns_impl_test.cc +++ b/test/common/network/dns_impl_test.cc @@ -362,13 +362,14 @@ class CustomInstance : public Address::Instance { CustomInstance(const std::string& address, uint32_t port) : instance_(address, port) { antagonistic_name_ = fmt::format("{}:borked_port_{}", address, port); } - ~CustomInstance() override {} + ~CustomInstance() override = default; // Address::Instance bool operator==(const Address::Instance& rhs) const override { return asString() == rhs.asString(); } const std::string& asString() const override { return antagonistic_name_; } + absl::string_view asStringView() const override { return antagonistic_name_; } const std::string& logicalName() const override { return antagonistic_name_; } Api::SysCallIntResult bind(int fd) const override { return instance_.bind(fd); } Api::SysCallIntResult connect(int fd) const override { return instance_.connect(fd); } diff --git a/test/common/network/filter_manager_impl_test.cc b/test/common/network/filter_manager_impl_test.cc index cccbac597e73..f713a79a63e3 100644 --- a/test/common/network/filter_manager_impl_test.cc +++ b/test/common/network/filter_manager_impl_test.cc @@ -56,7 +56,7 @@ class NetworkFilterManagerTest : public testing::Test { class LocalMockFilter : public MockFilter { public: - ~LocalMockFilter() { + ~LocalMockFilter() override { // Make sure the upstream host is still valid in the filter destructor. callbacks_->upstreamHost()->address(); } diff --git a/test/common/router/config_impl_test.cc b/test/common/router/config_impl_test.cc index 20dba970a5c7..5af81cbc1ff9 100644 --- a/test/common/router/config_impl_test.cc +++ b/test/common/router/config_impl_test.cc @@ -2319,7 +2319,7 @@ TEST_F(RouteMatcherTest, Retry) { retry_policy: per_try_timeout: 1s num_retries: 3 - retry_on: 5xx,gateway-error,connect-failure + retry_on: 5xx,gateway-error,connect-failure,reset )EOF"; TestConfigImpl config(parseRouteConfigurationFromV2Yaml(yaml), factory_context_, true); @@ -2363,7 +2363,7 @@ TEST_F(RouteMatcherTest, Retry) { ->retryPolicy() .numRetries()); EXPECT_EQ(RetryPolicy::RETRY_ON_CONNECT_FAILURE | RetryPolicy::RETRY_ON_5XX | - RetryPolicy::RETRY_ON_GATEWAY_ERROR, + RetryPolicy::RETRY_ON_GATEWAY_ERROR | RetryPolicy::RETRY_ON_RESET, config.route(genHeaders("www.lyft.com", "/", "GET"), 0) ->routeEntry() ->retryPolicy() @@ -2376,7 +2376,7 @@ name: RetryVirtualHostLevel virtual_hosts: - domains: [www.lyft.com] name: www - retry_policy: {num_retries: 3, per_try_timeout: 1s, retry_on: '5xx,gateway-error,connect-failure'} + retry_policy: {num_retries: 3, per_try_timeout: 1s, retry_on: '5xx,gateway-error,connect-failure,reset'} routes: - match: {prefix: /foo} route: @@ -2417,7 +2417,7 @@ name: RetryVirtualHostLevel ->retryPolicy() .numRetries()); EXPECT_EQ(RetryPolicy::RETRY_ON_CONNECT_FAILURE | RetryPolicy::RETRY_ON_5XX | - RetryPolicy::RETRY_ON_GATEWAY_ERROR, + RetryPolicy::RETRY_ON_GATEWAY_ERROR | RetryPolicy::RETRY_ON_RESET, config.route(genHeaders("www.lyft.com", "/bar", "GET"), 0) ->routeEntry() ->retryPolicy() @@ -2432,7 +2432,7 @@ name: RetryVirtualHostLevel ->retryPolicy() .numRetries()); EXPECT_EQ(RetryPolicy::RETRY_ON_CONNECT_FAILURE | RetryPolicy::RETRY_ON_5XX | - RetryPolicy::RETRY_ON_GATEWAY_ERROR, + RetryPolicy::RETRY_ON_GATEWAY_ERROR | RetryPolicy::RETRY_ON_RESET, config.route(genHeaders("www.lyft.com", "/", "GET"), 0) ->routeEntry() ->retryPolicy() @@ -3521,10 +3521,10 @@ struct Baz : public Envoy::Config::TypedMetadata::Object { }; class BazFactory : public HttpRouteTypedMetadataFactory { public: - const std::string name() const { return "baz"; } + const std::string name() const override { return "baz"; } // Returns nullptr (conversion failure) if d is empty. std::unique_ptr - parse(const ProtobufWkt::Struct& d) const { + parse(const ProtobufWkt::Struct& d) const override { if (d.fields().find("name") != d.fields().end()) { return std::make_unique(d.fields().at("name").string_value()); } diff --git a/test/common/router/header_formatter_test.cc b/test/common/router/header_formatter_test.cc index e0820fedf79e..3ab5ead740d7 100644 --- a/test/common/router/header_formatter_test.cc +++ b/test/common/router/header_formatter_test.cc @@ -1068,6 +1068,14 @@ match: { prefix: "/new_endpoint" } key: "x-request-start-default" value: "%START_TIME%" append: true + - header: + key: "set-cookie" + value: "foo" + - header: + key: "set-cookie" + value: "bar" + append: true + response_headers_to_remove: ["x-nope"] )EOF"; @@ -1097,6 +1105,15 @@ response_headers_to_remove: ["x-nope"] EXPECT_TRUE(header_map.has("x-request-start-range")); EXPECT_EQ("123456000, 1, 12, 123, 1234, 12345, 123456, 1234560, 12345600, 123456000", header_map.get_("x-request-start-range")); + EXPECT_EQ("foo", header_map.get_("set-cookie")); + + // Per https://github.com/envoyproxy/envoy/issues/7488 make sure we don't + // combine set-cookie headers + std::vector out; + Http::HeaderUtility::getAllOfHeader(header_map, "set-cookie", out); + ASSERT_EQ(out.size(), 2); + ASSERT_EQ(out[0], "foo"); + ASSERT_EQ(out[1], "bar"); } TEST(HeaderParserTest, EvaluateRequestHeadersRemoveBeforeAdd) { diff --git a/test/common/router/header_parser_corpus/clusterfuzz-testcase-header_parser_fuzz_test-5163306626580480 b/test/common/router/header_parser_corpus/clusterfuzz-testcase-header_parser_fuzz_test-5163306626580480 new file mode 100644 index 000000000000..57041ba39771 --- /dev/null +++ b/test/common/router/header_parser_corpus/clusterfuzz-testcase-header_parser_fuzz_test-5163306626580480 @@ -0,0 +1,80 @@ +headers_to_add { + header { + key: "P" + value: "%PER_REQUEST_STATE(oB]$T)%" + } +} +headers_to_add { + header { + key: "A" + value: "%START_TIME(B%444ssa4%s4%>TME(B%128sY$T_)%" + } +} +headers_to_add { + header { + key: "A" + value: "%PER_REQUEST_STATE(dB]$T)%" + } +} +headers_to_add { + header { + key: "\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177" + value: "%PER_REQUEST_STATE(dB]$T)%" + } + append { + value: true + } +} +headers_to_add { + header { + key: "]" + value: "%UPSTREAM_METADATA([\"\", \"\"])%" + } +} +stream_info { + dynamic_metadata { + filter_metadata { + key: "\000\000{\000+p" + value { + } + } + filter_metadata { + key: "\000}" + value { + } + } + filter_metadata { + key: "\000}" + value { + } + } + filter_metadata { + key: "K" + value { + fields { + key: "" + value { + } + } + } + } + } + upstream_metadata { + filter_metadata { + key: "" + value { + fields { + key: "" + value { + string_value: "c\000\000\000\000\000\000\000" + } + } + } + } + filter_metadata { + key: "-" + value { + } + } + } +} diff --git a/test/common/router/rds_impl_test.cc b/test/common/router/rds_impl_test.cc index daa93436b370..303589eb9750 100644 --- a/test/common/router/rds_impl_test.cc +++ b/test/common/router/rds_impl_test.cc @@ -75,7 +75,7 @@ class RdsImplTest : public RdsTestBase { route_config_provider_manager_ = std::make_unique(factory_context_.admin_); } - ~RdsImplTest() { factory_context_.thread_local_.shutdownThread(); } + ~RdsImplTest() override { factory_context_.thread_local_.shutdownThread(); } void setup() { const std::string config_json = R"EOF( @@ -276,7 +276,9 @@ class RouteConfigProviderManagerImplTest : public RdsTestBase { std::make_unique(factory_context_.admin_); } - ~RouteConfigProviderManagerImplTest() { factory_context_.thread_local_.shutdownThread(); } + ~RouteConfigProviderManagerImplTest() override { + factory_context_.thread_local_.shutdownThread(); + } envoy::config::filter::network::http_connection_manager::v2::Rds rds_; std::unique_ptr route_config_provider_manager_; diff --git a/test/common/router/retry_state_impl_test.cc b/test/common/router/retry_state_impl_test.cc index 415fa5b32ec2..7650fd5a3e54 100644 --- a/test/common/router/retry_state_impl_test.cc +++ b/test/common/router/retry_state_impl_test.cc @@ -412,6 +412,19 @@ TEST_F(RouterRetryStateImplTest, RetriableStatusCodesHeader) { } } +TEST_F(RouterRetryStateImplTest, PolicyResetRemoteReset) { + Http::TestHeaderMapImpl request_headers{{"x-envoy-retry-on", "reset"}}; + setup(request_headers); + EXPECT_TRUE(state_->enabled()); + + expectTimerCreateAndEnable(); + EXPECT_EQ(RetryStatus::Yes, state_->shouldRetryReset(remote_reset_, callback_)); + EXPECT_CALL(callback_ready_, ready()); + retry_timer_->callback_(); + + EXPECT_EQ(RetryStatus::NoRetryLimitExceeded, state_->shouldRetryReset(remote_reset_, callback_)); +} + TEST_F(RouterRetryStateImplTest, RouteConfigNoHeaderConfig) { policy_.num_retries_ = 1; policy_.retry_on_ = RetryPolicy::RETRY_ON_CONNECT_FAILURE; diff --git a/test/common/router/router_test.cc b/test/common/router/router_test.cc index 23aa2817d88f..b4d39e204140 100644 --- a/test/common/router/router_test.cc +++ b/test/common/router/router_test.cc @@ -33,6 +33,7 @@ #include "gtest/gtest.h" using testing::_; +using testing::AnyNumber; using testing::AssertionFailure; using testing::AssertionResult; using testing::AssertionSuccess; @@ -98,6 +99,9 @@ class RouterTestBase : public testing::Test { // Make the "system time" non-zero, because 0 is considered invalid by DateUtil. test_time_.setMonotonicTime(std::chrono::milliseconds(50)); + + // Allow any number of setTrackedObject calls for the dispatcher strict mock. + EXPECT_CALL(callbacks_.dispatcher_, setTrackedObject(_)).Times(AnyNumber()); } void expectResponseTimerCreate() { @@ -1292,10 +1296,13 @@ TEST_F(RouterTest, GrpcOk) { HttpTestUtility::addDefaultHeaders(headers); router_.decodeHeaders(headers, true); + EXPECT_CALL(callbacks_.dispatcher_, setTrackedObject(_)).Times(2); Http::HeaderMapPtr response_headers(new Http::TestHeaderMapImpl{{":status", "200"}}); EXPECT_CALL(cm_.conn_pool_.host_->outlier_detector_, putHttpResponseCode(200)); response_decoder->decodeHeaders(std::move(response_headers), false); EXPECT_TRUE(verifyHostUpstreamStats(0, 0)); + + EXPECT_CALL(callbacks_.dispatcher_, setTrackedObject(_)).Times(2); Http::HeaderMapPtr response_trailers(new Http::TestHeaderMapImpl{{"grpc-status", "0"}}); response_decoder->decodeTrailers(std::move(response_trailers)); EXPECT_TRUE(verifyHostUpstreamStats(1, 0)); @@ -1927,6 +1934,7 @@ TEST_F(RouterTest, RetryRequestNotComplete) { putResult(Upstream::Outlier::Result::LOCAL_ORIGIN_CONNECT_FAILED, _)); encoder1.stream_.resetStream(Http::StreamResetReason::RemoteReset); EXPECT_TRUE(verifyHostUpstreamStats(0, 1)); + EXPECT_EQ(1UL, stats_store_.counter("test.rq_retry_skipped_request_not_complete").value()); } // Two requests are sent (slow request + hedged retry) and then global timeout @@ -4388,8 +4396,8 @@ TEST(RouterFilterUtilityTest, StrictCheckValidHeaders) { {"x-envoy-upstream-rq-per-try-timeout-ms", "100"}, {"x-envoy-max-retries", "2"}, {"not-checked", "always passes"}, - {"x-envoy-retry-on", - "5xx,gateway-error,retriable-4xx,refused-stream,connect-failure,retriable-status-codes"}, + {"x-envoy-retry-on", "5xx,gateway-error,retriable-4xx,refused-stream,connect-failure," + "retriable-status-codes,reset"}, {"x-envoy-retry-grpc-on", "cancelled,internal,deadline-exceeded,resource-exhausted,unavailable"}, }; diff --git a/test/common/router/router_upstream_log_test.cc b/test/common/router/router_upstream_log_test.cc index 17e9a4c978d1..ce4574fe9358 100644 --- a/test/common/router/router_upstream_log_test.cc +++ b/test/common/router/router_upstream_log_test.cc @@ -91,6 +91,7 @@ class RouterUpstreamLogTest : public testing::Test { router_proto)); router_.reset(new TestFilter(*config_)); router_->setDecoderFilterCallbacks(callbacks_); + EXPECT_CALL(callbacks_.dispatcher_, setTrackedObject(_)).Times(testing::AnyNumber()); upstream_locality_.set_zone("to_az"); diff --git a/test/common/runtime/runtime_impl_test.cc b/test/common/runtime/runtime_impl_test.cc index cb73ae6e73bf..41f80ba3b360 100644 --- a/test/common/runtime/runtime_impl_test.cc +++ b/test/common/runtime/runtime_impl_test.cc @@ -155,7 +155,7 @@ TEST_F(DiskLoaderImplTest, All) { EXPECT_EQ(123UL, loader_->snapshot().getInteger("file4", 1)); bool value; - SnapshotImpl* snapshot = reinterpret_cast(&loader_->snapshot()); + const SnapshotImpl* snapshot = reinterpret_cast(&loader_->snapshot()); // Validate that the layer name is set properly for static layers. EXPECT_EQ("base", snapshot->getLayers()[0]->name()); @@ -538,7 +538,7 @@ TEST_F(StaticLoaderImplTest, ProtoParsing) { // Boolean getting. bool value; - SnapshotImpl* snapshot = reinterpret_cast(&loader_->snapshot()); + const SnapshotImpl* snapshot = reinterpret_cast(&loader_->snapshot()); EXPECT_EQ(true, snapshot->getBoolean("file11", value)); EXPECT_EQ(true, value); @@ -610,6 +610,63 @@ TEST_F(StaticLoaderImplTest, ProtoParsing) { EXPECT_EQ(2, store_.gauge("runtime.num_layers", Stats::Gauge::ImportMode::NeverImport).value()); } +TEST_F(StaticLoaderImplTest, RuntimeFromNonWorkerThreads) { + // Force the thread to be considered a non-worker thread. + tls_.registered_ = false; + setup(); + + // Set up foo -> bar + loader_->mergeValues({{"foo", "bar"}}); + EXPECT_EQ("bar", loader_->threadsafeSnapshot()->get("foo")); + const Snapshot* original_snapshot_pointer = loader_->threadsafeSnapshot().get(); + + // Now set up a test thread which verifies foo -> bar + // + // Then change foo and make sure the test thread picks up the change. + bool read_bar = false; + bool updated_eep = false; + Thread::MutexBasicLockable mutex; + Thread::CondVar foo_read; + Thread::CondVar foo_changed; + const Snapshot* original_thread_snapshot_pointer = nullptr; + auto thread = Thread::threadFactoryForTest().createThread([&]() { + { + Thread::LockGuard lock(mutex); + EXPECT_EQ("bar", loader_->threadsafeSnapshot()->get("foo")); + read_bar = true; + original_thread_snapshot_pointer = loader_->threadsafeSnapshot().get(); + EXPECT_EQ(original_thread_snapshot_pointer, loader_->threadsafeSnapshot().get()); + foo_read.notifyOne(); + } + + { + Thread::LockGuard lock(mutex); + if (!updated_eep) { + foo_changed.wait(mutex); + } + EXPECT_EQ("eep", loader_->threadsafeSnapshot()->get("foo")); + } + }); + + { + Thread::LockGuard lock(mutex); + if (!read_bar) { + foo_read.wait(mutex); + } + loader_->mergeValues({{"foo", "eep"}}); + updated_eep = true; + } + + { + Thread::LockGuard lock(mutex); + foo_changed.notifyOne(); + EXPECT_EQ("eep", loader_->threadsafeSnapshot()->get("foo")); + } + + thread->join(); + EXPECT_EQ(original_thread_snapshot_pointer, original_snapshot_pointer); +} + class DiskLayerTest : public testing::Test { protected: DiskLayerTest() : api_(Api::createApiForTest()) {} diff --git a/test/common/secret/BUILD b/test/common/secret/BUILD index 2a354658e4d3..19712797f54a 100644 --- a/test/common/secret/BUILD +++ b/test/common/secret/BUILD @@ -22,6 +22,7 @@ envoy_cc_test( "//test/mocks/server:server_mocks", "//test/test_common:environment_lib", "//test/test_common:registry_lib", + "//test/test_common:simulated_time_system_lib", "//test/test_common:utility_lib", ], ) diff --git a/test/common/secret/sds_api_test.cc b/test/common/secret/sds_api_test.cc index 7a2d0abe50d9..780211864399 100644 --- a/test/common/secret/sds_api_test.cc +++ b/test/common/secret/sds_api_test.cc @@ -42,6 +42,7 @@ class SdsApiTest : public testing::Test { NiceMock subscription_factory_; NiceMock init_manager_; NiceMock init_watcher_; + Event::GlobalTimeSystem time_system_; Init::TargetHandlePtr init_target_handle_; }; @@ -52,8 +53,8 @@ TEST_F(SdsApiTest, BasicTest) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; - TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, validation_visitor_, - server.stats(), init_manager_, []() {}); + TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, time_system_, + validation_visitor_, server.stats(), init_manager_, []() {}); initialize(); } @@ -62,8 +63,8 @@ TEST_F(SdsApiTest, BasicTest) { TEST_F(SdsApiTest, DynamicTlsCertificateUpdateSuccess) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; - TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, validation_visitor_, - server.stats(), init_manager_, []() {}); + TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, time_system_, + validation_visitor_, server.stats(), init_manager_, []() {}); initialize(); NiceMock secret_callback; auto handle = @@ -104,9 +105,9 @@ class PartialMockSds : public SdsApi { public: PartialMockSds(NiceMock& server, NiceMock& init_manager, envoy::api::v2::core::ConfigSource& config_source, - Config::SubscriptionFactory& subscription_factory) - : SdsApi(config_source, "abc.com", subscription_factory, validation_visitor_, server.stats(), - init_manager, []() {}) {} + Config::SubscriptionFactory& subscription_factory, TimeSource& time_source) + : SdsApi(config_source, "abc.com", subscription_factory, time_source, validation_visitor_, + server.stats(), init_manager, []() {}) {} MOCK_METHOD2(onConfigUpdate, void(const Protobuf::RepeatedPtrField&, const std::string&)); @@ -137,7 +138,8 @@ TEST_F(SdsApiTest, Delta) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; - PartialMockSds sds(server, init_manager_, config_source, subscription_factory_); + Event::GlobalTimeSystem time_system; + PartialMockSds sds(server, init_manager_, config_source, subscription_factory_, time_system); initialize(); EXPECT_CALL(sds, onConfigUpdate(RepeatedProtoEq(for_matching), "version1")); subscription_factory_.callbacks_->onConfigUpdate(resources, {}, "ignored"); @@ -155,8 +157,8 @@ TEST_F(SdsApiTest, Delta) { TEST_F(SdsApiTest, DeltaUpdateSuccess) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; - TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, validation_visitor_, - server.stats(), init_manager_, []() {}); + TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, time_system_, + validation_visitor_, server.stats(), init_manager_, []() {}); NiceMock secret_callback; auto handle = @@ -200,8 +202,8 @@ TEST_F(SdsApiTest, DynamicCertificateValidationContextUpdateSuccess) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; CertificateValidationContextSdsApi sds_api(config_source, "abc.com", subscription_factory_, - validation_visitor_, server.stats(), init_manager_, - []() {}); + time_system_, validation_visitor_, server.stats(), + init_manager_, []() {}); NiceMock secret_callback; auto handle = @@ -240,8 +242,8 @@ class CvcValidationCallback { class MockCvcValidationCallback : public CvcValidationCallback { public: - MockCvcValidationCallback() {} - ~MockCvcValidationCallback() {} + MockCvcValidationCallback() = default; + ~MockCvcValidationCallback() override = default; MOCK_METHOD1(validateCvc, void(const envoy::api::v2::auth::CertificateValidationContext&)); }; @@ -252,8 +254,8 @@ TEST_F(SdsApiTest, DefaultCertificateValidationContextTest) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; CertificateValidationContextSdsApi sds_api(config_source, "abc.com", subscription_factory_, - validation_visitor_, server.stats(), init_manager_, - []() {}); + time_system_, validation_visitor_, server.stats(), + init_manager_, []() {}); NiceMock secret_callback; auto handle = @@ -321,8 +323,8 @@ TEST_F(SdsApiTest, DefaultCertificateValidationContextTest) { TEST_F(SdsApiTest, EmptyResource) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; - TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, validation_visitor_, - server.stats(), init_manager_, []() {}); + TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, time_system_, + validation_visitor_, server.stats(), init_manager_, []() {}); Protobuf::RepeatedPtrField secret_resources; @@ -336,8 +338,8 @@ TEST_F(SdsApiTest, EmptyResource) { TEST_F(SdsApiTest, SecretUpdateWrongSize) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; - TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, validation_visitor_, - server.stats(), init_manager_, []() {}); + TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, time_system_, + validation_visitor_, server.stats(), init_manager_, []() {}); std::string yaml = R"EOF( @@ -365,8 +367,8 @@ TEST_F(SdsApiTest, SecretUpdateWrongSize) { TEST_F(SdsApiTest, SecretUpdateWrongSecretName) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; - TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, validation_visitor_, - server.stats(), init_manager_, []() {}); + TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, time_system_, + validation_visitor_, server.stats(), init_manager_, []() {}); std::string yaml = R"EOF( diff --git a/test/common/secret/secret_manager_impl_test.cc b/test/common/secret/secret_manager_impl_test.cc index 95daa82d0d78..b3a6105fb11f 100644 --- a/test/common/secret/secret_manager_impl_test.cc +++ b/test/common/secret/secret_manager_impl_test.cc @@ -1,15 +1,19 @@ #include +#include "envoy/admin/v2alpha/config_dump.pb.h" #include "envoy/api/v2/auth/cert.pb.h" #include "envoy/common/exception.h" +#include "common/common/logger.h" #include "common/secret/sds_api.h" #include "common/secret/secret_manager_impl.h" #include "common/ssl/certificate_validation_context_config_impl.h" #include "common/ssl/tls_certificate_config_impl.h" +#include "test/mocks/event/mocks.h" #include "test/mocks/server/mocks.h" #include "test/test_common/environment.h" +#include "test/test_common/simulated_time_system.h" #include "test/test_common/utility.h" #include "gmock/gmock.h" @@ -22,11 +26,24 @@ namespace Envoy { namespace Secret { namespace { -class SecretManagerImplTest : public testing::Test { +class SecretManagerImplTest : public testing::Test, public Logger::Loggable { protected: SecretManagerImplTest() : api_(Api::createApiForTest()) {} + void checkConfigDump(const std::string& expected_dump_yaml) { + auto message_ptr = config_tracker_.config_tracker_callbacks_["secrets"](); + const auto& secrets_config_dump = + dynamic_cast(*message_ptr); + envoy::admin::v2alpha::SecretsConfigDump expected_secrets_config_dump; + TestUtility::loadFromYaml(expected_dump_yaml, expected_secrets_config_dump); + EXPECT_EQ(expected_secrets_config_dump.DebugString(), secrets_config_dump.DebugString()); + } + + void setupSecretProviderContext() {} + Api::ApiPtr api_; + testing::NiceMock config_tracker_; + Event::SimulatedTimeSystem time_system_; }; // Validate that secret manager adds static TLS certificate secret successfully. @@ -42,7 +59,7 @@ name: "abc.com" filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/selfsigned_key.pem" )EOF"; TestUtility::loadFromYaml(TestEnvironment::substitute(yaml), secret_config); - std::unique_ptr secret_manager(new SecretManagerImpl()); + std::unique_ptr secret_manager(new SecretManagerImpl(config_tracker_)); secret_manager->addStaticSecret(secret_config); ASSERT_EQ(secret_manager->findStaticTlsCertificateProvider("undefined"), nullptr); @@ -75,7 +92,7 @@ TEST_F(SecretManagerImplTest, DuplicateStaticTlsCertificateSecret) { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/selfsigned_key.pem" )EOF"; TestUtility::loadFromYaml(TestEnvironment::substitute(yaml), secret_config); - std::unique_ptr secret_manager(new SecretManagerImpl()); + std::unique_ptr secret_manager(new SecretManagerImpl(config_tracker_)); secret_manager->addStaticSecret(secret_config); ASSERT_NE(secret_manager->findStaticTlsCertificateProvider("abc.com"), nullptr); @@ -94,7 +111,7 @@ TEST_F(SecretManagerImplTest, CertificateValidationContextSecretLoadSuccess) { allow_expired_certificate: true )EOF"; TestUtility::loadFromYaml(TestEnvironment::substitute(yaml), secret_config); - std::unique_ptr secret_manager(new SecretManagerImpl()); + std::unique_ptr secret_manager(new SecretManagerImpl(config_tracker_)); secret_manager->addStaticSecret(secret_config); ASSERT_EQ(secret_manager->findStaticCertificateValidationContextProvider("undefined"), nullptr); @@ -119,7 +136,7 @@ TEST_F(SecretManagerImplTest, DuplicateStaticCertificateValidationContextSecret) allow_expired_certificate: true )EOF"; TestUtility::loadFromYaml(TestEnvironment::substitute(yaml), secret_config); - std::unique_ptr secret_manager(new SecretManagerImpl()); + std::unique_ptr secret_manager(new SecretManagerImpl(config_tracker_)); secret_manager->addStaticSecret(secret_config); ASSERT_NE(secret_manager->findStaticCertificateValidationContextProvider("abc.com"), nullptr); @@ -142,7 +159,7 @@ name: "abc.com" TestUtility::loadFromYaml(TestEnvironment::substitute(yaml), secret_config); - std::unique_ptr secret_manager(new SecretManagerImpl()); + std::unique_ptr secret_manager(new SecretManagerImpl(config_tracker_)); EXPECT_THROW_WITH_MESSAGE(secret_manager->addStaticSecret(secret_config), EnvoyException, "Secret type not implemented"); @@ -150,7 +167,7 @@ name: "abc.com" TEST_F(SecretManagerImplTest, SdsDynamicSecretUpdateSuccess) { Server::MockInstance server; - std::unique_ptr secret_manager(std::make_unique()); + std::unique_ptr secret_manager(new SecretManagerImpl(config_tracker_)); NiceMock secret_context; @@ -168,6 +185,7 @@ TEST_F(SecretManagerImplTest, SdsDynamicSecretUpdateSuccess) { })); EXPECT_CALL(secret_context, stats()).WillOnce(ReturnRef(stats)); EXPECT_CALL(secret_context, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(secret_context, dispatcher()).WillRepeatedly(ReturnRef(dispatcher)); EXPECT_CALL(secret_context, localInfo()).WillOnce(ReturnRef(local_info)); auto secret_provider = @@ -199,6 +217,352 @@ name: "abc.com" tls_config.privateKey()); } +TEST_F(SecretManagerImplTest, ConfigDumpHandler) { + Server::MockInstance server; + auto secret_manager = std::make_unique(config_tracker_); + time_system_.setSystemTime(std::chrono::milliseconds(1234567891234)); + + NiceMock secret_context; + + envoy::api::v2::core::ConfigSource config_source; + NiceMock local_info; + NiceMock dispatcher; + NiceMock random; + Stats::IsolatedStoreImpl stats; + NiceMock init_manager; + NiceMock init_watcher; + Init::TargetHandlePtr init_target_handle; + EXPECT_CALL(init_manager, add(_)) + .WillRepeatedly(Invoke([&init_target_handle](const Init::Target& target) { + init_target_handle = target.createHandle("test"); + })); + EXPECT_CALL(secret_context, stats()).WillRepeatedly(ReturnRef(stats)); + EXPECT_CALL(secret_context, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(secret_context, dispatcher()).WillRepeatedly(ReturnRef(dispatcher)); + EXPECT_CALL(secret_context, localInfo()).WillRepeatedly(ReturnRef(local_info)); + + auto secret_provider = + secret_manager->findOrCreateTlsCertificateProvider(config_source, "abc.com", secret_context); + const std::string yaml = + R"EOF( +name: "abc.com" +tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "DUMMY_INLINE_BYTES_FOR_PRIVATE_KEY" + password: + inline_string: "DUMMY_PASSWORD" +)EOF"; + envoy::api::v2::auth::Secret typed_secret; + TestUtility::loadFromYaml(TestEnvironment::substitute(yaml), typed_secret); + Protobuf::RepeatedPtrField secret_resources; + secret_resources.Add()->PackFrom(typed_secret); + init_target_handle->initialize(init_watcher); + secret_context.cluster_manager_.subscription_factory_.callbacks_->onConfigUpdate(secret_resources, + "keycert-v1"); + Ssl::TlsCertificateConfigImpl tls_config(*secret_provider->secret(), *api_); + EXPECT_EQ("DUMMY_INLINE_BYTES_FOR_CERT_CHAIN", tls_config.certificateChain()); + EXPECT_EQ("DUMMY_INLINE_BYTES_FOR_PRIVATE_KEY", tls_config.privateKey()); + EXPECT_EQ("DUMMY_PASSWORD", tls_config.password()); + + // Private key and password are removed. + const std::string expected_secrets_config_dump = R"EOF( +dynamic_active_secrets: +- name: "abc.com" + version_info: "keycert-v1" + last_updated: + seconds: 1234567891 + nanos: 234000000 + secret: + name: "abc.com" + tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "[redacted]" + password: + inline_string: "[redacted]" +)EOF"; + checkConfigDump(expected_secrets_config_dump); + + // Add a dynamic tls validation context provider. + time_system_.setSystemTime(std::chrono::milliseconds(1234567899000)); + auto context_secret_provider = secret_manager->findOrCreateCertificateValidationContextProvider( + config_source, "abc.com.validation", secret_context); + const std::string validation_yaml = R"EOF( +name: "abc.com.validation" +validation_context: + trusted_ca: + inline_string: "DUMMY_INLINE_STRING_TRUSTED_CA" +)EOF"; + TestUtility::loadFromYaml(TestEnvironment::substitute(validation_yaml), typed_secret); + secret_resources.Clear(); + secret_resources.Add()->PackFrom(typed_secret); + + init_target_handle->initialize(init_watcher); + secret_context.cluster_manager_.subscription_factory_.callbacks_->onConfigUpdate( + secret_resources, "validation-context-v1"); + Ssl::CertificateValidationContextConfigImpl cert_validation_context( + *context_secret_provider->secret(), *api_); + EXPECT_EQ("DUMMY_INLINE_STRING_TRUSTED_CA", cert_validation_context.caCert()); + const std::string updated_config_dump = R"EOF( +dynamic_active_secrets: +- name: "abc.com" + version_info: "keycert-v1" + last_updated: + seconds: 1234567891 + nanos: 234000000 + secret: + name: "abc.com" + tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "[redacted]" + password: + inline_string: "[redacted]" +- name: "abc.com.validation" + version_info: "validation-context-v1" + last_updated: + seconds: 1234567899 + secret: + name: "abc.com.validation" + validation_context: + trusted_ca: + inline_string: "DUMMY_INLINE_STRING_TRUSTED_CA" +)EOF"; + checkConfigDump(updated_config_dump); +} + +TEST_F(SecretManagerImplTest, ConfigDumpHandlerWarmingSecrets) { + Server::MockInstance server; + auto secret_manager = std::make_unique(config_tracker_); + time_system_.setSystemTime(std::chrono::milliseconds(1234567891234)); + + NiceMock secret_context; + + envoy::api::v2::core::ConfigSource config_source; + NiceMock local_info; + NiceMock dispatcher; + NiceMock random; + Stats::IsolatedStoreImpl stats; + NiceMock init_manager; + NiceMock init_watcher; + Init::TargetHandlePtr init_target_handle; + EXPECT_CALL(init_manager, add(_)) + .WillRepeatedly(Invoke([&init_target_handle](const Init::Target& target) { + init_target_handle = target.createHandle("test"); + })); + EXPECT_CALL(secret_context, stats()).WillRepeatedly(ReturnRef(stats)); + EXPECT_CALL(secret_context, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(secret_context, dispatcher()).WillRepeatedly(ReturnRef(dispatcher)); + EXPECT_CALL(secret_context, localInfo()).WillRepeatedly(ReturnRef(local_info)); + + auto secret_provider = + secret_manager->findOrCreateTlsCertificateProvider(config_source, "abc.com", secret_context); + const std::string expected_secrets_config_dump = R"EOF( +dynamic_warming_secrets: +- name: "abc.com" + version_info: "uninitialized" + last_updated: + seconds: 1234567891 + nanos: 234000000 + secret: + name: "abc.com" + )EOF"; + checkConfigDump(expected_secrets_config_dump); + + time_system_.setSystemTime(std::chrono::milliseconds(1234567899000)); + auto context_secret_provider = secret_manager->findOrCreateCertificateValidationContextProvider( + config_source, "abc.com.validation", secret_context); + init_target_handle->initialize(init_watcher); + const std::string updated_config_dump = R"EOF( +dynamic_warming_secrets: +- name: "abc.com" + version_info: "uninitialized" + last_updated: + seconds: 1234567891 + nanos: 234000000 + secret: + name: "abc.com" +- name: "abc.com.validation" + version_info: "uninitialized" + last_updated: + seconds: 1234567899 + secret: + name: "abc.com.validation" +)EOF"; + checkConfigDump(updated_config_dump); +} + +TEST_F(SecretManagerImplTest, ConfigDumpHandlerStaticSecrets) { + Server::MockInstance server; + auto secret_manager = std::make_unique(config_tracker_); + time_system_.setSystemTime(std::chrono::milliseconds(1234567891234)); + + NiceMock secret_context; + + envoy::api::v2::core::ConfigSource config_source; + NiceMock local_info; + NiceMock dispatcher; + NiceMock random; + Stats::IsolatedStoreImpl stats; + NiceMock init_manager; + NiceMock init_watcher; + Init::TargetHandlePtr init_target_handle; + EXPECT_CALL(init_manager, add(_)) + .WillRepeatedly(Invoke([&init_target_handle](const Init::Target& target) { + init_target_handle = target.createHandle("test"); + })); + EXPECT_CALL(secret_context, stats()).WillRepeatedly(ReturnRef(stats)); + EXPECT_CALL(secret_context, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(secret_context, dispatcher()).WillRepeatedly(ReturnRef(dispatcher)); + EXPECT_CALL(secret_context, localInfo()).WillRepeatedly(ReturnRef(local_info)); + + const std::string tls_certificate = + R"EOF( +name: "abc.com" +tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "DUMMY_INLINE_BYTES_FOR_PRIVATE_KEY" + password: + inline_string: "DUMMY_PASSWORD" +)EOF"; + envoy::api::v2::auth::Secret tls_cert_secret; + TestUtility::loadFromYaml(TestEnvironment::substitute(tls_certificate), tls_cert_secret); + secret_manager->addStaticSecret(tls_cert_secret); + TestUtility::loadFromYaml(TestEnvironment::substitute(R"EOF( +name: "abc.com.nopassword" +tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "DUMMY_INLINE_BYTES_FOR_PRIVATE_KEY" +)EOF"), + tls_cert_secret); + secret_manager->addStaticSecret(tls_cert_secret); + const std::string expected_config_dump = R"EOF( +static_secrets: +- name: "abc.com.nopassword" + secret: + name: "abc.com.nopassword" + tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "[redacted]" +- name: "abc.com" + secret: + name: "abc.com" + tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "[redacted]" + password: + inline_string: "[redacted]" +)EOF"; + checkConfigDump(expected_config_dump); +} + +TEST_F(SecretManagerImplTest, ConfigDumpNotRedactFilenamePrivateKey) { + Server::MockInstance server; + auto secret_manager = std::make_unique(config_tracker_); + time_system_.setSystemTime(std::chrono::milliseconds(1234567891234)); + NiceMock secret_context; + envoy::api::v2::core::ConfigSource config_source; + NiceMock local_info; + NiceMock dispatcher; + NiceMock random; + Stats::IsolatedStoreImpl stats; + NiceMock init_manager; + NiceMock init_watcher; + Init::TargetHandlePtr init_target_handle; + EXPECT_CALL(init_manager, add(_)) + .WillRepeatedly(Invoke([&init_target_handle](const Init::Target& target) { + init_target_handle = target.createHandle("test"); + })); + EXPECT_CALL(secret_context, stats()).WillRepeatedly(ReturnRef(stats)); + EXPECT_CALL(secret_context, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(secret_context, dispatcher()).WillRepeatedly(ReturnRef(dispatcher)); + EXPECT_CALL(secret_context, localInfo()).WillRepeatedly(ReturnRef(local_info)); + + const std::string tls_certificate = R"EOF( +name: "abc.com" +tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "DUMMY_INLINE_BYTES_FOR_PRIVATE_KEY" + password: + filename: "/etc/certs/password" +)EOF"; + envoy::api::v2::auth::Secret tls_cert_secret; + TestUtility::loadFromYaml(TestEnvironment::substitute(tls_certificate), tls_cert_secret); + secret_manager->addStaticSecret(tls_cert_secret); + const std::string expected_config_dump = R"EOF( +static_secrets: +- name: "abc.com" + secret: + name: "abc.com" + tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "[redacted]" + password: + filename: "/etc/certs/password" +)EOF"; + checkConfigDump(expected_config_dump); +} + +TEST_F(SecretManagerImplTest, ConfigDumpHandlerStaticValidationContext) { + Server::MockInstance server; + auto secret_manager = std::make_unique(config_tracker_); + time_system_.setSystemTime(std::chrono::milliseconds(1234567891234)); + NiceMock secret_context; + envoy::api::v2::core::ConfigSource config_source; + NiceMock local_info; + NiceMock dispatcher; + NiceMock random; + Stats::IsolatedStoreImpl stats; + NiceMock init_manager; + NiceMock init_watcher; + Init::TargetHandlePtr init_target_handle; + EXPECT_CALL(init_manager, add(_)) + .WillRepeatedly(Invoke([&init_target_handle](const Init::Target& target) { + init_target_handle = target.createHandle("test"); + })); + EXPECT_CALL(secret_context, stats()).WillRepeatedly(ReturnRef(stats)); + EXPECT_CALL(secret_context, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(secret_context, dispatcher()).WillRepeatedly(ReturnRef(dispatcher)); + EXPECT_CALL(secret_context, localInfo()).WillRepeatedly(ReturnRef(local_info)); + + const std::string validation_context = + R"EOF( +name: "abc.com.validation" +validation_context: + trusted_ca: + inline_string: "DUMMY_INLINE_STRING_TRUSTED_CA" +)EOF"; + envoy::api::v2::auth::Secret validation_secret; + TestUtility::loadFromYaml(TestEnvironment::substitute(validation_context), validation_secret); + secret_manager->addStaticSecret(validation_secret); + const std::string expected_config_dump = R"EOF( +static_secrets: +- name: "abc.com.validation" + secret: + name: "abc.com.validation" + validation_context: + trusted_ca: + inline_string: "DUMMY_INLINE_STRING_TRUSTED_CA" +)EOF"; + checkConfigDump(expected_config_dump); +} + } // namespace } // namespace Secret } // namespace Envoy diff --git a/test/common/signal/signals_test.cc b/test/common/signal/signals_test.cc index 72b28c7bbf8b..98753f047d0f 100644 --- a/test/common/signal/signals_test.cc +++ b/test/common/signal/signals_test.cc @@ -1,6 +1,7 @@ -#include #include +#include + #include "common/signal/signal_action.h" #include "test/test_common/utility.h" @@ -35,7 +36,7 @@ TEST(SignalsDeathTest, InvalidAddressDeathTest) { } class TestFatalErrorHandler : public FatalErrorHandlerInterface { - virtual void onFatalError() const override { std::cerr << "HERE!"; } + void onFatalError() const override { std::cerr << "HERE!"; } }; TEST(SignalsDeathTest, RegisteredHandlerTest) { diff --git a/test/common/singleton/manager_impl_test.cc b/test/common/singleton/manager_impl_test.cc index 14b3d9eacad2..95b3b768a151 100644 --- a/test/common/singleton/manager_impl_test.cc +++ b/test/common/singleton/manager_impl_test.cc @@ -29,7 +29,7 @@ static Registry::RegisterFactory +#include "common/stats/allocator_impl.h" #include "common/stats/fake_symbol_table_impl.h" -#include "common/stats/heap_stat_data.h" #include "test/test_common/logging.h" @@ -11,10 +11,10 @@ namespace Envoy { namespace Stats { namespace { -class HeapAllocatorTest : public testing::Test { +class AllocatorImplTest : public testing::Test { protected: - HeapAllocatorTest() : alloc_(symbol_table_), pool_(symbol_table_) {} - ~HeapAllocatorTest() { clearStorage(); } + AllocatorImplTest() : alloc_(symbol_table_), pool_(symbol_table_) {} + ~AllocatorImplTest() override { clearStorage(); } StatNameStorage makeStatStorage(absl::string_view name) { return StatNameStorage(name, symbol_table_); @@ -28,12 +28,12 @@ class HeapAllocatorTest : public testing::Test { } FakeSymbolTableImpl symbol_table_; - HeapStatDataAllocator alloc_; + AllocatorImpl alloc_; StatNamePool pool_; }; // Allocate 2 counters of the same name, and you'll get the same object. -TEST_F(HeapAllocatorTest, CountersWithSameName) { +TEST_F(AllocatorImplTest, CountersWithSameName) { StatName counter_name = makeStat("counter.name"); CounterSharedPtr c1 = alloc_.makeCounter(counter_name, "", std::vector()); EXPECT_EQ(1, c1->use_count()); @@ -51,7 +51,7 @@ TEST_F(HeapAllocatorTest, CountersWithSameName) { EXPECT_EQ(2, c2->value()); } -TEST_F(HeapAllocatorTest, GaugesWithSameName) { +TEST_F(AllocatorImplTest, GaugesWithSameName) { StatName gauge_name = makeStat("gauges.name"); GaugeSharedPtr g1 = alloc_.makeGauge(gauge_name, "", std::vector(), Gauge::ImportMode::Accumulate); diff --git a/test/common/stats/metric_impl_test.cc b/test/common/stats/metric_impl_test.cc index 493444fd1d0e..16e90a220199 100644 --- a/test/common/stats/metric_impl_test.cc +++ b/test/common/stats/metric_impl_test.cc @@ -1,7 +1,7 @@ #include +#include "common/stats/allocator_impl.h" #include "common/stats/fake_symbol_table_impl.h" -#include "common/stats/heap_stat_data.h" #include "common/stats/utility.h" #include "test/test_common/logging.h" @@ -15,7 +15,7 @@ namespace { class MetricImplTest : public testing::Test { protected: MetricImplTest() : alloc_(symbol_table_), pool_(symbol_table_) {} - ~MetricImplTest() { clearStorage(); } + ~MetricImplTest() override { clearStorage(); } StatName makeStat(absl::string_view name) { return pool_.add(name); } @@ -25,7 +25,7 @@ class MetricImplTest : public testing::Test { } FakeSymbolTableImpl symbol_table_; - HeapStatDataAllocator alloc_; + AllocatorImpl alloc_; StatNamePool pool_; }; diff --git a/test/common/stats/stat_merger_test.cc b/test/common/stats/stat_merger_test.cc index e91cb3dda992..f56e8d98c718 100644 --- a/test/common/stats/stat_merger_test.cc +++ b/test/common/stats/stat_merger_test.cc @@ -183,7 +183,7 @@ TEST_F(StatMergerTest, gaugeMergeImportMode) { class StatMergerThreadLocalTest : public testing::Test { protected: FakeSymbolTableImpl symbol_table_; - HeapStatDataAllocator alloc_{symbol_table_}; + AllocatorImpl alloc_{symbol_table_}; ThreadLocalStoreImpl store_{alloc_}; }; @@ -196,7 +196,7 @@ TEST_F(StatMergerThreadLocalTest, filterOutUninitializedGauges) { // We don't get "newgauge1" in the aggregated list, but we *do* get it if we try to // find it by name. - absl::optional> find = store_.findGauge(g1.statName()); + OptionalGauge find = store_.findGauge(g1.statName()); ASSERT_TRUE(find); EXPECT_EQ(&g1, &(find->get())); } diff --git a/test/common/stats/stat_test_utility.cc b/test/common/stats/stat_test_utility.cc index 7a9241d2c5b4..ef13cdab3748 100644 --- a/test/common/stats/stat_test_utility.cc +++ b/test/common/stats/stat_test_utility.cc @@ -118,18 +118,19 @@ MemoryTest::Mode MemoryTest::mode() { const size_t end_mem = Memory::Stats::totalCurrentlyAllocated(); bool can_measure_memory = end_mem > start_mem; -#if defined(MEMORY_TEST_EXACT) // Set in "ci/do_ci.sh" for 'release' tests. - RELEASE_ASSERT(can_measure_memory, "Compilation is set up for canonical memory measurements, " - "but memory measurement looks broken"); - return Mode::Canonical; -#else - // Different versions of STL and other compiler/architecture differences may - // also impact memory usage, so when not compiling with MEMORY_TEST_EXACT, - // memory comparisons must be given some slack. There have recently emerged - // some memory-allocation differences between development and Envoy CI and - // Bazel CI (which compiles Envoy as a test of Bazel). - return can_measure_memory ? Mode::Approximate : Mode::Disabled; -#endif + if (getenv("ENVOY_MEMORY_TEST_EXACT") != nullptr) { // Set in "ci/do_ci.sh" for 'release' tests. + RELEASE_ASSERT(can_measure_memory, + "$ENVOY_MEMORY_TEST_EXACT is set for canonical memory measurements, " + "but memory measurement looks broken"); + return Mode::Canonical; + } else { + // Different versions of STL and other compiler/architecture differences may + // also impact memory usage, so when not compiling with MEMORY_TEST_EXACT, + // memory comparisons must be given some slack. There have recently emerged + // some memory-allocation differences between development and Envoy CI and + // Bazel CI (which compiles Envoy as a test of Bazel). + return can_measure_memory ? Mode::Approximate : Mode::Disabled; + } #endif } diff --git a/test/common/stats/tag_producer_impl_test.cc b/test/common/stats/tag_producer_impl_test.cc index d97819ed4e9c..7dd44f8cbcec 100644 --- a/test/common/stats/tag_producer_impl_test.cc +++ b/test/common/stats/tag_producer_impl_test.cc @@ -17,7 +17,7 @@ TEST(TagProducerTest, CheckConstructor) { auto& tag_specifier1 = *stats_config.mutable_stats_tags()->Add(); tag_specifier1.set_tag_name("test.x"); tag_specifier1.set_fixed_value("xxx"); - TagProducerImpl{stats_config}; + EXPECT_NO_THROW(TagProducerImpl{stats_config}); // Should raise an error when duplicate tag names are specified. auto& tag_specifier2 = *stats_config.mutable_stats_tags()->Add(); diff --git a/test/common/stats/thread_local_store_speed_test.cc b/test/common/stats/thread_local_store_speed_test.cc index 30413ff6b765..877c6bc7bb09 100644 --- a/test/common/stats/thread_local_store_speed_test.cc +++ b/test/common/stats/thread_local_store_speed_test.cc @@ -4,8 +4,8 @@ #include "common/common/logger.h" #include "common/common/thread.h" #include "common/event/dispatcher_impl.h" +#include "common/stats/allocator_impl.h" #include "common/stats/fake_symbol_table_impl.h" -#include "common/stats/heap_stat_data.h" #include "common/stats/tag_producer_impl.h" #include "common/stats/thread_local_store.h" #include "common/thread_local/thread_local_impl.h" @@ -56,7 +56,7 @@ class ThreadLocalStorePerf { private: Stats::FakeSymbolTableImpl symbol_table_; Event::SimulatedTimeSystem time_system_; - Stats::HeapStatDataAllocator heap_alloc_; + Stats::AllocatorImpl heap_alloc_; Stats::ThreadLocalStoreImpl store_; Api::ApiPtr api_; Event::DispatcherPtr dispatcher_; diff --git a/test/common/stats/thread_local_store_test.cc b/test/common/stats/thread_local_store_test.cc index edd3ba983591..711d1c459e46 100644 --- a/test/common/stats/thread_local_store_test.cc +++ b/test/common/stats/thread_local_store_test.cc @@ -43,7 +43,7 @@ class StatsThreadLocalStoreTest : public testing::Test { store_->addSink(sink_); } - void resetStoreWithAlloc(StatDataAllocator& alloc) { + void resetStoreWithAlloc(Allocator& alloc) { store_ = std::make_unique(alloc); store_->addSink(sink_); } @@ -51,7 +51,7 @@ class StatsThreadLocalStoreTest : public testing::Test { Stats::FakeSymbolTableImpl symbol_table_; NiceMock main_thread_dispatcher_; NiceMock tls_; - HeapStatDataAllocator alloc_; + AllocatorImpl alloc_; MockSink sink_; std::unique_ptr store_; }; @@ -169,7 +169,7 @@ class HistogramTest : public testing::Test { FakeSymbolTableImpl symbol_table_; NiceMock main_thread_dispatcher_; NiceMock tls_; - HeapStatDataAllocator alloc_; + AllocatorImpl alloc_; MockSink sink_; std::unique_ptr store_; InSequence s; @@ -461,7 +461,7 @@ class LookupWithStatNameTest : public testing::Test { StatName makeStatName(absl::string_view name) { return pool_.add(name); } Stats::FakeSymbolTableImpl symbol_table_; - HeapStatDataAllocator alloc_; + AllocatorImpl alloc_; ThreadLocalStoreImpl store_; StatNamePool pool_; }; @@ -758,7 +758,7 @@ class RememberStatsMatcherTest : public testing::TestWithParam { Stats::FakeSymbolTableImpl symbol_table_; NiceMock main_thread_dispatcher_; NiceMock tls_; - HeapStatDataAllocator heap_alloc_; + AllocatorImpl heap_alloc_; ThreadLocalStoreImpl store_; ScopePtr scope_; }; @@ -849,7 +849,7 @@ TEST_F(StatsThreadLocalStoreTest, NonHotRestartNoTruncation) { TEST(StatsThreadLocalStoreTestNoFixture, MemoryWithoutTls) { MockSink sink; Stats::FakeSymbolTableImpl symbol_table; - HeapStatDataAllocator alloc(symbol_table); + AllocatorImpl alloc(symbol_table); ThreadLocalStoreImpl store(alloc); store.addSink(sink); @@ -867,7 +867,7 @@ TEST(StatsThreadLocalStoreTestNoFixture, MemoryWithoutTls) { TEST(StatsThreadLocalStoreTestNoFixture, MemoryWithTls) { Stats::FakeSymbolTableImpl symbol_table; - HeapStatDataAllocator alloc(symbol_table); + AllocatorImpl alloc(symbol_table); NiceMock main_thread_dispatcher; NiceMock tls; ThreadLocalStoreImpl store(alloc); @@ -933,7 +933,7 @@ TEST(ThreadLocalStoreThreadTest, ConstructDestruct) { Api::ApiPtr api = Api::createApiForTest(); Event::DispatcherPtr dispatcher = api->allocateDispatcher(); NiceMock tls; - HeapStatDataAllocator alloc(symbol_table); + AllocatorImpl alloc(symbol_table); ThreadLocalStoreImpl store(alloc); store.initializeThreading(*dispatcher, tls); diff --git a/test/common/stream_info/filter_state_impl_test.cc b/test/common/stream_info/filter_state_impl_test.cc index 56fbbd91d00d..4cf7ab250881 100644 --- a/test/common/stream_info/filter_state_impl_test.cc +++ b/test/common/stream_info/filter_state_impl_test.cc @@ -14,7 +14,7 @@ class TestStoredTypeTracking : public FilterState::Object { public: TestStoredTypeTracking(int value, size_t* access_count, size_t* destruction_count) : value_(value), access_count_(access_count), destruction_count_(destruction_count) {} - ~TestStoredTypeTracking() { + ~TestStoredTypeTracking() override { if (destruction_count_) { ++*destruction_count_; } diff --git a/test/common/tcp/conn_pool_test.cc b/test/common/tcp/conn_pool_test.cc index 149354109c05..5cf14a40a0f5 100644 --- a/test/common/tcp/conn_pool_test.cc +++ b/test/common/tcp/conn_pool_test.cc @@ -34,7 +34,7 @@ namespace { struct TestConnectionState : public ConnectionPool::ConnectionState { TestConnectionState(int id, std::function on_destructor) : id_(id), on_destructor_(on_destructor) {} - ~TestConnectionState() { on_destructor_(); } + ~TestConnectionState() override { on_destructor_(); } int id_; std::function on_destructor_; @@ -79,7 +79,7 @@ class ConnPoolImplForTest : public ConnPoolImpl { Upstream::ResourcePriority::Default, nullptr, nullptr), mock_dispatcher_(dispatcher), mock_upstream_ready_timer_(upstream_ready_timer) {} - ~ConnPoolImplForTest() { + ~ConnPoolImplForTest() override { EXPECT_EQ(0U, ready_conns_.size()); EXPECT_EQ(0U, busy_conns_.size()); EXPECT_EQ(0U, pending_requests_.size()); @@ -158,7 +158,7 @@ class TcpConnPoolImplTest : public testing::Test { : upstream_ready_timer_(new NiceMock(&dispatcher_)), conn_pool_(dispatcher_, cluster_, upstream_ready_timer_) {} - ~TcpConnPoolImplTest() { + ~TcpConnPoolImplTest() override { EXPECT_TRUE(TestUtility::gaugesZeroed(cluster_->stats_store_.gauges())); } @@ -180,7 +180,7 @@ class TcpConnPoolImplDestructorTest : public testing::Test { Upstream::makeTestHost(cluster_, "tcp://127.0.0.1:9000"), Upstream::ResourcePriority::Default, nullptr, nullptr)} {} - ~TcpConnPoolImplDestructorTest() {} + ~TcpConnPoolImplDestructorTest() override = default; void prepareConn() { connection_ = new NiceMock(); diff --git a/test/common/tcp_proxy/tcp_proxy_test.cc b/test/common/tcp_proxy/tcp_proxy_test.cc index ec747aa3dca3..dbfb840d619c 100644 --- a/test/common/tcp_proxy/tcp_proxy_test.cc +++ b/test/common/tcp_proxy/tcp_proxy_test.cc @@ -357,7 +357,7 @@ class TcpProxyTest : public testing::Test { .WillByDefault(SaveArg<0>(&access_log_data_)); } - ~TcpProxyTest() { + ~TcpProxyTest() override { if (filter_ != nullptr) { filter_callbacks_.connection_.raiseEvent(Network::ConnectionEvent::RemoteClose); } diff --git a/test/common/thread_local/thread_local_impl_test.cc b/test/common/thread_local/thread_local_impl_test.cc index 49ba114a2daf..5a678c839384 100644 --- a/test/common/thread_local/thread_local_impl_test.cc +++ b/test/common/thread_local/thread_local_impl_test.cc @@ -18,7 +18,7 @@ namespace { class TestThreadLocalObject : public ThreadLocalObject { public: - ~TestThreadLocalObject() { onDestroy(); } + ~TestThreadLocalObject() override { onDestroy(); } MOCK_METHOD0(onDestroy, void()); }; diff --git a/test/common/upstream/BUILD b/test/common/upstream/BUILD index 7bbf8314c71e..566e06cf6012 100644 --- a/test/common/upstream/BUILD +++ b/test/common/upstream/BUILD @@ -57,6 +57,7 @@ envoy_cc_test( "//test/mocks/tcp:tcp_mocks", "//test/mocks/thread_local:thread_local_mocks", "//test/mocks/upstream:upstream_mocks", + "//test/test_common:registry_lib", "//test/test_common:simulated_time_system_lib", "//test/test_common:threadsafe_singleton_injector_lib", "//test/test_common:utility_lib", @@ -109,7 +110,6 @@ envoy_cc_test( deps = [ ":utility_lib", "//source/common/buffer:buffer_lib", - "//source/common/config:cds_json_lib", "//source/common/event:dispatcher_lib", "//source/common/http:headers_lib", "//source/common/json:json_loader_lib", @@ -396,7 +396,6 @@ envoy_cc_test_library( hdrs = ["utility.h"], deps = [ "//include/envoy/stats:stats_interface", - "//source/common/config:cds_json_lib", "//source/common/json:json_loader_lib", "//source/common/network:utility_lib", "//source/common/stats:stats_lib", diff --git a/test/common/upstream/cluster_manager_impl_test.cc b/test/common/upstream/cluster_manager_impl_test.cc index badbc3df0394..82ac958f3267 100644 --- a/test/common/upstream/cluster_manager_impl_test.cc +++ b/test/common/upstream/cluster_manager_impl_test.cc @@ -33,6 +33,7 @@ #include "test/mocks/tcp/mocks.h" #include "test/mocks/thread_local/mocks.h" #include "test/mocks/upstream/mocks.h" +#include "test/test_common/registry.h" #include "test/test_common/simulated_time_system.h" #include "test/test_common/threadsafe_singleton_injector.h" #include "test/test_common/utility.h" @@ -543,7 +544,8 @@ TEST_F(ClusterManagerImplTest, OriginalDstLbRestriction) { EXPECT_THROW_WITH_MESSAGE( create(parseBootstrapFromV2Yaml(yaml)), EnvoyException, - "cluster: cluster type 'original_dst' may only be used with LB type 'original_dst_lb'"); + "cluster: LB policy ROUND_ROBIN is not valid for Cluster type ORIGINAL_DST. Only " + "'original_dst_lb' is allowed with cluster type 'original_dst'"); } TEST_F(ClusterManagerImplTest, OriginalDstLbRestriction2) { @@ -566,7 +568,8 @@ TEST_F(ClusterManagerImplTest, OriginalDstLbRestriction2) { EXPECT_THROW_WITH_MESSAGE( create(parseBootstrapFromV2Yaml(yaml)), EnvoyException, - "cluster: LB type 'original_dst_lb' may only be used with cluster type 'original_dst'"); + "cluster: LB policy ORIGINAL_DST_LB is not valid for Cluster type STATIC. Only " + "'original_dst_lb' is allowed with cluster type 'original_dst'"); } TEST_F(ClusterManagerImplTest, SubsetLoadBalancerInitialization) { @@ -2128,14 +2131,14 @@ TEST_F(ClusterManagerImplTest, DynamicHostRemoveDefaultPriority) { class MockConnPoolWithDestroy : public Http::ConnectionPool::MockInstance { public: - ~MockConnPoolWithDestroy() { onDestroy(); } + ~MockConnPoolWithDestroy() override { onDestroy(); } MOCK_METHOD0(onDestroy, void()); }; class MockTcpConnPoolWithDestroy : public Tcp::ConnectionPool::MockInstance { public: - ~MockTcpConnPoolWithDestroy() { onDestroy(); } + ~MockTcpConnPoolWithDestroy() override { onDestroy(); } MOCK_METHOD0(onDestroy, void()); }; @@ -2687,6 +2690,61 @@ TEST_F(ClusterManagerImplTest, UpstreamSocketOptionsNullIsOkay) { EXPECT_NE(nullptr, cp); } +class TestUpstreamNetworkFilter : public Network::WriteFilter { +public: + Network::FilterStatus onWrite(Buffer::Instance&, bool) override { + return Network::FilterStatus::Continue; + } +}; + +class TestUpstreamNetworkFilterConfigFactory + : public Server::Configuration::NamedUpstreamNetworkFilterConfigFactory { +public: + Network::FilterFactoryCb + createFilterFactoryFromProto(const Protobuf::Message&, + Server::Configuration::CommonFactoryContext&) override { + return [](Network::FilterManager& filter_manager) -> void { + filter_manager.addWriteFilter(std::make_shared()); + }; + } + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); + } + std::string name() override { return "envoy.test.filter"; } +}; + +// Verify that configured upstream filters are added to client connections. +TEST_F(ClusterManagerImplTest, AddUpstreamFilters) { + TestUpstreamNetworkFilterConfigFactory factory; + Registry::InjectFactory registry( + factory); + const std::string yaml = R"EOF( + static_resources: + clusters: + - name: cluster_1 + connect_timeout: 0.250s + lb_policy: ROUND_ROBIN + type: STATIC + hosts: + - socket_address: + address: "127.0.0.1" + port_value: 11001 + filters: + - name: envoy.test.filter + )EOF"; + + create(parseBootstrapFromV2Yaml(yaml)); + Network::MockClientConnection* connection = new NiceMock(); + EXPECT_CALL(*connection, addReadFilter(_)).Times(0); + EXPECT_CALL(*connection, addWriteFilter(_)).Times(1); + EXPECT_CALL(*connection, addFilter(_)).Times(0); + EXPECT_CALL(factory_.tls_.dispatcher_, createClientConnection_(_, _, _, _)) + .WillOnce(Return(connection)); + auto conn_data = cluster_manager_->tcpConnForCluster("cluster_1", nullptr, nullptr); + EXPECT_EQ(connection, conn_data.connection_.get()); + factory_.tls_.shutdownThread(); +} + class ClusterManagerInitHelperTest : public testing::Test { public: MOCK_METHOD1(onClusterInit, void(Cluster& cluster)); diff --git a/test/common/upstream/eds_test.cc b/test/common/upstream/eds_test.cc index 864b7295558f..a3909a8ca79c 100644 --- a/test/common/upstream/eds_test.cc +++ b/test/common/upstream/eds_test.cc @@ -116,7 +116,7 @@ class EdsTest : public testing::Test { class EdsWithHealthCheckUpdateTest : public EdsTest { protected: - EdsWithHealthCheckUpdateTest() {} + EdsWithHealthCheckUpdateTest() = default; // Build the initial cluster with some endpoints. void initializeCluster(const std::vector endpoint_ports, @@ -1658,7 +1658,7 @@ TEST_F(EdsTest, MalformedIP) { class EdsAssignmentTimeoutTest : public EdsTest { public: - EdsAssignmentTimeoutTest() : interval_timer_(nullptr) { + EdsAssignmentTimeoutTest() { EXPECT_CALL(dispatcher_, createTimer_(_)) .WillOnce(Invoke([this](Event::TimerCb cb) { timer_cb_ = cb; @@ -1671,7 +1671,7 @@ class EdsAssignmentTimeoutTest : public EdsTest { resetCluster(); } - Event::MockTimer* interval_timer_; + Event::MockTimer* interval_timer_{nullptr}; Event::TimerCb timer_cb_; }; diff --git a/test/common/upstream/health_checker_impl_test.cc b/test/common/upstream/health_checker_impl_test.cc index f1d28d67d9b6..f48d8d2286ca 100644 --- a/test/common/upstream/health_checker_impl_test.cc +++ b/test/common/upstream/health_checker_impl_test.cc @@ -7,7 +7,6 @@ #include "common/buffer/buffer_impl.h" #include "common/buffer/zero_copy_input_stream_impl.h" -#include "common/config/cds_json.h" #include "common/grpc/common.h" #include "common/http/headers.h" #include "common/json/json_loader.h" @@ -1484,6 +1483,42 @@ TEST_F(HttpHealthCheckerImplTest, Timeout) { Host::ActiveHealthFailureType::TIMEOUT); } +// Make sure that a timeout during a partial response works correctly. +TEST_F(HttpHealthCheckerImplTest, TimeoutThenSuccess) { + setupNoServiceValidationHC(); + + cluster_->prioritySet().getMockHostSet(0)->hosts_ = { + makeTestHost(cluster_->info_, "tcp://127.0.0.1:80")}; + expectSessionCreate(); + expectStreamCreate(0); + EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_)); + health_checker_->start(); + + // Do a response that is not complete but includes headers. + std::unique_ptr response_headers( + new Http::TestHeaderMapImpl{{":status", "200"}}); + test_sessions_[0]->stream_response_callbacks_->decodeHeaders(std::move(response_headers), false); + + EXPECT_CALL(*this, onHostStatus(_, HealthTransition::ChangePending)); + EXPECT_CALL(*event_logger_, logUnhealthy(_, _, _, true)); + EXPECT_CALL(*test_sessions_[0]->client_connection_, close(_)); + EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(_)); + EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer()); + test_sessions_[0]->timeout_timer_->callback_(); + EXPECT_EQ(Host::Health::Healthy, cluster_->prioritySet().getMockHostSet(0)->hosts_[0]->health()); + + expectClientCreate(0); + expectStreamCreate(0); + EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_)); + test_sessions_[0]->interval_timer_->callback_(); + + EXPECT_CALL(*this, onHostStatus(_, HealthTransition::Unchanged)); + EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(_)); + EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer()); + respond(0, "200", false, false, true); + EXPECT_EQ(Host::Health::Healthy, cluster_->prioritySet().getMockHostSet(0)->hosts_[0]->health()); +} + TEST_F(HttpHealthCheckerImplTest, TimeoutThenRemoteClose) { setupNoServiceValidationHC(); EXPECT_CALL(*event_logger_, logUnhealthy(_, _, _, true)); @@ -2832,7 +2867,7 @@ class TestGrpcHealthCheckerImpl : public GrpcHealthCheckerImpl { class GrpcHealthCheckerImplTestBase { public: struct TestSession { - TestSession() {} + TestSession() = default; Event::MockTimer* interval_timer_{}; Event::MockTimer* timeout_timer_{}; diff --git a/test/common/upstream/load_balancer_impl_test.cc b/test/common/upstream/load_balancer_impl_test.cc index e9d26eb922cc..5a42f7bf5edf 100644 --- a/test/common/upstream/load_balancer_impl_test.cc +++ b/test/common/upstream/load_balancer_impl_test.cc @@ -829,6 +829,20 @@ TEST_P(RoundRobinLoadBalancerTest, MaxUnhealthyPanic) { EXPECT_EQ(3UL, stats_.lb_healthy_panic_.value()); } +// Ensure if the panic threshold is 0%, panic mode is disabled. +TEST_P(RoundRobinLoadBalancerTest, DisablePanicMode) { + hostSet().healthy_hosts_ = {}; + hostSet().hosts_ = {makeTestHost(info_, "tcp://127.0.0.1:80")}; + + common_config_.mutable_healthy_panic_threshold()->set_value(0); + + init(false); + EXPECT_CALL(runtime_.snapshot_, getInteger("upstream.healthy_panic_threshold", 50)) + .WillRepeatedly(Return(0)); + EXPECT_EQ(nullptr, lb_->chooseHost(nullptr)); + EXPECT_EQ(0UL, stats_.lb_healthy_panic_.value()); +} + // Test of host set selection with host filter TEST_P(RoundRobinLoadBalancerTest, HostSelectionWithFilter) { NiceMock context; @@ -1144,6 +1158,7 @@ TEST_P(RoundRobinLoadBalancerTest, NoZoneAwareRoutingLocalEmpty) { HostsPerLocalitySharedPtr local_hosts_per_locality = makeHostsPerLocality({{}, {}}); EXPECT_CALL(runtime_.snapshot_, getInteger("upstream.healthy_panic_threshold", 50)) + .WillOnce(Return(50)) .WillOnce(Return(50)); EXPECT_CALL(runtime_.snapshot_, featureEnabled("upstream.zone_routing.enabled", 100)) .WillOnce(Return(true)); diff --git a/test/common/upstream/logical_dns_cluster_test.cc b/test/common/upstream/logical_dns_cluster_test.cc index 03170a23af5a..4433db2931f1 100644 --- a/test/common/upstream/logical_dns_cluster_test.cc +++ b/test/common/upstream/logical_dns_cluster_test.cc @@ -35,31 +35,10 @@ namespace Envoy { namespace Upstream { namespace { -enum class ConfigType { V2_YAML, V1_JSON }; - class LogicalDnsClusterTest : public testing::Test { protected: LogicalDnsClusterTest() : api_(Api::createApiForTest(stats_store_)) {} - void setupFromV1Json(const std::string& json) { - resolve_timer_ = new Event::MockTimer(&dispatcher_); - NiceMock cm; - envoy::api::v2::Cluster cluster_config = parseClusterFromJson(json); - Envoy::Stats::ScopePtr scope = stats_store_.createScope(fmt::format( - "cluster.{}.", cluster_config.alt_stat_name().empty() ? cluster_config.name() - : cluster_config.alt_stat_name())); - Envoy::Server::Configuration::TransportSocketFactoryContextImpl factory_context( - admin_, ssl_context_manager_, *scope, cm, local_info_, dispatcher_, random_, stats_store_, - singleton_manager_, tls_, validation_visitor_, *api_); - cluster_.reset(new LogicalDnsCluster(cluster_config, runtime_, dns_resolver_, factory_context, - std::move(scope), false)); - cluster_->prioritySet().addPriorityUpdateCb( - [&](uint32_t, const HostVector&, const HostVector&) -> void { - membership_updated_.ready(); - }); - cluster_->initialize([&]() -> void { initialized_.ready(); }); - } - void setupFromV2Yaml(const std::string& yaml) { resolve_timer_ = new Event::MockTimer(&dispatcher_); NiceMock cm; @@ -90,14 +69,9 @@ class LogicalDnsClusterTest : public testing::Test { } void testBasicSetup(const std::string& config, const std::string& expected_address, - uint32_t expected_port, uint32_t expected_hc_port, - ConfigType config_type = ConfigType::V2_YAML) { + uint32_t expected_port, uint32_t expected_hc_port) { expectResolve(Network::DnsLookupFamily::V4Only, expected_address); - if (config_type == ConfigType::V1_JSON) { - setupFromV1Json(config); - } else { - setupFromV2Yaml(config); - } + setupFromV2Yaml(config); EXPECT_CALL(membership_updated_, ready()); EXPECT_CALL(initialized_, ready()); @@ -224,28 +198,31 @@ using LogicalDnsConfigTuple = std::vector generateLogicalDnsParams() { std::vector dns_config; { - std::string family_json(""); - Network::DnsLookupFamily family(Network::DnsLookupFamily::V4Only); + std::string family_yaml(""); + Network::DnsLookupFamily family(Network::DnsLookupFamily::Auto); std::list dns_response{"127.0.0.1", "127.0.0.2"}; - dns_config.push_back(std::make_tuple(family_json, family, dns_response)); + dns_config.push_back(std::make_tuple(family_yaml, family, dns_response)); } { - std::string family_json(R"EOF("dns_lookup_family": "v4_only",)EOF"); + std::string family_yaml(R"EOF(dns_lookup_family: v4_only + )EOF"); Network::DnsLookupFamily family(Network::DnsLookupFamily::V4Only); std::list dns_response{"127.0.0.1", "127.0.0.2"}; - dns_config.push_back(std::make_tuple(family_json, family, dns_response)); + dns_config.push_back(std::make_tuple(family_yaml, family, dns_response)); } { - std::string family_json(R"EOF("dns_lookup_family": "v6_only",)EOF"); + std::string family_yaml(R"EOF(dns_lookup_family: v6_only + )EOF"); Network::DnsLookupFamily family(Network::DnsLookupFamily::V6Only); std::list dns_response{"::1", "::2"}; - dns_config.push_back(std::make_tuple(family_json, family, dns_response)); + dns_config.push_back(std::make_tuple(family_yaml, family, dns_response)); } { - std::string family_json(R"EOF("dns_lookup_family": "auto",)EOF"); + std::string family_yaml(R"EOF(dns_lookup_family: auto + )EOF"); Network::DnsLookupFamily family(Network::DnsLookupFamily::Auto); std::list dns_response{"::1"}; - dns_config.push_back(std::make_tuple(family_json, family, dns_response)); + dns_config.push_back(std::make_tuple(family_yaml, family, dns_response)); } return dns_config; } @@ -260,16 +237,17 @@ INSTANTIATE_TEST_SUITE_P(DnsParam, LogicalDnsParamTest, // constructor, we have the expected host state and initialization callback // invocation. TEST_P(LogicalDnsParamTest, ImmediateResolve) { - const std::string json = R"EOF( - { - "name": "name", - "connect_timeout_ms": 250, - "type": "logical_dns", - "lb_type": "round_robin", + const std::string yaml = R"EOF( + name: name + connect_timeout: 0.25s + type: logical_dns + lb_policy: round_robin )EOF" + std::get<0>(GetParam()) + R"EOF( - "hosts": [{"url": "tcp://foo.bar.com:443"}] - } + hosts: + - socket_address: + address: foo.bar.com + port_value: 443 )EOF"; EXPECT_CALL(membership_updated_, ready()); @@ -281,7 +259,7 @@ TEST_P(LogicalDnsParamTest, ImmediateResolve) { cb(TestUtility::makeDnsResponse(std::get<2>(GetParam()))); return nullptr; })); - setupFromV1Json(json); + setupFromV2Yaml(yaml); EXPECT_EQ(1UL, cluster_->prioritySet().hostSetsPerPriority()[0]->hosts().size()); EXPECT_EQ(1UL, cluster_->prioritySet().hostSetsPerPriority()[0]->healthyHosts().size()); EXPECT_EQ("foo.bar.com", @@ -291,17 +269,22 @@ TEST_P(LogicalDnsParamTest, ImmediateResolve) { } TEST_F(LogicalDnsClusterTest, BadConfig) { - const std::string multiple_hosts_json = R"EOF( - { - "name": "name", - "connect_timeout_ms": 250, - "type": "logical_dns", - "lb_type": "round_robin", - "hosts": [{"url": "tcp://foo.bar.com:443"}, {"url": "tcp://foo2.bar.com:443"}] - } + const std::string multiple_hosts_yaml = R"EOF( + name: name + type: LOGICAL_DNS + dns_refresh_rate: 4s + connect_timeout: 0.25s + lb_policy: ROUND_ROBIN + hosts: + - socket_address: + address: foo.bar.com + port_value: 443 + - socket_address: + address: foo2.bar.com + port_value: 443 )EOF"; - EXPECT_THROW_WITH_MESSAGE(setupFromV1Json(multiple_hosts_json), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(setupFromV2Yaml(multiple_hosts_yaml), EnvoyException, "LOGICAL_DNS clusters must have a single host"); const std::string multiple_lb_endpoints_yaml = R"EOF( @@ -394,17 +377,6 @@ TEST_F(LogicalDnsClusterTest, BadConfig) { } TEST_F(LogicalDnsClusterTest, Basic) { - const std::string json = R"EOF( - { - "name": "name", - "connect_timeout_ms": 250, - "type": "logical_dns", - "lb_type": "round_robin", - "hosts": [{"url": "tcp://foo.bar.com:443"}], - "dns_refresh_rate_ms": 4000 - } - )EOF"; - const std::string basic_yaml_hosts = R"EOF( name: name type: LOGICAL_DNS @@ -442,7 +414,6 @@ TEST_F(LogicalDnsClusterTest, Basic) { port_value: 8000 )EOF"; - testBasicSetup(json, "foo.bar.com", 443, 443, ConfigType::V1_JSON); testBasicSetup(basic_yaml_hosts, "foo.bar.com", 443, 443); // Expect to override the health check address port value. testBasicSetup(basic_yaml_load_assignment, "foo.bar.com", 443, 8000); diff --git a/test/common/upstream/original_dst_cluster_test.cc b/test/common/upstream/original_dst_cluster_test.cc index e3c5638dfef2..ba5e955b6fa6 100644 --- a/test/common/upstream/original_dst_cluster_test.cc +++ b/test/common/upstream/original_dst_cluster_test.cc @@ -104,33 +104,16 @@ class OriginalDstClusterTest : public testing::Test { Api::ApiPtr api_; }; -TEST(OriginalDstClusterConfigTest, BadConfig) { - std::string json = R"EOF( - { - "name": "name", - "connect_timeout_ms": 250, - "type": "original_dst", - "lb_type": "original_dst_lb", - "hosts": [{"url": "tcp://foo.bar.com:443"}] - } - )EOF"; // Help Emacs balance quotation marks: " - - EXPECT_THROW_WITH_MESSAGE(parseClusterFromJson(json), EnvoyException, - "original_dst clusters must have no hosts configured"); -} - TEST(OriginalDstClusterConfigTest, GoodConfig) { - std::string json = R"EOF( - { - "name": "name", - "connect_timeout_ms": 250, - "type": "original_dst", - "lb_type": "original_dst_lb", - "cleanup_interval_ms": 1000 - } + const std::string yaml = R"EOF( + name: name + connect_timeout: 0.25s + type: original_dst + lb_policy: original_dst_lb + cleanup_interval: 1s )EOF"; // Help Emacs balance quotation marks: " - EXPECT_TRUE(parseClusterFromJson(json).has_cleanup_interval()); + EXPECT_TRUE(parseClusterFromV2Yaml(yaml).has_cleanup_interval()); } TEST_F(OriginalDstClusterTest, BadConfigWithLoadAssignment) { diff --git a/test/common/upstream/upstream_impl_test.cc b/test/common/upstream/upstream_impl_test.cc index b0b8094c55b2..d221c6d838ff 100644 --- a/test/common/upstream/upstream_impl_test.cc +++ b/test/common/upstream/upstream_impl_test.cc @@ -113,28 +113,31 @@ using StrictDnsConfigTuple = std::vector generateStrictDnsParams() { std::vector dns_config; { - std::string family_json(""); - Network::DnsLookupFamily family(Network::DnsLookupFamily::V4Only); + std::string family_yaml(""); + Network::DnsLookupFamily family(Network::DnsLookupFamily::Auto); std::list dns_response{"127.0.0.1", "127.0.0.2"}; - dns_config.push_back(std::make_tuple(family_json, family, dns_response)); + dns_config.push_back(std::make_tuple(family_yaml, family, dns_response)); } { - std::string family_json(R"EOF("dns_lookup_family": "v4_only",)EOF"); + std::string family_yaml(R"EOF(dns_lookup_family: v4_only + )EOF"); Network::DnsLookupFamily family(Network::DnsLookupFamily::V4Only); std::list dns_response{"127.0.0.1", "127.0.0.2"}; - dns_config.push_back(std::make_tuple(family_json, family, dns_response)); + dns_config.push_back(std::make_tuple(family_yaml, family, dns_response)); } { - std::string family_json(R"EOF("dns_lookup_family": "v6_only",)EOF"); + std::string family_yaml(R"EOF(dns_lookup_family: v6_only + )EOF"); Network::DnsLookupFamily family(Network::DnsLookupFamily::V6Only); std::list dns_response{"::1", "::2"}; - dns_config.push_back(std::make_tuple(family_json, family, dns_response)); + dns_config.push_back(std::make_tuple(family_yaml, family, dns_response)); } { - std::string family_json(R"EOF("dns_lookup_family": "auto",)EOF"); + std::string family_yaml(R"EOF(dns_lookup_family: auto + )EOF"); Network::DnsLookupFamily family(Network::DnsLookupFamily::Auto); std::list dns_response{"127.0.0.1", "127.0.0.2"}; - dns_config.push_back(std::make_tuple(family_json, family, dns_response)); + dns_config.push_back(std::make_tuple(family_yaml, family, dns_response)); } return dns_config; } @@ -148,16 +151,17 @@ INSTANTIATE_TEST_SUITE_P(DnsParam, StrictDnsParamTest, TEST_P(StrictDnsParamTest, ImmediateResolve) { auto dns_resolver = std::make_shared>(); ReadyWatcher initialized; - const std::string json = R"EOF( - { - "name": "name", - "connect_timeout_ms": 250, - "type": "strict_dns", - )EOF" + std::get<0>(GetParam()) + + const std::string yaml = R"EOF( + name: name + connect_timeout: 0.25s + type: strict_dns + )EOF" + std::get<0>(GetParam()) + R"EOF( - "lb_type": "round_robin", - "hosts": [{"url": "tcp://foo.bar.com:443"}] - } + lb_policy: round_robin + hosts: + - socket_address: + address: foo.bar.com + port_value: 443 )EOF"; EXPECT_CALL(initialized, ready()); EXPECT_CALL(*dns_resolver, resolve("foo.bar.com", std::get<1>(GetParam()), _)) @@ -166,7 +170,7 @@ TEST_P(StrictDnsParamTest, ImmediateResolve) { cb(TestUtility::makeDnsResponse(std::get<2>(GetParam()))); return nullptr; })); - envoy::api::v2::Cluster cluster_config = parseClusterFromJson(json); + envoy::api::v2::Cluster cluster_config = parseClusterFromV2Yaml(yaml); Envoy::Stats::ScopePtr scope = stats_.createScope(fmt::format( "cluster.{}.", cluster_config.alt_stat_name().empty() ? cluster_config.name() : cluster_config.alt_stat_name())); @@ -228,38 +232,33 @@ TEST_F(StrictDnsClusterImplTest, Basic) { ResolverData resolver2(*dns_resolver_, dispatcher_); ResolverData resolver1(*dns_resolver_, dispatcher_); - const std::string json = R"EOF( - { - "name": "name", - "connect_timeout_ms": 250, - "type": "strict_dns", - "dns_refresh_rate_ms": 4000, - "lb_type": "round_robin", - "circuit_breakers": { - "default": { - "max_connections": 43, - "max_pending_requests": 57, - "max_requests": 50, - "max_retries": 10 - }, - "high": { - "max_connections": 1, - "max_pending_requests": 2, - "max_requests": 3, - "max_retries": 4 - } - }, - "max_requests_per_connection": 3, - "http2_settings": { - "hpack_table_size": 0 - }, - "hosts": [{"url": "tcp://localhost1:11001"}, - {"url": "tcp://localhost2:11002"}] - - } + const std::string yaml = R"EOF( + name: name + connect_timeout: 0.25s + type: strict_dns + dns_refresh_rate: 4s + lb_policy: round_robin + circuit_breakers: + thresholds: + - priority: DEFAULT + max_connections: 43 + max_pending_requests: 57 + max_requests: 50 + max_retries: 10 + - priority: HIGH + max_connections: 1 + max_pending_requests: 2 + max_requests: 3 + max_retries: 4 + max_requests_per_connection: 3 + http2_protocol_options: + hpack_table_size: 0 + hosts: + - { socket_address: { address: localhost1, port_value: 11001 }} + - { socket_address: { address: localhost2, port_value: 11002 }} )EOF"; - envoy::api::v2::Cluster cluster_config = parseClusterFromJson(json); + envoy::api::v2::Cluster cluster_config = parseClusterFromV2Yaml(yaml); Envoy::Stats::ScopePtr scope = stats_.createScope(fmt::format( "cluster.{}.", cluster_config.alt_stat_name().empty() ? cluster_config.name() : cluster_config.alt_stat_name())); @@ -1050,32 +1049,6 @@ TEST_F(StaticClusterImplTest, InitialHosts) { EXPECT_FALSE(cluster.info()->addedViaApi()); } -TEST_F(StaticClusterImplTest, EmptyHostname) { - const std::string json = R"EOF( - { - "name": "staticcluster", - "connect_timeout_ms": 250, - "type": "static", - "lb_type": "random", - "hosts": [{"url": "tcp://10.0.0.1:11001"}] - } - )EOF"; - - envoy::api::v2::Cluster cluster_config = parseClusterFromJson(json); - Envoy::Stats::ScopePtr scope = stats_.createScope(fmt::format( - "cluster.{}.", cluster_config.alt_stat_name().empty() ? cluster_config.name() - : cluster_config.alt_stat_name())); - Envoy::Server::Configuration::TransportSocketFactoryContextImpl factory_context( - admin_, ssl_context_manager_, *scope, cm_, local_info_, dispatcher_, random_, stats_, - singleton_manager_, tls_, validation_visitor_, *api_); - StaticClusterImpl cluster(cluster_config, runtime_, factory_context, std::move(scope), false); - cluster.initialize([] {}); - - EXPECT_EQ(1UL, cluster.prioritySet().hostSetsPerPriority()[0]->healthyHosts().size()); - EXPECT_EQ("", cluster.prioritySet().hostSetsPerPriority()[0]->hosts()[0]->hostname()); - EXPECT_FALSE(cluster.info()->addedViaApi()); -} - TEST_F(StaticClusterImplTest, LoadAssignmentEmptyHostname) { const std::string yaml = R"EOF( name: staticcluster @@ -1278,17 +1251,15 @@ TEST_F(StaticClusterImplTest, AltStatName) { } TEST_F(StaticClusterImplTest, RingHash) { - const std::string json = R"EOF( - { - "name": "staticcluster", - "connect_timeout_ms": 250, - "type": "static", - "lb_type": "ring_hash", - "hosts": [{"url": "tcp://10.0.0.1:11001"}] - } + const std::string yaml = R"EOF( + name: staticcluster + connect_timeout: 0.25s + type: static + lb_policy: ring_hash + hosts: [{ socket_address: { address: 10.0.0.1, port_value: 11001 }}] )EOF"; - envoy::api::v2::Cluster cluster_config = parseClusterFromJson(json); + envoy::api::v2::Cluster cluster_config = parseClusterFromV2Yaml(yaml); Envoy::Stats::ScopePtr scope = stats_.createScope(fmt::format( "cluster.{}.", cluster_config.alt_stat_name().empty() ? cluster_config.name() : cluster_config.alt_stat_name())); @@ -1304,18 +1275,17 @@ TEST_F(StaticClusterImplTest, RingHash) { } TEST_F(StaticClusterImplTest, OutlierDetector) { - const std::string json = R"EOF( - { - "name": "addressportconfig", - "connect_timeout_ms": 250, - "type": "static", - "lb_type": "random", - "hosts": [{"url": "tcp://10.0.0.1:11001"}, - {"url": "tcp://10.0.0.2:11002"}] - } + const std::string yaml = R"EOF( + name: addressportconfig + connect_timeout: 0.25s + type: static + lb_policy: random + hosts: + - { socket_address: { address: 10.0.0.1, port_value: 11001 }} + - { socket_address: { address: 10.0.0.1, port_value: 11002 }} )EOF"; - envoy::api::v2::Cluster cluster_config = parseClusterFromJson(json); + envoy::api::v2::Cluster cluster_config = parseClusterFromV2Yaml(yaml); Envoy::Stats::ScopePtr scope = stats_.createScope(fmt::format( "cluster.{}.", cluster_config.alt_stat_name().empty() ? cluster_config.name() : cluster_config.alt_stat_name())); @@ -1353,18 +1323,17 @@ TEST_F(StaticClusterImplTest, OutlierDetector) { } TEST_F(StaticClusterImplTest, HealthyStat) { - const std::string json = R"EOF( - { - "name": "addressportconfig", - "connect_timeout_ms": 250, - "type": "static", - "lb_type": "random", - "hosts": [{"url": "tcp://10.0.0.1:11001"}, - {"url": "tcp://10.0.0.2:11002"}] - } + const std::string yaml = R"EOF( + name: addressportconfig + connect_timeout: 0.25s + type: static + lb_policy: random + hosts: + - { socket_address: { address: 10.0.0.1, port_value: 11001 }} + - { socket_address: { address: 10.0.0.1, port_value: 11002 }} )EOF"; - envoy::api::v2::Cluster cluster_config = parseClusterFromJson(json); + envoy::api::v2::Cluster cluster_config = parseClusterFromV2Yaml(yaml); Envoy::Stats::ScopePtr scope = stats_.createScope(fmt::format( "cluster.{}.", cluster_config.alt_stat_name().empty() ? cluster_config.name() : cluster_config.alt_stat_name())); @@ -1485,18 +1454,17 @@ TEST_F(StaticClusterImplTest, HealthyStat) { } TEST_F(StaticClusterImplTest, UrlConfig) { - const std::string json = R"EOF( - { - "name": "addressportconfig", - "connect_timeout_ms": 250, - "type": "static", - "lb_type": "random", - "hosts": [{"url": "tcp://10.0.0.1:11001"}, - {"url": "tcp://10.0.0.2:11002"}] - } + const std::string yaml = R"EOF( + name: addressportconfig + connect_timeout: 0.25s + type: static + lb_policy: random + hosts: + - { socket_address: { address: 10.0.0.1, port_value: 11001 }} + - { socket_address: { address: 10.0.0.2, port_value: 11002 }} )EOF"; - envoy::api::v2::Cluster cluster_config = parseClusterFromJson(json); + envoy::api::v2::Cluster cluster_config = parseClusterFromV2Yaml(yaml); Envoy::Stats::ScopePtr scope = stats_.createScope(fmt::format( "cluster.{}.", cluster_config.alt_stat_name().empty() ? cluster_config.name() : cluster_config.alt_stat_name())); @@ -1530,20 +1498,19 @@ TEST_F(StaticClusterImplTest, UrlConfig) { } TEST_F(StaticClusterImplTest, UnsupportedLBType) { - const std::string json = R"EOF( - { - "name": "addressportconfig", - "connect_timeout_ms": 250, - "type": "static", - "lb_type": "fakelbtype", - "hosts": [{"url": "tcp://192.168.1.1:22"}, - {"url": "tcp://192.168.1.2:44"}] - } + const std::string yaml = R"EOF( + name: addressportconfig + connect_timeout: 0.25s + type: static + lb_policy: fakelbtype + hosts: + - { socket_address: { address: 192.168.1.1, port_value: 22 }} + - { socket_address: { address: 192.168.1.2, port_value: 44 }} )EOF"; EXPECT_THROW_WITH_MESSAGE( { - envoy::api::v2::Cluster cluster_config = parseClusterFromJson(json); + envoy::api::v2::Cluster cluster_config = parseClusterFromV2Yaml(yaml); Envoy::Stats::ScopePtr scope = stats_.createScope(fmt::format("cluster.{}.", cluster_config.alt_stat_name().empty() ? cluster_config.name() @@ -1555,10 +1522,8 @@ TEST_F(StaticClusterImplTest, UnsupportedLBType) { false); }, EnvoyException, - "JSON at lines 2-9 does not conform to schema.\n" - " Invalid schema: #/properties/lb_type\n" - " Schema violation: enum\n" - " Offending document key: #/lb_type"); + "Protobuf message (type envoy.api.v2.Cluster reason INVALID_ARGUMENT:(lb_policy): invalid " + "value \"fakelbtype\" for type TYPE_ENUM) has unknown fields"); } TEST_F(StaticClusterImplTest, MalformedHostIP) { @@ -1872,10 +1837,10 @@ struct Baz : public Envoy::Config::TypedMetadata::Object { class BazFactory : public ClusterTypedMetadataFactory { public: - const std::string name() const { return "baz"; } + const std::string name() const override { return "baz"; } // Returns nullptr (conversion failure) if d is empty. std::unique_ptr - parse(const ProtobufWkt::Struct& d) const { + parse(const ProtobufWkt::Struct& d) const override { if (d.fields().find("name") != d.fields().end()) { return std::make_unique(d.fields().at("name").string_value()); } diff --git a/test/common/upstream/utility.h b/test/common/upstream/utility.h index 6a541d08d6bd..b5da2071d09b 100644 --- a/test/common/upstream/utility.h +++ b/test/common/upstream/utility.h @@ -3,7 +3,6 @@ #include "envoy/upstream/upstream.h" #include "common/common/utility.h" -#include "common/config/cds_json.h" #include "common/json/json_loader.h" #include "common/network/utility.h" #include "common/upstream/upstream_impl.h" @@ -43,14 +42,6 @@ parseBootstrapFromV2Json(const std::string& json_string) { return bootstrap; } -inline envoy::api::v2::Cluster parseClusterFromJson(const std::string& json_string) { - envoy::api::v2::Cluster cluster; - auto json_object_ptr = Json::Factory::loadFromString(json_string); - Config::CdsJson::translateCluster(*json_object_ptr, - absl::optional(), cluster); - return cluster; -} - inline envoy::api::v2::Cluster parseClusterFromV2Json(const std::string& json_string) { envoy::api::v2::Cluster cluster; TestUtility::loadFromJson(json_string, cluster); diff --git a/test/config/integration/BUILD b/test/config/integration/BUILD index ec19f4f4350b..d28d2d8011fa 100644 --- a/test/config/integration/BUILD +++ b/test/config/integration/BUILD @@ -9,8 +9,6 @@ envoy_package() exports_files([ "server.yaml", - "server.json", - "server_ads.yaml", "server_unix_listener.yaml", ]) diff --git a/test/config/integration/certs/upstreamlocalhostcert.cfg b/test/config/integration/certs/upstreamlocalhostcert.cfg index fbea513733e9..68c182e2c9f0 100644 --- a/test/config/integration/certs/upstreamlocalhostcert.cfg +++ b/test/config/integration/certs/upstreamlocalhostcert.cfg @@ -34,5 +34,5 @@ authorityKeyIdentifier = keyid:always [alt_names] DNS.2 = localhost -IP.1 = 0.0.0.0 -IP.2 = :: +IP.1 = 127.0.0.1 +IP.2 = ::1 diff --git a/test/config/integration/certs/upstreamlocalhostcert.pem b/test/config/integration/certs/upstreamlocalhostcert.pem index e34ab833d86c..169d1c63e568 100644 --- a/test/config/integration/certs/upstreamlocalhostcert.pem +++ b/test/config/integration/certs/upstreamlocalhostcert.pem @@ -1,25 +1,25 @@ -----BEGIN CERTIFICATE----- -MIIEPTCCAyWgAwIBAgIUS0ht/ypqxlVqt86GiCya6cw/jJ0wDQYJKoZIhvcNAQEL +MIIEPTCCAyWgAwIBAgIUfoTig3pqtlASJyyhMZ2/x0Hg33UwDQYJKoZIhvcNAQEL BQAwfzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM DVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBEx5ZnQxGTAXBgNVBAsMEEx5ZnQgRW5n -aW5lZXJpbmcxGTAXBgNVBAMMEFRlc3QgVXBzdHJlYW0gQ0EwHhcNMTkwNzA4MjE0 -NTU3WhcNMjEwNzA3MjE0NTU3WjCBgzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh +aW5lZXJpbmcxGTAXBgNVBAMMEFRlc3QgVXBzdHJlYW0gQ0EwHhcNMTkwNzEyMjI0 +MzQ1WhcNMjEwNzExMjI0MzQ1WjCBgzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh bGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBEx5ZnQx GTAXBgNVBAsMEEx5ZnQgRW5naW5lZXJpbmcxHTAbBgNVBAMMFFRlc3QgVXBzdHJl -YW0gU2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAujOqV+UB -T8oKxxnIlgKMPn10hIZxOOEzA96CDMQtQ2+180HLfSTErLWzQFNeP6jRDcbXTN0w -tYJlIUmVJtPaj7Dh4VvpORhRwAPZt9bkHcKKFCIaGYj61YCv3YpNyBSfJ0vwgATD -Yn6I2R8nobMKau/hMk4SpPZ6Z3pwSEt0GHd9/cE7t1WvE4BhqIjznexeFO+YrgvF -2ea4j7u4hJxezZhzAqOUyqtlbfkHQwXXzg/93PxBY5Y1mUPszjY+doGhW3DfTI1O -qgU2OfAoFZ6SKtUphUG/gt5DKHvKeARCWMEaUXC9UkyzhSNIl7s8qnRzweZwyOIk -KClryNQCtTjHOwIDAQABo4GrMIGoMAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgXg +YW0gU2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApWnYvUff +dh+TcLEYxQiw+ZUaGfBedmVmaxOHAbsWwBcMcwt3ITAjRPLPFEUt/DUxgmXO80zo +6YOc9uUIUGU0vqIFTQP3JfS9kMevrvQIkZbsO2rtNMYQ+F7HOmGUS3RiKdNNbHnX +NKKPsHe/UFiFCBwxVCT+NSGI3yHZFUSFlvH9BEO+a1lx4pp2R7UJTLdBVaGx42t1 +pTTR2E2S6E1tKXhtS/qN4+X+dDaUFfi7mz+QiNFsYKu5QgO9f8ewfdOPj9MImZvG +4l37/eNtNjzwTMx8Ph4moTSo4yH9ZBGHffPDm4ljPXpLUfiVyIvzR6ygG468ODcP +umQjprHM3TTxlQIDAQABo4GrMIGoMAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgXg MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAsBgNVHREEJTAjgglsb2Nh -bGhvc3SHBAAAAACHEAAAAAAAAAAAAAAAAAAAAAAwHQYDVR0OBBYEFPlBuX/WSFDb -+nUGMLTu7svrrtolMB8GA1UdIwQYMBaAFOLTMLryzNAcuxe3cKEhClkL7IduMA0G -CSqGSIb3DQEBCwUAA4IBAQCgknWXc/Iz/Av6inDxGOncsNlYehKU+UBoR69HlcUE -AEOW7nFaPey5zLL3dgTJd1nOe0u97yT5Hoy9b7O9z5cBWHkNYqFh2oEZKXeDtS81 -z/N4ZQuPxxAlS4d7krAsQNB2vjMFp81eGude680twbto6LKRg9iJMv+AeEJD9p0j -ubeZA20j8YV8Aijm/kNe82d+TQYULxQeLo5QM6VU0pK2VcCunHywcYFc/t99Ync6 -NaqGrxOu6Jfduzg0TsZsIX7GveYC4dmx3CK1qOSB7SE2SVQjAITZL7gIvbLQPEKu -XJrmpIIhgUw+AgPq7D8JEaLoYERCRQLWt4v/yVus2Tgd +bGhvc3SHBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwHQYDVR0OBBYEFFhoq2tgE+IN +uLyrUa1YpgsOpkwTMB8GA1UdIwQYMBaAFOLTMLryzNAcuxe3cKEhClkL7IduMA0G +CSqGSIb3DQEBCwUAA4IBAQB6jYcrAtO+8rLWdBp2W2tj9lgTHE8+W9BzMONrFwVo +PNMPHKPl2XfqKbv64sW3Z9sIA7ThSUu0nAe8i3ddaL4xQvPnaOwTdSnhykyMg2Hp +dDVAT8nCQb7Q87cuiFKE7o87XaQeOS3hgKeQ4uKexA48MkKwNYTVRMb7iC64yZcg +DY5H0nxRISs6pIAD9SPvPOQv+KZ35/LDJy59Kvso1zPoM9e+CJcdHU3hKM3RBK5J +FOjDL8qFair7vyjO9DUPDgoAZJntCQYGC0ToYxTe8cQVJD+sW5gqqIBLRchMr3gL +ni7rAL+oUyufHIEu3upRId+FdVF/hQMCLF2xk54/KX0V -----END CERTIFICATE----- diff --git a/test/config/integration/certs/upstreamlocalhostcert_hash.h b/test/config/integration/certs/upstreamlocalhostcert_hash.h index 409ad0af1cd3..9f81e65fcd83 100644 --- a/test/config/integration/certs/upstreamlocalhostcert_hash.h +++ b/test/config/integration/certs/upstreamlocalhostcert_hash.h @@ -1,4 +1,4 @@ // NOLINT(namespace-envoy) constexpr char TEST_UPSTREAMLOCALHOST_CERT_HASH[] = - "5B:5C:02:47:DE:17:B7:1B:98:05:0A:DB:41:2C:F6:8F:65:E3:86:E6:03:B3:9A:EC:67:33:2E:39:1F:05:88:" - "B0"; + "44:A1:C4:AD:71:B5:AE:A0:A2:24:63:DA:C8:FF:0C:FC:26:6E:4B:D7:08:DE:64:60:34:A0:72:42:6E:18:BA:" + "87"; diff --git a/test/config/integration/certs/upstreamlocalhostkey.pem b/test/config/integration/certs/upstreamlocalhostkey.pem index 7bf369f08b6d..5331d810952c 100644 --- a/test/config/integration/certs/upstreamlocalhostkey.pem +++ b/test/config/integration/certs/upstreamlocalhostkey.pem @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAujOqV+UBT8oKxxnIlgKMPn10hIZxOOEzA96CDMQtQ2+180HL -fSTErLWzQFNeP6jRDcbXTN0wtYJlIUmVJtPaj7Dh4VvpORhRwAPZt9bkHcKKFCIa -GYj61YCv3YpNyBSfJ0vwgATDYn6I2R8nobMKau/hMk4SpPZ6Z3pwSEt0GHd9/cE7 -t1WvE4BhqIjznexeFO+YrgvF2ea4j7u4hJxezZhzAqOUyqtlbfkHQwXXzg/93PxB -Y5Y1mUPszjY+doGhW3DfTI1OqgU2OfAoFZ6SKtUphUG/gt5DKHvKeARCWMEaUXC9 -UkyzhSNIl7s8qnRzweZwyOIkKClryNQCtTjHOwIDAQABAoIBABS0H/Gr9exgQ7iF -pmb/m4ZrPqRpqncvmxOIDx/KRFomNq34l96vUur9PRQe8PDVHYGRpWjXg037VLFR -1DLABaJKgaMkLBd8G8Lk6rVlQHIKqn24mPxT3cgVifhxI1rm6BdfeztQzETMWv0B -WM/C75qaV4jXY31SJqQQ2iE/uoXpuqHtBqxVE9TnBi0NvN2ZXlcxGgwnv7SYKrkE -4c9M5q0F5mJAAkHsrgyyQY18/op/vtQGbKvsdkuT9ihzruaeXxB6M04nevxdDn3r -dC5GUz05c+GCqCmMppU2gRPKYH0t/mvXfZhoGiOujfhTUbiIjQBle1kaxXmZl7Zr -Kz+lO+kCgYEA8IOstfsxJ6Zdf4Xvqi6MLr3MKZT3MmSpKT1dOixzYtD1IS1qc0hF -t4+SNhlP1ny5TlFF12356AC4TMM+kjlhCu9uAsvjqI5M/XSQ00SvybADbYoQc7jy -v9d69AEPOslmfQ7GYDAlFKT5NTK6tXEVpX1MIs6+LSl2pi4emtW7EzUCgYEAxjDG -Db/yEzanLyPC2Yfjk8KotnmprVZmXvmSWl0frOjWxbmYq2auVMNgBysY0+k8OHWk -MQjtjbVqA5b4Ze5Rm0Z7XlWieioxLt1naG3Gb0NAtaivmouaovlrIlZf7GtT4haC -Q4/GN9gGUxdjLLJRJ/WcdOG4X4gp7Opj19eazq8CgYAXVF5rZIs3El8dYIuH0W4N -lqF4Ixf7TmJOOsKRQwCKRESSzEn4FrmUfZusHbZt0rlSzHVe2S8VfwRhhcrK+j/c -hK8CHG7fybXUG/t0UsROZwFeHbdM0lLRowAtLPEiPajwVn+Nkv31y67UpzAPK4Hz -BH1fHvi5fr0gj3auhC7aRQKBgEEAAhTEXSp8BDzrp54ceUEe2KJwKHwXGCASDjPg -0uCsxLO4eR/N32MhaL8xHUVy+zMxMhZ67R5K32gp/XHAxbb9WLzJrS4P5G2QY7fW -OPyIvBJYLq+rFZ5Z2w858N/jG3HNHA/4eXQbP4fE5dvk58UJQrT6yrNaPxXakcBa -kAU1AoGBAJSSjgV9kR2tGzhBFqL0K11E5GP9uzO3sib3Zd7gtOJTO1cvJaLES3BV -Q6sxR9gPJ5cSpTXCNbaJwZ+jAsTfhJj8PE15am/JG7d7xZkflZIdfSf9/23g26w1 -dagOuDPRC2mcbjzprdPRLbNk3NfI/Llw+CboMP6R/smOYf/HRpS9 +MIIEowIBAAKCAQEApWnYvUffdh+TcLEYxQiw+ZUaGfBedmVmaxOHAbsWwBcMcwt3 +ITAjRPLPFEUt/DUxgmXO80zo6YOc9uUIUGU0vqIFTQP3JfS9kMevrvQIkZbsO2rt +NMYQ+F7HOmGUS3RiKdNNbHnXNKKPsHe/UFiFCBwxVCT+NSGI3yHZFUSFlvH9BEO+ +a1lx4pp2R7UJTLdBVaGx42t1pTTR2E2S6E1tKXhtS/qN4+X+dDaUFfi7mz+QiNFs +YKu5QgO9f8ewfdOPj9MImZvG4l37/eNtNjzwTMx8Ph4moTSo4yH9ZBGHffPDm4lj +PXpLUfiVyIvzR6ygG468ODcPumQjprHM3TTxlQIDAQABAoIBAH2pMnFg937qL/0N +XM7acm+4eLK561kwYST5GbgT5A2btOZ1EFRTGIgZmX1BrNSLqIfyRcyJYet8A7OA +fNdueypTNYmzeH8KNTSWrn1PgG7x45aj/X349g1pGxrb5GeKC8TQdGHzEa03zcb2 +wY0NIkrt9/9/durwBeXU9fB1NLNc++Gbrok7kvbDcU6jN8Fas1H86beqhjTohkcN +C0lXk+VLi6m/lBMMjMlezqvTevMdBAjp0LfjwKLMMQE2JhqiS3GxVXhn9N3v0PoP +wI3PuwiUmcIMSY5LvPWD0iy5e1yNFNxJRoTNnnpLnuUmymBSzEeZp4XPrtMefA84 +5Q5BOeECgYEA0yK96/qyTnYcvflqLYukz1YZT029haRR+Yd+TLegVgC+j34q1IuC +TDc2ypHbjwWzkzZYz/6VFMLDXLCPimVS9rpn8vaunZDCLH1xTJbFSTjHOcx83RMT +EBiNH07R33UfdRGJtL5xoLj1DI971wy6LR3yuCzu04VolCMu+PO3Zx0CgYEAyI/t +mF96dZhHB8DDkVe+MRVOuazfkq5JtoUlv74mtKAbx15Jk+iy7G37qHNLRHCGegYj +7PQDZhuGbrda3tce956d9SqpA6uZRqp/aTQBWTfHe6OanXvHPKG1q1hTmfSuWi7/ +Izjh1AGDIaPxtWgx5v7AU8mX4UifhlTvl9KwktkCgYEAug4rfv/0kN/UhDR+NJSS +L4OX2iKPmG0tL88OpVxLln4hbyGnbJVjxPYC+o9+A5LqpBeIPAIELb9TmSKd2z9e +1L1/TMPFLGScN8hzRyK1x8iZB34Dqm1cpxp7gdNbbqcviWJjDzujthZHG0J1xxQY +HBoAAfzWmN8/QQugIRHj1KECgYA1Uo7IxBm6yhGYbheQvNNEGXYkx2FpjgzrCdtP +by67NxYrm1XUjTmEwnj2ADEysPgP2TIT/YwpyYekR/tQ48DH9NPqKr1kzGqj7xCQ +19LD9aCDrquc0xvVcujp9UHE3Ni+AWCz7Jud0gkbGItav6kE0RYxMJfAvZ4sCMjq +hImNgQKBgBHs0Hhg+pie4VJfXh3sxb6Px+WV7UlTyNyTbDMRgq5RKxrisA4BpSax +CjvX/IpTdsP5pNCjAdRK3zs/XC10/wa4wHmk0cXHM9IAFgIncVOuHCkZQyzQ1JJA +cbG7OQFr/UiHJuafueERY2HukfPHfgIUVM3MsXXNR5zIypseBQLW -----END RSA PRIVATE KEY----- diff --git a/test/config/integration/server.json b/test/config/integration/server.json deleted file mode 100644 index 6dd4cc49fd0d..000000000000 --- a/test/config/integration/server.json +++ /dev/null @@ -1,526 +0,0 @@ -{ - "listeners": [ - { - "address": "tcp://{{ ip_loopback_address }}:0", - "filters": [ - { - "name": "http_connection_manager", - "config": { - "codec_type": "http1", - "drain_timeout_ms": 5000, - "access_log": [ - { - "path": "/dev/null", - "format": "[%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% \"%REQ(X-FORWARDED-FOR)%\" \"%REQ(USER-AGENT)%\" \"%REQ(X-REQUEST-ID)%\" \"%REQ(:AUTHORITY)%\" \"%UPSTREAM_HOST%\" \"%REQUEST_DURATION%\" \"%RESPONSE_DURATION%\"\n", - "filter" : { - "type": "logical_or", - "filters": [ - { - "type": "status_code", - "op": ">=", - "value": 500 - }, - { - "type": "duration", - "op": ">=", - "value": 1000000 - } - ] - } - }, - { - "path": "/dev/null" - }], - "stat_prefix": "router", - "route_config": - { - "virtual_hosts": [ - { - "name": "redirect", - "domains": [ "www.redirect.com" ], - "require_ssl": "all", - "routes": [ - { - "prefix": "/", - "cluster": "cluster_1" - } - ] - }, - { - "name": "integration", - "domains": [ "*" ], - "routes": [ - { - "prefix": "/", - "cluster": "cluster_1", - "runtime": { - "key": "some_key", - "default": 0 - } - }, - { - "prefix": "/test/long/url", - "cluster": "cluster_1", - "rate_limits": [ - { - "actions": [ - {"type": "destination_cluster"} - ] - } - ] - }, - { - "prefix": "/test/", - "cluster": "cluster_2" - }, - { - "prefix": "/websocket/test", - "prefix_rewrite": "/websocket", - "cluster": "cluster_1" - } - ] - } - ] - }, - "filters": [ - { "name": "health_check", - "config": { - "pass_through_mode": false, "endpoint": "/healthcheck" - } - }, - { "type": "decoder", "name": "rate_limit", - "config": { - "domain": "foo" - } - }, - { "type": "decoder", "name": "router", "config": {} } - ] - } - }] - }, - { - "address": "tcp://{{ ip_loopback_address }}:0", - "filters": [ - { - "name": "http_connection_manager", - "config": { - "codec_type": "http1", - "http1_settings": { - "allow_absolute_url": true - }, - "drain_timeout_ms": 5000, - "access_log": [ - { - "path": "/dev/null", - "format": "[%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% \"%REQ(X-FORWARDED-FOR)%\" \"%REQ(USER-AGENT)%\" \"%REQ(X-REQUEST-ID)%\" \"%REQ(:AUTHORITY)%\" \"%UPSTREAM_HOST%\" \"%REQUEST_DURATION%\" \"%RESPONSE_DURATION%\"\n", - "filter" : { - "type": "logical_or", - "filters": [ - { - "type": "status_code", - "op": ">=", - "value": 500 - }, - { - "type": "duration", - "op": ">=", - "value": 1000000 - } - ] - } - }, - { - "path": "/dev/null" - }], - "stat_prefix": "router", - "route_config": - { - "virtual_hosts": [ - { - "name": "redirect", - "domains": [ "www.redirect.com" ], - "require_ssl": "all", - "routes": [ - { - "prefix": "/", - "cluster": "cluster_1" - } - ] - }, - { - "name": "redirect", - "domains": [ "www.namewithport.com:1234" ], - "require_ssl": "all", - "routes": [ - { - "prefix": "/", - "cluster": "cluster_1" - } - ] - }, - { - "name": "integration", - "domains": [ "*" ], - "routes": [ - { - "prefix": "/", - "cluster": "cluster_1", - "runtime": { - "key": "some_key", - "default": 0 - } - }, - { - "prefix": "/test/long/url", - "cluster": "cluster_1", - "rate_limits": [ - { - "actions": [ - {"type": "destination_cluster"} - ] - } - ] - }, - { - "prefix": "/test/", - "cluster": "cluster_2" - }, - { - "prefix": "/websocket/test", - "prefix_rewrite": "/websocket", - "cluster": "cluster_1" - } - ] - } - ] - }, - "filters": [ - { "name": "health_check", - "config": { - "pass_through_mode": false, "endpoint": "/healthcheck" - } - }, - { "type": "decoder", "name": "rate_limit", - "config": { - "domain": "foo" - } - }, - { "type": "decoder", "name": "router", "config": {} } - ] - } - }] - }, - { - "address": "tcp://{{ ip_loopback_address }}:0", - "per_connection_buffer_limit_bytes": 1024, - "filters": [ - { - "name": "http_connection_manager", - "config": { - "codec_type": "http1", - "stat_prefix": "router", - "route_config": - { - "virtual_hosts": [ - { - "name": "integration", - "domains": [ "*" ], - "routes": [ - { - "prefix": "/test/long/url", - "cluster": "cluster_3" - } - ] - } - ] - }, - "filters": [ - { "type": "decoder", "name": "router", "config": {} } - ] - } - }] - }, - { - "address": "tcp://{{ ip_loopback_address }}:0", - "per_connection_buffer_limit_bytes": 1024, - "filters": [ - { - "name": "http_connection_manager", - "config": { - "codec_type": "http1", - "stat_prefix": "router", - "route_config": - { - "virtual_hosts": [ - { - "name": "integration", - "domains": [ "*" ], - "routes": [ - { - "prefix": "/dynamo/url", - "cluster": "cluster_3" - } - ] - } - ] - }, - "filters": [ - { "name": "http_dynamo_filter", "config": {} }, - { "type": "decoder", "name": "router", "config": {} } - ] - } - }] - }, - { - "address": "tcp://{{ ip_loopback_address }}:0", - "per_connection_buffer_limit_bytes": 1024, - "filters": [ - { - "name": "http_connection_manager", - "config": { - "codec_type": "http1", - "stat_prefix": "router", - "route_config": - { - "virtual_hosts": [ - { - "name": "integration", - "domains": [ "*" ], - "routes": [ - { - "prefix": "/test/long/url", - "cluster": "cluster_3" - } - ] - } - ] - }, - "filters": [ - { "type": "both", "name": "grpc_http1_bridge", "config": {} }, - { "type": "decoder", "name": "router", "config": {} } - ] - } - }] - }, - { - "address": "tcp://{{ ip_loopback_address }}:0", - "filters": [ - { - "name": "http_connection_manager", - "config": { - "codec_type": "http1", - "drain_timeout_ms": 5000, - "access_log": [ - { - "path": "/dev/null", - "format": "[%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% \"%REQ(X-FORWARDED-FOR)%\" \"%REQ(USER-AGENT)%\" \"%REQ(X-REQUEST-ID)%\" \"%REQ(:AUTHORITY)%\" \"%UPSTREAM_HOST%\" \"%REQUEST_DURATION%\" \"%RESPONSE_DURATION%\"\n", - "filter" : { - "type": "logical_or", - "filters": [ - { - "type": "status_code", - "op": ">=", - "value": 500 - }, - { - "type": "duration", - "op": ">=", - "value": 1000000 - } - ] - } - }, - { - "path": "/dev/null" - }], - "stat_prefix": "router", - "route_config": - { - "virtual_hosts": [ - { - "name": "redirect", - "domains": [ "www.redirect.com" ], - "require_ssl": "all", - "routes": [ - { - "prefix": "/", - "cluster": "cluster_1" - } - ] - }, - { - "name": "integration", - "domains": [ "*" ], - "routes": [ - { - "prefix": "/", - "cluster": "cluster_1", - "runtime": { - "key": "some_key", - "default": 0 - } - }, - { - "prefix": "/test/long/url", - "cluster": "cluster_1", - "rate_limits": [ - { - "actions": [ - {"type": "destination_cluster"} - ] - } - ] - }, - { - "prefix": "/test/", - "cluster": "cluster_2" - }, - { - "prefix": "/websocket/test", - "prefix_rewrite": "/websocket", - "cluster": "cluster_1" - } - ] - } - ] - }, - "filters": [ - { "name": "health_check", - "config": { - "pass_through_mode": false, "endpoint": "/healthcheck" - } - }, - { "type": "decoder", "name": "rate_limit", - "config": { - "domain": "foo" - } - }, - { "type": "decoder", "name": "buffer", - "config": { - "max_request_bytes": 5242880 - } - }, - { "type": "decoder", "name": "router", "config": {} } - ] - } - }] - }, - { - "address": "tcp://{{ ip_loopback_address }}:0", - "filters": [ - { - "name": "http_connection_manager", - "config": { - "codec_type": "http1", - "stat_prefix": "rds_dummy", - "rds": { - "cluster": "rds", - "route_config_name": "foo" - }, - "filters": [ - { "type": "decoder", "name": "router", "config": {} } - ] - } - }] - }, - { - "address": "tcp://{{ ip_loopback_address }}:0", - "filters": [ - { - "name": "redis_proxy", - "config": { - "cluster_name": "redis", - "stat_prefix": "redis", - "conn_pool": { - "op_timeout_ms": 400 - } - } - }] - }], - - "admin": { "access_log_path": "/dev/null", - "profile_path": "{{ test_tmpdir }}/envoy.prof", - "address": "tcp://{{ ip_loopback_address }}:0" }, - "flags_path": "/invalid_flags", - "statsd_udp_ip_address": "{{ ip_loopback_address }}:8125", - "statsd_tcp_cluster_name": "statsd", - - "lds": { - "api_type": "REST", - "cluster": "lds" - }, - - "runtime": { - "symlink_root": "{{ test_tmpdir }}/test/common/runtime/test_data/current", - "subdirectory": "envoy", - "override_subdirectory": "envoy_override" - }, - - "cluster_manager": { - "cds": { - "api_type": "REST", - "cluster": { - "name": "cds", - "connect_timeout_ms": 5000, - "type": "static", - "lb_type": "round_robin", - "hosts": [{"url": "tcp://{{ ip_loopback_address }}:4"}] - } - }, - "clusters": [ - { - "name": "rds", - "connect_timeout_ms": 5000, - "type": "static", - "lb_type": "round_robin", - "hosts": [{"url": "tcp://{{ ip_loopback_address }}:4"}] - }, - { - "name": "lds", - "connect_timeout_ms": 5000, - "type": "static", - "lb_type": "round_robin", - "hosts": [{"url": "tcp://{{ ip_loopback_address }}:4"}] - }, - { - "name": "cluster_1", - "connect_timeout_ms": 5000, - "type": "static", - "lb_type": "round_robin", - "hosts": [{"url": "tcp://{{ ip_loopback_address }}:{{ upstream_0 }}"}] - }, - { - "name": "cluster_2", - "connect_timeout_ms": 5000, - "type": "strict_dns", - "lb_type": "round_robin", - "dns_lookup_family": "{{ dns_lookup_family }}", - "hosts": [{"url": "tcp://localhost:{{ upstream_1 }}"}] - }, - { - "name": "cluster_3", - "per_connection_buffer_limit_bytes": 1024, - "connect_timeout_ms": 5000, - "type": "static", - "lb_type": "round_robin", - "hosts": [{"url": "tcp://{{ ip_loopback_address }}:{{ upstream_0 }}"}] - }, - { - "name": "statsd", - "connect_timeout_ms": 5000, - "type": "strict_dns", - "lb_type": "round_robin", - "dns_lookup_family": "{{ dns_lookup_family }}", - "hosts": [{"url": "tcp://localhost:4"}] - }, - { - "name": "redis", - "connect_timeout_ms": 5000, - "type": "strict_dns", - "lb_type": "ring_hash", - "dns_lookup_family": "{{ dns_lookup_family }}", - "hosts": [{"url": "tcp://localhost:4"}], - "outlier_detection": {} - }] - } -} diff --git a/test/config/integration/server.yaml b/test/config/integration/server.yaml index 91fdf5da5dfd..455a17bc0592 100644 --- a/test/config/integration/server.yaml +++ b/test/config/integration/server.yaml @@ -8,309 +8,69 @@ static_resources: - filters: - name: envoy.http_connection_manager config: - value: - drain_timeout_ms: 5000 - route_config: - virtual_hosts: - - require_ssl: all - routes: - - cluster: cluster_1 - prefix: "/" - domains: - - www.redirect.com - name: redirect - - routes: - - prefix: "/" + drain_timeout_ms: 5000 + route_config: + virtual_hosts: + - require_ssl: all + routes: + - route: { cluster: cluster_1 } + match: { prefix: "/" } + domains: + - www.redirect.com + name: redirect + - routes: + - match: { prefix: "/" } + route: cluster: cluster_1 runtime: key: some_key default: 0 - - prefix: "/test/long/url" + - match: { prefix: "/test/long/url" } + route: rate_limits: - actions: - - type: destination_cluster + - destination_cluster: {} cluster: cluster_1 - - prefix: "/test/" - cluster: cluster_2 - - prefix: "/websocket/test" + - match: { prefix: "/test/" } + route: { cluster: cluster_2 } + - match: { prefix: "/websocket/test" } + route: prefix_rewrite: "/websocket" cluster: cluster_1 - domains: - - "*" - name: integration - codec_type: http1 - stat_prefix: router - filters: - - name: health_check - config: - endpoint: "/healthcheck" - pass_through_mode: false - - name: rate_limit - config: - domain: foo - - name: router - config: {} - access_log: - - format: '[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% - %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% - %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" - "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%" - "%REQUEST_DURATION%" "%RESPONSE_DURATION%"' - path: "/dev/null" - filter: + domains: + - "*" + name: integration + codec_type: http1 + stat_prefix: router + filters: + - name: health_check + config: + endpoint: "/healthcheck" + pass_through_mode: false + - name: rate_limit + config: + domain: foo + - name: router + config: {} + access_log: + - name: envoy.file_access_log + config: + path: /dev/null + filter: + or_filter: filters: - - type: status_code - op: ">=" - value: 500 - - type: duration - op: ">=" - value: 1000000 - type: logical_or - - path: "/dev/null" - deprecated_v1: true - - address: - socket_address: - address: {{ ip_loopback_address }} - port_value: 0 - filter_chains: - - filters: - - name: envoy.http_connection_manager - config: - value: - filters: - - name: health_check - config: - endpoint: "/healthcheck" - pass_through_mode: false - - name: rate_limit - config: - domain: foo - - name: router - config: {} - access_log: - - filter: - type: logical_or - filters: - - value: 500 - type: status_code - op: ">=" - - type: duration - op: ">=" - value: 1555500 - format: '[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% - %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% - %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" - "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%" - "%REQUEST_DURATION%" "%RESPONSE_DURATION%"' - path: "/dev/null" - - path: "/dev/null" - drain_timeout_ms: 5000 - route_config: - virtual_hosts: - - routes: - - prefix: "/" - cluster: cluster_1 - domains: - - www.redirect.com - name: redirect - require_ssl: all - - routes: - - prefix: "/" - cluster: cluster_1 - domains: - - www.namewithport.com:1234 - name: redirect - require_ssl: all - - routes: - - cluster: cluster_1 - runtime: - key: some_key - default: 0 - prefix: "/" - - rate_limits: - - actions: - - type: destination_cluster - cluster: cluster_1 - prefix: "/test/long/url" - - prefix: "/test/" - cluster: cluster_2 - - cluster: cluster_1 - prefix: "/websocket/test" - prefix_rewrite: "/websocket" - domains: - - "*" - name: integration - codec_type: http1 - stat_prefix: router - http1_settings: - allow_absolute_url: true - deprecated_v1: true - - address: - socket_address: - address: {{ ip_loopback_address }} - port_value: 0 - filter_chains: - - filters: - - name: envoy.http_connection_manager - config: - value: - route_config: - virtual_hosts: - - routes: - - cluster: cluster_3 - prefix: "/test/long/url" - domains: - - "*" - name: integration - filters: - - name: router - config: {} - codec_type: http1 - stat_prefix: router - deprecated_v1: true - per_connection_buffer_limit_bytes: 1024 - - address: - socket_address: - address: {{ ip_loopback_address }} - port_value: 0 - filter_chains: - - filters: - - name: envoy.http_connection_manager - config: - value: - filters: - - name: http_dynamo_filter - config: {} - - name: router - config: {} - codec_type: http1 - stat_prefix: router - route_config: - virtual_hosts: - - routes: - - cluster: cluster_3 - prefix: "/dynamo/url" - domains: - - "*" - name: integration - deprecated_v1: true - per_connection_buffer_limit_bytes: 1024 - - address: - socket_address: - address: {{ ip_loopback_address }} - port_value: 0 - filter_chains: - - filters: - - name: envoy.http_connection_manager - config: - value: - route_config: - virtual_hosts: - - domains: - - "*" - name: integration - routes: - - prefix: "/test/long/url" - cluster: cluster_3 - filters: - - name: grpc_http1_bridge - config: {} - - name: router - config: {} - codec_type: http1 - stat_prefix: router - deprecated_v1: true - per_connection_buffer_limit_bytes: 1024 - - address: - socket_address: - address: {{ ip_loopback_address }} - port_value: 0 - filter_chains: - - filters: - - name: envoy.http_connection_manager - config: - value: - drain_timeout_ms: 5000 - route_config: - virtual_hosts: - - routes: - - cluster: cluster_1 - prefix: "/" - domains: - - www.redirect.com - name: redirect - require_ssl: all - - routes: - - cluster: cluster_1 - runtime: - key: some_key - default: 0 - prefix: "/" - - prefix: "/test/long/url" - rate_limits: - - actions: - - type: destination_cluster - cluster: cluster_1 - - prefix: "/test/" - cluster: cluster_2 - - prefix: "/websocket/test" - prefix_rewrite: "/websocket" - cluster: cluster_1 - domains: - - "*" - name: integration - codec_type: http1 - stat_prefix: router - filters: - - name: health_check - config: - endpoint: "/healthcheck" - pass_through_mode: false - - name: rate_limit - config: - domain: foo - - name: buffer - config: - max_request_bytes: 5242880 - - config: {} - name: router - access_log: - - filter: - filters: - - op: ">=" - value: 500 - type: status_code - - type: duration - op: ">=" - value: 1555500 - type: logical_or - format: '[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% - %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% - %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" - "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%" - "%REQUEST_DURATION%" "%RESPONSE_DURATION%"' - path: "/dev/null" - - path: "/dev/null" - deprecated_v1: true - - address: - socket_address: - address: {{ ip_loopback_address }} - port_value: 0 - filter_chains: - - filters: - - name: envoy.http_connection_manager - config: - value: - filters: - - name: router - config: {} - codec_type: http1 - stat_prefix: rds_dummy - rds: - api_type: REST - route_config_name: foo - cluster: rds - deprecated_v1: true + - status_code_filter: + comparison: + op: GE + value: + default_value: 500 + runtime_key: access_log.access_error.status + - duration_filter: + comparison: + op: GE + value: + default_value: 1000 + runtime_key: access_log.access_error.duration - address: socket_address: address: {{ ip_loopback_address }} @@ -319,12 +79,12 @@ static_resources: - filters: - name: envoy.redis_proxy config: - value: - conn_pool: - op_timeout_ms: 400 - stat_prefix: redis - cluster_name: redis - deprecated_v1: true + settings: + op_timeout: 0.4s + stat_prefix: redis + prefix_routes: + catch_all_route: + cluster: redis clusters: - name: cds connect_timeout: 5s diff --git a/test/config/integration/server_ads.yaml b/test/config/integration/server_ads.yaml deleted file mode 100644 index 3400df7e47e5..000000000000 --- a/test/config/integration/server_ads.yaml +++ /dev/null @@ -1,25 +0,0 @@ -dynamic_resources: - lds_config: {ads: {}} - cds_config: {ads: {}} - ads_config: - api_type: GRPC - grpc_services: - envoy_grpc: - cluster_name: ads_cluster -static_resources: - clusters: - - name: ads_cluster - connect_timeout: { seconds: 5 } - type: STATIC - hosts: - - socket_address: - address: {{ ntop_ip_loopback_address }} - port_value: {{ ads_upstream }} - lb_policy: ROUND_ROBIN - http2_protocol_options: {} -admin: - access_log_path: /dev/null - address: - socket_address: - address: {{ ntop_ip_loopback_address }} - port_value: 0 diff --git a/test/config/integration/server_unix_listener.yaml b/test/config/integration/server_unix_listener.yaml index f76f3bd126b4..0ba01442cb6d 100644 --- a/test/config/integration/server_unix_listener.yaml +++ b/test/config/integration/server_unix_listener.yaml @@ -7,22 +7,20 @@ static_resources: - filters: - name: envoy.http_connection_manager config: - value: - filters: - - name: router - config: {} - codec_type: auto - stat_prefix: router - drain_timeout_ms: 5000 - route_config: - virtual_hosts: - - domains: - - "*" - name: vhost_0 - routes: - - prefix: "/" - cluster: cluster_0 - deprecated_v1: true + filters: + - name: router + config: {} + codec_type: auto + stat_prefix: router + drain_timeout_ms: 5000 + route_config: + virtual_hosts: + - domains: + - "*" + name: vhost_0 + routes: + - match: { prefix: "/" } + route: { cluster: cluster_0 } clusters: - name: cluster_0 connect_timeout: 5s diff --git a/test/config/utility.cc b/test/config/utility.cc index b49638a6ca01..cecf66ca568c 100644 --- a/test/config/utility.cc +++ b/test/config/utility.cc @@ -31,6 +31,15 @@ const std::string ConfigHelper::BASE_CONFIG = R"EOF( lds_config: path: /dev/null static_resources: + secrets: + - name: "secret_static_0" + tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES" + private_key: + inline_string: "DUMMY_INLINE_BYTES" + password: + inline_string: "DUMMY_INLINE_BYTES" clusters: name: cluster_0 hosts: @@ -703,4 +712,5 @@ void EdsHelper::setEdsAndWait( RELEASE_ASSERT( update_successes_ == server_stats.counter("cluster.cluster_0.update_success")->value(), ""); } + } // namespace Envoy diff --git a/test/coverage/gcc_only_test/BUILD b/test/coverage/gcc_only_test/BUILD deleted file mode 100644 index 1482a741b3e3..000000000000 --- a/test/coverage/gcc_only_test/BUILD +++ /dev/null @@ -1,16 +0,0 @@ -licenses(["notice"]) # Apache 2 - -load( - "//bazel:envoy_build_system.bzl", - "envoy_cc_test", - "envoy_package", -) - -envoy_package() - -envoy_cc_test( - name = "gcc_only_test", - srcs = ["gcc_only_test.cc"], - coverage = False, - tags = ["manual"], -) diff --git a/test/coverage/gcc_only_test/gcc_only_test.cc b/test/coverage/gcc_only_test/gcc_only_test.cc deleted file mode 100644 index 31346323d20e..000000000000 --- a/test/coverage/gcc_only_test/gcc_only_test.cc +++ /dev/null @@ -1,12 +0,0 @@ -#include "gtest/gtest.h" - -namespace Envoy { - -TEST(GccOnly, CompilerCheck) { -#if defined(__clang__) or not defined(__GNUC__) - // clang is incompatible with gcov. - FAIL() << "GCC is required for coverage runs"; -#endif -} - -} // namespace Envoy diff --git a/test/coverage/gen_build.sh b/test/coverage/gen_build.sh index 5532e78a5e95..fb79e074745a 100755 --- a/test/coverage/gen_build.sh +++ b/test/coverage/gen_build.sh @@ -44,13 +44,6 @@ if [ -n "${EXTRA_QUERY_PATHS}" ]; then TARGETS="$TARGETS $("${BAZEL_BIN}" query ${BAZEL_QUERY_OPTIONS} "attr('tags', 'coverage_test_lib', ${EXTRA_QUERY_PATHS})" | grep "^//")" fi -# gcov requires gcc -if [ "${NO_GCOV}" != 1 ] -then - # Here we use the synthetic library target created by envoy_build_system.bzl - TARGETS="${TARGETS} ${REPOSITORY}//test/coverage/gcc_only_test:gcc_only_test_lib_internal_only" -fi - ( cat << EOF # This file is generated by test/coverage/gen_build.sh automatically prior to @@ -74,10 +67,14 @@ EOF done cat << EOF ], - tags = ["manual"], + # no-remote due to https://github.com/bazelbuild/bazel/issues/4685 + tags = ["manual", "no-remote"], coverage = False, - # Needed when invoking external shell tests etc. - local = True, + # Due to the nature of coverage_tests, the shard of coverage_tests are very uneven, some of + # shard can take 100s and some takes only 10s, so we use the maximum sharding to here to let + # Bazel scheduling them across CPU cores. + # Sharding can be disabled by --test_sharding_strategy=disabled. + shard_count = 50, ) EOF diff --git a/test/exe/main_common_test.cc b/test/exe/main_common_test.cc index baeeb243976a..4dadcb31875f 100644 --- a/test/exe/main_common_test.cc +++ b/test/exe/main_common_test.cc @@ -147,11 +147,7 @@ INSTANTIATE_TEST_SUITE_P(IpVersions, MainCommonTest, class AdminRequestTest : public MainCommonTest { protected: - AdminRequestTest() - : envoy_return_(false), envoy_started_(false), envoy_finished_(false), - pause_before_run_(false), pause_after_run_(false) { - addArg("--disable-hot-restart"); - } + AdminRequestTest() { addArg("--disable-hot-restart"); } // Runs an admin request specified in path, blocking until completion, and // returning the response body. @@ -210,7 +206,7 @@ class AdminRequestTest : public MainCommonTest { main_common_->dispatcherForTest().post([this, &done] { struct Sacrifice : Event::DeferredDeletable { Sacrifice(absl::Notification& notify) : notify_(notify) {} - ~Sacrifice() { notify_.Notify(); } + ~Sacrifice() override { notify_.Notify(); } absl::Notification& notify_; }; auto sacrifice = std::make_unique(done); @@ -234,11 +230,11 @@ class AdminRequestTest : public MainCommonTest { absl::Notification finished_; absl::Notification resume_; absl::Notification pause_point_; - bool envoy_return_; - bool envoy_started_; - bool envoy_finished_; - bool pause_before_run_; - bool pause_after_run_; + bool envoy_return_{false}; + bool envoy_started_{false}; + bool envoy_finished_{false}; + bool pause_before_run_{false}; + bool pause_after_run_{false}; }; TEST_P(AdminRequestTest, AdminRequestGetStatsAndQuit) { diff --git a/test/extensions/access_loggers/common/BUILD b/test/extensions/access_loggers/common/BUILD new file mode 100644 index 000000000000..9dbb3c91c70f --- /dev/null +++ b/test/extensions/access_loggers/common/BUILD @@ -0,0 +1,19 @@ +licenses(["notice"]) # Apache 2 + +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_test", + "envoy_package", +) + +envoy_package() + +envoy_cc_test( + name = "access_log_base_test", + srcs = ["access_log_base_test.cc"], + deps = [ + "//source/extensions/access_loggers/common:access_log_base", + "//test/mocks/access_log:access_log_mocks", + "//test/mocks/stream_info:stream_info_mocks", + ], +) diff --git a/test/extensions/access_loggers/common/access_log_base_test.cc b/test/extensions/access_loggers/common/access_log_base_test.cc new file mode 100644 index 000000000000..52fcb4a6bcdb --- /dev/null +++ b/test/extensions/access_loggers/common/access_log_base_test.cc @@ -0,0 +1,57 @@ +#include "extensions/access_loggers/common/access_log_base.h" + +#include "test/mocks/access_log/mocks.h" +#include "test/mocks/stream_info/mocks.h" + +#include "gmock/gmock.h" + +namespace Envoy { +namespace Extensions { +namespace AccessLoggers { +namespace Common { +namespace { + +using AccessLog::FilterPtr; +using AccessLog::MockFilter; +using testing::_; +using testing::Return; + +class TestImpl : public ImplBase { +public: + TestImpl(FilterPtr filter) : ImplBase(std::move(filter)) {} + + int count() { return count_; }; + +private: + void emitLog(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, + const StreamInfo::StreamInfo&) override { + count_++; + } + + int count_ = 0; +}; + +TEST(AccessLogBaseTest, NoFilter) { + StreamInfo::MockStreamInfo stream_info; + TestImpl logger(nullptr); + EXPECT_EQ(logger.count(), 0); + logger.log(nullptr, nullptr, nullptr, stream_info); + EXPECT_EQ(logger.count(), 1); +} + +TEST(AccessLogBaseTest, FilterReject) { + StreamInfo::MockStreamInfo stream_info; + + std::unique_ptr filter = std::make_unique(); + EXPECT_CALL(*filter, evaluate(_, _, _, _)).WillOnce(Return(false)); + TestImpl logger(std::move(filter)); + EXPECT_EQ(logger.count(), 0); + logger.log(nullptr, nullptr, nullptr, stream_info); + EXPECT_EQ(logger.count(), 0); +} + +} // namespace +} // namespace Common +} // namespace AccessLoggers +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/access_loggers/http_grpc/grpc_access_log_impl_test.cc b/test/extensions/access_loggers/http_grpc/grpc_access_log_impl_test.cc index 960bddb1b96f..f78eae541e26 100644 --- a/test/extensions/access_loggers/http_grpc/grpc_access_log_impl_test.cc +++ b/test/extensions/access_loggers/http_grpc/grpc_access_log_impl_test.cc @@ -1,5 +1,6 @@ #include +#include "common/buffer/zero_copy_input_stream_impl.h" #include "common/network/address_impl.h" #include "extensions/access_loggers/http_grpc/grpc_access_log_impl.h" @@ -24,18 +25,15 @@ namespace AccessLoggers { namespace HttpGrpc { namespace { -class GrpcAccessLogStreamerImplTest : public testing::Test { +class GrpcAccessLoggerImplTest : public testing::Test { public: using MockAccessLogStream = Grpc::MockAsyncStream; using AccessLogCallbacks = Grpc::AsyncStreamCallbacks; - GrpcAccessLogStreamerImplTest() { - EXPECT_CALL(*factory_, create()).WillOnce(Invoke([this] { - return Grpc::RawAsyncClientPtr{async_client_}; - })); - streamer_ = std::make_unique(Grpc::AsyncClientFactoryPtr{factory_}, - tls_, local_info_); + GrpcAccessLoggerImplTest() { + logger_ = std::make_unique(Grpc::RawAsyncClientPtr{async_client_}, + log_name_, local_info_); } void expectStreamStart(MockAccessLogStream& stream, AccessLogCallbacks** callbacks_to_set) { @@ -47,53 +45,86 @@ class GrpcAccessLogStreamerImplTest : public testing::Test { })); } - NiceMock tls_; + void expectStreamMessage(MockAccessLogStream& stream, const std::string& expected_message_yaml) { + envoy::service::accesslog::v2::StreamAccessLogsMessage expected_message; + TestUtility::loadFromYaml(expected_message_yaml, expected_message); + EXPECT_CALL(stream, sendMessageRaw_(_, false)) + .WillOnce(Invoke([expected_message](Buffer::InstancePtr& request, bool) { + envoy::service::accesslog::v2::StreamAccessLogsMessage message; + Buffer::ZeroCopyInputStreamImpl request_stream(std::move(request)); + EXPECT_TRUE(message.ParseFromZeroCopyStream(&request_stream)); + EXPECT_EQ(message.DebugString(), expected_message.DebugString()); + })); + } + + std::string log_name_ = "test_log_name"; LocalInfo::MockLocalInfo local_info_; Grpc::MockAsyncClient* async_client_{new Grpc::MockAsyncClient}; - Grpc::MockAsyncClientFactory* factory_{new Grpc::MockAsyncClientFactory}; - std::unique_ptr streamer_; + std::unique_ptr logger_; }; // Test basic stream logging flow. -TEST_F(GrpcAccessLogStreamerImplTest, BasicFlow) { +TEST_F(GrpcAccessLoggerImplTest, BasicFlow) { InSequence s; // Start a stream for the first log. - MockAccessLogStream stream1; - AccessLogCallbacks* callbacks1; - expectStreamStart(stream1, &callbacks1); - EXPECT_CALL(local_info_, node()); - EXPECT_CALL(stream1, sendMessageRaw_(_, false)); - envoy::service::accesslog::v2::StreamAccessLogsMessage message_log1; - streamer_->send(message_log1, "log1"); - - message_log1.Clear(); - EXPECT_CALL(stream1, sendMessageRaw_(_, false)); - streamer_->send(message_log1, "log1"); - - // Start a stream for the second log. - MockAccessLogStream stream2; - AccessLogCallbacks* callbacks2; - expectStreamStart(stream2, &callbacks2); + MockAccessLogStream stream; + AccessLogCallbacks* callbacks; + expectStreamStart(stream, &callbacks); EXPECT_CALL(local_info_, node()); - EXPECT_CALL(stream2, sendMessageRaw_(_, false)); - envoy::service::accesslog::v2::StreamAccessLogsMessage message_log2; - streamer_->send(message_log2, "log2"); + expectStreamMessage(stream, R"EOF( +identifier: + node: + id: node_name + cluster: cluster_name + locality: + zone: zone_name + log_name: test_log_name +http_logs: + log_entry: + request: + path: /test/path1 +)EOF"); + envoy::data::accesslog::v2::HTTPAccessLogEntry entry; + entry.mutable_request()->set_path("/test/path1"); + logger_->log(envoy::data::accesslog::v2::HTTPAccessLogEntry(entry)); + + expectStreamMessage(stream, R"EOF( +http_logs: + log_entry: + request: + path: /test/path2 +)EOF"); + entry.mutable_request()->set_path("/test/path2"); + logger_->log(envoy::data::accesslog::v2::HTTPAccessLogEntry(entry)); // Verify that sending an empty response message doesn't do anything bad. - callbacks1->onReceiveMessage( + callbacks->onReceiveMessage( std::make_unique()); - // Close stream 2 and make sure we make a new one. - callbacks2->onRemoteClose(Grpc::Status::Internal, "bad"); - expectStreamStart(stream2, &callbacks2); + // Close the stream and make sure we make a new one. + callbacks->onRemoteClose(Grpc::Status::Internal, "bad"); + expectStreamStart(stream, &callbacks); EXPECT_CALL(local_info_, node()); - EXPECT_CALL(stream2, sendMessageRaw_(_, false)); - streamer_->send(message_log2, "log2"); + expectStreamMessage(stream, R"EOF( +identifier: + node: + id: node_name + cluster: cluster_name + locality: + zone: zone_name + log_name: test_log_name +http_logs: + log_entry: + request: + path: /test/path3 +)EOF"); + entry.mutable_request()->set_path("/test/path3"); + logger_->log(envoy::data::accesslog::v2::HTTPAccessLogEntry(entry)); } // Test that stream failure is handled correctly. -TEST_F(GrpcAccessLogStreamerImplTest, StreamFailure) { +TEST_F(GrpcAccessLoggerImplTest, StreamFailure) { InSequence s; EXPECT_CALL(*async_client_, startRaw(_, _, _)) @@ -103,15 +134,75 @@ TEST_F(GrpcAccessLogStreamerImplTest, StreamFailure) { return nullptr; })); EXPECT_CALL(local_info_, node()); - envoy::service::accesslog::v2::StreamAccessLogsMessage message_log1; - streamer_->send(message_log1, "log1"); + envoy::data::accesslog::v2::HTTPAccessLogEntry entry; + logger_->log(envoy::data::accesslog::v2::HTTPAccessLogEntry(entry)); } -class MockGrpcAccessLogStreamer : public GrpcAccessLogStreamer { +class GrpcAccessLoggerCacheImplTest : public testing::Test { public: - // GrpcAccessLogStreamer - MOCK_METHOD2(send, void(envoy::service::accesslog::v2::StreamAccessLogsMessage& message, - const std::string& log_name)); + GrpcAccessLoggerCacheImplTest() { + logger_cache_ = std::make_unique(async_client_manager_, scope_, tls_, + local_info_); + } + + void expectClientCreation() { + factory_ = new Grpc::MockAsyncClientFactory; + async_client_ = new Grpc::MockAsyncClient; + EXPECT_CALL(async_client_manager_, factoryForGrpcService(_, _, false)) + .WillOnce(Invoke([this](const envoy::api::v2::core::GrpcService&, Stats::Scope&, bool) { + EXPECT_CALL(*factory_, create()).WillOnce(Invoke([this] { + return Grpc::RawAsyncClientPtr{async_client_}; + })); + return Grpc::AsyncClientFactoryPtr{factory_}; + })); + } + + LocalInfo::MockLocalInfo local_info_; + NiceMock tls_; + Grpc::MockAsyncClientManager async_client_manager_; + Grpc::MockAsyncClient* async_client_ = nullptr; + Grpc::MockAsyncClientFactory* factory_ = nullptr; + std::unique_ptr logger_cache_; + NiceMock scope_; +}; + +TEST_F(GrpcAccessLoggerCacheImplTest, Deduplication) { + InSequence s; + + ::envoy::config::accesslog::v2::CommonGrpcAccessLogConfig config; + config.set_log_name("log-1"); + config.mutable_grpc_service()->mutable_envoy_grpc()->set_cluster_name("cluster-1"); + + expectClientCreation(); + GrpcAccessLoggerSharedPtr logger1 = logger_cache_->getOrCreateLogger(config); + EXPECT_EQ(logger1, logger_cache_->getOrCreateLogger(config)); + + // Changing log name leads to another logger. + config.set_log_name("log-2"); + expectClientCreation(); + EXPECT_NE(logger1, logger_cache_->getOrCreateLogger(config)); + + config.set_log_name("log-1"); + EXPECT_EQ(logger1, logger_cache_->getOrCreateLogger(config)); + + // Changing cluster name leads to another logger. + config.mutable_grpc_service()->mutable_envoy_grpc()->set_cluster_name("cluster-2"); + expectClientCreation(); + EXPECT_NE(logger1, logger_cache_->getOrCreateLogger(config)); +} + +class MockGrpcAccessLogger : public GrpcAccessLogger { +public: + // GrpcAccessLogger + MOCK_METHOD1(log, void(envoy::data::accesslog::v2::HTTPAccessLogEntry&& entry)); +}; + +class MockGrpcAccessLoggerCache : public GrpcAccessLoggerCache { +public: + // GrpcAccessLoggerCache + MOCK_METHOD1(getOrCreateLogger, + GrpcAccessLoggerSharedPtr( + const ::envoy::config::accesslog::v2::CommonGrpcAccessLogConfig& config)); }; class HttpGrpcAccessLogTest : public testing::Test { @@ -119,22 +210,26 @@ class HttpGrpcAccessLogTest : public testing::Test { void init() { ON_CALL(*filter_, evaluate(_, _, _, _)).WillByDefault(Return(true)); config_.mutable_common_config()->set_log_name("hello_log"); - access_log_ = - std::make_unique(AccessLog::FilterPtr{filter_}, config_, streamer_); + EXPECT_CALL(*logger_cache_, getOrCreateLogger(_)) + .WillOnce([this](const ::envoy::config::accesslog::v2::CommonGrpcAccessLogConfig& config) { + EXPECT_EQ(config.DebugString(), config_.common_config().DebugString()); + return logger_; + }); + access_log_ = std::make_unique(AccessLog::FilterPtr{filter_}, config_, tls_, + logger_cache_); } - void expectLog(const std::string& expected_request_msg_yaml) { + void expectLog(const std::string& expected_log_entry_yaml) { if (access_log_ == nullptr) { init(); } - envoy::service::accesslog::v2::StreamAccessLogsMessage expected_request_msg; - TestUtility::loadFromYaml(expected_request_msg_yaml, expected_request_msg); - EXPECT_CALL(*streamer_, send(_, "hello_log")) - .WillOnce(Invoke( - [expected_request_msg](envoy::service::accesslog::v2::StreamAccessLogsMessage& message, - const std::string&) { - EXPECT_EQ(message.DebugString(), expected_request_msg.DebugString()); + envoy::data::accesslog::v2::HTTPAccessLogEntry expected_log_entry; + TestUtility::loadFromYaml(expected_log_entry_yaml, expected_log_entry); + EXPECT_CALL(*logger_, log(_)) + .WillOnce( + Invoke([expected_log_entry](envoy::data::accesslog::v2::HTTPAccessLogEntry&& entry) { + EXPECT_EQ(entry.DebugString(), expected_log_entry.DebugString()); })); } @@ -147,30 +242,30 @@ class HttpGrpcAccessLogTest : public testing::Test { }; expectLog(fmt::format(R"EOF( - http_logs: - log_entry: - common_properties: - downstream_remote_address: - socket_address: - address: "127.0.0.1" - port_value: 0 - downstream_local_address: - socket_address: - address: "127.0.0.2" - port_value: 0 - start_time: {{}} - request: - request_method: {} - request_headers_bytes: {} - response: {{}} +common_properties: + downstream_remote_address: + socket_address: + address: "127.0.0.1" + port_value: 0 + downstream_local_address: + socket_address: + address: "127.0.0.2" + port_value: 0 + start_time: {{}} +request: + request_method: {} + request_headers_bytes: {} +response: {{}} )EOF", request_method, request_method.length() + 7)); access_log_->log(&request_headers, nullptr, nullptr, stream_info); } AccessLog::MockFilter* filter_{new NiceMock()}; + NiceMock tls_; envoy::config::accesslog::v2::HttpGrpcAccessLogConfig config_; - std::shared_ptr streamer_{new MockGrpcAccessLogStreamer()}; + std::shared_ptr logger_{new MockGrpcAccessLogger()}; + std::shared_ptr logger_cache_{new MockGrpcAccessLoggerCache()}; std::unique_ptr access_log_; }; @@ -188,25 +283,23 @@ TEST_F(HttpGrpcAccessLogTest, Marshalling) { (*stream_info.metadata_.mutable_filter_metadata())["foo"] = ProtobufWkt::Struct(); expectLog(R"EOF( -http_logs: - log_entry: - common_properties: - downstream_remote_address: - socket_address: - address: "127.0.0.1" - port_value: 0 - downstream_local_address: - pipe: - path: "/foo" - start_time: - seconds: 3600 - time_to_last_downstream_tx_byte: - nanos: 2000000 - metadata: - filter_metadata: - foo: {} - request: {} - response: {} +common_properties: + downstream_remote_address: + socket_address: + address: "127.0.0.1" + port_value: 0 + downstream_local_address: + pipe: + path: "/foo" + start_time: + seconds: 3600 + time_to_last_downstream_tx_byte: + nanos: 2000000 + metadata: + filter_metadata: + foo: {} +request: {} +response: {} )EOF"); access_log_->log(nullptr, nullptr, nullptr, stream_info); } @@ -218,23 +311,21 @@ TEST_F(HttpGrpcAccessLogTest, Marshalling) { stream_info.last_downstream_tx_byte_sent_ = std::chrono::nanoseconds(2000000); expectLog(R"EOF( -http_logs: - log_entry: - common_properties: - downstream_remote_address: - socket_address: - address: "127.0.0.1" - port_value: 0 - downstream_local_address: - socket_address: - address: "127.0.0.2" - port_value: 0 - start_time: - seconds: 3600 - time_to_last_downstream_tx_byte: - nanos: 2000000 - request: {} - response: {} +common_properties: + downstream_remote_address: + socket_address: + address: "127.0.0.1" + port_value: 0 + downstream_local_address: + socket_address: + address: "127.0.0.2" + port_value: 0 + start_time: + seconds: 3600 + time_to_last_downstream_tx_byte: + nanos: 2000000 +request: {} +response: {} )EOF"); access_log_->log(nullptr, nullptr, nullptr, stream_info); } @@ -277,64 +368,62 @@ TEST_F(HttpGrpcAccessLogTest, Marshalling) { Http::TestHeaderMapImpl response_headers{{":status", "200"}}; expectLog(R"EOF( -http_logs: - log_entry: - common_properties: - downstream_remote_address: - socket_address: - address: "127.0.0.1" - port_value: 0 - downstream_local_address: - socket_address: - address: "127.0.0.2" - port_value: 0 - start_time: - seconds: 3600 - time_to_last_rx_byte: - nanos: 2000000 - time_to_first_upstream_tx_byte: - nanos: 4000000 - time_to_last_upstream_tx_byte: - nanos: 6000000 - time_to_first_upstream_rx_byte: - nanos: 8000000 - time_to_last_upstream_rx_byte: - nanos: 10000000 - time_to_first_downstream_tx_byte: - nanos: 12000000 - time_to_last_downstream_tx_byte: - nanos: 14000000 - upstream_remote_address: - socket_address: - address: "10.0.0.1" - port_value: 443 - upstream_local_address: - socket_address: - address: "10.0.0.2" - port_value: 0 - upstream_cluster: "fake_cluster" - response_flags: - fault_injected: true - route_name: "route-name-test" - protocol_version: HTTP10 - request: - scheme: "scheme_value" - authority: "authority_value" - path: "path_value" - user_agent: "user-agent_value" - referer: "referer_value" - forwarded_for: "x-forwarded-for_value" - request_id: "x-request-id_value" - original_path: "x-envoy-original-path_value" - request_headers_bytes: 230 - request_body_bytes: 10 - request_method: "POST" - response: - response_code: - value: 200 - response_headers_bytes: 10 - response_body_bytes: 20 - response_code_details: "via_upstream" +common_properties: + downstream_remote_address: + socket_address: + address: "127.0.0.1" + port_value: 0 + downstream_local_address: + socket_address: + address: "127.0.0.2" + port_value: 0 + start_time: + seconds: 3600 + time_to_last_rx_byte: + nanos: 2000000 + time_to_first_upstream_tx_byte: + nanos: 4000000 + time_to_last_upstream_tx_byte: + nanos: 6000000 + time_to_first_upstream_rx_byte: + nanos: 8000000 + time_to_last_upstream_rx_byte: + nanos: 10000000 + time_to_first_downstream_tx_byte: + nanos: 12000000 + time_to_last_downstream_tx_byte: + nanos: 14000000 + upstream_remote_address: + socket_address: + address: "10.0.0.1" + port_value: 443 + upstream_local_address: + socket_address: + address: "10.0.0.2" + port_value: 0 + upstream_cluster: "fake_cluster" + response_flags: + fault_injected: true + route_name: "route-name-test" +protocol_version: HTTP10 +request: + scheme: "scheme_value" + authority: "authority_value" + path: "path_value" + user_agent: "user-agent_value" + referer: "referer_value" + forwarded_for: "x-forwarded-for_value" + request_id: "x-request-id_value" + original_path: "x-envoy-original-path_value" + request_headers_bytes: 230 + request_body_bytes: 10 + request_method: "POST" +response: + response_code: + value: 200 + response_headers_bytes: 10 + response_body_bytes: 20 + response_code_details: "via_upstream" )EOF"); access_log_->log(&request_headers, &response_headers, nullptr, stream_info); } @@ -350,24 +439,22 @@ TEST_F(HttpGrpcAccessLogTest, Marshalling) { }; expectLog(R"EOF( -http_logs: - log_entry: - common_properties: - downstream_remote_address: - socket_address: - address: "127.0.0.1" - port_value: 0 - downstream_local_address: - socket_address: - address: "127.0.0.2" - port_value: 0 - start_time: - seconds: 3600 - upstream_transport_failure_reason: "TLS error" - request: - request_method: "METHOD_UNSPECIFIED" - request_headers_bytes: 16 - response: {} +common_properties: + downstream_remote_address: + socket_address: + address: "127.0.0.1" + port_value: 0 + downstream_local_address: + socket_address: + address: "127.0.0.2" + port_value: 0 + start_time: + seconds: 3600 + upstream_transport_failure_reason: "TLS error" +request: + request_method: "METHOD_UNSPECIFIED" + request_headers_bytes: 16 +response: {} )EOF"); access_log_->log(&request_headers, nullptr, nullptr, stream_info); } @@ -396,38 +483,36 @@ TEST_F(HttpGrpcAccessLogTest, Marshalling) { }; expectLog(R"EOF( -http_logs: - log_entry: - common_properties: - downstream_remote_address: - socket_address: - address: "127.0.0.1" - port_value: 0 - downstream_local_address: - socket_address: - address: "127.0.0.2" - port_value: 0 - start_time: - seconds: 3600 - tls_properties: - tls_version: TLSv1_3 - tls_cipher_suite: 0x2cc0 - tls_sni_hostname: sni - local_certificate_properties: - subject_alt_name: - - uri: localSan1 - - uri: localSan2 - subject: localSubject - peer_certificate_properties: - subject_alt_name: - - uri: peerSan1 - - uri: peerSan2 - subject: peerSubject - tls_session_id: D62A523A65695219D46FE1FFE285A4C371425ACE421B110B5B8D11D3EB4D5F0B - request: - request_method: "METHOD_UNSPECIFIED" - request_headers_bytes: 16 - response: {} +common_properties: + downstream_remote_address: + socket_address: + address: "127.0.0.1" + port_value: 0 + downstream_local_address: + socket_address: + address: "127.0.0.2" + port_value: 0 + start_time: + seconds: 3600 + tls_properties: + tls_version: TLSv1_3 + tls_cipher_suite: 0x2cc0 + tls_sni_hostname: sni + local_certificate_properties: + subject_alt_name: + - uri: localSan1 + - uri: localSan2 + subject: localSubject + peer_certificate_properties: + subject_alt_name: + - uri: peerSan1 + - uri: peerSan2 + subject: peerSubject + tls_session_id: D62A523A65695219D46FE1FFE285A4C371425ACE421B110B5B8D11D3EB4D5F0B +request: + request_method: "METHOD_UNSPECIFIED" + request_headers_bytes: 16 +response: {} )EOF"); access_log_->log(&request_headers, nullptr, nullptr, stream_info); } @@ -449,28 +534,26 @@ TEST_F(HttpGrpcAccessLogTest, Marshalling) { }; expectLog(R"EOF( -http_logs: - log_entry: - common_properties: - downstream_remote_address: - socket_address: - address: "127.0.0.1" - port_value: 0 - downstream_local_address: - socket_address: - address: "127.0.0.2" - port_value: 0 - start_time: - seconds: 3600 - tls_properties: - tls_version: TLSv1_2 - tls_cipher_suite: 0x2f - tls_sni_hostname: sni - local_certificate_properties: {} - peer_certificate_properties: {} - request: - request_method: "METHOD_UNSPECIFIED" - response: {} +common_properties: + downstream_remote_address: + socket_address: + address: "127.0.0.1" + port_value: 0 + downstream_local_address: + socket_address: + address: "127.0.0.2" + port_value: 0 + start_time: + seconds: 3600 + tls_properties: + tls_version: TLSv1_2 + tls_cipher_suite: 0x2f + tls_sni_hostname: sni + local_certificate_properties: {} + peer_certificate_properties: {} +request: + request_method: "METHOD_UNSPECIFIED" +response: {} )EOF"); access_log_->log(nullptr, nullptr, nullptr, stream_info); } @@ -492,28 +575,26 @@ TEST_F(HttpGrpcAccessLogTest, Marshalling) { }; expectLog(R"EOF( -http_logs: - log_entry: - common_properties: - downstream_remote_address: - socket_address: - address: "127.0.0.1" - port_value: 0 - downstream_local_address: - socket_address: - address: "127.0.0.2" - port_value: 0 - start_time: - seconds: 3600 - tls_properties: - tls_version: TLSv1_1 - tls_cipher_suite: 0x2f - tls_sni_hostname: sni - local_certificate_properties: {} - peer_certificate_properties: {} - request: - request_method: "METHOD_UNSPECIFIED" - response: {} +common_properties: + downstream_remote_address: + socket_address: + address: "127.0.0.1" + port_value: 0 + downstream_local_address: + socket_address: + address: "127.0.0.2" + port_value: 0 + start_time: + seconds: 3600 + tls_properties: + tls_version: TLSv1_1 + tls_cipher_suite: 0x2f + tls_sni_hostname: sni + local_certificate_properties: {} + peer_certificate_properties: {} +request: + request_method: "METHOD_UNSPECIFIED" +response: {} )EOF"); access_log_->log(nullptr, nullptr, nullptr, stream_info); } @@ -535,28 +616,26 @@ TEST_F(HttpGrpcAccessLogTest, Marshalling) { }; expectLog(R"EOF( -http_logs: - log_entry: - common_properties: - downstream_remote_address: - socket_address: - address: "127.0.0.1" - port_value: 0 - downstream_local_address: - socket_address: - address: "127.0.0.2" - port_value: 0 - start_time: - seconds: 3600 - tls_properties: - tls_version: TLSv1 - tls_cipher_suite: 0x2f - tls_sni_hostname: sni - local_certificate_properties: {} - peer_certificate_properties: {} - request: - request_method: "METHOD_UNSPECIFIED" - response: {} +common_properties: + downstream_remote_address: + socket_address: + address: "127.0.0.1" + port_value: 0 + downstream_local_address: + socket_address: + address: "127.0.0.2" + port_value: 0 + start_time: + seconds: 3600 + tls_properties: + tls_version: TLSv1 + tls_cipher_suite: 0x2f + tls_sni_hostname: sni + local_certificate_properties: {} + peer_certificate_properties: {} +request: + request_method: "METHOD_UNSPECIFIED" +response: {} )EOF"); access_log_->log(nullptr, nullptr, nullptr, stream_info); } @@ -578,28 +657,26 @@ TEST_F(HttpGrpcAccessLogTest, Marshalling) { }; expectLog(R"EOF( -http_logs: - log_entry: - common_properties: - downstream_remote_address: - socket_address: - address: "127.0.0.1" - port_value: 0 - downstream_local_address: - socket_address: - address: "127.0.0.2" - port_value: 0 - start_time: - seconds: 3600 - tls_properties: - tls_version: VERSION_UNSPECIFIED - tls_cipher_suite: 0x2f - tls_sni_hostname: sni - local_certificate_properties: {} - peer_certificate_properties: {} - request: - request_method: "METHOD_UNSPECIFIED" - response: {} +common_properties: + downstream_remote_address: + socket_address: + address: "127.0.0.1" + port_value: 0 + downstream_local_address: + socket_address: + address: "127.0.0.2" + port_value: 0 + start_time: + seconds: 3600 + tls_properties: + tls_version: VERSION_UNSPECIFIED + tls_cipher_suite: 0x2f + tls_sni_hostname: sni + local_certificate_properties: {} + peer_certificate_properties: {} +request: + request_method: "METHOD_UNSPECIFIED" +response: {} )EOF"); access_log_->log(nullptr, nullptr, nullptr, stream_info); } @@ -653,38 +730,36 @@ TEST_F(HttpGrpcAccessLogTest, MarshallingAdditionalHeaders) { }; expectLog(R"EOF( -http_logs: - log_entry: - common_properties: - downstream_remote_address: - socket_address: - address: "127.0.0.1" - port_value: 0 - downstream_local_address: - socket_address: - address: "127.0.0.2" - port_value: 0 - start_time: - seconds: 3600 - request: - scheme: "scheme_value" - authority: "authority_value" - path: "path_value" - request_method: "POST" - request_headers_bytes: 132 - request_headers: - "x-custom-request": "custom_value" - "x-custom-empty": "" - "x-envoy-max-retries": "3" - response: - response_headers_bytes: 92 - response_headers: - "x-custom-response": "custom_value" - "x-custom-empty": "" - "x-envoy-immediate-health-check-fail": "true" - response_trailers: - "x-logged-trailer": "value" - "x-empty-trailer": "" +common_properties: + downstream_remote_address: + socket_address: + address: "127.0.0.1" + port_value: 0 + downstream_local_address: + socket_address: + address: "127.0.0.2" + port_value: 0 + start_time: + seconds: 3600 +request: + scheme: "scheme_value" + authority: "authority_value" + path: "path_value" + request_method: "POST" + request_headers_bytes: 132 + request_headers: + "x-custom-request": "custom_value" + "x-custom-empty": "" + "x-envoy-max-retries": "3" +response: + response_headers_bytes: 92 + response_headers: + "x-custom-response": "custom_value" + "x-custom-empty": "" + "x-envoy-immediate-health-check-fail": "true" + response_trailers: + "x-logged-trailer": "value" + "x-empty-trailer": "" )EOF"); access_log_->log(&request_headers, &response_headers, &response_trailers, stream_info); } diff --git a/test/extensions/clusters/dynamic_forward_proxy/cluster_test.cc b/test/extensions/clusters/dynamic_forward_proxy/cluster_test.cc index 6d8db1e762b7..7e5ef2ae8f74 100644 --- a/test/extensions/clusters/dynamic_forward_proxy/cluster_test.cc +++ b/test/extensions/clusters/dynamic_forward_proxy/cluster_test.cc @@ -67,6 +67,7 @@ class ClusterTest : public testing::Test, // Allow touch() to still be strict. EXPECT_CALL(*host_map_[host], address()).Times(AtLeast(0)); + EXPECT_CALL(*host_map_[host], isIpAddress()).Times(AtLeast(0)); EXPECT_CALL(*host_map_[host], resolvedHost()).Times(AtLeast(0)); } diff --git a/test/extensions/clusters/redis/mocks.h b/test/extensions/clusters/redis/mocks.h index 3f4940836f91..7269548b1b2c 100644 --- a/test/extensions/clusters/redis/mocks.h +++ b/test/extensions/clusters/redis/mocks.h @@ -15,7 +15,7 @@ namespace Redis { class MockClusterSlotUpdateCallBack : public ClusterSlotUpdateCallBack { public: MockClusterSlotUpdateCallBack(); - ~MockClusterSlotUpdateCallBack() = default; + ~MockClusterSlotUpdateCallBack() override = default; MOCK_METHOD2(onClusterSlotUpdate, bool(const std::vector&, Upstream::HostMap)); }; diff --git a/test/extensions/clusters/redis/redis_cluster_integration_test.cc b/test/extensions/clusters/redis/redis_cluster_integration_test.cc index 45924a3a218b..546fee9a81c4 100644 --- a/test/extensions/clusters/redis/redis_cluster_integration_test.cc +++ b/test/extensions/clusters/redis/redis_cluster_integration_test.cc @@ -1,6 +1,8 @@ #include #include +#include "common/common/macros.h" + #include "extensions/filters/network/redis_proxy/command_splitter_impl.h" #include "test/integration/integration.h" @@ -14,7 +16,8 @@ namespace { // in the cluster. The load balancing policy must be set // to random for proper test operation. -const std::string CONFIG = R"EOF( +const std::string& testConfig() { + CONSTRUCT_ON_FIRST_USE(std::string, R"EOF( admin: access_log_path: /dev/null address: @@ -50,15 +53,18 @@ const std::string CONFIG = R"EOF( value: cluster_refresh_rate: 1s cluster_refresh_timeout: 4s -)EOF"; +)EOF"); +} // This is the basic redis_proxy configuration with an upstream // authentication password specified. -const std::string CONFIG_WITH_AUTH = CONFIG + R"EOF( +const std::string& testConfigWithAuth() { + CONSTRUCT_ON_FIRST_USE(std::string, testConfig() + R"EOF( extension_protocol_options: envoy.redis_proxy: { auth_password: { inline_string: somepassword }} -)EOF"; +)EOF"); +} // This function encodes commands as an array of bulkstrings as transmitted by Redis clients to // Redis servers, according to the Redis protocol. @@ -77,7 +83,7 @@ std::string makeBulkStringArray(std::vector&& command_strings) { class RedisClusterIntegrationTest : public testing::TestWithParam, public BaseIntegrationTest { public: - RedisClusterIntegrationTest(const std::string& config = CONFIG, int num_upstreams = 2) + RedisClusterIntegrationTest(const std::string& config = testConfig(), int num_upstreams = 2) : BaseIntegrationTest(GetParam(), config), num_upstreams_(num_upstreams), version_(GetParam()) {} @@ -265,7 +271,7 @@ class RedisClusterIntegrationTest : public testing::TestWithParamaddUpdateCallbacks(update_callbacks_); } - ~DnsCacheImplTest() { + ~DnsCacheImplTest() override { dns_cache_.reset(); EXPECT_EQ(0, TestUtility::findGauge(store_, "dns_cache.foo.num_hosts")->value()); } @@ -58,10 +58,22 @@ class DnsCacheImplTest : public testing::Test, public Event::TestUsingSimulatedT DnsCache::AddUpdateCallbacksHandlePtr update_callbacks_handle_; }; -MATCHER_P(SharedAddressEquals, expected, "") { - const bool equal = expected == arg->address()->asString(); +MATCHER_P3(DnsHostInfoEquals, address, resolved_host, is_ip_address, "") { + bool equal = address == arg->address()->asString(); if (!equal) { - *result_listener << fmt::format("'{}' != '{}'", expected, arg->address()->asString()); + *result_listener << fmt::format("address '{}' != '{}'", address, arg->address()->asString()); + return equal; + } + equal &= resolved_host == arg->resolvedHost(); + if (!equal) { + *result_listener << fmt::format("resolved_host '{}' != '{}'", resolved_host, + arg->resolvedHost()); + return equal; + } + equal &= is_ip_address == arg->isIpAddress(); + if (!equal) { + *result_listener << fmt::format("is_ip_address '{}' != '{}'", is_ip_address, + arg->isIpAddress()); } return equal; } @@ -84,7 +96,7 @@ TEST_F(DnsCacheImplTest, ResolveSuccess) { 1 /* added */, 0 /* removed */, 1 /* num hosts */); EXPECT_CALL(update_callbacks_, - onDnsHostAddOrUpdate("foo.com", SharedAddressEquals("10.0.0.1:80"))); + onDnsHostAddOrUpdate("foo.com", DnsHostInfoEquals("10.0.0.1:80", "foo.com", false))); EXPECT_CALL(callbacks, onLoadDnsCacheComplete()); EXPECT_CALL(*resolve_timer, enableTimer(std::chrono::milliseconds(60000))); resolve_cb(TestUtility::makeDnsResponse({"10.0.0.1"})); @@ -117,7 +129,7 @@ TEST_F(DnsCacheImplTest, ResolveSuccess) { // Address does change. EXPECT_CALL(update_callbacks_, - onDnsHostAddOrUpdate("foo.com", SharedAddressEquals("10.0.0.2:80"))); + onDnsHostAddOrUpdate("foo.com", DnsHostInfoEquals("10.0.0.2:80", "foo.com", false))); EXPECT_CALL(*resolve_timer, enableTimer(std::chrono::milliseconds(60000))); resolve_cb(TestUtility::makeDnsResponse({"10.0.0.2"})); @@ -125,6 +137,92 @@ TEST_F(DnsCacheImplTest, ResolveSuccess) { 1 /* added */, 0 /* removed */, 1 /* num hosts */); } +// Ipv4 address. +TEST_F(DnsCacheImplTest, Ipv4Address) { + initialize(); + InSequence s; + + MockLoadDnsCacheEntryCallbacks callbacks; + Network::DnsResolver::ResolveCb resolve_cb; + Event::MockTimer* resolve_timer = new Event::MockTimer(&dispatcher_); + EXPECT_CALL(*resolver_, resolve("127.0.0.1", _, _)) + .WillOnce(DoAll(SaveArg<2>(&resolve_cb), Return(&resolver_->active_query_))); + auto result = dns_cache_->loadDnsCacheEntry("127.0.0.1", 80, callbacks); + EXPECT_EQ(DnsCache::LoadDnsCacheEntryStatus::Loading, result.status_); + EXPECT_NE(result.handle_, nullptr); + + EXPECT_CALL( + update_callbacks_, + onDnsHostAddOrUpdate("127.0.0.1", DnsHostInfoEquals("127.0.0.1:80", "127.0.0.1", true))); + EXPECT_CALL(callbacks, onLoadDnsCacheComplete()); + EXPECT_CALL(*resolve_timer, enableTimer(std::chrono::milliseconds(60000))); + resolve_cb(TestUtility::makeDnsResponse({"127.0.0.1"})); +} + +// Ipv4 address with port. +TEST_F(DnsCacheImplTest, Ipv4AddressWithPort) { + initialize(); + InSequence s; + + MockLoadDnsCacheEntryCallbacks callbacks; + Network::DnsResolver::ResolveCb resolve_cb; + Event::MockTimer* resolve_timer = new Event::MockTimer(&dispatcher_); + EXPECT_CALL(*resolver_, resolve("127.0.0.1", _, _)) + .WillOnce(DoAll(SaveArg<2>(&resolve_cb), Return(&resolver_->active_query_))); + auto result = dns_cache_->loadDnsCacheEntry("127.0.0.1:10000", 80, callbacks); + EXPECT_EQ(DnsCache::LoadDnsCacheEntryStatus::Loading, result.status_); + EXPECT_NE(result.handle_, nullptr); + + EXPECT_CALL(update_callbacks_, + onDnsHostAddOrUpdate("127.0.0.1:10000", + DnsHostInfoEquals("127.0.0.1:10000", "127.0.0.1", true))); + EXPECT_CALL(callbacks, onLoadDnsCacheComplete()); + EXPECT_CALL(*resolve_timer, enableTimer(std::chrono::milliseconds(60000))); + resolve_cb(TestUtility::makeDnsResponse({"127.0.0.1"})); +} + +// Ipv6 address. +TEST_F(DnsCacheImplTest, Ipv6Address) { + initialize(); + InSequence s; + + MockLoadDnsCacheEntryCallbacks callbacks; + Network::DnsResolver::ResolveCb resolve_cb; + Event::MockTimer* resolve_timer = new Event::MockTimer(&dispatcher_); + EXPECT_CALL(*resolver_, resolve("::1", _, _)) + .WillOnce(DoAll(SaveArg<2>(&resolve_cb), Return(&resolver_->active_query_))); + auto result = dns_cache_->loadDnsCacheEntry("[::1]", 80, callbacks); + EXPECT_EQ(DnsCache::LoadDnsCacheEntryStatus::Loading, result.status_); + EXPECT_NE(result.handle_, nullptr); + + EXPECT_CALL(update_callbacks_, + onDnsHostAddOrUpdate("[::1]", DnsHostInfoEquals("[::1]:80", "::1", true))); + EXPECT_CALL(callbacks, onLoadDnsCacheComplete()); + EXPECT_CALL(*resolve_timer, enableTimer(std::chrono::milliseconds(60000))); + resolve_cb(TestUtility::makeDnsResponse({"::1"})); +} + +// Ipv6 address with port. +TEST_F(DnsCacheImplTest, Ipv6AddressWithPort) { + initialize(); + InSequence s; + + MockLoadDnsCacheEntryCallbacks callbacks; + Network::DnsResolver::ResolveCb resolve_cb; + Event::MockTimer* resolve_timer = new Event::MockTimer(&dispatcher_); + EXPECT_CALL(*resolver_, resolve("::1", _, _)) + .WillOnce(DoAll(SaveArg<2>(&resolve_cb), Return(&resolver_->active_query_))); + auto result = dns_cache_->loadDnsCacheEntry("[::1]:10000", 80, callbacks); + EXPECT_EQ(DnsCache::LoadDnsCacheEntryStatus::Loading, result.status_); + EXPECT_NE(result.handle_, nullptr); + + EXPECT_CALL(update_callbacks_, + onDnsHostAddOrUpdate("[::1]:10000", DnsHostInfoEquals("[::1]:10000", "::1", true))); + EXPECT_CALL(callbacks, onLoadDnsCacheComplete()); + EXPECT_CALL(*resolve_timer, enableTimer(std::chrono::milliseconds(60000))); + resolve_cb(TestUtility::makeDnsResponse({"::1"})); +} + // TTL purge test. TEST_F(DnsCacheImplTest, TTL) { initialize(); @@ -143,7 +241,7 @@ TEST_F(DnsCacheImplTest, TTL) { 1 /* added */, 0 /* removed */, 1 /* num hosts */); EXPECT_CALL(update_callbacks_, - onDnsHostAddOrUpdate("foo.com", SharedAddressEquals("10.0.0.1:80"))); + onDnsHostAddOrUpdate("foo.com", DnsHostInfoEquals("10.0.0.1:80", "foo.com", false))); EXPECT_CALL(callbacks, onLoadDnsCacheComplete()); EXPECT_CALL(*resolve_timer, enableTimer(std::chrono::milliseconds(60000))); resolve_cb(TestUtility::makeDnsResponse({"10.0.0.1"}, std::chrono::seconds(0))); @@ -200,7 +298,7 @@ TEST_F(DnsCacheImplTest, TTLWithCustomParameters) { EXPECT_NE(result.handle_, nullptr); EXPECT_CALL(update_callbacks_, - onDnsHostAddOrUpdate("foo.com", SharedAddressEquals("10.0.0.1:80"))); + onDnsHostAddOrUpdate("foo.com", DnsHostInfoEquals("10.0.0.1:80", "foo.com", false))); EXPECT_CALL(callbacks, onLoadDnsCacheComplete()); EXPECT_CALL(*resolve_timer, enableTimer(std::chrono::milliseconds(30000))); resolve_cb(TestUtility::makeDnsResponse({"10.0.0.1"}, std::chrono::seconds(0))); @@ -238,8 +336,9 @@ TEST_F(DnsCacheImplTest, InlineResolve) { callback(TestUtility::makeDnsResponse({"127.0.0.1"})); return nullptr; })); - EXPECT_CALL(update_callbacks_, - onDnsHostAddOrUpdate("localhost", SharedAddressEquals("127.0.0.1:80"))); + EXPECT_CALL( + update_callbacks_, + onDnsHostAddOrUpdate("localhost", DnsHostInfoEquals("127.0.0.1:80", "localhost", false))); EXPECT_CALL(callbacks, onLoadDnsCacheComplete()); EXPECT_CALL(*resolve_timer, enableTimer(std::chrono::milliseconds(60000))); post_cb(); @@ -286,7 +385,7 @@ TEST_F(DnsCacheImplTest, CancelResolve) { result.handle_.reset(); EXPECT_CALL(update_callbacks_, - onDnsHostAddOrUpdate("foo.com", SharedAddressEquals("10.0.0.1:80"))); + onDnsHostAddOrUpdate("foo.com", DnsHostInfoEquals("10.0.0.1:80", "foo.com", false))); resolve_cb(TestUtility::makeDnsResponse({"10.0.0.1"})); } @@ -310,7 +409,7 @@ TEST_F(DnsCacheImplTest, MultipleResolveSameHost) { EXPECT_NE(result2.handle_, nullptr); EXPECT_CALL(update_callbacks_, - onDnsHostAddOrUpdate("foo.com", SharedAddressEquals("10.0.0.1:80"))); + onDnsHostAddOrUpdate("foo.com", DnsHostInfoEquals("10.0.0.1:80", "foo.com", false))); EXPECT_CALL(callbacks2, onLoadDnsCacheComplete()); EXPECT_CALL(callbacks1, onLoadDnsCacheComplete()); resolve_cb(TestUtility::makeDnsResponse({"10.0.0.1"})); @@ -338,12 +437,12 @@ TEST_F(DnsCacheImplTest, MultipleResolveDifferentHost) { EXPECT_NE(result2.handle_, nullptr); EXPECT_CALL(update_callbacks_, - onDnsHostAddOrUpdate("bar.com", SharedAddressEquals("10.0.0.1:443"))); + onDnsHostAddOrUpdate("bar.com", DnsHostInfoEquals("10.0.0.1:443", "bar.com", false))); EXPECT_CALL(callbacks2, onLoadDnsCacheComplete()); resolve_cb2(TestUtility::makeDnsResponse({"10.0.0.1"})); EXPECT_CALL(update_callbacks_, - onDnsHostAddOrUpdate("foo.com", SharedAddressEquals("10.0.0.2:80"))); + onDnsHostAddOrUpdate("foo.com", DnsHostInfoEquals("10.0.0.2:80", "foo.com", false))); EXPECT_CALL(callbacks1, onLoadDnsCacheComplete()); resolve_cb1(TestUtility::makeDnsResponse({"10.0.0.2"})); } @@ -362,7 +461,7 @@ TEST_F(DnsCacheImplTest, CacheHit) { EXPECT_NE(result.handle_, nullptr); EXPECT_CALL(update_callbacks_, - onDnsHostAddOrUpdate("foo.com", SharedAddressEquals("10.0.0.1:80"))); + onDnsHostAddOrUpdate("foo.com", DnsHostInfoEquals("10.0.0.1:80", "foo.com", false))); EXPECT_CALL(callbacks, onLoadDnsCacheComplete()); resolve_cb(TestUtility::makeDnsResponse({"10.0.0.1"})); diff --git a/test/extensions/common/dynamic_forward_proxy/mocks.h b/test/extensions/common/dynamic_forward_proxy/mocks.h index 0c65895c1f7d..7f7a57d22ac6 100644 --- a/test/extensions/common/dynamic_forward_proxy/mocks.h +++ b/test/extensions/common/dynamic_forward_proxy/mocks.h @@ -12,7 +12,7 @@ namespace DynamicForwardProxy { class MockDnsCache : public DnsCache { public: MockDnsCache(); - ~MockDnsCache(); + ~MockDnsCache() override; struct MockLoadDnsCacheEntryResult { LoadDnsCacheEntryStatus status_; @@ -38,7 +38,7 @@ class MockDnsCache : public DnsCache { class MockLoadDnsCacheEntryHandle : public DnsCache::LoadDnsCacheEntryHandle { public: MockLoadDnsCacheEntryHandle(); - ~MockLoadDnsCacheEntryHandle(); + ~MockLoadDnsCacheEntryHandle() override; MOCK_METHOD0(onDestroy, void()); }; @@ -46,7 +46,7 @@ class MockLoadDnsCacheEntryHandle : public DnsCache::LoadDnsCacheEntryHandle { class MockDnsCacheManager : public DnsCacheManager { public: MockDnsCacheManager(); - ~MockDnsCacheManager(); + ~MockDnsCacheManager() override; MOCK_METHOD1( getCache, @@ -59,10 +59,11 @@ class MockDnsCacheManager : public DnsCacheManager { class MockDnsHostInfo : public DnsHostInfo { public: MockDnsHostInfo(); - ~MockDnsHostInfo(); + ~MockDnsHostInfo() override; MOCK_METHOD0(address, Network::Address::InstanceConstSharedPtr()); MOCK_METHOD0(resolvedHost, const std::string&()); + MOCK_METHOD0(isIpAddress, bool()); MOCK_METHOD0(touch, void()); Network::Address::InstanceConstSharedPtr address_; @@ -72,7 +73,7 @@ class MockDnsHostInfo : public DnsHostInfo { class MockUpdateCallbacks : public DnsCache::UpdateCallbacks { public: MockUpdateCallbacks(); - ~MockUpdateCallbacks(); + ~MockUpdateCallbacks() override; MOCK_METHOD2(onDnsHostAddOrUpdate, void(const std::string& host, const DnsHostInfoSharedPtr& address)); @@ -82,7 +83,7 @@ class MockUpdateCallbacks : public DnsCache::UpdateCallbacks { class MockLoadDnsCacheEntryCallbacks : public DnsCache::LoadDnsCacheEntryCallbacks { public: MockLoadDnsCacheEntryCallbacks(); - ~MockLoadDnsCacheEntryCallbacks(); + ~MockLoadDnsCacheEntryCallbacks() override; MOCK_METHOD0(onLoadDnsCacheComplete, void()); }; diff --git a/test/extensions/common/tap/admin_test.cc b/test/extensions/common/tap/admin_test.cc index 8af525043213..4c7428a62820 100644 --- a/test/extensions/common/tap/admin_test.cc +++ b/test/extensions/common/tap/admin_test.cc @@ -30,7 +30,9 @@ class AdminHandlerTest : public testing::Test { handler_ = std::make_unique(admin_, main_thread_dispatcher_); } - ~AdminHandlerTest() { EXPECT_CALL(admin_, removeHandler("/tap")).WillOnce(Return(true)); } + ~AdminHandlerTest() override { + EXPECT_CALL(admin_, removeHandler("/tap")).WillOnce(Return(true)); + } Server::MockAdmin admin_; Event::MockDispatcher main_thread_dispatcher_; diff --git a/test/extensions/common/tap/common.h b/test/extensions/common/tap/common.h index b98ed66f60b6..dda23a913472 100644 --- a/test/extensions/common/tap/common.h +++ b/test/extensions/common/tap/common.h @@ -37,7 +37,7 @@ namespace Tap { class MockPerTapSinkHandleManager : public PerTapSinkHandleManager { public: MockPerTapSinkHandleManager(); - ~MockPerTapSinkHandleManager(); + ~MockPerTapSinkHandleManager() override; void submitTrace(TraceWrapperPtr&& trace) override { submitTrace_(*trace); } @@ -47,7 +47,7 @@ class MockPerTapSinkHandleManager : public PerTapSinkHandleManager { class MockMatcher : public Matcher { public: using Matcher::Matcher; - ~MockMatcher(); + ~MockMatcher() override; MOCK_CONST_METHOD1(onNewStream, void(MatchStatusVector& statuses)); MOCK_CONST_METHOD2(onHttpRequestHeaders, diff --git a/test/extensions/filters/common/ext_authz/mocks.h b/test/extensions/filters/common/ext_authz/mocks.h index 75ffe3d391c8..8d2dd1a31365 100644 --- a/test/extensions/filters/common/ext_authz/mocks.h +++ b/test/extensions/filters/common/ext_authz/mocks.h @@ -16,7 +16,7 @@ namespace ExtAuthz { class MockClient : public Client { public: MockClient(); - ~MockClient(); + ~MockClient() override; // ExtAuthz::Client MOCK_METHOD0(cancel, void()); @@ -28,7 +28,7 @@ class MockClient : public Client { class MockRequestCallbacks : public RequestCallbacks { public: MockRequestCallbacks(); - ~MockRequestCallbacks(); + ~MockRequestCallbacks() override; void onComplete(ResponsePtr&& response) override { onComplete_(response); } diff --git a/test/extensions/filters/common/lua/lua_test.cc b/test/extensions/filters/common/lua/lua_test.cc index b2996f1b92aa..5c430403793a 100644 --- a/test/extensions/filters/common/lua/lua_test.cc +++ b/test/extensions/filters/common/lua/lua_test.cc @@ -23,7 +23,7 @@ namespace { // not aligned by Envoy. See https://github.com/envoyproxy/envoy/issues/5551 for details. class alignas(32) TestObject : public BaseLuaObject { public: - ~TestObject() { onDestroy(); } + ~TestObject() override { onDestroy(); } static ExportedFunctions exportedFunctions() { return {{"testCall", static_luaTestCall}}; } diff --git a/test/extensions/filters/common/lua/wrappers_test.cc b/test/extensions/filters/common/lua/wrappers_test.cc index 46428f22aec7..926db9ce3d5e 100644 --- a/test/extensions/filters/common/lua/wrappers_test.cc +++ b/test/extensions/filters/common/lua/wrappers_test.cc @@ -18,7 +18,7 @@ class LuaBufferWrapperTest : public LuaWrappersTestBase {}; class LuaMetadataMapWrapperTest : public LuaWrappersTestBase { public: - virtual void setup(const std::string& script) { + void setup(const std::string& script) override { LuaWrappersTestBase::setup(script); state_->registerType(); } @@ -32,7 +32,7 @@ class LuaMetadataMapWrapperTest : public LuaWrappersTestBase class LuaConnectionWrapperTest : public LuaWrappersTestBase { public: - virtual void setup(const std::string& script) { + void setup(const std::string& script) override { LuaWrappersTestBase::setup(script); state_->registerType(); } diff --git a/test/extensions/filters/common/ratelimit/mocks.h b/test/extensions/filters/common/ratelimit/mocks.h index accaa311aa4c..4c84e385eef2 100644 --- a/test/extensions/filters/common/ratelimit/mocks.h +++ b/test/extensions/filters/common/ratelimit/mocks.h @@ -18,7 +18,7 @@ namespace RateLimit { class MockClient : public Client { public: MockClient(); - ~MockClient(); + ~MockClient() override; // RateLimit::Client MOCK_METHOD0(cancel, void()); diff --git a/test/extensions/filters/common/ratelimit/ratelimit_impl_test.cc b/test/extensions/filters/common/ratelimit/ratelimit_impl_test.cc index 85c704dfa2de..97a5863c0bb6 100644 --- a/test/extensions/filters/common/ratelimit/ratelimit_impl_test.cc +++ b/test/extensions/filters/common/ratelimit/ratelimit_impl_test.cc @@ -36,7 +36,7 @@ namespace { class MockRequestCallbacks : public RequestCallbacks { public: - void complete(LimitStatus status, Http::HeaderMapPtr&& headers) { + void complete(LimitStatus status, Http::HeaderMapPtr&& headers) override { complete_(status, headers.get()); } diff --git a/test/extensions/filters/http/common/aws/credentials_provider_impl_test.cc b/test/extensions/filters/http/common/aws/credentials_provider_impl_test.cc index d4c22e6215af..b72ea27af87f 100644 --- a/test/extensions/filters/http/common/aws/credentials_provider_impl_test.cc +++ b/test/extensions/filters/http/common/aws/credentials_provider_impl_test.cc @@ -20,7 +20,7 @@ namespace Aws { class EvironmentCredentialsProviderTest : public testing::Test { public: - ~EvironmentCredentialsProviderTest() { + ~EvironmentCredentialsProviderTest() override { TestEnvironment::unsetEnvVar("AWS_ACCESS_KEY_ID"); TestEnvironment::unsetEnvVar("AWS_SECRET_ACCESS_KEY"); TestEnvironment::unsetEnvVar("AWS_SESSION_TOKEN"); @@ -330,7 +330,7 @@ class DefaultCredentialsProviderChainTest : public testing::Test { EXPECT_CALL(factories_, createEnvironmentCredentialsProvider()); } - ~DefaultCredentialsProviderChainTest() { + ~DefaultCredentialsProviderChainTest() override { TestEnvironment::unsetEnvVar("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"); TestEnvironment::unsetEnvVar("AWS_CONTAINER_CREDENTIALS_FULL_URI"); TestEnvironment::unsetEnvVar("AWS_CONTAINER_AUTHORIZATION_TOKEN"); @@ -349,9 +349,9 @@ class DefaultCredentialsProviderChainTest : public testing::Test { Api::Api&, const MetadataCredentialsProviderBase::MetadataFetcher& fetcher)); - virtual CredentialsProviderSharedPtr createTaskRoleCredentialsProvider( + CredentialsProviderSharedPtr createTaskRoleCredentialsProvider( Api::Api& api, const MetadataCredentialsProviderBase::MetadataFetcher& metadata_fetcher, - const std::string& credential_uri, const std::string& authorization_token) const { + const std::string& credential_uri, const std::string& authorization_token) const override { return createTaskRoleCredentialsProviderMock(api, metadata_fetcher, credential_uri, authorization_token); } diff --git a/test/extensions/filters/http/common/aws/mocks.cc b/test/extensions/filters/http/common/aws/mocks.cc index ee5048203bb1..3e68170b4b6e 100644 --- a/test/extensions/filters/http/common/aws/mocks.cc +++ b/test/extensions/filters/http/common/aws/mocks.cc @@ -6,13 +6,13 @@ namespace HttpFilters { namespace Common { namespace Aws { -MockCredentialsProvider::MockCredentialsProvider() {} +MockCredentialsProvider::MockCredentialsProvider() = default; -MockCredentialsProvider::~MockCredentialsProvider() {} +MockCredentialsProvider::~MockCredentialsProvider() = default; -MockSigner::MockSigner() {} +MockSigner::MockSigner() = default; -MockSigner::~MockSigner() {} +MockSigner::~MockSigner() = default; } // namespace Aws } // namespace Common diff --git a/test/extensions/filters/http/common/aws/mocks.h b/test/extensions/filters/http/common/aws/mocks.h index a19f906f238b..df97224efb5e 100644 --- a/test/extensions/filters/http/common/aws/mocks.h +++ b/test/extensions/filters/http/common/aws/mocks.h @@ -14,7 +14,7 @@ namespace Aws { class MockCredentialsProvider : public CredentialsProvider { public: MockCredentialsProvider(); - ~MockCredentialsProvider(); + ~MockCredentialsProvider() override; MOCK_METHOD0(getCredentials, Credentials()); }; @@ -22,14 +22,14 @@ class MockCredentialsProvider : public CredentialsProvider { class MockSigner : public Signer { public: MockSigner(); - ~MockSigner(); + ~MockSigner() override; MOCK_METHOD2(sign, void(Http::Message&, bool)); }; class MockMetadataFetcher { public: - virtual ~MockMetadataFetcher(){}; + virtual ~MockMetadataFetcher() = default; MOCK_CONST_METHOD3(fetch, absl::optional(const std::string&, const std::string&, const absl::optional&)); diff --git a/test/extensions/filters/http/common/aws/region_provider_impl_test.cc b/test/extensions/filters/http/common/aws/region_provider_impl_test.cc index 42ce4d907bef..7cb14439a521 100644 --- a/test/extensions/filters/http/common/aws/region_provider_impl_test.cc +++ b/test/extensions/filters/http/common/aws/region_provider_impl_test.cc @@ -12,7 +12,7 @@ namespace Aws { class EnvironmentRegionProviderTest : public testing::Test { public: - virtual ~EnvironmentRegionProviderTest() { TestEnvironment::unsetEnvVar("AWS_REGION"); } + ~EnvironmentRegionProviderTest() override { TestEnvironment::unsetEnvVar("AWS_REGION"); } EnvironmentRegionProvider provider_; }; diff --git a/test/extensions/filters/http/common/mock.h b/test/extensions/filters/http/common/mock.h index 2e16a0c2774f..a60fc266aa06 100644 --- a/test/extensions/filters/http/common/mock.h +++ b/test/extensions/filters/http/common/mock.h @@ -46,7 +46,7 @@ class MockJwksReceiver : public JwksFetcher::JwksReceiver { * Expectations and assertions should be made on onJwksSuccessImpl in place * of onJwksSuccess. */ - void onJwksSuccess(google::jwt_verify::JwksPtr&& jwks) { + void onJwksSuccess(google::jwt_verify::JwksPtr&& jwks) override { ASSERT(jwks); onJwksSuccessImpl(*jwks.get()); } diff --git a/test/extensions/filters/http/dynamic_forward_proxy/proxy_filter_integration_test.cc b/test/extensions/filters/http/dynamic_forward_proxy/proxy_filter_integration_test.cc index ddef72bc47fa..076fca7e3511 100644 --- a/test/extensions/filters/http/dynamic_forward_proxy/proxy_filter_integration_test.cc +++ b/test/extensions/filters/http/dynamic_forward_proxy/proxy_filter_integration_test.cc @@ -209,6 +209,31 @@ TEST_P(ProxyFilterIntegrationTest, UpstreamTls) { checkSimpleRequestSuccess(0, 0, response.get()); } +TEST_P(ProxyFilterIntegrationTest, UpstreamTlsWithIpHost) { + upstream_tls_ = true; + setup(); + codec_client_ = makeHttpConnection(lookupPort("http")); + const Http::TestHeaderMapImpl request_headers{ + {":method", "POST"}, + {":path", "/test/long/url"}, + {":scheme", "http"}, + {":authority", fmt::format("{}:{}", Network::Test::getLoopbackAddressUrlString(GetParam()), + fake_upstreams_[0]->localAddress()->ip()->port())}}; + + auto response = codec_client_->makeHeaderOnlyRequest(request_headers); + waitForNextUpstreamRequest(); + + // No SNI for IP hosts. + const Extensions::TransportSockets::Tls::SslSocket* ssl_socket = + dynamic_cast( + fake_upstream_connection_->connection().ssl()); + EXPECT_STREQ(nullptr, SSL_get_servername(ssl_socket->rawSslForTest(), TLSEXT_NAMETYPE_host_name)); + + upstream_request_->encodeHeaders(default_response_headers_, true); + response->waitForEndStream(); + checkSimpleRequestSuccess(0, 0, response.get()); +} + // Verify that auto-SAN verification fails with an incorrect certificate. TEST_P(ProxyFilterIntegrationTest, UpstreamTlsInvalidSAN) { upstream_tls_ = true; diff --git a/test/extensions/filters/http/dynamic_forward_proxy/proxy_filter_test.cc b/test/extensions/filters/http/dynamic_forward_proxy/proxy_filter_test.cc index 4718dee34720..b741cbc592f3 100644 --- a/test/extensions/filters/http/dynamic_forward_proxy/proxy_filter_test.cc +++ b/test/extensions/filters/http/dynamic_forward_proxy/proxy_filter_test.cc @@ -40,7 +40,7 @@ class ProxyFilterTest : public testing::Test, cm_.thread_local_cluster_.cluster_.info_->resetResourceManager(0, 1, 0, 0, 0); } - ~ProxyFilterTest() { + ~ProxyFilterTest() override { EXPECT_TRUE( cm_.thread_local_cluster_.cluster_.info_->resource_manager_->pendingRequests().canCreate()); } diff --git a/test/extensions/filters/http/dynamo/BUILD b/test/extensions/filters/http/dynamo/BUILD index 01797af74456..9d87a0531b40 100644 --- a/test/extensions/filters/http/dynamo/BUILD +++ b/test/extensions/filters/http/dynamo/BUILD @@ -40,12 +40,12 @@ envoy_extension_cc_test( ) envoy_extension_cc_test( - name = "dynamo_utility_test", - srcs = ["dynamo_utility_test.cc"], + name = "dynamo_stats_test", + srcs = ["dynamo_stats_test.cc"], extension_name = "envoy.filters.http.dynamo", deps = [ "//source/common/stats:stats_lib", - "//source/extensions/filters/http/dynamo:dynamo_utility_lib", + "//source/extensions/filters/http/dynamo:dynamo_stats_lib", "//test/mocks/stats:stats_mocks", ], ) diff --git a/test/extensions/filters/http/dynamo/dynamo_filter_test.cc b/test/extensions/filters/http/dynamo/dynamo_filter_test.cc index f7021a9b05e9..eb93be0c670c 100644 --- a/test/extensions/filters/http/dynamo/dynamo_filter_test.cc +++ b/test/extensions/filters/http/dynamo/dynamo_filter_test.cc @@ -34,19 +34,20 @@ class DynamoFilterTest : public testing::Test { .WillByDefault(Return(enabled)); EXPECT_CALL(loader_.snapshot_, featureEnabled("dynamodb.filter_enabled", 100)); - filter_ = std::make_unique(loader_, stat_prefix_, stats_, + auto stats = std::make_shared(stats_, "prefix."); + filter_ = std::make_unique(loader_, stats, decoder_callbacks_.dispatcher().timeSource()); filter_->setDecoderFilterCallbacks(decoder_callbacks_); filter_->setEncoderFilterCallbacks(encoder_callbacks_); } - ~DynamoFilterTest() { filter_->onDestroy(); } + ~DynamoFilterTest() override { filter_->onDestroy(); } + NiceMock stats_; std::unique_ptr filter_; NiceMock loader_; std::string stat_prefix_{"prefix."}; - NiceMock stats_; NiceMock decoder_callbacks_; NiceMock encoder_callbacks_; }; diff --git a/test/extensions/filters/http/dynamo/dynamo_utility_test.cc b/test/extensions/filters/http/dynamo/dynamo_stats_test.cc similarity index 63% rename from test/extensions/filters/http/dynamo/dynamo_utility_test.cc rename to test/extensions/filters/http/dynamo/dynamo_stats_test.cc index b00fd773e036..0458c5dc3879 100644 --- a/test/extensions/filters/http/dynamo/dynamo_utility_test.cc +++ b/test/extensions/filters/http/dynamo/dynamo_stats_test.cc @@ -1,6 +1,6 @@ #include -#include "extensions/filters/http/dynamo/dynamo_utility.h" +#include "extensions/filters/http/dynamo/dynamo_stats.h" #include "test/mocks/stats/mocks.h" @@ -17,40 +17,49 @@ namespace HttpFilters { namespace Dynamo { namespace { -TEST(DynamoUtility, PartitionIdStatString) { +TEST(DynamoStats, PartitionIdStatString) { + Stats::IsolatedStoreImpl store; + auto build_partition_string = + [&store](const std::string& stat_prefix, const std::string& table_name, + const std::string& operation, const std::string& partition_id) -> std::string { + DynamoStats stats(store, stat_prefix); + Stats::Counter& counter = stats.buildPartitionStatCounter(table_name, operation, partition_id); + return counter.name(); + }; + { - std::string stat_prefix = "stat.prefix."; + std::string stats_prefix = "prefix."; std::string table_name = "locations"; std::string operation = "GetItem"; std::string partition_id = "6235c781-1d0d-47a3-a4ea-eec04c5883ca"; std::string partition_stat_string = - Utility::buildPartitionStatString(stat_prefix, table_name, operation, partition_id); + build_partition_string(stats_prefix, table_name, operation, partition_id); std::string expected_stat_string = - "stat.prefix.table.locations.capacity.GetItem.__partition_id=c5883ca"; + "prefix.dynamodb.table.locations.capacity.GetItem.__partition_id=c5883ca"; EXPECT_EQ(expected_stat_string, partition_stat_string); } { - std::string stat_prefix = "http.egress_dynamodb_iad.dynamodb."; + std::string stats_prefix = "http.egress_dynamodb_iad."; std::string table_name = "locations-sandbox-partition-test-iad-mytest-really-long-name"; std::string operation = "GetItem"; std::string partition_id = "6235c781-1d0d-47a3-a4ea-eec04c5883ca"; std::string partition_stat_string = - Utility::buildPartitionStatString(stat_prefix, table_name, operation, partition_id); + build_partition_string(stats_prefix, table_name, operation, partition_id); std::string expected_stat_string = "http.egress_dynamodb_iad.dynamodb.table.locations-sandbox-partition-test-iad-mytest-" "really-long-name.capacity.GetItem.__partition_id=c5883ca"; EXPECT_EQ(expected_stat_string, partition_stat_string); } { - std::string stat_prefix = "http.egress_dynamodb_iad.dynamodb."; + std::string stats_prefix = "http.egress_dynamodb_iad."; std::string table_name = "locations-sandbox-partition-test-iad-mytest-rea"; std::string operation = "GetItem"; std::string partition_id = "6235c781-1d0d-47a3-a4ea-eec04c5883ca"; std::string partition_stat_string = - Utility::buildPartitionStatString(stat_prefix, table_name, operation, partition_id); + build_partition_string(stats_prefix, table_name, operation, partition_id); std::string expected_stat_string = "http.egress_dynamodb_iad.dynamodb.table.locations-sandbox-" "partition-test-iad-mytest-rea.capacity.GetItem.__partition_" "id=c5883ca"; diff --git a/test/extensions/filters/http/fault/fault_filter_test.cc b/test/extensions/filters/http/fault/fault_filter_test.cc index f6181e467675..e6cbf4ace6b9 100644 --- a/test/extensions/filters/http/fault/fault_filter_test.cc +++ b/test/extensions/filters/http/fault/fault_filter_test.cc @@ -1113,6 +1113,42 @@ TEST_F(FaultFilterRateLimitTest, ResponseRateLimitEnabled) { EXPECT_EQ(0UL, config_->stats().active_faults_.value()); } +class FaultFilterSettingsTest : public FaultFilterTest {}; + +TEST_F(FaultFilterSettingsTest, CheckDefaultRuntimeKeys) { + envoy::config::filter::http::fault::v2::HTTPFault fault; + + Fault::FaultSettings settings(fault); + + EXPECT_EQ("fault.http.delay.fixed_delay_percent", settings.delayPercentRuntime()); + EXPECT_EQ("fault.http.abort.abort_percent", settings.abortPercentRuntime()); + EXPECT_EQ("fault.http.delay.fixed_duration_ms", settings.delayDurationRuntime()); + EXPECT_EQ("fault.http.abort.http_status", settings.abortHttpStatusRuntime()); + EXPECT_EQ("fault.http.max_active_faults", settings.maxActiveFaultsRuntime()); + EXPECT_EQ("fault.http.rate_limit.response_percent", settings.responseRateLimitPercentRuntime()); +} + +TEST_F(FaultFilterSettingsTest, CheckOverrideRuntimeKeys) { + envoy::config::filter::http::fault::v2::HTTPFault fault; + fault.set_abort_percent_runtime(std::string("fault.abort_percent_runtime")); + fault.set_delay_percent_runtime(std::string("fault.delay_percent_runtime")); + fault.set_abort_http_status_runtime(std::string("fault.abort_http_status_runtime")); + fault.set_delay_duration_runtime(std::string("fault.delay_duration_runtime")); + fault.set_max_active_faults_runtime(std::string("fault.max_active_faults_runtime")); + fault.set_response_rate_limit_percent_runtime( + std::string("fault.response_rate_limit_percent_runtime")); + + Fault::FaultSettings settings(fault); + + EXPECT_EQ("fault.delay_percent_runtime", settings.delayPercentRuntime()); + EXPECT_EQ("fault.abort_percent_runtime", settings.abortPercentRuntime()); + EXPECT_EQ("fault.delay_duration_runtime", settings.delayDurationRuntime()); + EXPECT_EQ("fault.abort_http_status_runtime", settings.abortHttpStatusRuntime()); + EXPECT_EQ("fault.max_active_faults_runtime", settings.maxActiveFaultsRuntime()); + EXPECT_EQ("fault.response_rate_limit_percent_runtime", + settings.responseRateLimitPercentRuntime()); +} + } // namespace } // namespace Fault } // namespace HttpFilters diff --git a/test/extensions/filters/http/grpc_json_transcoder/grpc_json_transcoder_integration_test.cc b/test/extensions/filters/http/grpc_json_transcoder/grpc_json_transcoder_integration_test.cc index d4672646d22f..89459dd4f341 100644 --- a/test/extensions/filters/http/grpc_json_transcoder/grpc_json_transcoder_integration_test.cc +++ b/test/extensions/filters/http/grpc_json_transcoder/grpc_json_transcoder_integration_test.cc @@ -41,7 +41,6 @@ class GrpcJsonTranscoderIntegrationTest )EOF"; config_helper_.addFilter( fmt::format(filter, TestEnvironment::runfilesPath("/test/proto/bookstore.descriptor"))); - HttpIntegrationTest::initialize(); } /** @@ -161,6 +160,7 @@ INSTANTIATE_TEST_SUITE_P(IpVersions, GrpcJsonTranscoderIntegrationTest, TestUtility::ipTestParamsToString); TEST_P(GrpcJsonTranscoderIntegrationTest, UnaryPost) { + HttpIntegrationTest::initialize(); testTranscoding( Http::TestHeaderMapImpl{{":method", "POST"}, {":path", "/shelf"}, @@ -176,6 +176,7 @@ TEST_P(GrpcJsonTranscoderIntegrationTest, UnaryPost) { } TEST_P(GrpcJsonTranscoderIntegrationTest, UnaryGet) { + HttpIntegrationTest::initialize(); testTranscoding( Http::TestHeaderMapImpl{{":method", "GET"}, {":path", "/shelves"}, {":authority", "host"}}, "", {""}, {R"(shelves { id: 20 theme: "Children" } @@ -189,6 +190,7 @@ TEST_P(GrpcJsonTranscoderIntegrationTest, UnaryGet) { } TEST_P(GrpcJsonTranscoderIntegrationTest, UnaryGetHttpBody) { + HttpIntegrationTest::initialize(); testTranscoding( Http::TestHeaderMapImpl{{":method", "GET"}, {":path", "/index"}, {":authority", "host"}}, "", {""}, {R"(content_type: "text/html" data: "

Hello!

" )"}, Status(), @@ -200,6 +202,7 @@ TEST_P(GrpcJsonTranscoderIntegrationTest, UnaryGetHttpBody) { } TEST_P(GrpcJsonTranscoderIntegrationTest, UnaryGetError) { + HttpIntegrationTest::initialize(); testTranscoding( Http::TestHeaderMapImpl{ {":method", "GET"}, {":path", "/shelves/100?"}, {":authority", "host"}}, @@ -209,7 +212,30 @@ TEST_P(GrpcJsonTranscoderIntegrationTest, UnaryGetError) { ""); } +TEST_P(GrpcJsonTranscoderIntegrationTest, UnaryGetError1) { + const std::string filter = + R"EOF( + name: envoy.grpc_json_transcoder + config: + proto_descriptor : "{}" + services : "bookstore.Bookstore" + ignore_unknown_query_parameters : true + )EOF"; + config_helper_.addFilter( + fmt::format(filter, TestEnvironment::runfilesPath("/test/proto/bookstore.descriptor"))); + HttpIntegrationTest::initialize(); + testTranscoding( + Http::TestHeaderMapImpl{{":method", "GET"}, + {":path", "/shelves/100?unknown=1&shelf=9999"}, + {":authority", "host"}}, + "", {"shelf: 9999"}, {}, Status(Code::NOT_FOUND, "Shelf 9999 Not Found"), + Http::TestHeaderMapImpl{ + {":status", "404"}, {"grpc-status", "5"}, {"grpc-message", "Shelf 9999 Not Found"}}, + ""); +} + TEST_P(GrpcJsonTranscoderIntegrationTest, UnaryDelete) { + HttpIntegrationTest::initialize(); testTranscoding( Http::TestHeaderMapImpl{ {":method", "DELETE"}, {":path", "/shelves/456/books/123"}, {":authority", "host"}}, @@ -222,6 +248,7 @@ TEST_P(GrpcJsonTranscoderIntegrationTest, UnaryDelete) { } TEST_P(GrpcJsonTranscoderIntegrationTest, UnaryPatch) { + HttpIntegrationTest::initialize(); testTranscoding( Http::TestHeaderMapImpl{ {":method", "PATCH"}, {":path", "/shelves/456/books/123"}, {":authority", "host"}}, @@ -236,6 +263,7 @@ TEST_P(GrpcJsonTranscoderIntegrationTest, UnaryPatch) { } TEST_P(GrpcJsonTranscoderIntegrationTest, UnaryCustom) { + HttpIntegrationTest::initialize(); testTranscoding( Http::TestHeaderMapImpl{ {":method", "OPTIONS"}, {":path", "/shelves/456"}, {":authority", "host"}}, @@ -248,6 +276,7 @@ TEST_P(GrpcJsonTranscoderIntegrationTest, UnaryCustom) { } TEST_P(GrpcJsonTranscoderIntegrationTest, BindingAndBody) { + HttpIntegrationTest::initialize(); testTranscoding( Http::TestHeaderMapImpl{ {":method", "PUT"}, {":path", "/shelves/1/books"}, {":authority", "host"}}, @@ -259,6 +288,7 @@ TEST_P(GrpcJsonTranscoderIntegrationTest, BindingAndBody) { } TEST_P(GrpcJsonTranscoderIntegrationTest, ServerStreamingGet) { + HttpIntegrationTest::initialize(); testTranscoding( Http::TestHeaderMapImpl{ {":method", "GET"}, {":path", "/shelves/1/books"}, {":authority", "host"}}, @@ -271,6 +301,7 @@ TEST_P(GrpcJsonTranscoderIntegrationTest, ServerStreamingGet) { } TEST_P(GrpcJsonTranscoderIntegrationTest, StreamingPost) { + HttpIntegrationTest::initialize(); testTranscoding( Http::TestHeaderMapImpl{ {":method", "POST"}, {":path", "/bulk/shelves"}, {":authority", "host"}}, @@ -300,6 +331,7 @@ TEST_P(GrpcJsonTranscoderIntegrationTest, StreamingPost) { } TEST_P(GrpcJsonTranscoderIntegrationTest, InvalidJson) { + HttpIntegrationTest::initialize(); // Usually the response would be // "Unexpected token.\n" // "INVALID_JSON\n" diff --git a/test/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter_test.cc b/test/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter_test.cc index 437bc9d373b4..673a13e0a80c 100644 --- a/test/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter_test.cc +++ b/test/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter_test.cc @@ -249,6 +249,24 @@ TEST_F(GrpcJsonTranscoderConfigTest, InvalidQueryParameter) { EXPECT_FALSE(transcoder); } +TEST_F(GrpcJsonTranscoderConfigTest, UnknownQueryParameterIsIgnored) { + auto proto_config = getProtoConfig( + TestEnvironment::runfilesPath("test/proto/bookstore.descriptor"), "bookstore.Bookstore"); + proto_config.set_ignore_unknown_query_parameters(true); + JsonTranscoderConfig config(proto_config, *api_); + + Http::TestHeaderMapImpl headers{{":method", "GET"}, {":path", "/shelves?foo=bar"}}; + + TranscoderInputStreamImpl request_in, response_in; + std::unique_ptr transcoder; + const MethodDescriptor* method_descriptor; + auto status = + config.createTranscoder(headers, request_in, response_in, transcoder, method_descriptor); + + EXPECT_TRUE(status.ok()); + EXPECT_TRUE(transcoder); +} + TEST_F(GrpcJsonTranscoderConfigTest, IgnoredQueryParameter) { std::vector ignored_query_parameters = {"key"}; JsonTranscoderConfig config( @@ -740,7 +758,7 @@ class GrpcJsonTranscoderFilterPrintTest filter_->setEncoderFilterCallbacks(encoder_callbacks_); } - ~GrpcJsonTranscoderFilterPrintTest() { + ~GrpcJsonTranscoderFilterPrintTest() override { delete filter_; delete config_; } diff --git a/test/extensions/filters/http/ip_tagging/ip_tagging_filter_test.cc b/test/extensions/filters/http/ip_tagging/ip_tagging_filter_test.cc index 5dfaeaa7cd1b..50679f090c42 100644 --- a/test/extensions/filters/http/ip_tagging/ip_tagging_filter_test.cc +++ b/test/extensions/filters/http/ip_tagging/ip_tagging_filter_test.cc @@ -50,7 +50,7 @@ request_type: internal filter_->setDecoderFilterCallbacks(filter_callbacks_); } - ~IpTaggingFilterTest() { filter_->onDestroy(); } + ~IpTaggingFilterTest() override { filter_->onDestroy(); } IpTaggingFilterConfigSharedPtr config_; std::unique_ptr filter_; diff --git a/test/extensions/filters/http/jwt_authn/filter_integration_test.cc b/test/extensions/filters/http/jwt_authn/filter_integration_test.cc index f65637c7fcfb..7f064293f3e2 100644 --- a/test/extensions/filters/http/jwt_authn/filter_integration_test.cc +++ b/test/extensions/filters/http/jwt_authn/filter_integration_test.cc @@ -47,7 +47,8 @@ class HeaderToFilterStateFilterConfig : public Common::EmptyHttpFilterConfig { HeaderToFilterStateFilterConfig() : Common::EmptyHttpFilterConfig(HeaderToFilterStateFilterName) {} - Http::FilterFactoryCb createFilter(const std::string&, Server::Configuration::FactoryContext&) { + Http::FilterFactoryCb createFilter(const std::string&, + Server::Configuration::FactoryContext&) override { return [](Http::FilterChainFactoryCallbacks& callbacks) -> void { callbacks.addStreamDecoderFilter( std::make_shared("jwt_selector", "jwt_selector")); diff --git a/test/extensions/filters/http/jwt_authn/filter_test.cc b/test/extensions/filters/http/jwt_authn/filter_test.cc index 3a65d74c3bcc..f0ed58f82de9 100644 --- a/test/extensions/filters/http/jwt_authn/filter_test.cc +++ b/test/extensions/filters/http/jwt_authn/filter_test.cc @@ -104,11 +104,13 @@ TEST_F(FilterTest, TestSetPayloadCall) { EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(headers)); } -// This test verifies Verifier::Callback is called inline with a failure status. +// This test verifies Verifier::Callback is called inline with a failure(401 Unauthorized) status. // All functions should return Continue except decodeHeaders(), it returns StopIteration. -TEST_F(FilterTest, InlineFailure) { +TEST_F(FilterTest, InlineUnauthorizedFailure) { setupMockConfig(); // A failed authentication completed inline: callback is called inside verify(). + + EXPECT_CALL(filter_callbacks_, sendLocalReply(Http::Code::Unauthorized, _, _, _, _)); EXPECT_CALL(*mock_verifier_, verify(_)).WillOnce(Invoke([](ContextSharedPtr context) { context->callback()->onComplete(Status::JwtBadFormat); })); @@ -123,6 +125,27 @@ TEST_F(FilterTest, InlineFailure) { EXPECT_EQ("jwt_authn_access_denied", filter_callbacks_.details_); } +// This test verifies Verifier::Callback is called inline with a failure(403 Forbidden) status. +// All functions should return Continue except decodeHeaders(), it returns StopIteration. +TEST_F(FilterTest, InlineForbiddenFailure) { + setupMockConfig(); + // A failed authentication completed inline: callback is called inside verify(). + + EXPECT_CALL(filter_callbacks_, sendLocalReply(Http::Code::Forbidden, _, _, _, _)); + EXPECT_CALL(*mock_verifier_, verify(_)).WillOnce(Invoke([](ContextSharedPtr context) { + context->callback()->onComplete(Status::JwtAudienceNotAllowed); + })); + + auto headers = Http::TestHeaderMapImpl{}; + EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders(headers, false)); + EXPECT_EQ(1U, mock_config_->stats().denied_.value()); + + Buffer::OwnedImpl data(""); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, false)); + EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(headers)); + EXPECT_EQ("jwt_authn_access_denied", filter_callbacks_.details_); +} + // This test verifies Verifier::Callback is called with OK status after verify(). TEST_F(FilterTest, OutBoundOK) { setupMockConfig(); @@ -140,7 +163,6 @@ TEST_F(FilterTest, OutBoundOK) { EXPECT_EQ(Http::FilterTrailersStatus::StopIteration, filter_->decodeTrailers(headers)); // Callback is called now with OK status. - auto context = Verifier::createContext(headers, &verifier_callback_); m_cb->onComplete(Status::Ok); EXPECT_EQ(1U, mock_config_->stats().allowed_.value()); @@ -148,8 +170,9 @@ TEST_F(FilterTest, OutBoundOK) { EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(headers)); } -// This test verifies Verifier::Callback is called with a failure after verify(). -TEST_F(FilterTest, OutBoundFailure) { +// This test verifies Verifier::Callback is called with a failure(401 Unauthorized) after verify() +// returns any NonOK status except JwtAudienceNotAllowed. +TEST_F(FilterTest, OutBoundUnauthorizedFailure) { setupMockConfig(); Verifier::Callbacks* m_cb; // callback is saved, not called right @@ -164,8 +187,8 @@ TEST_F(FilterTest, OutBoundFailure) { EXPECT_EQ(Http::FilterDataStatus::StopIterationAndWatermark, filter_->decodeData(data, false)); EXPECT_EQ(Http::FilterTrailersStatus::StopIteration, filter_->decodeTrailers(headers)); - auto context = Verifier::createContext(headers, &verifier_callback_); // Callback is called now with a failure status. + EXPECT_CALL(filter_callbacks_, sendLocalReply(Http::Code::Unauthorized, _, _, _, _)); m_cb->onComplete(Status::JwtBadFormat); EXPECT_EQ(1U, mock_config_->stats().denied_.value()); @@ -176,6 +199,35 @@ TEST_F(FilterTest, OutBoundFailure) { m_cb->onComplete(Status::JwtBadFormat); } +// This test verifies Verifier::Callback is called with a failure(403 Forbidden) after verify() +// returns JwtAudienceNotAllowed. +TEST_F(FilterTest, OutBoundForbiddenFailure) { + setupMockConfig(); + Verifier::Callbacks* m_cb; + // callback is saved, not called right + EXPECT_CALL(*mock_verifier_, verify(_)).WillOnce(Invoke([&m_cb](ContextSharedPtr context) { + m_cb = context->callback(); + })); + + auto headers = Http::TestHeaderMapImpl{}; + EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders(headers, false)); + + Buffer::OwnedImpl data(""); + EXPECT_EQ(Http::FilterDataStatus::StopIterationAndWatermark, filter_->decodeData(data, false)); + EXPECT_EQ(Http::FilterTrailersStatus::StopIteration, filter_->decodeTrailers(headers)); + + // Callback is called now with a failure status. + EXPECT_CALL(filter_callbacks_, sendLocalReply(Http::Code::Forbidden, _, _, _, _)); + m_cb->onComplete(Status::JwtAudienceNotAllowed); + + EXPECT_EQ(1U, mock_config_->stats().denied_.value()); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, false)); + EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(headers)); + + // Should be OK to call the onComplete() again. + m_cb->onComplete(Status::JwtAudienceNotAllowed); +} + // Test verifies that if no route matched requirement, then request is allowed. TEST_F(FilterTest, TestNoRouteMatched) { EXPECT_CALL(*mock_config_.get(), findVerifier(_, _)).WillOnce(Return(nullptr)); diff --git a/test/extensions/filters/http/jwt_authn/mock.h b/test/extensions/filters/http/jwt_authn/mock.h index a97342ae11b4..025351a35dc0 100644 --- a/test/extensions/filters/http/jwt_authn/mock.h +++ b/test/extensions/filters/http/jwt_authn/mock.h @@ -28,7 +28,7 @@ class MockAuthenticator : public Authenticator { SetPayloadCallback set_payload_cb, AuthenticatorCallback callback)); void verify(Http::HeaderMap& headers, std::vector&& tokens, - SetPayloadCallback set_payload_cb, AuthenticatorCallback callback) { + SetPayloadCallback set_payload_cb, AuthenticatorCallback callback) override { doVerify(headers, &tokens, std::move(set_payload_cb), std::move(callback)); } diff --git a/test/extensions/filters/http/lua/lua_filter_test.cc b/test/extensions/filters/http/lua/lua_filter_test.cc index d9be20d3f301..2d444fc6f61a 100644 --- a/test/extensions/filters/http/lua/lua_filter_test.cc +++ b/test/extensions/filters/http/lua/lua_filter_test.cc @@ -66,7 +66,7 @@ class LuaHttpFilterTest : public testing::Test { EXPECT_CALL(encoder_callbacks_, encodingBuffer()).Times(AtLeast(0)); } - ~LuaHttpFilterTest() { filter_->onDestroy(); } + ~LuaHttpFilterTest() override { filter_->onDestroy(); } void setup(const std::string& lua_code) { config_.reset(new FilterConfig(lua_code, tls_, cluster_manager_)); diff --git a/test/extensions/filters/http/lua/lua_integration_test.cc b/test/extensions/filters/http/lua/lua_integration_test.cc index 4149d4333852..db599dee1302 100644 --- a/test/extensions/filters/http/lua/lua_integration_test.cc +++ b/test/extensions/filters/http/lua/lua_integration_test.cc @@ -445,7 +445,7 @@ name: envoy.lua request_handle:headers():add("signature_verification", "rejected") end - request_handle:releasePublicKey(pubkey) + request_handle:headers():add("verification", "done") end )EOF"; @@ -473,6 +473,11 @@ name: envoy.lua ->value() .getStringView()); + EXPECT_EQ("done", upstream_request_->headers() + .get(Http::LowerCaseString("verification")) + ->value() + .getStringView()); + upstream_request_->encodeHeaders(default_response_headers_, true); response->waitForEndStream(); diff --git a/test/extensions/filters/http/ratelimit/ratelimit_test.cc b/test/extensions/filters/http/ratelimit/ratelimit_test.cc index c956709a2a54..4e030d64b8e7 100644 --- a/test/extensions/filters/http/ratelimit/ratelimit_test.cc +++ b/test/extensions/filters/http/ratelimit/ratelimit_test.cc @@ -76,9 +76,7 @@ class HttpRateLimitFilterTest : public testing::Test { domain: foo )EOF"; - FilterConfigSharedPtr config_; Filters::Common::RateLimit::MockClient* client_; - std::unique_ptr filter_; NiceMock filter_callbacks_; Filters::Common::RateLimit::RequestCallbacks* request_callbacks_{}; Http::TestHeaderMapImpl request_headers_; @@ -86,6 +84,8 @@ class HttpRateLimitFilterTest : public testing::Test { Buffer::OwnedImpl data_; Buffer::OwnedImpl response_data_; NiceMock stats_store_; + FilterConfigSharedPtr config_; + std::unique_ptr filter_; NiceMock runtime_; NiceMock route_rate_limit_; NiceMock vh_rate_limit_; diff --git a/test/extensions/filters/http/rbac/rbac_filter_test.cc b/test/extensions/filters/http/rbac/rbac_filter_test.cc index 62967602dfc6..ecc0b1dcafac 100644 --- a/test/extensions/filters/http/rbac/rbac_filter_test.cc +++ b/test/extensions/filters/http/rbac/rbac_filter_test.cc @@ -47,7 +47,7 @@ class RoleBasedAccessControlFilterTest : public testing::Test { RoleBasedAccessControlFilterTest() : config_(setupConfig()), filter_(config_) {} - void SetUp() { + void SetUp() override { EXPECT_CALL(callbacks_, connection()).WillRepeatedly(Return(&connection_)); EXPECT_CALL(callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_)); filter_.setDecoderFilterCallbacks(callbacks_); diff --git a/test/extensions/filters/listener/http_inspector/BUILD b/test/extensions/filters/listener/http_inspector/BUILD new file mode 100644 index 000000000000..fcce5eea9449 --- /dev/null +++ b/test/extensions/filters/listener/http_inspector/BUILD @@ -0,0 +1,43 @@ +licenses(["notice"]) # Apache 2 + +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_test", + "envoy_package", +) +load( + "//test/extensions:extensions_build_system.bzl", + "envoy_extension_cc_test", +) + +envoy_package() + +envoy_extension_cc_test( + name = "http_inspector_test", + srcs = ["http_inspector_test.cc"], + extension_name = "envoy.filters.listener.http_inspector", + deps = [ + "//source/common/common:hex_lib", + "//source/extensions/filters/listener/http_inspector:http_inspector_lib", + "//test/mocks/api:api_mocks", + "//test/mocks/network:network_mocks", + "//test/mocks/stats:stats_mocks", + "//test/test_common:threadsafe_singleton_injector_lib", + ], +) + +envoy_extension_cc_test( + name = "http_inspector_config_test", + srcs = ["http_inspector_config_test.cc"], + extension_name = "envoy.filters.listener.http_inspector", + deps = [ + "//source/extensions/filters/listener:well_known_names", + "//source/extensions/filters/listener/http_inspector:config", + "//source/extensions/filters/listener/http_inspector:http_inspector_lib", + "//test/mocks/api:api_mocks", + "//test/mocks/network:network_mocks", + "//test/mocks/server:server_mocks", + "//test/mocks/stats:stats_mocks", + "//test/test_common:threadsafe_singleton_injector_lib", + ], +) diff --git a/test/extensions/filters/listener/http_inspector/http_inspector_config_test.cc b/test/extensions/filters/listener/http_inspector/http_inspector_config_test.cc new file mode 100644 index 000000000000..3e8bc84d4b72 --- /dev/null +++ b/test/extensions/filters/listener/http_inspector/http_inspector_config_test.cc @@ -0,0 +1,52 @@ +#include "extensions/filters/listener/http_inspector/http_inspector.h" +#include "extensions/filters/listener/well_known_names.h" + +#include "test/mocks/server/mocks.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using testing::Invoke; + +namespace Envoy { +namespace Extensions { +namespace ListenerFilters { +namespace HttpInspector { +namespace { + +TEST(HttpInspectorConfigFactoryTest, TestCreateFactory) { + Server::Configuration::NamedListenerFilterConfigFactory* factory = + Registry::FactoryRegistry:: + getFactory(ListenerFilters::ListenerFilterNames::get().HttpInspector); + + EXPECT_EQ(factory->name(), ListenerFilters::ListenerFilterNames::get().HttpInspector); + + const std::string yaml = R"EOF( + {} +)EOF"; + + ProtobufTypes::MessagePtr proto_config = factory->createEmptyConfigProto(); + TestUtility::loadFromYaml(yaml, *proto_config); + + Server::Configuration::MockListenerFactoryContext context; + EXPECT_CALL(context, scope()).Times(1); + Network::ListenerFilterFactoryCb cb = + factory->createFilterFactoryFromProto(*proto_config, context); + + Network::MockListenerFilterManager manager; + Network::ListenerFilterPtr added_filter; + EXPECT_CALL(manager, addAcceptFilter_(_)) + .WillOnce(Invoke([&added_filter](Network::ListenerFilterPtr& filter) { + added_filter = std::move(filter); + })); + cb(manager); + + // Make sure we actually create the correct type! + EXPECT_NE(dynamic_cast(added_filter.get()), nullptr); +} + +} // namespace +} // namespace HttpInspector +} // namespace ListenerFilters +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/filters/listener/http_inspector/http_inspector_test.cc b/test/extensions/filters/listener/http_inspector/http_inspector_test.cc new file mode 100644 index 000000000000..afca8e66e9f7 --- /dev/null +++ b/test/extensions/filters/listener/http_inspector/http_inspector_test.cc @@ -0,0 +1,425 @@ +#include "common/common/hex.h" +#include "common/network/io_socket_handle_impl.h" + +#include "extensions/filters/listener/http_inspector/http_inspector.h" + +#include "test/mocks/api/mocks.h" +#include "test/mocks/network/mocks.h" +#include "test/mocks/stats/mocks.h" +#include "test/test_common/threadsafe_singleton_injector.h" + +#include "gtest/gtest.h" + +using testing::_; +using testing::AtLeast; +using testing::Eq; +using testing::InSequence; +using testing::Invoke; +using testing::InvokeWithoutArgs; +using testing::NiceMock; +using testing::Return; +using testing::ReturnNew; +using testing::ReturnRef; +using testing::SaveArg; + +namespace Envoy { +namespace Extensions { +namespace ListenerFilters { +namespace HttpInspector { +namespace { + +class HttpInspectorTest : public testing::Test { +public: + HttpInspectorTest() + : cfg_(std::make_shared(store_)), + io_handle_(std::make_unique(42)) {} + ~HttpInspectorTest() override { io_handle_->close(); } + + void init() { + filter_ = std::make_unique(cfg_); + + EXPECT_CALL(cb_, socket()).WillRepeatedly(ReturnRef(socket_)); + EXPECT_CALL(socket_, detectedTransportProtocol()).WillRepeatedly(Return("raw_buffer")); + EXPECT_CALL(cb_, dispatcher()).WillRepeatedly(ReturnRef(dispatcher_)); + EXPECT_CALL(testing::Const(socket_), ioHandle()).WillRepeatedly(ReturnRef(*io_handle_)); + + EXPECT_CALL(dispatcher_, + createFileEvent_(_, _, Event::FileTriggerType::Edge, Event::FileReadyType::Read)) + .WillOnce( + DoAll(SaveArg<1>(&file_event_callback_), ReturnNew>())); + filter_->onAccept(cb_); + } + + NiceMock os_sys_calls_; + TestThreadsafeSingletonInjector os_calls_{&os_sys_calls_}; + Stats::IsolatedStoreImpl store_; + ConfigSharedPtr cfg_; + std::unique_ptr filter_; + Network::MockListenerFilterCallbacks cb_; + Network::MockConnectionSocket socket_; + NiceMock dispatcher_; + Event::FileReadyCb file_event_callback_; + Network::IoHandlePtr io_handle_; +}; + +TEST_F(HttpInspectorTest, SkipHttpInspectForTLS) { + filter_ = std::make_unique(cfg_); + + EXPECT_CALL(cb_, socket()).WillRepeatedly(ReturnRef(socket_)); + EXPECT_CALL(socket_, detectedTransportProtocol()).WillRepeatedly(Return("TLS")); + EXPECT_EQ(filter_->onAccept(cb_), Network::FilterStatus::Continue); +} + +TEST_F(HttpInspectorTest, InspectHttp10) { + init(); + const absl::string_view header = + "GET /anything HTTP/1.0\r\nhost: google.com\r\nuser-agent: curl/7.64.0\r\naccept: " + "*/*\r\nx-forwarded-proto: http\r\nx-request-id: " + "a52df4a0-ed00-4a19-86a7-80e5049c6c84\r\nx-envoy-expected-rq-timeout-ms: " + "15000\r\ncontent-length: 0\r\n\r\n"; + + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)) + .WillOnce(Invoke([&header](int, void* buffer, size_t length, int) -> Api::SysCallSizeResult { + ASSERT(length >= header.size()); + memcpy(buffer, header.data(), header.size()); + return Api::SysCallSizeResult{ssize_t(header.size()), 0}; + })); + + const std::vector alpn_protos{absl::string_view("http/1.0")}; + + EXPECT_CALL(socket_, setRequestedApplicationProtocols(alpn_protos)); + EXPECT_CALL(cb_, continueFilterChain(true)); + file_event_callback_(Event::FileReadyType::Read); + EXPECT_EQ(1, cfg_->stats().http10_found_.value()); +} + +TEST_F(HttpInspectorTest, InspectHttp11) { + init(); + const absl::string_view header = + "GET /anything HTTP/1.1\r\nhost: google.com\r\nuser-agent: curl/7.64.0\r\naccept: " + "*/*\r\nx-forwarded-proto: http\r\nx-request-id: " + "a52df4a0-ed00-4a19-86a7-80e5049c6c84\r\nx-envoy-expected-rq-timeout-ms: " + "15000\r\ncontent-length: 0\r\n\r\n"; + + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)) + .WillOnce(Invoke([&header](int, void* buffer, size_t length, int) -> Api::SysCallSizeResult { + ASSERT(length >= header.size()); + memcpy(buffer, header.data(), header.size()); + return Api::SysCallSizeResult{ssize_t(header.size()), 0}; + })); + + const std::vector alpn_protos{absl::string_view("http/1.1")}; + + EXPECT_CALL(socket_, setRequestedApplicationProtocols(alpn_protos)); + EXPECT_CALL(cb_, continueFilterChain(true)); + file_event_callback_(Event::FileReadyType::Read); + EXPECT_EQ(1, cfg_->stats().http11_found_.value()); +} + +TEST_F(HttpInspectorTest, InvalidHttpMethod) { + init(); + const absl::string_view header = "BAD /anything HTTP/1.1\r\n"; + + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)) + .WillOnce(Invoke([&header](int, void* buffer, size_t length, int) -> Api::SysCallSizeResult { + ASSERT(length >= header.size()); + memcpy(buffer, header.data(), header.size()); + return Api::SysCallSizeResult{ssize_t(header.size()), 0}; + })); + + EXPECT_CALL(socket_, setRequestedApplicationProtocols(_)).Times(0); + EXPECT_CALL(cb_, continueFilterChain(true)); + file_event_callback_(Event::FileReadyType::Read); + EXPECT_EQ(0, cfg_->stats().http11_found_.value()); +} + +TEST_F(HttpInspectorTest, InvalidHttpRequestLine) { + init(); + const absl::string_view header = "BAD /anything HTTP/1.1"; + + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)) + .WillOnce(Invoke([&header](int, void* buffer, size_t length, int) -> Api::SysCallSizeResult { + ASSERT(length >= header.size()); + memcpy(buffer, header.data(), header.size()); + return Api::SysCallSizeResult{ssize_t(header.size()), 0}; + })); + + EXPECT_CALL(socket_, setRequestedApplicationProtocols(_)).Times(0); + EXPECT_CALL(cb_, continueFilterChain(_)).Times(0); + file_event_callback_(Event::FileReadyType::Read); +} + +TEST_F(HttpInspectorTest, UnsupportedHttpProtocol) { + init(); + const absl::string_view header = "GET /anything HTTP/0.9\r\n"; + + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)) + .WillOnce(Invoke([&header](int, void* buffer, size_t length, int) -> Api::SysCallSizeResult { + ASSERT(length >= header.size()); + memcpy(buffer, header.data(), header.size()); + return Api::SysCallSizeResult{ssize_t(header.size()), 0}; + })); + + EXPECT_CALL(socket_, setRequestedApplicationProtocols(_)).Times(0); + EXPECT_CALL(cb_, continueFilterChain(true)); + file_event_callback_(Event::FileReadyType::Read); + EXPECT_EQ(1, cfg_->stats().http_not_found_.value()); +} + +TEST_F(HttpInspectorTest, InvalidRequestLine) { + init(); + const absl::string_view header = "GET /anything HTTP/1.1 BadRequestLine\r\n"; + + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)) + .WillOnce(Invoke([&header](int, void* buffer, size_t length, int) -> Api::SysCallSizeResult { + ASSERT(length >= header.size()); + memcpy(buffer, header.data(), header.size()); + return Api::SysCallSizeResult{ssize_t(header.size()), 0}; + })); + + EXPECT_CALL(socket_, setRequestedApplicationProtocols(_)).Times(0); + EXPECT_CALL(cb_, continueFilterChain(true)); + file_event_callback_(Event::FileReadyType::Read); + EXPECT_EQ(1, cfg_->stats().http_not_found_.value()); +} + +TEST_F(HttpInspectorTest, InspectHttp2) { + init(); + + const std::string header = + "505249202a20485454502f322e300d0a0d0a534d0d0a0d0a00000c04000000000000041000000000020000000000" + "00040800000000000fff000100007d010500000001418aa0e41d139d09b8f0000f048860757a4ce6aa660582867a" + "8825b650c3abb8d2e053032a2f2a408df2b4a7b3c0ec90b22d5d8749ff839d29af4089f2b585ed6950958d279a18" + "9e03f1ca5582265f59a75b0ac3111959c7e49004908db6e83f4096f2b16aee7f4b17cd65224b22d6765926a4a7b5" + "2b528f840b60003f"; + std::vector data = Hex::decode(header); + + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)) + .WillOnce(Invoke([&data](int, void* buffer, size_t length, int) -> Api::SysCallSizeResult { + ASSERT(length >= data.size()); + memcpy(buffer, data.data(), data.size()); + return Api::SysCallSizeResult{ssize_t(data.size()), 0}; + })); + + const std::vector alpn_protos{absl::string_view("h2")}; + + EXPECT_CALL(socket_, setRequestedApplicationProtocols(alpn_protos)); + EXPECT_CALL(cb_, continueFilterChain(true)); + file_event_callback_(Event::FileReadyType::Read); + EXPECT_EQ(1, cfg_->stats().http2_found_.value()); +} + +TEST_F(HttpInspectorTest, InvalidConnectionPreface) { + init(); + + const std::string header = "505249202a20485454502f322e300d0a"; + const std::vector data = Hex::decode(header); + + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)) + .WillOnce(Invoke([&data](int, void* buffer, size_t length, int) -> Api::SysCallSizeResult { + ASSERT(length >= data.size()); + memcpy(buffer, data.data(), data.size()); + return Api::SysCallSizeResult{ssize_t(data.size()), 0}; + })); + + EXPECT_CALL(socket_, setRequestedApplicationProtocols(_)).Times(0); + EXPECT_CALL(cb_, continueFilterChain(true)).Times(0); + file_event_callback_(Event::FileReadyType::Read); + EXPECT_EQ(0, cfg_->stats().http_not_found_.value()); +} + +TEST_F(HttpInspectorTest, ReadError) { + init(); + + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)).WillOnce(InvokeWithoutArgs([]() { + return Api::SysCallSizeResult{ssize_t(-1), ENOTSUP}; + })); + EXPECT_CALL(cb_, continueFilterChain(true)); + file_event_callback_(Event::FileReadyType::Read); + EXPECT_EQ(1, cfg_->stats().read_error_.value()); +} + +TEST_F(HttpInspectorTest, MultipleReadsHttp2) { + + init(); + const std::vector alpn_protos = {absl::string_view("h2")}; + + const std::string header = + "505249202a20485454502f322e300d0a0d0a534d0d0a0d0a00000c04000000000000041000000000020000000000" + "00040800000000000fff000100007d010500000001418aa0e41d139d09b8f0000f048860757a4ce6aa660582867a" + "8825b650c3abb8d2e053032a2f2a408df2b4a7b3c0ec90b22d5d8749ff839d29af4089f2b585ed6950958d279a18" + "9e03f1ca5582265f59a75b0ac3111959c7e49004908db6e83f4096f2b16aee7f4b17cd65224b22d6765926a4a7b5" + "2b528f840b60003f"; + const std::vector data = Hex::decode(header); + { + InSequence s; + + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)).WillOnce(InvokeWithoutArgs([]() { + return Api::SysCallSizeResult{ssize_t(-1), EAGAIN}; + })); + + for (size_t i = 1; i <= 24; i++) { + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)) + .WillOnce( + Invoke([&data, i](int, void* buffer, size_t length, int) -> Api::SysCallSizeResult { + ASSERT(length >= data.size()); + memcpy(buffer, data.data(), data.size()); + return Api::SysCallSizeResult{ssize_t(i), 0}; + })); + } + } + + bool got_continue = false; + EXPECT_CALL(socket_, setRequestedApplicationProtocols(alpn_protos)); + EXPECT_CALL(cb_, continueFilterChain(true)).WillOnce(InvokeWithoutArgs([&got_continue]() { + got_continue = true; + })); + while (!got_continue) { + file_event_callback_(Event::FileReadyType::Read); + } + EXPECT_EQ(1, cfg_->stats().http2_found_.value()); +} + +TEST_F(HttpInspectorTest, MultipleReadsHttp2BadPreface) { + + init(); + const std::string header = "505249202a20485454502f322e300d0a0d0c"; + const std::vector data = Hex::decode(header); + { + InSequence s; + + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)).WillOnce(InvokeWithoutArgs([]() { + return Api::SysCallSizeResult{ssize_t(-1), EAGAIN}; + })); + + for (size_t i = 1; i <= data.size(); i++) { + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)) + .WillOnce( + Invoke([&data, i](int, void* buffer, size_t length, int) -> Api::SysCallSizeResult { + ASSERT(length >= data.size()); + memcpy(buffer, data.data(), data.size()); + return Api::SysCallSizeResult{ssize_t(i), 0}; + })); + } + } + + bool got_continue = false; + EXPECT_CALL(socket_, setRequestedApplicationProtocols(_)).Times(0); + EXPECT_CALL(cb_, continueFilterChain(true)).WillOnce(InvokeWithoutArgs([&got_continue]() { + got_continue = true; + })); + while (!got_continue) { + file_event_callback_(Event::FileReadyType::Read); + } + EXPECT_EQ(1, cfg_->stats().http_not_found_.value()); +} + +TEST_F(HttpInspectorTest, MultipleReadsHttp1) { + + init(); + + const absl::string_view data = "GET /anything HTTP/1.0\r"; + { + InSequence s; + + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)).WillOnce(InvokeWithoutArgs([]() { + return Api::SysCallSizeResult{ssize_t(-1), EAGAIN}; + })); + + for (size_t i = 1; i <= data.length(); i++) { + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)) + .WillOnce( + Invoke([&data, i](int, void* buffer, size_t length, int) -> Api::SysCallSizeResult { + ASSERT(length >= data.size()); + memcpy(buffer, data.data(), data.size()); + return Api::SysCallSizeResult{ssize_t(i), 0}; + })); + } + } + + bool got_continue = false; + const std::vector alpn_protos = {absl::string_view("http/1.0")}; + EXPECT_CALL(socket_, setRequestedApplicationProtocols(alpn_protos)); + EXPECT_CALL(cb_, continueFilterChain(true)).WillOnce(InvokeWithoutArgs([&got_continue]() { + got_continue = true; + })); + while (!got_continue) { + file_event_callback_(Event::FileReadyType::Read); + } + EXPECT_EQ(1, cfg_->stats().http10_found_.value()); +} + +TEST_F(HttpInspectorTest, MultipleReadsHttp1IncompleteHeader) { + + init(); + + const absl::string_view data = "GE"; + bool end_stream = false; + + { + InSequence s; + + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)).WillOnce(InvokeWithoutArgs([]() { + return Api::SysCallSizeResult{ssize_t(-1), EAGAIN}; + })); + + for (size_t i = 1; i <= data.length(); i++) { + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)) + .WillOnce(Invoke([&data, &end_stream, i](int, void* buffer, size_t length, + int) -> Api::SysCallSizeResult { + ASSERT(length >= data.size()); + memcpy(buffer, data.data(), data.size()); + if (i == data.length()) { + end_stream = true; + } + + return Api::SysCallSizeResult{ssize_t(i), 0}; + })); + } + } + + EXPECT_CALL(socket_, setRequestedApplicationProtocols(_)).Times(0); + EXPECT_EQ(0, cfg_->stats().http_not_found_.value()); + while (!end_stream) { + file_event_callback_(Event::FileReadyType::Read); + } +} +TEST_F(HttpInspectorTest, MultipleReadsHttp1BadProtocol) { + + init(); + + const absl::string_view data = "GET /index HTT\r"; + { + InSequence s; + + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)).WillOnce(InvokeWithoutArgs([]() { + return Api::SysCallSizeResult{ssize_t(-1), EAGAIN}; + })); + + for (size_t i = 1; i <= data.length(); i++) { + EXPECT_CALL(os_sys_calls_, recv(42, _, _, MSG_PEEK)) + .WillOnce( + Invoke([&data, i](int, void* buffer, size_t length, int) -> Api::SysCallSizeResult { + ASSERT(length >= data.size()); + memcpy(buffer, data.data(), data.size()); + return Api::SysCallSizeResult{ssize_t(i), 0}; + })); + } + } + + bool got_continue = false; + EXPECT_CALL(socket_, setRequestedApplicationProtocols(_)).Times(0); + EXPECT_CALL(cb_, continueFilterChain(true)).WillOnce(InvokeWithoutArgs([&got_continue]() { + got_continue = true; + })); + while (!got_continue) { + file_event_callback_(Event::FileReadyType::Read); + } + EXPECT_EQ(1, cfg_->stats().http_not_found_.value()); +} + +} // namespace +} // namespace HttpInspector +} // namespace ListenerFilters +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/filters/listener/tls_inspector/tls_inspector_test.cc b/test/extensions/filters/listener/tls_inspector/tls_inspector_test.cc index 9412e3a0caf6..63cff699cffe 100644 --- a/test/extensions/filters/listener/tls_inspector/tls_inspector_test.cc +++ b/test/extensions/filters/listener/tls_inspector/tls_inspector_test.cc @@ -34,7 +34,7 @@ class TlsInspectorTest : public testing::Test { TlsInspectorTest() : cfg_(std::make_shared(store_)), io_handle_(std::make_unique(42)) {} - ~TlsInspectorTest() { io_handle_->close(); } + ~TlsInspectorTest() override { io_handle_->close(); } void init() { filter_ = std::make_unique(cfg_); diff --git a/test/extensions/filters/network/client_ssl_auth/client_ssl_auth_test.cc b/test/extensions/filters/network/client_ssl_auth/client_ssl_auth_test.cc index 7c5e09642488..5321d370a189 100644 --- a/test/extensions/filters/network/client_ssl_auth/client_ssl_auth_test.cc +++ b/test/extensions/filters/network/client_ssl_auth/client_ssl_auth_test.cc @@ -59,7 +59,7 @@ class ClientSslAuthFilterTest : public testing::Test { ClientSslAuthFilterTest() : request_(&cm_.async_client_), interval_timer_(new Event::MockTimer(&dispatcher_)), api_(Api::createApiForTest(stats_store_)) {} - ~ClientSslAuthFilterTest() { tls_.shutdownThread(); } + ~ClientSslAuthFilterTest() override { tls_.shutdownThread(); } void setup() { std::string yaml = R"EOF( diff --git a/test/extensions/filters/network/common/redis/client_impl_test.cc b/test/extensions/filters/network/common/redis/client_impl_test.cc index ecea5c887c22..fd7d9ec9b7e5 100644 --- a/test/extensions/filters/network/common/redis/client_impl_test.cc +++ b/test/extensions/filters/network/common/redis/client_impl_test.cc @@ -43,7 +43,7 @@ class RedisClientImplTest : public testing::Test, public Common::Redis::DecoderF return Common::Redis::DecoderPtr{decoder_}; } - ~RedisClientImplTest() { + ~RedisClientImplTest() override { client_.reset(); EXPECT_TRUE(TestUtility::gaugesZeroed(host_->cluster_.stats_store_.gauges())); diff --git a/test/extensions/filters/network/common/redis/mocks.h b/test/extensions/filters/network/common/redis/mocks.h index 829983abd53d..859ea03cf42b 100644 --- a/test/extensions/filters/network/common/redis/mocks.h +++ b/test/extensions/filters/network/common/redis/mocks.h @@ -27,7 +27,7 @@ void PrintTo(const RespValuePtr& value, std::ostream* os); class MockEncoder : public Common::Redis::Encoder { public: MockEncoder(); - ~MockEncoder(); + ~MockEncoder() override; MOCK_METHOD2(encode, void(const Common::Redis::RespValue& value, Buffer::Instance& out)); @@ -38,7 +38,7 @@ class MockEncoder : public Common::Redis::Encoder { class MockDecoder : public Common::Redis::Decoder { public: MockDecoder(); - ~MockDecoder(); + ~MockDecoder() override; MOCK_METHOD1(decode, void(Buffer::Instance& data)); }; @@ -48,7 +48,7 @@ namespace Client { class MockClient : public Client { public: MockClient(); - ~MockClient(); + ~MockClient() override; void raiseEvent(Network::ConnectionEvent event) { for (Network::ConnectionCallbacks* callbacks : callbacks_) { @@ -80,7 +80,7 @@ class MockClient : public Client { class MockPoolRequest : public PoolRequest { public: MockPoolRequest(); - ~MockPoolRequest(); + ~MockPoolRequest() override; MOCK_METHOD0(cancel, void()); }; @@ -88,7 +88,7 @@ class MockPoolRequest : public PoolRequest { class MockPoolCallbacks : public PoolCallbacks { public: MockPoolCallbacks(); - ~MockPoolCallbacks(); + ~MockPoolCallbacks() override; void onResponse(Common::Redis::RespValuePtr&& value) override { onResponse_(value); } diff --git a/test/extensions/filters/network/dubbo_proxy/BUILD b/test/extensions/filters/network/dubbo_proxy/BUILD index 3d40c8ae9bb7..f59221ca29d9 100644 --- a/test/extensions/filters/network/dubbo_proxy/BUILD +++ b/test/extensions/filters/network/dubbo_proxy/BUILD @@ -21,8 +21,9 @@ envoy_cc_mock( "//source/common/protobuf", "//source/common/protobuf:utility_lib", "//source/extensions/filters/network/dubbo_proxy:decoder_events_lib", - "//source/extensions/filters/network/dubbo_proxy:deserializer_interface", + "//source/extensions/filters/network/dubbo_proxy:decoder_lib", "//source/extensions/filters/network/dubbo_proxy:protocol_interface", + "//source/extensions/filters/network/dubbo_proxy:serializer_interface", "//source/extensions/filters/network/dubbo_proxy/filters:factory_base_lib", "//source/extensions/filters/network/dubbo_proxy/filters:filter_interface", "//source/extensions/filters/network/dubbo_proxy/router:router_interface", @@ -68,13 +69,13 @@ envoy_extension_cc_test( ) envoy_extension_cc_test( - name = "hessian_deserializer_impl_test", - srcs = ["hessian_deserializer_impl_test.cc"], + name = "dubbo_hessian2_serializer_impl_test", + srcs = ["dubbo_hessian2_serializer_impl_test.cc"], extension_name = "envoy.filters.network.dubbo_proxy", deps = [ ":mocks_lib", ":utility_lib", - "//source/extensions/filters/network/dubbo_proxy:hessian_deserializer_impl_lib", + "//source/extensions/filters/network/dubbo_proxy:dubbo_hessian2_serializer_impl_lib", "//source/extensions/filters/network/dubbo_proxy:hessian_utils_lib", "//test/mocks/server:server_mocks", ], @@ -101,6 +102,7 @@ envoy_extension_cc_test( extension_name = "envoy.filters.network.dubbo_proxy", deps = [ "//source/extensions/filters/network/dubbo_proxy:metadata_lib", + "//source/extensions/filters/network/dubbo_proxy:serializer_interface", ], ) @@ -123,8 +125,8 @@ envoy_extension_cc_test( deps = [ ":mocks_lib", "//source/extensions/filters/network/dubbo_proxy:app_exception_lib", + "//source/extensions/filters/network/dubbo_proxy:dubbo_hessian2_serializer_impl_lib", "//source/extensions/filters/network/dubbo_proxy:dubbo_protocol_impl_lib", - "//source/extensions/filters/network/dubbo_proxy:hessian_deserializer_impl_lib", "//source/extensions/filters/network/dubbo_proxy:metadata_lib", "//source/extensions/filters/network/dubbo_proxy/router:config", "//test/mocks/server:server_mocks", @@ -140,8 +142,8 @@ envoy_extension_cc_test( ":mocks_lib", ":utility_lib", "//source/extensions/filters/network/dubbo_proxy:app_exception_lib", + "//source/extensions/filters/network/dubbo_proxy:dubbo_hessian2_serializer_impl_lib", "//source/extensions/filters/network/dubbo_proxy:dubbo_protocol_impl_lib", - "//source/extensions/filters/network/dubbo_proxy:hessian_deserializer_impl_lib", "//source/extensions/filters/network/dubbo_proxy:hessian_utils_lib", "//source/extensions/filters/network/dubbo_proxy:metadata_lib", ], @@ -180,8 +182,8 @@ envoy_extension_cc_test( ":utility_lib", "//source/extensions/filters/network/dubbo_proxy:config", "//source/extensions/filters/network/dubbo_proxy:conn_manager_lib", + "//source/extensions/filters/network/dubbo_proxy:dubbo_hessian2_serializer_impl_lib", "//source/extensions/filters/network/dubbo_proxy:dubbo_protocol_impl_lib", - "//source/extensions/filters/network/dubbo_proxy:hessian_deserializer_impl_lib", "//test/mocks/server:server_mocks", ], ) diff --git a/test/extensions/filters/network/dubbo_proxy/app_exception_test.cc b/test/extensions/filters/network/dubbo_proxy/app_exception_test.cc index 0fa7c8dd0e9f..3856f893bf2c 100644 --- a/test/extensions/filters/network/dubbo_proxy/app_exception_test.cc +++ b/test/extensions/filters/network/dubbo_proxy/app_exception_test.cc @@ -1,10 +1,10 @@ #include "extensions/filters/network/dubbo_proxy/app_exception.h" -#include "extensions/filters/network/dubbo_proxy/deserializer_impl.h" +#include "extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.h" #include "extensions/filters/network/dubbo_proxy/dubbo_protocol_impl.h" #include "extensions/filters/network/dubbo_proxy/filters/filter.h" -#include "extensions/filters/network/dubbo_proxy/hessian_deserializer_impl.h" #include "extensions/filters/network/dubbo_proxy/hessian_utils.h" #include "extensions/filters/network/dubbo_proxy/metadata.h" +#include "extensions/filters/network/dubbo_proxy/serializer_impl.h" #include "test/extensions/filters/network/dubbo_proxy/mocks.h" @@ -21,12 +21,12 @@ namespace DubboProxy { class AppExceptionTest : public testing::Test { public: - AppExceptionTest() : metadata_(std::make_shared()) {} + AppExceptionTest() : metadata_(std::make_shared()) { + protocol_.initSerializer(SerializationType::Hessian2); + } - HessianDeserializerImpl deserializer_; DubboProtocolImpl protocol_; MessageMetadataSharedPtr metadata_; - Protocol::Context context_; }; TEST_F(AppExceptionTest, Encode) { @@ -39,16 +39,19 @@ TEST_F(AppExceptionTest, Encode) { HessianUtils::writeInt(buffer, static_cast(app_exception.response_type_)); buffer.drain(buffer.length()); - metadata_->setSerializationType(SerializationType::Hessian); + metadata_->setSerializationType(SerializationType::Hessian2); metadata_->setRequestId(0); - EXPECT_EQ(app_exception.encode(*(metadata_.get()), protocol_, deserializer_, buffer), + EXPECT_EQ(app_exception.encode(*(metadata_.get()), protocol_, buffer), DubboFilters::DirectResponse::ResponseType::Exception); MessageMetadataSharedPtr metadata = std::make_shared(); - EXPECT_TRUE(protocol_.decode(buffer, &context_, metadata)); - EXPECT_EQ(expect_body_size, context_.body_size_); + auto result = protocol_.decodeHeader(buffer, metadata); + EXPECT_TRUE(result.second); + + const ContextImpl* context = static_cast(result.first.get()); + EXPECT_EQ(expect_body_size, context->body_size()); EXPECT_EQ(metadata->message_type(), MessageType::Response); - buffer.drain(context_.header_size_); + buffer.drain(context->header_size()); // Verify the response type and content. size_t hessian_int_size; @@ -61,17 +64,17 @@ TEST_F(AppExceptionTest, Encode) { EXPECT_EQ(buffer.length(), hessian_int_size + hessian_string_size); - auto result = deserializer_.deserializeRpcResult(buffer, context_.body_size_); - EXPECT_TRUE(result->hasException()); + auto rpc_result = protocol_.serializer()->deserializeRpcResult(buffer, result.first); + EXPECT_TRUE(rpc_result.second); + EXPECT_TRUE(rpc_result.first->hasException()); buffer.drain(buffer.length()); AppException new_app_exception(app_exception); EXPECT_EQ(new_app_exception.status_, ResponseStatus::ServiceNotFound); MockProtocol mock_protocol; - EXPECT_CALL(mock_protocol, encode(_, _, _)).WillOnce(Return(false)); - EXPECT_THROW(app_exception.encode(*(metadata_.get()), mock_protocol, deserializer_, buffer), - EnvoyException); + EXPECT_CALL(mock_protocol, encode(_, _, _, _)).WillOnce(Return(false)); + EXPECT_THROW(app_exception.encode(*(metadata_.get()), mock_protocol, buffer), EnvoyException); } } // namespace DubboProxy diff --git a/test/extensions/filters/network/dubbo_proxy/conn_manager_test.cc b/test/extensions/filters/network/dubbo_proxy/conn_manager_test.cc index 833bf34c1ad2..a8dc3e35d24c 100644 --- a/test/extensions/filters/network/dubbo_proxy/conn_manager_test.cc +++ b/test/extensions/filters/network/dubbo_proxy/conn_manager_test.cc @@ -6,8 +6,9 @@ #include "extensions/filters/network/dubbo_proxy/app_exception.h" #include "extensions/filters/network/dubbo_proxy/config.h" #include "extensions/filters/network/dubbo_proxy/conn_manager.h" +#include "extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.h" #include "extensions/filters/network/dubbo_proxy/dubbo_protocol_impl.h" -#include "extensions/filters/network/dubbo_proxy/hessian_deserializer_impl.h" +#include "extensions/filters/network/dubbo_proxy/message_impl.h" #include "test/extensions/filters/network/dubbo_proxy/mocks.h" #include "test/extensions/filters/network/dubbo_proxy/utility.h" @@ -46,14 +47,18 @@ class TestConfigImpl : public ConfigImpl { if (custom_filter_) { callbacks.addDecoderFilter(custom_filter_); } - callbacks.addDecoderFilter(decoder_filter_); - } - DeserializerPtr createDeserializer() override { - if (deserializer_) { - return DeserializerPtr{deserializer_}; + if (encoder_filter_) { + callbacks.addEncoderFilter(encoder_filter_); + } + + if (decoder_filter_) { + callbacks.addDecoderFilter(decoder_filter_); + } + + if (codec_filter_) { + callbacks.addFilter(codec_filter_); } - return ConfigImpl::createDeserializer(); } ProtocolPtr createProtocol() override { @@ -73,8 +78,10 @@ class TestConfigImpl : public ConfigImpl { DubboFilters::DecoderFilterSharedPtr custom_filter_; DubboFilters::DecoderFilterSharedPtr decoder_filter_; + DubboFilters::EncoderFilterSharedPtr encoder_filter_; + DubboFilters::CodecFilterSharedPtr codec_filter_; DubboFilterStats& stats_; - MockDeserializer* deserializer_{}; + MockSerializer* serializer_{}; MockProtocol* protocol_{}; std::shared_ptr route_; }; @@ -82,7 +89,9 @@ class TestConfigImpl : public ConfigImpl { class ConnectionManagerTest : public testing::Test { public: ConnectionManagerTest() : stats_(DubboFilterStats::generateStats("test.", store_)) {} - ~ConnectionManagerTest() { filter_callbacks_.connection_.dispatcher_.clearDeferredDeleteList(); } + ~ConnectionManagerTest() override { + filter_callbacks_.connection_.dispatcher_.clearDeferredDeleteList(); + } TimeSource& timeSystem() { return factory_context_.dispatcher().timeSource(); } @@ -102,8 +111,8 @@ class ConnectionManagerTest : public testing::Test { decoder_filter_.reset(new NiceMock()); config_ = std::make_unique(proto_config_, factory_context_, decoder_filter_, stats_); - if (custom_deserializer_) { - config_->deserializer_ = custom_deserializer_; + if (custom_serializer_) { + config_->serializer_ = custom_serializer_; } if (custom_protocol_) { config_->protocol_ = custom_protocol_; @@ -112,8 +121,6 @@ class ConnectionManagerTest : public testing::Test { config_->custom_filter_ = custom_filter_; } - decoder_event_handler_.reset(new NiceMock()); - ON_CALL(random_, random()).WillByDefault(Return(42)); filter_ = std::make_unique( *config_, random_, filter_callbacks_.connection_.dispatcher_.timeSource()); @@ -272,14 +279,13 @@ class ConnectionManagerTest : public testing::Test { buffer.add(std::string{'\xda', '\xbb'}); buffer.add(static_cast(&msg_type), 1); - buffer.add(std::string{0x00}); + buffer.add(std::string{0x14}); addInt64(buffer, request_id); // Request Id buffer.add(std::string{0x00, 0x00, 0x00, 0x00}); // Body Length } NiceMock factory_context_; std::shared_ptr decoder_filter_; - std::shared_ptr decoder_event_handler_; Stats::IsolatedStoreImpl store_; DubboFilterStats stats_; ConfigDubboProxy proto_config_; @@ -291,7 +297,7 @@ class ConnectionManagerTest : public testing::Test { NiceMock filter_callbacks_; NiceMock random_; std::unique_ptr filter_; - MockDeserializer* custom_deserializer_{}; + MockSerializer* custom_serializer_{}; MockProtocol* custom_protocol_{}; DubboFilters::DecoderFilterSharedPtr custom_filter_; }; @@ -334,13 +340,14 @@ TEST_F(ConnectionManagerTest, OnDataHandlesHeartbeatEvent) { EXPECT_CALL(filter_callbacks_.connection_, write(_, false)) .WillOnce(Invoke([&](Buffer::Instance& buffer, bool) -> void { ProtocolPtr protocol = filter_->config().createProtocol(); - Protocol::Context ctx; MessageMetadataSharedPtr metadata(std::make_shared()); - EXPECT_TRUE(protocol->decode(buffer, &ctx, metadata)); - EXPECT_TRUE(ctx.is_heartbeat_); - EXPECT_EQ(metadata->response_status().value(), ResponseStatus::Ok); - EXPECT_EQ(metadata->message_type(), MessageType::Response); - buffer.drain(ctx.header_size_); + auto result = protocol->decodeHeader(buffer, metadata); + EXPECT_TRUE(result.second); + const DubboProxy::ContextImpl& ctx = *static_cast(result.first.get()); + EXPECT_TRUE(ctx.is_heartbeat()); + EXPECT_EQ(metadata->response_status(), ResponseStatus::Ok); + EXPECT_EQ(metadata->message_type(), MessageType::HeartbeatResponse); + buffer.drain(ctx.header_size()); })); EXPECT_EQ(filter_->onData(buffer_, false), Network::FilterStatus::StopIteration); @@ -354,7 +361,7 @@ TEST_F(ConnectionManagerTest, HandlesHeartbeatWithException) { custom_protocol_ = new NiceMock(); initializeFilter(); - EXPECT_CALL(*custom_protocol_, encode(_, _, _)).WillOnce(Return(false)); + EXPECT_CALL(*custom_protocol_, encode(_, _, _, _)).WillOnce(Return(false)); MessageMetadataSharedPtr meta = std::make_shared(); EXPECT_THROW_WITH_MESSAGE(filter_->onHeartbeat(meta), EnvoyException, @@ -408,9 +415,7 @@ TEST_F(ConnectionManagerTest, OnDataHandlesProtocolErrorOnWrite) { // Disable sniffing writeInvalidRequestMessage(write_buffer_); - DubboProtocolImpl protocol; - HessianDeserializerImpl deserializer; - callbacks->startUpstreamResponse(deserializer, protocol); + callbacks->startUpstreamResponse(); EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, deferredDelete_(_)).Times(1); EXPECT_NE(DubboFilters::UpstreamResponseStatus::Complete, callbacks->upstreamData(write_buffer_)); @@ -425,7 +430,7 @@ TEST_F(ConnectionManagerTest, OnDataStopsSniffingWithTooManyPendingCalls) { writeHessianRequestMessage(buffer_, false, false, i); } - EXPECT_CALL(*decoder_filter_, messageEnd(_)).Times(64); + EXPECT_CALL(*decoder_filter_, onMessageDecoded(_, _)).Times(64); EXPECT_EQ(filter_->onData(buffer_, false), Network::FilterStatus::StopIteration); EXPECT_EQ(64U, store_.gauge("test.request_active", Stats::Gauge::ImportMode::Accumulate).value()); @@ -455,9 +460,7 @@ TEST_F(ConnectionManagerTest, OnWriteHandlesResponse) { writeHessianResponseMessage(write_buffer_, false, request_id); - DubboProtocolImpl protocol; - HessianDeserializerImpl deserializer; - callbacks->startUpstreamResponse(deserializer, protocol); + callbacks->startUpstreamResponse(); EXPECT_EQ(callbacks->requestId(), request_id); EXPECT_EQ(callbacks->connection(), &(filter_callbacks_.connection_)); @@ -491,9 +494,7 @@ TEST_F(ConnectionManagerTest, HandlesResponseContainExceptionInfo) { writeHessianExceptionResponseMessage(write_buffer_, false, 1); - DubboProtocolImpl protocol; - HessianDeserializerImpl deserializer; - callbacks->startUpstreamResponse(deserializer, protocol); + callbacks->startUpstreamResponse(); EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, deferredDelete_(_)).Times(1); EXPECT_EQ(DubboFilters::UpstreamResponseStatus::Complete, callbacks->upstreamData(write_buffer_)); @@ -523,9 +524,7 @@ TEST_F(ConnectionManagerTest, HandlesResponseError) { writeHessianErrorResponseMessage(write_buffer_, false, 1); - DubboProtocolImpl protocol; - HessianDeserializerImpl deserializer; - callbacks->startUpstreamResponse(deserializer, protocol); + callbacks->startUpstreamResponse(); EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, deferredDelete_(_)).Times(1); EXPECT_EQ(DubboFilters::UpstreamResponseStatus::Complete, callbacks->upstreamData(write_buffer_)); @@ -552,9 +551,7 @@ TEST_F(ConnectionManagerTest, OnWriteHandlesResponseException) { writeInvalidRequestMessage(write_buffer_); - DubboProtocolImpl protocol; - HessianDeserializerImpl deserializer; - callbacks->startUpstreamResponse(deserializer, protocol); + callbacks->startUpstreamResponse(); EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, deferredDelete_(_)).Times(1); EXPECT_EQ(DubboFilters::UpstreamResponseStatus::Reset, callbacks->upstreamData(write_buffer_)); @@ -582,18 +579,9 @@ TEST_F(ConnectionManagerTest, OnDataResumesWithNextFilter) { .WillOnce(Invoke([&](DubboFilters::DecoderFilterCallbacks& cb) -> void { callbacks = &cb; })); EXPECT_CALL(*decoder_filter_, setDecoderFilterCallbacks(_)); - ON_CALL(*filter, transferHeaderTo(_, _)) - .WillByDefault(Invoke([&](Buffer::Instance&, size_t) -> Network::FilterStatus { - return Network::FilterStatus::Continue; - })); - ON_CALL(*filter, transferBodyTo(_, _)) - .WillByDefault(Invoke([&](Buffer::Instance&, size_t) -> Network::FilterStatus { - return Network::FilterStatus::Continue; - })); - // First filter stops iteration. { - EXPECT_CALL(*filter, transportBegin()).WillOnce(Return(Network::FilterStatus::StopIteration)); + EXPECT_CALL(*filter, onMessageDecoded(_, _)).WillOnce(Return(FilterStatus::StopIteration)); EXPECT_EQ(filter_->onData(buffer_, false), Network::FilterStatus::StopIteration); EXPECT_EQ(0U, store_.counter("test.request").value()); EXPECT_EQ(1U, @@ -603,10 +591,8 @@ TEST_F(ConnectionManagerTest, OnDataResumesWithNextFilter) { // Resume processing. { InSequence s; - EXPECT_CALL(*decoder_filter_, transportBegin()) - .WillOnce(Return(Network::FilterStatus::Continue)); - EXPECT_CALL(*filter, messageEnd(_)).WillOnce(Return(Network::FilterStatus::Continue)); - EXPECT_CALL(*decoder_filter_, messageEnd(_)).WillOnce(Return(Network::FilterStatus::Continue)); + EXPECT_CALL(*filter, onMessageDecoded(_, _)).WillOnce(Return(FilterStatus::Continue)); + EXPECT_CALL(*decoder_filter_, onMessageDecoded(_, _)).WillOnce(Return(FilterStatus::Continue)); callbacks->continueDecoding(); } @@ -622,20 +608,9 @@ TEST_F(ConnectionManagerTest, OnDataHandlesDubboCallWithMultipleFilters) { writeHessianRequestMessage(buffer_, false, false, 0x0F); - ON_CALL(*filter, transferHeaderTo(_, _)) - .WillByDefault(Invoke([&](Buffer::Instance&, size_t) -> Network::FilterStatus { - return Network::FilterStatus::Continue; - })); - ON_CALL(*filter, transferBodyTo(_, _)) - .WillByDefault(Invoke([&](Buffer::Instance&, size_t) -> Network::FilterStatus { - return Network::FilterStatus::Continue; - })); - InSequence s; - EXPECT_CALL(*filter, transportBegin()).WillOnce(Return(Network::FilterStatus::Continue)); - EXPECT_CALL(*decoder_filter_, transportBegin()).WillOnce(Return(Network::FilterStatus::Continue)); - EXPECT_CALL(*filter, messageEnd(_)).WillOnce(Return(Network::FilterStatus::Continue)); - EXPECT_CALL(*decoder_filter_, messageEnd(_)).WillOnce(Return(Network::FilterStatus::Continue)); + EXPECT_CALL(*filter, onMessageDecoded(_, _)).WillOnce(Return(FilterStatus::Continue)); + EXPECT_CALL(*decoder_filter_, onMessageDecoded(_, _)).WillOnce(Return(FilterStatus::Continue)); EXPECT_EQ(filter_->onData(buffer_, false), Network::FilterStatus::StopIteration); EXPECT_EQ(1U, store_.counter("test.request").value()); @@ -659,11 +634,8 @@ TEST_F(ConnectionManagerTest, PipelinedRequestAndResponse) { EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, deferredDelete_(_)).Times(2); - DubboProtocolImpl protocol; - HessianDeserializerImpl deserializer; - writeHessianResponseMessage(write_buffer_, false, 0x01); - callbacks.front()->startUpstreamResponse(deserializer, protocol); + callbacks.front()->startUpstreamResponse(); EXPECT_EQ(DubboFilters::UpstreamResponseStatus::Complete, callbacks.front()->upstreamData(write_buffer_)); callbacks.pop_front(); @@ -671,7 +643,7 @@ TEST_F(ConnectionManagerTest, PipelinedRequestAndResponse) { EXPECT_EQ(1U, store_.counter("test.response_success").value()); writeHessianResponseMessage(write_buffer_, false, 0x02); - callbacks.front()->startUpstreamResponse(deserializer, protocol); + callbacks.front()->startUpstreamResponse(); EXPECT_EQ(DubboFilters::UpstreamResponseStatus::Complete, callbacks.front()->upstreamData(write_buffer_)); callbacks.pop_front(); @@ -772,7 +744,6 @@ TEST_F(ConnectionManagerTest, OnEvent) { buffer_.drain(buffer_.length()); } } - TEST_F(ConnectionManagerTest, ResponseWithUnknownSequenceID) { initializeFilter(); @@ -785,9 +756,7 @@ TEST_F(ConnectionManagerTest, ResponseWithUnknownSequenceID) { writeHessianResponseMessage(write_buffer_, false, 10); - DubboProtocolImpl protocol; - HessianDeserializerImpl deserializer; - callbacks->startUpstreamResponse(deserializer, protocol); + callbacks->startUpstreamResponse(); EXPECT_EQ(DubboFilters::UpstreamResponseStatus::Reset, callbacks->upstreamData(write_buffer_)); EXPECT_EQ(1U, store_.counter("test.response_decoding_error").value()); @@ -800,15 +769,6 @@ TEST_F(ConnectionManagerTest, OnDataWithFilterSendsLocalReply) { initializeFilter(); writeHessianRequestMessage(buffer_, false, false, 1); - ON_CALL(*filter, transferHeaderTo(_, _)) - .WillByDefault(Invoke([&](Buffer::Instance&, size_t) -> Network::FilterStatus { - return Network::FilterStatus::Continue; - })); - ON_CALL(*filter, transferBodyTo(_, _)) - .WillByDefault(Invoke([&](Buffer::Instance&, size_t) -> Network::FilterStatus { - return Network::FilterStatus::Continue; - })); - DubboFilters::DecoderFilterCallbacks* callbacks{}; EXPECT_CALL(*filter, setDecoderFilterCallbacks(_)) .WillOnce(Invoke([&](DubboFilters::DecoderFilterCallbacks& cb) -> void { callbacks = &cb; })); @@ -816,19 +776,19 @@ TEST_F(ConnectionManagerTest, OnDataWithFilterSendsLocalReply) { const std::string fake_response("mock dubbo response"); NiceMock direct_response; - EXPECT_CALL(direct_response, encode(_, _, _, _)) - .WillOnce(Invoke([&](MessageMetadata&, Protocol&, Deserializer&, + EXPECT_CALL(direct_response, encode(_, _, _)) + .WillOnce(Invoke([&](MessageMetadata&, Protocol&, Buffer::Instance& buffer) -> DubboFilters::DirectResponse::ResponseType { buffer.add(fake_response); return DubboFilters::DirectResponse::ResponseType::SuccessReply; })); // First filter sends local reply. - EXPECT_CALL(*filter, messageEnd(_)) - .WillOnce(Invoke([&](MessageMetadataSharedPtr) -> Network::FilterStatus { + EXPECT_CALL(*filter, onMessageDecoded(_, _)) + .WillOnce(Invoke([&](MessageMetadataSharedPtr, ContextSharedPtr) -> FilterStatus { callbacks->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::NoRouteFound); callbacks->sendLocalReply(direct_response, false); - return Network::FilterStatus::StopIteration; + return FilterStatus::StopIteration; })); EXPECT_CALL(filter_callbacks_.connection_, write(_, false)) .WillOnce(Invoke([&](Buffer::Instance& buffer, bool) -> void { @@ -836,8 +796,8 @@ TEST_F(ConnectionManagerTest, OnDataWithFilterSendsLocalReply) { })); EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, deferredDelete_(_)).Times(1); EXPECT_EQ(filter_->onData(buffer_, false), Network::FilterStatus::StopIteration); - EXPECT_EQ(SerializationType::Hessian, callbacks->downstreamSerializationType()); - EXPECT_EQ(ProtocolType::Dubbo, callbacks->downstreamProtocolType()); + EXPECT_EQ(SerializationType::Hessian2, callbacks->serializationType()); + EXPECT_EQ(ProtocolType::Dubbo, callbacks->protocolType()); filter_callbacks_.connection_.dispatcher_.clearDeferredDeleteList(); @@ -853,15 +813,6 @@ TEST_F(ConnectionManagerTest, OnDataWithFilterSendsLocalErrorReply) { initializeFilter(); writeHessianRequestMessage(buffer_, false, false, 1); - ON_CALL(*filter, transferHeaderTo(_, _)) - .WillByDefault(Invoke([&](Buffer::Instance&, size_t) -> Network::FilterStatus { - return Network::FilterStatus::Continue; - })); - ON_CALL(*filter, transferBodyTo(_, _)) - .WillByDefault(Invoke([&](Buffer::Instance&, size_t) -> Network::FilterStatus { - return Network::FilterStatus::Continue; - })); - DubboFilters::DecoderFilterCallbacks* callbacks{}; EXPECT_CALL(*filter, setDecoderFilterCallbacks(_)) .WillOnce(Invoke([&](DubboFilters::DecoderFilterCallbacks& cb) -> void { callbacks = &cb; })); @@ -869,18 +820,18 @@ TEST_F(ConnectionManagerTest, OnDataWithFilterSendsLocalErrorReply) { const std::string fake_response("mock dubbo response"); NiceMock direct_response; - EXPECT_CALL(direct_response, encode(_, _, _, _)) - .WillOnce(Invoke([&](MessageMetadata&, Protocol&, Deserializer&, + EXPECT_CALL(direct_response, encode(_, _, _)) + .WillOnce(Invoke([&](MessageMetadata&, Protocol&, Buffer::Instance& buffer) -> DubboFilters::DirectResponse::ResponseType { buffer.add(fake_response); return DubboFilters::DirectResponse::ResponseType::ErrorReply; })); // First filter sends local reply. - EXPECT_CALL(*filter, messageEnd(_)) - .WillOnce(Invoke([&](MessageMetadataSharedPtr) -> Network::FilterStatus { + EXPECT_CALL(*filter, onMessageDecoded(_, _)) + .WillOnce(Invoke([&](MessageMetadataSharedPtr, ContextSharedPtr) -> FilterStatus { callbacks->sendLocalReply(direct_response, false); - return Network::FilterStatus::StopIteration; + return FilterStatus::StopIteration; })); EXPECT_CALL(filter_callbacks_.connection_, write(_, false)) .WillOnce(Invoke([&](Buffer::Instance& buffer, bool) -> void { @@ -900,9 +851,9 @@ TEST_F(ConnectionManagerTest, TwoWayRequestWithEndStream) { initializeFilter(); writeHessianRequestMessage(buffer_, false, false, 0x0F); - ON_CALL(*decoder_filter_, transferHeaderTo(_, _)) - .WillByDefault(Invoke([&](Buffer::Instance&, size_t) -> Network::FilterStatus { - return Network::FilterStatus::StopIteration; + EXPECT_CALL(*decoder_filter_, onMessageDecoded(_, _)) + .WillOnce(Invoke([&](MessageMetadataSharedPtr, ContextSharedPtr) -> FilterStatus { + return FilterStatus::StopIteration; })); EXPECT_CALL(filter_callbacks_.connection_, close(Network::ConnectionCloseType::FlushWrite)) @@ -916,15 +867,15 @@ TEST_F(ConnectionManagerTest, OneWayRequestWithEndStream) { initializeFilter(); writeHessianRequestMessage(buffer_, true, false, 0x0F); - EXPECT_CALL(*decoder_filter_, messageEnd(_)) - .WillOnce(Invoke([&](MessageMetadataSharedPtr) -> Network::FilterStatus { - return Network::FilterStatus::StopIteration; + EXPECT_CALL(*decoder_filter_, onMessageDecoded(_, _)) + .WillOnce(Invoke([&](MessageMetadataSharedPtr, ContextSharedPtr) -> FilterStatus { + return FilterStatus::StopIteration; })); EXPECT_CALL(filter_callbacks_.connection_, close(Network::ConnectionCloseType::FlushWrite)) - .Times(0); - EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, deferredDelete_(_)).Times(0); + .Times(1); + EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, deferredDelete_(_)).Times(1); EXPECT_EQ(filter_->onData(buffer_, true), Network::FilterStatus::StopIteration); - EXPECT_EQ(0U, store_.counter("test.cx_destroy_remote_with_active_rq").value()); + EXPECT_EQ(1U, store_.counter("test.cx_destroy_remote_with_active_rq").value()); } TEST_F(ConnectionManagerTest, EmptyRequestData) { @@ -940,9 +891,9 @@ TEST_F(ConnectionManagerTest, StopHandleRequest) { initializeFilter(); writeHessianRequestMessage(buffer_, false, false, 0x0F); - ON_CALL(*decoder_filter_, transferHeaderTo(_, _)) - .WillByDefault(Invoke([&](Buffer::Instance&, size_t) -> Network::FilterStatus { - return Network::FilterStatus::StopIteration; + ON_CALL(*decoder_filter_, onMessageDecoded(_, _)) + .WillByDefault(Invoke([&](MessageMetadataSharedPtr, ContextSharedPtr) -> FilterStatus { + return FilterStatus::StopIteration; })); EXPECT_CALL(filter_callbacks_.connection_, close(Network::ConnectionCloseType::FlushWrite)) @@ -973,8 +924,8 @@ TEST_F(ConnectionManagerTest, SendsLocalReplyWithCloseConnection) { const std::string fake_response("mock dubbo response"); NiceMock direct_response; - EXPECT_CALL(direct_response, encode(_, _, _, _)) - .WillOnce(Invoke([&](MessageMetadata&, Protocol&, Deserializer&, + EXPECT_CALL(direct_response, encode(_, _, _)) + .WillOnce(Invoke([&](MessageMetadata&, Protocol&, Buffer::Instance& buffer) -> DubboFilters::DirectResponse::ResponseType { buffer.add(fake_response); return DubboFilters::DirectResponse::ResponseType::ErrorReply; @@ -987,7 +938,7 @@ TEST_F(ConnectionManagerTest, SendsLocalReplyWithCloseConnection) { EXPECT_EQ(1U, store_.counter("test.local_response_error").value()); // The connection closed. - EXPECT_CALL(direct_response, encode(_, _, _, _)).Times(0); + EXPECT_CALL(direct_response, encode(_, _, _)).Times(0); filter_->sendLocalReply(metadata, direct_response, true); } @@ -995,19 +946,16 @@ TEST_F(ConnectionManagerTest, ContinueDecodingWithHalfClose) { initializeFilter(); writeHessianRequestMessage(buffer_, true, false, 0x0F); - EXPECT_CALL(*decoder_filter_, messageEnd(_)) - .WillOnce(Invoke([&](MessageMetadataSharedPtr) -> Network::FilterStatus { - return Network::FilterStatus::StopIteration; + EXPECT_CALL(*decoder_filter_, onMessageDecoded(_, _)) + .WillOnce(Invoke([&](MessageMetadataSharedPtr, ContextSharedPtr) -> FilterStatus { + return FilterStatus::StopIteration; })); - EXPECT_CALL(filter_callbacks_.connection_, close(Network::ConnectionCloseType::FlushWrite)) - .Times(0); - EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, deferredDelete_(_)).Times(0); - EXPECT_EQ(filter_->onData(buffer_, true), Network::FilterStatus::StopIteration); - EXPECT_EQ(0U, store_.counter("test.cx_destroy_remote_with_active_rq").value()); - EXPECT_CALL(filter_callbacks_.connection_, close(Network::ConnectionCloseType::FlushWrite)) .Times(1); EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, deferredDelete_(_)).Times(1); + EXPECT_EQ(filter_->onData(buffer_, true), Network::FilterStatus::StopIteration); + EXPECT_EQ(1U, store_.counter("test.cx_destroy_remote_with_active_rq").value()); + filter_->continueDecoding(); } @@ -1030,11 +978,9 @@ TEST_F(ConnectionManagerTest, RoutingSuccess) { TEST_F(ConnectionManagerTest, RoutingFailure) { initializeFilter(); - writeHessianRequestMessage(buffer_, false, false, 0x0F); + writePartialHessianRequestMessage(buffer_, false, false, 0x0F, true); - EXPECT_CALL(*decoder_filter_, transportBegin()).WillOnce(Invoke([&]() -> Network::FilterStatus { - return Network::FilterStatus::StopIteration; - })); + EXPECT_CALL(*decoder_filter_, onMessageDecoded(_, _)).Times(0); DubboFilters::DecoderFilterCallbacks* callbacks{}; EXPECT_CALL(*decoder_filter_, setDecoderFilterCallbacks(_)) @@ -1076,9 +1022,7 @@ TEST_F(ConnectionManagerTest, NeedMoreDataForHandleResponse) { writePartialHessianRequestMessage(write_buffer_, false, false, 0x0F, true); - DubboProtocolImpl protocol; - HessianDeserializerImpl deserializer; - callbacks->startUpstreamResponse(deserializer, protocol); + callbacks->startUpstreamResponse(); EXPECT_EQ(DubboFilters::UpstreamResponseStatus::MoreData, callbacks->upstreamData(write_buffer_)); } @@ -1091,9 +1035,9 @@ TEST_F(ConnectionManagerTest, PendingMessageEnd) { DubboFilters::DecoderFilterCallbacks* callbacks{}; EXPECT_CALL(*decoder_filter_, setDecoderFilterCallbacks(_)) .WillOnce(Invoke([&](DubboFilters::DecoderFilterCallbacks& cb) -> void { callbacks = &cb; })); - EXPECT_CALL(*decoder_filter_, messageEnd(_)) - .WillOnce(Invoke([&](MessageMetadataSharedPtr) -> Network::FilterStatus { - return Network::FilterStatus::StopIteration; + EXPECT_CALL(*decoder_filter_, onMessageDecoded(_, _)) + .WillOnce(Invoke([&](MessageMetadataSharedPtr, ContextSharedPtr) -> FilterStatus { + return FilterStatus::StopIteration; })); EXPECT_EQ(filter_->onData(buffer_, false), Network::FilterStatus::StopIteration); @@ -1124,11 +1068,13 @@ serialization_type: Hessian2 DubboFilters::DecoderFilterCallbacks* callbacks{}; EXPECT_CALL(*decoder_filter_, setDecoderFilterCallbacks(_)) .WillOnce(Invoke([&](DubboFilters::DecoderFilterCallbacks& cb) -> void { callbacks = &cb; })); - EXPECT_CALL(*decoder_filter_, messageEnd(_)) - .WillOnce(Invoke([&](MessageMetadataSharedPtr metadata) -> Network::FilterStatus { - metadata->setServiceName("org.apache.dubbo.demo.DemoService"); - metadata->setMethodName("test"); - return Network::FilterStatus::StopIteration; + EXPECT_CALL(*decoder_filter_, onMessageDecoded(_, _)) + .WillOnce(Invoke([&](MessageMetadataSharedPtr metadata, ContextSharedPtr) -> FilterStatus { + auto invo = static_cast(&metadata->invocation_info()); + auto data = const_cast(invo); + data->setServiceName("org.apache.dubbo.demo.DemoService"); + data->setMethodName("test"); + return FilterStatus::StopIteration; })); EXPECT_EQ(filter_->onData(buffer_, false), Network::FilterStatus::StopIteration); @@ -1153,9 +1099,7 @@ TEST_F(ConnectionManagerTest, TransportEndWithConnectionClose) { writeHessianResponseMessage(write_buffer_, false, 1); - DubboProtocolImpl protocol; - HessianDeserializerImpl deserializer; - callbacks->startUpstreamResponse(deserializer, protocol); + callbacks->startUpstreamResponse(); filter_callbacks_.connection_.close(Network::ConnectionCloseType::FlushWrite); @@ -1163,27 +1107,26 @@ TEST_F(ConnectionManagerTest, TransportEndWithConnectionClose) { EXPECT_EQ(1U, store_.counter("test.response_error_caused_connection_close").value()); } -TEST_F(ConnectionManagerTest, TransportBeginReturnStopIteration) { +TEST_F(ConnectionManagerTest, MessageDecodedReturnStopIteration) { initializeFilter(); DubboFilters::DecoderFilterCallbacks* callbacks{}; EXPECT_CALL(*decoder_filter_, setDecoderFilterCallbacks(_)) .WillOnce(Invoke([&](DubboFilters::DecoderFilterCallbacks& cb) -> void { callbacks = &cb; })); - EXPECT_CALL(*decoder_filter_, transportBegin()).WillOnce(Invoke([&]() -> Network::FilterStatus { - return Network::FilterStatus::StopIteration; - })); - - EXPECT_CALL(*decoder_filter_, messageBegin(_, _, _)).Times(0); - EXPECT_CALL(*decoder_filter_, messageEnd(_)).Times(0); - EXPECT_CALL(*decoder_filter_, transferBodyTo(_, _)).Times(0); - EXPECT_CALL(*decoder_filter_, transportEnd()).Times(0); - // The sendLocalReply is not called and the message type is not oneway, // the ActiveMessage object is not destroyed. EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, deferredDelete_(_)).Times(0); writeHessianRequestMessage(buffer_, false, false, 1); + + size_t buf_size = buffer_.length(); + EXPECT_CALL(*decoder_filter_, onMessageDecoded(_, _)) + .WillOnce(Invoke([&](MessageMetadataSharedPtr, ContextSharedPtr ctx) -> FilterStatus { + EXPECT_EQ(ctx->message_size(), buf_size); + return FilterStatus::StopIteration; + })); + EXPECT_EQ(filter_->onData(buffer_, false), Network::FilterStatus::StopIteration); // Buffer data should be consumed. @@ -1193,7 +1136,7 @@ TEST_F(ConnectionManagerTest, TransportBeginReturnStopIteration) { EXPECT_EQ(0U, store_.counter("test.request").value()); } -TEST_F(ConnectionManagerTest, SendLocalReplyInTransportBegin) { +TEST_F(ConnectionManagerTest, SendLocalReplyInMessageDecoded) { initializeFilter(); DubboFilters::DecoderFilterCallbacks* callbacks{}; @@ -1202,26 +1145,23 @@ TEST_F(ConnectionManagerTest, SendLocalReplyInTransportBegin) { const std::string fake_response("mock dubbo response"); NiceMock direct_response; - EXPECT_CALL(direct_response, encode(_, _, _, _)) - .WillOnce(Invoke([&](MessageMetadata&, Protocol&, Deserializer&, + EXPECT_CALL(direct_response, encode(_, _, _)) + .WillOnce(Invoke([&](MessageMetadata&, Protocol&, Buffer::Instance& buffer) -> DubboFilters::DirectResponse::ResponseType { buffer.add(fake_response); return DubboFilters::DirectResponse::ResponseType::ErrorReply; })); - EXPECT_CALL(*decoder_filter_, transportBegin()).WillOnce(Invoke([&]() -> Network::FilterStatus { - callbacks->sendLocalReply(direct_response, false); - return Network::FilterStatus::StopIteration; - })); - - EXPECT_CALL(*decoder_filter_, messageBegin(_, _, _)).Times(0); - EXPECT_CALL(*decoder_filter_, messageEnd(_)).Times(0); - EXPECT_CALL(*decoder_filter_, transferBodyTo(_, _)).Times(0); - EXPECT_CALL(*decoder_filter_, transportEnd()).Times(0); + EXPECT_CALL(*decoder_filter_, onMessageDecoded(_, _)) + .WillOnce(Invoke([&](MessageMetadataSharedPtr, ContextSharedPtr) -> FilterStatus { + callbacks->sendLocalReply(direct_response, false); + return FilterStatus::StopIteration; + })); // The sendLocalReply is called, the ActiveMessage object should be destroyed. EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, deferredDelete_(_)).Times(1); writeHessianRequestMessage(buffer_, false, false, 1); + EXPECT_EQ(filter_->onData(buffer_, false), Network::FilterStatus::StopIteration); // Buffer data should be consumed. @@ -1231,42 +1171,103 @@ TEST_F(ConnectionManagerTest, SendLocalReplyInTransportBegin) { EXPECT_EQ(1U, store_.counter("test.request").value()); } -TEST_F(ConnectionManagerTest, SendLocalReplyInMessageBegin) { +TEST_F(ConnectionManagerTest, HandleResponseWithEncoderFilter) { + uint64_t request_id = 100; initializeFilter(); + config_->encoder_filter_ = std::make_unique(); + auto mock_encoder_filter = + static_cast(config_->encoder_filter_.get()); + + writeHessianRequestMessage(buffer_, false, false, request_id); DubboFilters::DecoderFilterCallbacks* callbacks{}; EXPECT_CALL(*decoder_filter_, setDecoderFilterCallbacks(_)) .WillOnce(Invoke([&](DubboFilters::DecoderFilterCallbacks& cb) -> void { callbacks = &cb; })); - const std::string fake_response("mock dubbo response"); - NiceMock direct_response; - EXPECT_CALL(direct_response, encode(_, _, _, _)) - .WillOnce(Invoke([&](MessageMetadata&, Protocol&, Deserializer&, - Buffer::Instance& buffer) -> DubboFilters::DirectResponse::ResponseType { - buffer.add(fake_response); - return DubboFilters::DirectResponse::ResponseType::ErrorReply; - })); - EXPECT_CALL(*decoder_filter_, messageBegin(_, _, _)) - .WillOnce(Invoke([&](MessageType, int64_t, SerializationType) -> Network::FilterStatus { - callbacks->sendLocalReply(direct_response, false); - return Network::FilterStatus::StopIteration; - })); + EXPECT_CALL(*mock_encoder_filter, setEncoderFilterCallbacks(_)).Times(1); + + EXPECT_EQ(filter_->onData(buffer_, false), Network::FilterStatus::StopIteration); + EXPECT_EQ(1U, store_.counter("test.request").value()); + EXPECT_EQ(1U, store_.gauge("test.request_active", Stats::Gauge::ImportMode::Accumulate).value()); - EXPECT_CALL(*decoder_filter_, messageEnd(_)).Times(0); - EXPECT_CALL(*decoder_filter_, transferBodyTo(_, _)).Times(0); - EXPECT_CALL(*decoder_filter_, transportEnd()).Times(0); + writeHessianResponseMessage(write_buffer_, false, request_id); + + callbacks->startUpstreamResponse(); + + EXPECT_EQ(callbacks->requestId(), request_id); + EXPECT_EQ(callbacks->connection(), &(filter_callbacks_.connection_)); + EXPECT_GE(callbacks->streamId(), 0); + + size_t expect_response_length = write_buffer_.length(); + EXPECT_CALL(*mock_encoder_filter, onMessageEncoded(_, _)) + .WillOnce( + Invoke([&](MessageMetadataSharedPtr metadata, ContextSharedPtr ctx) -> FilterStatus { + EXPECT_EQ(metadata->request_id(), request_id); + EXPECT_EQ(ctx->message_size(), expect_response_length); + return FilterStatus::Continue; + })); - // The sendLocalReply is called, the ActiveMessage object should be destroyed. EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, deferredDelete_(_)).Times(1); + EXPECT_EQ(DubboFilters::UpstreamResponseStatus::Complete, callbacks->upstreamData(write_buffer_)); - writeHessianRequestMessage(buffer_, false, false, 1); - EXPECT_EQ(filter_->onData(buffer_, false), Network::FilterStatus::StopIteration); + filter_callbacks_.connection_.dispatcher_.clearDeferredDeleteList(); - // Buffer data should be consumed. - EXPECT_EQ(0, buffer_.length()); + EXPECT_EQ(1U, store_.counter("test.response").value()); + EXPECT_EQ(1U, store_.counter("test.response_success").value()); +} - // The finalizeRequest should be called. +TEST_F(ConnectionManagerTest, HandleResponseWithCodecFilter) { + uint64_t request_id = 100; + initializeFilter(); + config_->codec_filter_ = std::make_unique(); + auto mock_codec_filter = + static_cast(config_->codec_filter_.get()); + config_->decoder_filter_.reset(); + decoder_filter_.reset(); + EXPECT_EQ(config_->decoder_filter_.get(), nullptr); + + writeHessianRequestMessage(buffer_, false, false, request_id); + + DubboFilters::DecoderFilterCallbacks* callbacks{}; + EXPECT_CALL(*mock_codec_filter, setDecoderFilterCallbacks(_)) + .WillOnce(Invoke([&](DubboFilters::DecoderFilterCallbacks& cb) -> void { callbacks = &cb; })); + EXPECT_CALL(*mock_codec_filter, onMessageDecoded(_, _)) + .WillOnce(Invoke([&](MessageMetadataSharedPtr metadata, ContextSharedPtr) -> FilterStatus { + EXPECT_EQ(metadata->request_id(), request_id); + return FilterStatus::Continue; + })); + + EXPECT_CALL(*mock_codec_filter, setEncoderFilterCallbacks(_)).Times(1); + + EXPECT_EQ(filter_->onData(buffer_, false), Network::FilterStatus::StopIteration); EXPECT_EQ(1U, store_.counter("test.request").value()); + EXPECT_EQ(1U, store_.gauge("test.request_active", Stats::Gauge::ImportMode::Accumulate).value()); + + writeHessianResponseMessage(write_buffer_, false, request_id); + + callbacks->startUpstreamResponse(); + + EXPECT_EQ(callbacks->requestId(), request_id); + EXPECT_EQ(callbacks->connection(), &(filter_callbacks_.connection_)); + EXPECT_GE(callbacks->streamId(), 0); + + size_t expect_response_length = write_buffer_.length(); + EXPECT_CALL(*mock_codec_filter, onMessageEncoded(_, _)) + .WillOnce( + Invoke([&](MessageMetadataSharedPtr metadata, ContextSharedPtr ctx) -> FilterStatus { + EXPECT_EQ(metadata->request_id(), request_id); + EXPECT_EQ(ctx->message_size(), expect_response_length); + return FilterStatus::Continue; + })); + + EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, deferredDelete_(_)).Times(1); + EXPECT_EQ(DubboFilters::UpstreamResponseStatus::Complete, callbacks->upstreamData(write_buffer_)); + EXPECT_CALL(*mock_codec_filter, onDestroy()).Times(1); + + filter_callbacks_.connection_.dispatcher_.clearDeferredDeleteList(); + + EXPECT_EQ(1U, store_.counter("test.response").value()); + EXPECT_EQ(1U, store_.counter("test.response_success").value()); } } // namespace DubboProxy diff --git a/test/extensions/filters/network/dubbo_proxy/decoder_test.cc b/test/extensions/filters/network/dubbo_proxy/decoder_test.cc index f33943c94100..aade1c594766 100644 --- a/test/extensions/filters/network/dubbo_proxy/decoder_test.cc +++ b/test/extensions/filters/network/dubbo_proxy/decoder_test.cc @@ -1,5 +1,6 @@ #include "extensions/filters/network/dubbo_proxy/decoder.h" -#include "extensions/filters/network/dubbo_proxy/deserializer_impl.h" +#include "extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.h" +#include "extensions/filters/network/dubbo_proxy/message_impl.h" #include "extensions/filters/network/dubbo_proxy/metadata.h" #include "test/extensions/filters/network/dubbo_proxy/mocks.h" @@ -22,33 +23,36 @@ namespace DubboProxy { class DecoderStateMachineTestBase { public: - DecoderStateMachineTestBase() : metadata_(std::make_shared()) { - context_.header_size_ = 16; - } - virtual ~DecoderStateMachineTestBase() = default; + DecoderStateMachineTestBase() = default; + virtual ~DecoderStateMachineTestBase() { active_stream_.reset(); } void initHandler() { - EXPECT_CALL(decoder_callback_, newDecoderEventHandler()) - .WillOnce(Invoke([this]() -> DecoderEventHandler* { return &handler_; })); + ON_CALL(delegate_, newStream(_, _)) + .WillByDefault(Invoke([this](MessageMetadataSharedPtr data, + ContextSharedPtr ctx) -> ActiveStream* { + this->active_stream_ = std::make_shared>(handler_, data, ctx); + return active_stream_.get(); + })); } - void initProtocolDecoder(MessageType type, int32_t body_size, bool is_heartbeat = false) { - EXPECT_CALL(protocol_, decode(_, _, _)) - .WillOnce(Invoke([=](Buffer::Instance&, Protocol::Context* context, - MessageMetadataSharedPtr metadata) -> bool { - context->is_heartbeat_ = is_heartbeat; - context->body_size_ = body_size; - metadata->setMessageType(type); - return true; - })); + void initProtocolDecoder(MessageType type, int32_t body_size) { + ON_CALL(protocol_, decodeHeader(_, _)) + .WillByDefault( + Invoke([=](Buffer::Instance&, + MessageMetadataSharedPtr metadata) -> std::pair { + auto context = std::make_shared(); + context->set_header_size(16); + context->set_body_size(body_size); + metadata->setMessageType(type); + + return std::pair(context, true); + })); } NiceMock protocol_; - NiceMock deserializer_; - NiceMock handler_; - NiceMock decoder_callback_; - MessageMetadataSharedPtr metadata_; - Protocol::Context context_; + NiceMock delegate_; + std::shared_ptr> active_stream_; + NiceMock handler_; }; class DubboDecoderStateMachineTest : public DecoderStateMachineTestBase, public testing::Test {}; @@ -56,166 +60,165 @@ class DubboDecoderStateMachineTest : public DecoderStateMachineTestBase, public class DubboDecoderTest : public testing::Test { public: DubboDecoderTest() = default; - virtual ~DubboDecoderTest() override = default; + ~DubboDecoderTest() override = default; NiceMock protocol_; - NiceMock deserializer_; - NiceMock callbacks_; + NiceMock handler_; + NiceMock request_callbacks_; + NiceMock response_callbacks_; }; TEST_F(DubboDecoderStateMachineTest, EmptyData) { - EXPECT_CALL(protocol_, decode(_, _, _)).Times(1); - EXPECT_CALL(handler_, transferHeaderTo(_, _)).Times(0); - EXPECT_CALL(handler_, messageBegin(_, _, _)).Times(0); + EXPECT_CALL(protocol_, decodeHeader(_, _)).Times(1); + EXPECT_CALL(delegate_, newStream(_, _)).Times(0); + EXPECT_CALL(delegate_, onHeartbeat(_)).Times(0); - DecoderStateMachine dsm(protocol_, deserializer_, metadata_, decoder_callback_); + DecoderStateMachine dsm(protocol_, delegate_); Buffer::OwnedImpl buffer; EXPECT_EQ(dsm.run(buffer), ProtocolState::WaitForData); } TEST_F(DubboDecoderStateMachineTest, OnlyHaveHeaderData) { initHandler(); - initProtocolDecoder(MessageType::Request, 1, false); + initProtocolDecoder(MessageType::Request, 1); - EXPECT_CALL(handler_, transportBegin()).Times(1); - EXPECT_CALL(handler_, transferHeaderTo(_, _)).Times(1); - EXPECT_CALL(handler_, messageBegin(_, _, _)).Times(1); - EXPECT_CALL(handler_, messageEnd(_)).Times(0); + EXPECT_CALL(delegate_, onHeartbeat(_)).Times(0); + EXPECT_CALL(protocol_, decodeData(_, _, _)).WillOnce(Return(false)); Buffer::OwnedImpl buffer; - DecoderStateMachine dsm(protocol_, deserializer_, metadata_, decoder_callback_); + DecoderStateMachine dsm(protocol_, delegate_); EXPECT_EQ(dsm.run(buffer), ProtocolState::WaitForData); } TEST_F(DubboDecoderStateMachineTest, RequestMessageCallbacks) { initHandler(); - initProtocolDecoder(MessageType::Request, 0, false); + initProtocolDecoder(MessageType::Request, 0); - EXPECT_CALL(handler_, transportBegin()).Times(1); - EXPECT_CALL(handler_, transferHeaderTo(_, _)).Times(1); - EXPECT_CALL(handler_, messageBegin(_, _, _)).Times(1); - EXPECT_CALL(handler_, messageEnd(_)).Times(1); - EXPECT_CALL(handler_, transferBodyTo(_, _)).Times(1); - EXPECT_CALL(handler_, transportEnd()).Times(1); + EXPECT_CALL(delegate_, onHeartbeat(_)).Times(0); + EXPECT_CALL(protocol_, decodeData(_, _, _)).WillOnce(Return(true)); + EXPECT_CALL(handler_, onStreamDecoded(_, _)).Times(1); - EXPECT_CALL(deserializer_, deserializeRpcInvocation(_, _, _)).WillOnce(Return()); - - DecoderStateMachine dsm(protocol_, deserializer_, metadata_, decoder_callback_); + DecoderStateMachine dsm(protocol_, delegate_); Buffer::OwnedImpl buffer; EXPECT_EQ(dsm.run(buffer), ProtocolState::Done); + + EXPECT_EQ(active_stream_->metadata_->message_type(), MessageType::Request); } TEST_F(DubboDecoderStateMachineTest, ResponseMessageCallbacks) { initHandler(); - initProtocolDecoder(MessageType::Response, 0, false); - - EXPECT_CALL(handler_, transportBegin()).Times(1); - EXPECT_CALL(handler_, transferHeaderTo(_, _)).Times(1); - EXPECT_CALL(handler_, messageBegin(_, _, _)).Times(1); - EXPECT_CALL(handler_, messageEnd(_)).Times(1); - EXPECT_CALL(handler_, transferBodyTo(_, _)).Times(1); - EXPECT_CALL(handler_, transportEnd()).Times(1); - - EXPECT_CALL(deserializer_, deserializeRpcResult(_, _)) - .WillOnce(Invoke([](Buffer::Instance&, size_t) -> RpcResultPtr { - return std::make_unique(false); - })); + initProtocolDecoder(MessageType::Response, 0); + + EXPECT_CALL(delegate_, onHeartbeat(_)).Times(0); + EXPECT_CALL(protocol_, decodeData(_, _, _)).WillOnce(Return(true)); + EXPECT_CALL(handler_, onStreamDecoded(_, _)).Times(1); - DecoderStateMachine dsm(protocol_, deserializer_, metadata_, decoder_callback_); + DecoderStateMachine dsm(protocol_, delegate_); Buffer::OwnedImpl buffer; EXPECT_EQ(dsm.run(buffer), ProtocolState::Done); + + EXPECT_EQ(active_stream_->metadata_->message_type(), MessageType::Response); } -TEST_F(DubboDecoderStateMachineTest, DeserializeRpcInvocationException) { +TEST_F(DubboDecoderStateMachineTest, SerializeRpcInvocationException) { initHandler(); - initProtocolDecoder(MessageType::Request, 0, false); + initProtocolDecoder(MessageType::Request, 0); - EXPECT_CALL(handler_, messageEnd(_)).Times(0); - EXPECT_CALL(handler_, transferBodyTo(_, _)).Times(0); - EXPECT_CALL(handler_, transportEnd()).Times(0); + EXPECT_CALL(delegate_, newStream(_, _)).Times(1); + EXPECT_CALL(delegate_, onHeartbeat(_)).Times(0); + EXPECT_CALL(handler_, onStreamDecoded(_, _)).Times(0); - EXPECT_CALL(deserializer_, deserializeRpcInvocation(_, _, _)) - .WillOnce(Invoke([](Buffer::Instance&, int32_t, MessageMetadataSharedPtr) -> void { - throw EnvoyException(fmt::format("mock deserialize exception")); + EXPECT_CALL(protocol_, decodeData(_, _, _)) + .WillOnce(Invoke([&](Buffer::Instance&, ContextSharedPtr, MessageMetadataSharedPtr) -> bool { + throw EnvoyException(fmt::format("mock serialize exception")); })); - DecoderStateMachine dsm(protocol_, deserializer_, metadata_, decoder_callback_); + DecoderStateMachine dsm(protocol_, delegate_); Buffer::OwnedImpl buffer; - EXPECT_THROW_WITH_MESSAGE(dsm.run(buffer), EnvoyException, "mock deserialize exception"); - EXPECT_EQ(dsm.currentState(), ProtocolState::OnMessageEnd); + EXPECT_THROW_WITH_MESSAGE(dsm.run(buffer), EnvoyException, "mock serialize exception"); + EXPECT_EQ(dsm.currentState(), ProtocolState::OnDecodeStreamData); } -TEST_F(DubboDecoderStateMachineTest, DeserializeRpcResultException) { +TEST_F(DubboDecoderStateMachineTest, SerializeRpcResultException) { initHandler(); - initProtocolDecoder(MessageType::Response, 0, false); + initProtocolDecoder(MessageType::Response, 0); - EXPECT_CALL(handler_, messageEnd(_)).Times(0); - EXPECT_CALL(handler_, transferBodyTo(_, _)).Times(0); - EXPECT_CALL(handler_, transportEnd()).Times(0); + EXPECT_CALL(delegate_, newStream(_, _)).Times(1); + EXPECT_CALL(delegate_, onHeartbeat(_)).Times(0); + EXPECT_CALL(handler_, onStreamDecoded(_, _)).Times(0); - EXPECT_CALL(deserializer_, deserializeRpcResult(_, _)) - .WillOnce(Invoke([](Buffer::Instance&, size_t) -> RpcResultPtr { - throw EnvoyException(fmt::format("mock deserialize exception")); + EXPECT_CALL(protocol_, decodeData(_, _, _)) + .WillOnce(Invoke([&](Buffer::Instance&, ContextSharedPtr, MessageMetadataSharedPtr) -> bool { + throw EnvoyException(fmt::format("mock serialize exception")); })); - DecoderStateMachine dsm(protocol_, deserializer_, metadata_, decoder_callback_); + DecoderStateMachine dsm(protocol_, delegate_); Buffer::OwnedImpl buffer; - EXPECT_THROW_WITH_MESSAGE(dsm.run(buffer), EnvoyException, "mock deserialize exception"); - EXPECT_EQ(dsm.currentState(), ProtocolState::OnMessageEnd); + EXPECT_THROW_WITH_MESSAGE(dsm.run(buffer), EnvoyException, "mock serialize exception"); + EXPECT_EQ(dsm.currentState(), ProtocolState::OnDecodeStreamData); } TEST_F(DubboDecoderStateMachineTest, ProtocolDecodeException) { - EXPECT_CALL(decoder_callback_, newDecoderEventHandler()).Times(0); - EXPECT_CALL(protocol_, decode(_, _, _)) - .WillOnce(Invoke([](Buffer::Instance&, Protocol::Context*, MessageMetadataSharedPtr) -> bool { - throw EnvoyException(fmt::format("mock deserialize exception")); - })); + EXPECT_CALL(delegate_, newStream(_, _)).Times(0); + EXPECT_CALL(protocol_, decodeHeader(_, _)) + .WillOnce(Invoke( + [](Buffer::Instance&, MessageMetadataSharedPtr) -> std::pair { + throw EnvoyException(fmt::format("mock protocol decode exception")); + })); - DecoderStateMachine dsm(protocol_, deserializer_, metadata_, decoder_callback_); + DecoderStateMachine dsm(protocol_, delegate_); Buffer::OwnedImpl buffer; - EXPECT_THROW_WITH_MESSAGE(dsm.run(buffer), EnvoyException, "mock deserialize exception"); - EXPECT_EQ(dsm.currentState(), ProtocolState::OnTransportBegin); + EXPECT_THROW_WITH_MESSAGE(dsm.run(buffer), EnvoyException, "mock protocol decode exception"); + EXPECT_EQ(dsm.currentState(), ProtocolState::OnDecodeStreamHeader); } TEST_F(DubboDecoderTest, NeedMoreDataForProtocolHeader) { - EXPECT_CALL(protocol_, decode(_, _, _)) - .WillOnce(Invoke([](Buffer::Instance&, Protocol::Context*, MessageMetadataSharedPtr) -> bool { - return false; - })); - EXPECT_CALL(callbacks_, newDecoderEventHandler()).Times(0); + EXPECT_CALL(request_callbacks_, newStream()).Times(0); + EXPECT_CALL(protocol_, decodeHeader(_, _)) + .WillOnce(Invoke( + [](Buffer::Instance&, MessageMetadataSharedPtr) -> std::pair { + return std::pair(nullptr, false); + })); - Decoder decoder(protocol_, deserializer_, callbacks_); + RequestDecoder decoder(protocol_, request_callbacks_); Buffer::OwnedImpl buffer; bool buffer_underflow; - EXPECT_EQ(decoder.onData(buffer, buffer_underflow), Network::FilterStatus::Continue); + EXPECT_EQ(decoder.onData(buffer, buffer_underflow), FilterStatus::Continue); EXPECT_EQ(buffer_underflow, true); } TEST_F(DubboDecoderTest, NeedMoreDataForProtocolBody) { - EXPECT_CALL(protocol_, decode(_, _, _)) - .WillOnce(Invoke([](Buffer::Instance&, Protocol::Context* context, - MessageMetadataSharedPtr metadata) -> bool { - metadata->setMessageType(MessageType::Request); - context->body_size_ = 10; - return true; + EXPECT_CALL(protocol_, decodeHeader(_, _)) + .WillOnce(Invoke([](Buffer::Instance&, + MessageMetadataSharedPtr metadate) -> std::pair { + metadate->setMessageType(MessageType::Response); + auto context = std::make_shared(); + context->set_header_size(16); + context->set_body_size(10); + return std::pair(context, true); })); - EXPECT_CALL(callbacks_, newDecoderEventHandler()).Times(1); - EXPECT_CALL(callbacks_.handler_, transportBegin()).Times(1); - EXPECT_CALL(callbacks_.handler_, transferHeaderTo(_, _)).Times(1); - EXPECT_CALL(callbacks_.handler_, messageBegin(_, _, _)).Times(1); - EXPECT_CALL(callbacks_.handler_, messageEnd(_)).Times(0); - EXPECT_CALL(callbacks_.handler_, transferBodyTo(_, _)).Times(0); - EXPECT_CALL(callbacks_.handler_, transportEnd()).Times(0); + EXPECT_CALL(protocol_, decodeData(_, _, _)) + .WillOnce(Invoke([&](Buffer::Instance&, ContextSharedPtr, MessageMetadataSharedPtr) -> bool { + return false; + })); + + std::shared_ptr> active_stream; - Decoder decoder(protocol_, deserializer_, callbacks_); + EXPECT_CALL(response_callbacks_, newStream()).WillOnce(Invoke([this]() -> StreamHandler& { + return handler_; + })); + EXPECT_CALL(response_callbacks_, onHeartbeat(_)).Times(0); + EXPECT_CALL(handler_, onStreamDecoded(_, _)).Times(0); + + ResponseDecoder decoder(protocol_, response_callbacks_); Buffer::OwnedImpl buffer; bool buffer_underflow; - EXPECT_EQ(decoder.onData(buffer, buffer_underflow), Network::FilterStatus::Continue); + EXPECT_EQ(decoder.onData(buffer, buffer_underflow), FilterStatus::Continue); EXPECT_EQ(buffer_underflow, true); } @@ -223,30 +226,31 @@ TEST_F(DubboDecoderTest, decodeResponseMessage) { Buffer::OwnedImpl buffer; buffer.add(std::string({'\xda', '\xbb', '\xc2', 0x00})); - EXPECT_CALL(protocol_, decode(_, _, _)) - .WillOnce(Invoke([&](Buffer::Instance&, Protocol::Context* context, - MessageMetadataSharedPtr metadata) -> bool { - metadata->setMessageType(MessageType::Response); - context->body_size_ = buffer.length(); - return true; + EXPECT_CALL(protocol_, decodeHeader(_, _)) + .WillOnce(Invoke([](Buffer::Instance&, + MessageMetadataSharedPtr metadate) -> std::pair { + metadate->setMessageType(MessageType::Response); + auto context = std::make_shared(); + context->set_header_size(16); + context->set_body_size(10); + return std::pair(context, true); })); - EXPECT_CALL(deserializer_, deserializeRpcResult(_, _)) - .WillOnce(Invoke([](Buffer::Instance&, size_t) -> RpcResultPtr { - return std::make_unique(true); + EXPECT_CALL(protocol_, decodeData(_, _, _)) + .WillOnce(Invoke([&](Buffer::Instance&, ContextSharedPtr, MessageMetadataSharedPtr) -> bool { + return true; })); - EXPECT_CALL(callbacks_, newDecoderEventHandler()).Times(1); - EXPECT_CALL(callbacks_.handler_, transportBegin()).Times(1); - EXPECT_CALL(callbacks_.handler_, transferHeaderTo(_, _)).Times(1); - EXPECT_CALL(callbacks_.handler_, messageBegin(_, _, _)).Times(1); - EXPECT_CALL(callbacks_.handler_, messageEnd(_)).Times(1); - EXPECT_CALL(callbacks_.handler_, transferBodyTo(_, _)).Times(1); - EXPECT_CALL(callbacks_.handler_, transportEnd()).Times(1); - Decoder decoder(protocol_, deserializer_, callbacks_); + EXPECT_CALL(response_callbacks_, newStream()).WillOnce(Invoke([this]() -> StreamHandler& { + return handler_; + })); + EXPECT_CALL(response_callbacks_, onHeartbeat(_)).Times(0); + EXPECT_CALL(handler_, onStreamDecoded(_, _)).Times(1); + + ResponseDecoder decoder(protocol_, response_callbacks_); bool buffer_underflow; - EXPECT_EQ(decoder.onData(buffer, buffer_underflow), Network::FilterStatus::Continue); - EXPECT_EQ(buffer_underflow, false); + EXPECT_EQ(decoder.onData(buffer, buffer_underflow), FilterStatus::Continue); + EXPECT_EQ(buffer_underflow, true); } } // namespace DubboProxy diff --git a/test/extensions/filters/network/dubbo_proxy/hessian_deserializer_impl_test.cc b/test/extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl_test.cc similarity index 56% rename from test/extensions/filters/network/dubbo_proxy/hessian_deserializer_impl_test.cc rename to test/extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl_test.cc index 38a66a6ffdbf..3a74b52b3f89 100644 --- a/test/extensions/filters/network/dubbo_proxy/hessian_deserializer_impl_test.cc +++ b/test/extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl_test.cc @@ -1,5 +1,6 @@ -#include "extensions/filters/network/dubbo_proxy/hessian_deserializer_impl.h" +#include "extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.h" #include "extensions/filters/network/dubbo_proxy/hessian_utils.h" +#include "extensions/filters/network/dubbo_proxy/message_impl.h" #include "test/extensions/filters/network/dubbo_proxy/mocks.h" #include "test/extensions/filters/network/dubbo_proxy/utility.h" @@ -17,12 +18,12 @@ namespace NetworkFilters { namespace DubboProxy { TEST(HessianProtocolTest, Name) { - HessianDeserializerImpl deserializer; - EXPECT_EQ(deserializer.name(), "hessian"); + DubboHessian2SerializerImpl serializer; + EXPECT_EQ(serializer.name(), "dubbo.hessian2"); } TEST(HessianProtocolTest, deserializeRpcInvocation) { - HessianDeserializerImpl deserializer; + DubboHessian2SerializerImpl serializer; { Buffer::OwnedImpl buffer; @@ -32,11 +33,15 @@ TEST(HessianProtocolTest, deserializeRpcInvocation) { 0x05, '0', '.', '0', '.', '0', // Service version 0x04, 't', 'e', 's', 't', // method name })); - MessageMetadataSharedPtr metadata = std::make_shared(); - deserializer.deserializeRpcInvocation(buffer, buffer.length(), metadata); - EXPECT_STREQ("test", metadata->method_name().value().c_str()); - EXPECT_STREQ("test", metadata->service_name().c_str()); - EXPECT_STREQ("0.0.0", metadata->service_version().value().c_str()); + std::shared_ptr context = std::make_shared(); + context->set_body_size(buffer.length()); + auto result = serializer.deserializeRpcInvocation(buffer, context); + EXPECT_TRUE(result.second); + + auto invo = result.first; + EXPECT_STREQ("test", invo->method_name().c_str()); + EXPECT_STREQ("test", invo->service_name().c_str()); + EXPECT_STREQ("0.0.0", invo->service_version().value().c_str()); } // incorrect body size @@ -50,15 +55,16 @@ TEST(HessianProtocolTest, deserializeRpcInvocation) { })); std::string exception_string = fmt::format("RpcInvocation size({}) large than body size({})", buffer.length(), buffer.length() - 1); - MessageMetadataSharedPtr metadata = std::make_shared(); - EXPECT_THROW_WITH_MESSAGE( - deserializer.deserializeRpcInvocation(buffer, buffer.length() - 1, metadata), - EnvoyException, exception_string); + std::shared_ptr context = std::make_shared(); + context->set_body_size(buffer.length() - 1); + EXPECT_THROW_WITH_MESSAGE(serializer.deserializeRpcInvocation(buffer, context), EnvoyException, + exception_string); } } TEST(HessianProtocolTest, deserializeRpcResult) { - HessianDeserializerImpl deserializer; + DubboHessian2SerializerImpl serializer; + std::shared_ptr context = std::make_shared(); { Buffer::OwnedImpl buffer; @@ -66,8 +72,10 @@ TEST(HessianProtocolTest, deserializeRpcResult) { '\x94', // return type 0x04, 't', 'e', 's', 't', // return body })); - auto result = deserializer.deserializeRpcResult(buffer, 4); - EXPECT_FALSE(result->hasException()); + context->set_body_size(4); + auto result = serializer.deserializeRpcResult(buffer, context); + EXPECT_TRUE(result.second); + EXPECT_FALSE(result.first->hasException()); } { @@ -76,8 +84,10 @@ TEST(HessianProtocolTest, deserializeRpcResult) { '\x93', // return type 0x04, 't', 'e', 's', 't', // return body })); - auto result = deserializer.deserializeRpcResult(buffer, 4); - EXPECT_TRUE(result->hasException()); + context->set_body_size(4); + auto result = serializer.deserializeRpcResult(buffer, context); + EXPECT_TRUE(result.second); + EXPECT_TRUE(result.first->hasException()); } { @@ -86,8 +96,10 @@ TEST(HessianProtocolTest, deserializeRpcResult) { '\x90', // return type 0x04, 't', 'e', 's', 't', // return body })); - auto result = deserializer.deserializeRpcResult(buffer, 4); - EXPECT_TRUE(result->hasException()); + context->set_body_size(4); + auto result = serializer.deserializeRpcResult(buffer, context); + EXPECT_TRUE(result.second); + EXPECT_TRUE(result.first->hasException()); } { @@ -96,8 +108,10 @@ TEST(HessianProtocolTest, deserializeRpcResult) { '\x91', // return type 0x04, 't', 'e', 's', 't', // return body })); - auto result = deserializer.deserializeRpcResult(buffer, 4); - EXPECT_TRUE(result->hasException()); + context->set_body_size(4); + auto result = serializer.deserializeRpcResult(buffer, context); + EXPECT_TRUE(result.second); + EXPECT_TRUE(result.first->hasException()); } // incorrect body size @@ -107,7 +121,8 @@ TEST(HessianProtocolTest, deserializeRpcResult) { '\x94', // return type 0x05, 't', 'e', 's', 't', // return body })); - EXPECT_THROW_WITH_MESSAGE(deserializer.deserializeRpcResult(buffer, 0), EnvoyException, + context->set_body_size(0); + EXPECT_THROW_WITH_MESSAGE(serializer.deserializeRpcResult(buffer, context), EnvoyException, "RpcResult size(1) large than body size(0)"); } @@ -118,8 +133,9 @@ TEST(HessianProtocolTest, deserializeRpcResult) { '\x96', // incorrect return type 0x05, 't', 'e', 's', 't', // return body })); - EXPECT_THROW_WITH_MESSAGE(deserializer.deserializeRpcResult(buffer, buffer.length()), - EnvoyException, "not supported return type 6"); + context->set_body_size(buffer.length()); + EXPECT_THROW_WITH_MESSAGE(serializer.deserializeRpcResult(buffer, context), EnvoyException, + "not supported return type 6"); } // incorrect value size @@ -132,25 +148,27 @@ TEST(HessianProtocolTest, deserializeRpcResult) { std::string exception_string = fmt::format("RpcResult is no value, but the rest of the body size({}) not equal 0", buffer.length() - 1); - EXPECT_THROW_WITH_MESSAGE(deserializer.deserializeRpcResult(buffer, buffer.length()), - EnvoyException, exception_string); + context->set_body_size(buffer.length()); + EXPECT_THROW_WITH_MESSAGE(serializer.deserializeRpcResult(buffer, context), EnvoyException, + exception_string); } } TEST(HessianProtocolTest, HessianDeserializerConfigFactory) { - auto deserializer = - NamedDeserializerConfigFactory::getFactory(SerializationType::Hessian).createDeserializer(); - EXPECT_EQ(deserializer->name(), "hessian"); - EXPECT_EQ(deserializer->type(), SerializationType::Hessian); + auto serializer = + NamedSerializerConfigFactory::getFactory(ProtocolType::Dubbo, SerializationType::Hessian2) + .createSerializer(); + EXPECT_EQ(serializer->name(), "dubbo.hessian2"); + EXPECT_EQ(serializer->type(), SerializationType::Hessian2); } TEST(HessianProtocolTest, serializeRpcResult) { Buffer::OwnedImpl buffer; std::string mock_response("invalid method name 'Add'"); RpcResponseType mock_response_type = RpcResponseType::ResponseWithException; - HessianDeserializerImpl deserializer; + DubboHessian2SerializerImpl serializer; - deserializer.serializeRpcResult(buffer, mock_response, mock_response_type); + EXPECT_NE(serializer.serializeRpcResult(buffer, mock_response, mock_response_type), 0); size_t hessian_int_size; int type_value = HessianUtils::peekInt(buffer, &hessian_int_size); @@ -163,8 +181,10 @@ TEST(HessianProtocolTest, serializeRpcResult) { EXPECT_EQ(buffer.length(), hessian_int_size + hessian_string_size); size_t body_size = mock_response.size() + sizeof(mock_response_type); - auto result = deserializer.deserializeRpcResult(buffer, body_size); - EXPECT_TRUE(result->hasException()); + std::shared_ptr context = std::make_shared(); + context->set_body_size(body_size); + auto result = serializer.deserializeRpcResult(buffer, context); + EXPECT_TRUE(result.first->hasException()); } } // namespace DubboProxy diff --git a/test/extensions/filters/network/dubbo_proxy/dubbo_protocol_impl_test.cc b/test/extensions/filters/network/dubbo_proxy/dubbo_protocol_impl_test.cc index f98cb0dee33c..3ee19707380a 100644 --- a/test/extensions/filters/network/dubbo_proxy/dubbo_protocol_impl_test.cc +++ b/test/extensions/filters/network/dubbo_proxy/dubbo_protocol_impl_test.cc @@ -19,11 +19,13 @@ using testing::StrictMock; TEST(DubboProtocolImplTest, NotEnoughData) { Buffer::OwnedImpl buffer; DubboProtocolImpl dubbo_protocol; - Protocol::Context context; MessageMetadataSharedPtr metadata = std::make_shared(); - EXPECT_FALSE(dubbo_protocol.decode(buffer, &context, metadata)); + auto result = dubbo_protocol.decodeHeader(buffer, metadata); + EXPECT_FALSE(result.second); + buffer.add(std::string(15, 0x00)); - EXPECT_FALSE(dubbo_protocol.decode(buffer, &context, metadata)); + result = dubbo_protocol.decodeHeader(buffer, metadata); + EXPECT_FALSE(result.second); } TEST(DubboProtocolImplTest, Name) { @@ -36,37 +38,37 @@ TEST(DubboProtocolImplTest, Normal) { // Normal dubbo request message { Buffer::OwnedImpl buffer; - Protocol::Context context; MessageMetadataSharedPtr metadata = std::make_shared(); buffer.add(std::string({'\xda', '\xbb', '\xc2', 0x00})); addInt64(buffer, 1); addInt32(buffer, 1); - EXPECT_TRUE(dubbo_protocol.decode(buffer, &context, metadata)); + + auto result = dubbo_protocol.decodeHeader(buffer, metadata); + auto context = result.first; + EXPECT_TRUE(result.second); EXPECT_EQ(1, metadata->request_id()); - EXPECT_EQ(1, context.body_size_); - EXPECT_EQ(false, context.is_heartbeat_); + EXPECT_EQ(1, context->body_size()); EXPECT_EQ(MessageType::Request, metadata->message_type()); } // Normal dubbo response message { Buffer::OwnedImpl buffer; - Protocol::Context context; MessageMetadataSharedPtr metadata = std::make_shared(); buffer.add(std::string({'\xda', '\xbb', 0x42, 20})); addInt64(buffer, 1); addInt32(buffer, 1); - EXPECT_TRUE(dubbo_protocol.decode(buffer, &context, metadata)); + auto result = dubbo_protocol.decodeHeader(buffer, metadata); + auto context = result.first; + EXPECT_TRUE(result.second); EXPECT_EQ(1, metadata->request_id()); - EXPECT_EQ(1, context.body_size_); - EXPECT_EQ(false, context.is_heartbeat_); + EXPECT_EQ(1, context->body_size()); EXPECT_EQ(MessageType::Response, metadata->message_type()); } } TEST(DubboProtocolImplTest, InvalidProtocol) { DubboProtocolImpl dubbo_protocol; - Protocol::Context context; MessageMetadataSharedPtr metadata = std::make_shared(); // Invalid dubbo magic number @@ -74,7 +76,7 @@ TEST(DubboProtocolImplTest, InvalidProtocol) { Buffer::OwnedImpl buffer; addInt64(buffer, 0); addInt64(buffer, 0); - EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decode(buffer, &context, metadata), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decodeHeader(buffer, metadata), EnvoyException, "invalid dubbo message magic number 0"); } @@ -86,7 +88,7 @@ TEST(DubboProtocolImplTest, InvalidProtocol) { addInt32(buffer, DubboProtocolImpl::MaxBodySize + 1); std::string exception_string = fmt::format("invalid dubbo message size {}", DubboProtocolImpl::MaxBodySize + 1); - EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decode(buffer, &context, metadata), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decodeHeader(buffer, metadata), EnvoyException, exception_string); } @@ -96,7 +98,7 @@ TEST(DubboProtocolImplTest, InvalidProtocol) { buffer.add(std::string({'\xda', '\xbb', '\xc3', 0x00})); addInt64(buffer, 1); addInt32(buffer, 0xff); - EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decode(buffer, &context, metadata), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decodeHeader(buffer, metadata), EnvoyException, "invalid dubbo message serialization type 3"); } @@ -106,60 +108,70 @@ TEST(DubboProtocolImplTest, InvalidProtocol) { buffer.add(std::string({'\xda', '\xbb', 0x42, 0x00})); addInt64(buffer, 1); addInt32(buffer, 0xff); - EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decode(buffer, &context, metadata), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decodeHeader(buffer, metadata), EnvoyException, "invalid dubbo message response status 0"); } } TEST(DubboProtocolImplTest, DubboProtocolConfigFactory) { - auto protocol = NamedProtocolConfigFactory::getFactory(ProtocolType::Dubbo).createProtocol(); + auto protocol = NamedProtocolConfigFactory::getFactory(ProtocolType::Dubbo) + .createProtocol(SerializationType::Hessian2); EXPECT_EQ(protocol->name(), "dubbo"); EXPECT_EQ(protocol->type(), ProtocolType::Dubbo); + EXPECT_EQ(protocol->serializer()->type(), SerializationType::Hessian2); } TEST(DubboProtocolImplTest, encode) { MessageMetadata metadata; metadata.setMessageType(MessageType::Response); metadata.setResponseStatus(ResponseStatus::ServiceNotFound); - metadata.setSerializationType(SerializationType::Hessian); + metadata.setSerializationType(SerializationType::Hessian2); metadata.setRequestId(100); Buffer::OwnedImpl buffer; DubboProtocolImpl dubbo_protocol; - int32_t expect_body_size = 100; - EXPECT_TRUE(dubbo_protocol.encode(buffer, expect_body_size, metadata)); + dubbo_protocol.initSerializer(SerializationType::Hessian2); + std::string content("this is test data"); + EXPECT_TRUE(dubbo_protocol.encode(buffer, metadata, content, RpcResponseType::ResponseWithValue)); - Protocol::Context context; MessageMetadataSharedPtr output_metadata = std::make_shared(); - EXPECT_TRUE(dubbo_protocol.decode(buffer, &context, output_metadata)); + auto result = dubbo_protocol.decodeHeader(buffer, output_metadata); + EXPECT_TRUE(result.second); EXPECT_EQ(metadata.message_type(), output_metadata->message_type()); - EXPECT_EQ(metadata.response_status().value(), output_metadata->response_status().value()); + EXPECT_EQ(metadata.response_status(), output_metadata->response_status()); EXPECT_EQ(metadata.serialization_type(), output_metadata->serialization_type()); EXPECT_EQ(metadata.request_id(), output_metadata->request_id()); - EXPECT_EQ(context.body_size_, expect_body_size); + + Buffer::OwnedImpl body_buffer; + size_t serialized_body_size = dubbo_protocol.serializer()->serializeRpcResult( + body_buffer, content, RpcResponseType::ResponseWithValue); + auto context = result.first; + EXPECT_EQ(context->body_size(), serialized_body_size); + + buffer.drain(context->header_size()); + EXPECT_TRUE(dubbo_protocol.decodeData(buffer, context, output_metadata)); } TEST(DubboProtocolImplTest, decode) { Buffer::OwnedImpl buffer; MessageMetadataSharedPtr metadata; - Protocol::Context context; DubboProtocolImpl dubbo_protocol; // metadata is nullptr - EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decode(buffer, &context, metadata), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decodeHeader(buffer, metadata), EnvoyException, "invalid metadata parameter"); metadata = std::make_shared(); // Invalid message header size - EXPECT_FALSE(dubbo_protocol.decode(buffer, &context, metadata)); + EXPECT_FALSE(dubbo_protocol.decodeHeader(buffer, metadata).second); // Invalid dubbo magic number { addInt64(buffer, 0); addInt64(buffer, 0); - EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decode(buffer, &context, metadata), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decodeHeader(buffer, metadata), EnvoyException, "invalid dubbo message magic number 0"); buffer.drain(buffer.length()); } @@ -171,7 +183,7 @@ TEST(DubboProtocolImplTest, decode) { addInt32(buffer, DubboProtocolImpl::MaxBodySize + 1); std::string exception_string = fmt::format("invalid dubbo message size {}", DubboProtocolImpl::MaxBodySize + 1); - EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decode(buffer, &context, metadata), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decodeHeader(buffer, metadata), EnvoyException, exception_string); buffer.drain(buffer.length()); } @@ -181,7 +193,7 @@ TEST(DubboProtocolImplTest, decode) { buffer.add(std::string({'\xda', '\xbb', '\xc3', 0x00})); addInt64(buffer, 1); addInt32(buffer, 0xff); - EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decode(buffer, &context, metadata), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decodeHeader(buffer, metadata), EnvoyException, "invalid dubbo message serialization type 3"); buffer.drain(buffer.length()); } @@ -191,38 +203,38 @@ TEST(DubboProtocolImplTest, decode) { buffer.add(std::string({'\xda', '\xbb', 0x42, 0x00})); addInt64(buffer, 1); addInt32(buffer, 0xff); - EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decode(buffer, &context, metadata), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(dubbo_protocol.decodeHeader(buffer, metadata), EnvoyException, "invalid dubbo message response status 0"); buffer.drain(buffer.length()); } // The dubbo request message { - Protocol::Context context; buffer.add(std::string({'\xda', '\xbb', '\xc2', 0x00})); addInt64(buffer, 1); addInt32(buffer, 1); - EXPECT_TRUE(dubbo_protocol.decode(buffer, &context, metadata)); - EXPECT_EQ(1, context.body_size_); - EXPECT_FALSE(context.is_heartbeat_); + auto result = dubbo_protocol.decodeHeader(buffer, metadata); + EXPECT_TRUE(result.second); + auto context = result.first; + EXPECT_EQ(1, context->body_size()); EXPECT_EQ(MessageType::Request, metadata->message_type()); EXPECT_EQ(1, metadata->request_id()); - EXPECT_EQ(SerializationType::Hessian, metadata->serialization_type()); + EXPECT_EQ(SerializationType::Hessian2, metadata->serialization_type()); buffer.drain(buffer.length()); } // The One-way dubbo request message { - Protocol::Context context; buffer.add(std::string({'\xda', '\xbb', '\x82', 0x00})); addInt64(buffer, 1); addInt32(buffer, 1); - EXPECT_TRUE(dubbo_protocol.decode(buffer, &context, metadata)); - EXPECT_EQ(1, context.body_size_); - EXPECT_FALSE(context.is_heartbeat_); + auto result = dubbo_protocol.decodeHeader(buffer, metadata); + EXPECT_TRUE(result.second); + auto context = result.first; + EXPECT_EQ(1, context->body_size()); EXPECT_EQ(MessageType::Oneway, metadata->message_type()); EXPECT_EQ(1, metadata->request_id()); - EXPECT_EQ(SerializationType::Hessian, metadata->serialization_type()); + EXPECT_EQ(SerializationType::Hessian2, metadata->serialization_type()); } } diff --git a/test/extensions/filters/network/dubbo_proxy/metadata_test.cc b/test/extensions/filters/network/dubbo_proxy/metadata_test.cc index f89179cd637c..ab94547762f7 100644 --- a/test/extensions/filters/network/dubbo_proxy/metadata_test.cc +++ b/test/extensions/filters/network/dubbo_proxy/metadata_test.cc @@ -1,4 +1,6 @@ +#include "extensions/filters/network/dubbo_proxy/message_impl.h" #include "extensions/filters/network/dubbo_proxy/metadata.h" +#include "extensions/filters/network/dubbo_proxy/serializer_impl.h" #include "gtest/gtest.h" @@ -9,43 +11,51 @@ namespace DubboProxy { TEST(MessageMetadataTest, Fields) { MessageMetadata metadata; + auto invo = std::make_shared(); - EXPECT_FALSE(metadata.method_name().has_value()); - EXPECT_THROW(metadata.method_name().value(), absl::bad_optional_access); - metadata.setMethodName("method"); - EXPECT_TRUE(metadata.method_name().has_value()); - EXPECT_EQ("method", metadata.method_name()); - - EXPECT_FALSE(metadata.service_version().has_value()); - EXPECT_THROW(metadata.service_version().value(), absl::bad_optional_access); - metadata.setServiceVersion("1.0.0"); - EXPECT_TRUE(metadata.service_version().has_value()); - EXPECT_EQ("1.0.0", metadata.service_version().value()); - - EXPECT_FALSE(metadata.service_group().has_value()); - EXPECT_THROW(metadata.service_group().value(), absl::bad_optional_access); - metadata.setServiceGroup("group"); - EXPECT_TRUE(metadata.service_group().has_value()); - EXPECT_EQ("group", metadata.service_group().value()); + EXPECT_FALSE(metadata.hasInvocationInfo()); + metadata.setInvocationInfo(invo); + EXPECT_TRUE(metadata.hasInvocationInfo()); + + EXPECT_THROW(metadata.timeout().value(), absl::bad_optional_access); + metadata.setTimeout(3); + EXPECT_TRUE(metadata.timeout().has_value()); + + invo->setMethodName("method"); + EXPECT_EQ("method", invo->method_name()); + + EXPECT_FALSE(invo->service_version().has_value()); + EXPECT_THROW(invo->service_version().value(), absl::bad_optional_access); + invo->setServiceVersion("1.0.0"); + EXPECT_TRUE(invo->service_version().has_value()); + EXPECT_EQ("1.0.0", invo->service_version().value()); + + EXPECT_FALSE(invo->service_group().has_value()); + EXPECT_THROW(invo->service_group().value(), absl::bad_optional_access); + invo->setServiceGroup("group"); + EXPECT_TRUE(invo->service_group().has_value()); + EXPECT_EQ("group", invo->service_group().value()); } TEST(MessageMetadataTest, Headers) { MessageMetadata metadata; + auto invo = std::make_shared(); - EXPECT_FALSE(metadata.hasHeaders()); - metadata.addHeader("k", "v"); - EXPECT_EQ(metadata.headers().size(), 1); + EXPECT_FALSE(invo->hasHeaders()); + invo->addHeader("k", "v"); + EXPECT_EQ(invo->headers().size(), 1); } TEST(MessageMetadataTest, Parameters) { MessageMetadata metadata; + auto invo = std::make_shared(); - EXPECT_FALSE(metadata.hasParameters()); - metadata.addParameterValue(0, "test"); - EXPECT_TRUE(metadata.hasParameters()); - EXPECT_EQ(metadata.parameters().size(), 1); - EXPECT_EQ(metadata.getParameterValue(0), "test"); - EXPECT_EQ(metadata.getParameterValue(1), ""); + EXPECT_FALSE(invo->hasParameters()); + invo->addParameterValue(0, "test"); + EXPECT_TRUE(invo->hasParameters()); + EXPECT_EQ(invo->parameters().size(), 1); + EXPECT_EQ(invo->getParameterValue(0), "test"); + EXPECT_EQ(invo->getParameterValue(1), ""); } } // namespace DubboProxy diff --git a/test/extensions/filters/network/dubbo_proxy/mocks.cc b/test/extensions/filters/network/dubbo_proxy/mocks.cc index 14a55f348d81..2e93c8eebbc3 100644 --- a/test/extensions/filters/network/dubbo_proxy/mocks.cc +++ b/test/extensions/filters/network/dubbo_proxy/mocks.cc @@ -17,52 +17,41 @@ namespace Extensions { namespace NetworkFilters { namespace DubboProxy { -MockDecoderEventHandler::MockDecoderEventHandler() { - ON_CALL(*this, transportBegin()).WillByDefault(Return(Network::FilterStatus::Continue)); - ON_CALL(*this, transportEnd()).WillByDefault(Return(Network::FilterStatus::Continue)); - ON_CALL(*this, messageBegin(_, _, _)).WillByDefault(Return(Network::FilterStatus::Continue)); - ON_CALL(*this, messageEnd(_)).WillByDefault(Return(Network::FilterStatus::Continue)); - ON_CALL(*this, transferHeaderTo(_, _)).WillByDefault(Return(Network::FilterStatus::Continue)); - ON_CALL(*this, transferBodyTo(_, _)).WillByDefault(Return(Network::FilterStatus::Continue)); +MockStreamDecoder::MockStreamDecoder() { + ON_CALL(*this, onMessageDecoded(_, _)).WillByDefault(Return(FilterStatus::Continue)); } -MockDecoderCallbacks::MockDecoderCallbacks() { - ON_CALL(*this, newDecoderEventHandler()).WillByDefault(Return(&handler_)); +MockStreamEncoder::MockStreamEncoder() { + ON_CALL(*this, onMessageEncoded(_, _)).WillByDefault(Return(FilterStatus::Continue)); +} + +MockRequestDecoderCallbacks::MockRequestDecoderCallbacks() { + ON_CALL(*this, newStream()).WillByDefault(ReturnRef(handler_)); +} + +MockResponseDecoderCallbacks::MockResponseDecoderCallbacks() { + ON_CALL(*this, newStream()).WillByDefault(ReturnRef(handler_)); } MockProtocol::MockProtocol() { ON_CALL(*this, name()).WillByDefault(ReturnRef(name_)); ON_CALL(*this, type()).WillByDefault(Return(type_)); + ON_CALL(*this, serializer()).WillByDefault(Return(&serializer_)); } MockProtocol::~MockProtocol() = default; -MockDeserializer::MockDeserializer() { +MockSerializer::MockSerializer() { ON_CALL(*this, name()).WillByDefault(ReturnRef(name_)); ON_CALL(*this, type()).WillByDefault(Return(type_)); } -MockDeserializer::~MockDeserializer() = default; +MockSerializer::~MockSerializer() = default; namespace DubboFilters { MockFilterChainFactoryCallbacks::MockFilterChainFactoryCallbacks() = default; MockFilterChainFactoryCallbacks::~MockFilterChainFactoryCallbacks() = default; -MockDecoderFilter::MockDecoderFilter() { - ON_CALL(*this, transportBegin()).WillByDefault(Return(Network::FilterStatus::Continue)); - ON_CALL(*this, transportEnd()).WillByDefault(Return(Network::FilterStatus::Continue)); - ON_CALL(*this, messageBegin(_, _, _)).WillByDefault(Return(Network::FilterStatus::Continue)); - ON_CALL(*this, messageEnd(_)).WillByDefault(Return(Network::FilterStatus::Continue)); - ON_CALL(*this, transferHeaderTo(_, _)) - .WillByDefault(Invoke([&](Buffer::Instance& buf, size_t size) -> Network::FilterStatus { - buf.drain(size); - return Network::FilterStatus::Continue; - })); - ON_CALL(*this, transferBodyTo(_, _)) - .WillByDefault(Invoke([&](Buffer::Instance& buf, size_t size) -> Network::FilterStatus { - buf.drain(size); - return Network::FilterStatus::Continue; - })); -} +MockDecoderFilter::MockDecoderFilter() = default; MockDecoderFilter::~MockDecoderFilter() = default; MockDecoderFilterCallbacks::MockDecoderFilterCallbacks() { @@ -72,11 +61,26 @@ MockDecoderFilterCallbacks::MockDecoderFilterCallbacks() { ON_CALL(*this, connection()).WillByDefault(Return(&connection_)); ON_CALL(*this, route()).WillByDefault(Return(route_)); ON_CALL(*this, streamInfo()).WillByDefault(ReturnRef(stream_info_)); + ON_CALL(*this, dispatcher()).WillByDefault(ReturnRef(dispatcher_)); } MockDecoderFilterCallbacks::~MockDecoderFilterCallbacks() = default; -MockDirectResponse::MockDirectResponse() = default; -MockDirectResponse::~MockDirectResponse() = default; +MockEncoderFilter::MockEncoderFilter() = default; +MockEncoderFilter::~MockEncoderFilter() = default; + +MockEncoderFilterCallbacks::MockEncoderFilterCallbacks() { + route_.reset(new NiceMock()); + + ON_CALL(*this, streamId()).WillByDefault(Return(stream_id_)); + ON_CALL(*this, connection()).WillByDefault(Return(&connection_)); + ON_CALL(*this, route()).WillByDefault(Return(route_)); + ON_CALL(*this, streamInfo()).WillByDefault(ReturnRef(stream_info_)); + ON_CALL(*this, dispatcher()).WillByDefault(ReturnRef(dispatcher_)); +} +MockEncoderFilterCallbacks::~MockEncoderFilterCallbacks() = default; + +MockCodecFilter::MockCodecFilter() = default; +MockCodecFilter::~MockCodecFilter() = default; MockFilterConfigFactory::MockFilterConfigFactory() : MockFactoryBase("envoy.filters.dubbo.mock_filter"), diff --git a/test/extensions/filters/network/dubbo_proxy/mocks.h b/test/extensions/filters/network/dubbo_proxy/mocks.h index 4de8c76982ca..02a5176f1485 100644 --- a/test/extensions/filters/network/dubbo_proxy/mocks.h +++ b/test/extensions/filters/network/dubbo_proxy/mocks.h @@ -3,6 +3,7 @@ #include "common/protobuf/protobuf.h" #include "common/protobuf/utility.h" +#include "extensions/filters/network/dubbo_proxy/decoder.h" #include "extensions/filters/network/dubbo_proxy/decoder_event_handler.h" #include "extensions/filters/network/dubbo_proxy/filters/factory_base.h" #include "extensions/filters/network/dubbo_proxy/filters/filter.h" @@ -22,71 +23,129 @@ namespace Extensions { namespace NetworkFilters { namespace DubboProxy { -class MockDecoderEventHandler : public DecoderEventHandler { +class MockStreamDecoder : public StreamDecoder { public: - MockDecoderEventHandler(); + MockStreamDecoder(); - MOCK_METHOD0(transportBegin, Network::FilterStatus()); - MOCK_METHOD0(transportEnd, Network::FilterStatus()); - MOCK_METHOD3(messageBegin, Network::FilterStatus(MessageType, int64_t, SerializationType)); - MOCK_METHOD1(messageEnd, Network::FilterStatus(MessageMetadataSharedPtr)); - MOCK_METHOD2(transferHeaderTo, Network::FilterStatus(Buffer::Instance&, size_t)); - MOCK_METHOD2(transferBodyTo, Network::FilterStatus(Buffer::Instance&, size_t)); + MOCK_METHOD2(onMessageDecoded, FilterStatus(MessageMetadataSharedPtr, ContextSharedPtr)); }; -class MockDecoderCallbacks : public DecoderCallbacks { +class MockStreamEncoder : public StreamEncoder { public: - MockDecoderCallbacks(); - ~MockDecoderCallbacks() = default; + MockStreamEncoder(); - MOCK_METHOD0(newDecoderEventHandler, DecoderEventHandler*()); + MOCK_METHOD2(onMessageEncoded, FilterStatus(MessageMetadataSharedPtr, ContextSharedPtr)); +}; + +class MockStreamHandler : public StreamHandler { +public: + MockStreamHandler() = default; + + MOCK_METHOD2(onStreamDecoded, void(MessageMetadataSharedPtr, ContextSharedPtr)); +}; + +class MockRequestDecoderCallbacks : public RequestDecoderCallbacks { +public: + MockRequestDecoderCallbacks(); + ~MockRequestDecoderCallbacks() override = default; + + MOCK_METHOD0(newStream, StreamHandler&()); MOCK_METHOD1(onHeartbeat, void(MessageMetadataSharedPtr)); - MockDecoderEventHandler handler_; + MockStreamHandler handler_; }; +class MockResponseDecoderCallbacks : public ResponseDecoderCallbacks { +public: + MockResponseDecoderCallbacks(); + ~MockResponseDecoderCallbacks() override = default; -class MockProtocolCallbacks : public ProtocolCallbacks { + MOCK_METHOD0(newStream, StreamHandler&()); + MOCK_METHOD1(onHeartbeat, void(MessageMetadataSharedPtr)); + + MockStreamHandler handler_; +}; + +class MockActiveStream : public ActiveStream { public: - MockProtocolCallbacks() = default; - ~MockProtocolCallbacks() = default; + MockActiveStream(StreamHandler& handler, MessageMetadataSharedPtr metadata, + ContextSharedPtr context) + : ActiveStream(handler, metadata, context) {} + ~MockActiveStream() = default; - void onRequestMessage(RequestMessagePtr&& req) override { onRequestMessageRvr(req.get()); } - void onResponseMessage(ResponseMessagePtr&& res) override { onResponseMessageRvr(res.get()); } + MOCK_METHOD2(newStream, ActiveStream*(MessageMetadataSharedPtr, ContextSharedPtr)); + MOCK_METHOD1(onHeartbeat, void(MessageMetadataSharedPtr)); +}; + +class MockDecoderStateMachineDelegate : public DecoderStateMachine::Delegate { +public: + MockDecoderStateMachineDelegate() = default; + ~MockDecoderStateMachineDelegate() override = default; - // DubboProxy::ProtocolCallbacks - MOCK_METHOD1(onRequestMessageRvr, void(RequestMessage*)); - MOCK_METHOD1(onResponseMessageRvr, void(ResponseMessage*)); + MOCK_METHOD2(newStream, ActiveStream*(MessageMetadataSharedPtr, ContextSharedPtr)); + MOCK_METHOD1(onHeartbeat, void(MessageMetadataSharedPtr)); +}; + +class MockSerializer : public Serializer { +public: + MockSerializer(); + ~MockSerializer() override; + + // DubboProxy::Serializer + MOCK_CONST_METHOD0(name, const std::string&()); + MOCK_CONST_METHOD0(type, SerializationType()); + MOCK_METHOD2(deserializeRpcInvocation, + std::pair(Buffer::Instance&, ContextSharedPtr)); + MOCK_METHOD2(deserializeRpcResult, + std::pair(Buffer::Instance&, ContextSharedPtr)); + MOCK_METHOD3(serializeRpcResult, size_t(Buffer::Instance&, const std::string&, RpcResponseType)); + + std::string name_{"mockDeserializer"}; + SerializationType type_{SerializationType::Hessian2}; }; class MockProtocol : public Protocol { public: MockProtocol(); - ~MockProtocol(); + ~MockProtocol() override; MOCK_CONST_METHOD0(name, const std::string&()); MOCK_CONST_METHOD0(type, ProtocolType()); - MOCK_METHOD2(decode, bool(Buffer::Instance&, Context*)); - MOCK_METHOD3(decode, bool(Buffer::Instance&, Protocol::Context*, MessageMetadataSharedPtr)); - MOCK_METHOD3(encode, bool(Buffer::Instance&, int32_t, const MessageMetadata&)); + MOCK_CONST_METHOD0(serializer, Serializer*()); + MOCK_METHOD2(decodeHeader, + std::pair(Buffer::Instance&, MessageMetadataSharedPtr)); + MOCK_METHOD3(decodeData, bool(Buffer::Instance&, ContextSharedPtr, MessageMetadataSharedPtr)); + MOCK_METHOD4(encode, bool(Buffer::Instance&, const MessageMetadata&, const std::string&, + RpcResponseType)); std::string name_{"MockProtocol"}; ProtocolType type_{ProtocolType::Dubbo}; + NiceMock serializer_; }; -class MockDeserializer : public Deserializer { +class MockNamedSerializerConfigFactory : public NamedSerializerConfigFactory { public: - MockDeserializer(); - ~MockDeserializer(); + MockNamedSerializerConfigFactory(std::function f) : f_(f) {} - // DubboProxy::Deserializer - MOCK_CONST_METHOD0(name, const std::string&()); - MOCK_CONST_METHOD0(type, SerializationType()); - MOCK_METHOD3(deserializeRpcInvocation, void(Buffer::Instance&, size_t, MessageMetadataSharedPtr)); - MOCK_METHOD2(deserializeRpcResult, RpcResultPtr(Buffer::Instance&, size_t)); - MOCK_METHOD3(serializeRpcResult, size_t(Buffer::Instance&, const std::string&, RpcResponseType)); + SerializerPtr createSerializer() override { return SerializerPtr{f_()}; } + std::string name() override { + return SerializerNames::get().fromType(SerializationType::Hessian2); + } - std::string name_{"mockDeserializer"}; - SerializationType type_{SerializationType::Hessian}; + std::function f_; +}; + +class MockNamedProtocolConfigFactory : public NamedProtocolConfigFactory { +public: + MockNamedProtocolConfigFactory(std::function f) : f_(f) {} + + ProtocolPtr createProtocol(SerializationType serialization_type) override { + auto protocol = ProtocolPtr{f_()}; + protocol->initSerializer(serialization_type); + return protocol; + } + std::string name() override { return ProtocolNames::get().fromType(ProtocolType::Dubbo); } + + std::function f_; }; namespace Router { @@ -98,33 +157,28 @@ namespace DubboFilters { class MockFilterChainFactoryCallbacks : public FilterChainFactoryCallbacks { public: MockFilterChainFactoryCallbacks(); - ~MockFilterChainFactoryCallbacks(); + ~MockFilterChainFactoryCallbacks() override; MOCK_METHOD1(addDecoderFilter, void(DecoderFilterSharedPtr)); + MOCK_METHOD1(addEncoderFilter, void(EncoderFilterSharedPtr)); + MOCK_METHOD1(addFilter, void(CodecFilterSharedPtr)); }; class MockDecoderFilter : public DecoderFilter { public: MockDecoderFilter(); - ~MockDecoderFilter(); + ~MockDecoderFilter() override; // DubboProxy::DubboFilters::DecoderFilter MOCK_METHOD0(onDestroy, void()); MOCK_METHOD1(setDecoderFilterCallbacks, void(DecoderFilterCallbacks& callbacks)); - - // DubboProxy::DecoderEventHandler - MOCK_METHOD0(transportBegin, Network::FilterStatus()); - MOCK_METHOD0(transportEnd, Network::FilterStatus()); - MOCK_METHOD3(messageBegin, Network::FilterStatus(MessageType, int64_t, SerializationType)); - MOCK_METHOD1(messageEnd, Network::FilterStatus(MessageMetadataSharedPtr)); - MOCK_METHOD2(transferHeaderTo, Network::FilterStatus(Buffer::Instance& buf, size_t size)); - MOCK_METHOD2(transferBodyTo, Network::FilterStatus(Buffer::Instance& buf, size_t size)); + MOCK_METHOD2(onMessageDecoded, FilterStatus(MessageMetadataSharedPtr, ContextSharedPtr)); }; class MockDecoderFilterCallbacks : public DecoderFilterCallbacks { public: MockDecoderFilterCallbacks(); - ~MockDecoderFilterCallbacks(); + ~MockDecoderFilterCallbacks() override; // DubboProxy::DubboFilters::DecoderFilterCallbacks MOCK_CONST_METHOD0(requestId, uint64_t()); @@ -132,28 +186,78 @@ class MockDecoderFilterCallbacks : public DecoderFilterCallbacks { MOCK_CONST_METHOD0(connection, const Network::Connection*()); MOCK_METHOD0(continueDecoding, void()); MOCK_METHOD0(route, Router::RouteConstSharedPtr()); - MOCK_CONST_METHOD0(downstreamSerializationType, SerializationType()); - MOCK_CONST_METHOD0(downstreamProtocolType, ProtocolType()); + MOCK_CONST_METHOD0(serializationType, SerializationType()); + MOCK_CONST_METHOD0(protocolType, ProtocolType()); MOCK_METHOD2(sendLocalReply, void(const DirectResponse&, bool)); - MOCK_METHOD2(startUpstreamResponse, void(Deserializer&, Protocol&)); + MOCK_METHOD0(startUpstreamResponse, void()); MOCK_METHOD1(upstreamData, UpstreamResponseStatus(Buffer::Instance&)); MOCK_METHOD0(resetDownstreamConnection, void()); MOCK_METHOD0(streamInfo, StreamInfo::StreamInfo&()); MOCK_METHOD0(resetStream, void()); + MOCK_METHOD0(dispatcher, Event::Dispatcher&()); uint64_t stream_id_{1}; NiceMock connection_; NiceMock stream_info_; std::shared_ptr route_; + NiceMock dispatcher_; +}; + +class MockEncoderFilter : public EncoderFilter { +public: + MockEncoderFilter(); + ~MockEncoderFilter() override; + + // DubboProxy::DubboFilters::EncoderFilter + MOCK_METHOD0(onDestroy, void()); + MOCK_METHOD1(setEncoderFilterCallbacks, void(EncoderFilterCallbacks& callbacks)); + MOCK_METHOD2(onMessageEncoded, FilterStatus(MessageMetadataSharedPtr, ContextSharedPtr)); +}; + +class MockEncoderFilterCallbacks : public EncoderFilterCallbacks { +public: + MockEncoderFilterCallbacks(); + ~MockEncoderFilterCallbacks() override; + + // DubboProxy::DubboFilters::MockEncoderFilterCallbacks + MOCK_CONST_METHOD0(requestId, uint64_t()); + MOCK_CONST_METHOD0(streamId, uint64_t()); + MOCK_CONST_METHOD0(connection, const Network::Connection*()); + MOCK_METHOD0(route, Router::RouteConstSharedPtr()); + MOCK_CONST_METHOD0(serializationType, SerializationType()); + MOCK_CONST_METHOD0(protocolType, ProtocolType()); + MOCK_METHOD0(streamInfo, StreamInfo::StreamInfo&()); + MOCK_METHOD0(resetStream, void()); + MOCK_METHOD0(dispatcher, Event::Dispatcher&()); + MOCK_METHOD0(continueEncoding, void()); + MOCK_METHOD0(continueDecoding, void()); + + uint64_t stream_id_{1}; + NiceMock connection_; + NiceMock stream_info_; + std::shared_ptr route_; + NiceMock dispatcher_; +}; + +class MockCodecFilter : public CodecFilter { +public: + MockCodecFilter(); + ~MockCodecFilter() override; + + MOCK_METHOD0(onDestroy, void()); + MOCK_METHOD1(setEncoderFilterCallbacks, void(EncoderFilterCallbacks& callbacks)); + MOCK_METHOD2(onMessageEncoded, FilterStatus(MessageMetadataSharedPtr, ContextSharedPtr)); + MOCK_METHOD1(setDecoderFilterCallbacks, void(DecoderFilterCallbacks& callbacks)); + MOCK_METHOD2(onMessageDecoded, FilterStatus(MessageMetadataSharedPtr, ContextSharedPtr)); }; class MockDirectResponse : public DirectResponse { public: - MockDirectResponse(); - ~MockDirectResponse(); + MockDirectResponse() = default; + ~MockDirectResponse() override = default; - MOCK_CONST_METHOD4(encode, DirectResponse::ResponseType(MessageMetadata&, Protocol&, - Deserializer&, Buffer::Instance&)); + MOCK_CONST_METHOD3(encode, + DirectResponse::ResponseType(MessageMetadata&, Protocol&, Buffer::Instance&)); }; template class MockFactoryBase : public NamedDubboFilterConfigFactory { @@ -187,7 +291,7 @@ template class MockFactoryBase : public NamedDubboFilterConf class MockFilterConfigFactory : public MockFactoryBase { public: MockFilterConfigFactory(); - ~MockFilterConfigFactory(); + ~MockFilterConfigFactory() override; DubboFilters::FilterFactoryCb createFilterFactoryFromProtoTyped(const ProtobufWkt::Struct& proto_config, @@ -206,7 +310,7 @@ namespace Router { class MockRouteEntry : public RouteEntry { public: MockRouteEntry(); - ~MockRouteEntry(); + ~MockRouteEntry() override; // DubboProxy::Router::RouteEntry MOCK_CONST_METHOD0(clusterName, const std::string&()); @@ -218,7 +322,7 @@ class MockRouteEntry : public RouteEntry { class MockRoute : public Route { public: MockRoute(); - ~MockRoute(); + ~MockRoute() override; // DubboProxy::Router::Route MOCK_CONST_METHOD0(routeEntry, const RouteEntry*()); diff --git a/test/extensions/filters/network/dubbo_proxy/route_matcher_test.cc b/test/extensions/filters/network/dubbo_proxy/route_matcher_test.cc index 69a3762604e4..623c6f657cd1 100644 --- a/test/extensions/filters/network/dubbo_proxy/route_matcher_test.cc +++ b/test/extensions/filters/network/dubbo_proxy/route_matcher_test.cc @@ -6,9 +6,11 @@ #include "common/protobuf/protobuf.h" #include "extensions/filters/network/dubbo_proxy/router/route_matcher.h" +#include "extensions/filters/network/dubbo_proxy/serializer_impl.h" -#include "test/test_common/utility.h" +#include "test/mocks/server/mocks.h" +#include "gmock/gmock.h" #include "gtest/gtest.h" namespace Envoy { @@ -53,28 +55,31 @@ interface: org.apache.dubbo.demo.DemoService envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteConfiguration config = parseRouteConfigurationFromV2Yaml(yaml); - RouteMatcher matcher(config); + NiceMock context; + SignleRouteMatcherImpl matcher(config, context); + auto invo = std::make_shared(); MessageMetadata metadata; - metadata.setMethodName("test"); + metadata.setInvocationInfo(invo); + invo->setMethodName("test"); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setServiceName("unknown"); + invo->setServiceName("unknown"); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setServiceGroup("test"); + invo->setServiceGroup("test"); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setServiceVersion("1.0.0"); + invo->setServiceVersion("1.0.0"); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setServiceName("org.apache.dubbo.demo.DemoService"); + invo->setServiceName("org.apache.dubbo.demo.DemoService"); EXPECT_EQ("user_service_dubbo_server", matcher.route(metadata, 0)->routeEntry()->clusterName()); // Ignore version matches if there is no version field in the configuration information. - metadata.setServiceVersion("1.0.1"); + invo->setServiceVersion("1.0.1"); EXPECT_EQ("user_service_dubbo_server", matcher.route(metadata, 0)->routeEntry()->clusterName()); - metadata.setServiceGroup("test_one"); + invo->setServiceGroup("test_one"); EXPECT_EQ("user_service_dubbo_server", matcher.route(metadata, 0)->routeEntry()->clusterName()); } @@ -97,16 +102,19 @@ group: test envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteConfiguration config = parseRouteConfigurationFromV2Yaml(yaml); - RouteMatcher matcher(config); + NiceMock context; + SignleRouteMatcherImpl matcher(config, context); + auto invo = std::make_shared(); MessageMetadata metadata; - metadata.setMethodName("test"); - metadata.setServiceName("org.apache.dubbo.demo.DemoService"); + metadata.setInvocationInfo(invo); + invo->setMethodName("test"); + invo->setServiceName("org.apache.dubbo.demo.DemoService"); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setServiceGroup("test"); + invo->setServiceGroup("test"); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setServiceVersion("1.0.0"); + invo->setServiceVersion("1.0.0"); EXPECT_EQ("user_service_dubbo_server", matcher.route(metadata, 0)->routeEntry()->clusterName()); } @@ -128,21 +136,24 @@ version: 1.0.0 envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteConfiguration config = parseRouteConfigurationFromV2Yaml(yaml); - RouteMatcher matcher(config); + NiceMock context; + SignleRouteMatcherImpl matcher(config, context); + auto invo = std::make_shared(); MessageMetadata metadata; - metadata.setMethodName("test"); - metadata.setServiceName("org.apache.dubbo.demo.DemoService"); + metadata.setInvocationInfo(invo); + invo->setMethodName("test"); + invo->setServiceName("org.apache.dubbo.demo.DemoService"); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setServiceGroup("test"); + invo->setServiceGroup("test"); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setServiceVersion("1.0.0"); + invo->setServiceVersion("1.0.0"); EXPECT_NE(nullptr, matcher.route(metadata, 0)); EXPECT_EQ("user_service_dubbo_server", matcher.route(metadata, 0)->routeEntry()->clusterName()); // Ignore group matches if there is no group field in the configuration information. - metadata.setServiceGroup("test_1"); + invo->setServiceGroup("test_1"); EXPECT_EQ("user_service_dubbo_server", matcher.route(metadata, 0)->routeEntry()->clusterName()); } @@ -164,19 +175,22 @@ group: HSF envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteConfiguration config = parseRouteConfigurationFromV2Yaml(yaml); - RouteMatcher matcher(config); + NiceMock context; + SignleRouteMatcherImpl matcher(config, context); + auto invo = std::make_shared(); MessageMetadata metadata; - metadata.setMethodName("test"); - metadata.setServiceName("org.apache.dubbo.demo.DemoService"); + metadata.setInvocationInfo(invo); + invo->setMethodName("test"); + invo->setServiceName("org.apache.dubbo.demo.DemoService"); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setServiceGroup("test"); + invo->setServiceGroup("test"); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setServiceVersion("1.0.0"); + invo->setServiceVersion("1.0.0"); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setServiceGroup("HSF"); + invo->setServiceGroup("HSF"); EXPECT_EQ("user_service_dubbo_server", matcher.route(metadata, 0)->routeEntry()->clusterName()); } } @@ -196,16 +210,19 @@ interface: org.apache.dubbo.demo.DemoService envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteConfiguration config = parseRouteConfigurationFromV2Yaml(yaml); + auto invo = std::make_shared(); MessageMetadata metadata; - metadata.setServiceName("org.apache.dubbo.demo.DemoService"); + metadata.setInvocationInfo(invo); + invo->setServiceName("org.apache.dubbo.demo.DemoService"); - RouteMatcher matcher(config); + NiceMock context; + SignleRouteMatcherImpl matcher(config, context); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setMethodName("sub"); + invo->setMethodName("sub"); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setMethodName("add"); + invo->setMethodName("add"); EXPECT_EQ("user_service_dubbo_server", matcher.route(metadata, 0)->routeEntry()->clusterName()); } @@ -224,16 +241,19 @@ interface: org.apache.dubbo.demo.DemoService envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteConfiguration config = parseRouteConfigurationFromV2Yaml(yaml); + auto invo = std::make_shared(); MessageMetadata metadata; - metadata.setServiceName("org.apache.dubbo.demo.DemoService"); + metadata.setInvocationInfo(invo); + invo->setServiceName("org.apache.dubbo.demo.DemoService"); - RouteMatcher matcher(config); + NiceMock context; + SignleRouteMatcherImpl matcher(config, context); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setMethodName("sub"); + invo->setMethodName("sub"); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setMethodName("add123test"); + invo->setMethodName("add123test"); EXPECT_EQ("user_service_dubbo_server", matcher.route(metadata, 0)->routeEntry()->clusterName()); } @@ -252,19 +272,22 @@ interface: org.apache.dubbo.demo.DemoService envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteConfiguration config = parseRouteConfigurationFromV2Yaml(yaml); + auto invo = std::make_shared(); MessageMetadata metadata; - metadata.setServiceName("org.apache.dubbo.demo.DemoService"); + metadata.setInvocationInfo(invo); + invo->setServiceName("org.apache.dubbo.demo.DemoService"); - RouteMatcher matcher(config); + NiceMock context; + SignleRouteMatcherImpl matcher(config, context); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setMethodName("ab12test"); + invo->setMethodName("ab12test"); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setMethodName("test12d2test"); + invo->setMethodName("test12d2test"); EXPECT_EQ("user_service_dubbo_server", matcher.route(metadata, 0)->routeEntry()->clusterName()); - metadata.setMethodName("testme"); + invo->setMethodName("testme"); EXPECT_EQ("user_service_dubbo_server", matcher.route(metadata, 0)->routeEntry()->clusterName()); } @@ -283,19 +306,22 @@ interface: org.apache.dubbo.demo.DemoService envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteConfiguration config = parseRouteConfigurationFromV2Yaml(yaml); + auto invo = std::make_shared(); MessageMetadata metadata; - metadata.setServiceName("org.apache.dubbo.demo.DemoService"); + metadata.setInvocationInfo(invo); + invo->setServiceName("org.apache.dubbo.demo.DemoService"); - RouteMatcher matcher(config); + NiceMock context; + SignleRouteMatcherImpl matcher(config, context); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setMethodName("12test"); + invo->setMethodName("12test"); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); - metadata.setMethodName("456test"); + invo->setMethodName("456test"); EXPECT_EQ("user_service_dubbo_server", matcher.route(metadata, 0)->routeEntry()->clusterName()); - metadata.setMethodName("4567test"); + invo->setMethodName("4567test"); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); } @@ -319,12 +345,15 @@ interface: org.apache.dubbo.demo.DemoService envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteConfiguration config = parseRouteConfigurationFromV2Yaml(yaml); + auto invo = std::make_shared(); MessageMetadata metadata; - metadata.setServiceName("org.apache.dubbo.demo.DemoService"); - metadata.setMethodName("add"); - metadata.addParameterValue(0, "150"); + metadata.setInvocationInfo(invo); + invo->setServiceName("org.apache.dubbo.demo.DemoService"); + invo->setMethodName("add"); + invo->addParameterValue(0, "150"); - RouteMatcher matcher(config); + NiceMock context; + SignleRouteMatcherImpl matcher(config, context); EXPECT_EQ("user_service_dubbo_server", matcher.route(metadata, 0)->routeEntry()->clusterName()); } @@ -346,12 +375,15 @@ interface: org.apache.dubbo.demo.DemoService envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteConfiguration config = parseRouteConfigurationFromV2Yaml(yaml); + auto invo = std::make_shared(); MessageMetadata metadata; - metadata.setServiceName("org.apache.dubbo.demo.DemoService"); - metadata.setMethodName("add"); - metadata.addParameterValue(1, "user_id:94562"); + metadata.setInvocationInfo(invo); + invo->setServiceName("org.apache.dubbo.demo.DemoService"); + invo->setMethodName("add"); + invo->addParameterValue(1, "user_id:94562"); - RouteMatcher matcher(config); + NiceMock context; + SignleRouteMatcherImpl matcher(config, context); EXPECT_EQ("user_service_dubbo_server", matcher.route(metadata, 0)->routeEntry()->clusterName()); } @@ -376,16 +408,19 @@ interface: org.apache.dubbo.demo.DemoService envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteConfiguration config = parseRouteConfigurationFromV2Yaml(yaml); + auto invo = std::make_shared(); MessageMetadata metadata; - metadata.setServiceName("org.apache.dubbo.demo.DemoService"); - metadata.setMethodName("add"); - metadata.addHeader("custom", "123"); + metadata.setInvocationInfo(invo); + invo->setServiceName("org.apache.dubbo.demo.DemoService"); + invo->setMethodName("add"); + invo->addHeader("custom", "123"); std::string test_value("123"); Envoy::Http::LowerCaseString test_key("custom1"); - metadata.addHeaderReference(test_key, test_value); + invo->addHeaderReference(test_key, test_value); - RouteMatcher matcher(config); + NiceMock context; + SignleRouteMatcherImpl matcher(config, context); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); test_value = "456"; @@ -427,17 +462,20 @@ serialization_type: Hessian2 envoy::config::filter::network::dubbo_proxy::v2alpha1::DubboProxy config = parseDubboProxyFromV2Yaml(yaml); + auto invo = std::make_shared(); MessageMetadata metadata; - metadata.setServiceName("org.apache.dubbo.demo.DemoService"); - metadata.setMethodName("add"); - metadata.addParameterValue(1, "user_id"); + metadata.setInvocationInfo(invo); + invo->setServiceName("org.apache.dubbo.demo.DemoService"); + invo->setMethodName("add"); + invo->addParameterValue(1, "user_id"); - MultiRouteMatcher matcher(config.route_config()); + NiceMock context; + MultiRouteMatcher matcher(config.route_config(), context); EXPECT_EQ("user_service_dubbo_server", matcher.route(metadata, 0)->routeEntry()->clusterName()); { envoy::config::filter::network::dubbo_proxy::v2alpha1::DubboProxy invalid_config; - MultiRouteMatcher matcher(invalid_config.route_config()); + MultiRouteMatcher matcher(invalid_config.route_config(), context); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); } } @@ -460,23 +498,28 @@ interface: org.apache.dubbo.demo.DemoService envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteConfiguration config = parseRouteConfigurationFromV2Yaml(yaml); + auto invo = std::make_shared(); MessageMetadata metadata; - metadata.setServiceName("org.apache.dubbo.demo.DemoService"); - metadata.setMethodName("add"); + metadata.setInvocationInfo(invo); + invo->setServiceName("org.apache.dubbo.demo.DemoService"); + invo->setMethodName("add"); // There is no parameter information in metadata. - RouteMatcher matcher(config); + NiceMock context; + SignleRouteMatcherImpl matcher(config, context); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); // The parameter is empty. - metadata.addParameterValue(1, ""); + invo->addParameterValue(1, ""); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); { + auto invo = std::make_shared(); MessageMetadata metadata; - metadata.setServiceName("org.apache.dubbo.demo.DemoService"); - metadata.setMethodName("add"); - metadata.addParameterValue(1, "user_id:562"); + metadata.setInvocationInfo(invo); + invo->setServiceName("org.apache.dubbo.demo.DemoService"); + invo->setMethodName("add"); + invo->addParameterValue(1, "user_id:562"); EXPECT_EQ(nullptr, matcher.route(metadata, 0)); } } @@ -516,12 +559,16 @@ interface: org.apache.dubbo.demo.DemoService envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteConfiguration config = parseRouteConfigurationFromV2Yaml(yaml); - RouteMatcher matcher(config); + auto invo = std::make_shared(); MessageMetadata metadata; - metadata.setServiceName("org.apache.dubbo.demo.DemoService"); + metadata.setInvocationInfo(invo); + invo->setServiceName("org.apache.dubbo.demo.DemoService"); + + NiceMock context; + SignleRouteMatcherImpl matcher(config, context); { - metadata.setMethodName("method1"); + invo->setMethodName("method1"); EXPECT_EQ("cluster1", matcher.route(metadata, 0)->routeEntry()->clusterName()); EXPECT_EQ("cluster1", matcher.route(metadata, 29)->routeEntry()->clusterName()); EXPECT_EQ("cluster2", matcher.route(metadata, 30)->routeEntry()->clusterName()); @@ -533,7 +580,7 @@ interface: org.apache.dubbo.demo.DemoService } { - metadata.setMethodName("method2"); + invo->setMethodName("method2"); EXPECT_EQ("cluster1", matcher.route(metadata, 0)->routeEntry()->clusterName()); EXPECT_EQ("cluster1", matcher.route(metadata, 1999)->routeEntry()->clusterName()); EXPECT_EQ("cluster2", matcher.route(metadata, 2000)->routeEntry()->clusterName()); @@ -565,7 +612,8 @@ name: config envoy::config::filter::network::dubbo_proxy::v2alpha1::RouteConfiguration config = parseRouteConfigurationFromV2Yaml(yaml); - EXPECT_THROW(RouteMatcher m(config), EnvoyException); + NiceMock context; + EXPECT_THROW(SignleRouteMatcherImpl m(config, context), EnvoyException); } } // namespace Router diff --git a/test/extensions/filters/network/dubbo_proxy/router_test.cc b/test/extensions/filters/network/dubbo_proxy/router_test.cc index 6376a8a96166..8caf2cfd4097 100644 --- a/test/extensions/filters/network/dubbo_proxy/router_test.cc +++ b/test/extensions/filters/network/dubbo_proxy/router_test.cc @@ -1,7 +1,9 @@ #include "extensions/filters/network/dubbo_proxy/app_exception.h" -#include "extensions/filters/network/dubbo_proxy/deserializer.h" +#include "extensions/filters/network/dubbo_proxy/dubbo_hessian2_serializer_impl.h" +#include "extensions/filters/network/dubbo_proxy/message_impl.h" #include "extensions/filters/network/dubbo_proxy/protocol.h" #include "extensions/filters/network/dubbo_proxy/router/router_impl.h" +#include "extensions/filters/network/dubbo_proxy/serializer_impl.h" #include "test/extensions/filters/network/dubbo_proxy/mocks.h" #include "test/mocks/network/mocks.h" @@ -30,23 +32,27 @@ namespace Router { namespace { -class TestNamedDeserializerConfigFactory : public NamedDeserializerConfigFactory { +class TestNamedSerializerConfigFactory : public NamedSerializerConfigFactory { public: - TestNamedDeserializerConfigFactory(std::function f) : f_(f) {} + TestNamedSerializerConfigFactory(std::function f) : f_(f) {} - DeserializerPtr createDeserializer() override { return DeserializerPtr{f_()}; } + SerializerPtr createSerializer() override { return SerializerPtr{f_()}; } std::string name() override { - return DeserializerNames::get().fromType(SerializationType::Hessian); + return SerializerNames::get().fromType(SerializationType::Hessian2); } - std::function f_; + std::function f_; }; class TestNamedProtocolConfigFactory : public NamedProtocolConfigFactory { public: TestNamedProtocolConfigFactory(std::function f) : f_(f) {} - ProtocolPtr createProtocol() override { return ProtocolPtr{f_()}; } + ProtocolPtr createProtocol(SerializationType serialization_type) override { + auto protocol = ProtocolPtr{f_()}; + protocol->initSerializer(serialization_type); + return protocol; + } std::string name() override { return ProtocolNames::get().fromType(ProtocolType::Dubbo); } std::function f_; @@ -57,13 +63,13 @@ class TestNamedProtocolConfigFactory : public NamedProtocolConfigFactory { class DubboRouterTestBase { public: DubboRouterTestBase() - : deserializer_factory_([&]() -> MockDeserializer* { - ASSERT(deserializer_ == nullptr); - deserializer_ = new NiceMock(); - if (mock_deserializer_cb_) { - mock_deserializer_cb_(deserializer_); + : serializer_factory_([&]() -> MockSerializer* { + ASSERT(serializer_ == nullptr); + serializer_ = new NiceMock(); + if (mock_serializer_cb_) { + mock_serializer_cb_(serializer_); } - return deserializer_; + return serializer_; }), protocol_factory_([&]() -> MockProtocol* { ASSERT(protocol_ == nullptr); @@ -73,7 +79,7 @@ class DubboRouterTestBase { } return protocol_; }), - deserializer_register_(deserializer_factory_), protocol_register_(protocol_factory_) {} + serializer_register_(serializer_factory_), protocol_register_(protocol_factory_) {} void initializeRouter() { route_ = new NiceMock(); @@ -90,9 +96,14 @@ class DubboRouterTestBase { msg_type_ = msg_type; metadata_.reset(new MessageMetadata()); - metadata_->setServiceName("test"); metadata_->setMessageType(msg_type_); metadata_->setRequestId(1); + + auto invo = std::make_shared(); + metadata_->setInvocationInfo(invo); + invo->setMethodName("test"); + + message_context_ = std::make_shared(); } void startRequest(MessageType msg_type) { @@ -102,13 +113,10 @@ class DubboRouterTestBase { EXPECT_CALL(*route_, routeEntry()).WillOnce(Return(&route_entry_)); EXPECT_CALL(route_entry_, clusterName()).WillRepeatedly(ReturnRef(cluster_name_)); - EXPECT_CALL(callbacks_, downstreamSerializationType()) - .WillOnce(Return(SerializationType::Hessian)); - EXPECT_CALL(callbacks_, downstreamProtocolType()).WillOnce(Return(ProtocolType::Dubbo)); + EXPECT_CALL(callbacks_, serializationType()).WillOnce(Return(SerializationType::Hessian2)); + EXPECT_CALL(callbacks_, protocolType()).WillOnce(Return(ProtocolType::Dubbo)); - EXPECT_EQ(Network::FilterStatus::Continue, - router_->messageBegin(msg_type, metadata_->request_id(), SerializationType::Hessian)); - EXPECT_EQ(Network::FilterStatus::StopIteration, router_->messageEnd(metadata_)); + EXPECT_EQ(FilterStatus::StopIteration, router_->onMessageDecoded(metadata_, message_context_)); EXPECT_CALL(callbacks_, connection()).WillRepeatedly(Return(&connection_)); EXPECT_EQ(&connection_, router_->downstreamConnection()); @@ -137,8 +145,6 @@ class DubboRouterTestBase { } void startRequestWithExistingConnection(MessageType msg_type) { - EXPECT_EQ(Network::FilterStatus::Continue, router_->transportBegin()); - EXPECT_CALL(callbacks_, route()).WillOnce(Return(route_ptr_)); EXPECT_CALL(*route_, routeEntry()).WillOnce(Return(&route_entry_)); EXPECT_CALL(route_entry_, clusterName()).WillRepeatedly(ReturnRef(cluster_name_)); @@ -158,9 +164,8 @@ class DubboRouterTestBase { EXPECT_EQ(nullptr, router_->metadataMatchCriteria()); EXPECT_EQ(nullptr, router_->downstreamHeaders()); - EXPECT_CALL(callbacks_, downstreamSerializationType()) - .WillOnce(Return(SerializationType::Hessian)); - EXPECT_CALL(callbacks_, downstreamProtocolType()).WillOnce(Return(ProtocolType::Dubbo)); + EXPECT_CALL(callbacks_, serializationType()).WillOnce(Return(SerializationType::Hessian2)); + EXPECT_CALL(callbacks_, protocolType()).WillOnce(Return(ProtocolType::Dubbo)); EXPECT_CALL(callbacks_, continueDecoding()).Times(0); EXPECT_CALL(context_.cluster_manager_.tcp_conn_pool_, newConnection(_)) @@ -175,7 +180,7 @@ class DubboRouterTestBase { void returnResponse() { Buffer::OwnedImpl buffer; - EXPECT_CALL(callbacks_, startUpstreamResponse(_, _)); + EXPECT_CALL(callbacks_, startUpstreamResponse()); EXPECT_CALL(callbacks_, upstreamData(Ref(buffer))) .WillOnce(Return(DubboFilters::UpstreamResponseStatus::MoreData)); @@ -196,18 +201,18 @@ class DubboRouterTestBase { router_.reset(); } - TestNamedDeserializerConfigFactory deserializer_factory_; + TestNamedSerializerConfigFactory serializer_factory_; TestNamedProtocolConfigFactory protocol_factory_; - Registry::InjectFactory deserializer_register_; + Registry::InjectFactory serializer_register_; Registry::InjectFactory protocol_register_; - std::function mock_deserializer_cb_{}; + std::function mock_serializer_cb_{}; std::function mock_protocol_cb_{}; NiceMock context_; NiceMock connection_; NiceMock callbacks_; - NiceMock* deserializer_{}; + NiceMock* serializer_{}; NiceMock* protocol_{}; NiceMock* route_{}; NiceMock route_entry_; @@ -221,6 +226,7 @@ class DubboRouterTestBase { MessageType msg_type_{MessageType::Request}; MessageMetadataSharedPtr metadata_; + ContextSharedPtr message_context_; Tcp::ConnectionPool::UpstreamCallbacks* upstream_callbacks_{}; NiceMock upstream_connection_; @@ -293,7 +299,7 @@ TEST_F(DubboRouterTest, ClusterMaintenanceMode) { EXPECT_THAT(app_ex.what(), ContainsRegex(".*maintenance mode.*")); EXPECT_FALSE(end_stream); })); - EXPECT_EQ(Network::FilterStatus::StopIteration, router_->messageEnd(metadata_)); + EXPECT_EQ(FilterStatus::StopIteration, router_->onMessageDecoded(metadata_, message_context_)); } TEST_F(DubboRouterTest, NoHealthyHosts) { @@ -314,18 +320,18 @@ TEST_F(DubboRouterTest, NoHealthyHosts) { EXPECT_FALSE(end_stream); })); - EXPECT_EQ(Network::FilterStatus::StopIteration, router_->messageEnd(metadata_)); + EXPECT_EQ(FilterStatus::StopIteration, router_->onMessageDecoded(metadata_, message_context_)); } TEST_F(DubboRouterTest, PoolConnectionFailureWithOnewayMessage) { initializeRouter(); initializeMetadata(MessageType::Oneway); - EXPECT_CALL(callbacks_, downstreamSerializationType()) - .WillOnce(Return(SerializationType::Hessian)); + EXPECT_CALL(callbacks_, protocolType()).WillOnce(Return(ProtocolType::Dubbo)); + EXPECT_CALL(callbacks_, serializationType()).WillOnce(Return(SerializationType::Hessian2)); EXPECT_CALL(callbacks_, sendLocalReply(_, _)).Times(0); EXPECT_CALL(callbacks_, resetStream()).Times(1); - EXPECT_EQ(Network::FilterStatus::StopIteration, router_->messageEnd(metadata_)); + EXPECT_EQ(FilterStatus::StopIteration, router_->onMessageDecoded(metadata_, message_context_)); context_.cluster_manager_.tcp_conn_pool_.poolFailure( Tcp::ConnectionPool::PoolFailureReason::RemoteConnectionFailure); @@ -345,7 +351,7 @@ TEST_F(DubboRouterTest, NoRoute) { EXPECT_THAT(app_ex.what(), ContainsRegex(".*no route.*")); EXPECT_FALSE(end_stream); })); - EXPECT_EQ(Network::FilterStatus::StopIteration, router_->messageEnd(metadata_)); + EXPECT_EQ(FilterStatus::StopIteration, router_->onMessageDecoded(metadata_, message_context_)); } TEST_F(DubboRouterTest, NoCluster) { @@ -363,24 +369,21 @@ TEST_F(DubboRouterTest, NoCluster) { EXPECT_THAT(app_ex.what(), ContainsRegex(".*unknown cluster.*")); EXPECT_FALSE(end_stream); })); - EXPECT_EQ(Network::FilterStatus::StopIteration, router_->messageEnd(metadata_)); + EXPECT_EQ(FilterStatus::StopIteration, router_->onMessageDecoded(metadata_, message_context_)); } TEST_F(DubboRouterTest, UnexpectedRouterDestroy) { initializeRouter(); initializeMetadata(MessageType::Request); EXPECT_CALL(upstream_connection_, close(Network::ConnectionCloseType::NoFlush)); - startRequest(MessageType::Request); - - EXPECT_EQ(Network::FilterStatus::Continue, router_->transportBegin()); Buffer::OwnedImpl buffer; - buffer.add(std::string({'\xda', '\xbb', 0x42, 20})); - EXPECT_EQ(Network::FilterStatus::Continue, router_->transferHeaderTo(buffer, buffer.length())); - buffer.drain(buffer.length()); - buffer.add("test"); - EXPECT_EQ(Network::FilterStatus::Continue, router_->transferBodyTo(buffer, buffer.length())); + buffer.add(std::string({'\xda', '\xbb', 0x42, 20})); // Header + buffer.add("test"); // Body + auto ctx = static_cast(message_context_.get()); + ctx->message_origin_data().move(buffer, buffer.length()); + startRequest(MessageType::Request); connectUpstream(); destroyRouter(); } @@ -418,9 +421,6 @@ TEST_F(DubboRouterTest, OneWay) { startRequest(MessageType::Oneway); connectUpstream(); - - EXPECT_EQ(Network::FilterStatus::Continue, router_->transportEnd()); - destroyRouter(); } @@ -432,10 +432,6 @@ TEST_F(DubboRouterTest, Call) { startRequest(MessageType::Request); connectUpstream(); - - EXPECT_EQ(Network::FilterStatus::Continue, router_->transportBegin()); - EXPECT_EQ(Network::FilterStatus::Continue, router_->transportEnd()); - returnResponse(); destroyRouter(); } @@ -445,15 +441,12 @@ TEST_F(DubboRouterTest, DecoderFilterCallbacks) { initializeMetadata(MessageType::Request); EXPECT_CALL(upstream_connection_, write(_, false)); - EXPECT_CALL(callbacks_, startUpstreamResponse(_, _)).Times(1); + EXPECT_CALL(callbacks_, startUpstreamResponse()).Times(1); EXPECT_CALL(callbacks_, upstreamData(_)).Times(1); startRequest(MessageType::Request); connectUpstream(); - EXPECT_EQ(Network::FilterStatus::Continue, router_->transportBegin()); - EXPECT_EQ(Network::FilterStatus::Continue, router_->transportEnd()); - Buffer::OwnedImpl buffer; buffer.add(std::string("This is the test data")); router_->onUpstreamData(buffer, true); @@ -465,7 +458,7 @@ TEST_F(DubboRouterTest, UpstreamDataReset) { initializeRouter(); initializeMetadata(MessageType::Request); - EXPECT_CALL(callbacks_, startUpstreamResponse(_, _)).Times(1); + EXPECT_CALL(callbacks_, startUpstreamResponse()).Times(1); EXPECT_CALL(callbacks_, upstreamData(_)) .WillOnce(Return(DubboFilters::UpstreamResponseStatus::Reset)); EXPECT_CALL(upstream_connection_, close(Network::ConnectionCloseType::NoFlush)); @@ -484,7 +477,7 @@ TEST_F(DubboRouterTest, StartRequestWithExistingConnection) { initializeRouter(); startRequestWithExistingConnection(MessageType::Request); - EXPECT_EQ(Network::FilterStatus::Continue, router_->messageEnd(metadata_)); + EXPECT_EQ(FilterStatus::Continue, router_->onMessageDecoded(metadata_, message_context_)); destroyRouter(); } @@ -511,7 +504,7 @@ TEST_F(DubboRouterTest, LocalClosedWhileResponseComplete) { initializeRouter(); initializeMetadata(MessageType::Request); - EXPECT_CALL(callbacks_, startUpstreamResponse(_, _)).Times(1); + EXPECT_CALL(callbacks_, startUpstreamResponse()).Times(1); EXPECT_CALL(callbacks_, upstreamData(_)) .WillOnce(Return(DubboFilters::UpstreamResponseStatus::Complete)); EXPECT_CALL(callbacks_, sendLocalReply(_, _)).Times(0); diff --git a/test/extensions/filters/network/ext_authz/ext_authz_test.cc b/test/extensions/filters/network/ext_authz/ext_authz_test.cc index 1e4d08186dce..8a344ed162f5 100644 --- a/test/extensions/filters/network/ext_authz/ext_authz_test.cc +++ b/test/extensions/filters/network/ext_authz/ext_authz_test.cc @@ -69,7 +69,7 @@ class ExtAuthzFilterTest : public testing::Test { return response; } - ~ExtAuthzFilterTest() { + ~ExtAuthzFilterTest() override { for (const Stats::GaugeSharedPtr& gauge : stats_store_.gauges()) { EXPECT_EQ(0U, gauge->value()); } diff --git a/test/extensions/filters/network/http_connection_manager/BUILD b/test/extensions/filters/network/http_connection_manager/BUILD index 71873e28e902..c2333de286e0 100644 --- a/test/extensions/filters/network/http_connection_manager/BUILD +++ b/test/extensions/filters/network/http_connection_manager/BUILD @@ -18,7 +18,10 @@ envoy_extension_cc_test( deps = [ "//source/common/buffer:buffer_lib", "//source/common/event:dispatcher_lib", + "//source/extensions/access_loggers/file:config", "//source/extensions/filters/http/dynamo:config", + "//source/extensions/filters/http/health_check:config", + "//source/extensions/filters/http/ratelimit:config", "//source/extensions/filters/http/router:config", "//source/extensions/filters/network/http_connection_manager:config", "//test/mocks/network:network_mocks", diff --git a/test/extensions/filters/network/http_connection_manager/config_test.cc b/test/extensions/filters/network/http_connection_manager/config_test.cc index c232ad8fd276..9afdaa5a6c2b 100644 --- a/test/extensions/filters/network/http_connection_manager/config_test.cc +++ b/test/extensions/filters/network/http_connection_manager/config_test.cc @@ -49,6 +49,77 @@ TEST_F(HttpConnectionManagerConfigTest, ValidateFail) { ProtoValidationException); } +// Verify that the v1 JSON config path still works. This will be deleted when v1 is fully removed. +TEST_F(HttpConnectionManagerConfigTest, V1Config) { + const std::string yaml_string = R"EOF( +drain_timeout_ms: 5000 +route_config: + virtual_hosts: + - require_ssl: all + routes: + - cluster: cluster_1 + prefix: "/" + domains: + - www.redirect.com + name: redirect + - routes: + - prefix: "/" + cluster: cluster_1 + runtime: + key: some_key + default: 0 + - prefix: "/test/long/url" + rate_limits: + - actions: + - type: destination_cluster + cluster: cluster_1 + - prefix: "/test/" + cluster: cluster_2 + - prefix: "/websocket/test" + prefix_rewrite: "/websocket" + cluster: cluster_1 + domains: + - "*" + name: integration +codec_type: http1 +stat_prefix: router +filters: +- name: health_check + config: + endpoint: "/healthcheck" + pass_through_mode: false +- name: rate_limit + config: + domain: foo +- name: router + config: {} +access_log: +- format: '[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% + %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% + %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" + "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%" + "%REQUEST_DURATION%" "%RESPONSE_DURATION%"' + path: "/dev/null" + filter: + filters: + - type: status_code + op: ">=" + value: 500 + - type: duration + op: ">=" + value: 1000000 + type: logical_or +- path: "/dev/null" + )EOF"; + + ON_CALL(context_.runtime_loader_.snapshot_, + deprecatedFeatureEnabled("envoy.deprecated_features.v1_filter_json_config")) + .WillByDefault(Return(true)); + + HttpConnectionManagerFilterConfigFactory().createFilterFactory( + *Json::Factory::loadFromYamlString(yaml_string), context_); +} + TEST_F(HttpConnectionManagerConfigTest, InvalidFilterName) { const std::string yaml_string = R"EOF( codec_type: http1 diff --git a/test/extensions/filters/network/kafka/kafka_request_parser_test.cc b/test/extensions/filters/network/kafka/kafka_request_parser_test.cc index a70797742806..fda8f7770e6c 100644 --- a/test/extensions/filters/network/kafka/kafka_request_parser_test.cc +++ b/test/extensions/filters/network/kafka/kafka_request_parser_test.cc @@ -21,7 +21,7 @@ class KafkaRequestParserTest : public testing::Test, public BufferBasedTest {}; class MockRequestParserResolver : public RequestParserResolver { public: - MockRequestParserResolver(){}; + MockRequestParserResolver() = default; MOCK_CONST_METHOD3(createParser, RequestParserSharedPtr(int16_t, int16_t, RequestContextSharedPtr)); }; diff --git a/test/extensions/filters/network/kafka/kafka_response_parser_test.cc b/test/extensions/filters/network/kafka/kafka_response_parser_test.cc index de1ab3edf013..ea7fd9699126 100644 --- a/test/extensions/filters/network/kafka/kafka_response_parser_test.cc +++ b/test/extensions/filters/network/kafka/kafka_response_parser_test.cc @@ -21,7 +21,7 @@ class KafkaResponseParserTest : public testing::Test, public BufferBasedTest {}; class MockResponseParserResolver : public ResponseParserResolver { public: - MockResponseParserResolver(){}; + MockResponseParserResolver() = default; MOCK_CONST_METHOD1(createParser, ResponseParserSharedPtr(ResponseContextSharedPtr)); }; diff --git a/test/extensions/filters/network/kafka/serialization_utilities.h b/test/extensions/filters/network/kafka/serialization_utilities.h index caadecb8b69d..8417afb6e61e 100644 --- a/test/extensions/filters/network/kafka/serialization_utilities.h +++ b/test/extensions/filters/network/kafka/serialization_utilities.h @@ -120,16 +120,14 @@ template class CapturingCall /** * Stores the message. */ - virtual void onMessage(Message message) override { captured_messages_.push_back(message); } + void onMessage(Message message) override { captured_messages_.push_back(message); } /** * Returns the stored messages. */ const std::vector& getCapturedMessages() const { return captured_messages_; } - virtual void onFailedParse(Failure failure_data) override { - parse_failures_.push_back(failure_data); - } + void onFailedParse(Failure failure_data) override { parse_failures_.push_back(failure_data); } const std::vector& getParseFailures() const { return parse_failures_; } diff --git a/test/extensions/filters/network/ratelimit/ratelimit_test.cc b/test/extensions/filters/network/ratelimit/ratelimit_test.cc index 1ff47f4dbe6c..0b639e1275d2 100644 --- a/test/extensions/filters/network/ratelimit/ratelimit_test.cc +++ b/test/extensions/filters/network/ratelimit/ratelimit_test.cc @@ -50,7 +50,7 @@ class RateLimitFilterTest : public testing::Test { filter_->onBelowWriteBufferLowWatermark(); } - ~RateLimitFilterTest() { + ~RateLimitFilterTest() override { for (const Stats::GaugeSharedPtr& gauge : stats_store_.gauges()) { EXPECT_EQ(0U, gauge->value()); } diff --git a/test/extensions/filters/network/redis_proxy/command_lookup_speed_test.cc b/test/extensions/filters/network/redis_proxy/command_lookup_speed_test.cc index b4be8f79419f..173e5efc8c2a 100644 --- a/test/extensions/filters/network/redis_proxy/command_lookup_speed_test.cc +++ b/test/extensions/filters/network/redis_proxy/command_lookup_speed_test.cc @@ -24,7 +24,7 @@ namespace RedisProxy { class NoOpSplitCallbacks : public CommandSplitter::SplitCallbacks { public: NoOpSplitCallbacks() = default; - ~NoOpSplitCallbacks() = default; + ~NoOpSplitCallbacks() override = default; bool connectionAllowed() override { return true; } void onAuth(const std::string&) override {} diff --git a/test/extensions/filters/network/redis_proxy/mocks.cc b/test/extensions/filters/network/redis_proxy/mocks.cc index b3da756d65c3..f06a6bd9b0b9 100644 --- a/test/extensions/filters/network/redis_proxy/mocks.cc +++ b/test/extensions/filters/network/redis_proxy/mocks.cc @@ -10,32 +10,32 @@ namespace Extensions { namespace NetworkFilters { namespace RedisProxy { -MockRouter::MockRouter() {} -MockRouter::~MockRouter() {} +MockRouter::MockRouter() = default; +MockRouter::~MockRouter() = default; MockRoute::MockRoute(ConnPool::InstanceSharedPtr conn_pool) : conn_pool_(std::move(conn_pool)) { ON_CALL(*this, upstream()).WillByDefault(Return(conn_pool_)); ON_CALL(*this, mirrorPolicies()).WillByDefault(ReturnRef(policies_)); } -MockRoute::~MockRoute() {} +MockRoute::~MockRoute() = default; namespace ConnPool { -MockInstance::MockInstance() {} -MockInstance::~MockInstance() {} +MockInstance::MockInstance() = default; +MockInstance::~MockInstance() = default; } // namespace ConnPool namespace CommandSplitter { -MockSplitRequest::MockSplitRequest() {} -MockSplitRequest::~MockSplitRequest() {} +MockSplitRequest::MockSplitRequest() = default; +MockSplitRequest::~MockSplitRequest() = default; -MockSplitCallbacks::MockSplitCallbacks() {} -MockSplitCallbacks::~MockSplitCallbacks() {} +MockSplitCallbacks::MockSplitCallbacks() = default; +MockSplitCallbacks::~MockSplitCallbacks() = default; -MockInstance::MockInstance() {} -MockInstance::~MockInstance() {} +MockInstance::MockInstance() = default; +MockInstance::~MockInstance() = default; } // namespace CommandSplitter } // namespace RedisProxy diff --git a/test/extensions/filters/network/redis_proxy/mocks.h b/test/extensions/filters/network/redis_proxy/mocks.h index cafd3f31966d..7a169df1f767 100644 --- a/test/extensions/filters/network/redis_proxy/mocks.h +++ b/test/extensions/filters/network/redis_proxy/mocks.h @@ -22,7 +22,7 @@ namespace RedisProxy { class MockRouter : public Router { public: MockRouter(); - ~MockRouter(); + ~MockRouter() override; MOCK_METHOD1(upstreamPool, RouteSharedPtr(std::string& key)); }; @@ -30,7 +30,7 @@ class MockRouter : public Router { class MockRoute : public Route { public: MockRoute(ConnPool::InstanceSharedPtr); - ~MockRoute(); + ~MockRoute() override; MOCK_CONST_METHOD0(upstream, ConnPool::InstanceSharedPtr()); MOCK_CONST_METHOD0(mirrorPolicies, const MirrorPolicies&()); @@ -45,7 +45,7 @@ namespace ConnPool { class MockInstance : public Instance { public: MockInstance(); - ~MockInstance(); + ~MockInstance() override; MOCK_METHOD3(makeRequest, Common::Redis::Client::PoolRequest*( @@ -64,7 +64,7 @@ namespace CommandSplitter { class MockSplitRequest : public SplitRequest { public: MockSplitRequest(); - ~MockSplitRequest(); + ~MockSplitRequest() override; MOCK_METHOD0(cancel, void()); }; @@ -72,7 +72,7 @@ class MockSplitRequest : public SplitRequest { class MockSplitCallbacks : public SplitCallbacks { public: MockSplitCallbacks(); - ~MockSplitCallbacks(); + ~MockSplitCallbacks() override; MOCK_METHOD0(connectionAllowed, bool()); MOCK_METHOD1(onAuth, void(const std::string& password)); @@ -85,7 +85,7 @@ class MockSplitCallbacks : public SplitCallbacks { class MockInstance : public Instance { public: MockInstance(); - ~MockInstance(); + ~MockInstance() override; SplitRequestPtr makeRequest(Common::Redis::RespValuePtr&& request, SplitCallbacks& callbacks) override { diff --git a/test/extensions/filters/network/thrift_proxy/filters/ratelimit/ratelimit_test.cc b/test/extensions/filters/network/thrift_proxy/filters/ratelimit/ratelimit_test.cc index f8f3d4dd812b..01877c365c4e 100644 --- a/test/extensions/filters/network/thrift_proxy/filters/ratelimit/ratelimit_test.cc +++ b/test/extensions/filters/network/thrift_proxy/filters/ratelimit/ratelimit_test.cc @@ -75,6 +75,7 @@ class ThriftRateLimitFilterTest : public testing::Test { domain: foo )EOF"; + Stats::IsolatedStoreImpl stats_store_; ConfigSharedPtr config_; Filters::Common::RateLimit::MockClient* client_; std::unique_ptr filter_; @@ -84,7 +85,6 @@ class ThriftRateLimitFilterTest : public testing::Test { Http::TestHeaderMapImpl response_headers_; Buffer::OwnedImpl data_; Buffer::OwnedImpl response_data_; - Stats::IsolatedStoreImpl stats_store_; NiceMock runtime_; NiceMock cm_; NiceMock route_rate_limit_; diff --git a/test/extensions/filters/network/thrift_proxy/header_transport_impl_test.cc b/test/extensions/filters/network/thrift_proxy/header_transport_impl_test.cc index 261eb6c80adb..791a2f9f4d59 100644 --- a/test/extensions/filters/network/thrift_proxy/header_transport_impl_test.cc +++ b/test/extensions/filters/network/thrift_proxy/header_transport_impl_test.cc @@ -24,8 +24,8 @@ namespace { class MockBuffer : public Envoy::MockBuffer { public: - MockBuffer() {} - ~MockBuffer() {} + MockBuffer() = default; + ~MockBuffer() override = default; MOCK_CONST_METHOD0(length, uint64_t()); }; diff --git a/test/extensions/filters/network/thrift_proxy/mocks.cc b/test/extensions/filters/network/thrift_proxy/mocks.cc index e32c0a654782..3f591919a4fc 100644 --- a/test/extensions/filters/network/thrift_proxy/mocks.cc +++ b/test/extensions/filters/network/thrift_proxy/mocks.cc @@ -18,14 +18,14 @@ namespace Extensions { namespace NetworkFilters { namespace ThriftProxy { -MockConfig::MockConfig() {} -MockConfig::~MockConfig() {} +MockConfig::MockConfig() = default; +MockConfig::~MockConfig() = default; MockTransport::MockTransport() { ON_CALL(*this, name()).WillByDefault(ReturnRef(name_)); ON_CALL(*this, type()).WillByDefault(Return(type_)); } -MockTransport::~MockTransport() {} +MockTransport::~MockTransport() = default; MockProtocol::MockProtocol() { ON_CALL(*this, name()).WillByDefault(ReturnRef(name_)); @@ -35,24 +35,24 @@ MockProtocol::MockProtocol() { })); ON_CALL(*this, supportsUpgrade()).WillByDefault(Return(false)); } -MockProtocol::~MockProtocol() {} +MockProtocol::~MockProtocol() = default; -MockDecoderCallbacks::MockDecoderCallbacks() {} -MockDecoderCallbacks::~MockDecoderCallbacks() {} +MockDecoderCallbacks::MockDecoderCallbacks() = default; +MockDecoderCallbacks::~MockDecoderCallbacks() = default; -MockDecoderEventHandler::MockDecoderEventHandler() {} -MockDecoderEventHandler::~MockDecoderEventHandler() {} +MockDecoderEventHandler::MockDecoderEventHandler() = default; +MockDecoderEventHandler::~MockDecoderEventHandler() = default; -MockDirectResponse::MockDirectResponse() {} -MockDirectResponse::~MockDirectResponse() {} +MockDirectResponse::MockDirectResponse() = default; +MockDirectResponse::~MockDirectResponse() = default; -MockThriftObject::MockThriftObject() {} -MockThriftObject::~MockThriftObject() {} +MockThriftObject::MockThriftObject() = default; +MockThriftObject::~MockThriftObject() = default; namespace ThriftFilters { -MockFilterChainFactoryCallbacks::MockFilterChainFactoryCallbacks() {} -MockFilterChainFactoryCallbacks::~MockFilterChainFactoryCallbacks() {} +MockFilterChainFactoryCallbacks::MockFilterChainFactoryCallbacks() = default; +MockFilterChainFactoryCallbacks::~MockFilterChainFactoryCallbacks() = default; MockDecoderFilter::MockDecoderFilter() { ON_CALL(*this, transportBegin(_)).WillByDefault(Return(FilterStatus::Continue)); @@ -77,7 +77,7 @@ MockDecoderFilter::MockDecoderFilter() { ON_CALL(*this, setBegin(_, _)).WillByDefault(Return(FilterStatus::Continue)); ON_CALL(*this, setEnd()).WillByDefault(Return(FilterStatus::Continue)); } -MockDecoderFilter::~MockDecoderFilter() {} +MockDecoderFilter::~MockDecoderFilter() = default; MockDecoderFilterCallbacks::MockDecoderFilterCallbacks() { route_.reset(new NiceMock()); @@ -87,14 +87,14 @@ MockDecoderFilterCallbacks::MockDecoderFilterCallbacks() { ON_CALL(*this, route()).WillByDefault(Return(route_)); ON_CALL(*this, streamInfo()).WillByDefault(ReturnRef(stream_info_)); } -MockDecoderFilterCallbacks::~MockDecoderFilterCallbacks() {} +MockDecoderFilterCallbacks::~MockDecoderFilterCallbacks() = default; MockFilterConfigFactory::MockFilterConfigFactory() : FactoryBase("envoy.filters.thrift.mock_filter") { mock_filter_.reset(new NiceMock()); } -MockFilterConfigFactory::~MockFilterConfigFactory() {} +MockFilterConfigFactory::~MockFilterConfigFactory() = default; FilterFactoryCb MockFilterConfigFactory::createFilterFactoryFromProtoTyped( const ProtobufWkt::Struct& proto_config, const std::string& stat_prefix, @@ -116,22 +116,22 @@ namespace Router { MockRateLimitPolicyEntry::MockRateLimitPolicyEntry() { ON_CALL(*this, disableKey()).WillByDefault(ReturnRef(disable_key_)); } -MockRateLimitPolicyEntry::~MockRateLimitPolicyEntry() {} +MockRateLimitPolicyEntry::~MockRateLimitPolicyEntry() = default; MockRateLimitPolicy::MockRateLimitPolicy() { ON_CALL(*this, empty()).WillByDefault(Return(true)); ON_CALL(*this, getApplicableRateLimit(_)).WillByDefault(ReturnRef(rate_limit_policy_entry_)); } -MockRateLimitPolicy::~MockRateLimitPolicy() {} +MockRateLimitPolicy::~MockRateLimitPolicy() = default; MockRouteEntry::MockRouteEntry() { ON_CALL(*this, clusterName()).WillByDefault(ReturnRef(cluster_name_)); ON_CALL(*this, rateLimitPolicy()).WillByDefault(ReturnRef(rate_limit_policy_)); } -MockRouteEntry::~MockRouteEntry() {} +MockRouteEntry::~MockRouteEntry() = default; MockRoute::MockRoute() { ON_CALL(*this, routeEntry()).WillByDefault(Return(&route_entry_)); } -MockRoute::~MockRoute() {} +MockRoute::~MockRoute() = default; } // namespace Router } // namespace ThriftProxy diff --git a/test/extensions/filters/network/thrift_proxy/mocks.h b/test/extensions/filters/network/thrift_proxy/mocks.h index 1d4f8631eba1..542cbca2f170 100644 --- a/test/extensions/filters/network/thrift_proxy/mocks.h +++ b/test/extensions/filters/network/thrift_proxy/mocks.h @@ -28,7 +28,7 @@ namespace ThriftProxy { class MockConfig : public Config { public: MockConfig(); - ~MockConfig(); + ~MockConfig() override; // ThriftProxy::Config MOCK_METHOD0(filterFactory, ThriftFilters::FilterChainFactory&()); @@ -40,7 +40,7 @@ class MockConfig : public Config { class MockTransport : public Transport { public: MockTransport(); - ~MockTransport(); + ~MockTransport() override; // ThriftProxy::Transport MOCK_CONST_METHOD0(name, const std::string&()); @@ -56,7 +56,7 @@ class MockTransport : public Transport { class MockProtocol : public Protocol { public: MockProtocol(); - ~MockProtocol(); + ~MockProtocol() override; // ThriftProxy::Protocol MOCK_CONST_METHOD0(name, const std::string&()); @@ -121,7 +121,7 @@ class MockProtocol : public Protocol { class MockDecoderCallbacks : public DecoderCallbacks { public: MockDecoderCallbacks(); - ~MockDecoderCallbacks(); + ~MockDecoderCallbacks() override; // ThriftProxy::DecoderCallbacks MOCK_METHOD0(newDecoderEventHandler, DecoderEventHandler&()); @@ -130,7 +130,7 @@ class MockDecoderCallbacks : public DecoderCallbacks { class MockDecoderEventHandler : public DecoderEventHandler { public: MockDecoderEventHandler(); - ~MockDecoderEventHandler(); + ~MockDecoderEventHandler() override; // ThriftProxy::DecoderEventHandler MOCK_METHOD1(transportBegin, FilterStatus(MessageMetadataSharedPtr metadata)); @@ -160,7 +160,7 @@ class MockDecoderEventHandler : public DecoderEventHandler { class MockDirectResponse : public DirectResponse { public: MockDirectResponse(); - ~MockDirectResponse(); + ~MockDirectResponse() override; // ThriftProxy::DirectResponse MOCK_CONST_METHOD3(encode, @@ -170,7 +170,7 @@ class MockDirectResponse : public DirectResponse { class MockThriftObject : public ThriftObject { public: MockThriftObject(); - ~MockThriftObject(); + ~MockThriftObject() override; MOCK_CONST_METHOD0(fields, ThriftFieldPtrList&()); MOCK_METHOD1(onData, bool(Buffer::Instance&)); @@ -185,7 +185,7 @@ namespace ThriftFilters { class MockFilterChainFactoryCallbacks : public FilterChainFactoryCallbacks { public: MockFilterChainFactoryCallbacks(); - ~MockFilterChainFactoryCallbacks(); + ~MockFilterChainFactoryCallbacks() override; MOCK_METHOD1(addDecoderFilter, void(DecoderFilterSharedPtr)); }; @@ -193,7 +193,7 @@ class MockFilterChainFactoryCallbacks : public FilterChainFactoryCallbacks { class MockDecoderFilter : public DecoderFilter { public: MockDecoderFilter(); - ~MockDecoderFilter(); + ~MockDecoderFilter() override; // ThriftProxy::ThriftFilters::DecoderFilter MOCK_METHOD0(onDestroy, void()); @@ -228,7 +228,7 @@ class MockDecoderFilter : public DecoderFilter { class MockDecoderFilterCallbacks : public DecoderFilterCallbacks { public: MockDecoderFilterCallbacks(); - ~MockDecoderFilterCallbacks(); + ~MockDecoderFilterCallbacks() override; // ThriftProxy::ThriftFilters::DecoderFilterCallbacks MOCK_CONST_METHOD0(streamId, uint64_t()); @@ -252,7 +252,7 @@ class MockDecoderFilterCallbacks : public DecoderFilterCallbacks { class MockFilterConfigFactory : public ThriftFilters::FactoryBase { public: MockFilterConfigFactory(); - ~MockFilterConfigFactory(); + ~MockFilterConfigFactory() override; ThriftFilters::FilterFactoryCb createFilterFactoryFromProtoTyped(const ProtobufWkt::Struct& proto_config, @@ -271,7 +271,7 @@ namespace Router { class MockRateLimitPolicyEntry : public RateLimitPolicyEntry { public: MockRateLimitPolicyEntry(); - ~MockRateLimitPolicyEntry(); + ~MockRateLimitPolicyEntry() override; MOCK_CONST_METHOD0(stage, uint32_t()); MOCK_CONST_METHOD0(disableKey, const std::string&()); @@ -286,7 +286,7 @@ class MockRateLimitPolicyEntry : public RateLimitPolicyEntry { class MockRateLimitPolicy : public RateLimitPolicy { public: MockRateLimitPolicy(); - ~MockRateLimitPolicy(); + ~MockRateLimitPolicy() override; MOCK_CONST_METHOD0(empty, bool()); MOCK_CONST_METHOD1( @@ -299,7 +299,7 @@ class MockRateLimitPolicy : public RateLimitPolicy { class MockRouteEntry : public RouteEntry { public: MockRouteEntry(); - ~MockRouteEntry(); + ~MockRouteEntry() override; // ThriftProxy::Router::RouteEntry MOCK_CONST_METHOD0(clusterName, const std::string&()); @@ -313,7 +313,7 @@ class MockRouteEntry : public RouteEntry { class MockRoute : public Route { public: MockRoute(); - ~MockRoute(); + ~MockRoute() override; // ThriftProxy::Router::Route MOCK_CONST_METHOD0(routeEntry, const RouteEntry*()); diff --git a/test/extensions/grpc_credentials/file_based_metadata/file_based_metadata_grpc_credentials_test.cc b/test/extensions/grpc_credentials/file_based_metadata/file_based_metadata_grpc_credentials_test.cc index ec1f153c8d4f..d683abfa4974 100644 --- a/test/extensions/grpc_credentials/file_based_metadata/file_based_metadata_grpc_credentials_test.cc +++ b/test/extensions/grpc_credentials/file_based_metadata/file_based_metadata_grpc_credentials_test.cc @@ -30,7 +30,7 @@ class GrpcFileBasedMetadataClientIntegrationTest : public GrpcSslClientIntegrati } } - virtual envoy::api::v2::core::GrpcService createGoogleGrpcConfig() override { + envoy::api::v2::core::GrpcService createGoogleGrpcConfig() override { auto config = GrpcClientIntegrationTest::createGoogleGrpcConfig(); auto* google_grpc = config.mutable_google_grpc(); google_grpc->set_credentials_factory_name(credentials_factory_name_); diff --git a/test/extensions/quic_listeners/quiche/BUILD b/test/extensions/quic_listeners/quiche/BUILD index a51b6ea79b34..313ef1d0e808 100644 --- a/test/extensions/quic_listeners/quiche/BUILD +++ b/test/extensions/quic_listeners/quiche/BUILD @@ -22,6 +22,7 @@ envoy_cc_test( "//source/extensions/quic_listeners/quiche:envoy_quic_alarm_lib", "//source/extensions/quic_listeners/quiche/platform:envoy_quic_clock_lib", "//test/test_common:simulated_time_system_lib", + "//test/test_common:utility_lib", ], ) @@ -47,3 +48,14 @@ envoy_cc_test( "@com_googlesource_quiche//:quic_core_versions_lib", ], ) + +envoy_cc_test_library( + name = "quic_test_utils_for_envoy_lib", + srcs = ["crypto_test_utils_for_envoy.cc"], + tags = ["nofips"], + deps = [ + "//source/extensions/quic_listeners/quiche:envoy_quic_proof_source_lib", + "//source/extensions/quic_listeners/quiche:envoy_quic_proof_verifier_lib", + "@com_googlesource_quiche//:quic_test_tools_test_utils_interface_lib", + ], +) diff --git a/test/extensions/quic_listeners/quiche/crypto_test_utils_for_envoy.cc b/test/extensions/quic_listeners/quiche/crypto_test_utils_for_envoy.cc new file mode 100644 index 000000000000..b3a94737a5e6 --- /dev/null +++ b/test/extensions/quic_listeners/quiche/crypto_test_utils_for_envoy.cc @@ -0,0 +1,39 @@ +// NOLINT(namespace-envoy) + +// This file defines platform dependent test utility functions which is declared +// in quiche/quic/test_tools/crypto_test_utils.h. + +#pragma GCC diagnostic push +// QUICHE allows unused parameters. +#pragma GCC diagnostic ignored "-Wunused-parameter" +// QUICHE uses offsetof(). +#pragma GCC diagnostic ignored "-Winvalid-offsetof" +#pragma GCC diagnostic ignored "-Wtype-limits" + +#include "quiche/quic/test_tools/crypto_test_utils.h" + +#pragma GCC diagnostic pop + +#include +#include "extensions/quic_listeners/quiche/envoy_quic_fake_proof_source.h" +#include "extensions/quic_listeners/quiche/envoy_quic_fake_proof_verifier.h" + +namespace quic { +namespace test { +namespace crypto_test_utils { +std::unique_ptr ProofSourceForTesting() { + return std::make_unique(); +} + +std::unique_ptr ProofVerifierForTesting() { + return std::make_unique(); +} + +std::unique_ptr ProofVerifyContextForTesting() { + // No context needed for fake verifier. + return nullptr; +} + +} // namespace crypto_test_utils +} // namespace test +} // namespace quic diff --git a/test/extensions/quic_listeners/quiche/envoy_quic_alarm_test.cc b/test/extensions/quic_listeners/quiche/envoy_quic_alarm_test.cc index 6dc18d378150..9ab3753ec855 100644 --- a/test/extensions/quic_listeners/quiche/envoy_quic_alarm_test.cc +++ b/test/extensions/quic_listeners/quiche/envoy_quic_alarm_test.cc @@ -1,10 +1,9 @@ -#include "common/event/libevent_scheduler.h" - #include "extensions/quic_listeners/quiche/envoy_quic_alarm.h" #include "extensions/quic_listeners/quiche/envoy_quic_alarm_factory.h" #include "extensions/quic_listeners/quiche/platform/envoy_quic_clock.h" #include "test/test_common/simulated_time_system.h" +#include "test/test_common/utility.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -17,7 +16,7 @@ namespace Quic { class TestDelegate : public quic::QuicAlarm::Delegate { public: - TestDelegate() : fired_(false) {} + TestDelegate() = default; // quic::QuicAlarm::Delegate void OnAlarm() override { fired_ = true; } @@ -26,25 +25,25 @@ class TestDelegate : public quic::QuicAlarm::Delegate { void set_fired(bool fired) { fired_ = fired; } private: - bool fired_; + bool fired_{false}; }; class EnvoyQuicAlarmTest : public ::testing::Test { public: EnvoyQuicAlarmTest() - : clock_(time_system_), scheduler_(time_system_.createScheduler(base_scheduler_)), - alarm_factory_(*scheduler_, clock_) {} + : api_(Api::createApiForTest(time_system_)), dispatcher_(api_->allocateDispatcher()), + clock_(*dispatcher_), alarm_factory_(*dispatcher_, clock_) {} void advanceMsAndLoop(int64_t delay_ms) { time_system_.sleep(std::chrono::milliseconds(delay_ms)); - base_scheduler_.run(Dispatcher::RunType::NonBlock); + dispatcher_->run(Dispatcher::RunType::NonBlock); } protected: Event::SimulatedTimeSystemHelper time_system_; + Api::ApiPtr api_; + Event::DispatcherPtr dispatcher_; EnvoyQuicClock clock_; - Event::LibeventScheduler base_scheduler_; - Event::SchedulerPtr scheduler_; EnvoyQuicAlarmFactory alarm_factory_; quic::QuicConnectionArena arena_; }; @@ -157,7 +156,7 @@ TEST_F(EnvoyQuicAlarmTest, SetAlarmToPastTime) { // alarm becomes active upon Set(). alarm->Set(clock_.Now() - QuicTime::Delta::FromMilliseconds(10)); EXPECT_FALSE(unowned_delegate->fired()); - base_scheduler_.run(Dispatcher::RunType::NonBlock); + dispatcher_->run(Dispatcher::RunType::NonBlock); EXPECT_TRUE(unowned_delegate->fired()); } @@ -170,7 +169,7 @@ TEST_F(EnvoyQuicAlarmTest, UpdateAlarmWithPastDeadline) { EXPECT_FALSE(unowned_delegate->fired()); // alarm becomes active upon Update(). alarm->Update(clock_.Now() - QuicTime::Delta::FromMilliseconds(1), quic::QuicTime::Delta::Zero()); - base_scheduler_.run(Dispatcher::RunType::NonBlock); + dispatcher_->run(Dispatcher::RunType::NonBlock); EXPECT_TRUE(unowned_delegate->fired()); unowned_delegate->set_fired(false); advanceMsAndLoop(1); @@ -186,7 +185,7 @@ TEST_F(EnvoyQuicAlarmTest, CancelActiveAlarm) { // alarm becomes active upon Set(). alarm->Set(clock_.Now() - QuicTime::Delta::FromMilliseconds(10)); alarm->Cancel(); - base_scheduler_.run(Dispatcher::RunType::NonBlock); + dispatcher_->run(Dispatcher::RunType::NonBlock); EXPECT_FALSE(unowned_delegate->fired()); } diff --git a/test/extensions/quic_listeners/quiche/platform/BUILD b/test/extensions/quic_listeners/quiche/platform/BUILD index 911943c915ce..1383cfbfbb17 100644 --- a/test/extensions/quic_listeners/quiche/platform/BUILD +++ b/test/extensions/quic_listeners/quiche/platform/BUILD @@ -221,5 +221,6 @@ envoy_cc_test( "//source/extensions/quic_listeners/quiche/platform:envoy_quic_clock_lib", "//test/test_common:simulated_time_system_lib", "//test/test_common:test_time_lib", + "//test/test_common:utility_lib", ], ) diff --git a/test/extensions/quic_listeners/quiche/platform/envoy_quic_clock_test.cc b/test/extensions/quic_listeners/quiche/platform/envoy_quic_clock_test.cc index 8bdf8a987512..2a14f28b5217 100644 --- a/test/extensions/quic_listeners/quiche/platform/envoy_quic_clock_test.cc +++ b/test/extensions/quic_listeners/quiche/platform/envoy_quic_clock_test.cc @@ -4,6 +4,7 @@ #include "test/test_common/simulated_time_system.h" #include "test/test_common/test_time.h" +#include "test/test_common/utility.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -13,7 +14,9 @@ namespace Quic { TEST(EnvoyQuicClockTest, TestNow) { Event::SimulatedTimeSystemHelper time_system; - EnvoyQuicClock clock(time_system); + Api::ApiPtr api = Api::createApiForTest(time_system); + Event::DispatcherPtr dispatcher = api->allocateDispatcher(); + EnvoyQuicClock clock(*dispatcher); uint64_t mono_time = std::chrono::duration_cast( time_system.monotonicTime().time_since_epoch()) .count(); @@ -41,7 +44,9 @@ TEST(EnvoyQuicClockTest, TestNow) { // Tests that Now() should never go back. TEST(EnvoyQuicClockTest, TestMonotonicityWithReadTimeSystem) { Event::TestRealTimeSystem time_system; - EnvoyQuicClock clock(time_system); + Api::ApiPtr api = Api::createApiForTest(time_system); + Event::DispatcherPtr dispatcher = api->allocateDispatcher(); + EnvoyQuicClock clock(*dispatcher); quic::QuicTime last_now = clock.Now(); for (int i = 0; i < 1000; ++i) { quic::QuicTime now = clock.Now(); diff --git a/test/extensions/quic_listeners/quiche/platform/quic_epoll_clock.h b/test/extensions/quic_listeners/quiche/platform/quic_epoll_clock.h index fc605c9a2611..f1446dbb4bee 100644 --- a/test/extensions/quic_listeners/quiche/platform/quic_epoll_clock.h +++ b/test/extensions/quic_listeners/quiche/platform/quic_epoll_clock.h @@ -21,7 +21,7 @@ class QuicEpollClock : public QuicClock { QuicEpollClock(const QuicEpollClock&) = delete; QuicEpollClock& operator=(const QuicEpollClock&) = delete; - ~QuicEpollClock() override {} + ~QuicEpollClock() override = default; // Returns the approximate current time as a QuicTime object. QuicTime ApproximateNow() const override; diff --git a/test/extensions/quic_listeners/quiche/platform/quic_mock_log_impl.h b/test/extensions/quic_listeners/quiche/platform/quic_mock_log_impl.h index b57b9fe48ffc..f5cdc5e74499 100644 --- a/test/extensions/quic_listeners/quiche/platform/quic_mock_log_impl.h +++ b/test/extensions/quic_listeners/quiche/platform/quic_mock_log_impl.h @@ -19,9 +19,9 @@ namespace quic { // destruction(or StopCapturingLogs()). class QuicEnvoyMockLog : public QuicLogSink { public: - QuicEnvoyMockLog() : is_capturing_(false) {} + QuicEnvoyMockLog() = default; - virtual ~QuicEnvoyMockLog() { + ~QuicEnvoyMockLog() override { if (is_capturing_) { StopCapturingLogs(); } @@ -43,7 +43,7 @@ class QuicEnvoyMockLog : public QuicLogSink { private: QuicLogSink* original_sink_; - bool is_capturing_; + bool is_capturing_{false}; }; // ScopedDisableExitOnDFatal is used to disable exiting the program when we encounter a diff --git a/test/extensions/quic_listeners/quiche/platform/quic_platform_test.cc b/test/extensions/quic_listeners/quiche/platform/quic_platform_test.cc index 8fcb0ff33365..1fce91d5148b 100644 --- a/test/extensions/quic_listeners/quiche/platform/quic_platform_test.cc +++ b/test/extensions/quic_listeners/quiche/platform/quic_platform_test.cc @@ -85,7 +85,7 @@ class QuicPlatformTest : public testing::Test { GetLogger().set_level(ERROR); } - ~QuicPlatformTest() { + ~QuicPlatformTest() override { SetVerbosityLogThreshold(verbosity_log_threshold_); GetLogger().set_level(log_level_); } @@ -361,6 +361,18 @@ TEST_F(QuicPlatformTest, QuicLog) { #define VALUE_BY_COMPILE_MODE(debug_mode_value, release_mode_value) debug_mode_value #endif +TEST_F(QuicPlatformTest, LogIoManipulators) { + GetLogger().set_level(ERROR); + QUIC_DLOG(ERROR) << "aaaa" << std::endl; + EXPECT_LOG_CONTAINS("error", "aaaa\n\n", QUIC_LOG(ERROR) << "aaaa" << std::endl << std::endl); + EXPECT_LOG_NOT_CONTAINS("error", "aaaa\n\n\n", + QUIC_LOG(ERROR) << "aaaa" << std::endl + << std::endl); + + EXPECT_LOG_CONTAINS("error", "42 in octal is 52", + QUIC_LOG(ERROR) << 42 << " in octal is " << std::oct << 42); +} + TEST_F(QuicPlatformTest, QuicDLog) { int i = 0; @@ -726,7 +738,7 @@ TEST_F(QuicPlatformTest, TestQuicOptional) { class QuicMemSliceTest : public Envoy::Buffer::BufferImplementationParamTest { public: - ~QuicMemSliceTest() override {} + ~QuicMemSliceTest() override = default; }; INSTANTIATE_TEST_SUITE_P(QuicMemSliceTests, QuicMemSliceTest, diff --git a/test/extensions/resource_monitors/fixed_heap/fixed_heap_monitor_test.cc b/test/extensions/resource_monitors/fixed_heap/fixed_heap_monitor_test.cc index 697e556590cf..d8c82b845017 100644 --- a/test/extensions/resource_monitors/fixed_heap/fixed_heap_monitor_test.cc +++ b/test/extensions/resource_monitors/fixed_heap/fixed_heap_monitor_test.cc @@ -12,7 +12,7 @@ namespace { class MockMemoryStatsReader : public MemoryStatsReader { public: - MockMemoryStatsReader() {} + MockMemoryStatsReader() = default; MOCK_METHOD0(reservedHeapBytes, uint64_t()); MOCK_METHOD0(unmappedHeapBytes, uint64_t()); diff --git a/test/extensions/stats_sinks/metrics_service/grpc_metrics_service_impl_test.cc b/test/extensions/stats_sinks/metrics_service/grpc_metrics_service_impl_test.cc index 30fabc69b5f2..4ed180c0a05f 100644 --- a/test/extensions/stats_sinks/metrics_service/grpc_metrics_service_impl_test.cc +++ b/test/extensions/stats_sinks/metrics_service/grpc_metrics_service_impl_test.cc @@ -91,7 +91,7 @@ class TestGrpcMetricsStreamer : public GrpcMetricsStreamer { public: int metric_count; // GrpcMetricsStreamer - void send(envoy::service::metrics::v2::StreamMetricsMessage& message) { + void send(envoy::service::metrics::v2::StreamMetricsMessage& message) override { metric_count = message.envoy_metrics_size(); } }; diff --git a/test/extensions/tracers/opencensus/BUILD b/test/extensions/tracers/opencensus/BUILD index d4d7d4cfb079..03b343f5884b 100644 --- a/test/extensions/tracers/opencensus/BUILD +++ b/test/extensions/tracers/opencensus/BUILD @@ -19,6 +19,7 @@ envoy_extension_cc_test( deps = [ "//source/extensions/tracers/opencensus:opencensus_tracer_impl", "//test/mocks/http:http_mocks", + "//test/mocks/local_info:local_info_mocks", "//test/mocks/tracing:tracing_mocks", ], ) diff --git a/test/extensions/tracers/opencensus/config_test.cc b/test/extensions/tracers/opencensus/config_test.cc index 31442eee7007..1f549cd4afb1 100644 --- a/test/extensions/tracers/opencensus/config_test.cc +++ b/test/extensions/tracers/opencensus/config_test.cc @@ -50,7 +50,6 @@ TEST(OpenCensusTracerConfigTest, OpenCensusHttpTracerWithTypedConfig) { stackdriver_project_id: test_project_id zipkin_exporter_enabled: true zipkin_url: http://127.0.0.1:9411/api/v2/spans - zipkin_service_name: test_service incoming_trace_context: trace_context incoming_trace_context: grpc_trace_bin incoming_trace_context: cloud_trace_context diff --git a/test/extensions/tracers/opencensus/tracer_test.cc b/test/extensions/tracers/opencensus/tracer_test.cc index a223b08e3be5..2c7cf5695fec 100644 --- a/test/extensions/tracers/opencensus/tracer_test.cc +++ b/test/extensions/tracers/opencensus/tracer_test.cc @@ -12,6 +12,7 @@ #include "extensions/tracers/opencensus/opencensus_tracer_impl.h" #include "test/mocks/http/mocks.h" +#include "test/mocks/local_info/mocks.h" #include "test/mocks/tracing/mocks.h" #include "gmock/gmock.h" @@ -101,7 +102,8 @@ void registerSpanCatcher() { TEST(OpenCensusTracerTest, Span) { registerSpanCatcher(); OpenCensusConfig oc_config; - std::unique_ptr driver(new OpenCensus::Driver(oc_config)); + NiceMock local_info; + std::unique_ptr driver(new OpenCensus::Driver(oc_config, local_info)); NiceMock config; Http::TestHeaderMapImpl request_headers{ @@ -132,18 +134,17 @@ TEST(OpenCensusTracerTest, Span) { const auto& sd = (spans[0].name() == operation_name) ? spans[0] : spans[1]; ENVOY_LOG_MISC(debug, "{}", sd.DebugString()); - EXPECT_EQ("my_operation_1", sd.name()); + EXPECT_EQ("different_name", sd.name()); EXPECT_TRUE(sd.context().IsValid()); EXPECT_TRUE(sd.context().trace_options().IsSampled()); ::opencensus::trace::SpanId zeros; EXPECT_EQ(zeros, sd.parent_span_id()); parent_span_id = sd.context().span_id(); - ASSERT_EQ(4, sd.annotations().events().size()); - EXPECT_EQ("setOperation", sd.annotations().events()[0].event().description()); - EXPECT_EQ("my annotation", sd.annotations().events()[1].event().description()); - EXPECT_EQ("spawnChild", sd.annotations().events()[2].event().description()); - EXPECT_EQ("setSampled", sd.annotations().events()[3].event().description()); + ASSERT_EQ(3, sd.annotations().events().size()); + EXPECT_EQ("my annotation", sd.annotations().events()[0].event().description()); + EXPECT_EQ("spawnChild", sd.annotations().events()[1].event().description()); + EXPECT_EQ("setSampled", sd.annotations().events()[2].event().description()); EXPECT_TRUE(sd.has_ended()); } @@ -166,6 +167,7 @@ TEST(OpenCensusTracerTest, PropagateTraceContext) { // The test calls the helper with each kind of incoming context in turn. auto helper = [](const std::string& header, const std::string& value) { OpenCensusConfig oc_config; + NiceMock local_info; oc_config.add_incoming_trace_context(OpenCensusConfig::NONE); oc_config.add_incoming_trace_context(OpenCensusConfig::TRACE_CONTEXT); oc_config.add_incoming_trace_context(OpenCensusConfig::GRPC_TRACE_BIN); @@ -174,7 +176,7 @@ TEST(OpenCensusTracerTest, PropagateTraceContext) { oc_config.add_outgoing_trace_context(OpenCensusConfig::TRACE_CONTEXT); oc_config.add_outgoing_trace_context(OpenCensusConfig::GRPC_TRACE_BIN); oc_config.add_outgoing_trace_context(OpenCensusConfig::CLOUD_TRACE_CONTEXT); - std::unique_ptr driver(new OpenCensus::Driver(oc_config)); + std::unique_ptr driver(new OpenCensus::Driver(oc_config, local_info)); NiceMock config; Http::TestHeaderMapImpl request_headers{ {":path", "/"}, @@ -239,7 +241,8 @@ namespace { // the exporter (either zero or one). int SamplerTestHelper(const OpenCensusConfig& oc_config) { registerSpanCatcher(); - std::unique_ptr driver(new OpenCensus::Driver(oc_config)); + NiceMock local_info; + std::unique_ptr driver(new OpenCensus::Driver(oc_config, local_info)); auto span = ::opencensus::trace::Span::StartSpan("test_span"); span.End(); // Retrieve SpanData from the OpenCensus trace exporter. diff --git a/test/extensions/tracers/zipkin/tracer_test.cc b/test/extensions/tracers/zipkin/tracer_test.cc index 0b1de42b7221..04fdbe3e07b4 100644 --- a/test/extensions/tracers/zipkin/tracer_test.cc +++ b/test/extensions/tracers/zipkin/tracer_test.cc @@ -28,7 +28,7 @@ namespace { class TestReporterImpl : public Reporter { public: TestReporterImpl(int value) : value_(value) {} - void reportSpan(const Span& span) { reported_spans_.push_back(span); } + void reportSpan(const Span& span) override { reported_spans_.push_back(span); } int getValue() { return value_; } std::vector& reportedSpans() { return reported_spans_; } diff --git a/test/extensions/transport_sockets/alts/noop_transport_socket_callbacks_test.cc b/test/extensions/transport_sockets/alts/noop_transport_socket_callbacks_test.cc index 2ba6dc28f4ad..507448d70d47 100644 --- a/test/extensions/transport_sockets/alts/noop_transport_socket_callbacks_test.cc +++ b/test/extensions/transport_sockets/alts/noop_transport_socket_callbacks_test.cc @@ -19,7 +19,7 @@ class TestTransportSocketCallbacks : public Network::TransportSocketCallbacks { explicit TestTransportSocketCallbacks(Network::Connection& connection) : io_handle_(std::make_unique()), connection_(connection) {} - ~TestTransportSocketCallbacks() override {} + ~TestTransportSocketCallbacks() override = default; Network::IoHandle& ioHandle() override { return *io_handle_; } const Network::IoHandle& ioHandle() const override { return *io_handle_; } Network::Connection& connection() override { return connection_; } diff --git a/test/extensions/transport_sockets/tls/BUILD b/test/extensions/transport_sockets/tls/BUILD index 0d5e5f67735b..32ec88bb3d58 100644 --- a/test/extensions/transport_sockets/tls/BUILD +++ b/test/extensions/transport_sockets/tls/BUILD @@ -17,9 +17,13 @@ envoy_cc_test( ], data = [ "gen_unittest_certs.sh", + # TODO(mattklein123): We should consolidate all of our test certs in a single place as + # right now we have a bunch of duplication which is confusing. + "//test/config/integration/certs", "//test/extensions/transport_sockets/tls/test_data:certs", ], external_deps = ["ssl"], + shard_count = 4, deps = [ "//include/envoy/network:transport_socket_interface", "//source/common/buffer:buffer_lib", diff --git a/test/extensions/transport_sockets/tls/context_impl_test.cc b/test/extensions/transport_sockets/tls/context_impl_test.cc index f987590cfae2..ef82b26fff43 100644 --- a/test/extensions/transport_sockets/tls/context_impl_test.cc +++ b/test/extensions/transport_sockets/tls/context_impl_test.cc @@ -286,8 +286,8 @@ TEST_F(SslContextImplTest, TestGetCertInformationWithExpiration) { } TEST_F(SslContextImplTest, TestNoCert) { - Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString("{}"); - ClientContextConfigImpl cfg(*loader, factory_context_); + envoy::api::v2::auth::UpstreamTlsContext config; + ClientContextConfigImpl cfg(config, factory_context_); Envoy::Ssl::ClientContextSharedPtr context(manager_.createSslClientContext(store_, cfg)); EXPECT_EQ(nullptr, context->getCaCertInformation()); EXPECT_TRUE(context->getCertChainInformation().empty()); @@ -748,9 +748,11 @@ TEST_F(ClientContextConfigImplTest, SecretNotReady) { NiceMock local_info; Stats::IsolatedStoreImpl stats; NiceMock init_manager; + NiceMock dispatcher; EXPECT_CALL(factory_context_, localInfo()).WillOnce(ReturnRef(local_info)); EXPECT_CALL(factory_context_, stats()).WillOnce(ReturnRef(stats)); EXPECT_CALL(factory_context_, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(factory_context_, dispatcher()).WillOnce(ReturnRef(dispatcher)); auto sds_secret_configs = tls_context.mutable_common_tls_context()->mutable_tls_certificate_sds_secret_configs()->Add(); sds_secret_configs->set_name("abc.com"); @@ -778,9 +780,11 @@ TEST_F(ClientContextConfigImplTest, ValidationContextNotReady) { NiceMock local_info; Stats::IsolatedStoreImpl stats; NiceMock init_manager; + NiceMock dispatcher; EXPECT_CALL(factory_context_, localInfo()).WillOnce(ReturnRef(local_info)); EXPECT_CALL(factory_context_, stats()).WillOnce(ReturnRef(stats)); EXPECT_CALL(factory_context_, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(factory_context_, dispatcher()).WillOnce(ReturnRef(dispatcher)); auto sds_secret_configs = tls_context.mutable_common_tls_context()->mutable_validation_context_sds_secret_config(); sds_secret_configs->set_name("abc.com"); @@ -1079,9 +1083,11 @@ TEST_F(ServerContextConfigImplTest, SecretNotReady) { NiceMock local_info; Stats::IsolatedStoreImpl stats; NiceMock init_manager; + NiceMock dispatcher; EXPECT_CALL(factory_context_, localInfo()).WillOnce(ReturnRef(local_info)); EXPECT_CALL(factory_context_, stats()).WillOnce(ReturnRef(stats)); EXPECT_CALL(factory_context_, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(factory_context_, dispatcher()).WillOnce(ReturnRef(dispatcher)); auto sds_secret_configs = tls_context.mutable_common_tls_context()->mutable_tls_certificate_sds_secret_configs()->Add(); sds_secret_configs->set_name("abc.com"); @@ -1109,9 +1115,11 @@ TEST_F(ServerContextConfigImplTest, ValidationContextNotReady) { NiceMock local_info; Stats::IsolatedStoreImpl stats; NiceMock init_manager; + NiceMock dispatcher; EXPECT_CALL(factory_context_, localInfo()).WillOnce(ReturnRef(local_info)); EXPECT_CALL(factory_context_, stats()).WillOnce(ReturnRef(stats)); EXPECT_CALL(factory_context_, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(factory_context_, dispatcher()).WillOnce(ReturnRef(dispatcher)); auto sds_secret_configs = tls_context.mutable_common_tls_context()->mutable_validation_context_sds_secret_config(); sds_secret_configs->set_name("abc.com"); diff --git a/test/extensions/transport_sockets/tls/ssl_socket_test.cc b/test/extensions/transport_sockets/tls/ssl_socket_test.cc index f7395a7a518e..07daedca6ca0 100644 --- a/test/extensions/transport_sockets/tls/ssl_socket_test.cc +++ b/test/extensions/transport_sockets/tls/ssl_socket_test.cc @@ -879,6 +879,52 @@ TEST_P(SslSocketTest, GetUriWithUriSan) { .setExpectedSerialNumber(TEST_SAN_URI_CERT_SERIAL)); } +// Verify that IP SANs work with an IPv4 address specified in the validation context. +TEST_P(SslSocketTest, Ipv4San) { + const std::string client_ctx_yaml = R"EOF( + common_tls_context: + validation_context: + trusted_ca: + filename: "{{ test_rundir }}/test/config/integration/certs/upstreamcacert.pem" + verify_subject_alt_name: "127.0.0.1" +)EOF"; + + const std::string server_ctx_yaml = R"EOF( + common_tls_context: + tls_certificates: + certificate_chain: + filename: "{{ test_rundir }}/test/config/integration/certs/upstreamlocalhostcert.pem" + private_key: + filename: "{{ test_rundir }}/test/config/integration/certs/upstreamlocalhostkey.pem" +)EOF"; + + TestUtilOptions test_options(client_ctx_yaml, server_ctx_yaml, true, GetParam()); + testUtil(test_options); +} + +// Verify that IP SANs work with an IPv6 address specified in the validation context. +TEST_P(SslSocketTest, Ipv6San) { + const std::string client_ctx_yaml = R"EOF( + common_tls_context: + validation_context: + trusted_ca: + filename: "{{ test_rundir }}/test/config/integration/certs/upstreamcacert.pem" + verify_subject_alt_name: "::1" +)EOF"; + + const std::string server_ctx_yaml = R"EOF( + common_tls_context: + tls_certificates: + certificate_chain: + filename: "{{ test_rundir }}/test/config/integration/certs/upstreamlocalhostcert.pem" + private_key: + filename: "{{ test_rundir }}/test/config/integration/certs/upstreamlocalhostkey.pem" +)EOF"; + + TestUtilOptions test_options(client_ctx_yaml, server_ctx_yaml, true, GetParam()); + testUtil(test_options); +} + TEST_P(SslSocketTest, GetNoUriWithDnsSan) { const std::string client_ctx_yaml = R"EOF( common_tls_context: @@ -3710,6 +3756,8 @@ TEST_P(SslSocketTest, DownstreamNotReadySslSocket) { NiceMock local_info; testing::NiceMock factory_context; NiceMock init_manager; + NiceMock dispatcher; + EXPECT_CALL(factory_context, dispatcher()).WillOnce(ReturnRef(dispatcher)); EXPECT_CALL(factory_context, localInfo()).WillOnce(ReturnRef(local_info)); EXPECT_CALL(factory_context, stats()).WillOnce(ReturnRef(stats_store)); EXPECT_CALL(factory_context, initManager()).WillRepeatedly(Return(&init_manager)); @@ -3744,9 +3792,11 @@ TEST_P(SslSocketTest, UpstreamNotReadySslSocket) { NiceMock local_info; testing::NiceMock factory_context; NiceMock init_manager; + NiceMock dispatcher; EXPECT_CALL(factory_context, localInfo()).WillOnce(ReturnRef(local_info)); EXPECT_CALL(factory_context, stats()).WillOnce(ReturnRef(stats_store)); EXPECT_CALL(factory_context, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(factory_context, dispatcher()).WillOnce(ReturnRef(dispatcher)); envoy::api::v2::auth::UpstreamTlsContext tls_context; auto sds_secret_configs = diff --git a/test/fuzz/utility.h b/test/fuzz/utility.h index 0f869149e2bf..155226aa026c 100644 --- a/test/fuzz/utility.h +++ b/test/fuzz/utility.h @@ -52,6 +52,23 @@ inline Protobuf::RepeatedPtrField repla return processed; } +inline envoy::api::v2::core::Metadata +replaceInvalidStringValues(const envoy::api::v2::core::Metadata& upstream_metadata) { + envoy::api::v2::core::Metadata processed = upstream_metadata; + for (auto& metadata_struct : *processed.mutable_filter_metadata()) { + // Metadata fields consist of keyed Structs, which is a map of dynamically typed values. These + // values can be null, a number, a string, a boolean, a list of values, or a recursive struct. + // This clears any invalid characters in string values. It may not be likely a coverage-driven + // fuzzer will explore recursive structs, so this case is not handled here. + for (auto& field : *metadata_struct.second.mutable_fields()) { + if (field.second.kind_case() == ProtobufWkt::Value::kStringValue) { + field.second.set_string_value(replaceInvalidCharacters(field.second.string_value())); + } + } + } + return processed; +} + // Convert from test proto Headers to TestHeaderMapImpl. inline Http::TestHeaderMapImpl fromHeaders( const test::fuzz::Headers& headers, @@ -103,8 +120,8 @@ inline TestStreamInfo fromStreamInfo(const test::fuzz::StreamInfo& stream_info, test_stream_info.response_code_ = stream_info.response_code().value(); } auto upstream_host = std::make_shared>(); - auto upstream_metadata = - std::make_shared(stream_info.upstream_metadata()); + auto upstream_metadata = std::make_shared( + replaceInvalidStringValues(stream_info.upstream_metadata())); ON_CALL(*upstream_host, metadata()).WillByDefault(testing::Return(upstream_metadata)); test_stream_info.upstream_host_ = upstream_host; auto address = Network::Utility::resolveUrl("tcp://10.0.0.1:443"); diff --git a/test/integration/BUILD b/test/integration/BUILD index 708030bc66fb..d00ef6ca405a 100644 --- a/test/integration/BUILD +++ b/test/integration/BUILD @@ -17,9 +17,14 @@ load( envoy_package() -envoy_cc_test( - name = "ads_integration_test", - srcs = ["ads_integration_test.cc"], +envoy_cc_test_library( + name = "ads_integration_lib", + srcs = [ + "ads_integration.cc", + ], + hdrs = [ + "ads_integration.h", + ], data = [ "//test/config/integration/certs", ], @@ -28,13 +33,28 @@ envoy_cc_test( "//source/common/config:protobuf_link_hacks", "//source/common/config:resources_lib", "//source/common/protobuf:utility_lib", - "//source/extensions/transport_sockets/tls:config", - "//source/extensions/transport_sockets/tls:context_config_lib", - "//source/extensions/transport_sockets/tls:context_lib", - "//source/extensions/transport_sockets/tls:ssl_socket_lib", "//test/common/grpc:grpc_client_integration_lib", - "//test/mocks/runtime:runtime_mocks", - "//test/mocks/server:server_mocks", + "//test/test_common:network_utility_lib", + "//test/test_common:utility_lib", + "@envoy_api//envoy/api/v2:cds_cc", + "@envoy_api//envoy/api/v2:discovery_cc", + "@envoy_api//envoy/api/v2:eds_cc", + "@envoy_api//envoy/api/v2:lds_cc", + "@envoy_api//envoy/api/v2:rds_cc", + "@envoy_api//envoy/service/discovery/v2:ads_cc", + ], +) + +envoy_cc_test( + name = "ads_integration_test", + srcs = ["ads_integration_test.cc"], + deps = [ + ":ads_integration_lib", + ":http_integration_lib", + "//source/common/config:protobuf_link_hacks", + "//source/common/config:resources_lib", + "//source/common/protobuf:utility_lib", + "//test/common/grpc:grpc_client_integration_lib", "//test/test_common:network_utility_lib", "//test/test_common:utility_lib", "@envoy_api//envoy/api/v2:cds_cc", @@ -121,6 +141,18 @@ envoy_cc_test( ], ) +envoy_cc_test( + name = "cluster_filter_integration_test", + srcs = ["cluster_filter_integration_test.cc"], + deps = [ + ":integration_lib", + "//include/envoy/network:filter_interface", + "//include/envoy/registry", + "//source/extensions/filters/network/tcp_proxy:config", + "//test/config:utility_lib", + ], +) + envoy_cc_test( name = "custom_cluster_integration_test", srcs = ["custom_cluster_integration_test.cc"], @@ -398,6 +430,7 @@ envoy_cc_test_library( "//source/common/network:filter_lib", "//source/common/network:listen_socket_lib", "//source/common/network:utility_lib", + "//source/common/runtime:runtime_lib", "//source/common/stats:isolated_store_lib", "//source/common/stats:thread_local_store_lib", "//source/common/thread_local:thread_local_lib", diff --git a/test/integration/ads_integration.cc b/test/integration/ads_integration.cc new file mode 100644 index 000000000000..a950bc8e5899 --- /dev/null +++ b/test/integration/ads_integration.cc @@ -0,0 +1,280 @@ +#include "test/integration/ads_integration.h" + +#include "envoy/api/v2/cds.pb.h" +#include "envoy/api/v2/discovery.pb.h" +#include "envoy/api/v2/eds.pb.h" +#include "envoy/api/v2/lds.pb.h" +#include "envoy/api/v2/rds.pb.h" + +#include "common/config/protobuf_link_hacks.h" +#include "common/config/resources.h" +#include "common/protobuf/protobuf.h" +#include "common/protobuf/utility.h" + +#include "test/test_common/network_utility.h" +#include "test/test_common/utility.h" + +using testing::AssertionFailure; +using testing::AssertionResult; +using testing::AssertionSuccess; +using testing::IsSubstring; + +namespace Envoy { + +AdsIntegrationTest::AdsIntegrationTest() + : HttpIntegrationTest(Http::CodecClient::Type::HTTP2, ipVersion(), AdsIntegrationConfig()) { + use_lds_ = false; + create_xds_upstream_ = true; + tls_xds_upstream_ = true; +} + +void AdsIntegrationTest::TearDown() { + cleanUpXdsConnection(); + test_server_.reset(); + fake_upstreams_.clear(); +} + +envoy::api::v2::Cluster AdsIntegrationTest::buildCluster(const std::string& name) { + return TestUtility::parseYaml(fmt::format(R"EOF( + name: {} + connect_timeout: 5s + type: EDS + eds_cluster_config: {{ eds_config: {{ ads: {{}} }} }} + lb_policy: ROUND_ROBIN + http2_protocol_options: {{}} + )EOF", + name)); +} + +envoy::api::v2::ClusterLoadAssignment +AdsIntegrationTest::buildClusterLoadAssignment(const std::string& name) { + return TestUtility::parseYaml( + fmt::format(R"EOF( + cluster_name: {} + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: {} + port_value: {} + )EOF", + name, Network::Test::getLoopbackAddressString(ipVersion()), + fake_upstreams_[0]->localAddress()->ip()->port())); +} + +envoy::api::v2::Listener AdsIntegrationTest::buildListener(const std::string& name, + const std::string& route_config, + const std::string& stat_prefix) { + return TestUtility::parseYaml(fmt::format( + R"EOF( + name: {} + address: + socket_address: + address: {} + port_value: 0 + filter_chains: + filters: + - name: envoy.http_connection_manager + config: + stat_prefix: {} + codec_type: HTTP2 + rds: + route_config_name: {} + config_source: {{ ads: {{}} }} + http_filters: [{{ name: envoy.router }}] + )EOF", + name, Network::Test::getLoopbackAddressString(ipVersion()), stat_prefix, route_config)); +} + +envoy::api::v2::RouteConfiguration +AdsIntegrationTest::buildRouteConfig(const std::string& name, const std::string& cluster) { + return TestUtility::parseYaml(fmt::format(R"EOF( + name: {} + virtual_hosts: + - name: integration + domains: ["*"] + routes: + - match: {{ prefix: "/" }} + route: {{ cluster: {} }} + )EOF", + name, cluster)); +} + +void AdsIntegrationTest::makeSingleRequest() { + registerTestServerPorts({"http"}); + testRouterHeaderOnlyRequestAndResponse(); + cleanupUpstreamAndDownstream(); +} + +void AdsIntegrationTest::initialize() { initializeAds(false); } + +void AdsIntegrationTest::initializeAds(const bool rate_limiting) { + config_helper_.addConfigModifier([this, &rate_limiting]( + envoy::config::bootstrap::v2::Bootstrap& bootstrap) { + auto* ads_config = bootstrap.mutable_dynamic_resources()->mutable_ads_config(); + if (rate_limiting) { + ads_config->mutable_rate_limit_settings(); + } + auto* grpc_service = ads_config->add_grpc_services(); + setGrpcService(*grpc_service, "ads_cluster", xds_upstream_->localAddress()); + auto* ads_cluster = bootstrap.mutable_static_resources()->add_clusters(); + ads_cluster->MergeFrom(bootstrap.static_resources().clusters()[0]); + ads_cluster->set_name("ads_cluster"); + auto* context = ads_cluster->mutable_tls_context(); + auto* validation_context = context->mutable_common_tls_context()->mutable_validation_context(); + validation_context->mutable_trusted_ca()->set_filename( + TestEnvironment::runfilesPath("test/config/integration/certs/upstreamcacert.pem")); + validation_context->add_verify_subject_alt_name("foo.lyft.com"); + if (clientType() == Grpc::ClientType::GoogleGrpc) { + auto* google_grpc = grpc_service->mutable_google_grpc(); + auto* ssl_creds = google_grpc->mutable_channel_credentials()->mutable_ssl_credentials(); + ssl_creds->mutable_root_certs()->set_filename( + TestEnvironment::runfilesPath("test/config/integration/certs/upstreamcacert.pem")); + } + }); + setUpstreamProtocol(FakeHttpConnection::Type::HTTP2); + HttpIntegrationTest::initialize(); + if (xds_stream_ == nullptr) { + createXdsConnection(); + AssertionResult result = xds_connection_->waitForNewStream(*dispatcher_, xds_stream_); + RELEASE_ASSERT(result, result.message()); + xds_stream_->startGrpcStream(); + } +} + +void AdsIntegrationTest::testBasicFlow() { + // Send initial configuration, validate we can process a request. + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "", {}, {}, {})); + sendDiscoveryResponse(Config::TypeUrl::get().Cluster, + {buildCluster("cluster_0")}, + {buildCluster("cluster_0")}, {}, "1"); + + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().ClusterLoadAssignment, "", + {"cluster_0"}, {"cluster_0"}, {})); + sendDiscoveryResponse( + Config::TypeUrl::get().ClusterLoadAssignment, {buildClusterLoadAssignment("cluster_0")}, + {buildClusterLoadAssignment("cluster_0")}, {}, "1"); + + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "1", {}, {}, {})); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Listener, "", {}, {}, {})); + sendDiscoveryResponse( + Config::TypeUrl::get().Listener, {buildListener("listener_0", "route_config_0")}, + {buildListener("listener_0", "route_config_0")}, {}, "1"); + + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().ClusterLoadAssignment, "1", + {"cluster_0"}, {}, {})); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().RouteConfiguration, "", + {"route_config_0"}, {"route_config_0"}, {})); + sendDiscoveryResponse( + Config::TypeUrl::get().RouteConfiguration, {buildRouteConfig("route_config_0", "cluster_0")}, + {buildRouteConfig("route_config_0", "cluster_0")}, {}, "1"); + + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Listener, "1", {}, {}, {})); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().RouteConfiguration, "1", + {"route_config_0"}, {}, {})); + + test_server_->waitForCounterGe("listener_manager.listener_create_success", 1); + makeSingleRequest(); + const ProtobufWkt::Timestamp first_active_listener_ts_1 = + getListenersConfigDump().dynamic_active_listeners()[0].last_updated(); + const ProtobufWkt::Timestamp first_active_cluster_ts_1 = + getClustersConfigDump().dynamic_active_clusters()[0].last_updated(); + const ProtobufWkt::Timestamp first_route_config_ts_1 = + getRoutesConfigDump().dynamic_route_configs()[0].last_updated(); + + // Upgrade RDS/CDS/EDS to a newer config, validate we can process a request. + sendDiscoveryResponse( + Config::TypeUrl::get().Cluster, {buildCluster("cluster_1"), buildCluster("cluster_2")}, + {buildCluster("cluster_1"), buildCluster("cluster_2")}, {"cluster_0"}, "2"); + test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 2); + sendDiscoveryResponse( + Config::TypeUrl::get().ClusterLoadAssignment, + {buildClusterLoadAssignment("cluster_1"), buildClusterLoadAssignment("cluster_2")}, + {buildClusterLoadAssignment("cluster_1"), buildClusterLoadAssignment("cluster_2")}, + {"cluster_0"}, "2"); + test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 0); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().ClusterLoadAssignment, "1", + {"cluster_2", "cluster_1"}, {"cluster_2", "cluster_1"}, + {"cluster_0"})); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "2", {}, {}, {})); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().ClusterLoadAssignment, "2", + {"cluster_2", "cluster_1"}, {}, {})); + sendDiscoveryResponse( + Config::TypeUrl::get().RouteConfiguration, {buildRouteConfig("route_config_0", "cluster_1")}, + {buildRouteConfig("route_config_0", "cluster_1")}, {}, "2"); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().RouteConfiguration, "2", + {"route_config_0"}, {}, {})); + + makeSingleRequest(); + const ProtobufWkt::Timestamp first_active_listener_ts_2 = + getListenersConfigDump().dynamic_active_listeners()[0].last_updated(); + const ProtobufWkt::Timestamp first_active_cluster_ts_2 = + getClustersConfigDump().dynamic_active_clusters()[0].last_updated(); + const ProtobufWkt::Timestamp first_route_config_ts_2 = + getRoutesConfigDump().dynamic_route_configs()[0].last_updated(); + + // Upgrade LDS/RDS, validate we can process a request. + sendDiscoveryResponse(Config::TypeUrl::get().Listener, + {buildListener("listener_1", "route_config_1"), + buildListener("listener_2", "route_config_2")}, + {buildListener("listener_1", "route_config_1"), + buildListener("listener_2", "route_config_2")}, + {"listener_0"}, "2"); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().RouteConfiguration, "2", + {"route_config_2", "route_config_1", "route_config_0"}, + {"route_config_2", "route_config_1"}, {})); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Listener, "2", {}, {}, {})); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().RouteConfiguration, "2", + {"route_config_2", "route_config_1"}, {}, + {"route_config_0"})); + sendDiscoveryResponse( + Config::TypeUrl::get().RouteConfiguration, + {buildRouteConfig("route_config_1", "cluster_1"), + buildRouteConfig("route_config_2", "cluster_1")}, + {buildRouteConfig("route_config_1", "cluster_1"), + buildRouteConfig("route_config_2", "cluster_1")}, + {"route_config_0"}, "3"); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().RouteConfiguration, "3", + {"route_config_2", "route_config_1"}, {}, {})); + + test_server_->waitForCounterGe("listener_manager.listener_create_success", 2); + makeSingleRequest(); + const ProtobufWkt::Timestamp first_active_listener_ts_3 = + getListenersConfigDump().dynamic_active_listeners()[0].last_updated(); + const ProtobufWkt::Timestamp first_active_cluster_ts_3 = + getClustersConfigDump().dynamic_active_clusters()[0].last_updated(); + const ProtobufWkt::Timestamp first_route_config_ts_3 = + getRoutesConfigDump().dynamic_route_configs()[0].last_updated(); + + // Expect last_updated timestamps to be updated in a predictable way + // For the listener configs in this example, 1 == 2 < 3. + EXPECT_EQ(first_active_listener_ts_2, first_active_listener_ts_1); + EXPECT_GT(first_active_listener_ts_3, first_active_listener_ts_2); + // For the cluster configs in this example, 1 < 2 == 3. + EXPECT_GT(first_active_cluster_ts_2, first_active_cluster_ts_1); + EXPECT_EQ(first_active_cluster_ts_3, first_active_cluster_ts_2); + // For the route configs in this example, 1 < 2 < 3. + EXPECT_GT(first_route_config_ts_2, first_route_config_ts_1); + EXPECT_GT(first_route_config_ts_3, first_route_config_ts_2); +} + +envoy::admin::v2alpha::ClustersConfigDump AdsIntegrationTest::getClustersConfigDump() { + auto message_ptr = + test_server_->server().admin().getConfigTracker().getCallbacksMap().at("clusters")(); + return dynamic_cast(*message_ptr); +} + +envoy::admin::v2alpha::ListenersConfigDump AdsIntegrationTest::getListenersConfigDump() { + auto message_ptr = + test_server_->server().admin().getConfigTracker().getCallbacksMap().at("listeners")(); + return dynamic_cast(*message_ptr); +} + +envoy::admin::v2alpha::RoutesConfigDump AdsIntegrationTest::getRoutesConfigDump() { + auto message_ptr = + test_server_->server().admin().getConfigTracker().getCallbacksMap().at("routes")(); + return dynamic_cast(*message_ptr); +} + +} // namespace Envoy diff --git a/test/integration/ads_integration.h b/test/integration/ads_integration.h new file mode 100644 index 000000000000..c03e42e645bf --- /dev/null +++ b/test/integration/ads_integration.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include + +#include "envoy/admin/v2alpha/config_dump.pb.h" +#include "envoy/api/v2/cds.pb.h" +#include "envoy/api/v2/eds.pb.h" +#include "envoy/api/v2/lds.pb.h" +#include "envoy/api/v2/rds.pb.h" + +#include "test/common/grpc/grpc_client_integration.h" +#include "test/integration/http_integration.h" + +namespace Envoy { +static const std::string& AdsIntegrationConfig() { + CONSTRUCT_ON_FIRST_USE(std::string, R"EOF( +dynamic_resources: + lds_config: {ads: {}} + cds_config: {ads: {}} + ads_config: + api_type: GRPC +static_resources: + clusters: + name: dummy_cluster + connect_timeout: { seconds: 5 } + type: STATIC + hosts: + socket_address: + address: 127.0.0.1 + port_value: 0 + lb_policy: ROUND_ROBIN + http2_protocol_options: {} +admin: + access_log_path: /dev/null + address: + socket_address: + address: 127.0.0.1 + port_value: 0 +)EOF"); +} + +class AdsIntegrationTest : public Grpc::GrpcClientIntegrationParamTest, public HttpIntegrationTest { +public: + AdsIntegrationTest(); + + void TearDown() override; + + envoy::api::v2::Cluster buildCluster(const std::string& name); + + envoy::api::v2::ClusterLoadAssignment buildClusterLoadAssignment(const std::string& name); + + envoy::api::v2::Listener buildListener(const std::string& name, const std::string& route_config, + const std::string& stat_prefix = "ads_test"); + + envoy::api::v2::RouteConfiguration buildRouteConfig(const std::string& name, + const std::string& cluster); + + void makeSingleRequest(); + + void initialize() override; + void initializeAds(const bool rate_limiting); + + void testBasicFlow(); + + envoy::admin::v2alpha::ClustersConfigDump getClustersConfigDump(); + envoy::admin::v2alpha::ListenersConfigDump getListenersConfigDump(); + envoy::admin::v2alpha::RoutesConfigDump getRoutesConfigDump(); +}; + +} // namespace Envoy diff --git a/test/integration/ads_integration_test.cc b/test/integration/ads_integration_test.cc index 3745513ee431..e87fdff3f6f4 100644 --- a/test/integration/ads_integration_test.cc +++ b/test/integration/ads_integration_test.cc @@ -7,7 +7,6 @@ #include "envoy/api/v2/route/route.pb.h" #include "envoy/grpc/status.h" #include "envoy/service/discovery/v2/ads.pb.h" -#include "envoy/stats/scope.h" #include "common/config/protobuf_link_hacks.h" #include "common/config/resources.h" @@ -15,11 +14,10 @@ #include "common/protobuf/utility.h" #include "test/common/grpc/grpc_client_integration.h" +#include "test/integration/ads_integration.h" #include "test/integration/http_integration.h" #include "test/integration/utility.h" -#include "test/mocks/server/mocks.h" #include "test/test_common/network_utility.h" -#include "test/test_common/simulated_time_system.h" #include "test/test_common/utility.h" #include "gtest/gtest.h" @@ -30,293 +28,6 @@ using testing::AssertionSuccess; using testing::IsSubstring; namespace Envoy { -namespace { - -const std::string config = R"EOF( -dynamic_resources: - lds_config: {ads: {}} - cds_config: {ads: {}} - ads_config: - api_type: GRPC -static_resources: - clusters: - name: dummy_cluster - connect_timeout: { seconds: 5 } - type: STATIC - hosts: - socket_address: - address: 127.0.0.1 - port_value: 0 - lb_policy: ROUND_ROBIN - http2_protocol_options: {} -admin: - access_log_path: /dev/null - address: - socket_address: - address: 127.0.0.1 - port_value: 0 -)EOF"; - -class AdsIntegrationTest : public Grpc::GrpcClientIntegrationParamTest, public HttpIntegrationTest { -public: - AdsIntegrationTest() : HttpIntegrationTest(Http::CodecClient::Type::HTTP2, ipVersion(), config) { - use_lds_ = false; - create_xds_upstream_ = true; - tls_xds_upstream_ = true; - } - - void TearDown() override { - cleanUpXdsConnection(); - test_server_.reset(); - fake_upstreams_.clear(); - } - - envoy::api::v2::Cluster buildCluster(const std::string& name) { - return TestUtility::parseYaml(fmt::format(R"EOF( - name: {} - connect_timeout: 5s - type: EDS - eds_cluster_config: {{ eds_config: {{ ads: {{}} }} }} - lb_policy: ROUND_ROBIN - http2_protocol_options: {{}} - )EOF", - name)); - } - - envoy::api::v2::ClusterLoadAssignment buildClusterLoadAssignment(const std::string& name) { - return TestUtility::parseYaml( - fmt::format(R"EOF( - cluster_name: {} - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: {} - port_value: {} - )EOF", - name, Network::Test::getLoopbackAddressString(ipVersion()), - fake_upstreams_[0]->localAddress()->ip()->port())); - } - - envoy::api::v2::Listener buildListener(const std::string& name, const std::string& route_config, - const std::string& stat_prefix = "ads_test") { - return TestUtility::parseYaml(fmt::format( - R"EOF( - name: {} - address: - socket_address: - address: {} - port_value: 0 - filter_chains: - filters: - - name: envoy.http_connection_manager - config: - stat_prefix: {} - codec_type: HTTP2 - rds: - route_config_name: {} - config_source: {{ ads: {{}} }} - http_filters: [{{ name: envoy.router }}] - )EOF", - name, Network::Test::getLoopbackAddressString(ipVersion()), stat_prefix, route_config)); - } - - envoy::api::v2::RouteConfiguration buildRouteConfig(const std::string& name, - const std::string& cluster) { - return TestUtility::parseYaml(fmt::format(R"EOF( - name: {} - virtual_hosts: - - name: integration - domains: ["*"] - routes: - - match: {{ prefix: "/" }} - route: {{ cluster: {} }} - )EOF", - name, cluster)); - } - - void makeSingleRequest() { - registerTestServerPorts({"http"}); - testRouterHeaderOnlyRequestAndResponse(); - cleanupUpstreamAndDownstream(); - } - - void initialize() override { initializeAds(false); } - - void initializeAds(const bool rate_limiting) { - config_helper_.addConfigModifier( - [this, &rate_limiting](envoy::config::bootstrap::v2::Bootstrap& bootstrap) { - auto* ads_config = bootstrap.mutable_dynamic_resources()->mutable_ads_config(); - if (rate_limiting) { - ads_config->mutable_rate_limit_settings(); - } - auto* grpc_service = ads_config->add_grpc_services(); - setGrpcService(*grpc_service, "ads_cluster", xds_upstream_->localAddress()); - auto* ads_cluster = bootstrap.mutable_static_resources()->add_clusters(); - ads_cluster->MergeFrom(bootstrap.static_resources().clusters()[0]); - ads_cluster->set_name("ads_cluster"); - auto* context = ads_cluster->mutable_tls_context(); - auto* validation_context = - context->mutable_common_tls_context()->mutable_validation_context(); - validation_context->mutable_trusted_ca()->set_filename( - TestEnvironment::runfilesPath("test/config/integration/certs/upstreamcacert.pem")); - validation_context->add_verify_subject_alt_name("foo.lyft.com"); - if (clientType() == Grpc::ClientType::GoogleGrpc) { - auto* google_grpc = grpc_service->mutable_google_grpc(); - auto* ssl_creds = google_grpc->mutable_channel_credentials()->mutable_ssl_credentials(); - ssl_creds->mutable_root_certs()->set_filename( - TestEnvironment::runfilesPath("test/config/integration/certs/upstreamcacert.pem")); - } - }); - setUpstreamProtocol(FakeHttpConnection::Type::HTTP2); - HttpIntegrationTest::initialize(); - if (xds_stream_ == nullptr) { - createXdsConnection(); - AssertionResult result = xds_connection_->waitForNewStream(*dispatcher_, xds_stream_); - RELEASE_ASSERT(result, result.message()); - xds_stream_->startGrpcStream(); - } - } - - void testBasicFlow() { - // Send initial configuration, validate we can process a request. - EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "", {}, {}, {})); - sendDiscoveryResponse(Config::TypeUrl::get().Cluster, - {buildCluster("cluster_0")}, - {buildCluster("cluster_0")}, {}, "1"); - - EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().ClusterLoadAssignment, "", - {"cluster_0"}, {"cluster_0"}, {})); - sendDiscoveryResponse( - Config::TypeUrl::get().ClusterLoadAssignment, {buildClusterLoadAssignment("cluster_0")}, - {buildClusterLoadAssignment("cluster_0")}, {}, "1"); - - EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "1", {}, {}, {})); - EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Listener, "", {}, {}, {})); - sendDiscoveryResponse( - Config::TypeUrl::get().Listener, {buildListener("listener_0", "route_config_0")}, - {buildListener("listener_0", "route_config_0")}, {}, "1"); - - EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().ClusterLoadAssignment, "1", - {"cluster_0"}, {}, {})); - EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().RouteConfiguration, "", - {"route_config_0"}, {"route_config_0"}, {})); - sendDiscoveryResponse( - Config::TypeUrl::get().RouteConfiguration, - {buildRouteConfig("route_config_0", "cluster_0")}, - {buildRouteConfig("route_config_0", "cluster_0")}, {}, "1"); - - EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Listener, "1", {}, {}, {})); - EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().RouteConfiguration, "1", - {"route_config_0"}, {}, {})); - - test_server_->waitForCounterGe("listener_manager.listener_create_success", 1); - makeSingleRequest(); - const ProtobufWkt::Timestamp first_active_listener_ts_1 = - getListenersConfigDump().dynamic_active_listeners()[0].last_updated(); - const ProtobufWkt::Timestamp first_active_cluster_ts_1 = - getClustersConfigDump().dynamic_active_clusters()[0].last_updated(); - const ProtobufWkt::Timestamp first_route_config_ts_1 = - getRoutesConfigDump().dynamic_route_configs()[0].last_updated(); - - // Upgrade RDS/CDS/EDS to a newer config, validate we can process a request. - sendDiscoveryResponse( - Config::TypeUrl::get().Cluster, {buildCluster("cluster_1"), buildCluster("cluster_2")}, - {buildCluster("cluster_1"), buildCluster("cluster_2")}, {"cluster_0"}, "2"); - test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 2); - sendDiscoveryResponse( - Config::TypeUrl::get().ClusterLoadAssignment, - {buildClusterLoadAssignment("cluster_1"), buildClusterLoadAssignment("cluster_2")}, - {buildClusterLoadAssignment("cluster_1"), buildClusterLoadAssignment("cluster_2")}, - {"cluster_0"}, "2"); - test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 0); - EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().ClusterLoadAssignment, "1", - {"cluster_2", "cluster_1"}, {"cluster_2", "cluster_1"}, - {"cluster_0"})); - EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "2", {}, {}, {})); - EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().ClusterLoadAssignment, "2", - {"cluster_2", "cluster_1"}, {}, {})); - sendDiscoveryResponse( - Config::TypeUrl::get().RouteConfiguration, - {buildRouteConfig("route_config_0", "cluster_1")}, - {buildRouteConfig("route_config_0", "cluster_1")}, {}, "2"); - EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().RouteConfiguration, "2", - {"route_config_0"}, {}, {})); - - makeSingleRequest(); - const ProtobufWkt::Timestamp first_active_listener_ts_2 = - getListenersConfigDump().dynamic_active_listeners()[0].last_updated(); - const ProtobufWkt::Timestamp first_active_cluster_ts_2 = - getClustersConfigDump().dynamic_active_clusters()[0].last_updated(); - const ProtobufWkt::Timestamp first_route_config_ts_2 = - getRoutesConfigDump().dynamic_route_configs()[0].last_updated(); - - // Upgrade LDS/RDS, validate we can process a request. - sendDiscoveryResponse(Config::TypeUrl::get().Listener, - {buildListener("listener_1", "route_config_1"), - buildListener("listener_2", "route_config_2")}, - {buildListener("listener_1", "route_config_1"), - buildListener("listener_2", "route_config_2")}, - {"listener_0"}, "2"); - EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().RouteConfiguration, "2", - {"route_config_2", "route_config_1", "route_config_0"}, - {"route_config_2", "route_config_1"}, {})); - EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Listener, "2", {}, {}, {})); - EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().RouteConfiguration, "2", - {"route_config_2", "route_config_1"}, {}, - {"route_config_0"})); - sendDiscoveryResponse( - Config::TypeUrl::get().RouteConfiguration, - {buildRouteConfig("route_config_1", "cluster_1"), - buildRouteConfig("route_config_2", "cluster_1")}, - {buildRouteConfig("route_config_1", "cluster_1"), - buildRouteConfig("route_config_2", "cluster_1")}, - {"route_config_0"}, "3"); - EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().RouteConfiguration, "3", - {"route_config_2", "route_config_1"}, {}, {})); - - test_server_->waitForCounterGe("listener_manager.listener_create_success", 2); - makeSingleRequest(); - const ProtobufWkt::Timestamp first_active_listener_ts_3 = - getListenersConfigDump().dynamic_active_listeners()[0].last_updated(); - const ProtobufWkt::Timestamp first_active_cluster_ts_3 = - getClustersConfigDump().dynamic_active_clusters()[0].last_updated(); - const ProtobufWkt::Timestamp first_route_config_ts_3 = - getRoutesConfigDump().dynamic_route_configs()[0].last_updated(); - - // Expect last_updated timestamps to be updated in a predictable way - // For the listener configs in this example, 1 == 2 < 3. - EXPECT_EQ(first_active_listener_ts_2, first_active_listener_ts_1); - EXPECT_GT(first_active_listener_ts_3, first_active_listener_ts_2); - // For the cluster configs in this example, 1 < 2 == 3. - EXPECT_GT(first_active_cluster_ts_2, first_active_cluster_ts_1); - EXPECT_EQ(first_active_cluster_ts_3, first_active_cluster_ts_2); - // For the route configs in this example, 1 < 2 < 3. - EXPECT_GT(first_route_config_ts_2, first_route_config_ts_1); - EXPECT_GT(first_route_config_ts_3, first_route_config_ts_2); - } - - envoy::admin::v2alpha::ClustersConfigDump getClustersConfigDump() { - auto message_ptr = - test_server_->server().admin().getConfigTracker().getCallbacksMap().at("clusters")(); - return dynamic_cast(*message_ptr); - } - - envoy::admin::v2alpha::ListenersConfigDump getListenersConfigDump() { - auto message_ptr = - test_server_->server().admin().getConfigTracker().getCallbacksMap().at("listeners")(); - return dynamic_cast(*message_ptr); - } - - envoy::admin::v2alpha::RoutesConfigDump getRoutesConfigDump() { - auto message_ptr = - test_server_->server().admin().getConfigTracker().getCallbacksMap().at("routes")(); - return dynamic_cast(*message_ptr); - } - - Extensions::TransportSockets::Tls::ContextManagerImpl context_manager_{timeSystem()}; -}; INSTANTIATE_TEST_SUITE_P(IpVersionsClientType, AdsIntegrationTest, GRPC_CLIENT_INTEGRATION_PARAMS); @@ -825,7 +536,7 @@ class AdsFailIntegrationTest : public Grpc::GrpcClientIntegrationParamTest, public HttpIntegrationTest { public: AdsFailIntegrationTest() - : HttpIntegrationTest(Http::CodecClient::Type::HTTP2, ipVersion(), config) { + : HttpIntegrationTest(Http::CodecClient::Type::HTTP2, ipVersion(), AdsIntegrationConfig()) { create_xds_upstream_ = true; use_lds_ = false; } @@ -866,7 +577,7 @@ class AdsConfigIntegrationTest : public Grpc::GrpcClientIntegrationParamTest, public HttpIntegrationTest { public: AdsConfigIntegrationTest() - : HttpIntegrationTest(Http::CodecClient::Type::HTTP2, ipVersion(), config) { + : HttpIntegrationTest(Http::CodecClient::Type::HTTP2, ipVersion(), AdsIntegrationConfig()) { create_xds_upstream_ = true; use_lds_ = false; } @@ -958,25 +669,44 @@ TEST_P(AdsIntegrationTest, XdsBatching) { TEST_P(AdsIntegrationTest, ListenerDrainBeforeServerStart) { initialize(); + // Initial request for cluster, response for cluster_0. + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "", {}, {}, {})); sendDiscoveryResponse(Config::TypeUrl::get().Cluster, {buildCluster("cluster_0")}, {buildCluster("cluster_0")}, {}, "1"); + + // Initial request for load assignment for cluster_0, respond with version 1 + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().ClusterLoadAssignment, "", + {"cluster_0"}, {"cluster_0"}, {})); sendDiscoveryResponse( Config::TypeUrl::get().ClusterLoadAssignment, {buildClusterLoadAssignment("cluster_0")}, {buildClusterLoadAssignment("cluster_0")}, {}, "1"); + // Request for updates to cluster_0 version 1, no response + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "1", {}, {}, {})); + // Initial request for any listener, respond with listener_0 version 1 + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Listener, "", {}, {}, {})); sendDiscoveryResponse( Config::TypeUrl::get().Listener, {buildListener("listener_0", "route_config_0")}, {buildListener("listener_0", "route_config_0")}, {}, "1"); + + // Request for updates to load assignment version 1, no response + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().ClusterLoadAssignment, "1", + {"cluster_0"}, {}, {})); + + // Initial request for route_config_0 (referenced by listener_0), respond with version 1 + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().RouteConfiguration, "", + {"route_config_0"}, {"route_config_0"}, {})); + test_server_->waitForGaugeGe("listener_manager.total_listeners_active", 1); // Before server is started, even though listeners are added to active list // we mark them as "warming" in config dump since they're not initialized yet. EXPECT_EQ(getListenersConfigDump().dynamic_warming_listeners().size(), 1); // Remove listener. + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Listener, "1", {}, {}, {})); sendDiscoveryResponse(Config::TypeUrl::get().Listener, {}, {}, {}, "1"); test_server_->waitForGaugeEq("listener_manager.total_listeners_active", 0); } -} // namespace } // namespace Envoy diff --git a/test/integration/autonomous_upstream.h b/test/integration/autonomous_upstream.h index bdfc8a8eaa73..e749294d7426 100644 --- a/test/integration/autonomous_upstream.h +++ b/test/integration/autonomous_upstream.h @@ -22,7 +22,7 @@ class AutonomousStream : public FakeStream { AutonomousStream(FakeHttpConnection& parent, Http::StreamEncoder& encoder, AutonomousUpstream& upstream); - ~AutonomousStream(); + ~AutonomousStream() override; void setEndStream(bool set) override; @@ -55,7 +55,7 @@ class AutonomousUpstream : public FakeUpstream { AutonomousUpstream(uint32_t port, FakeHttpConnection::Type type, Network::Address::IpVersion version, Event::TestTimeSystem& time_system) : FakeUpstream(port, type, version, time_system) {} - ~AutonomousUpstream(); + ~AutonomousUpstream() override; bool createNetworkFilterChain(Network::Connection& connection, const std::vector& filter_factories) override; diff --git a/test/integration/cluster_filter_integration_test.cc b/test/integration/cluster_filter_integration_test.cc new file mode 100644 index 000000000000..a418c3278fd8 --- /dev/null +++ b/test/integration/cluster_filter_integration_test.cc @@ -0,0 +1,131 @@ +#include "envoy/network/filter.h" +#include "envoy/registry/registry.h" + +#include "test/config/utility.h" +#include "test/integration/integration.h" + +#include "gtest/gtest.h" + +namespace Envoy { +namespace { + +class PoliteFilter : public Network::Filter, Logger::Loggable { +public: + PoliteFilter(const ProtobufWkt::StringValue& value) : greeting_(value.value()) {} + + Network::FilterStatus onData(Buffer::Instance& data, bool end_stream) override { + ENVOY_CONN_LOG(debug, "polite: onData {} bytes {} end_stream", read_callbacks_->connection(), + data.length(), end_stream); + if (!read_greeted_) { + Buffer::OwnedImpl greeter(greeting_); + read_callbacks_->injectReadDataToFilterChain(greeter, false); + read_greeted_ = true; + } + return Network::FilterStatus::Continue; + } + Network::FilterStatus onWrite(Buffer::Instance& data, bool end_stream) override { + ENVOY_CONN_LOG(debug, "polite: onWrite {} bytes {} end_stream", write_callbacks_->connection(), + data.length(), end_stream); + if (!write_greeted_) { + Buffer::OwnedImpl greeter("please "); + write_callbacks_->injectWriteDataToFilterChain(greeter, false); + write_greeted_ = true; + } + return Network::FilterStatus::Continue; + } + Network::FilterStatus onNewConnection() override { + ENVOY_CONN_LOG(debug, "polite: new connection", read_callbacks_->connection()); + return Network::FilterStatus::Continue; + } + + void initializeReadFilterCallbacks(Network::ReadFilterCallbacks& callbacks) override { + read_callbacks_ = &callbacks; + } + void initializeWriteFilterCallbacks(Network::WriteFilterCallbacks& callbacks) override { + write_callbacks_ = &callbacks; + } + +private: + const std::string greeting_; + Network::ReadFilterCallbacks* read_callbacks_{}; + Network::WriteFilterCallbacks* write_callbacks_{}; + bool read_greeted_{false}; + bool write_greeted_{false}; +}; + +class PoliteFilterConfigFactory + : public Server::Configuration::NamedUpstreamNetworkFilterConfigFactory { +public: + Network::FilterFactoryCb + createFilterFactoryFromProto(const Protobuf::Message& proto_config, + Server::Configuration::CommonFactoryContext&) override { + auto config = dynamic_cast(proto_config); + return [config](Network::FilterManager& filter_manager) -> void { + filter_manager.addFilter(std::make_shared(config)); + }; + } + + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); + } + + std::string name() override { return "envoy.upstream.polite"; } +}; + +// perform static registration +REGISTER_FACTORY(PoliteFilterConfigFactory, + Server::Configuration::NamedUpstreamNetworkFilterConfigFactory); + +class ClusterFilterIntegrationTest : public testing::TestWithParam, + public BaseIntegrationTest { +public: + ClusterFilterIntegrationTest() + : BaseIntegrationTest(GetParam(), ConfigHelper::TCP_PROXY_CONFIG) {} + + void initialize() override { + enable_half_close_ = true; + config_helper_.addConfigModifier([](envoy::config::bootstrap::v2::Bootstrap& bootstrap) { + auto* cluster_0 = bootstrap.mutable_static_resources()->mutable_clusters(0); + auto* filter = cluster_0->add_filters(); + filter->set_name("envoy.upstream.polite"); + ProtobufWkt::StringValue config; + config.set_value("surely "); + filter->mutable_typed_config()->PackFrom(config); + }); + BaseIntegrationTest::initialize(); + } +}; + +INSTANTIATE_TEST_SUITE_P(IpVersions, ClusterFilterIntegrationTest, + testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), + TestUtility::ipTestParamsToString); + +TEST_P(ClusterFilterIntegrationTest, TestClusterFilter) { + initialize(); + + auto tcp_client = makeTcpConnection(lookupPort("listener_0")); + FakeRawConnectionPtr fake_upstream_connection; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + + std::string observed_data; + tcp_client->write("test"); + ASSERT_TRUE(fake_upstream_connection->waitForData(11, &observed_data)); + EXPECT_EQ("please test", observed_data); + + observed_data.clear(); + tcp_client->write(" everything"); + ASSERT_TRUE(fake_upstream_connection->waitForData(22, &observed_data)); + EXPECT_EQ("please test everything", observed_data); + + ASSERT_TRUE(fake_upstream_connection->write("yes")); + tcp_client->waitForData("surely yes"); + + tcp_client->write("", true); + ASSERT_TRUE(fake_upstream_connection->waitForHalfClose()); + ASSERT_TRUE(fake_upstream_connection->write("", true)); + ASSERT_TRUE(fake_upstream_connection->waitForDisconnect(true)); + tcp_client->waitForDisconnect(); +} + +} // namespace +} // namespace Envoy diff --git a/test/integration/fake_upstream.h b/test/integration/fake_upstream.h index 72b831ad4664..4338e4a1e998 100644 --- a/test/integration/fake_upstream.h +++ b/test/integration/fake_upstream.h @@ -531,7 +531,7 @@ class FakeUpstream : Logger::Loggable, FakeUpstream(Network::TransportSocketFactoryPtr&& transport_socket_factory, uint32_t port, FakeHttpConnection::Type type, Network::Address::IpVersion version, Event::TestTimeSystem& time_system); - ~FakeUpstream(); + ~FakeUpstream() override; FakeHttpConnection::Type httpType() { return http_type_; } diff --git a/test/integration/filters/add_trailers_filter.cc b/test/integration/filters/add_trailers_filter.cc index dd6c0f0fa0d2..cd698d71e736 100644 --- a/test/integration/filters/add_trailers_filter.cc +++ b/test/integration/filters/add_trailers_filter.cc @@ -12,7 +12,7 @@ namespace Envoy { // A test filter that inserts trailers at the end of encode/decode class AddTrailersStreamFilter : public Http::PassThroughFilter { public: - Http::FilterDataStatus decodeData(Buffer::Instance&, bool end_stream) { + Http::FilterDataStatus decodeData(Buffer::Instance&, bool end_stream) override { if (end_stream) { decoder_callbacks_->addDecodedTrailers().insertGrpcMessage().value(std::string("decode")); } @@ -20,7 +20,7 @@ class AddTrailersStreamFilter : public Http::PassThroughFilter { return Http::FilterDataStatus::Continue; } - Http::FilterDataStatus encodeData(Buffer::Instance&, bool end_stream) { + Http::FilterDataStatus encodeData(Buffer::Instance&, bool end_stream) override { if (end_stream) { encoder_callbacks_->addEncodedTrailers().insertGrpcMessage().value(std::string("encode")); } @@ -34,7 +34,8 @@ class AddTrailersStreamFilterConfig public: AddTrailersStreamFilterConfig() : EmptyHttpFilterConfig("add-trailers-filter") {} - Http::FilterFactoryCb createFilter(const std::string&, Server::Configuration::FactoryContext&) { + Http::FilterFactoryCb createFilter(const std::string&, + Server::Configuration::FactoryContext&) override { return [](Http::FilterChainFactoryCallbacks& callbacks) -> void { callbacks.addStreamFilter(std::make_shared<::Envoy::AddTrailersStreamFilter>()); }; diff --git a/test/integration/filters/clear_route_cache_filter.cc b/test/integration/filters/clear_route_cache_filter.cc index 1e7f72cf6627..94f75d1beb61 100644 --- a/test/integration/filters/clear_route_cache_filter.cc +++ b/test/integration/filters/clear_route_cache_filter.cc @@ -22,7 +22,8 @@ class ClearRouteCacheFilterConfig : public Extensions::HttpFilters::Common::Empt public: ClearRouteCacheFilterConfig() : EmptyHttpFilterConfig("clear-route-cache") {} - Http::FilterFactoryCb createFilter(const std::string&, Server::Configuration::FactoryContext&) { + Http::FilterFactoryCb createFilter(const std::string&, + Server::Configuration::FactoryContext&) override { return [](Http::FilterChainFactoryCallbacks& callbacks) -> void { callbacks.addStreamFilter(std::make_shared<::Envoy::ClearRouteCacheFilter>()); }; diff --git a/test/integration/filters/common.h b/test/integration/filters/common.h index 524fbce49272..247e756d5e45 100644 --- a/test/integration/filters/common.h +++ b/test/integration/filters/common.h @@ -15,7 +15,8 @@ class SimpleFilterConfig : public Extensions::HttpFilters::Common::EmptyHttpFilt public: SimpleFilterConfig() : EmptyHttpFilterConfig(T::name) {} - Http::FilterFactoryCb createFilter(const std::string&, Server::Configuration::FactoryContext&) { + Http::FilterFactoryCb createFilter(const std::string&, + Server::Configuration::FactoryContext&) override { return [](Http::FilterChainFactoryCallbacks& callbacks) -> void { callbacks.addStreamFilter(std::make_shared()); }; diff --git a/test/integration/filters/eds_ready_filter.cc b/test/integration/filters/eds_ready_filter.cc index c1fbf66e9b53..665c0232161c 100644 --- a/test/integration/filters/eds_ready_filter.cc +++ b/test/integration/filters/eds_ready_filter.cc @@ -20,8 +20,7 @@ class EdsReadyFilter : public Http::PassThroughFilter { EdsReadyFilter(const Stats::Scope& root_scope, Stats::SymbolTable& symbol_table) : root_scope_(root_scope), stat_name_("cluster.cluster_0.membership_healthy", symbol_table) {} Http::FilterHeadersStatus decodeHeaders(Http::HeaderMap&, bool) override { - absl::optional> gauge = - root_scope_.findGauge(stat_name_.statName()); + Stats::OptionalGauge gauge = root_scope_.findGauge(stat_name_.statName()); if (!gauge.has_value()) { decoder_callbacks_->sendLocalReply(Envoy::Http::Code::InternalServerError, "Couldn't find stat", nullptr, absl::nullopt, ""); diff --git a/test/integration/filters/modify_buffer_filter.cc b/test/integration/filters/modify_buffer_filter.cc index 82fc65d6ffe9..f96a258b09ce 100644 --- a/test/integration/filters/modify_buffer_filter.cc +++ b/test/integration/filters/modify_buffer_filter.cc @@ -13,7 +13,7 @@ namespace Envoy { // the content of the filter buffer. class ModifyBufferStreamFilter : public Http::PassThroughFilter { public: - Http::FilterDataStatus decodeData(Buffer::Instance& data, bool end_stream) { + Http::FilterDataStatus decodeData(Buffer::Instance& data, bool end_stream) override { decoder_callbacks_->addDecodedData(data, true); if (end_stream) { @@ -27,7 +27,7 @@ class ModifyBufferStreamFilter : public Http::PassThroughFilter { return Http::FilterDataStatus::StopIterationNoBuffer; } - Http::FilterDataStatus encodeData(Buffer::Instance& data, bool end_stream) { + Http::FilterDataStatus encodeData(Buffer::Instance& data, bool end_stream) override { encoder_callbacks_->addEncodedData(data, true); if (end_stream) { @@ -46,7 +46,8 @@ class ModifyBuffferFilterConfig : public Extensions::HttpFilters::Common::EmptyH public: ModifyBuffferFilterConfig() : EmptyHttpFilterConfig("modify-buffer-filter") {} - Http::FilterFactoryCb createFilter(const std::string&, Server::Configuration::FactoryContext&) { + Http::FilterFactoryCb createFilter(const std::string&, + Server::Configuration::FactoryContext&) override { return [](Http::FilterChainFactoryCallbacks& callbacks) -> void { callbacks.addStreamFilter(std::make_shared<::Envoy::ModifyBufferStreamFilter>()); }; diff --git a/test/integration/filters/pause_filter.cc b/test/integration/filters/pause_filter.cc index 228dce27f725..8ed74d4198b8 100644 --- a/test/integration/filters/pause_filter.cc +++ b/test/integration/filters/pause_filter.cc @@ -63,7 +63,8 @@ class TestPauseFilterConfig : public Extensions::HttpFilters::Common::EmptyHttpF public: TestPauseFilterConfig() : EmptyHttpFilterConfig("pause-filter") {} - Http::FilterFactoryCb createFilter(const std::string&, Server::Configuration::FactoryContext&) { + Http::FilterFactoryCb createFilter(const std::string&, + Server::Configuration::FactoryContext&) override { return [&](Http::FilterChainFactoryCallbacks& callbacks) -> void { // GUARDED_BY insists the lock be held when the guarded variables are passed by reference. absl::WriterMutexLock m(&encode_lock_); diff --git a/test/integration/filters/process_context_filter.h b/test/integration/filters/process_context_filter.h index 7e1fde35ff64..16e4cff2a6c9 100644 --- a/test/integration/filters/process_context_filter.h +++ b/test/integration/filters/process_context_filter.h @@ -7,7 +7,7 @@ namespace Envoy { class ProcessObjectForFilter : public ProcessObject { public: explicit ProcessObjectForFilter(bool is_healthy) : is_healthy_(is_healthy) {} - ~ProcessObjectForFilter() override {} + ~ProcessObjectForFilter() override = default; bool isHealthy() { return is_healthy_; } diff --git a/test/integration/filters/random_pause_filter.cc b/test/integration/filters/random_pause_filter.cc index 15f3f71e160e..b709da758ce9 100644 --- a/test/integration/filters/random_pause_filter.cc +++ b/test/integration/filters/random_pause_filter.cc @@ -49,7 +49,8 @@ class RandomPauseFilterConfig : public Extensions::HttpFilters::Common::EmptyHtt public: RandomPauseFilterConfig() : EmptyHttpFilterConfig("random-pause-filter") {} - Http::FilterFactoryCb createFilter(const std::string&, Server::Configuration::FactoryContext&) { + Http::FilterFactoryCb createFilter(const std::string&, + Server::Configuration::FactoryContext&) override { return [&](Http::FilterChainFactoryCallbacks& callbacks) -> void { absl::WriterMutexLock m(&rand_lock_); if (rng_ == nullptr) { diff --git a/test/integration/filters/request_metadata_filter.cc b/test/integration/filters/request_metadata_filter.cc index 19c6425bdc3a..b3823542213d 100644 --- a/test/integration/filters/request_metadata_filter.cc +++ b/test/integration/filters/request_metadata_filter.cc @@ -51,7 +51,8 @@ class AddRequestMetadataStreamFilterConfig : public Extensions::HttpFilters::Common::EmptyHttpFilterConfig { public: AddRequestMetadataStreamFilterConfig() : EmptyHttpFilterConfig("request-metadata-filter") {} - Http::FilterFactoryCb createFilter(const std::string&, Server::Configuration::FactoryContext&) { + Http::FilterFactoryCb createFilter(const std::string&, + Server::Configuration::FactoryContext&) override { return [](Http::FilterChainFactoryCallbacks& callbacks) -> void { callbacks.addStreamFilter(std::make_shared<::Envoy::RequestMetadataStreamFilter>()); }; diff --git a/test/integration/filters/response_metadata_filter.cc b/test/integration/filters/response_metadata_filter.cc index 4d5f45f07a3c..bc3779d3692e 100644 --- a/test/integration/filters/response_metadata_filter.cc +++ b/test/integration/filters/response_metadata_filter.cc @@ -83,7 +83,8 @@ class AddMetadataStreamFilterConfig public: AddMetadataStreamFilterConfig() : EmptyHttpFilterConfig("response-metadata-filter") {} - Http::FilterFactoryCb createFilter(const std::string&, Server::Configuration::FactoryContext&) { + Http::FilterFactoryCb createFilter(const std::string&, + Server::Configuration::FactoryContext&) override { return [](Http::FilterChainFactoryCallbacks& callbacks) -> void { callbacks.addStreamFilter(std::make_shared<::Envoy::ResponseMetadataStreamFilter>()); }; diff --git a/test/integration/filters/stop_iteration_and_continue_filter.cc b/test/integration/filters/stop_iteration_and_continue_filter.cc index b86cccbb1396..aad8c51cb960 100644 --- a/test/integration/filters/stop_iteration_and_continue_filter.cc +++ b/test/integration/filters/stop_iteration_and_continue_filter.cc @@ -9,22 +9,59 @@ namespace Envoy { -// A test filter that does StopIterationNoBuffer then continues after a 0ms alarm. +// A test filter that does StopIterationNoBuffer on end stream, then continues after a 0ms alarm. class StopIterationAndContinueFilter : public Http::PassThroughFilter { public: - Http::FilterDataStatus decodeData(Buffer::Instance&, bool end_stream) { - RELEASE_ASSERT(!end_stream_seen_, "end stream seen twice"); + void setEndStreamAndDecodeTimer() { + decode_end_stream_seen_ = true; + decode_delay_timer_ = decoder_callbacks_->dispatcher().createTimer( + [this]() -> void { decoder_callbacks_->continueDecoding(); }); + decode_delay_timer_->enableTimer(std::chrono::seconds(0)); + } + + void setEndStreamAndEncodeTimer() { + encode_end_stream_seen_ = true; + encode_delay_timer_ = decoder_callbacks_->dispatcher().createTimer( + [this]() -> void { encoder_callbacks_->continueEncoding(); }); + encode_delay_timer_->enableTimer(std::chrono::seconds(0)); + } + + Http::FilterHeadersStatus decodeHeaders(Http::HeaderMap&, bool end_stream) override { + if (end_stream) { + setEndStreamAndDecodeTimer(); + return Http::FilterHeadersStatus::StopIteration; + } + return Http::FilterHeadersStatus::Continue; + } + + Http::FilterDataStatus decodeData(Buffer::Instance&, bool end_stream) override { + RELEASE_ASSERT(!decode_end_stream_seen_, "end stream seen twice"); + if (end_stream) { + setEndStreamAndDecodeTimer(); + } + return Http::FilterDataStatus::StopIterationNoBuffer; + } + + Http::FilterHeadersStatus encodeHeaders(Http::HeaderMap&, bool end_stream) override { + if (end_stream) { + setEndStreamAndEncodeTimer(); + return Http::FilterHeadersStatus::StopIteration; + } + return Http::FilterHeadersStatus::Continue; + } + + Http::FilterDataStatus encodeData(Buffer::Instance&, bool end_stream) override { + RELEASE_ASSERT(!encode_end_stream_seen_, "end stream seen twice"); if (end_stream) { - end_stream_seen_ = true; - delay_timer_ = decoder_callbacks_->dispatcher().createTimer( - [this]() -> void { decoder_callbacks_->continueDecoding(); }); - delay_timer_->enableTimer(std::chrono::seconds(0)); + setEndStreamAndEncodeTimer(); } return Http::FilterDataStatus::StopIterationNoBuffer; } - Event::TimerPtr delay_timer_; - bool end_stream_seen_{}; + Event::TimerPtr decode_delay_timer_; + bool decode_end_stream_seen_{}; + Event::TimerPtr encode_delay_timer_; + bool encode_end_stream_seen_{}; }; class StopIterationAndContinueFilterConfig @@ -33,7 +70,8 @@ class StopIterationAndContinueFilterConfig StopIterationAndContinueFilterConfig() : EmptyHttpFilterConfig("stop-iteration-and-continue-filter") {} - Http::FilterFactoryCb createFilter(const std::string&, Server::Configuration::FactoryContext&) { + Http::FilterFactoryCb createFilter(const std::string&, + Server::Configuration::FactoryContext&) override { return [](Http::FilterChainFactoryCallbacks& callbacks) -> void { callbacks.addStreamFilter(std::make_shared<::Envoy::StopIterationAndContinueFilter>()); }; diff --git a/test/integration/http2_integration_test.cc b/test/integration/http2_integration_test.cc index 22929816f97f..be8fc519633f 100644 --- a/test/integration/http2_integration_test.cc +++ b/test/integration/http2_integration_test.cc @@ -1112,6 +1112,28 @@ TEST_P(Http2IntegrationTest, PauseAndResume) { // Now send the final data frame and make sure it gets proxied. codec_client_->sendData(*request_encoder_, 0, true); ASSERT_TRUE(upstream_request_->waitForEndStream(*dispatcher_)); + upstream_request_->encodeHeaders(default_response_headers_, false); + + response->waitForHeaders(); + upstream_request_->encodeData(0, true); + response->waitForEndStream(); + ASSERT_TRUE(response->complete()); +} + +TEST_P(Http2IntegrationTest, PauseAndResumeHeadersOnly) { + config_helper_.addFilter(R"EOF( + name: stop-iteration-and-continue-filter + config: {} + )EOF"); + initialize(); + + codec_client_ = makeHttpConnection(lookupPort("http")); + auto response = codec_client_->makeHeaderOnlyRequest(default_request_headers_); + + ASSERT_TRUE(fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, fake_upstream_connection_)); + ASSERT_TRUE(fake_upstream_connection_->waitForNewStream(*dispatcher_, upstream_request_)); + ASSERT_TRUE(upstream_request_->waitForEndStream(*dispatcher_)); + upstream_request_->encodeHeaders(default_response_headers_, true); response->waitForEndStream(); ASSERT_TRUE(response->complete()); diff --git a/test/integration/http_integration.h b/test/integration/http_integration.h index 2df23c0462d0..bbeda044911e 100644 --- a/test/integration/http_integration.h +++ b/test/integration/http_integration.h @@ -98,7 +98,7 @@ class HttpIntegrationTest : public BaseIntegrationTest { const InstanceConstSharedPtrFn& upstream_address_fn, Network::Address::IpVersion version, const std::string& config = ConfigHelper::HTTP_PROXY_CONFIG); - virtual ~HttpIntegrationTest(); + ~HttpIntegrationTest() override; // Waits for the first access log entry. std::string waitForAccessLog(const std::string& filename); diff --git a/test/integration/integration_admin_test.cc b/test/integration/integration_admin_test.cc index 137e972e0055..2af1c1f069df 100644 --- a/test/integration/integration_admin_test.cc +++ b/test/integration/integration_admin_test.cc @@ -393,7 +393,8 @@ TEST_P(IntegrationAdminTest, Admin) { "type.googleapis.com/envoy.admin.v2alpha.ClustersConfigDump", "type.googleapis.com/envoy.admin.v2alpha.ListenersConfigDump", "type.googleapis.com/envoy.admin.v2alpha.ScopedRoutesConfigDump", - "type.googleapis.com/envoy.admin.v2alpha.RoutesConfigDump"}; + "type.googleapis.com/envoy.admin.v2alpha.RoutesConfigDump", + "type.googleapis.com/envoy.admin.v2alpha.SecretsConfigDump"}; for (const Json::ObjectSharedPtr& obj_ptr : json->getObjectArray("configs")) { EXPECT_TRUE(expected_types[index].compare(obj_ptr->getString("@type")) == 0); @@ -403,12 +404,16 @@ TEST_P(IntegrationAdminTest, Admin) { // Validate we can parse as proto. envoy::admin::v2alpha::ConfigDump config_dump; TestUtility::loadFromJson(response->body(), config_dump); - EXPECT_EQ(5, config_dump.configs_size()); + EXPECT_EQ(6, config_dump.configs_size()); // .. and that we can unpack one of the entries. envoy::admin::v2alpha::RoutesConfigDump route_config_dump; config_dump.configs(4).UnpackTo(&route_config_dump); EXPECT_EQ("route_config_0", route_config_dump.static_route_configs(0).route_config().name()); + + envoy::admin::v2alpha::SecretsConfigDump secret_config_dump; + config_dump.configs(5).UnpackTo(&secret_config_dump); + EXPECT_EQ("secret_static_0", secret_config_dump.static_secrets(0).name()); } TEST_P(IntegrationAdminTest, AdminOnDestroyCallbacks) { diff --git a/test/integration/protocol_integration_test.cc b/test/integration/protocol_integration_test.cc index 1e7c6bcb0b72..ae7801e4176e 100644 --- a/test/integration/protocol_integration_test.cc +++ b/test/integration/protocol_integration_test.cc @@ -1020,6 +1020,28 @@ name: encode-headers-return-stop-all-filter EXPECT_EQ(count_ * size_ + added_decoded_data_size_, response->body().size()); } +// Per https://github.com/envoyproxy/envoy/issues/7488 make sure we don't +// combine set-cookie headers +TEST_P(ProtocolIntegrationTest, MultipleSetCookies) { + initialize(); + + codec_client_ = makeHttpConnection(lookupPort("http")); + + Http::TestHeaderMapImpl response_headers{ + {":status", "200"}, {"set-cookie", "foo"}, {"set-cookie", "bar"}}; + + auto response = sendRequestAndWaitForResponse(default_request_headers_, 0, response_headers, 0); + + ASSERT_TRUE(response->complete()); + EXPECT_EQ("200", response->headers().Status()->value().getStringView()); + + std::vector out; + Http::HeaderUtility::getAllOfHeader(response->headers(), "set-cookie", out); + ASSERT_EQ(out.size(), 2); + ASSERT_EQ(out[0], "foo"); + ASSERT_EQ(out[1], "bar"); +} + // For tests which focus on downstream-to-Envoy behavior, and don't need to be // run with both HTTP/1 and HTTP/2 upstreams. INSTANTIATE_TEST_SUITE_P(Protocols, DownstreamProtocolIntegrationTest, diff --git a/test/integration/run_envoy_test.sh b/test/integration/run_envoy_test.sh index 409f84bb34f1..805fdb5a2493 100755 --- a/test/integration/run_envoy_test.sh +++ b/test/integration/run_envoy_test.sh @@ -21,7 +21,7 @@ expect_fail_with_error "PARSE ERROR: Argument: --bogus-flag" --bogus-flag start_test Launching envoy without --config-path or --config-yaml fails. expect_fail_with_error \ - "At least one of --config-path and --config-yaml should be non-empty" + "At least one of --config-path or --config-yaml or Options::configProto() should be non-empty" start_test Launching envoy with unknown IP address. expect_fail_with_error "error: unknown IP address version" --local-address-ip-version foo diff --git a/test/integration/sds_dynamic_integration_test.cc b/test/integration/sds_dynamic_integration_test.cc index f91c7a5c383a..d260bdf6f0d0 100644 --- a/test/integration/sds_dynamic_integration_test.cc +++ b/test/integration/sds_dynamic_integration_test.cc @@ -239,7 +239,7 @@ TEST_P(SdsDynamicDownstreamIntegrationTest, WrongSecretFirst) { class SdsDynamicDownstreamCertValidationContextTest : public SdsDynamicDownstreamIntegrationTest { public: - SdsDynamicDownstreamCertValidationContextTest() : use_combined_validation_context_(false) {} + SdsDynamicDownstreamCertValidationContextTest() = default; void initialize() override { config_helper_.addConfigModifier([this](envoy::config::bootstrap::v2::Bootstrap& bootstrap) { @@ -285,7 +285,7 @@ class SdsDynamicDownstreamCertValidationContextTest : public SdsDynamicDownstrea void enableCombinedValidationContext(bool enable) { use_combined_validation_context_ = enable; } private: - bool use_combined_validation_context_; + bool use_combined_validation_context_{false}; }; INSTANTIATE_TEST_SUITE_P(IpVersionsClientType, SdsDynamicDownstreamCertValidationContextTest, diff --git a/test/integration/server.cc b/test/integration/server.cc index ddd12b31191d..382332aa80c3 100644 --- a/test/integration/server.cc +++ b/test/integration/server.cc @@ -180,7 +180,7 @@ void IntegrationTestServerImpl::createAndRunEnvoyServer( Stats::FakeSymbolTableImpl symbol_table; Server::HotRestartNopImpl restarter; ThreadLocal::InstanceImpl tls; - Stats::HeapStatDataAllocator stats_allocator(symbol_table); + Stats::AllocatorImpl stats_allocator(symbol_table); Stats::ThreadLocalStoreImpl stat_store(stats_allocator); std::unique_ptr process_context; if (process_object.has_value()) { diff --git a/test/integration/server.h b/test/integration/server.h index 1b77f511fbae..55e3c11eab23 100644 --- a/test/integration/server.h +++ b/test/integration/server.h @@ -109,16 +109,15 @@ class TestScopeWrapper : public Scope { return histogramFromStatName(storage.statName()); } - absl::optional> findCounter(StatName name) const override { + OptionalCounter findCounter(StatName name) const override { Thread::LockGuard lock(lock_); return wrapped_scope_->findCounter(name); } - absl::optional> findGauge(StatName name) const override { + OptionalGauge findGauge(StatName name) const override { Thread::LockGuard lock(lock_); return wrapped_scope_->findGauge(name); } - absl::optional> - findHistogram(StatName name) const override { + OptionalHistogram findHistogram(StatName name) const override { Thread::LockGuard lock(lock_); return wrapped_scope_->findHistogram(name); } @@ -170,16 +169,15 @@ class TestIsolatedStoreImpl : public StoreRoot { Thread::LockGuard lock(lock_); return store_.histogram(name); } - absl::optional> findCounter(StatName name) const override { + OptionalCounter findCounter(StatName name) const override { Thread::LockGuard lock(lock_); return store_.findCounter(name); } - absl::optional> findGauge(StatName name) const override { + OptionalGauge findGauge(StatName name) const override { Thread::LockGuard lock(lock_); return store_.findGauge(name); } - absl::optional> - findHistogram(StatName name) const override { + OptionalHistogram findHistogram(StatName name) const override { Thread::LockGuard lock(lock_); return store_.findHistogram(name); } @@ -238,7 +236,7 @@ class IntegrationTestServer : public Logger::Loggable, absl::optional> process_object = absl::nullopt); // Note that the derived class is responsible for tearing down the server in its // destructor. - ~IntegrationTestServer(); + ~IntegrationTestServer() override; void waitUntilListenersReady(); diff --git a/test/integration/stats_integration_test.cc b/test/integration/stats_integration_test.cc index a404e8de89d5..cc016ffbea1a 100644 --- a/test/integration/stats_integration_test.cc +++ b/test/integration/stats_integration_test.cc @@ -210,6 +210,8 @@ TEST_P(ClusterMemoryTestRunner, MemoryLargeClusterSizeWithStats) { // 2019/06/29 7364 45685 46000 combine 2 levels of stat ref-counting into 1 // 2019/06/30 7428 42742 43000 remove stats multiple inheritance, inline HeapStatData // 2019/07/06 7477 42742 43000 fork gauge representation to drop pending_increment_ + // 2019/07/15 7555 42806 43000 static link libstdc++ in tests + // 2019/07/24 7503 43030 44000 add upstream filters to clusters // Note: when adjusting this value: EXPECT_MEMORY_EQ is active only in CI // 'release' builds, where we control the platform and tool-chain. So you @@ -219,8 +221,8 @@ TEST_P(ClusterMemoryTestRunner, MemoryLargeClusterSizeWithStats) { // On a local clang8/libstdc++/linux flow, the memory usage was observed in // June 2019 to be 64 bytes higher than it is in CI/release. Your mileage may // vary. - EXPECT_MEMORY_EQ(m_per_cluster, 42742); // 104 bytes higher than a debug build. - EXPECT_MEMORY_LE(m_per_cluster, 43000); + EXPECT_MEMORY_EQ(m_per_cluster, 43030); // 104 bytes higher than a debug build. + EXPECT_MEMORY_LE(m_per_cluster, 44000); } } // namespace diff --git a/test/integration/tcp_dump.cc b/test/integration/tcp_dump.cc index 1c3b76f124b7..95cd8b55c0e0 100644 --- a/test/integration/tcp_dump.cc +++ b/test/integration/tcp_dump.cc @@ -1,10 +1,10 @@ #include "test/integration/tcp_dump.h" -#include #include #include #include +#include #include #include "common/common/assert.h" diff --git a/test/integration/utility.cc b/test/integration/utility.cc index ecf5fd26ae7d..e0953f354001 100644 --- a/test/integration/utility.cc +++ b/test/integration/utility.cc @@ -129,7 +129,7 @@ RawConnectionDriver::RawConnectionDriver(uint32_t port, Buffer::Instance& initia client_->connect(); } -RawConnectionDriver::~RawConnectionDriver() {} +RawConnectionDriver::~RawConnectionDriver() = default; void RawConnectionDriver::run(Event::Dispatcher::RunType run_type) { dispatcher_->run(run_type); } diff --git a/test/integration/xfcc_integration_test.cc b/test/integration/xfcc_integration_test.cc index 2e9a5f12d8a6..4e2bed984cfb 100644 --- a/test/integration/xfcc_integration_test.cc +++ b/test/integration/xfcc_integration_test.cc @@ -39,30 +39,37 @@ void XfccIntegrationTest::TearDown() { } Network::TransportSocketFactoryPtr XfccIntegrationTest::createClientSslContext(bool mtls) { - std::string json_tls = R"EOF( -{ - "ca_cert_file": "{{ test_rundir }}/test/config/integration/certs/cacert.pem", - "verify_subject_alt_name": [ "spiffe://lyft.com/backend-team", "lyft.com", "www.lyft.com" ] -} + const std::string yaml_tls = R"EOF( +common_tls_context: + validation_context: + trusted_ca: + filename: {{ test_rundir }}/test/config/integration/certs/cacert.pem + verify_subject_alt_name: [ spiffe://lyft.com/backend-team, lyft.com, www.lyft.com ] )EOF"; - std::string json_mtls = R"EOF( -{ - "ca_cert_file": "{{ test_rundir }}/test/config/integration/certs/cacert.pem", - "cert_chain_file": "{{ test_rundir }}/test/config/integration/certs/clientcert.pem", - "private_key_file": "{{ test_rundir }}/test/config/integration/certs/clientkey.pem", - "verify_subject_alt_name": [ "spiffe://lyft.com/backend-team", "lyft.com", "www.lyft.com" ] -} + + const std::string yaml_mtls = R"EOF( +common_tls_context: + validation_context: + trusted_ca: + filename: {{ test_rundir }}/test/config/integration/certs/cacert.pem + verify_subject_alt_name: [ spiffe://lyft.com/backend-team, lyft.com, www.lyft.com ] + tls_certificates: + certificate_chain: + filename: {{ test_rundir }}/test/config/integration/certs/clientcert.pem + private_key: + filename: {{ test_rundir }}/test/config/integration/certs/clientkey.pem )EOF"; std::string target; if (mtls) { - target = json_mtls; + target = yaml_mtls; } else { - target = json_tls; + target = yaml_tls; } - Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(target); + envoy::api::v2::auth::UpstreamTlsContext config; + TestUtility::loadFromYaml(TestEnvironment::substitute(target), config); auto cfg = std::make_unique( - *loader, factory_context_); + config, factory_context_); static auto* client_stats_store = new Stats::TestIsolatedStoreImpl(); return Network::TransportSocketFactoryPtr{ new Extensions::TransportSockets::Tls::ClientSslSocketFactory( diff --git a/test/mocks/access_log/mocks.cc b/test/mocks/access_log/mocks.cc index 0220ae53f450..33c7b022fd31 100644 --- a/test/mocks/access_log/mocks.cc +++ b/test/mocks/access_log/mocks.cc @@ -10,20 +10,20 @@ using testing::ReturnRef; namespace Envoy { namespace AccessLog { -MockAccessLogFile::MockAccessLogFile() {} -MockAccessLogFile::~MockAccessLogFile() {} +MockAccessLogFile::MockAccessLogFile() = default; +MockAccessLogFile::~MockAccessLogFile() = default; -MockFilter::MockFilter() {} -MockFilter::~MockFilter() {} +MockFilter::MockFilter() = default; +MockFilter::~MockFilter() = default; MockAccessLogManager::MockAccessLogManager() { ON_CALL(*this, createAccessLog(_)).WillByDefault(Return(file_)); } -MockAccessLogManager::~MockAccessLogManager() {} +MockAccessLogManager::~MockAccessLogManager() = default; -MockInstance::MockInstance() {} -MockInstance::~MockInstance() {} +MockInstance::MockInstance() = default; +MockInstance::~MockInstance() = default; } // namespace AccessLog } // namespace Envoy diff --git a/test/mocks/access_log/mocks.h b/test/mocks/access_log/mocks.h index 562d817e896b..51748550b559 100644 --- a/test/mocks/access_log/mocks.h +++ b/test/mocks/access_log/mocks.h @@ -13,7 +13,7 @@ namespace AccessLog { class MockAccessLogFile : public AccessLogFile { public: MockAccessLogFile(); - ~MockAccessLogFile(); + ~MockAccessLogFile() override; // AccessLog::AccessLogFile MOCK_METHOD1(write, void(absl::string_view data)); @@ -24,7 +24,7 @@ class MockAccessLogFile : public AccessLogFile { class MockFilter : public Filter { public: MockFilter(); - ~MockFilter(); + ~MockFilter() override; // AccessLog::Filter MOCK_METHOD4(evaluate, @@ -36,7 +36,7 @@ class MockFilter : public Filter { class MockAccessLogManager : public AccessLogManager { public: MockAccessLogManager(); - ~MockAccessLogManager(); + ~MockAccessLogManager() override; // AccessLog::AccessLogManager MOCK_METHOD0(reopen, void()); @@ -48,7 +48,7 @@ class MockAccessLogManager : public AccessLogManager { class MockInstance : public Instance { public: MockInstance(); - ~MockInstance(); + ~MockInstance() override; // AccessLog::Instance MOCK_METHOD4(log, diff --git a/test/mocks/api/mocks.cc b/test/mocks/api/mocks.cc index b3eb6296544d..77f6a4463dd3 100644 --- a/test/mocks/api/mocks.cc +++ b/test/mocks/api/mocks.cc @@ -17,7 +17,7 @@ MockApi::MockApi() { ON_CALL(*this, rootScope()).WillByDefault(ReturnRef(stats_store_)); } -MockApi::~MockApi() {} +MockApi::~MockApi() = default; Event::DispatcherPtr MockApi::allocateDispatcher() { return Event::DispatcherPtr{allocateDispatcher_(time_system_)}; @@ -26,9 +26,9 @@ Event::DispatcherPtr MockApi::allocateDispatcher(Buffer::WatermarkFactoryPtr&& w return Event::DispatcherPtr{allocateDispatcher_(std::move(watermark_factory), time_system_)}; } -MockOsSysCalls::MockOsSysCalls() {} +MockOsSysCalls::MockOsSysCalls() = default; -MockOsSysCalls::~MockOsSysCalls() {} +MockOsSysCalls::~MockOsSysCalls() = default; SysCallIntResult MockOsSysCalls::setsockopt(int sockfd, int level, int optname, const void* optval, socklen_t optlen) { diff --git a/test/mocks/api/mocks.h b/test/mocks/api/mocks.h index 4bda9755288a..a85587a62683 100644 --- a/test/mocks/api/mocks.h +++ b/test/mocks/api/mocks.h @@ -26,7 +26,7 @@ namespace Api { class MockApi : public Api { public: MockApi(); - ~MockApi(); + ~MockApi() override; // Api::Api Event::DispatcherPtr allocateDispatcher() override; @@ -49,7 +49,7 @@ class MockApi : public Api { class MockOsSysCalls : public OsSysCallsImpl { public: MockOsSysCalls(); - ~MockOsSysCalls(); + ~MockOsSysCalls() override; // Api::OsSysCalls SysCallIntResult setsockopt(int sockfd, int level, int optname, const void* optval, diff --git a/test/mocks/buffer/mocks.cc b/test/mocks/buffer/mocks.cc index 1aae98289c2c..64459da03703 100644 --- a/test/mocks/buffer/mocks.cc +++ b/test/mocks/buffer/mocks.cc @@ -22,7 +22,7 @@ MockBufferBase::MockBufferBase(std::function, std::fu template <> MockBufferBase::MockBufferBase() : Buffer::OwnedImpl() {} -MockBufferFactory::MockBufferFactory() {} -MockBufferFactory::~MockBufferFactory() {} +MockBufferFactory::MockBufferFactory() = default; +MockBufferFactory::~MockBufferFactory() = default; } // namespace Envoy diff --git a/test/mocks/buffer/mocks.h b/test/mocks/buffer/mocks.h index 6713259969f7..2f9eb963eca4 100644 --- a/test/mocks/buffer/mocks.h +++ b/test/mocks/buffer/mocks.h @@ -90,7 +90,7 @@ class MockWatermarkBuffer : public MockBufferBase { class MockBufferFactory : public Buffer::WatermarkFactory { public: MockBufferFactory(); - ~MockBufferFactory(); + ~MockBufferFactory() override; Buffer::InstancePtr create(std::function below_low, std::function above_high) override { diff --git a/test/mocks/common.cc b/test/mocks/common.cc index f0b878da8477..ba36e63fc102 100644 --- a/test/mocks/common.cc +++ b/test/mocks/common.cc @@ -1,10 +1,10 @@ #include "test/mocks/common.h" namespace Envoy { -ReadyWatcher::ReadyWatcher() {} -ReadyWatcher::~ReadyWatcher() {} +ReadyWatcher::ReadyWatcher() = default; +ReadyWatcher::~ReadyWatcher() = default; -MockTimeSystem::MockTimeSystem() {} -MockTimeSystem::~MockTimeSystem() {} +MockTimeSystem::MockTimeSystem() = default; +MockTimeSystem::~MockTimeSystem() = default; } // namespace Envoy diff --git a/test/mocks/common.h b/test/mocks/common.h index 77637b83ade2..22f9fcafa422 100644 --- a/test/mocks/common.h +++ b/test/mocks/common.h @@ -2,6 +2,7 @@ #include +#include "envoy/common/scope_tracker.h" #include "envoy/common/time.h" #include "envoy/common/token_bucket.h" #include "envoy/event/timer.h" @@ -43,7 +44,7 @@ class ReadyWatcher { class MockTimeSystem : public Event::TestTimeSystem { public: MockTimeSystem(); - ~MockTimeSystem(); + ~MockTimeSystem() override; // TODO(#4160): Eliminate all uses of MockTimeSystem, replacing with SimulatedTimeSystem, // where timer callbacks are triggered by the advancement of time. This implementation @@ -86,4 +87,8 @@ inline bool operator==(const StringViewSaver& saver, const char* str) { return saver.value() == str; } +class MockScopedTrackedObject : public ScopeTrackedObject { + MOCK_CONST_METHOD2(dumpState, void(std::ostream&, int)); +}; + } // namespace Envoy diff --git a/test/mocks/config/mocks.h b/test/mocks/config/mocks.h index fbcd624a1e1a..ee7c9291782b 100644 --- a/test/mocks/config/mocks.h +++ b/test/mocks/config/mocks.h @@ -25,7 +25,7 @@ template class MockSubscriptionCallbacks : public Subscript return resourceName_(TestUtility::anyConvert(resource)); })); } - ~MockSubscriptionCallbacks() override {} + ~MockSubscriptionCallbacks() override = default; static std::string resourceName_(const envoy::api::v2::ClusterLoadAssignment& resource) { return resource.cluster_name(); } diff --git a/test/mocks/event/mocks.cc b/test/mocks/event/mocks.cc index f1d5cdcadb19..0cd2f11d33be 100644 --- a/test/mocks/event/mocks.cc +++ b/test/mocks/event/mocks.cc @@ -24,7 +24,7 @@ MockDispatcher::MockDispatcher() { ON_CALL(*this, post(_)).WillByDefault(Invoke([](PostCb cb) -> void { cb(); })); } -MockDispatcher::~MockDispatcher() {} +MockDispatcher::~MockDispatcher() = default; MockTimer::MockTimer() { ON_CALL(*this, enableTimer(_)).WillByDefault(Assign(&enabled_, true)); @@ -41,7 +41,7 @@ MockTimer::MockTimer(MockDispatcher* dispatcher) : MockTimer() { .RetiresOnSaturation(); } -MockTimer::~MockTimer() {} +MockTimer::~MockTimer() = default; MockSignalEvent::MockSignalEvent(MockDispatcher* dispatcher) { EXPECT_CALL(*dispatcher, listenForSignal_(_, _)) @@ -49,10 +49,10 @@ MockSignalEvent::MockSignalEvent(MockDispatcher* dispatcher) { .RetiresOnSaturation(); } -MockSignalEvent::~MockSignalEvent() {} +MockSignalEvent::~MockSignalEvent() = default; -MockFileEvent::MockFileEvent() {} -MockFileEvent::~MockFileEvent() {} +MockFileEvent::MockFileEvent() = default; +MockFileEvent::~MockFileEvent() = default; } // namespace Event } // namespace Envoy diff --git a/test/mocks/event/mocks.h b/test/mocks/event/mocks.h index 5cbd2f076f5f..4ff1eda3140c 100644 --- a/test/mocks/event/mocks.h +++ b/test/mocks/event/mocks.h @@ -28,7 +28,7 @@ namespace Event { class MockDispatcher : public Dispatcher { public: MockDispatcher(); - ~MockDispatcher(); + ~MockDispatcher() override; // Dispatcher TimeSource& timeSource() override { return time_system_; } @@ -114,6 +114,7 @@ class MockDispatcher : public Dispatcher { MOCK_METHOD1(post, void(std::function callback)); MOCK_METHOD1(run, void(RunType type)); MOCK_METHOD1(setTrackedObject, const ScopeTrackedObject*(const ScopeTrackedObject* object)); + MOCK_CONST_METHOD0(isThreadSafe, bool()); Buffer::WatermarkFactory& getWatermarkFactory() override { return buffer_factory_; } GlobalTimeSystem time_system_; @@ -125,7 +126,7 @@ class MockTimer : public Timer { public: MockTimer(); MockTimer(MockDispatcher* dispatcher); - ~MockTimer(); + ~MockTimer() override; void invokeCallback() { EXPECT_TRUE(enabled_); @@ -147,7 +148,7 @@ class MockTimer : public Timer { class MockSignalEvent : public SignalEvent { public: MockSignalEvent(MockDispatcher* dispatcher); - ~MockSignalEvent(); + ~MockSignalEvent() override; SignalCb callback_; }; @@ -155,7 +156,7 @@ class MockSignalEvent : public SignalEvent { class MockFileEvent : public FileEvent { public: MockFileEvent(); - ~MockFileEvent(); + ~MockFileEvent() override; MOCK_METHOD1(activate, void(uint32_t events)); MOCK_METHOD1(setEnabled, void(uint32_t events)); diff --git a/test/mocks/filesystem/mocks.cc b/test/mocks/filesystem/mocks.cc index a9eca9c4815c..5aa5806a26a0 100644 --- a/test/mocks/filesystem/mocks.cc +++ b/test/mocks/filesystem/mocks.cc @@ -7,7 +7,7 @@ namespace Envoy { namespace Filesystem { MockFile::MockFile() : num_opens_(0), num_writes_(0), is_open_(false) {} -MockFile::~MockFile() {} +MockFile::~MockFile() = default; Api::IoCallBoolResult MockFile::open() { Thread::LockGuard lock(open_mutex_); diff --git a/test/mocks/grpc/mocks.cc b/test/mocks/grpc/mocks.cc index 1eccf7ea0870..07b3e3b348dc 100644 --- a/test/mocks/grpc/mocks.cc +++ b/test/mocks/grpc/mocks.cc @@ -3,17 +3,17 @@ namespace Envoy { namespace Grpc { -MockAsyncRequest::MockAsyncRequest() {} -MockAsyncRequest::~MockAsyncRequest() {} +MockAsyncRequest::MockAsyncRequest() = default; +MockAsyncRequest::~MockAsyncRequest() = default; -MockAsyncStream::MockAsyncStream() {} -MockAsyncStream::~MockAsyncStream() {} +MockAsyncStream::MockAsyncStream() = default; +MockAsyncStream::~MockAsyncStream() = default; -MockAsyncClientFactory::MockAsyncClientFactory() {} -MockAsyncClientFactory::~MockAsyncClientFactory() {} +MockAsyncClientFactory::MockAsyncClientFactory() = default; +MockAsyncClientFactory::~MockAsyncClientFactory() = default; -MockAsyncClientManager::MockAsyncClientManager() {} -MockAsyncClientManager::~MockAsyncClientManager() {} +MockAsyncClientManager::MockAsyncClientManager() = default; +MockAsyncClientManager::~MockAsyncClientManager() = default; } // namespace Grpc } // namespace Envoy diff --git a/test/mocks/grpc/mocks.h b/test/mocks/grpc/mocks.h index f851f0e0176d..a2393b32444a 100644 --- a/test/mocks/grpc/mocks.h +++ b/test/mocks/grpc/mocks.h @@ -19,7 +19,7 @@ namespace Grpc { class MockAsyncRequest : public AsyncRequest { public: MockAsyncRequest(); - ~MockAsyncRequest(); + ~MockAsyncRequest() override; MOCK_METHOD0(cancel, void()); }; @@ -27,9 +27,9 @@ class MockAsyncRequest : public AsyncRequest { class MockAsyncStream : public RawAsyncStream { public: MockAsyncStream(); - ~MockAsyncStream(); + ~MockAsyncStream() override; - void sendMessageRaw(Buffer::InstancePtr&& request, bool end_stream) { + void sendMessageRaw(Buffer::InstancePtr&& request, bool end_stream) override { sendMessageRaw_(request, end_stream); } MOCK_METHOD2_T(sendMessageRaw_, void(Buffer::InstancePtr& request, bool end_stream)); @@ -85,7 +85,7 @@ class MockAsyncClient : public RawAsyncClient { class MockAsyncClientFactory : public AsyncClientFactory { public: MockAsyncClientFactory(); - ~MockAsyncClientFactory(); + ~MockAsyncClientFactory() override; MOCK_METHOD0(create, RawAsyncClientPtr()); }; @@ -93,7 +93,7 @@ class MockAsyncClientFactory : public AsyncClientFactory { class MockAsyncClientManager : public AsyncClientManager { public: MockAsyncClientManager(); - ~MockAsyncClientManager(); + ~MockAsyncClientManager() override; MOCK_METHOD3(factoryForGrpcService, AsyncClientFactoryPtr(const envoy::api::v2::core::GrpcService& grpc_service, diff --git a/test/mocks/http/conn_pool.h b/test/mocks/http/conn_pool.h index 18ea24063c56..60566c96b129 100644 --- a/test/mocks/http/conn_pool.h +++ b/test/mocks/http/conn_pool.h @@ -14,7 +14,7 @@ class MockCancellable : public Cancellable { public: MockCancellable(); - ~MockCancellable(); + ~MockCancellable() override; // Http::ConnectionPool::Cancellable MOCK_METHOD0(cancel, void()); @@ -23,7 +23,7 @@ class MockCancellable : public Cancellable { class MockInstance : public Instance { public: MockInstance(); - ~MockInstance(); + ~MockInstance() override; // Http::ConnectionPool::Instance MOCK_CONST_METHOD0(protocol, Http::Protocol()); diff --git a/test/mocks/http/mocks.cc b/test/mocks/http/mocks.cc index c30c9bc400ea..0f1161c5725e 100644 --- a/test/mocks/http/mocks.cc +++ b/test/mocks/http/mocks.cc @@ -65,6 +65,7 @@ MockStreamDecoderFilterCallbacks::MockStreamDecoderFilterCallbacks() { ON_CALL(*this, activeSpan()).WillByDefault(ReturnRef(active_span_)); ON_CALL(*this, tracingConfig()).WillByDefault(ReturnRef(tracing_config_)); + ON_CALL(*this, scope()).WillByDefault(ReturnRef(scope_)); ON_CALL(*this, sendLocalReply(_, _, _, _, _)) .WillByDefault(Invoke([this](Code code, absl::string_view body, std::function modify_headers, @@ -97,6 +98,7 @@ MockStreamEncoderFilterCallbacks::MockStreamEncoderFilterCallbacks() { ON_CALL(*this, encodingBuffer()).WillByDefault(Invoke(&buffer_, &Buffer::InstancePtr::get)); ON_CALL(*this, activeSpan()).WillByDefault(ReturnRef(active_span_)); ON_CALL(*this, tracingConfig()).WillByDefault(ReturnRef(tracing_config_)); + ON_CALL(*this, scope()).WillByDefault(ReturnRef(scope_)); } MockStreamEncoderFilterCallbacks::~MockStreamEncoderFilterCallbacks() = default; diff --git a/test/mocks/http/mocks.h b/test/mocks/http/mocks.h index a3a3f53768c9..13f5d6717a03 100644 --- a/test/mocks/http/mocks.h +++ b/test/mocks/http/mocks.h @@ -41,7 +41,7 @@ namespace Http { class MockConnectionCallbacks : public virtual ConnectionCallbacks { public: MockConnectionCallbacks(); - ~MockConnectionCallbacks(); + ~MockConnectionCallbacks() override; // Http::ConnectionCallbacks MOCK_METHOD0(onGoAway, void()); @@ -51,7 +51,7 @@ class MockServerConnectionCallbacks : public ServerConnectionCallbacks, public MockConnectionCallbacks { public: MockServerConnectionCallbacks(); - ~MockServerConnectionCallbacks(); + ~MockServerConnectionCallbacks() override; // Http::ServerConnectionCallbacks MOCK_METHOD2(newStream, @@ -61,7 +61,7 @@ class MockServerConnectionCallbacks : public ServerConnectionCallbacks, class MockStreamCallbacks : public StreamCallbacks { public: MockStreamCallbacks(); - ~MockStreamCallbacks(); + ~MockStreamCallbacks() override; // Http::StreamCallbacks MOCK_METHOD2(onResetStream, void(StreamResetReason reason, absl::string_view)); @@ -72,7 +72,7 @@ class MockStreamCallbacks : public StreamCallbacks { class MockServerConnection : public ServerConnection { public: MockServerConnection(); - ~MockServerConnection(); + ~MockServerConnection() override; // Http::Connection MOCK_METHOD1(dispatch, void(Buffer::Instance& data)); @@ -89,7 +89,7 @@ class MockServerConnection : public ServerConnection { class MockClientConnection : public ClientConnection { public: MockClientConnection(); - ~MockClientConnection(); + ~MockClientConnection() override; // Http::Connection MOCK_METHOD1(dispatch, void(Buffer::Instance& data)); @@ -107,7 +107,7 @@ class MockClientConnection : public ClientConnection { class MockFilterChainFactory : public FilterChainFactory { public: MockFilterChainFactory(); - ~MockFilterChainFactory(); + ~MockFilterChainFactory() override; // Http::FilterChainFactory MOCK_METHOD1(createFilterChain, void(FilterChainFactoryCallbacks& callbacks)); @@ -128,7 +128,7 @@ class MockStreamDecoderFilterCallbacks : public StreamDecoderFilterCallbacks, public MockStreamFilterCallbacksBase { public: MockStreamDecoderFilterCallbacks(); - ~MockStreamDecoderFilterCallbacks(); + ~MockStreamDecoderFilterCallbacks() override; // Http::StreamFilterCallbacks MOCK_METHOD0(connection, const Network::Connection*()); @@ -141,6 +141,7 @@ class MockStreamDecoderFilterCallbacks : public StreamDecoderFilterCallbacks, MOCK_METHOD0(streamInfo, StreamInfo::StreamInfo&()); MOCK_METHOD0(activeSpan, Tracing::Span&()); MOCK_METHOD0(tracingConfig, Tracing::Config&()); + MOCK_METHOD0(scope, const ScopeTrackedObject&()); MOCK_METHOD0(onDecoderFilterAboveWriteBufferHighWatermark, void()); MOCK_METHOD0(onDecoderFilterBelowWriteBufferLowWatermark, void()); MOCK_METHOD1(addDownstreamWatermarkCallbacks, void(DownstreamWatermarkCallbacks&)); @@ -189,6 +190,7 @@ class MockStreamDecoderFilterCallbacks : public StreamDecoderFilterCallbacks, std::list callbacks_{}; testing::NiceMock active_span_; testing::NiceMock tracing_config_; + testing::NiceMock scope_; std::string details_; bool is_grpc_request_{}; bool is_head_request_{false}; @@ -199,7 +201,7 @@ class MockStreamEncoderFilterCallbacks : public StreamEncoderFilterCallbacks, public MockStreamFilterCallbacksBase { public: MockStreamEncoderFilterCallbacks(); - ~MockStreamEncoderFilterCallbacks(); + ~MockStreamEncoderFilterCallbacks() override; // Http::StreamFilterCallbacks MOCK_METHOD0(connection, const Network::Connection*()); @@ -212,6 +214,7 @@ class MockStreamEncoderFilterCallbacks : public StreamEncoderFilterCallbacks, MOCK_METHOD0(streamInfo, StreamInfo::StreamInfo&()); MOCK_METHOD0(activeSpan, Tracing::Span&()); MOCK_METHOD0(tracingConfig, Tracing::Config&()); + MOCK_METHOD0(scope, const ScopeTrackedObject&()); MOCK_METHOD0(onEncoderFilterAboveWriteBufferHighWatermark, void()); MOCK_METHOD0(onEncoderFilterBelowWriteBufferLowWatermark, void()); MOCK_METHOD1(setEncoderBufferLimit, void(uint32_t)); @@ -228,12 +231,13 @@ class MockStreamEncoderFilterCallbacks : public StreamEncoderFilterCallbacks, Buffer::InstancePtr buffer_; testing::NiceMock active_span_; testing::NiceMock tracing_config_; + testing::NiceMock scope_; }; class MockStreamDecoderFilter : public StreamDecoderFilter { public: MockStreamDecoderFilter(); - ~MockStreamDecoderFilter(); + ~MockStreamDecoderFilter() override; // Http::StreamFilterBase MOCK_METHOD0(onDestroy, void()); @@ -252,7 +256,7 @@ class MockStreamDecoderFilter : public StreamDecoderFilter { class MockStreamEncoderFilter : public StreamEncoderFilter { public: MockStreamEncoderFilter(); - ~MockStreamEncoderFilter(); + ~MockStreamEncoderFilter() override; // Http::StreamFilterBase MOCK_METHOD0(onDestroy, void()); @@ -272,7 +276,7 @@ class MockStreamEncoderFilter : public StreamEncoderFilter { class MockStreamFilter : public StreamFilter { public: MockStreamFilter(); - ~MockStreamFilter(); + ~MockStreamFilter() override; // Http::StreamFilterBase MOCK_METHOD0(onDestroy, void()); @@ -299,7 +303,7 @@ class MockStreamFilter : public StreamFilter { class MockAsyncClient : public AsyncClient { public: MockAsyncClient(); - ~MockAsyncClient(); + ~MockAsyncClient() override; MOCK_METHOD0(onRequestDestroy, void()); @@ -321,7 +325,7 @@ class MockAsyncClient : public AsyncClient { class MockAsyncClientCallbacks : public AsyncClient::Callbacks { public: MockAsyncClientCallbacks(); - ~MockAsyncClientCallbacks(); + ~MockAsyncClientCallbacks() override; void onSuccess(MessagePtr&& response) override { onSuccess_(response.get()); } @@ -333,7 +337,7 @@ class MockAsyncClientCallbacks : public AsyncClient::Callbacks { class MockAsyncClientStreamCallbacks : public AsyncClient::StreamCallbacks { public: MockAsyncClientStreamCallbacks(); - ~MockAsyncClientStreamCallbacks(); + ~MockAsyncClientStreamCallbacks() override; void onHeaders(HeaderMapPtr&& headers, bool end_stream) override { onHeaders_(*headers, end_stream); @@ -349,7 +353,7 @@ class MockAsyncClientStreamCallbacks : public AsyncClient::StreamCallbacks { class MockAsyncClientRequest : public AsyncClient::Request { public: MockAsyncClientRequest(MockAsyncClient* client); - ~MockAsyncClientRequest(); + ~MockAsyncClientRequest() override; MOCK_METHOD0(cancel, void()); @@ -359,7 +363,7 @@ class MockAsyncClientRequest : public AsyncClient::Request { class MockAsyncClientStream : public AsyncClient::Stream { public: MockAsyncClientStream(); - ~MockAsyncClientStream(); + ~MockAsyncClientStream() override; MOCK_METHOD2(sendHeaders, void(HeaderMap& headers, bool end_stream)); MOCK_METHOD2(sendData, void(Buffer::Instance& data, bool end_stream)); @@ -370,7 +374,7 @@ class MockAsyncClientStream : public AsyncClient::Stream { class MockFilterChainFactoryCallbacks : public Http::FilterChainFactoryCallbacks { public: MockFilterChainFactoryCallbacks(); - ~MockFilterChainFactoryCallbacks(); + ~MockFilterChainFactoryCallbacks() override; MOCK_METHOD1(addStreamDecoderFilter, void(Http::StreamDecoderFilterSharedPtr filter)); MOCK_METHOD1(addStreamEncoderFilter, void(Http::StreamEncoderFilterSharedPtr filter)); diff --git a/test/mocks/http/stream.cc b/test/mocks/http/stream.cc index ef881fb8618c..95ef73f56c42 100644 --- a/test/mocks/http/stream.cc +++ b/test/mocks/http/stream.cc @@ -22,7 +22,7 @@ MockStream::MockStream() { })); } -MockStream::~MockStream() {} +MockStream::~MockStream() = default; } // namespace Http } // namespace Envoy diff --git a/test/mocks/http/stream_decoder.cc b/test/mocks/http/stream_decoder.cc index 592a55ce96a6..3c2c75aed33b 100644 --- a/test/mocks/http/stream_decoder.cc +++ b/test/mocks/http/stream_decoder.cc @@ -3,8 +3,8 @@ namespace Envoy { namespace Http { -MockStreamDecoder::MockStreamDecoder() {} -MockStreamDecoder::~MockStreamDecoder() {} +MockStreamDecoder::MockStreamDecoder() = default; +MockStreamDecoder::~MockStreamDecoder() = default; } // namespace Http } // namespace Envoy diff --git a/test/mocks/http/stream_encoder.cc b/test/mocks/http/stream_encoder.cc index da99c0b97035..98fdec782184 100644 --- a/test/mocks/http/stream_encoder.cc +++ b/test/mocks/http/stream_encoder.cc @@ -7,7 +7,7 @@ MockStreamEncoder::MockStreamEncoder() { ON_CALL(*this, getStream()).WillByDefault(ReturnRef(stream_)); } -MockStreamEncoder::~MockStreamEncoder() {} +MockStreamEncoder::~MockStreamEncoder() = default; } // namespace Http } // namespace Envoy diff --git a/test/mocks/http/stream_encoder.h b/test/mocks/http/stream_encoder.h index 5c2e067979e5..bc9138e37746 100644 --- a/test/mocks/http/stream_encoder.h +++ b/test/mocks/http/stream_encoder.h @@ -12,7 +12,7 @@ namespace Http { class MockStreamEncoder : public StreamEncoder { public: MockStreamEncoder(); - ~MockStreamEncoder(); + ~MockStreamEncoder() override; // Http::StreamEncoder MOCK_METHOD1(encode100ContinueHeaders, void(const HeaderMap& headers)); diff --git a/test/mocks/local_info/mocks.cc b/test/mocks/local_info/mocks.cc index 2f3a2e8ff4b7..7faff3e6b8b8 100644 --- a/test/mocks/local_info/mocks.cc +++ b/test/mocks/local_info/mocks.cc @@ -23,7 +23,7 @@ MockLocalInfo::MockLocalInfo() : address_(new Network::Address::Ipv4Instance("12 ON_CALL(*this, node()).WillByDefault(ReturnRef(node_)); } -MockLocalInfo::~MockLocalInfo() {} +MockLocalInfo::~MockLocalInfo() = default; } // namespace LocalInfo } // namespace Envoy diff --git a/test/mocks/local_info/mocks.h b/test/mocks/local_info/mocks.h index 6c53a2c19a3f..655eaaf59030 100644 --- a/test/mocks/local_info/mocks.h +++ b/test/mocks/local_info/mocks.h @@ -12,7 +12,7 @@ namespace LocalInfo { class MockLocalInfo : public LocalInfo { public: MockLocalInfo(); - ~MockLocalInfo(); + ~MockLocalInfo() override; MOCK_CONST_METHOD0(address, Network::Address::InstanceConstSharedPtr()); MOCK_CONST_METHOD0(zoneName, const std::string&()); diff --git a/test/mocks/network/connection.cc b/test/mocks/network/connection.cc index f329be222c68..915eb0e86c48 100644 --- a/test/mocks/network/connection.cc +++ b/test/mocks/network/connection.cc @@ -9,8 +9,8 @@ using testing::ReturnRef; namespace Envoy { namespace Network { -MockConnectionCallbacks::MockConnectionCallbacks() {} -MockConnectionCallbacks::~MockConnectionCallbacks() {} +MockConnectionCallbacks::MockConnectionCallbacks() = default; +MockConnectionCallbacks::~MockConnectionCallbacks() = default; uint64_t MockConnectionBase::next_id_; @@ -79,7 +79,7 @@ MockConnection::MockConnection() { remote_address_ = Utility::resolveUrl("tcp://10.0.0.3:50000"); initializeMockConnection(*this); } -MockConnection::~MockConnection() {} +MockConnection::~MockConnection() = default; MockClientConnection::MockClientConnection() { remote_address_ = Utility::resolveUrl("tcp://10.0.0.1:443"); @@ -87,7 +87,7 @@ MockClientConnection::MockClientConnection() { initializeMockConnection(*this); } -MockClientConnection::~MockClientConnection() {} +MockClientConnection::~MockClientConnection() = default; MockFilterManagerConnection::MockFilterManagerConnection() { remote_address_ = Utility::resolveUrl("tcp://10.0.0.3:50000"); @@ -98,7 +98,7 @@ MockFilterManagerConnection::MockFilterManagerConnection() { buffer.drain(buffer.length()); })); } -MockFilterManagerConnection::~MockFilterManagerConnection() {} +MockFilterManagerConnection::~MockFilterManagerConnection() = default; } // namespace Network } // namespace Envoy diff --git a/test/mocks/network/connection.h b/test/mocks/network/connection.h index 880802982a11..f660269de13a 100644 --- a/test/mocks/network/connection.h +++ b/test/mocks/network/connection.h @@ -17,7 +17,7 @@ namespace Network { class MockConnectionCallbacks : public ConnectionCallbacks { public: MockConnectionCallbacks(); - ~MockConnectionCallbacks(); + ~MockConnectionCallbacks() override; // Network::ConnectionCallbacks MOCK_METHOD1(onEvent, void(Network::ConnectionEvent event)); @@ -48,7 +48,7 @@ class MockConnectionBase { class MockConnection : public Connection, public MockConnectionBase { public: MockConnection(); - ~MockConnection(); + ~MockConnection() override; // Network::Connection MOCK_METHOD1(addConnectionCallbacks, void(ConnectionCallbacks& cb)); @@ -94,7 +94,7 @@ class MockConnection : public Connection, public MockConnectionBase { class MockClientConnection : public ClientConnection, public MockConnectionBase { public: MockClientConnection(); - ~MockClientConnection(); + ~MockClientConnection() override; // Network::Connection MOCK_METHOD1(addConnectionCallbacks, void(ConnectionCallbacks& cb)); @@ -143,7 +143,7 @@ class MockClientConnection : public ClientConnection, public MockConnectionBase class MockFilterManagerConnection : public FilterManagerConnection, public MockConnectionBase { public: MockFilterManagerConnection(); - ~MockFilterManagerConnection(); + ~MockFilterManagerConnection() override; // Network::Connection MOCK_METHOD1(addConnectionCallbacks, void(ConnectionCallbacks& cb)); diff --git a/test/mocks/network/mocks.cc b/test/mocks/network/mocks.cc index b3307515d5cc..6070d90c3fb2 100644 --- a/test/mocks/network/mocks.cc +++ b/test/mocks/network/mocks.cc @@ -30,22 +30,22 @@ MockListenerConfig::MockListenerConfig() { ON_CALL(*this, listenerScope()).WillByDefault(ReturnRef(scope_)); ON_CALL(*this, name()).WillByDefault(ReturnRef(name_)); } -MockListenerConfig::~MockListenerConfig() {} +MockListenerConfig::~MockListenerConfig() = default; -MockActiveDnsQuery::MockActiveDnsQuery() {} -MockActiveDnsQuery::~MockActiveDnsQuery() {} +MockActiveDnsQuery::MockActiveDnsQuery() = default; +MockActiveDnsQuery::~MockActiveDnsQuery() = default; MockDnsResolver::MockDnsResolver() { ON_CALL(*this, resolve(_, _, _)).WillByDefault(Return(&active_query_)); } -MockDnsResolver::~MockDnsResolver() {} +MockDnsResolver::~MockDnsResolver() = default; MockAddressResolver::MockAddressResolver() { ON_CALL(*this, name()).WillByDefault(Return("envoy.mock.resolver")); } -MockAddressResolver::~MockAddressResolver() {} +MockAddressResolver::~MockAddressResolver() = default; MockReadFilterCallbacks::MockReadFilterCallbacks() { ON_CALL(*this, connection()).WillByDefault(ReturnRef(connection_)); @@ -53,7 +53,7 @@ MockReadFilterCallbacks::MockReadFilterCallbacks() { ON_CALL(*this, upstreamHost(_)).WillByDefault(SaveArg<0>(&host_)); } -MockReadFilterCallbacks::~MockReadFilterCallbacks() {} +MockReadFilterCallbacks::~MockReadFilterCallbacks() = default; MockReadFilter::MockReadFilter() { ON_CALL(*this, onData(_, _)).WillByDefault(Return(FilterStatus::StopIteration)); @@ -62,20 +62,20 @@ MockReadFilter::MockReadFilter() { Invoke([this](ReadFilterCallbacks& callbacks) -> void { callbacks_ = &callbacks; })); } -MockReadFilter::~MockReadFilter() {} +MockReadFilter::~MockReadFilter() = default; MockWriteFilterCallbacks::MockWriteFilterCallbacks() { ON_CALL(*this, connection()).WillByDefault(ReturnRef(connection_)); } -MockWriteFilterCallbacks::~MockWriteFilterCallbacks() {} +MockWriteFilterCallbacks::~MockWriteFilterCallbacks() = default; MockWriteFilter::MockWriteFilter() { EXPECT_CALL(*this, initializeWriteFilterCallbacks(_)) .WillOnce(Invoke( [this](WriteFilterCallbacks& callbacks) -> void { write_callbacks_ = &callbacks; })); } -MockWriteFilter::~MockWriteFilter() {} +MockWriteFilter::~MockWriteFilter() = default; MockFilter::MockFilter() { EXPECT_CALL(*this, initializeReadFilterCallbacks(_)) @@ -86,39 +86,39 @@ MockFilter::MockFilter() { [this](WriteFilterCallbacks& callbacks) -> void { write_callbacks_ = &callbacks; })); } -MockFilter::~MockFilter() {} +MockFilter::~MockFilter() = default; -MockListenerCallbacks::MockListenerCallbacks() {} -MockListenerCallbacks::~MockListenerCallbacks() {} +MockListenerCallbacks::MockListenerCallbacks() = default; +MockListenerCallbacks::~MockListenerCallbacks() = default; -MockUdpListenerCallbacks::MockUdpListenerCallbacks() {} -MockUdpListenerCallbacks::~MockUdpListenerCallbacks() {} +MockUdpListenerCallbacks::MockUdpListenerCallbacks() = default; +MockUdpListenerCallbacks::~MockUdpListenerCallbacks() = default; -MockDrainDecision::MockDrainDecision() {} -MockDrainDecision::~MockDrainDecision() {} +MockDrainDecision::MockDrainDecision() = default; +MockDrainDecision::~MockDrainDecision() = default; -MockListenerFilter::MockListenerFilter() {} -MockListenerFilter::~MockListenerFilter() {} +MockListenerFilter::MockListenerFilter() = default; +MockListenerFilter::~MockListenerFilter() = default; MockListenerFilterCallbacks::MockListenerFilterCallbacks() { ON_CALL(*this, socket()).WillByDefault(ReturnRef(socket_)); } -MockListenerFilterCallbacks::~MockListenerFilterCallbacks() {} +MockListenerFilterCallbacks::~MockListenerFilterCallbacks() = default; -MockListenerFilterManager::MockListenerFilterManager() {} -MockListenerFilterManager::~MockListenerFilterManager() {} +MockListenerFilterManager::MockListenerFilterManager() = default; +MockListenerFilterManager::~MockListenerFilterManager() = default; -MockFilterChain::MockFilterChain() {} -MockFilterChain::~MockFilterChain() {} +MockFilterChain::MockFilterChain() = default; +MockFilterChain::~MockFilterChain() = default; -MockFilterChainManager::MockFilterChainManager() {} -MockFilterChainManager::~MockFilterChainManager() {} +MockFilterChainManager::MockFilterChainManager() = default; +MockFilterChainManager::~MockFilterChainManager() = default; MockFilterChainFactory::MockFilterChainFactory() { ON_CALL(*this, createListenerFilterChain(_)).WillByDefault(Return(true)); ON_CALL(*this, createUdpListenerFilterChain(_, _)).WillByDefault(Return(true)); } -MockFilterChainFactory::~MockFilterChainFactory() {} +MockFilterChainFactory::~MockFilterChainFactory() = default; MockListenSocket::MockListenSocket() : io_handle_(std::make_unique()), @@ -133,7 +133,7 @@ MockSocketOption::MockSocketOption() { ON_CALL(*this, setOption(_, _)).WillByDefault(Return(true)); } -MockSocketOption::~MockSocketOption() {} +MockSocketOption::~MockSocketOption() = default; MockConnectionSocket::MockConnectionSocket() : io_handle_(std::make_unique()), @@ -145,46 +145,46 @@ MockConnectionSocket::MockConnectionSocket() ON_CALL(testing::Const(*this), ioHandle()).WillByDefault(ReturnRef(*io_handle_)); } -MockListener::MockListener() {} +MockListener::MockListener() = default; MockListener::~MockListener() { onDestroy(); } -MockConnectionHandler::MockConnectionHandler() {} -MockConnectionHandler::~MockConnectionHandler() {} +MockConnectionHandler::MockConnectionHandler() = default; +MockConnectionHandler::~MockConnectionHandler() = default; -MockIp::MockIp() {} -MockIp::~MockIp() {} +MockIp::MockIp() = default; +MockIp::~MockIp() = default; -MockResolvedAddress::~MockResolvedAddress() {} +MockResolvedAddress::~MockResolvedAddress() = default; MockTransportSocket::MockTransportSocket() { ON_CALL(*this, setTransportSocketCallbacks(_)) .WillByDefault(Invoke([&](TransportSocketCallbacks& callbacks) { callbacks_ = &callbacks; })); } -MockTransportSocket::~MockTransportSocket() {} +MockTransportSocket::~MockTransportSocket() = default; -MockTransportSocketFactory::MockTransportSocketFactory() {} -MockTransportSocketFactory::~MockTransportSocketFactory() {} +MockTransportSocketFactory::MockTransportSocketFactory() = default; +MockTransportSocketFactory::~MockTransportSocketFactory() = default; MockTransportSocketCallbacks::MockTransportSocketCallbacks() { ON_CALL(*this, connection()).WillByDefault(ReturnRef(connection_)); } -MockTransportSocketCallbacks::~MockTransportSocketCallbacks() {} +MockTransportSocketCallbacks::~MockTransportSocketCallbacks() = default; -MockUdpListener::MockUdpListener() {} +MockUdpListener::MockUdpListener() = default; MockUdpListener::~MockUdpListener() { onDestroy(); } MockUdpReadFilterCallbacks::MockUdpReadFilterCallbacks() { ON_CALL(*this, udpListener()).WillByDefault(ReturnRef(udp_listener_)); } -MockUdpReadFilterCallbacks::~MockUdpReadFilterCallbacks() {} +MockUdpReadFilterCallbacks::~MockUdpReadFilterCallbacks() = default; MockUdpListenerReadFilter::MockUdpListenerReadFilter(UdpReadFilterCallbacks& callbacks) : UdpListenerReadFilter(callbacks) {} -MockUdpListenerReadFilter::~MockUdpListenerReadFilter() {} +MockUdpListenerReadFilter::~MockUdpListenerReadFilter() = default; -MockUdpListenerFilterManager::MockUdpListenerFilterManager() {} -MockUdpListenerFilterManager::~MockUdpListenerFilterManager() {} +MockUdpListenerFilterManager::MockUdpListenerFilterManager() = default; +MockUdpListenerFilterManager::~MockUdpListenerFilterManager() = default; } // namespace Network } // namespace Envoy diff --git a/test/mocks/network/mocks.h b/test/mocks/network/mocks.h index 80fec6e54c42..8d6401fd44ea 100644 --- a/test/mocks/network/mocks.h +++ b/test/mocks/network/mocks.h @@ -29,7 +29,7 @@ namespace Network { class MockActiveDnsQuery : public ActiveDnsQuery { public: MockActiveDnsQuery(); - ~MockActiveDnsQuery(); + ~MockActiveDnsQuery() override; // Network::ActiveDnsQuery MOCK_METHOD0(cancel, void()); @@ -38,7 +38,7 @@ class MockActiveDnsQuery : public ActiveDnsQuery { class MockDnsResolver : public DnsResolver { public: MockDnsResolver(); - ~MockDnsResolver(); + ~MockDnsResolver() override; // Network::DnsResolver MOCK_METHOD3(resolve, ActiveDnsQuery*(const std::string& dns_name, @@ -50,7 +50,7 @@ class MockDnsResolver : public DnsResolver { class MockAddressResolver : public Address::Resolver { public: MockAddressResolver(); - ~MockAddressResolver(); + ~MockAddressResolver() override; MOCK_METHOD1(resolve, Address::InstanceConstSharedPtr(const envoy::api::v2::core::SocketAddress&)); @@ -60,7 +60,7 @@ class MockAddressResolver : public Address::Resolver { class MockReadFilterCallbacks : public ReadFilterCallbacks { public: MockReadFilterCallbacks(); - ~MockReadFilterCallbacks(); + ~MockReadFilterCallbacks() override; MOCK_METHOD0(connection, Connection&()); MOCK_METHOD0(continueReading, void()); @@ -75,7 +75,7 @@ class MockReadFilterCallbacks : public ReadFilterCallbacks { class MockReadFilter : public ReadFilter { public: MockReadFilter(); - ~MockReadFilter(); + ~MockReadFilter() override; MOCK_METHOD2(onData, FilterStatus(Buffer::Instance& data, bool end_stream)); MOCK_METHOD0(onNewConnection, FilterStatus()); @@ -87,7 +87,7 @@ class MockReadFilter : public ReadFilter { class MockWriteFilterCallbacks : public WriteFilterCallbacks { public: MockWriteFilterCallbacks(); - ~MockWriteFilterCallbacks(); + ~MockWriteFilterCallbacks() override; MOCK_METHOD0(connection, Connection&()); MOCK_METHOD2(injectWriteDataToFilterChain, void(Buffer::Instance& data, bool end_stream)); @@ -98,7 +98,7 @@ class MockWriteFilterCallbacks : public WriteFilterCallbacks { class MockWriteFilter : public WriteFilter { public: MockWriteFilter(); - ~MockWriteFilter(); + ~MockWriteFilter() override; MOCK_METHOD2(onWrite, FilterStatus(Buffer::Instance& data, bool end_stream)); MOCK_METHOD1(initializeWriteFilterCallbacks, void(WriteFilterCallbacks& callbacks)); @@ -109,7 +109,7 @@ class MockWriteFilter : public WriteFilter { class MockFilter : public Filter { public: MockFilter(); - ~MockFilter(); + ~MockFilter() override; MOCK_METHOD2(onData, FilterStatus(Buffer::Instance& data, bool end_stream)); MOCK_METHOD0(onNewConnection, FilterStatus()); @@ -124,7 +124,7 @@ class MockFilter : public Filter { class MockListenerCallbacks : public ListenerCallbacks { public: MockListenerCallbacks(); - ~MockListenerCallbacks(); + ~MockListenerCallbacks() override; void onAccept(ConnectionSocketPtr&& socket, bool redirected) override { onAccept_(socket, redirected); @@ -138,7 +138,7 @@ class MockListenerCallbacks : public ListenerCallbacks { class MockUdpListenerCallbacks : public UdpListenerCallbacks { public: MockUdpListenerCallbacks(); - ~MockUdpListenerCallbacks(); + ~MockUdpListenerCallbacks() override; void onData(UdpRecvData& data) override { onData_(data); } @@ -158,7 +158,7 @@ class MockUdpListenerCallbacks : public UdpListenerCallbacks { class MockDrainDecision : public DrainDecision { public: MockDrainDecision(); - ~MockDrainDecision(); + ~MockDrainDecision() override; MOCK_CONST_METHOD0(drainClose, bool()); }; @@ -166,7 +166,7 @@ class MockDrainDecision : public DrainDecision { class MockListenerFilter : public ListenerFilter { public: MockListenerFilter(); - ~MockListenerFilter(); + ~MockListenerFilter() override; MOCK_METHOD1(onAccept, Network::FilterStatus(ListenerFilterCallbacks&)); }; @@ -174,7 +174,7 @@ class MockListenerFilter : public ListenerFilter { class MockListenerFilterManager : public ListenerFilterManager { public: MockListenerFilterManager(); - ~MockListenerFilterManager(); + ~MockListenerFilterManager() override; void addAcceptFilter(ListenerFilterPtr&& filter) override { addAcceptFilter_(filter); } @@ -184,7 +184,7 @@ class MockListenerFilterManager : public ListenerFilterManager { class MockFilterChain : public FilterChain { public: MockFilterChain(); - ~MockFilterChain(); + ~MockFilterChain() override; // Network::FilterChain MOCK_CONST_METHOD0(transportSocketFactory, const TransportSocketFactory&()); @@ -194,7 +194,7 @@ class MockFilterChain : public FilterChain { class MockFilterChainManager : public FilterChainManager { public: MockFilterChainManager(); - ~MockFilterChainManager(); + ~MockFilterChainManager() override; // Network::FilterChainManager MOCK_CONST_METHOD1(findFilterChain, const FilterChain*(const ConnectionSocket& socket)); @@ -203,7 +203,7 @@ class MockFilterChainManager : public FilterChainManager { class MockFilterChainFactory : public FilterChainFactory { public: MockFilterChainFactory(); - ~MockFilterChainFactory(); + ~MockFilterChainFactory() override; MOCK_METHOD2(createNetworkFilterChain, bool(Connection& connection, @@ -216,7 +216,7 @@ class MockFilterChainFactory : public FilterChainFactory { class MockListenSocket : public Socket { public: MockListenSocket(); - ~MockListenSocket() override {} + ~MockListenSocket() override = default; void addOption(const Socket::OptionConstSharedPtr& option) override { addOption_(option); } void addOptions(const Socket::OptionsSharedPtr& options) override { addOptions_(options); } @@ -239,7 +239,7 @@ class MockListenSocket : public Socket { class MockSocketOption : public Socket::Option { public: MockSocketOption(); - ~MockSocketOption(); + ~MockSocketOption() override; MOCK_CONST_METHOD2(setOption, bool(Socket&, envoy::api::v2::core::SocketOption::SocketState state)); @@ -252,7 +252,7 @@ class MockSocketOption : public Socket::Option { class MockConnectionSocket : public ConnectionSocket { public: MockConnectionSocket(); - ~MockConnectionSocket() override {} + ~MockConnectionSocket() override = default; void addOption(const Socket::OptionConstSharedPtr& option) override { addOption_(option); } void addOptions(const Socket::OptionsSharedPtr& options) override { addOptions_(options); } @@ -285,7 +285,7 @@ class MockConnectionSocket : public ConnectionSocket { class MockListenerFilterCallbacks : public ListenerFilterCallbacks { public: MockListenerFilterCallbacks(); - ~MockListenerFilterCallbacks(); + ~MockListenerFilterCallbacks() override; MOCK_METHOD0(socket, ConnectionSocket&()); MOCK_METHOD0(dispatcher, Event::Dispatcher&()); @@ -297,7 +297,7 @@ class MockListenerFilterCallbacks : public ListenerFilterCallbacks { class MockListenerConfig : public ListenerConfig { public: MockListenerConfig(); - ~MockListenerConfig(); + ~MockListenerConfig() override; MOCK_METHOD0(filterChainManager, FilterChainManager&()); MOCK_METHOD0(filterChainFactory, FilterChainFactory&()); @@ -320,7 +320,7 @@ class MockListenerConfig : public ListenerConfig { class MockListener : public Listener { public: MockListener(); - ~MockListener(); + ~MockListener() override; MOCK_METHOD0(onDestroy, void()); MOCK_METHOD0(enable, void()); @@ -330,7 +330,7 @@ class MockListener : public Listener { class MockConnectionHandler : public ConnectionHandler { public: MockConnectionHandler(); - ~MockConnectionHandler(); + ~MockConnectionHandler() override; MOCK_METHOD0(numConnections, uint64_t()); MOCK_METHOD1(addListener, void(ListenerConfig& config)); @@ -346,7 +346,7 @@ class MockConnectionHandler : public ConnectionHandler { class MockIp : public Address::Ip { public: MockIp(); - ~MockIp(); + ~MockIp() override; MOCK_CONST_METHOD0(addressAsString, const std::string&()); MOCK_CONST_METHOD0(isAnyAddress, bool()); @@ -361,7 +361,7 @@ class MockResolvedAddress : public Address::Instance { public: MockResolvedAddress(const std::string& logical, const std::string& physical) : logical_(logical), physical_(physical) {} - ~MockResolvedAddress(); + ~MockResolvedAddress() override; bool operator==(const Address::Instance& other) const override { return asString() == other.asString(); @@ -376,6 +376,7 @@ class MockResolvedAddress : public Address::Instance { MOCK_CONST_METHOD0(sockAddrLen, socklen_t()); const std::string& asString() const override { return physical_; } + absl::string_view asStringView() const override { return physical_; } const std::string& logicalName() const override { return logical_; } const std::string logical_; @@ -385,7 +386,7 @@ class MockResolvedAddress : public Address::Instance { class MockTransportSocket : public TransportSocket { public: MockTransportSocket(); - ~MockTransportSocket(); + ~MockTransportSocket() override; MOCK_METHOD1(setTransportSocketCallbacks, void(TransportSocketCallbacks& callbacks)); MOCK_CONST_METHOD0(protocol, std::string()); @@ -403,7 +404,7 @@ class MockTransportSocket : public TransportSocket { class MockTransportSocketFactory : public TransportSocketFactory { public: MockTransportSocketFactory(); - ~MockTransportSocketFactory(); + ~MockTransportSocketFactory() override; MOCK_CONST_METHOD0(implementsSecureTransport, bool()); MOCK_CONST_METHOD1(createTransportSocket, TransportSocketPtr(TransportSocketOptionsSharedPtr)); @@ -412,7 +413,7 @@ class MockTransportSocketFactory : public TransportSocketFactory { class MockTransportSocketCallbacks : public TransportSocketCallbacks { public: MockTransportSocketCallbacks(); - ~MockTransportSocketCallbacks(); + ~MockTransportSocketCallbacks() override; MOCK_METHOD0(ioHandle, IoHandle&()); MOCK_CONST_METHOD0(ioHandle, const IoHandle&()); @@ -427,7 +428,7 @@ class MockTransportSocketCallbacks : public TransportSocketCallbacks { class MockUdpListener : public UdpListener { public: MockUdpListener(); - ~MockUdpListener(); + ~MockUdpListener() override; MOCK_METHOD0(onDestroy, void()); MOCK_METHOD0(enable, void()); @@ -440,7 +441,7 @@ class MockUdpListener : public UdpListener { class MockUdpReadFilterCallbacks : public UdpReadFilterCallbacks { public: MockUdpReadFilterCallbacks(); - ~MockUdpReadFilterCallbacks(); + ~MockUdpReadFilterCallbacks() override; MOCK_METHOD0(udpListener, UdpListener&()); @@ -450,7 +451,7 @@ class MockUdpReadFilterCallbacks : public UdpReadFilterCallbacks { class MockUdpListenerReadFilter : public UdpListenerReadFilter { public: MockUdpListenerReadFilter(UdpReadFilterCallbacks& callbacks); - ~MockUdpListenerReadFilter(); + ~MockUdpListenerReadFilter() override; MOCK_METHOD1(onData, void(UdpRecvData&)); }; @@ -458,7 +459,7 @@ class MockUdpListenerReadFilter : public UdpListenerReadFilter { class MockUdpListenerFilterManager : public UdpListenerFilterManager { public: MockUdpListenerFilterManager(); - ~MockUdpListenerFilterManager(); + ~MockUdpListenerFilterManager() override; void addReadFilter(UdpListenerReadFilterPtr&& filter) override { addReadFilter_(filter); } diff --git a/test/mocks/protobuf/mocks.cc b/test/mocks/protobuf/mocks.cc index 95799456341c..908b08864fab 100644 --- a/test/mocks/protobuf/mocks.cc +++ b/test/mocks/protobuf/mocks.cc @@ -3,9 +3,9 @@ namespace Envoy { namespace ProtobufMessage { -MockValidationVisitor::MockValidationVisitor() {} +MockValidationVisitor::MockValidationVisitor() = default; -MockValidationVisitor::~MockValidationVisitor() {} +MockValidationVisitor::~MockValidationVisitor() = default; } // namespace ProtobufMessage } // namespace Envoy diff --git a/test/mocks/protobuf/mocks.h b/test/mocks/protobuf/mocks.h index 48c975e31ac1..66e2f5d2b9c1 100644 --- a/test/mocks/protobuf/mocks.h +++ b/test/mocks/protobuf/mocks.h @@ -10,7 +10,7 @@ namespace ProtobufMessage { class MockValidationVisitor : public ValidationVisitor { public: MockValidationVisitor(); - ~MockValidationVisitor(); + ~MockValidationVisitor() override; MOCK_METHOD1(onUnknownField, void(absl::string_view)); }; diff --git a/test/mocks/router/mocks.cc b/test/mocks/router/mocks.cc index f99496356e95..827e9c84f875 100644 --- a/test/mocks/router/mocks.cc +++ b/test/mocks/router/mocks.cc @@ -15,10 +15,10 @@ using testing::SaveArg; namespace Envoy { namespace Router { -MockDirectResponseEntry::MockDirectResponseEntry() {} -MockDirectResponseEntry::~MockDirectResponseEntry() {} +MockDirectResponseEntry::MockDirectResponseEntry() = default; +MockDirectResponseEntry::~MockDirectResponseEntry() = default; -MockRetryState::MockRetryState() {} +MockRetryState::MockRetryState() = default; void MockRetryState::expectHeadersRetry() { EXPECT_CALL(*this, shouldRetryHeaders(_, _)) @@ -35,43 +35,43 @@ void MockRetryState::expectResetRetry() { .WillOnce(DoAll(SaveArg<1>(&callback_), Return(RetryStatus::Yes))); } -MockRetryState::~MockRetryState() {} +MockRetryState::~MockRetryState() = default; MockRateLimitPolicyEntry::MockRateLimitPolicyEntry() { ON_CALL(*this, disableKey()).WillByDefault(ReturnRef(disable_key_)); } -MockRateLimitPolicyEntry::~MockRateLimitPolicyEntry() {} +MockRateLimitPolicyEntry::~MockRateLimitPolicyEntry() = default; MockRateLimitPolicy::MockRateLimitPolicy() { ON_CALL(*this, getApplicableRateLimit(_)).WillByDefault(ReturnRef(rate_limit_policy_entry_)); ON_CALL(*this, empty()).WillByDefault(Return(true)); } -MockRateLimitPolicy::~MockRateLimitPolicy() {} +MockRateLimitPolicy::~MockRateLimitPolicy() = default; -MockShadowWriter::MockShadowWriter() {} -MockShadowWriter::~MockShadowWriter() {} +MockShadowWriter::MockShadowWriter() = default; +MockShadowWriter::~MockShadowWriter() = default; MockVirtualHost::MockVirtualHost() { ON_CALL(*this, name()).WillByDefault(ReturnRef(name_)); ON_CALL(*this, rateLimitPolicy()).WillByDefault(ReturnRef(rate_limit_policy_)); } -MockVirtualHost::~MockVirtualHost() {} +MockVirtualHost::~MockVirtualHost() = default; -MockHashPolicy::MockHashPolicy() {} -MockHashPolicy::~MockHashPolicy() {} +MockHashPolicy::MockHashPolicy() = default; +MockHashPolicy::~MockHashPolicy() = default; -MockMetadataMatchCriteria::MockMetadataMatchCriteria() {} -MockMetadataMatchCriteria::~MockMetadataMatchCriteria() {} +MockMetadataMatchCriteria::MockMetadataMatchCriteria() = default; +MockMetadataMatchCriteria::~MockMetadataMatchCriteria() = default; MockPathMatchCriterion::MockPathMatchCriterion() { ON_CALL(*this, matchType()).WillByDefault(ReturnPointee(&type_)); ON_CALL(*this, matcher()).WillByDefault(ReturnPointee(&matcher_)); } -MockPathMatchCriterion::~MockPathMatchCriterion() {} +MockPathMatchCriterion::~MockPathMatchCriterion() = default; MockRouteEntry::MockRouteEntry() { ON_CALL(*this, clusterName()).WillByDefault(ReturnRef(cluster_name_)); @@ -90,7 +90,7 @@ MockRouteEntry::MockRouteEntry() { ON_CALL(*this, routeName()).WillByDefault(ReturnRef(route_name_)); } -MockRouteEntry::~MockRouteEntry() {} +MockRouteEntry::~MockRouteEntry() = default; MockConfig::MockConfig() : route_(new NiceMock()) { ON_CALL(*this, route(_, _)).WillByDefault(Return(route_)); @@ -99,28 +99,28 @@ MockConfig::MockConfig() : route_(new NiceMock()) { ON_CALL(*this, usesVhds()).WillByDefault(Return(false)); } -MockConfig::~MockConfig() {} +MockConfig::~MockConfig() = default; MockDecorator::MockDecorator() { ON_CALL(*this, getOperation()).WillByDefault(ReturnRef(operation_)); } -MockDecorator::~MockDecorator() {} +MockDecorator::~MockDecorator() = default; -MockRouteTracing::MockRouteTracing() {} -MockRouteTracing::~MockRouteTracing() {} +MockRouteTracing::MockRouteTracing() = default; +MockRouteTracing::~MockRouteTracing() = default; MockRoute::MockRoute() { ON_CALL(*this, routeEntry()).WillByDefault(Return(&route_entry_)); ON_CALL(*this, decorator()).WillByDefault(Return(&decorator_)); ON_CALL(*this, tracingConfig()).WillByDefault(Return(nullptr)); } -MockRoute::~MockRoute() {} +MockRoute::~MockRoute() = default; -MockRouteConfigProviderManager::MockRouteConfigProviderManager() {} -MockRouteConfigProviderManager::~MockRouteConfigProviderManager() {} +MockRouteConfigProviderManager::MockRouteConfigProviderManager() = default; +MockRouteConfigProviderManager::~MockRouteConfigProviderManager() = default; -MockScopedConfig::MockScopedConfig() {} -MockScopedConfig::~MockScopedConfig() {} +MockScopedConfig::MockScopedConfig() = default; +MockScopedConfig::~MockScopedConfig() = default; } // namespace Router } // namespace Envoy diff --git a/test/mocks/router/mocks.h b/test/mocks/router/mocks.h index f84aacda8ab8..aeda21400f98 100644 --- a/test/mocks/router/mocks.h +++ b/test/mocks/router/mocks.h @@ -34,7 +34,7 @@ namespace Router { class MockDirectResponseEntry : public DirectResponseEntry { public: MockDirectResponseEntry(); - ~MockDirectResponseEntry(); + ~MockDirectResponseEntry() override; // DirectResponseEntry MOCK_CONST_METHOD2(finalizeResponseHeaders, @@ -112,7 +112,7 @@ class TestRetryPolicy : public RetryPolicy { class MockRetryState : public RetryState { public: MockRetryState(); - ~MockRetryState(); + ~MockRetryState() override; void expectHeadersRetry(); void expectHedgedPerTryTimeoutRetry(); @@ -138,7 +138,7 @@ class MockRetryState : public RetryState { class MockRateLimitPolicyEntry : public RateLimitPolicyEntry { public: MockRateLimitPolicyEntry(); - ~MockRateLimitPolicyEntry(); + ~MockRateLimitPolicyEntry() override; // Router::RateLimitPolicyEntry MOCK_CONST_METHOD0(stage, uint64_t()); @@ -156,7 +156,7 @@ class MockRateLimitPolicyEntry : public RateLimitPolicyEntry { class MockRateLimitPolicy : public RateLimitPolicy { public: MockRateLimitPolicy(); - ~MockRateLimitPolicy(); + ~MockRateLimitPolicy() override; // Router::RateLimitPolicy MOCK_CONST_METHOD1( @@ -182,7 +182,7 @@ class TestShadowPolicy : public ShadowPolicy { class MockShadowWriter : public ShadowWriter { public: MockShadowWriter(); - ~MockShadowWriter(); + ~MockShadowWriter() override; // Router::ShadowWriter void shadow(const std::string& cluster, Http::MessagePtr&& request, @@ -206,7 +206,7 @@ class TestVirtualCluster : public VirtualCluster { class MockVirtualHost : public VirtualHost { public: MockVirtualHost(); - ~MockVirtualHost(); + ~MockVirtualHost() override; // Router::VirtualHost MOCK_CONST_METHOD0(name, const std::string&()); @@ -233,7 +233,7 @@ class MockVirtualHost : public VirtualHost { class MockHashPolicy : public HashPolicy { public: MockHashPolicy(); - ~MockHashPolicy(); + ~MockHashPolicy() override; // Router::HashPolicy MOCK_CONST_METHOD3(generateHash, @@ -245,7 +245,7 @@ class MockHashPolicy : public HashPolicy { class MockMetadataMatchCriteria : public MetadataMatchCriteria { public: MockMetadataMatchCriteria(); - ~MockMetadataMatchCriteria(); + ~MockMetadataMatchCriteria() override; // Router::MetadataMatchCriteria MOCK_CONST_METHOD0(metadataMatchCriteria, @@ -256,7 +256,7 @@ class MockMetadataMatchCriteria : public MetadataMatchCriteria { class MockPathMatchCriterion : public PathMatchCriterion { public: MockPathMatchCriterion(); - ~MockPathMatchCriterion(); + ~MockPathMatchCriterion() override; // Router::PathMatchCriterion MOCK_CONST_METHOD0(matchType, PathMatchType()); @@ -269,7 +269,7 @@ class MockPathMatchCriterion : public PathMatchCriterion { class MockRouteEntry : public RouteEntry { public: MockRouteEntry(); - ~MockRouteEntry(); + ~MockRouteEntry() override; // Router::Config MOCK_CONST_METHOD0(clusterName, const std::string&()); @@ -326,7 +326,7 @@ class MockRouteEntry : public RouteEntry { class MockDecorator : public Decorator { public: MockDecorator(); - ~MockDecorator(); + ~MockDecorator() override; // Router::Decorator MOCK_CONST_METHOD0(getOperation, const std::string&()); @@ -338,7 +338,7 @@ class MockDecorator : public Decorator { class MockRouteTracing : public RouteTracing { public: MockRouteTracing(); - ~MockRouteTracing(); + ~MockRouteTracing() override; // Router::RouteTracing MOCK_CONST_METHOD0(getClientSampling, const envoy::type::FractionalPercent&()); @@ -349,7 +349,7 @@ class MockRouteTracing : public RouteTracing { class MockRoute : public Route { public: MockRoute(); - ~MockRoute(); + ~MockRoute() override; // Router::Route MOCK_CONST_METHOD0(directResponseEntry, const DirectResponseEntry*()); @@ -366,7 +366,7 @@ class MockRoute : public Route { class MockConfig : public Config { public: MockConfig(); - ~MockConfig(); + ~MockConfig() override; // Router::Config MOCK_CONST_METHOD2(route, RouteConstSharedPtr(const Http::HeaderMap&, uint64_t random_value)); @@ -382,7 +382,7 @@ class MockConfig : public Config { class MockRouteConfigProviderManager : public RouteConfigProviderManager { public: MockRouteConfigProviderManager(); - ~MockRouteConfigProviderManager(); + ~MockRouteConfigProviderManager() override; MOCK_METHOD3(createRdsRouteConfigProvider, RouteConfigProviderPtr( @@ -397,7 +397,7 @@ class MockRouteConfigProviderManager : public RouteConfigProviderManager { class MockScopedConfig : public ScopedConfig { public: MockScopedConfig(); - ~MockScopedConfig(); + ~MockScopedConfig() override; MOCK_CONST_METHOD1(getRouteConfig, ConfigConstSharedPtr(const Http::HeaderMap& headers)); }; diff --git a/test/mocks/runtime/mocks.cc b/test/mocks/runtime/mocks.cc index acc39e811d86..c0415b560e44 100644 --- a/test/mocks/runtime/mocks.cc +++ b/test/mocks/runtime/mocks.cc @@ -12,19 +12,19 @@ namespace Runtime { MockRandomGenerator::MockRandomGenerator() { ON_CALL(*this, uuid()).WillByDefault(Return(uuid_)); } -MockRandomGenerator::~MockRandomGenerator() {} +MockRandomGenerator::~MockRandomGenerator() = default; MockSnapshot::MockSnapshot() { ON_CALL(*this, getInteger(_, _)).WillByDefault(ReturnArg<1>()); } -MockSnapshot::~MockSnapshot() {} +MockSnapshot::~MockSnapshot() = default; MockLoader::MockLoader() { ON_CALL(*this, snapshot()).WillByDefault(ReturnRef(snapshot_)); } -MockLoader::~MockLoader() {} +MockLoader::~MockLoader() = default; -MockOverrideLayer::MockOverrideLayer() {} +MockOverrideLayer::MockOverrideLayer() = default; -MockOverrideLayer::~MockOverrideLayer() {} +MockOverrideLayer::~MockOverrideLayer() = default; } // namespace Runtime } // namespace Envoy diff --git a/test/mocks/runtime/mocks.h b/test/mocks/runtime/mocks.h index e67e34361958..388d789a8940 100644 --- a/test/mocks/runtime/mocks.h +++ b/test/mocks/runtime/mocks.h @@ -15,7 +15,7 @@ namespace Runtime { class MockRandomGenerator : public RandomGenerator { public: MockRandomGenerator(); - ~MockRandomGenerator(); + ~MockRandomGenerator() override; MOCK_METHOD0(random, uint64_t()); MOCK_METHOD0(uuid, std::string()); @@ -60,10 +60,11 @@ class MockSnapshot : public Snapshot { class MockLoader : public Loader { public: MockLoader(); - ~MockLoader(); + ~MockLoader() override; MOCK_METHOD1(initialize, void(Upstream::ClusterManager& cm)); - MOCK_METHOD0(snapshot, Snapshot&()); + MOCK_METHOD0(snapshot, const Snapshot&()); + MOCK_METHOD0(threadsafeSnapshot, std::shared_ptr()); MOCK_METHOD1(mergeValues, void(const std::unordered_map&)); testing::NiceMock snapshot_; @@ -72,7 +73,7 @@ class MockLoader : public Loader { class MockOverrideLayer : public Snapshot::OverrideLayer { public: MockOverrideLayer(); - ~MockOverrideLayer(); + ~MockOverrideLayer() override; MOCK_CONST_METHOD0(name, const std::string&()); MOCK_CONST_METHOD0(values, const Snapshot::EntryMap&()); diff --git a/test/mocks/secret/mocks.cc b/test/mocks/secret/mocks.cc index 3bacd5fe9894..30fd6ae5d622 100644 --- a/test/mocks/secret/mocks.cc +++ b/test/mocks/secret/mocks.cc @@ -21,11 +21,11 @@ MockSecretManager::MockSecretManager() { })); } -MockSecretManager::~MockSecretManager() {} +MockSecretManager::~MockSecretManager() = default; -MockSecretCallbacks::MockSecretCallbacks() {} +MockSecretCallbacks::MockSecretCallbacks() = default; -MockSecretCallbacks::~MockSecretCallbacks() {} +MockSecretCallbacks::~MockSecretCallbacks() = default; } // namespace Secret } // namespace Envoy diff --git a/test/mocks/secret/mocks.h b/test/mocks/secret/mocks.h index 428f1ec28faa..2f3f2c5f073e 100644 --- a/test/mocks/secret/mocks.h +++ b/test/mocks/secret/mocks.h @@ -14,7 +14,7 @@ namespace Secret { class MockSecretManager : public SecretManager { public: MockSecretManager(); - ~MockSecretManager(); + ~MockSecretManager() override; MOCK_METHOD1(addStaticSecret, void(const envoy::api::v2::auth::Secret& secret)); MOCK_CONST_METHOD1(findStaticTlsCertificateProvider, @@ -42,7 +42,7 @@ class MockSecretManager : public SecretManager { class MockSecretCallbacks : public SecretCallbacks { public: MockSecretCallbacks(); - ~MockSecretCallbacks(); + ~MockSecretCallbacks() override; MOCK_METHOD0(onAddOrUpdateSecret, void()); }; diff --git a/test/mocks/server/BUILD b/test/mocks/server/BUILD index f6384d37070d..5d368f3c78ba 100644 --- a/test/mocks/server/BUILD +++ b/test/mocks/server/BUILD @@ -45,5 +45,6 @@ envoy_cc_mock( "//test/mocks/tracing:tracing_mocks", "//test/mocks/upstream:upstream_mocks", "//test/test_common:test_time_lib", + "@envoy_api//envoy/config/bootstrap/v2:bootstrap_cc", ], ) diff --git a/test/mocks/server/mocks.cc b/test/mocks/server/mocks.cc index bfaa237f50d5..e1006497c8ba 100644 --- a/test/mocks/server/mocks.cc +++ b/test/mocks/server/mocks.cc @@ -21,6 +21,7 @@ namespace Server { MockOptions::MockOptions(const std::string& config_path) : config_path_(config_path) { ON_CALL(*this, concurrency()).WillByDefault(ReturnPointee(&concurrency_)); ON_CALL(*this, configPath()).WillByDefault(ReturnRef(config_path_)); + ON_CALL(*this, configProto()).WillByDefault(ReturnRef(config_proto_)); ON_CALL(*this, configYaml()).WillByDefault(ReturnRef(config_yaml_)); ON_CALL(*this, adminAddressPath()).WillByDefault(ReturnRef(admin_address_path_)); ON_CALL(*this, serviceClusterName()).WillByDefault(ReturnRef(service_cluster_name_)); @@ -124,8 +125,8 @@ MockWorker::MockWorker() { MockWorker::~MockWorker() = default; MockInstance::MockInstance() - : secret_manager_(new Secret::SecretManagerImpl()), cluster_manager_(timeSource()), - ssl_context_manager_(timeSource()), + : secret_manager_(std::make_unique(admin_.getConfigTracker())), + cluster_manager_(timeSource()), ssl_context_manager_(timeSource()), singleton_manager_(new Singleton::ManagerImpl(Thread::threadFactoryForTest())), grpc_context_(stats_store_.symbolTable()), http_context_(stats_store_.symbolTable()) { ON_CALL(*this, threadLocal()).WillByDefault(ReturnRef(thread_local_)); @@ -197,7 +198,7 @@ MockFactoryContext::MockFactoryContext() MockFactoryContext::~MockFactoryContext() = default; MockTransportSocketFactoryContext::MockTransportSocketFactoryContext() - : secret_manager_(new Secret::SecretManagerImpl()) { + : secret_manager_(std::make_unique(config_tracker_)) { ON_CALL(*this, clusterManager()).WillByDefault(ReturnRef(cluster_manager_)); ON_CALL(*this, api()).WillByDefault(ReturnRef(api_)); ON_CALL(*this, messageValidationVisitor()) diff --git a/test/mocks/server/mocks.h b/test/mocks/server/mocks.h index 6ab3baac302c..7df622152422 100644 --- a/test/mocks/server/mocks.h +++ b/test/mocks/server/mocks.h @@ -6,6 +6,7 @@ #include #include "envoy/common/mutex_tracer.h" +#include "envoy/config/bootstrap/v2/bootstrap.pb.h" #include "envoy/server/admin.h" #include "envoy/server/configuration.h" #include "envoy/server/drain_manager.h" @@ -59,6 +60,7 @@ class MockOptions : public Options { MOCK_CONST_METHOD0(baseId, uint64_t()); MOCK_CONST_METHOD0(concurrency, uint32_t()); MOCK_CONST_METHOD0(configPath, const std::string&()); + MOCK_CONST_METHOD0(configProto, const envoy::config::bootstrap::v2::Bootstrap&()); MOCK_CONST_METHOD0(configYaml, const std::string&()); MOCK_CONST_METHOD0(allowUnknownFields, bool()); MOCK_CONST_METHOD0(adminAddressPath, const std::string&()); @@ -84,6 +86,7 @@ class MockOptions : public Options { MOCK_CONST_METHOD0(toCommandLineOptions, Server::CommandLineOptionsPtr()); std::string config_path_; + envoy::config::bootstrap::v2::Bootstrap config_proto_; std::string config_yaml_; std::string admin_address_path_; std::string service_cluster_name_; @@ -128,9 +131,10 @@ class MockAdmin : public Admin { MOCK_METHOD1(removeHandler, bool(const std::string& prefix)); MOCK_METHOD0(socket, Network::Socket&()); MOCK_METHOD0(getConfigTracker, ConfigTracker&()); - MOCK_METHOD4(startHttpListener, + MOCK_METHOD5(startHttpListener, void(const std::string& access_log_path, const std::string& address_out_path, Network::Address::InstanceConstSharedPtr address, + const Network::Socket::OptionsSharedPtr& socket_options, Stats::ScopePtr&& listener_scope)); MOCK_METHOD4(request, Http::Code(absl::string_view path_and_query, absl::string_view method, Http::HeaderMap& response_headers, std::string& body)); @@ -206,13 +210,13 @@ class MockHotRestart : public HotRestart { MOCK_METHOD0(version, std::string()); MOCK_METHOD0(logLock, Thread::BasicLockable&()); MOCK_METHOD0(accessLogLock, Thread::BasicLockable&()); - MOCK_METHOD0(statsAllocator, Stats::StatDataAllocator&()); + MOCK_METHOD0(statsAllocator, Stats::Allocator&()); private: Test::Global symbol_table_; Thread::MutexBasicLockable log_lock_; Thread::MutexBasicLockable access_log_lock_; - Stats::HeapStatDataAllocator stats_allocator_; + Stats::AllocatorImpl stats_allocator_; }; class MockListenerComponentFactory : public ListenerComponentFactory { @@ -380,7 +384,6 @@ class MockInstance : public Instance { TimeSource& timeSource() override { return time_system_; } - std::unique_ptr secret_manager_; testing::NiceMock thread_local_; NiceMock stats_store_; std::shared_ptr> dns_resolver_{ @@ -388,6 +391,7 @@ class MockInstance : public Instance { testing::NiceMock api_; testing::NiceMock admin_; Event::GlobalTimeSystem time_system_; + std::unique_ptr secret_manager_; testing::NiceMock cluster_manager_; Thread::MutexBasicLockable access_log_lock_; testing::NiceMock runtime_loader_; @@ -507,8 +511,9 @@ class MockTransportSocketFactoryContext : public TransportSocketFactoryContext { MOCK_METHOD0(api, Api::Api&()); testing::NiceMock cluster_manager_; - std::unique_ptr secret_manager_; testing::NiceMock api_; + testing::NiceMock config_tracker_; + std::unique_ptr secret_manager_; }; class MockListenerFactoryContext : public MockFactoryContext, public ListenerFactoryContext { @@ -516,14 +521,6 @@ class MockListenerFactoryContext : public MockFactoryContext, public ListenerFac MockListenerFactoryContext(); ~MockListenerFactoryContext() override; - void addListenSocketOption(const Network::Socket::OptionConstSharedPtr& option) override { - addListenSocketOption_(option); - } - MOCK_METHOD1(addListenSocketOption_, void(const Network::Socket::OptionConstSharedPtr&)); - void addListenSocketOptions(const Network::Socket::OptionsSharedPtr& options) override { - addListenSocketOptions_(options); - } - MOCK_METHOD1(addListenSocketOptions_, void(const Network::Socket::OptionsSharedPtr&)); const Network::ListenerConfig& listenerConfig() const override { return _listenerConfig_; } MOCK_CONST_METHOD0(listenerConfig_, const Network::ListenerConfig&()); diff --git a/test/mocks/ssl/mocks.cc b/test/mocks/ssl/mocks.cc index 3318d4ec9804..72702de823ed 100644 --- a/test/mocks/ssl/mocks.cc +++ b/test/mocks/ssl/mocks.cc @@ -3,20 +3,20 @@ namespace Envoy { namespace Ssl { -MockContextManager::MockContextManager() {} -MockContextManager::~MockContextManager() {} +MockContextManager::MockContextManager() = default; +MockContextManager::~MockContextManager() = default; -MockConnectionInfo::MockConnectionInfo() {} -MockConnectionInfo::~MockConnectionInfo() {} +MockConnectionInfo::MockConnectionInfo() = default; +MockConnectionInfo::~MockConnectionInfo() = default; -MockClientContext::MockClientContext() {} -MockClientContext::~MockClientContext() {} +MockClientContext::MockClientContext() = default; +MockClientContext::~MockClientContext() = default; -MockClientContextConfig::MockClientContextConfig() {} -MockClientContextConfig::~MockClientContextConfig() {} +MockClientContextConfig::MockClientContextConfig() = default; +MockClientContextConfig::~MockClientContextConfig() = default; -MockServerContextConfig::MockServerContextConfig() {} -MockServerContextConfig::~MockServerContextConfig() {} +MockServerContextConfig::MockServerContextConfig() = default; +MockServerContextConfig::~MockServerContextConfig() = default; } // namespace Ssl } // namespace Envoy diff --git a/test/mocks/ssl/mocks.h b/test/mocks/ssl/mocks.h index cd91a237327f..20621bd29ca4 100644 --- a/test/mocks/ssl/mocks.h +++ b/test/mocks/ssl/mocks.h @@ -20,7 +20,7 @@ namespace Ssl { class MockContextManager : public ContextManager { public: MockContextManager(); - ~MockContextManager(); + ~MockContextManager() override; MOCK_METHOD2(createSslClientContext, ClientContextSharedPtr(Stats::Scope& scope, const ClientContextConfig& config)); @@ -34,7 +34,7 @@ class MockContextManager : public ContextManager { class MockConnectionInfo : public ConnectionInfo { public: MockConnectionInfo(); - ~MockConnectionInfo(); + ~MockConnectionInfo() override; MOCK_CONST_METHOD0(peerCertificatePresented, bool()); MOCK_CONST_METHOD0(uriSanLocalCertificate, std::vector()); @@ -59,7 +59,7 @@ class MockConnectionInfo : public ConnectionInfo { class MockClientContext : public ClientContext { public: MockClientContext(); - ~MockClientContext(); + ~MockClientContext() override; MOCK_CONST_METHOD0(daysUntilFirstCertExpires, size_t()); MOCK_CONST_METHOD0(getCaCertInformation, CertificateDetailsPtr()); @@ -69,7 +69,7 @@ class MockClientContext : public ClientContext { class MockClientContextConfig : public ClientContextConfig { public: MockClientContextConfig(); - ~MockClientContextConfig(); + ~MockClientContextConfig() override; MOCK_CONST_METHOD0(alpnProtocols, const std::string&()); MOCK_CONST_METHOD0(cipherSuites, const std::string&()); @@ -91,7 +91,7 @@ class MockClientContextConfig : public ClientContextConfig { class MockServerContextConfig : public ServerContextConfig { public: MockServerContextConfig(); - ~MockServerContextConfig(); + ~MockServerContextConfig() override; MOCK_CONST_METHOD0(alpnProtocols, const std::string&()); MOCK_CONST_METHOD0(cipherSuites, const std::string&()); diff --git a/test/mocks/stats/mocks.h b/test/mocks/stats/mocks.h index 987e86c43fa7..d418ad430f2b 100644 --- a/test/mocks/stats/mocks.h +++ b/test/mocks/stats/mocks.h @@ -271,10 +271,9 @@ class MockStore : public SymbolTableProvider, public StoreImpl { MOCK_METHOD1(histogram, Histogram&(const std::string& name)); MOCK_CONST_METHOD0(histograms, std::vector()); - MOCK_CONST_METHOD1(findCounter, absl::optional>(StatName)); - MOCK_CONST_METHOD1(findGauge, absl::optional>(StatName)); - MOCK_CONST_METHOD1(findHistogram, - absl::optional>(StatName)); + MOCK_CONST_METHOD1(findCounter, OptionalCounter(StatName)); + MOCK_CONST_METHOD1(findGauge, OptionalGauge(StatName)); + MOCK_CONST_METHOD1(findHistogram, OptionalHistogram(StatName)); Counter& counterFromStatName(StatName name) override { return counter(symbol_table_->toString(name)); diff --git a/test/mocks/stream_info/mocks.cc b/test/mocks/stream_info/mocks.cc index 0d102036dd90..6c842c9ecb3c 100644 --- a/test/mocks/stream_info/mocks.cc +++ b/test/mocks/stream_info/mocks.cc @@ -96,7 +96,7 @@ MockStreamInfo::MockStreamInfo() .WillByDefault(ReturnRef(upstream_transport_failure_reason_)); } -MockStreamInfo::~MockStreamInfo() {} +MockStreamInfo::~MockStreamInfo() = default; } // namespace StreamInfo } // namespace Envoy diff --git a/test/mocks/stream_info/mocks.h b/test/mocks/stream_info/mocks.h index 9332fec087ec..0fbd34222291 100644 --- a/test/mocks/stream_info/mocks.h +++ b/test/mocks/stream_info/mocks.h @@ -14,7 +14,7 @@ namespace StreamInfo { class MockStreamInfo : public StreamInfo { public: MockStreamInfo(); - ~MockStreamInfo(); + ~MockStreamInfo() override; // StreamInfo::StreamInfo MOCK_METHOD1(setResponseFlag, void(ResponseFlag response_flag)); diff --git a/test/mocks/tcp/mocks.cc b/test/mocks/tcp/mocks.cc index d9ffcc2f79e7..be7f9046fdb1 100644 --- a/test/mocks/tcp/mocks.cc +++ b/test/mocks/tcp/mocks.cc @@ -12,13 +12,13 @@ namespace Envoy { namespace Tcp { namespace ConnectionPool { -MockCancellable::MockCancellable() {} -MockCancellable::~MockCancellable() {} +MockCancellable::MockCancellable() = default; +MockCancellable::~MockCancellable() = default; -MockUpstreamCallbacks::MockUpstreamCallbacks() {} -MockUpstreamCallbacks::~MockUpstreamCallbacks() {} +MockUpstreamCallbacks::MockUpstreamCallbacks() = default; +MockUpstreamCallbacks::~MockUpstreamCallbacks() = default; -MockConnectionData::MockConnectionData() {} +MockConnectionData::MockConnectionData() = default; MockConnectionData::~MockConnectionData() { if (release_callback_) { release_callback_(); @@ -30,7 +30,7 @@ MockInstance::MockInstance() { return newConnectionImpl(cb); })); } -MockInstance::~MockInstance() {} +MockInstance::~MockInstance() = default; MockCancellable* MockInstance::newConnectionImpl(Callbacks& cb) { handles_.emplace_back(); diff --git a/test/mocks/tcp/mocks.h b/test/mocks/tcp/mocks.h index 3f864ec3296d..5ac8b8ee6f80 100644 --- a/test/mocks/tcp/mocks.h +++ b/test/mocks/tcp/mocks.h @@ -18,7 +18,7 @@ namespace ConnectionPool { class MockCancellable : public Cancellable { public: MockCancellable(); - ~MockCancellable(); + ~MockCancellable() override; // Tcp::ConnectionPool::Cancellable MOCK_METHOD1(cancel, void(CancelPolicy cancel_policy)); @@ -27,7 +27,7 @@ class MockCancellable : public Cancellable { class MockUpstreamCallbacks : public UpstreamCallbacks { public: MockUpstreamCallbacks(); - ~MockUpstreamCallbacks(); + ~MockUpstreamCallbacks() override; // Tcp::ConnectionPool::UpstreamCallbacks MOCK_METHOD2(onUpstreamData, void(Buffer::Instance& data, bool end_stream)); @@ -39,7 +39,7 @@ class MockUpstreamCallbacks : public UpstreamCallbacks { class MockConnectionData : public ConnectionData { public: MockConnectionData(); - ~MockConnectionData(); + ~MockConnectionData() override; // Tcp::ConnectionPool::ConnectionData MOCK_METHOD0(connection, Network::ClientConnection&()); @@ -57,7 +57,7 @@ class MockConnectionData : public ConnectionData { class MockInstance : public Instance { public: MockInstance(); - ~MockInstance(); + ~MockInstance() override; // Tcp::ConnectionPool::Instance MOCK_METHOD1(addDrainedCallback, void(DrainedCb cb)); diff --git a/test/mocks/thread_local/mocks.h b/test/mocks/thread_local/mocks.h index 24393722887a..3d7a43efaef8 100644 --- a/test/mocks/thread_local/mocks.h +++ b/test/mocks/thread_local/mocks.h @@ -15,7 +15,7 @@ namespace ThreadLocal { class MockInstance : public Instance { public: MockInstance(); - ~MockInstance(); + ~MockInstance() override; MOCK_METHOD1(runOnAllThreads, void(Event::PostCb cb)); MOCK_METHOD2(runOnAllThreads, void(Event::PostCb cb, Event::PostCb main_callback)); @@ -48,7 +48,7 @@ class MockInstance : public Instance { parent_.data_.resize(index_ + 1); } - ~SlotImpl() { + ~SlotImpl() override { // Do not actually clear slot data during shutdown. This mimics the production code. if (!parent_.shutdown_) { EXPECT_LT(index_, parent_.data_.size()); @@ -58,6 +58,7 @@ class MockInstance : public Instance { // ThreadLocal::Slot ThreadLocalObjectSharedPtr get() override { return parent_.data_[index_]; } + bool currentThreadRegistered() override { return parent_.registered_; } void runOnAllThreads(Event::PostCb cb) override { parent_.runOnAllThreads(cb); } void runOnAllThreads(Event::PostCb cb, Event::PostCb main_callback) override { parent_.runOnAllThreads(cb, main_callback); @@ -72,6 +73,7 @@ class MockInstance : public Instance { testing::NiceMock dispatcher_; std::vector data_; bool shutdown_{}; + bool registered_{true}; }; } // namespace ThreadLocal diff --git a/test/mocks/tracing/mocks.cc b/test/mocks/tracing/mocks.cc index 04e9df4ae7aa..db9be3902320 100644 --- a/test/mocks/tracing/mocks.cc +++ b/test/mocks/tracing/mocks.cc @@ -9,21 +9,21 @@ using testing::ReturnRef; namespace Envoy { namespace Tracing { -MockSpan::MockSpan() {} -MockSpan::~MockSpan() {} +MockSpan::MockSpan() = default; +MockSpan::~MockSpan() = default; MockConfig::MockConfig() { ON_CALL(*this, operationName()).WillByDefault(Return(operation_name_)); ON_CALL(*this, requestHeadersForTags()).WillByDefault(ReturnRef(headers_)); ON_CALL(*this, verbose()).WillByDefault(Return(verbose_)); } -MockConfig::~MockConfig() {} +MockConfig::~MockConfig() = default; -MockHttpTracer::MockHttpTracer() {} -MockHttpTracer::~MockHttpTracer() {} +MockHttpTracer::MockHttpTracer() = default; +MockHttpTracer::~MockHttpTracer() = default; -MockDriver::MockDriver() {} -MockDriver::~MockDriver() {} +MockDriver::MockDriver() = default; +MockDriver::~MockDriver() = default; } // namespace Tracing } // namespace Envoy diff --git a/test/mocks/tracing/mocks.h b/test/mocks/tracing/mocks.h index d62036fd8d07..22a694edfd9a 100644 --- a/test/mocks/tracing/mocks.h +++ b/test/mocks/tracing/mocks.h @@ -13,7 +13,7 @@ namespace Tracing { class MockConfig : public Config { public: MockConfig(); - ~MockConfig(); + ~MockConfig() override; MOCK_CONST_METHOD0(operationName, OperationName()); MOCK_CONST_METHOD0(requestHeadersForTags, const std::vector&()); @@ -27,7 +27,7 @@ class MockConfig : public Config { class MockSpan : public Span { public: MockSpan(); - ~MockSpan(); + ~MockSpan() override; MOCK_METHOD1(setOperation, void(absl::string_view operation)); MOCK_METHOD2(setTag, void(absl::string_view name, absl::string_view value)); @@ -48,7 +48,7 @@ class MockSpan : public Span { class MockHttpTracer : public HttpTracer { public: MockHttpTracer(); - ~MockHttpTracer(); + ~MockHttpTracer() override; SpanPtr startSpan(const Config& config, Http::HeaderMap& request_headers, const StreamInfo::StreamInfo& stream_info, @@ -64,7 +64,7 @@ class MockHttpTracer : public HttpTracer { class MockDriver : public Driver { public: MockDriver(); - ~MockDriver(); + ~MockDriver() override; SpanPtr startSpan(const Config& config, Http::HeaderMap& request_headers, const std::string& operation_name, SystemTime start_time, diff --git a/test/mocks/upstream/cluster_info.cc b/test/mocks/upstream/cluster_info.cc index d34c8fa20fe1..c139f9b2c8e0 100644 --- a/test/mocks/upstream/cluster_info.cc +++ b/test/mocks/upstream/cluster_info.cc @@ -25,13 +25,13 @@ MockLoadBalancerSubsetInfo::MockLoadBalancerSubsetInfo() { ON_CALL(*this, subsetSelectors()).WillByDefault(ReturnRef(subset_selectors_)); } -MockLoadBalancerSubsetInfo::~MockLoadBalancerSubsetInfo() {} +MockLoadBalancerSubsetInfo::~MockLoadBalancerSubsetInfo() = default; MockIdleTimeEnabledClusterInfo::MockIdleTimeEnabledClusterInfo() { ON_CALL(*this, idleTimeout()).WillByDefault(Return(std::chrono::milliseconds(1000))); } -MockIdleTimeEnabledClusterInfo::~MockIdleTimeEnabledClusterInfo() {} +MockIdleTimeEnabledClusterInfo::~MockIdleTimeEnabledClusterInfo() = default; MockClusterInfo::MockClusterInfo() : stats_(ClusterInfoImpl::generateStats(stats_store_)), @@ -82,7 +82,7 @@ MockClusterInfo::MockClusterInfo() ON_CALL(*this, clusterType()).WillByDefault(ReturnRef(cluster_type_)); } -MockClusterInfo::~MockClusterInfo() {} +MockClusterInfo::~MockClusterInfo() = default; } // namespace Upstream } // namespace Envoy diff --git a/test/mocks/upstream/cluster_info.h b/test/mocks/upstream/cluster_info.h index 46b318c3f36d..6aa750b9e55b 100644 --- a/test/mocks/upstream/cluster_info.h +++ b/test/mocks/upstream/cluster_info.h @@ -26,7 +26,7 @@ namespace Upstream { class MockLoadBalancerSubsetInfo : public LoadBalancerSubsetInfo { public: MockLoadBalancerSubsetInfo(); - ~MockLoadBalancerSubsetInfo(); + ~MockLoadBalancerSubsetInfo() override; // Upstream::LoadBalancerSubsetInfo MOCK_CONST_METHOD0(isEnabled, bool()); @@ -61,7 +61,7 @@ class MockClusterTypedMetadata : public Config::TypedMetadataImpl()); + MOCK_CONST_METHOD1(createNetworkFilterChain, void(Network::Connection&)); std::string name_{"fake_cluster"}; absl::optional eds_service_name_; @@ -135,7 +136,7 @@ class MockClusterInfo : public ClusterInfo { class MockIdleTimeEnabledClusterInfo : public MockClusterInfo { public: MockIdleTimeEnabledClusterInfo(); - ~MockIdleTimeEnabledClusterInfo(); + ~MockIdleTimeEnabledClusterInfo() override; }; } // namespace Upstream diff --git a/test/mocks/upstream/host.cc b/test/mocks/upstream/host.cc index 536428cba59a..10eb8d9bb151 100644 --- a/test/mocks/upstream/host.cc +++ b/test/mocks/upstream/host.cc @@ -11,11 +11,11 @@ namespace Envoy { namespace Upstream { namespace Outlier { -MockDetectorHostMonitor::MockDetectorHostMonitor() {} -MockDetectorHostMonitor::~MockDetectorHostMonitor() {} +MockDetectorHostMonitor::MockDetectorHostMonitor() = default; +MockDetectorHostMonitor::~MockDetectorHostMonitor() = default; -MockEventLogger::MockEventLogger() {} -MockEventLogger::~MockEventLogger() {} +MockEventLogger::MockEventLogger() = default; +MockEventLogger::~MockEventLogger() = default; MockDetector::MockDetector() { ON_CALL(*this, addChangedStateCb(_)).WillByDefault(Invoke([this](ChangeStateCb cb) -> void { @@ -23,12 +23,12 @@ MockDetector::MockDetector() { })); } -MockDetector::~MockDetector() {} +MockDetector::~MockDetector() = default; } // namespace Outlier -MockHealthCheckHostMonitor::MockHealthCheckHostMonitor() {} -MockHealthCheckHostMonitor::~MockHealthCheckHostMonitor() {} +MockHealthCheckHostMonitor::MockHealthCheckHostMonitor() = default; +MockHealthCheckHostMonitor::~MockHealthCheckHostMonitor() = default; MockHostDescription::MockHostDescription() : address_(Network::Utility::resolveUrl("tcp://10.0.0.1:443")) { @@ -40,7 +40,7 @@ MockHostDescription::MockHostDescription() ON_CALL(*this, healthChecker()).WillByDefault(ReturnRef(health_checker_)); } -MockHostDescription::~MockHostDescription() {} +MockHostDescription::~MockHostDescription() = default; MockHost::MockHost() { ON_CALL(*this, cluster()).WillByDefault(ReturnRef(cluster_)); @@ -49,7 +49,7 @@ MockHost::MockHost() { ON_CALL(*this, warmed()).WillByDefault(Return(true)); } -MockHost::~MockHost() {} +MockHost::~MockHost() = default; } // namespace Upstream } // namespace Envoy diff --git a/test/mocks/upstream/host.h b/test/mocks/upstream/host.h index f4c43a2fd06b..095c67c1ae88 100644 --- a/test/mocks/upstream/host.h +++ b/test/mocks/upstream/host.h @@ -22,7 +22,7 @@ namespace Outlier { class MockDetectorHostMonitor : public DetectorHostMonitor { public: MockDetectorHostMonitor(); - ~MockDetectorHostMonitor(); + ~MockDetectorHostMonitor() override; MOCK_METHOD0(numEjections, uint32_t()); MOCK_METHOD1(putHttpResponseCode, void(uint64_t code)); @@ -38,7 +38,7 @@ class MockDetectorHostMonitor : public DetectorHostMonitor { class MockEventLogger : public EventLogger { public: MockEventLogger(); - ~MockEventLogger(); + ~MockEventLogger() override; MOCK_METHOD4(logEject, void(const HostDescriptionConstSharedPtr& host, Detector& detector, @@ -49,7 +49,7 @@ class MockEventLogger : public EventLogger { class MockDetector : public Detector { public: MockDetector(); - ~MockDetector(); + ~MockDetector() override; void runCallbacks(HostSharedPtr host) { for (const ChangeStateCb& cb : callbacks_) { @@ -70,7 +70,7 @@ class MockDetector : public Detector { class MockHealthCheckHostMonitor : public HealthCheckHostMonitor { public: MockHealthCheckHostMonitor(); - ~MockHealthCheckHostMonitor(); + ~MockHealthCheckHostMonitor() override; MOCK_METHOD0(setUnhealthy, void()); }; @@ -78,7 +78,7 @@ class MockHealthCheckHostMonitor : public HealthCheckHostMonitor { class MockHostDescription : public HostDescription { public: MockHostDescription(); - ~MockHostDescription(); + ~MockHostDescription() override; MOCK_CONST_METHOD0(address, Network::Address::InstanceConstSharedPtr()); MOCK_CONST_METHOD0(healthCheckAddress, Network::Address::InstanceConstSharedPtr()); @@ -120,7 +120,7 @@ class MockHost : public Host { }; MockHost(); - ~MockHost(); + ~MockHost() override; CreateConnectionData createConnection(Event::Dispatcher& dispatcher, const Network::ConnectionSocket::OptionsSharedPtr& options, diff --git a/test/mocks/upstream/load_balancer_context.h b/test/mocks/upstream/load_balancer_context.h index 495da74935a4..6d9e7046545c 100644 --- a/test/mocks/upstream/load_balancer_context.h +++ b/test/mocks/upstream/load_balancer_context.h @@ -8,7 +8,7 @@ namespace Upstream { class MockLoadBalancerContext : public LoadBalancerContext { public: MockLoadBalancerContext(); - ~MockLoadBalancerContext(); + ~MockLoadBalancerContext() override; MOCK_METHOD0(computeHashKey, absl::optional()); MOCK_METHOD0(metadataMatchCriteria, Router::MetadataMatchCriteria*()); diff --git a/test/mocks/upstream/mocks.h b/test/mocks/upstream/mocks.h index e9b86baf2be6..f194bffceca0 100644 --- a/test/mocks/upstream/mocks.h +++ b/test/mocks/upstream/mocks.h @@ -38,7 +38,7 @@ class MockHostSet : public HostSet { public: MockHostSet(uint32_t priority = 0, uint32_t overprovisioning_factor = kDefaultOverProvisioningFactor); - ~MockHostSet(); + ~MockHostSet() override; void runCallbacks(const HostVector added, const HostVector removed) { member_update_cb_helper_.runCallbacks(priority(), added, removed); @@ -92,7 +92,7 @@ class MockHostSet : public HostSet { class MockPrioritySet : public PrioritySet { public: MockPrioritySet(); - ~MockPrioritySet(); + ~MockPrioritySet() override; HostSet& getHostSet(uint32_t priority); void runUpdateCallbacks(uint32_t priority, const HostVector& hosts_added, @@ -125,10 +125,10 @@ class MockRetryPriority : public RetryPriority { const DegradedLoad& degraded_priority_load) : priority_load_({healthy_priority_load, degraded_priority_load}) {} MockRetryPriority(const MockRetryPriority& other) : priority_load_(other.priority_load_) {} - ~MockRetryPriority(); + ~MockRetryPriority() override; const HealthyAndDegradedLoad& determinePriorityLoad(const PrioritySet&, - const HealthyAndDegradedLoad&) { + const HealthyAndDegradedLoad&) override { return priority_load_; } @@ -158,7 +158,7 @@ class MockRetryPriorityFactory : public RetryPriorityFactory { class MockCluster : public Cluster { public: MockCluster(); - ~MockCluster(); + ~MockCluster() override; // Upstream::Cluster MOCK_METHOD0(healthChecker, HealthChecker*()); @@ -182,7 +182,7 @@ class MockCluster : public Cluster { class MockClusterRealPrioritySet : public MockCluster { public: MockClusterRealPrioritySet(); - ~MockClusterRealPrioritySet(); + ~MockClusterRealPrioritySet() override; // Upstream::Cluster PrioritySetImpl& prioritySet() override { return priority_set_; } @@ -195,7 +195,7 @@ class MockClusterRealPrioritySet : public MockCluster { class MockClusterMockPrioritySet : public MockCluster { public: MockClusterMockPrioritySet(); - ~MockClusterMockPrioritySet(); + ~MockClusterMockPrioritySet() override; // Upstream::Cluster MockPrioritySet& prioritySet() override { return priority_set_; } @@ -207,7 +207,7 @@ class MockClusterMockPrioritySet : public MockCluster { class MockLoadBalancer : public LoadBalancer { public: MockLoadBalancer(); - ~MockLoadBalancer(); + ~MockLoadBalancer() override; // Upstream::LoadBalancer MOCK_METHOD1(chooseHost, HostConstSharedPtr(LoadBalancerContext* context)); @@ -218,7 +218,7 @@ class MockLoadBalancer : public LoadBalancer { class MockThreadAwareLoadBalancer : public ThreadAwareLoadBalancer { public: MockThreadAwareLoadBalancer(); - ~MockThreadAwareLoadBalancer(); + ~MockThreadAwareLoadBalancer() override; // Upstream::ThreadAwareLoadBalancer MOCK_METHOD0(factory, LoadBalancerFactorySharedPtr()); @@ -228,7 +228,7 @@ class MockThreadAwareLoadBalancer : public ThreadAwareLoadBalancer { class MockThreadLocalCluster : public ThreadLocalCluster { public: MockThreadLocalCluster(); - ~MockThreadLocalCluster(); + ~MockThreadLocalCluster() override; // Upstream::ThreadLocalCluster MOCK_METHOD0(prioritySet, const PrioritySet&()); @@ -242,7 +242,7 @@ class MockThreadLocalCluster : public ThreadLocalCluster { class MockClusterManagerFactory : public ClusterManagerFactory { public: MockClusterManagerFactory(); - ~MockClusterManagerFactory(); + ~MockClusterManagerFactory() override; Secret::MockSecretManager& secretManager() override { return secret_manager_; }; @@ -275,14 +275,14 @@ class MockClusterManagerFactory : public ClusterManagerFactory { class MockClusterUpdateCallbacksHandle : public ClusterUpdateCallbacksHandle { public: MockClusterUpdateCallbacksHandle(); - ~MockClusterUpdateCallbacksHandle(); + ~MockClusterUpdateCallbacksHandle() override; }; class MockClusterManager : public ClusterManager { public: explicit MockClusterManager(TimeSource& time_source); MockClusterManager(); - ~MockClusterManager(); + ~MockClusterManager() override; ClusterUpdateCallbacksHandlePtr addThreadLocalClusterUpdateCallbacks(ClusterUpdateCallbacks& callbacks) override { @@ -344,7 +344,7 @@ class MockClusterManager : public ClusterManager { class MockHealthChecker : public HealthChecker { public: MockHealthChecker(); - ~MockHealthChecker(); + ~MockHealthChecker() override; MOCK_METHOD1(addHostCheckCompleteCb, void(HostStatusCb callback)); MOCK_METHOD0(start, void()); @@ -377,7 +377,7 @@ class MockHealthCheckEventLogger : public HealthCheckEventLogger { class MockCdsApi : public CdsApi { public: MockCdsApi(); - ~MockCdsApi(); + ~MockCdsApi() override; MOCK_METHOD0(initialize, void()); MOCK_METHOD1(setInitializedCb, void(std::function callback)); @@ -389,7 +389,7 @@ class MockCdsApi : public CdsApi { class MockClusterUpdateCallbacks : public ClusterUpdateCallbacks { public: MockClusterUpdateCallbacks(); - ~MockClusterUpdateCallbacks(); + ~MockClusterUpdateCallbacks() override; MOCK_METHOD1(onClusterAddOrUpdate, void(ThreadLocalCluster& cluster)); MOCK_METHOD1(onClusterRemoval, void(const std::string& cluster_name)); @@ -398,7 +398,7 @@ class MockClusterUpdateCallbacks : public ClusterUpdateCallbacks { class MockClusterInfoFactory : public ClusterInfoFactory, Logger::Loggable { public: MockClusterInfoFactory(); - ~MockClusterInfoFactory(); + ~MockClusterInfoFactory() override; MOCK_METHOD1(createClusterInfo, ClusterInfoConstSharedPtr(const CreateClusterInfoParams&)); }; @@ -406,7 +406,7 @@ class MockClusterInfoFactory : public ClusterInfoFactory, Logger::Loggable "${COVERAGE_SUMMARY}" +echo "Merging coverage data..." +llvm-profdata merge -sparse -o ${COVERAGE_DATA} $(find -L bazel-out/k8-fastbuild/testlogs/test/coverage/coverage_tests/ -name coverage.dat) -# Clean up the generated test/coverage/BUILD file: subsequent bazel invocations -# can choke on it if it references things that changed since the last coverage -# run. -rm "${SRCDIR}"/test/coverage/BUILD +echo "Generating report..." +llvm-cov show "${COVERAGE_BINARY}" -instr-profile="${COVERAGE_DATA}" -Xdemangler=c++filt \ + -ignore-filename-regex="${COVERAGE_IGNORE_REGEX}" -output-dir=${COVERAGE_DIR} -format=html +sed -i -e 's|>proc/self/cwd/|>|g' "${COVERAGE_DIR}/index.html" +sed -i -e 's|>bazel-out/[^/]*/bin/\([^/]*\)/[^<]*/_virtual_includes/[^/]*|>\1|g' "${COVERAGE_DIR}/index.html" [[ -z "${ENVOY_COVERAGE_DIR}" ]] || rsync -av "${COVERAGE_DIR}"/ "${ENVOY_COVERAGE_DIR}" if [ "$VALIDATE_COVERAGE" == "true" ] then - COVERAGE_VALUE=$(grep -Po 'lines: \K(\d|\.)*' "${COVERAGE_SUMMARY}") - COVERAGE_THRESHOLD=97.5 + COVERAGE_VALUE=$(llvm-cov export "${COVERAGE_BINARY}" -instr-profile="${COVERAGE_DATA}" \ + -ignore-filename-regex="${COVERAGE_IGNORE_REGEX}" -summary-only | \ + python3 -c "import sys, json; print(json.load(sys.stdin)['data'][0]['totals']['lines']['percent'])") + COVERAGE_THRESHOLD=97.0 COVERAGE_FAILED=$(echo "${COVERAGE_VALUE}<${COVERAGE_THRESHOLD}" | bc) if test ${COVERAGE_FAILED} -eq 1; then echo Code coverage ${COVERAGE_VALUE} is lower than limit of ${COVERAGE_THRESHOLD} @@ -123,5 +62,5 @@ then else echo Code coverage ${COVERAGE_VALUE} is good and higher than limit of ${COVERAGE_THRESHOLD} fi - echo "HTML coverage report is in ${COVERAGE_DIR}/coverage.html" fi +echo "HTML coverage report is in ${COVERAGE_DIR}/index.html" diff --git a/test/server/BUILD b/test/server/BUILD index a6601e6ca5c4..e65a4896459e 100644 --- a/test/server/BUILD +++ b/test/server/BUILD @@ -122,6 +122,7 @@ envoy_cc_test( "//test/test_common:logging_lib", "//test/test_common:threadsafe_singleton_injector_lib", "//test/test_common:utility_lib", + "@envoy_api//envoy/config/bootstrap/v2:bootstrap_cc", ], ) @@ -254,13 +255,12 @@ envoy_cc_test( ":invalid_runtime_bootstrap.yaml", ":node_bootstrap.yaml", ":node_bootstrap_no_admin_port.yaml", + ":node_bootstrap_with_admin_socket_options.yaml", ":node_bootstrap_without_access_log.yaml", ":runtime_bootstrap.yaml", ":runtime_test_data", ":stats_sink_bootstrap.yaml", ":zipkin_tracing.yaml", - "//test/config/integration:server.json", - "//test/config/integration:server_config_files", ], deps = [ "//source/common/common:version_lib", diff --git a/test/server/configuration_impl_test.cc b/test/server/configuration_impl_test.cc index 732c47126c51..c2c4247b1f87 100644 --- a/test/server/configuration_impl_test.cc +++ b/test/server/configuration_impl_test.cc @@ -459,6 +459,50 @@ TEST(InitialImplTest, DeprecatedRuntimeTranslation) { EXPECT_THAT(config.runtime(), ProtoEq(expected_runtime)); } +TEST_F(ConfigurationImplTest, AdminSocketOptions) { + std::string json = R"EOF( + { + "admin": { + "access_log_path": "/dev/null", + "address": { + "socket_address": { + "address": "1.2.3.4", + "port_value": 5678 + } + }, + "socket_options": [ + { + "level": 1, + "name": 2, + "int_value": 3, + "state": "STATE_PREBIND" + }, + { + "level": 4, + "name": 5, + "int_value": 6, + "state": "STATE_BOUND" + }, + ] + } + } + )EOF"; + + auto bootstrap = Upstream::parseBootstrapFromV2Json(json); + InitialImpl config(bootstrap); + Network::MockListenSocket socket_mock; + + ASSERT_EQ(config.admin().socketOptions()->size(), 2); + auto detail = config.admin().socketOptions()->at(0)->getOptionDetails( + socket_mock, envoy::api::v2::core::SocketOption::STATE_PREBIND); + ASSERT_NE(detail, absl::nullopt); + EXPECT_EQ(detail->name_, Envoy::Network::SocketOptionName(1, 2, "1/2")); + detail = config.admin().socketOptions()->at(1)->getOptionDetails( + socket_mock, envoy::api::v2::core::SocketOption::STATE_BOUND); + ASSERT_NE(detail, absl::nullopt); + EXPECT_EQ(detail->name_, Envoy::Network::SocketOptionName(4, 5, "4/5")); +} + } // namespace } // namespace Configuration } // namespace Server diff --git a/test/server/filter_chain_benchmark_test.cc b/test/server/filter_chain_benchmark_test.cc index 5070cc1271ae..0517635414c7 100644 --- a/test/server/filter_chain_benchmark_test.cc +++ b/test/server/filter_chain_benchmark_test.cc @@ -85,7 +85,7 @@ class MockConnectionSocket : public Network::ConnectionSocket { return Network::Address::SocketType::Stream; } void setLocalAddress(const Network::Address::InstanceConstSharedPtr&) override {} - void restoreLocalAddress(const Network::Address::InstanceConstSharedPtr&) override { return; } + void restoreLocalAddress(const Network::Address::InstanceConstSharedPtr&) override {} void setRemoteAddress(const Network::Address::InstanceConstSharedPtr&) override {} bool localAddressRestored() const override { return true; } void setDetectedTransportProtocol(absl::string_view) override {} @@ -149,9 +149,10 @@ const char YamlSingleDstPortBottom[] = R"EOF( class FilterChainBenchmarkFixture : public benchmark::Fixture { public: - void SetUp(const ::benchmark::State& state) { + void SetUp(const ::benchmark::State& state) override { int64_t input_size = state.range(0); std::vector port_chains; + port_chains.reserve(input_size); for (int i = 0; i < input_size; i++) { port_chains.push_back(absl::StrCat(YamlSingleDstPortTop, 10000 + i, YamlSingleDstPortBottom)); } diff --git a/test/server/guarddog_impl_test.cc b/test/server/guarddog_impl_test.cc index 77b3397ffd59..e4f5d35f8e2c 100644 --- a/test/server/guarddog_impl_test.cc +++ b/test/server/guarddog_impl_test.cc @@ -30,12 +30,12 @@ namespace { class DebugTestInterlock : public GuardDogImpl::TestInterlockHook { public: // GuardDogImpl::TestInterlockHook - virtual void signalFromImpl(MonotonicTime time) { + void signalFromImpl(MonotonicTime time) override { impl_reached_ = time; impl_.notifyAll(); } - virtual void waitFromTest(Thread::MutexBasicLockable& mutex, MonotonicTime time) + void waitFromTest(Thread::MutexBasicLockable& mutex, MonotonicTime time) override EXCLUSIVE_LOCKS_REQUIRED(mutex) { while (impl_reached_ < time) { impl_.wait(mutex); diff --git a/test/server/http/admin_test.cc b/test/server/http/admin_test.cc index 274f4dfcd524..481a1bbfd533 100644 --- a/test/server/http/admin_test.cc +++ b/test/server/http/admin_test.cc @@ -66,7 +66,7 @@ class AdminStatsTest : public testing::TestWithParam main_thread_dispatcher_; NiceMock tls_; - Stats::HeapStatDataAllocator alloc_; + Stats::AllocatorImpl alloc_; Stats::MockSink sink_; std::unique_ptr store_; }; @@ -586,7 +586,7 @@ class AdminInstanceTest : public testing::TestWithParam factory_context; - Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString("{}"); - Extensions::TransportSockets::Tls::ClientContextConfigImpl cfg(*loader, factory_context); + envoy::api::v2::auth::UpstreamTlsContext config; + Extensions::TransportSockets::Tls::ClientContextConfigImpl cfg(config, factory_context); Stats::IsolatedStoreImpl store; Envoy::Ssl::ClientContextSharedPtr client_ctx( server_.sslContextManager().createSslClientContext(store, cfg)); @@ -1397,7 +1397,7 @@ class PrometheusStatsFormatterTest : public testing::Test { } Stats::FakeSymbolTableImpl symbol_table_; - Stats::HeapStatDataAllocator alloc_; + Stats::AllocatorImpl alloc_; std::vector counters_; std::vector gauges_; std::vector histograms_; diff --git a/test/server/http/config_tracker_impl_test.cc b/test/server/http/config_tracker_impl_test.cc index d085e2c962af..60d4633f08a7 100644 --- a/test/server/http/config_tracker_impl_test.cc +++ b/test/server/http/config_tracker_impl_test.cc @@ -21,7 +21,7 @@ class ConfigTrackerImplTest : public testing::Test { ProtobufTypes::MessagePtr test_msg() { return std::make_unique(); } - virtual ~ConfigTrackerImplTest() = default; + ~ConfigTrackerImplTest() override = default; ConfigTrackerImpl tracker; const std::map& cbs_map; diff --git a/test/server/listener_manager_impl_test.cc b/test/server/listener_manager_impl_test.cc index 46c733415434..18df21b388e1 100644 --- a/test/server/listener_manager_impl_test.cc +++ b/test/server/listener_manager_impl_test.cc @@ -2686,30 +2686,12 @@ class OriginalDstTestFilter : public Extensions::ListenerFilters::OriginalDst::O }; TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilter) { - // Static scope required for the io_handle to be in scope for the lambda below - // and for the final check at the end of this test. - static int fd; - fd = -1; - // temporary io_handle to test result of socket creation - Network::IoHandlePtr io_handle_tmp = std::make_unique(0); - EXPECT_CALL(*listener_factory_.socket_, ioHandle()).WillOnce(ReturnRef(*io_handle_tmp)); - class OriginalDstTestConfigFactory : public Configuration::NamedListenerFilterConfigFactory { public: // NamedListenerFilterConfigFactory Network::ListenerFilterFactoryCb createFilterFactoryFromProto(const Protobuf::Message&, - Configuration::ListenerFactoryContext& context) override { - auto option = std::make_unique(); - EXPECT_CALL(*option, setOption(_, envoy::api::v2::core::SocketOption::STATE_PREBIND)) - .WillOnce(Return(true)); - EXPECT_CALL(*option, setOption(_, envoy::api::v2::core::SocketOption::STATE_BOUND)) - .WillOnce(Invoke( - [](Network::Socket& socket, envoy::api::v2::core::SocketOption::SocketState) -> bool { - fd = socket.ioHandle().fd(); - return true; - })); - context.addListenSocketOption(std::move(option)); + Configuration::ListenerFactoryContext&) override { return [](Network::ListenerFilterManager& filter_manager) -> void { filter_manager.addAcceptFilter(std::make_unique()); }; @@ -2767,57 +2749,6 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilter) { EXPECT_TRUE(filterChainFactory.createListenerFilterChain(manager)); EXPECT_TRUE(socket.localAddressRestored()); EXPECT_EQ("127.0.0.2:2345", socket.localAddress()->asString()); - EXPECT_NE(fd, -1); - io_handle_tmp->close(); -} - -TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterOptionFail) { - class OriginalDstTestConfigFactory : public Configuration::NamedListenerFilterConfigFactory { - public: - // NamedListenerFilterConfigFactory - Network::ListenerFilterFactoryCb - createFilterFactoryFromProto(const Protobuf::Message&, - Configuration::ListenerFactoryContext& context) override { - auto option = std::make_unique(); - EXPECT_CALL(*option, setOption(_, envoy::api::v2::core::SocketOption::STATE_PREBIND)) - .WillOnce(Return(false)); - context.addListenSocketOption(std::move(option)); - return [](Network::ListenerFilterManager& filter_manager) -> void { - filter_manager.addAcceptFilter(std::make_unique()); - }; - } - - ProtobufTypes::MessagePtr createEmptyConfigProto() override { - return std::make_unique(); - } - - std::string name() override { return "testfail.listener.original_dst"; } - }; - - /** - * Static registration for the original dst filter. @see RegisterFactory. - */ - static Registry::RegisterFactory - registered_; - - const std::string yaml = TestEnvironment::substitute(R"EOF( - name: "socketOptionFailListener" - address: - socket_address: { address: 127.0.0.1, port_value: 1111 } - filter_chains: {} - listener_filters: - - name: "testfail.listener.original_dst" - config: {} - )EOF", - Network::Address::IpVersion::v4); - - EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, true)); - - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV2Yaml(yaml), "", true), - EnvoyException, - "MockListenerComponentFactory: Setting socket options failed"); - EXPECT_EQ(0U, manager_->listeners().size()); } class OriginalDstTestFilterIPv6 @@ -2829,30 +2760,12 @@ class OriginalDstTestFilterIPv6 }; TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterIPv6) { - // Static scope required for the io_handle to be in scope for the lambda below - // and for the final check at the end of this test. - static int fd; - fd = -1; - // temporary io_handle to test result of socket creation - Network::IoHandlePtr io_handle_tmp = std::make_unique(0); - EXPECT_CALL(*listener_factory_.socket_, ioHandle()).WillOnce(ReturnRef(*io_handle_tmp)); - class OriginalDstTestConfigFactory : public Configuration::NamedListenerFilterConfigFactory { public: // NamedListenerFilterConfigFactory Network::ListenerFilterFactoryCb createFilterFactoryFromProto(const Protobuf::Message&, - Configuration::ListenerFactoryContext& context) override { - auto option = std::make_unique(); - EXPECT_CALL(*option, setOption(_, envoy::api::v2::core::SocketOption::STATE_PREBIND)) - .WillOnce(Return(true)); - EXPECT_CALL(*option, setOption(_, envoy::api::v2::core::SocketOption::STATE_BOUND)) - .WillOnce(Invoke( - [](Network::Socket& socket, envoy::api::v2::core::SocketOption::SocketState) -> bool { - fd = socket.ioHandle().fd(); - return true; - })); - context.addListenSocketOption(std::move(option)); + Configuration::ListenerFactoryContext&) override { return [](Network::ListenerFilterManager& filter_manager) -> void { filter_manager.addAcceptFilter(std::make_unique()); }; @@ -2910,57 +2823,6 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterIPv6) { EXPECT_TRUE(filterChainFactory.createListenerFilterChain(manager)); EXPECT_TRUE(socket.localAddressRestored()); EXPECT_EQ("[1::2]:2345", socket.localAddress()->asString()); - EXPECT_NE(fd, -1); - io_handle_tmp->close(); -} - -TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterOptionFailIPv6) { - class OriginalDstTestConfigFactory : public Configuration::NamedListenerFilterConfigFactory { - public: - // NamedListenerFilterConfigFactory - Network::ListenerFilterFactoryCb - createFilterFactoryFromProto(const Protobuf::Message&, - Configuration::ListenerFactoryContext& context) override { - auto option = std::make_unique(); - EXPECT_CALL(*option, setOption(_, envoy::api::v2::core::SocketOption::STATE_PREBIND)) - .WillOnce(Return(false)); - context.addListenSocketOption(std::move(option)); - return [](Network::ListenerFilterManager& filter_manager) -> void { - filter_manager.addAcceptFilter(std::make_unique()); - }; - } - - ProtobufTypes::MessagePtr createEmptyConfigProto() override { - return std::make_unique(); - } - - std::string name() override { return "testfail.listener.original_dstipv6"; } - }; - - /** - * Static registration for the original dst filter. @see RegisterFactory. - */ - static Registry::RegisterFactory - registered_; - - const std::string yaml = TestEnvironment::substitute(R"EOF( - name: "socketOptionFailListener" - address: - socket_address: { address: ::0001, port_value: 1111 } - filter_chains: {} - listener_filters: - - name: "testfail.listener.original_dstipv6" - config: {} - )EOF", - Network::Address::IpVersion::v6); - - EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, true)); - - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV2Yaml(yaml), "", true), - EnvoyException, - "MockListenerComponentFactory: Setting socket options failed"); - EXPECT_EQ(0U, manager_->listeners().size()); } // Validate that when neither transparent nor freebind is not set in the diff --git a/test/server/node_bootstrap_with_admin_socket_options.yaml b/test/server/node_bootstrap_with_admin_socket_options.yaml new file mode 100644 index 000000000000..4c3dad6e1985 --- /dev/null +++ b/test/server/node_bootstrap_with_admin_socket_options.yaml @@ -0,0 +1,19 @@ +node: + id: bootstrap_id + cluster: bootstrap_cluster + locality: + zone: bootstrap_zone + sub_zone: bootstrap_sub_zone + build_version: should_be_ignored +admin: + access_log_path: /dev/null + address: + socket_address: + address: {{ ntop_ip_loopback_address }} + port_value: 0 + socket_options: + - description: SO_REUSEPORT + level: {{ sol_socket }} + name: {{ so_reuseport }} + int_value: 1 + state: STATE_PREBIND diff --git a/test/server/options_impl_test.cc b/test/server/options_impl_test.cc index e3dbe1dfd7af..86ab2b378be7 100644 --- a/test/server/options_impl_test.cc +++ b/test/server/options_impl_test.cc @@ -6,6 +6,7 @@ #include #include "envoy/common/exception.h" +#include "envoy/config/bootstrap/v2/bootstrap.pb.h" #include "common/common/utility.h" @@ -109,6 +110,9 @@ TEST_F(OptionsImplTest, SetAll) { options->setBaseId(109876); options->setConcurrency(42); options->setConfigPath("foo"); + envoy::config::bootstrap::v2::Bootstrap bootstrap_foo{}; + bootstrap_foo.mutable_node()->set_id("foo"); + options->setConfigProto(bootstrap_foo); options->setConfigYaml("bogus:"); options->setAdminAddressPath("path"); options->setLocalAddressIpVersion(Network::Address::IpVersion::v6); @@ -130,6 +134,9 @@ TEST_F(OptionsImplTest, SetAll) { EXPECT_EQ(109876, options->baseId()); EXPECT_EQ(42U, options->concurrency()); EXPECT_EQ("foo", options->configPath()); + envoy::config::bootstrap::v2::Bootstrap bootstrap_bar{}; + bootstrap_bar.mutable_node()->set_id("foo"); + EXPECT_TRUE(TestUtility::protoEqual(bootstrap_bar, options->configProto())); EXPECT_EQ("bogus:", options->configYaml()); EXPECT_EQ("path", options->adminAddressPath()); EXPECT_EQ(Network::Address::IpVersion::v6, options->localAddressIpVersion()); @@ -278,6 +285,8 @@ TEST_F(OptionsImplTest, SaneTestConstructor) { EXPECT_EQ(regular_options_impl->baseId(), test_options_impl.baseId()); EXPECT_EQ(regular_options_impl->configPath(), test_options_impl.configPath()); + EXPECT_TRUE(TestUtility::protoEqual(regular_options_impl->configProto(), + test_options_impl.configProto())); EXPECT_EQ(regular_options_impl->configYaml(), test_options_impl.configYaml()); EXPECT_EQ(regular_options_impl->adminAddressPath(), test_options_impl.adminAddressPath()); EXPECT_EQ(regular_options_impl->localAddressIpVersion(), diff --git a/test/server/server_test.cc b/test/server/server_test.cc index 8ddc2ff7fd4f..b5044f1b87c3 100644 --- a/test/server/server_test.cc +++ b/test/server/server_test.cc @@ -3,6 +3,8 @@ #include "common/common/assert.h" #include "common/common/version.h" #include "common/network/address_impl.h" +#include "common/network/listen_socket_impl.h" +#include "common/network/socket_option_impl.h" #include "common/thread_local/thread_local_impl.h" #include "server/process_context_impl.h" @@ -170,10 +172,7 @@ class ServerInstanceImplTest : public testing::TestWithParamjoin(); } +// A test target which never signals that it is ready. +class NeverReadyTarget : public Init::TargetImpl { +public: + NeverReadyTarget(absl::Notification& initialized) + : Init::TargetImpl("test", [this] { initialize(); }), initialized_(initialized) {} + +private: + void initialize() { initialized_.Notify(); } + + absl::Notification& initialized_; +}; + +TEST_P(ServerInstanceImplTest, NoLifecycleNotificationOnEarlyShutdown) { + absl::Notification initialized; + + auto server_thread = Thread::threadFactoryForTest().createThread([&] { + initialize("test/server/node_bootstrap.yaml"); + + // This shutdown notification should never be called because we will shutdown + // early before the init manager finishes initializing and therefore before + // the server starts worker threads. + auto shutdown_handle = server_->registerCallback(ServerLifecycleNotifier::Stage::ShutdownExit, + [&](Event::PostCb) { FAIL(); }); + NeverReadyTarget target(initialized); + server_->initManager().add(target); + server_->run(); + + shutdown_handle = nullptr; + server_ = nullptr; + thread_local_ = nullptr; + }); + + // Wait until the init manager starts initializing targets... + initialized.WaitForNotification(); + + // Now shutdown the main dispatcher and trigger server lifecycle notifications. + server_->dispatcher().post([&] { server_->shutdown(); }); + server_thread->join(); +} + TEST_P(ServerInstanceImplTest, V2ConfigOnly) { options_.service_cluster_name_ = "some_cluster_name"; options_.service_node_name_ = "some_node_name"; @@ -413,6 +452,25 @@ TEST_P(ServerInstanceImplTest, BootstrapNode) { EXPECT_EQ(VersionInfo::version(), server_->localInfo().node().build_version()); } +TEST_P(ServerInstanceImplTest, LoadsBootstrapFromConfigProtoOptions) { + options_.config_proto_.mutable_node()->set_id("foo"); + initialize("test/server/node_bootstrap.yaml"); + EXPECT_EQ("foo", server_->localInfo().node().id()); +} + +TEST_P(ServerInstanceImplTest, LoadsBootstrapFromConfigYamlAfterConfigPath) { + options_.config_yaml_ = "node:\n id: 'bar'"; + initialize("test/server/node_bootstrap.yaml"); + EXPECT_EQ("bar", server_->localInfo().node().id()); +} + +TEST_P(ServerInstanceImplTest, LoadsBootstrapFromConfigProtoOptionsLast) { + options_.config_yaml_ = "node:\n id: 'bar'"; + options_.config_proto_.mutable_node()->set_id("foo"); + initialize("test/server/node_bootstrap.yaml"); + EXPECT_EQ("foo", server_->localInfo().node().id()); +} + // Validate server localInfo() from bootstrap Node with CLI overrides. TEST_P(ServerInstanceImplTest, BootstrapNodeWithOptionsOverride) { options_.service_cluster_name_ = "some_cluster_name"; @@ -526,6 +584,39 @@ TEST_P(ServerInstanceImplTest, BootstrapNodeWithoutAccessLog) { "An admin access log path is required for a listening server."); } +namespace { +void bindAndListenTcpSocket(const Network::Address::InstanceConstSharedPtr& address, + const Network::Socket::OptionsSharedPtr& options) { + auto socket = std::make_unique(address, options, true); + // Some kernels erroneously allow `bind` without SO_REUSEPORT for addresses + // with some other socket already listening on it, see #7636. + if (::listen(socket->ioHandle().fd(), 1) != 0) { + // Mimic bind exception for the test simplicity. + throw Network::SocketBindException(fmt::format("cannot listen: {}", strerror(errno)), errno); + } +} +} // namespace + +// Test that `socket_options` field in an Admin proto is honored. +TEST_P(ServerInstanceImplTest, BootstrapNodeWithSocketOptions) { + // Start Envoy instance with admin port with SO_REUSEPORT option. + ASSERT_NO_THROW(initialize("test/server/node_bootstrap_with_admin_socket_options.yaml")); + const auto address = server_->admin().socket().localAddress(); + + // First attempt to bind and listen socket should fail due to the lack of SO_REUSEPORT socket + // options. + EXPECT_THAT_THROWS_MESSAGE(bindAndListenTcpSocket(address, nullptr), EnvoyException, + HasSubstr(strerror(EADDRINUSE))); + + // Second attempt should succeed as kernel allows multiple sockets to listen the same address iff + // both of them use SO_REUSEPORT socket option. + auto options = std::make_shared(); + options->emplace_back(std::make_shared( + envoy::api::v2::core::SocketOption::STATE_PREBIND, + ENVOY_MAKE_SOCKET_OPTION_NAME(SOL_SOCKET, SO_REUSEPORT), 1)); + EXPECT_NO_THROW(bindAndListenTcpSocket(address, options)); +} + // Empty bootstrap succeeds. TEST_P(ServerInstanceImplTest, EmptyBootstrap) { options_.service_cluster_name_ = "some_cluster_name"; @@ -599,7 +690,9 @@ TEST_P(ServerInstanceImplTest, NoOptionsPassed) { hooks_, restart_, stats_store_, fakelock_, component_factory_, std::make_unique>(), *thread_local_, Thread::threadFactoryForTest(), Filesystem::fileSystemForTest(), nullptr)), - EnvoyException, "At least one of --config-path and --config-yaml should be non-empty"); + EnvoyException, + "At least one of --config-path or --config-yaml or Options::configProto() should be " + "non-empty"); } // Validate that when std::exception is unexpectedly thrown, we exit safely. diff --git a/test/test_common/environment.cc b/test/test_common/environment.cc index ee770090818d..a83054bdcdb2 100644 --- a/test/test_common/environment.cc +++ b/test/test_common/environment.cc @@ -234,6 +234,14 @@ std::string TestEnvironment::substitute(const std::string& str, break; } + // Substitute socket options arguments. + const std::regex sol_socket_regex(R"(\{\{ sol_socket \}\})"); + out_json_string = + std::regex_replace(out_json_string, sol_socket_regex, std::to_string(SOL_SOCKET)); + const std::regex so_reuseport_regex(R"(\{\{ so_reuseport \}\})"); + out_json_string = + std::regex_replace(out_json_string, so_reuseport_regex, std::to_string(SO_REUSEPORT)); + return out_json_string; } diff --git a/test/test_common/logging.cc b/test/test_common/logging.cc index d53a175f3c52..636bb56c4bad 100644 --- a/test/test_common/logging.cc +++ b/test/test_common/logging.cc @@ -23,7 +23,7 @@ LogLevelSetter::~LogLevelSetter() { LogRecordingSink::LogRecordingSink(Logger::DelegatingLogSinkPtr log_sink) : Logger::SinkDelegate(log_sink) {} -LogRecordingSink::~LogRecordingSink() {} +LogRecordingSink::~LogRecordingSink() = default; void LogRecordingSink::log(absl::string_view msg) { previous_delegate()->log(msg); diff --git a/test/test_common/logging.h b/test/test_common/logging.h index c7e1fed70c9a..62fe9f6d7d53 100644 --- a/test/test_common/logging.h +++ b/test/test_common/logging.h @@ -49,7 +49,7 @@ class LogLevelSetter { class LogRecordingSink : public Logger::SinkDelegate { public: explicit LogRecordingSink(Logger::DelegatingLogSinkPtr log_sink); - virtual ~LogRecordingSink(); + ~LogRecordingSink() override; // Logger::SinkDelegate void log(absl::string_view msg) override; diff --git a/test/test_common/simulated_time_system.cc b/test/test_common/simulated_time_system.cc index 1e700f650832..c4801ae68bda 100644 --- a/test/test_common/simulated_time_system.cc +++ b/test/test_common/simulated_time_system.cc @@ -55,7 +55,7 @@ class SimulatedTimeSystemHelper::Alarm : public Timer { time_system_(time_system), index_(time_system.nextIndex()), armed_(false), pending_(false) { } - virtual ~Alarm(); + ~Alarm() override; // Timer void disableTimer() override; diff --git a/test/test_common/test_time_system.h b/test/test_common/test_time_system.h index bd3c184648ad..4d2ef8196642 100644 --- a/test/test_common/test_time_system.h +++ b/test/test_common/test_time_system.h @@ -15,7 +15,7 @@ class TestTimeSystem; // Adds sleep() and waitFor() interfaces to Event::TimeSystem. class TestTimeSystem : public Event::TimeSystem { public: - virtual ~TestTimeSystem() = default; + ~TestTimeSystem() override = default; /** * Advances time forward by the specified duration, running any timers diff --git a/test/tools/router_check/router.h b/test/tools/router_check/router.h index 026bc1343a9a..6c507f5bc8bd 100644 --- a/test/tools/router_check/router.h +++ b/test/tools/router_check/router.h @@ -29,7 +29,7 @@ namespace Envoy { * input file. */ struct ToolConfig { - ToolConfig() : random_value_(0){}; + ToolConfig() = default; /** * @param check_config tool config json object pointer. @@ -49,7 +49,7 @@ struct ToolConfig { std::unique_ptr headers_; Router::RouteConstSharedPtr route_; - int random_value_; + int random_value_{0}; private: ToolConfig(std::unique_ptr headers, int random_value); diff --git a/tools/check_format.py b/tools/check_format.py index d05194f627d2..8f5759c5aa96 100755 --- a/tools/check_format.py +++ b/tools/check_format.py @@ -16,7 +16,8 @@ EXCLUDED_PREFIXES = ("./generated/", "./thirdparty/", "./build", "./.git/", "./bazel-", "./.cache", "./source/extensions/extensions_build_config.bzl", - "./tools/testdata/check_format/", "./tools/pyformat/") + "./bazel/toolchains/configs/", "./tools/testdata/check_format/", + "./tools/pyformat/") SUFFIXES = ("BUILD", "WORKSPACE", ".bzl", ".cc", ".h", ".java", ".m", ".md", ".mm", ".proto", ".rst") DOCS_SUFFIX = (".md", ".rst") @@ -41,6 +42,22 @@ "./test/test_common/utility.cc", "./test/test_common/utility.h", "./test/integration/integration.h") +# Files matching these directories can use stats by string for now. These should +# be eliminated but for now we don't want to grow this work. The goal for this +# whitelist is to eliminate it by making code transformations similar to +# https://github.com/envoyproxy/envoy/pull/7573 and others. +# +# TODO(#4196): Eliminate this list completely and then merge #4980. +STAT_FROM_STRING_WHITELIST = ("./source/extensions/filters/http/ext_authz/ext_authz.cc", + "./source/extensions/filters/http/fault/fault_filter.cc", + "./source/extensions/filters/http/ip_tagging/ip_tagging_filter.cc", + "./source/extensions/filters/network/mongo_proxy/proxy.cc", + "./source/extensions/filters/network/zookeeper_proxy/filter.cc", + "./source/extensions/stat_sinks/common/statsd/statsd.cc", + "./source/extensions/transport_sockets/tls/context_impl.cc", + "./source/server/guarddog_impl.cc", + "./source/server/overload_manager_impl.cc") + # Files in these paths can use MessageLite::SerializeAsString SERIALIZE_AS_STRING_WHITELIST = ("./test/common/protobuf/utility_test.cc", "./test/common/grpc/codec_test.cc") @@ -315,6 +332,10 @@ def whitelistedForJsonStringToMessage(file_path): return file_path in JSON_STRING_TO_MESSAGE_WHITELIST +def whitelistedForStatFromString(file_path): + return file_path in STAT_FROM_STRING_WHITELIST + + def findSubstringAndReturnError(pattern, file_path, error_message): with open(file_path) as f: text = f.read() @@ -455,11 +476,24 @@ def hasCondVarWaitFor(line): return True +# Determines whether the filename is either in the specified subdirectory, or +# at the top level. We consider files in the top level for the benefit of +# the check_format testcases in tools/testdata/check_format. +def isInSubdir(filename, *subdirs): + # Skip this check for check_format's unit-tests. + if filename.count("/") <= 1: + return True + for subdir in subdirs: + if filename.startswith('./' + subdir + '/'): + return True + return False + + def checkSourceLine(line, file_path, reportError): # Check fixable errors. These may have been fixed already. if line.find(". ") != -1: reportError("over-enthusiastic spaces") - if ('source' in file_path or 'include' in file_path) and X_ENVOY_USED_DIRECTLY_REGEX.match(line): + if isInSubdir(file_path, 'source', 'include') and X_ENVOY_USED_DIRECTLY_REGEX.match(line): reportError( "Please do not use the raw literal x-envoy in source code. See Envoy::Http::PrefixValue.") if hasInvalidAngleBracketDirectory(line): @@ -545,6 +579,11 @@ def checkSourceLine(line, file_path, reportError): # behavior. reportError("Don't use Protobuf::util::JsonStringToMessage, use TestUtility::loadFromJson.") + if isInSubdir(file_path, 'source') and file_path.endswith('.cc') and \ + not whitelistedForStatFromString(file_path) and \ + ('.counter(' in line or '.gauge(' in line or '.histogram(' in line): + reportError("Don't lookup stats by name at runtime; use StatName saved during construction") + def checkBuildLine(line, file_path, reportError): if "@bazel_tools" in line and not (isSkylarkFile(file_path) or file_path.startswith("./bazel/")): diff --git a/tools/check_format_test_helper.py b/tools/check_format_test_helper.py index 646512239866..7309a4bcaff1 100755 --- a/tools/check_format_test_helper.py +++ b/tools/check_format_test_helper.py @@ -102,26 +102,26 @@ def emitStdoutAsError(stdout): logging.error("\n".join(stdout)) -def expectError(status, stdout, expected_substring): +def expectError(filename, status, stdout, expected_substring): if status == 0: - logging.error("Expected failure `%s`, but succeeded" % expected_substring) + logging.error("%s: Expected failure `%s`, but succeeded" % (filename, expected_substring)) return 1 for line in stdout: if expected_substring in line: return 0 - logging.error("Could not find '%s' in:\n" % expected_substring) + logging.error("%s: Could not find '%s' in:\n" % (filename, expected_substring)) emitStdoutAsError(stdout) return 1 def fixFileExpectingFailure(filename, expected_substring): command, infile, outfile, status, stdout = fixFileHelper(filename) - return expectError(status, stdout, expected_substring) + return expectError(filename, status, stdout, expected_substring) def checkFileExpectingError(filename, expected_substring): command, status, stdout = runCheckFormat("check", getInputFile(filename)) - return expectError(status, stdout, expected_substring) + return expectError(filename, status, stdout, expected_substring) def checkAndFixError(filename, expected_substring): @@ -208,6 +208,15 @@ def checkFileExpectingOK(filename): "version_history.rst", "Version history line malformed. Does not match VERSION_HISTORY_NEW_LINE_REGEX in " "check_format.py") + errors += checkUnfixableError( + "counter_from_string.cc", + "Don't lookup stats by name at runtime; use StatName saved during construction") + errors += checkUnfixableError( + "gauge_from_string.cc", + "Don't lookup stats by name at runtime; use StatName saved during construction") + errors += checkUnfixableError( + "histogram_from_string.cc", + "Don't lookup stats by name at runtime; use StatName saved during construction") errors += fixFileExpectingFailure( "api/missing_package.proto", diff --git a/tools/envoy_build_fixer.py b/tools/envoy_build_fixer.py index 4114ce552f3b..fa4f3c14e251 100755 --- a/tools/envoy_build_fixer.py +++ b/tools/envoy_build_fixer.py @@ -26,7 +26,7 @@ def FixBuild(path): if line != '\n': outlines.append('\n') first = False - if path.startswith('./bazel/external/'): + if path.startswith('./bazel/external/') or path.startswith('./bazel/toolchains/'): outlines.append(line) continue if line.startswith('package(') and not path.endswith('bazel/BUILD') and not path.endswith( diff --git a/tools/format_python_tools.sh b/tools/format_python_tools.sh index 91b34feb2122..6749ade47071 100755 --- a/tools/format_python_tools.sh +++ b/tools/format_python_tools.sh @@ -9,8 +9,8 @@ cd "$SCRIPTPATH" source_venv "$VENV_DIR" echo "Installing requirements..." -pip3 install --upgrade pip -pip3 install -r requirements.txt +pip3 -q install --upgrade pip +pip3 -q install -r requirements.txt echo "Running Python format check..." python3 format_python_tools.py $1 diff --git a/tools/spelling_dictionary.txt b/tools/spelling_dictionary.txt index f7e6dfa0bbe6..50abfff89e48 100644 --- a/tools/spelling_dictionary.txt +++ b/tools/spelling_dictionary.txt @@ -244,6 +244,7 @@ SIGSEGV SIGTERM SimpleAtoi SNI +SPD SPDY SPIFFE SPKI @@ -298,6 +299,7 @@ XDS decRefCount getaddrinfo sendto +ssize upcasts vip xDSes diff --git a/tools/testdata/check_format/counter_from_string.cc b/tools/testdata/check_format/counter_from_string.cc new file mode 100644 index 000000000000..8c89250fefe9 --- /dev/null +++ b/tools/testdata/check_format/counter_from_string.cc @@ -0,0 +1,7 @@ +namespace Envoy { + +void init(Stats::Scope& scope) { + scope.counter("hello"); +} + +} // namespace Envoy diff --git a/tools/testdata/check_format/gauge_from_string.cc b/tools/testdata/check_format/gauge_from_string.cc new file mode 100644 index 000000000000..06dbd01d2ea3 --- /dev/null +++ b/tools/testdata/check_format/gauge_from_string.cc @@ -0,0 +1,7 @@ +namespace Envoy { + +void init(Stats::Scope& scope) { + scope.gauge("hello"); +} + +} // namespace Envoy diff --git a/tools/testdata/check_format/histogram_from_string.cc b/tools/testdata/check_format/histogram_from_string.cc new file mode 100644 index 000000000000..3c16b433a1a9 --- /dev/null +++ b/tools/testdata/check_format/histogram_from_string.cc @@ -0,0 +1,7 @@ +namespace Envoy { + +void init(Stats::Scope& scope) { + scope.histogram("hello"); +} + +} // namespace Envoy From fb28731ef86905d36cfec6c6563b802813c5641e Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Tue, 30 Jul 2019 22:10:54 -0400 Subject: [PATCH 17/21] fix tidy format error Signed-off-by: Xin Zhuang --- source/common/config/config_provider_impl.h | 2 +- test/common/config/config_provider_impl_test.cc | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/source/common/config/config_provider_impl.h b/source/common/config/config_provider_impl.h index 561170388eed..5e50ef807211 100644 --- a/source/common/config/config_provider_impl.h +++ b/source/common/config/config_provider_impl.h @@ -219,7 +219,7 @@ class ConfigSubscriptionCommonBase void applyConfigUpdate( const std::function< ConfigProvider::ConfigConstSharedPtr(ConfigProvider::ConfigConstSharedPtr)>& update_fn, - Event::PostCb complete_cb = []() {}) { + const Event::PostCb& complete_cb = []() {}) { // It is safe to call shared_from_this here as this is in main thread, and destruction of a // ConfigSubscriptionCommonBase owner (i.e., a provider) happens in main thread as well. auto shared_this = shared_from_this(); diff --git a/test/common/config/config_provider_impl_test.cc b/test/common/config/config_provider_impl_test.cc index a989cc6e8dca..020d6f5260d8 100644 --- a/test/common/config/config_provider_impl_test.cc +++ b/test/common/config/config_provider_impl_test.cc @@ -21,7 +21,7 @@ class DummyConfigProviderManager; class DummyConfig : public Envoy::Config::ConfigProvider::Config { public: - DummyConfig() {} + DummyConfig() = default; explicit DummyConfig(const test::common::config::DummyConfig& config_proto) { protos_.push_back(config_proto); } @@ -354,8 +354,7 @@ TEST_F(ConfigProviderImplTest, DuplicateConfigProto) { config_source_proto, factory_context_, "dummy_prefix", ConfigProviderManager::NullOptionalArg()); auto* typed_provider = static_cast(provider.get()); - DummyConfigSubscription& subscription = - static_cast(typed_provider->subscription()); + auto& subscription = static_cast(typed_provider->subscription()); EXPECT_EQ(subscription.getConfig(), nullptr); // First time issuing a configUpdate(). A new ConfigProvider::Config should be created. Protobuf::RepeatedPtrField untyped_dummy_configs; From 1bd43be9aadf7c5d03a7d6338654fd380d28b81e Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Wed, 31 Jul 2019 11:49:31 -0400 Subject: [PATCH 18/21] fixes per htuch review feedbacks Signed-off-by: Xin Zhuang --- source/common/config/config_provider_impl.h | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/source/common/config/config_provider_impl.h b/source/common/config/config_provider_impl.h index 5e50ef807211..241ff74da7af 100644 --- a/source/common/config/config_provider_impl.h +++ b/source/common/config/config_provider_impl.h @@ -216,10 +216,10 @@ class ConfigSubscriptionCommonBase * returns a updated/new version Config. * @param complete_cb the callback to run when the update propagation is done. */ + using ConfigUpdateCb = + std::function; void applyConfigUpdate( - const std::function< - ConfigProvider::ConfigConstSharedPtr(ConfigProvider::ConfigConstSharedPtr)>& update_fn, - const Event::PostCb& complete_cb = []() {}) { + const ConfigUpdateFn& update_fn, const Event::PostCb& complete_cb = []() {}) { // It is safe to call shared_from_this here as this is in main thread, and destruction of a // ConfigSubscriptionCommonBase owner (i.e., a provider) happens in main thread as well. auto shared_this = shared_from_this(); @@ -228,8 +228,8 @@ class ConfigSubscriptionCommonBase tls_->getTyped().config_ = update_fn(this->getConfig()); }, /*During the update propagation, a subscription may get teared down in main thread due to - all owners/providers destructed in a xDS update (e.g. LDS demolishes RouteConfigProvider and - its subscription). Hold a reference to the shared subscription instance to make sure the + all owners/providers destructed in a xDS update (e.g. LDS demolishes a RouteConfigProvider + and its subscription). Hold a reference to the shared subscription instance to make sure the update can be safely pushed to workers in such an event.*/ [shared_this, complete_cb]() { complete_cb(); }); } @@ -321,7 +321,6 @@ class ConfigSubscriptionInstance : public ConfigSubscriptionCommonBase { class DeltaConfigSubscriptionInstance : public ConfigSubscriptionCommonBase { protected: using ConfigSubscriptionCommonBase::ConfigSubscriptionCommonBase; - ~DeltaConfigSubscriptionInstance() override = default; /** * Must be called by the derived class' constructor. @@ -344,8 +343,6 @@ class DeltaConfigSubscriptionInstance : public ConfigSubscriptionCommonBase { */ class MutableConfigProviderCommonBase : public ConfigProvider { public: - ~MutableConfigProviderCommonBase() override = default; - // Envoy::Config::ConfigProvider SystemTime lastUpdated() const override { return subscription_->lastUpdated(); } ApiType apiType() const override { return api_type_; } @@ -384,8 +381,6 @@ class MutableConfigProviderCommonBase : public ConfigProvider { */ class ConfigProviderManagerImplBase : public ConfigProviderManager, public Singleton::Instance { public: - ~ConfigProviderManagerImplBase() override = default; - /** * This is invoked by the /config_dump admin handler. * @return ProtobufTypes::MessagePtr the config dump proto corresponding to the associated From f074e9d97394480bfa8e78d3200dad1bf9976207 Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Wed, 31 Jul 2019 13:29:29 -0400 Subject: [PATCH 19/21] improve the comment per htuch's suggestion. Signed-off-by: Xin Zhuang --- source/common/config/config_provider_impl.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/source/common/config/config_provider_impl.h b/source/common/config/config_provider_impl.h index 241ff74da7af..2e44ec8026ae 100644 --- a/source/common/config/config_provider_impl.h +++ b/source/common/config/config_provider_impl.h @@ -219,7 +219,7 @@ class ConfigSubscriptionCommonBase using ConfigUpdateCb = std::function; void applyConfigUpdate( - const ConfigUpdateFn& update_fn, const Event::PostCb& complete_cb = []() {}) { + const ConfigUpdateCb& update_fn, const Event::PostCb& complete_cb = []() {}) { // It is safe to call shared_from_this here as this is in main thread, and destruction of a // ConfigSubscriptionCommonBase owner (i.e., a provider) happens in main thread as well. auto shared_this = shared_from_this(); @@ -227,10 +227,13 @@ class ConfigSubscriptionCommonBase [this, update_fn]() { tls_->getTyped().config_ = update_fn(this->getConfig()); }, - /*During the update propagation, a subscription may get teared down in main thread due to + /* During the update propagation, a subscription may get teared down in main thread due to all owners/providers destructed in a xDS update (e.g. LDS demolishes a RouteConfigProvider - and its subscription). Hold a reference to the shared subscription instance to make sure the - update can be safely pushed to workers in such an event.*/ + and its subscription). + If such a race condition happens, hold a reference to the "*this" subscription instance in + this cb will ensure the shared "*this" gets posted back to main thread, after all the + workers finish calling the update_fn, at which point it's safe to destruct "*this" + instance. */ [shared_this, complete_cb]() { complete_cb(); }); } From 7cbb6aed0f0d0d4157ba188a9f245f821c9eea42 Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Wed, 31 Jul 2019 13:57:29 -0400 Subject: [PATCH 20/21] fix comment nit Signed-off-by: Xin Zhuang --- source/common/config/config_provider_impl.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/common/config/config_provider_impl.h b/source/common/config/config_provider_impl.h index 2e44ec8026ae..cf3d1a12ec92 100644 --- a/source/common/config/config_provider_impl.h +++ b/source/common/config/config_provider_impl.h @@ -227,13 +227,13 @@ class ConfigSubscriptionCommonBase [this, update_fn]() { tls_->getTyped().config_ = update_fn(this->getConfig()); }, - /* During the update propagation, a subscription may get teared down in main thread due to - all owners/providers destructed in a xDS update (e.g. LDS demolishes a RouteConfigProvider - and its subscription). - If such a race condition happens, hold a reference to the "*this" subscription instance in - this cb will ensure the shared "*this" gets posted back to main thread, after all the - workers finish calling the update_fn, at which point it's safe to destruct "*this" - instance. */ + // During the update propagation, a subscription may get teared down in main thread due to + // all owners/providers destructed in a xDS update (e.g. LDS demolishes a + // RouteConfigProvider and its subscription). + // If such a race condition happens, holding a reference to the "*this" subscription + // instance in this cb will ensure the shared "*this" gets posted back to main thread, after + // all the workers finish calling the update_fn, at which point it's safe to destruct + // "*this" instance. [shared_this, complete_cb]() { complete_cb(); }); } From fb7867ba9f3d5ece0b4302b36ccef886f96fa233 Mon Sep 17 00:00:00 2001 From: Xin Zhuang Date: Wed, 31 Jul 2019 17:03:03 -0400 Subject: [PATCH 21/21] move updateConfigCb and add a description for it. Signed-off-by: Xin Zhuang --- source/common/config/config_provider_impl.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/source/common/config/config_provider_impl.h b/source/common/config/config_provider_impl.h index cf3d1a12ec92..a1a7b02d71b7 100644 --- a/source/common/config/config_provider_impl.h +++ b/source/common/config/config_provider_impl.h @@ -150,6 +150,12 @@ class ConfigSubscriptionCommonBase : protected Logger::Loggable, public std::enable_shared_from_this { public: + // Callback for updating a Config implementation held in each worker thread, the callback is + // called in applyConfigUpdate() with the current version Config, and is expected to return the + // new version Config. + using ConfigUpdateCb = + std::function; + struct LastConfigInfo { absl::optional last_config_hash_; std::string last_config_version_; @@ -216,8 +222,6 @@ class ConfigSubscriptionCommonBase * returns a updated/new version Config. * @param complete_cb the callback to run when the update propagation is done. */ - using ConfigUpdateCb = - std::function; void applyConfigUpdate( const ConfigUpdateCb& update_fn, const Event::PostCb& complete_cb = []() {}) { // It is safe to call shared_from_this here as this is in main thread, and destruction of a