diff --git a/.circleci/config.yml b/.circleci/config.yml index e7007f4d6ea2b..6566717c6a822 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,16 +1,16 @@ -references: - envoy-build-image: &envoy-build-image - envoyproxy/envoy-build:faea2a2ebc397b7a3a5e3c877ceaefc5cf4daf25 +version: 2.1 + +executors: + ubuntu-build: + description: "A regular build executor based on ubuntu image" + docker: + - image: envoyproxy/envoy-build:faea2a2ebc397b7a3a5e3c877ceaefc5cf4daf25 + resource_class: xlarge + working_directory: /source -version: 2 jobs: release: - docker: - - image: *envoy-build-image - resource_class: xlarge - working_directory: /source - environment: - BAZEL_REMOTE_CACHE: https://storage.googleapis.com/envoy-circleci-bazel-cache/ + executor: ubuntu-build steps: - run: rm -rf /home/circleci/project/.git # CircleCI git caching is likely broken - checkout @@ -19,12 +19,7 @@ jobs: - run: ci/docker_push.sh - run: ci/docker_tag.sh asan: - docker: - - image: *envoy-build-image - resource_class: xlarge - working_directory: /source - environment: - BAZEL_REMOTE_CACHE: https://storage.googleapis.com/envoy-circleci-bazel-cache/ + executor: ubuntu-build steps: - run: rm -rf /home/circleci/project/.git # CircleCI git caching is likely broken - run: echo $CIRCLE_SHA1 @@ -33,21 +28,13 @@ jobs: - checkout - run: ci/do_circle_ci.sh bazel.asan tsan: - docker: - - image: *envoy-build-image - resource_class: xlarge - working_directory: /source - environment: - BAZEL_REMOTE_CACHE: https://storage.googleapis.com/envoy-circleci-bazel-cache/ + 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 api: - docker: - - image: *envoy-build-image - resource_class: xlarge - working_directory: /source + executor: ubuntu-build steps: - run: rm -rf /home/circleci/project/.git # CircleCI git caching is likely broken - checkout @@ -57,10 +44,7 @@ jobs: - "fb:f3:fe:be:1c:b2:ec:b6:25:f9:7b:a6:87:54:02:8c" - run: ci/api_mirror.sh filter_example_mirror: - docker: - - image: *envoy-build-image - resource_class: xlarge - working_directory: /source + executor: ubuntu-build steps: - run: rm -rf /home/circleci/project/.git # CircleCI git caching is likely broken - checkout @@ -70,15 +54,13 @@ jobs: - run: ci/filter_example_mirror.sh ipv6_tests: machine: true - environment: - BAZEL_REMOTE_CACHE: https://storage.googleapis.com/envoy-circleci-bazel-cache/ steps: - run: rm -rf /home/circleci/project/.git # CircleCI git caching is likely broken - checkout - run: name: enable ipv6 command: | - cat <<'EOF' | sudo tee /etc/docker/daemon.json + cat \<<'EOF' | sudo tee /etc/docker/daemon.json { "ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64" @@ -94,10 +76,7 @@ jobs: - run: ./ci/do_circle_ci_ipv6_tests.sh coverage: - docker: - - image: *envoy-build-image - resource_class: xlarge - working_directory: /source + executor: ubuntu-build steps: - run: rm -rf /home/circleci/project/.git # CircleCI git caching is likely broken - checkout @@ -106,10 +85,8 @@ jobs: - store_artifacts: path: /build/envoy/generated/coverage format: - docker: - - image: *envoy-build-image + executor: ubuntu-build resource_class: small - working_directory: /source steps: - run: rm -rf /home/circleci/project/.git # CircleCI git caching is likely broken - checkout @@ -128,10 +105,7 @@ jobs: - setup_remote_docker - run: ci/build_container/docker_push.sh docs: - docker: - - image: *envoy-build-image - resource_class: xlarge - working_directory: /source + executor: ubuntu-build steps: - run: rm -rf /home/circleci/project/.git # CircleCI git caching is likely broken - checkout @@ -145,8 +119,6 @@ jobs: mac: macos: xcode: "9.3.0" - environment: - BAZEL_REMOTE_CACHE: https://storage.googleapis.com/envoy-circleci-bazel-cache/ steps: - run: sudo ntpdate -vu time.apple.com - run: rm -rf /home/circleci/project/.git # CircleCI git caching is likely broken diff --git a/.gitignore b/.gitignore index f45b41d7735ac..9584d615f8c71 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ BROWSE /ci/bazel-* /ci/prebuilt/thirdparty /ci/prebuilt/thirdparty_build +compile_commands.json cscope.* .deps /docs/landing_source/.bundle diff --git a/CODEOWNERS b/CODEOWNERS index 96fe6fa848b67..3aadceae544cb 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,4 +1,4 @@ -# TODO(zuercher): determine how we want to deal deal with auto-assignment +# TODO(zuercher): determine how we want to deal with auto-assignment # By default, @envoyproxy/maintainers own everything. #* @envoyproxy/maintainers diff --git a/DEPRECATED.md b/DEPRECATED.md index 770b0d954723a..447a428858709 100644 --- a/DEPRECATED.md +++ b/DEPRECATED.md @@ -6,7 +6,9 @@ As of release 1.3.0, Envoy will follow a The following features have been DEPRECATED and will be removed in the specified release cycle. A logged warning is expected for each deprecated item that is in deprecation window. -## Version 1.8.0 (pending) +## Version 1.9.0 (pending) + +## Version 1.8.0 (Oct 4, 2018) * Use of the v1 API (including `*.deprecated_v1` fields in the v2 API) is deprecated. See envoy-announce [email](https://groups.google.com/forum/#!topic/envoy-announce/oPnYMZw8H4U). @@ -29,10 +31,13 @@ A logged warning is expected for each deprecated item that is in deprecation win * Setting hosts via `hosts` field in `Cluster` is deprecated. Use `load_assignment` instead. * Use of `response_headers_to_*` and `request_headers_to_add` are deprecated at the `RouteAction` level. Please use the configuration options at the `Route` level. +* Use of `runtime` in `RouteMatch`, found in + [route.proto](https://github.com/envoyproxy/envoy/blob/master/api/envoy/api/v2/route/route.proto). + Set the `runtime_fraction` field instead. * Use of the string `user` field in `Authenticated` in [rbac.proto](https://github.com/envoyproxy/envoy/blob/master/api/envoy/config/rbac/v2alpha/rbac.proto) is deprecated in favor of the new `StringMatcher` based `principal_name` field. -## Version 1.7.0 +## Version 1.7.0 (Jun 21, 2018) * Admin mutations should be sent as POSTs rather than GETs. HTTP GETs will result in an error status code and will not have their intended effect. Prior to 1.7, GETs can be used for diff --git a/VERSION b/VERSION index 0ef074f2eca2b..b57588e592f8b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.8.0-dev +1.9.0-dev diff --git a/WORKSPACE b/WORKSPACE index ebdb050a79cf1..32547b75780bc 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,6 +1,6 @@ workspace(name = "envoy") -load("//bazel:repositories.bzl", "envoy_dependencies") +load("//bazel:repositories.bzl", "envoy_dependencies", "GO_VERSION") load("//bazel:cc_configure.bzl", "cc_configure") envoy_dependencies() @@ -11,4 +11,4 @@ api_dependencies() load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains") go_rules_dependencies() -go_register_toolchains() +go_register_toolchains(go_version = GO_VERSION) diff --git a/api/docs/BUILD b/api/docs/BUILD index d7ff02017f62d..922ba916ab84d 100644 --- a/api/docs/BUILD +++ b/api/docs/BUILD @@ -12,8 +12,10 @@ package_group( proto_library( name = "protos", deps = [ + "//envoy/admin/v2alpha:certs", "//envoy/admin/v2alpha:clusters", "//envoy/admin/v2alpha:config_dump", + "//envoy/admin/v2alpha:memory", "//envoy/api/v2:cds", "//envoy/api/v2:discovery", "//envoy/api/v2:eds", @@ -36,6 +38,7 @@ proto_library( "//envoy/config/filter/http/header_to_metadata/v2:header_to_metadata", "//envoy/config/filter/http/health_check/v2:health_check", "//envoy/config/filter/http/ip_tagging/v2:ip_tagging", + "//envoy/config/filter/http/jwt_authn/v2alpha:jwt_authn", "//envoy/config/filter/http/lua/v2:lua", "//envoy/config/filter/http/rate_limit/v2:rate_limit", "//envoy/config/filter/http/rbac/v2:rbac", diff --git a/api/envoy/admin/v2alpha/BUILD b/api/envoy/admin/v2alpha/BUILD index ffe447ed30693..a059ae422a3cb 100644 --- a/api/envoy/admin/v2alpha/BUILD +++ b/api/envoy/admin/v2alpha/BUILD @@ -37,3 +37,9 @@ api_proto_library_internal( srcs = ["memory.proto"], visibility = ["//visibility:public"], ) + +api_proto_library_internal( + name = "certs", + srcs = ["certs.proto"], + visibility = ["//visibility:public"], +) diff --git a/api/envoy/admin/v2alpha/certs.proto b/api/envoy/admin/v2alpha/certs.proto new file mode 100644 index 0000000000000..9816520953b91 --- /dev/null +++ b/api/envoy/admin/v2alpha/certs.proto @@ -0,0 +1,45 @@ +syntax = "proto3"; + +package envoy.admin.v2alpha; + +// [#protodoc-title: Certificates] + +// Proto representation of certificate details. Admin endpoint uses this wrapper for `/certs` to +// display certificate information. See :ref:`/certs ` for more +// information. +message Certificates { + // List of certificates known to an Envoy. + repeated Certificate certificates = 1; +} + +message Certificate { + + // Details of CA certificate. + repeated CertificateDetails ca_cert = 1; + + // Details of Certificate Chain + repeated CertificateDetails cert_chain = 2; +} + +message CertificateDetails { + // Path of the certificate. + string path = 1; + + // Certificate Serial Number. + string serial_number = 2; + + // List of Subject Alternate names. + repeated SubjectAlternateName subject_alt_names = 3; + + // Minimum of days until expiration of certificate and it's chain. + uint64 days_until_expiration = 4; +} + +message SubjectAlternateName { + + // Subject Alternate Name. + oneof name { + string dns = 1; + string uri = 2; + } +} diff --git a/api/envoy/api/v2/core/BUILD b/api/envoy/api/v2/core/BUILD index 71a8d33f59d35..45251aebb4ba5 100644 --- a/api/envoy/api/v2/core/BUILD +++ b/api/envoy/api/v2/core/BUILD @@ -37,11 +37,15 @@ api_proto_library_internal( visibility = [ ":friends", ], + deps = [ + "//envoy/type:percent", + ], ) api_go_proto_library( name = "base", proto = ":base", + deps = ["//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 40204e38d87c7..14c9a89a76a4b 100644 --- a/api/envoy/api/v2/core/base.proto +++ b/api/envoy/api/v2/core/base.proto @@ -9,6 +9,8 @@ import "google/protobuf/wrappers.proto"; import "validate/validate.proto"; import "gogoproto/gogo.proto"; +import "envoy/type/percent.proto"; + option (gogoproto.equal_all) = true; // [#protodoc-title: Common types] @@ -216,3 +218,13 @@ message SocketOption { SocketState state = 6 [(validate.rules).message.required = true, (validate.rules).enum.defined_only = true]; } + +// Runtime derived FractionalPercent with defaults for when the numerator or denominator is not +// specified via a runtime key. +message RuntimeFractionalPercent { + // Default value if the runtime value's for the numerator/denominator keys are not available. + envoy.type.FractionalPercent default_value = 1 [(validate.rules).message.required = true]; + + // Runtime key for a YAML representation of a FractionalPercent. + string runtime_key = 2; +} diff --git a/api/envoy/api/v2/route/route.proto b/api/envoy/api/v2/route/route.proto index 51fb5ce5f91c6..5127bc37fc4b2 100644 --- a/api/envoy/api/v2/route/route.proto +++ b/api/envoy/api/v2/route/route.proto @@ -25,7 +25,7 @@ option (gogoproto.equal_all) = true; // host header. This allows a single listener to service multiple top level domain path trees. Once // a virtual host is selected based on the domain, the routes are processed in order to see which // upstream cluster to route to or whether to perform a redirect. -// [#comment:next free field: 14] +// [#comment:next free field: 15] message VirtualHost { // The logical name of the virtual host. This is used when emitting certain // statistics but is not relevant for routing. @@ -109,6 +109,16 @@ message VirtualHost { // specific; see the :ref:`HTTP filter documentation ` // for if and how it is utilized. map per_filter_config = 12; + + // Decides whether the :ref:`x-envoy-attempt-count + // ` header should be included + // in the upstream request. Setting this option will cause it to override any existing header + // value, so in the case of two Envoys on the request path with this option enabled, the upstream + // will see the attempt count as perceived by the second Envoy. Defaults to false. + // This header is unaffected by the + // :ref:`suppress_envoy_headers + // ` flag. + bool include_request_attempt_count = 14; } // A route is both a specification of how to match a request as well as an indication of what to do @@ -291,16 +301,33 @@ message RouteMatch { // is true. google.protobuf.BoolValue case_sensitive = 4; - // Indicates that the route should additionally match on a runtime key. An - // integer between 0-100. Every time the route is considered for a match, a - // random number between 0-99 is selected. If the number is <= the value found - // in the key (checked first) or, if the key is not present, the default - // value, the route is a match (assuming everything also about the route - // matches). A runtime route configuration can be used to roll out route changes in a - // gradual manner without full code/config deploys. Refer to the - // :ref:`traffic shifting ` docs - // for additional documentation. - core.RuntimeUInt32 runtime = 5; + oneof runtime_specifier { + // Indicates that the route should additionally match on a runtime key. An integer between + // 0-100. Every time the route is considered for a match, a random number between 0-99 is + // selected. If the number is <= the value found in the key (checked first) or, if the key is + // not present, the default value, the route is a match (assuming everything also about the + // route matches). A runtime route configuration can be used to roll out route changes in a + // gradual manner without full code/config deploys. Refer to the :ref:`traffic shifting + // ` docs for additional + // documentation. + // + // .. attention:: + // + // **This field is deprecated**. Set the + // :ref:`runtime_fraction` field instead. + core.RuntimeUInt32 runtime = 5 [deprecated = true]; + + // Indicates that the route should additionally match on a runtime key. Every time the route + // is considered for a match, it must also fall under the percentage of matches indicated by + // this field. For some fraction N/D, a random number in the range [0,D) is selected. If the + // number is <= the value of the numberator N, or if the key is not present, the default + // value, the router continues to evaluate the remaining match criteria. A runtime_fraction + // route configuration can be used to roll out route changes in a gradual manner (with more + // granularity than the deprecated runtime field) without full code/config deploys. Refer to + // the :ref:`traffic shifting ` docs + // for additional documentation. + core.RuntimeFractionalPercent runtime_fraction = 9; + } // Specifies a set of headers that the route should match on. The router will // check the request’s headers against all the specified headers in the route @@ -488,7 +515,6 @@ message RouteAction { google.protobuf.Struct config = 2; } - // [#not-implemented-hide:] // Specifies an implementation of a RetryPriority which is used to determine the // distribution of load across priorities used for retries. RetryPriority retry_priority = 4; @@ -498,16 +524,17 @@ message RouteAction { google.protobuf.Struct config = 2; } - // [#not-implemented-hide:] // Specifies a collection of RetryHostPredicates that will be consulted when selecting a host // for retries. If any of the predicates reject the host, host selection will be reattempted. repeated RetryHostPredicate retry_host_predicate = 5; - // [#not-implemented-hide:] // The maximum number of times host selection will be reattempted before giving up, at which // point the host that was last selected will be routed to. If unspecified, this will default to // retrying once. int64 host_selection_retry_max_attempts = 6; + + // HTTP status codes that should trigger a retry in addition to those specified by retry_on. + repeated uint32 retriable_status_codes = 7; } // Specifies the idle timeout for the route. If not specified, there is no per-route idle timeout, diff --git a/api/envoy/config/accesslog/v2/file.proto b/api/envoy/config/accesslog/v2/file.proto index d1ca2d1e41514..cb348b88b4d87 100644 --- a/api/envoy/config/accesslog/v2/file.proto +++ b/api/envoy/config/accesslog/v2/file.proto @@ -4,6 +4,7 @@ package envoy.config.accesslog.v2; option go_package = "v2"; import "validate/validate.proto"; +import "google/protobuf/struct.proto"; // [#protodoc-title: File access log] @@ -17,5 +18,8 @@ message FileAccessLog { // Access log format. Envoy supports :ref:`custom access log formats // ` as well as a :ref:`default format // `. - string format = 2; + oneof access_log_format { + string format = 2; + google.protobuf.Struct json_format = 3; + } } diff --git a/api/envoy/config/filter/fault/v2/fault.proto b/api/envoy/config/filter/fault/v2/fault.proto index 8cfd17ed44444..56560f134ec91 100644 --- a/api/envoy/config/filter/fault/v2/fault.proto +++ b/api/envoy/config/filter/fault/v2/fault.proto @@ -24,13 +24,7 @@ message FaultDelay { // supported. FaultDelayType type = 1 [(validate.rules).enum.defined_only = true]; - // An integer between 0-100 indicating the percentage of operations/connection requests - // on which the delay will be injected. - // - // .. attention:: - // - // Use of integer `percent` value is deprecated. Use fractional `percentage` field instead. - uint32 percent = 2 [(validate.rules).uint32.lte = 100, deprecated = true]; + reserved 2; oneof fault_delay_secifier { option (validate.required) = true; diff --git a/api/envoy/config/filter/http/fault/v2/fault.proto b/api/envoy/config/filter/http/fault/v2/fault.proto index 36e1d01a6b869..d42a9fe9bb831 100644 --- a/api/envoy/config/filter/http/fault/v2/fault.proto +++ b/api/envoy/config/filter/http/fault/v2/fault.proto @@ -13,13 +13,7 @@ import "validate/validate.proto"; // Fault Injection :ref:`configuration overview `. message FaultAbort { - // An integer between 0-100 indicating the percentage of requests/operations/connections - // that will be aborted with the error code provided. - // - // .. attention:: - // - // Use of integer `percent` value is deprecated. Use fractional `percentage` field instead. - uint32 percent = 1 [(validate.rules).uint32.lte = 100, deprecated = true]; + reserved 1; oneof error_type { option (validate.required) = true; @@ -50,12 +44,12 @@ message HTTPFault { // Specifies a set of headers that the filter should match on. The fault // injection filter can be applied selectively to requests that match a set of // headers specified in the fault filter config. The chances of actual fault - // injection further depend on the value of the :ref:`percent - // ` field. The filter will - // check the request's headers against all the specified headers in the filter - // config. A match will happen if all the headers in the config are present in - // the request with the same values (or based on presence if the *value* field - // is not in the config). + // injection further depend on the value of the :ref:`percentage + // ` field. + // The filter will check the request's headers against all the specified + // headers in the filter config. A match will happen if all the headers in the + // config are present in the request with the same values (or based on + // presence if the *value* field is not in the config). repeated envoy.api.v2.route.HeaderMatcher headers = 4; // Faults are injected for the specified list of downstream hosts. If this diff --git a/api/envoy/config/filter/http/jwt_authn/v2alpha/config.proto b/api/envoy/config/filter/http/jwt_authn/v2alpha/config.proto index 85e134bcc82d3..153264e4f1242 100644 --- a/api/envoy/config/filter/http/jwt_authn/v2alpha/config.proto +++ b/api/envoy/config/filter/http/jwt_authn/v2alpha/config.proto @@ -11,10 +11,19 @@ import "google/protobuf/empty.proto"; import "google/protobuf/wrappers.proto"; import "validate/validate.proto"; -// This message specifies how a JSON Web Token (JWT) can be verified. JWT format is defined -// `here `_. Please see `OAuth2.0 -// `_ and `OIDC1.0 `_ for -// the authentication flow. +// Please see following for JWT authentication flow: +// +// * `JSON Web Token (JWT) `_ +// * `The OAuth 2.0 Authorization Framework `_ +// * `OpenID Connect `_ +// +// A JwtProvider message specifies how a JSON Web Token (JWT) can be verified. It specifies: +// +// * issuer: the principal that issues the JWT. It has to match the one from the token. +// * allowed audiences: the ones in the token have to be listed here. +// * how to fetch public key JWKS to verify the token signature. +// * how to extract JWT token in the request. +// * how to pass successfully verified token payload. // // Example: // @@ -32,15 +41,15 @@ import "validate/validate.proto"; // seconds: 300 // message JwtProvider { - // Identifies the principal that issued the JWT. See `here - // `_. Usually a URL or an email address. + // Specify the `principal `_ that issued + // the JWT, usually a URL or an email address. // // Example: https://securetoken.google.com // Example: 1234567-compute@developer.gserviceaccount.com // string issuer = 1 [(validate.rules).string.min_bytes = 1]; - // The list of JWT `audiences `_. that are + // The list of JWT `audiences `_ are // allowed to access. A JWT containing any of these audiences will be accepted. If not specified, // will not check audiences in the token. // @@ -54,8 +63,8 @@ message JwtProvider { // repeated string audiences = 2; - // `JSON Web Key Set `_ is needed. to validate - // signature of the JWT. This field specifies where to fetch JWKS. + // `JSON Web Key Set (JWKS) `_ is needed to + // validate signature of a JWT. This field specifies where to fetch JWKS. oneof jwks_source_specifier { option (validate.required) = true; @@ -90,7 +99,7 @@ message JwtProvider { // .. code-block:: yaml // // local_jwks: - // inline_string: "ACADADADADA" + // inline_string: ACADADADADA // envoy.api.v2.core.DataSource local_jwks = 4; } @@ -103,18 +112,16 @@ message JwtProvider { // // If no explicit location is specified, the following default locations are tried in order: // - // 1. The Authorization header using the Bearer schema. See `here - // `_. Example: + // 1. The Authorization header using the `Bearer schema + // `_. Example:: // - // Authorization: Bearer . + // Authorization: Bearer . // - // 2. `access_token` query parameter. See `this - // `_ + // 2. `access_token `_ query parameter. // - // Multiple JWTs can be verified for a request. Each JWT has to be extracted from the locations - // its issuer specified or from the default locations. - + // its provider specified or from the default locations. + // // Specify the HTTP headers to extract JWT token. For examples, following config: // // .. code-block:: yaml @@ -149,10 +156,6 @@ message JwtProvider { // base64_encoded(jwt_payload_in_JSON) // // If it is not specified, the payload will not be forwarded. - // Multiple JWTs in a request from different issuers will be supported. Multiple JWTs from the - // same issuer will not be supported. Each issuer can config this `forward_payload_header`. If - // multiple JWTs from different issuers want to forward their payloads, their - // `forward_payload_header` should be different. string forward_payload_header = 8; } @@ -201,37 +204,37 @@ message ProviderWithAudiences { // # Example 1: not required with an empty message // // # Example 2: require A -// provider_name: "provider-A" +// provider_name: provider-A // // # Example 3: require A or B // requires_any: // requirements: -// - provider_name: "provider-A" -// - provider_name: "provider-B" +// - provider_name: provider-A +// - provider_name: provider-B // // # Example 4: require A and B // requires_all: // requirements: -// - provider_name: "provider-A" -// - provider_name: "provider-B" +// - provider_name: provider-A +// - provider_name: provider-B // // # Example 5: require A and (B or C) // requires_all: // requirements: -// - provider_name: "provider-A" +// - provider_name: provider-A // - requires_any: // requirements: -// - provider_name: "provider-B" -// - provider_name: "provider-C" +// - provider_name: provider-B +// - provider_name: provider-C // // # Example 6: require A or (B and C) // requires_any: // requirements: -// - provider_name: "provider-A" +// - provider_name: provider-A // - requires_all: // requirements: -// - provider_name: "provider-B" -// - provider_name: "provider-C" +// - provider_name: provider-B +// - provider_name: provider-C // message JwtRequirement { oneof requires_type { @@ -277,7 +280,7 @@ message JwtRequirementAndList { // .. code-block:: yaml // // - match: -// prefix: "/healthz" +// prefix: /healthz // // In above example, "requires" field is empty for /healthz prefix match, // it means that requests matching the path prefix don't require JWT authentication. @@ -287,8 +290,8 @@ message JwtRequirementAndList { // .. code-block:: yaml // // - match: -// prefix: "/" -// requires: { provider_name: "provider-A" } +// prefix: / +// requires: { provider_name: provider-A } // // In above example, all requests matched the path prefix require jwt authentication // from "provider-A". @@ -301,7 +304,7 @@ message RequirementRule { // .. code-block:: yaml // // match: - // prefix: "/" + // prefix: / // envoy.api.v2.route.RouteMatch match = 1 [(validate.rules).message.required = true]; @@ -333,22 +336,22 @@ message RequirementRule { // rules: // # Not jwt verification is required for /health path // - match: -// prefix: "/health" +// prefix: /health // // # Jwt verification for provider1 is required for path prefixed with "prefix" // - match: -// prefix: "/prefix" +// prefix: /prefix // requires: -// provider_name: "provider1" +// provider_name: provider1 // // # Jwt verification for either provider1 or provider2 is required for all other requests. // - match: -// prefix: "/" +// prefix: / // requires: // requires_any: // requirements: -// - provider_name: "provider1" -// - provider_name: "provider2" +// - provider_name: provider1 +// - provider_name: provider2 // message JwtAuthentication { // Map of provider names to JwtProviders. @@ -380,22 +383,26 @@ message JwtAuthentication { // .. code-block:: yaml // // rules: - // - match: { prefix: "/healthz" } - // - match: { prefix: "/baz" } + // - match: + // prefix: /healthz + // - match: + // prefix: /baz // requires: - // provider_name: "provider1" - // - match: { prefix: "/foo" } + // provider_name: provider1 + // - match: + // prefix: /foo // requires: // requires_any: // requirements: - // - provider_name: "provider1" - // - provider_name: "provider2" - // - match: { prefix: "/bar" } + // - provider_name: provider1 + // - provider_name: provider2 + // - match: + // prefix: /bar // requires: // requires_all: // requirements: - // - provider_name: "provider1" - // - provider_name: "provider2" + // - provider_name: provider1 + // - provider_name: provider2 // repeated RequirementRule rules = 2; } diff --git a/api/envoy/config/metrics/v2/BUILD b/api/envoy/config/metrics/v2/BUILD index 9d061aeb918e6..9ae462617bcc5 100644 --- a/api/envoy/config/metrics/v2/BUILD +++ b/api/envoy/config/metrics/v2/BUILD @@ -29,6 +29,7 @@ api_proto_library_internal( ], deps = [ "//envoy/api/v2/core:address", + "//envoy/type/matcher:string", ], ) @@ -37,5 +38,6 @@ api_go_proto_library( proto = ":stats", deps = [ "//envoy/api/v2/core:address_go_proto", + "//envoy/type/matcher:string_go_proto", ], ) diff --git a/api/envoy/config/metrics/v2/stats.proto b/api/envoy/config/metrics/v2/stats.proto index f3471643c93bb..f623ed893c2aa 100644 --- a/api/envoy/config/metrics/v2/stats.proto +++ b/api/envoy/config/metrics/v2/stats.proto @@ -7,6 +7,7 @@ package envoy.config.metrics.v2; option go_package = "v2"; import "envoy/api/v2/core/address.proto"; +import "envoy/type/matcher/string.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/wrappers.proto"; @@ -56,6 +57,98 @@ message StatsConfig { // // If not provided, the value is assumed to be true. google.protobuf.BoolValue use_all_default_tags = 2; + + // Inclusion/exclusion matcher for stat name creation. If not provided, all stats are instantiated + // as normal. Preventing the instantiation of certain families of stats can improve memory + // performance for Envoys running especially large configs. + StatsMatcher stats_matcher = 3; +} + +// Configuration for disabling stat instantiation. +message StatsMatcher { + // The instantiation of stats is unrestricted by default. If the goal is to configure Envoy to + // instantiate all stats, there is no need to construct a StatsMatcher. + // + // However, StatsMatcher can be used to limit the creation of families of stats in order to + // conserve memory. Stats can either be disabled entirely, or they can be + // limited by either an exclusion or an inclusion list of :ref:`StringMatcher + // ` protos: + // + // * If `reject_all` is set to `true`, no stats will be instantiated. If `reject_all` is set to + // `false`, all stats will be instantiated. + // + // * If an exclusion list is supplied, any stat name matching *any* of the StringMatchers in the + // list will not instantiate. + // + // * If an inclusion list is supplied, no stats will instantiate, except those matching *any* of + // the StringMatchers in the list. + // + // + // A StringMatcher can be used to match against an exact string, a suffix / prefix, or a regex. + // **NB:** For performance reasons, it is highly recommended to use a prefix- or suffix-based + // matcher rather than a regex-based matcher. + // + // Example 1. Excluding all stats. + // + // .. code-block:: json + // + // { + // "statsMatcher": { + // "rejectAll": "true" + // } + // } + // + // Example 2. Excluding all cluster-specific stats, but not cluster-manager stats: + // + // .. code-block:: json + // + // { + // "statsMatcher": { + // "exclusionList": { + // "patterns": [ + // { + // "prefix": "cluster." + // } + // ] + // } + // } + // } + // + // Example 3. Including only manager-related stats: + // + // .. code-block:: json + // + // { + // "statsMatcher": { + // "inclusionList": { + // "patterns": [ + // { + // "prefix": "cluster_manager." + // }, + // { + // "prefix": "listener_manager." + // } + // ] + // } + // } + // } + // + + oneof stats_matcher { + option (validate.required) = true; + + // If `reject_all` is true, then all stats are disabled. If `reject_all` is false, then all + // stats are enabled. + bool reject_all = 1; + + // Exclusive match. All stats are enabled except for those matching one of the supplied + // StringMatcher protos. + envoy.type.matcher.ListStringMatcher exclusion_list = 2; + + // Inclusive match. No stats are enabled except for those matching one of the supplied + // StringMatcher protos. + envoy.type.matcher.ListStringMatcher inclusion_list = 3; + }; } // Designates a tag name and value pair. The value may be either a fixed value @@ -200,6 +293,10 @@ message DogStatsdSink { } reserved 2; + + // Optional custom metric name prefix. See :ref:`StatsdSink's prefix field + // ` for more details. + string prefix = 3; } // Stats configuration proto schema for built-in *envoy.stat_sinks.hystrix* sink. diff --git a/api/envoy/config/retry/other_priority/BUILD b/api/envoy/config/retry/other_priority/BUILD new file mode 100644 index 0000000000000..cb0cfcd025394 --- /dev/null +++ b/api/envoy/config/retry/other_priority/BUILD @@ -0,0 +1,11 @@ +licenses(["notice"]) # Apache 2 + +load("//bazel:api_build_system.bzl", "api_proto_library_internal") + +api_proto_library_internal( + name = "other_priority", + srcs = ["other_priority_config.proto"], + deps = [ + "//envoy/api/v2/core:base", + ], +) diff --git a/api/envoy/config/retry/other_priority/other_priority_config.proto b/api/envoy/config/retry/other_priority/other_priority_config.proto new file mode 100644 index 0000000000000..0113417619ddb --- /dev/null +++ b/api/envoy/config/retry/other_priority/other_priority_config.proto @@ -0,0 +1,37 @@ +syntax = "proto3"; + +package envoy.config.retry.other_priority; + +// A retry host selector that attempts to spread retries between priorities, even if certain +// priorities would not normally be attempted due to higher priorities being available. +// +// As priorities get excluded, load will be distributed amongst the remaining healthy priorities +// based on the relative health of the priorities, matching how load is distributed during regular +// host selection. For example, given priority healths of {100, 50, 50}, the original load will be +// {100, 0, 0} (since P0 has capacity to handle 100% of the traffic). If P0 is excluded, the load +// changes to {0, 50, 50}, because P1 is only able to handle 50% of the traffic, causing the +// remaining to spill over to P2. +// +// Each priority attempted will be excluded until there are no healthy priorities left, at which +// point the list of attempted priorities will be reset, essentially starting from the beginning. +// For example, given three priorities P0, P1, P2 with healthy % of 100, 0 and 50 respectively, the +// following sequence of priorities would be selected (assuming update_frequency = 1): +// Attempt 1: P0 (P0 is 100% healthy) +// Attempt 2: P2 (P0 already attempted, P2 only healthy priority) +// Attempt 3: P0 (no healthy priorities, reset) +// Attempt 4: P2 +// +// Using this PriorityFilter requires rebuilding the priority load, which runs in O(# of +// priorities), which might incur significant overhead for clusters with many priorities. +message OtherPriorityConfig { + // How often the priority load should be updated based on previously attempted priorities. Useful + // to allow each priorities to receive more than one request before being excluded or to reduce + // the number of times that the priority load has to be recomputed. + // + // For example, by setting this to 2, then the first two attempts (initial attempt and first + // retry) will use the unmodified priority load. The third and fourth attempt will use priority + // load which excludes the priorities routed to with the first two attempts, and the fifth and + // sixth attempt will use the priority load excluding the priorities used for the first four + // attempts. + int32 update_frequency = 1; +} diff --git a/api/envoy/type/matcher/string.proto b/api/envoy/type/matcher/string.proto index 4fdea1f5859d5..db6930f9041f8 100644 --- a/api/envoy/type/matcher/string.proto +++ b/api/envoy/type/matcher/string.proto @@ -47,3 +47,8 @@ message StringMatcher { string regex = 4 [(validate.rules).string.max_bytes = 1024]; } } + +// Specifies a list of ways to match a string. +message ListStringMatcher { + repeated StringMatcher patterns = 1 [(validate.rules).repeated .min_items = 1]; +} diff --git a/bazel/README.md b/bazel/README.md index 99b00ceee7633..e0314f9af1f19 100644 --- a/bazel/README.md +++ b/bazel/README.md @@ -28,15 +28,16 @@ for how to update or override dependencies. 1. Install the latest version of [Bazel](https://bazel.build/versions/master/docs/install.html) in your environment. 2. Install external dependencies libtool, cmake, ninja, realpath and curl libraries separately. -On Ubuntu, run the following commands: +On Ubuntu, run the following command: ``` - apt-get install libtool - apt-get install cmake - apt-get install realpath - apt-get install clang-format-7 - apt-get install automake - apt-get install ninja-build - apt-get install curl +sudo apt-get install \ + libtool \ + cmake \ + realpath \ + clang-format-7 \ + automake \ + ninja-build \ + curl ``` On Fedora (maybe also other red hat distros), run the following: @@ -412,3 +413,13 @@ bazel build --explain=file.txt --verbose_explanations //source/... Sometimes it's useful to see real system paths in bazel error message output (vs. symbolic links). `tools/path_fix.sh` is provided to help with this. See the comments in that file. + +# Compilation database + +Run `tools/gen_compilation_database.py` to generate +a [JSON Compilation Database](https://clang.llvm.org/docs/JSONCompilationDatabase.html). This could be used +with any tools (e.g. clang-tidy) compatible with the format. + +The compilation database could also be used to setup editors with cross reference, code completion. +For example, you can use [You Complete Me](https://valloric.github.io/YouCompleteMe/) or +[cquery](https://github.com/cquery-project/cquery) with supported editors. diff --git a/bazel/gen_compilation_database.sh b/bazel/gen_compilation_database.sh new file mode 100755 index 0000000000000..dde636d08dd76 --- /dev/null +++ b/bazel/gen_compilation_database.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +RELEASE_VERSION=0.2.3 + +if [[ ! -d bazel-compilation-database-${RELEASE_VERSION} ]]; then + curl -L https://github.com/grailbio/bazel-compilation-database/archive/${RELEASE_VERSION}.tar.gz | tar -xz +fi + +bazel-compilation-database-${RELEASE_VERSION}/generate.sh $@ diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl index b910ee18df170..a62bde82cc821 100644 --- a/bazel/repositories.bzl +++ b/bazel/repositories.bzl @@ -17,6 +17,9 @@ load("@bazel_tools//tools/cpp:lib_cc_configure.bzl", "get_env_var") # dict of {build recipe name: longform extension name,} PPC_SKIP_TARGETS = {"luajit": "envoy.filters.http.lua"} +# go version for rules_go +GO_VERSION = "1.10.4" + def _repository_impl(name, **kwargs): # `existing_rule_keys` contains the names of repositories that have already # been defined in the Bazel workspace. By skipping repos with existing keys, @@ -28,7 +31,8 @@ def _repository_impl(name, **kwargs): # wants to override the version. Do nothing. return - location = REPOSITORY_LOCATIONS[name] + loc_key = kwargs.pop("repository_key", name) + location = REPOSITORY_LOCATIONS[loc_key] # Git tags are mutable. We want to depend on commit IDs instead. Give the # user a useful error if they accidentally specify a tag. @@ -211,7 +215,21 @@ def _go_deps(skip_targets): # Keep the skip_targets check around until Istio Proxy has stopped using # it to exclude the Go rules. if "io_bazel_rules_go" not in skip_targets: + _repository_impl( + name = "com_github_golang_protobuf", + # These patches are to add BUILD files to golang/protobuf. + # TODO(sesmith177): Remove this dependency when both: + # 1. There's a release of golang/protobuf that includes + # https://github.com/golang/protobuf/commit/31e0d063dd98c052257e5b69eeb006818133f45c + # 2. That release is included in rules_go + patches = [ + "@io_bazel_rules_go//third_party:com_github_golang_protobuf-gazelle.patch", + "@io_bazel_rules_go//third_party:com_github_golang_protobuf-extras.patch", + ], + patch_args = ["-p1"], + ) _repository_impl("io_bazel_rules_go") + _repository_impl("bazel_gazelle") def _envoy_api_deps(): # Treat the data plane API as an external repo, this simplifies exporting the API to @@ -489,8 +507,10 @@ def _com_google_protobuf(): # Needed for cc_proto_library, Bazel doesn't support aliases today for repos, # see https://groups.google.com/forum/#!topic/bazel-discuss/859ybHQZnuI and # https://github.com/bazelbuild/bazel/issues/3219. - location = REPOSITORY_LOCATIONS["com_google_protobuf"] - git_repository(name = "com_google_protobuf_cc", **location) + _repository_impl( + "com_google_protobuf_cc", + repository_key = "com_google_protobuf", + ) native.bind( name = "protobuf", actual = "@com_google_protobuf//:protobuf", @@ -500,6 +520,13 @@ def _com_google_protobuf(): actual = "@com_google_protobuf_cc//:protoc", ) + # Needed for `bazel fetch` to work with @com_google_protobuf + # https://github.com/google/protobuf/blob/v3.6.1/util/python/BUILD#L6-L9 + native.bind( + name = "python_headers", + actual = "@com_google_protobuf//util/python:python_headers", + ) + def _com_github_grpc_grpc(): _repository_impl("com_github_grpc_grpc") diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index e4078aad79536..047f443a738eb 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -1,4 +1,9 @@ REPOSITORY_LOCATIONS = dict( + bazel_gazelle = dict( + sha256 = "1b959bd6b6ce88fc3fdfc28946adf1eafb1d5e4d470d2e08a51774d09078d031", + strip_prefix = "bazel-gazelle-0.14.0", + urls = ["https://github.com/bazelbuild/bazel-gazelle/archive/0.14.0.tar.gz"], + ), boringssl = dict( # Use commits from branch "chromium-stable-with-bazel" commit = "ab36a84b91b3116bacc85973995504818748d8a9", # chromium-69.0.3497.81 @@ -129,17 +134,25 @@ REPOSITORY_LOCATIONS = dict( # that includes: # - https://github.com/google/protobuf/commit/f35669b8d3f46f7f1236bd21f14d744bba251e60 # - https://github.com/google/protobuf/commit/6a4fec616ec4b20f54d5fb530808b855cb664390 - commit = "6a4fec616ec4b20f54d5fb530808b855cb664390", + # - https://github.com/google/protobuf/commit/fa252ec2a54acb24ddc87d48fed1ecfd458445fd + commit = "fa252ec2a54acb24ddc87d48fed1ecfd458445fd", remote = "https://github.com/google/protobuf", ), grpc_httpjson_transcoding = dict( commit = "05a15e4ecd0244a981fdf0348a76658def62fa9c", # 2018-05-30 remote = "https://github.com/grpc-ecosystem/grpc-httpjson-transcoding", ), + com_github_golang_protobuf = dict( + # TODO(sesmith177): Remove this dependency when both: + # 1. There's a release of golang/protobuf that includes + # https://github.com/golang/protobuf/commit/31e0d063dd98c052257e5b69eeb006818133f45c + # 2. That release is included in rules_go + commit = "31e0d063dd98c052257e5b69eeb006818133f45c", # 2018-10-03 + remote = "https://github.com/golang/protobuf", + ), io_bazel_rules_go = dict( - sha256 = "5a89e9c1fe89d45c4a45132fae94bf130842ce3c77e3a735a68f6991d4e00a25", - strip_prefix = "rules_go-0.11.2", - urls = ["https://github.com/bazelbuild/rules_go/archive/0.11.2.tar.gz"], + commit = "3d966375ff7971d43b863f785f495c7dcd6923da", # 2018-10-02 + remote = "https://github.com/bazelbuild/rules_go", ), six_archive = dict( sha256 = "105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a", diff --git a/ci/README.md b/ci/README.md index cc9e144f518c5..8d402f8dd2359 100644 --- a/ci/README.md +++ b/ci/README.md @@ -24,7 +24,6 @@ Currently there are three build images: * `envoyproxy/envoy-build` — alias to `envoyproxy/envoy-build-ubuntu`. * `envoyproxy/envoy-build-ubuntu` — based on Ubuntu 16.04 (Xenial) which uses the GCC 5.4 compiler. -* `envoyproxy/envoy-build-centos` — based on CentOS 7 which uses the GCC 5.3.1 compiler (devtoolset-4). We also install and use the clang-7 compiler for some sanitizing runs. @@ -36,17 +35,13 @@ An example basic invocation to build a developer version of the Envoy static bin ./ci/run_envoy_docker.sh './ci/do_ci.sh bazel.dev' ``` -The build image defaults to `envoyproxy/envoy-build-ubuntu`, but you can choose build image by setting `IMAGE_NAME` in the environment, -e.g. to use the `envoyproxy/envoy-build-centos` image you can run: - -```bash -IMAGE_NAME=envoyproxy/envoy-build-centos ./ci/run_envoy_docker.sh './ci/do_ci.sh bazel.dev' +The build image defaults to `envoyproxy/envoy-build-ubuntu`, but you can choose build image by setting `IMAGE_NAME` in the environment. ``` In case your setup is behind a proxy, set `http_proxy` and `https_proxy` to the proxy servers before invoking the build. ```bash -IMAGE_NAME=envoyproxy/envoy-build-centos http_proxy=http://proxy.foo.com:8080 https_proxy=http://proxy.bar.com:8080 ./ci/run_envoy_docker.sh './ci/do_ci.sh bazel.dev' +IMAGE_NAME=envoyproxy/envoy-build-ubuntu http_proxy=http://proxy.foo.com:8080 https_proxy=http://proxy.bar.com:8080 ./ci/run_envoy_docker.sh './ci/do_ci.sh bazel.dev' ``` The Envoy binary can be found in `/tmp/envoy-docker-build/envoy/source/exe/envoy-fastbuild` on the Docker host. You @@ -110,7 +105,6 @@ IMAGE_NAME="envoyproxy/envoy-build-${DISTRO}" IMAGE_ID=my_tag ./ci/run_envoy_doc ``` This build the Ubuntu based `envoyproxy/envoy-build-ubuntu` image, and the final call will run against your local copy of the build image. -To build the CentOS based `envoyproxy/envoy-build-ubuntu-centos` image, change `DISTRO` above to *centos*. # MacOS Build Flow diff --git a/ci/WORKSPACE b/ci/WORKSPACE index 33dad12a3f59a..b22222ef37bd3 100644 --- a/ci/WORKSPACE +++ b/ci/WORKSPACE @@ -1,6 +1,6 @@ workspace(name = "ci") -load("//bazel:repositories.bzl", "envoy_dependencies") +load("//bazel:repositories.bzl", "envoy_dependencies", "GO_VERSION") load("//bazel:cc_configure.bzl", "cc_configure") # We shouldn't need this, but it's a workaround for https://github.com/bazelbuild/bazel/issues/3580. @@ -20,4 +20,4 @@ api_dependencies() load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains") go_rules_dependencies() -go_register_toolchains() +go_register_toolchains(go_version = GO_VERSION) diff --git a/ci/WORKSPACE.filter.example b/ci/WORKSPACE.filter.example index 45a8e26ce727b..632e35eac78d7 100644 --- a/ci/WORKSPACE.filter.example +++ b/ci/WORKSPACE.filter.example @@ -5,7 +5,7 @@ local_repository( path = "/source", ) -load("//bazel:repositories.bzl", "envoy_dependencies") +load("//bazel:repositories.bzl", "envoy_dependencies", "GO_VERSION") load("//bazel:cc_configure.bzl", "cc_configure") envoy_dependencies( @@ -19,4 +19,4 @@ api_dependencies() load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains") go_rules_dependencies() -go_register_toolchains() +go_register_toolchains(go_version = GO_VERSION) diff --git a/ci/build_container/Dockerfile-centos b/ci/build_container/Dockerfile-centos deleted file mode 100644 index 10fd40f4018ff..0000000000000 --- a/ci/build_container/Dockerfile-centos +++ /dev/null @@ -1,11 +0,0 @@ -FROM centos:7 - -COPY ./build_and_install_deps.sh ./recipe_wrapper.sh ./Makefile ./build_container_common.sh / -COPY WORKSPACE /bazel-prebuilt/ -COPY ./api /bazel-prebuilt/api -COPY ./bazel /bazel-prebuilt/bazel -COPY ./build_recipes/*.sh /build_recipes/ - -COPY ./build_container_centos.sh / - -RUN ./build_container_centos.sh diff --git a/ci/build_container/build_container_centos.sh b/ci/build_container/build_container_centos.sh deleted file mode 100755 index d6347c4c5c3f4..0000000000000 --- a/ci/build_container/build_container_centos.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -e - -# scl devtoolset and epel repositories -yum install -y centos-release-scl epel-release - -# llvm-5.0.0 repository from copr -curl -L -o /etc/yum.repos.d/alonid-llvm-5.0.0-epel-7.repo \ - https://copr.fedorainfracloud.org/coprs/alonid/llvm-5.0.0/repo/epel-7/alonid-llvm-5.0.0-epel-7.repo - -# dependencies for bazel and build_recipes -yum install -y java-1.8.0-openjdk-devel unzip which openssl rpm-build \ - cmake3 devtoolset-4-gcc-c++ git golang libtool make ninja-build patch rsync wget \ - clang-5.0.0 devtoolset-4-libatomic-devel llvm-5.0.0 python-virtualenv bc -yum clean all - -ln -s /usr/bin/cmake3 /usr/bin/cmake -ln -s /usr/bin/ninja-build /usr/bin/ninja - -# latest bazel installer -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 ug+x "./${BAZEL_INSTALLER}" -"./${BAZEL_INSTALLER}" -rm "./${BAZEL_INSTALLER}" - -# symbolic links for clang -pushd /opt/llvm-5.0.0/bin -ln -s clang++ clang++-5.0 -ln -s clang-format clang-format-5.0 -popd - -mkdir -p /usr/lib/llvm-5.0/bin -pushd /usr/lib/llvm-5.0/bin -ln -s /opt/llvm-5.0.0/bin/llvm-symbolizer . -popd - -# setup bash env -echo '. scl_source enable devtoolset-4' > /etc/profile.d/devtoolset-4.sh -echo 'PATH=/opt/llvm-5.0.0/bin:$PATH' > /etc/profile.d/llvm-5.0.0.sh - -# enable devtoolset-4 for current shell -# disable errexit temporarily, otherwise bash will quit during sourcing -set +e -. scl_source enable devtoolset-4 -set -e - -EXPECTED_CXX_VERSION="g++ (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6)" ./build_container_common.sh diff --git a/ci/build_container/build_container_common.sh b/ci/build_container/build_container_common.sh index 0fe5b73257cd8..b48630c17be78 100755 --- a/ci/build_container/build_container_common.sh +++ b/ci/build_container/build_container_common.sh @@ -1,7 +1,7 @@ #!/bin/bash -e VERSION=0.15.0 -SHA256=0dea01a7a511797878f486e6ed8e549980c0710a0a116c8ee953d4e26de41515 +SHA256=769b9757644a8ec9c4b07369fda4a3e6592639a1338a7a03225ceeedbc760b45 # buildifier curl --location --output /usr/local/bin/buildifier https://github.com/bazelbuild/buildtools/releases/download/"$VERSION"/buildifier \ diff --git a/ci/build_container/build_container_ubuntu.sh b/ci/build_container/build_container_ubuntu.sh index 095879d8730f6..c60d82d5dd061 100755 --- a/ci/build_container/build_container_ubuntu.sh +++ b/ci/build_container/build_container_ubuntu.sh @@ -11,7 +11,7 @@ apt-get install -y wget software-properties-common make cmake git python python- 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-7 main" apt-get update -apt-get install -y clang-7 clang-format-7 lld-7 +apt-get install -y clang-7 clang-format-7 clang-tidy-7 lld-7 # Bazel and related dependencies. apt-get install -y openjdk-8-jdk curl echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | tee /etc/apt/sources.list.d/bazel.list diff --git a/ci/build_container/build_recipes/luajit.sh b/ci/build_container/build_recipes/luajit.sh index 7408968973a9f..e05d6c8880f59 100644 --- a/ci/build_container/build_recipes/luajit.sh +++ b/ci/build_container/build_recipes/luajit.sh @@ -10,6 +10,7 @@ curl https://github.com/LuaJIT/LuaJIT/archive/v"$VERSION".tar.gz -sLo LuaJIT-"$V tar xf LuaJIT-"$VERSION".tar.gz cd LuaJIT-"$VERSION" + # Fixup Makefile with things that cannot be set via env var. cat > ../luajit_make.diff << 'EOF' diff --git a/src/Makefile b/src/Makefile @@ -69,5 +70,9 @@ if [[ "${OS}" == "Windows_NT" ]]; then else patch -p1 < ../luajit_make.diff - DEFAULT_CC=${CC} TARGET_CFLAGS=${CFLAGS} TARGET_LDFLAGS=${CFLAGS} CFLAGS="" make V=1 PREFIX="$THIRDPARTY_BUILD" install + # Default MACOSX_DEPLOYMENT_TARGET is 10.4, which will fail the build at link time on macOS 10.14: + # ld: library not found for -lgcc_s.10.4 + # This doesn't affect other platforms + MACOSX_DEPLOYMENT_TARGET=10.6 DEFAULT_CC=${CC} TARGET_CFLAGS=${CFLAGS} TARGET_LDFLAGS=${CFLAGS} \ + CFLAGS="" make V=1 PREFIX="$THIRDPARTY_BUILD" install fi diff --git a/ci/build_container/docker_push.sh b/ci/build_container/docker_push.sh index c684b6a526c4e..df888642dc84e 100755 --- a/ci/build_container/docker_push.sh +++ b/ci/build_container/docker_push.sh @@ -27,7 +27,7 @@ then cd ci/build_container docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD" - for distro in ubuntu centos + for distro in ubuntu do echo "Updating envoyproxy/envoy-build-${distro} image" LINUX_DISTRO=$distro ./docker_build.sh diff --git a/ci/build_container/recipe_wrapper.sh b/ci/build_container/recipe_wrapper.sh index 101e26cd99ee8..575623a11f825 100755 --- a/ci/build_container/recipe_wrapper.sh +++ b/ci/build_container/recipe_wrapper.sh @@ -3,6 +3,12 @@ PS4='+ $(date "+%s.%N") ' set -x +if [[ `uname` == "Darwin" ]]; then + function sha256sum { + gsha256sum + } +fi + . $1 echo DONE diff --git a/ci/coverage_publish.sh b/ci/coverage_publish.sh index f273d6cd9eec0..45bc71bfa503f 100755 --- a/ci/coverage_publish.sh +++ b/ci/coverage_publish.sh @@ -8,11 +8,11 @@ if [ "${CIRCLECI}" != "true" ]; then exit 0 fi -# available for master builds and PRs from originating repository (not forks) -if [ -z "$CIRCLE_PULL_REQUEST" ] +# available for master builds +if [ -z "$CIRCLE_PR_NUMBER" ] then echo "Uploading coverage report..." - + [[ -z "${ENVOY_BUILD_DIR}" ]] && ENVOY_BUILD_DIR=/build COVERAGE_FILE="${ENVOY_BUILD_DIR}/envoy/generated/coverage/coverage.html" diff --git a/ci/mac_ci_steps.sh b/ci/mac_ci_steps.sh index 253f2acec0d35..c8e09228c1f32 100755 --- a/ci/mac_ci_steps.sh +++ b/ci/mac_ci_steps.sh @@ -2,11 +2,6 @@ set -e -# Add non-g prefixed coreutils installed sha256sum to the path -# allowing us to check the sha of dependencies downloaded in -# ci/build_container/build_recipes/*.sh -export PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH" - . "$(dirname "$0")"/setup_gcs_cache.sh BAZEL_BUILD_OPTIONS="--curses=no --show_task_finish --verbose_failures ${BAZEL_BUILD_EXTRA_OPTIONS}" diff --git a/docs/build.sh b/docs/build.sh index 5d8a50f878aa4..6bfa67f9a49dc 100755 --- a/docs/build.sh +++ b/docs/build.sh @@ -49,8 +49,10 @@ bazel build ${BAZEL_BUILD_OPTIONS} @envoy_api//docs:protos --aspects \ # These are the protos we want to put in docs, this list will grow. # TODO(htuch): Factor this out of this script. PROTO_RST=" + /envoy/admin/v2alpha/certs/envoy/admin/v2alpha/certs.proto.rst /envoy/admin/v2alpha/clusters/envoy/admin/v2alpha/clusters.proto.rst /envoy/admin/v2alpha/config_dump/envoy/admin/v2alpha/config_dump.proto.rst + /envoy/admin/v2alpha/memory/envoy/admin/v2alpha/memory.proto.rst /envoy/admin/v2alpha/clusters/envoy/admin/v2alpha/metrics.proto.rst /envoy/api/v2/core/address/envoy/api/v2/core/address.proto.rst /envoy/api/v2/core/base/envoy/api/v2/core/base.proto.rst @@ -87,6 +89,7 @@ PROTO_RST=" /envoy/config/filter/http/health_check/v2/health_check/envoy/config/filter/http/health_check/v2/health_check.proto.rst /envoy/config/filter/http/header_to_metadata/v2/header_to_metadata/envoy/config/filter/http/header_to_metadata/v2/header_to_metadata.proto.rst /envoy/config/filter/http/ip_tagging/v2/ip_tagging/envoy/config/filter/http/ip_tagging/v2/ip_tagging.proto.rst + /envoy/config/filter/http/jwt_authn/v2alpha/jwt_authn/envoy/config/filter/http/jwt_authn/v2alpha/config.proto.rst /envoy/config/filter/http/lua/v2/lua/envoy/config/filter/http/lua/v2/lua.proto.rst /envoy/config/filter/http/rate_limit/v2/rate_limit/envoy/config/filter/http/rate_limit/v2/rate_limit.proto.rst /envoy/config/filter/http/rbac/v2/rbac/envoy/config/filter/http/rbac/v2/rbac.proto.rst diff --git a/docs/root/api-v2/admin/admin.rst b/docs/root/api-v2/admin/admin.rst index db0081b902492..dac068b956b11 100644 --- a/docs/root/api-v2/admin/admin.rst +++ b/docs/root/api-v2/admin/admin.rst @@ -4,7 +4,9 @@ Admin .. toctree:: :glob: :maxdepth: 2 - + + ../admin/v2alpha/certs.proto ../admin/v2alpha/config_dump.proto ../admin/v2alpha/clusters.proto + ../admin/v2alpha/memory.proto ../admin/v2alpha/metrics.proto diff --git a/docs/root/configuration/access_log.rst b/docs/root/configuration/access_log.rst index 323b5f1b712d3..ee26fe37c2ffc 100644 --- a/docs/root/configuration/access_log.rst +++ b/docs/root/configuration/access_log.rst @@ -211,7 +211,7 @@ The following command operators are supported: where NAMESPACE is the the filter namespace used when setting the metadata, KEY is an optional lookup up key in the namespace with the option of specifying nested keys separated by ':', and Z is an optional parameter denoting string truncation up to Z characters long. Dynamic Metadata - can be set by filters using the :repo:`RequestInfo ` API: + can be set by filters using the :repo:`StreamInfo ` API: *setDynamicMetadata*. The data will be logged as a JSON string. For example, for the following dynamic metadata: ``com.test.my_filter: {"test_key": "foo", "test_object": {"inner_key": "bar"}}`` diff --git a/docs/root/configuration/http_conn_man/headers.rst b/docs/root/configuration/http_conn_man/headers.rst index b17dcd81d91f8..d0fe42fd2c26a 100644 --- a/docs/root/configuration/http_conn_man/headers.rst +++ b/docs/root/configuration/http_conn_man/headers.rst @@ -495,7 +495,7 @@ Supported variable names are: parameters **do not** need to be escaped by doubling them. %PER_REQUEST_STATE(reverse.dns.data.name)% - Populates the header with values set on the request info perRequestState() object. To be + Populates the header with values set on the stream info perRequestState() object. To be usable in custom request/response headers, these values must be of type Envoy::Router::StringAccessor. These values should be named in standard reverse DNS style, identifying the organization that created the value and ending in a unique name for the data. diff --git a/docs/root/configuration/http_filters/http_filters.rst b/docs/root/configuration/http_filters/http_filters.rst index 91af21e0e7bf9..49900f74ac538 100644 --- a/docs/root/configuration/http_filters/http_filters.rst +++ b/docs/root/configuration/http_filters/http_filters.rst @@ -18,6 +18,7 @@ HTTP filters health_check_filter header_to_metadata_filter ip_tagging_filter + jwt_authn_filter lua_filter rate_limit_filter rbac_filter diff --git a/docs/root/configuration/http_filters/jwt_authn_filter.rst b/docs/root/configuration/http_filters/jwt_authn_filter.rst new file mode 100644 index 0000000000000..1e22742e9f7b5 --- /dev/null +++ b/docs/root/configuration/http_filters/jwt_authn_filter.rst @@ -0,0 +1,187 @@ +.. _config_http_filters_jwt_authn: + +JWT Authentication +================== + +This HTTP filter can be used to verify JSON Web Token (JWT). It will verify its signature, audiences and issuer. It will also check its time restrictions, such as expiration and nbf (not before) time. If the JWT verification fails, its request will be rejected. If the JWT verification succeeds, its payload can be forwarded to the upstream for further authorization if desired. + +JWKS is needed to verify JWT signatures. They can be specified in the filter config or can be fetched remotely from a JWKS server. + +.. attention:: + Only ES256 and RS256 are supported for the JWT alg. + +Configuration +------------- + +This HTTP :ref:`filter config ` has two fields: + +* Field *providers* specifies how a JWT should be verified, such as where to extract the token, where to fetch the public key (JWKS) and where to output its payload. +* Field *rules* specifies matching rules and their requirements. If a request matches a rule, its requirement applies. The requirement specifies which JWT providers should be used. + +JwtProvider +~~~~~~~~~~~ + +:ref:`JwtProvider ` specifies how a JWT should be verified. It has the following fields: + +* *issuer*: the principal that issued the JWT, usually a URL or an email address. +* *audiences*: a list of JWT audiences allowed to access. A JWT containing any of these audiences will be accepted. + If not specified, the audiences in JWT will not be checked. +* *local_jwks*: fetch JWKS in local data source, either in a local file or embedded in the inline string. +* *remote_jwks*: fetch JWKS from a remote HTTP server, also specify cache duration. +* *forward*: if true, JWT will be forwarded to the upstream. +* *from_headers*: extract JWT from HTTP headers. +* *from_params*: extract JWT from query parameters. +* *forward_payload_header*: forward the JWT payload in the specified HTTP header. + +Default Extract Location +~~~~~~~~~~~~~~~~~~~~~~~~ + +If *from_headers* and *from_params* is empty, the default location to extract JWT is from HTTP header:: + + Authorization: Bearer + +If fails to extract a JWT from above header, then check query parameter key *access_token* as in this example:: + + /path?access_token= + +In the :ref:`filter config `, *providers* is a map, to map *provider_name* to a :ref:`JwtProvider `. The *provider_name* must be unique, it is referred in the `JwtRequirement ` in its *provider_name* field. + +.. important:: + For *remote_jwks*, a **jwks_cluster** cluster is required. + +Due to above requirement, `OpenID Connect Discovery `_ is not supported since the URL to fetch JWKS is in the response of the discovery. It is not easy to setup a cluster config for a dynamic URL. + +Remote JWKS config example +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: yaml + + providers: + provider_name1: + issuer: https://example.com + audiences: + - bookstore_android.apps.googleusercontent.com + - bookstore_web.apps.googleusercontent.com + remote_jwks: + http_uri: + uri: https://example.com/jwks.json + cluster: example_jwks_cluster + cache_duration: + seconds: 300 + +Above example fetches JWSK from a remote server with URL https://example.com/jwks.json. The token will be extracted from the default extract locations. The token will not be forwarded to upstream. JWT payload will not be added to the request header. + +Following cluster **example_jwks_cluster** is needed to fetch JWKS. + +.. code-block:: yaml + + cluster: + name: example_jwks_cluster + type: STRICT_DNS + hosts: + socket_address: + address: example.com + port_value: 80 + + +Inline JWKS config example +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Another config example using inline JWKS: + +.. code-block:: yaml + + providers: + provider_name2: + issuer: https://example2.com + local_jwks: + inline_string: PUBLIC-KEY + from_headers: + - name: jwt-assertion + forward: true + forward_payload_header: x-jwt-payload + +Above example uses config inline string to specify JWKS. The JWT token will be extracted from HTTP headers as:: + + jwt-assertion: . + +JWT payload will be added to the request header as following format:: + + x-jwt-payload: base64_encoded(jwt_payload_in_JSON) + +RequirementRule +~~~~~~~~~~~~~~~ + +:ref:`RequirementRule ` has two fields: + +* Field *match* specifies how a request can be matched; e.g. by HTTP headers, or by query parameters, or by path prefixes. +* Field *requires* specifies the JWT requirement, e.g. which provider is required. + +.. important:: + - **If a request matches multiple rules, the first matched rule will apply**. + - If the matched rule has empty *requires* field, **JWT verification is not required**. + - If a request doesn't match any rules, **JWT verification is not required**. + +Single requirement config example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: yaml + + providers: + jwt_provider1: + issuer: https://example.com + audiences: + audience1 + local_jwks: + inline_string: PUBLIC-KEY + rules: + - match: + prefix: /health + - match: + prefix: /api + requires: + provider_and_audiences: + provider_name: jwt_provider1 + audiences: + api_audience + - match: + prefix: / + requires: + provider_name: jwt_provider1 + +Above config uses single requirement rule, each rule may have either an empty requirement or a single requirement with one provider name. + +Group requirement config example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: yaml + + providers: + provider1: + issuer: https://provider1.com + local_jwks: + inline_string: PUBLIC-KEY + provider2: + issuer: https://provider2.com + local_jwks: + inline_string: PUBLIC-KEY + rules: + - match: + prefix: /any + requires: + requires_any: + requirements: + - provider_name: provider1 + - provider_name: provider2 + - match: + prefix: /all + requires: + requires_all: + requirements: + - provider_name: provider1 + - provider_name: provider2 + +Above config uses more complex *group* requirements: + +* The first *rule* specifies *requires_any*; if any of **provider1** or **provider2** requirement is satisfied, the request is OK to proceed. +* The second *rule* specifies *requires_all*; only if both **provider1** and **provider2** requirements are satisfied, the request is OK to proceed. diff --git a/docs/root/configuration/http_filters/lua_filter.rst b/docs/root/configuration/http_filters/lua_filter.rst index cb7e52dde6763..7cfe4e0d805c2 100644 --- a/docs/root/configuration/http_filters/lua_filter.rst +++ b/docs/root/configuration/http_filters/lua_filter.rst @@ -290,16 +290,16 @@ under the filter name i.e. *envoy.lua*. Below is an example of a *metadata* in a Returns a :ref:`metadata object `. -requestInfo() +streamInfo() ^^^^^^^^^^^^^ .. code-block:: lua - requestInfo = handle:requestInfo() + streamInfo = handle:streamInfo() -Returns :repo:`information ` related to the current request. +Returns :repo:`information ` related to the current request. -Returns a :ref:`request info object `. +Returns a :ref:`stream info object `. connection() ^^^^^^^^^^^^ @@ -426,9 +426,9 @@ __pairs() Iterates through every *metadata* entry. *key* is a string that supplies a *metadata* key. *value* is *metadata* entry value. -.. _config_http_filters_lua_request_info_wrapper: +.. _config_http_filters_lua_stream_info_wrapper: -Request info object API +Stream info object API ----------------------- protocol() @@ -436,7 +436,7 @@ protocol() .. code-block:: lua - requestInfo:protocol() + streamInfo:protocol() Returns the string representation of :repo:`HTTP protocol ` used by the current request. The possible values are: *HTTP/1.0*, *HTTP/1.1*, and *HTTP/2*. @@ -446,11 +446,11 @@ dynamicMetadata() .. code-block:: lua - requestInfo:dynamicMetadata() + streamInfo:dynamicMetadata() -Returns a :ref:`dynamic metadata object `. +Returns a :ref:`dynamic metadata object `. -.. _config_http_filters_lua_request_info_dynamic_metadata_wrapper: +.. _config_http_filters_lua_stream_info_dynamic_metadata_wrapper: Dynamic metadata object API --------------------------- diff --git a/docs/root/configuration/http_filters/router_filter.rst b/docs/root/configuration/http_filters/router_filter.rst index 2ae24ac7e73be..0a72ecdc1b836 100644 --- a/docs/root/configuration/http_filters/router_filter.rst +++ b/docs/root/configuration/http_filters/router_filter.rst @@ -95,6 +95,11 @@ refused-stream Envoy will attempt a retry if the upstream server resets the stream with a REFUSED_STREAM error code. This reset type indicates that a request is safe to retry. (Included in *5xx*) +retriable-status-codes + Envoy will attempt a retry if the upstream server responds with any response code matching one defined + in either :ref:`the retry policy ` + or in the :ref:`config_http_filters_router_x-envoy-retriable-status-codes` header. + The number of retries can be controlled via the :ref:`config_http_filters_router_x-envoy-max-retries` header or via the :ref:`route configuration `. @@ -122,6 +127,9 @@ cancelled deadline-exceeded Envoy will attempt a retry if the gRPC status code in the response headers is "deadline-exceeded" (4) +internal + Envoy will attempt to retry if the gRPC status code in the response headers is "internal" (13) + resource-exhausted Envoy will attempt a retry if the gRPC status code in the response headers is "resource-exhausted" (8) @@ -136,6 +144,20 @@ Note that retry policies can also be applied at the :ref:`route level By default, Envoy will *not* perform retries unless you've configured them per above. +.. _config_http_filters_router_x-envoy-retriable-status-codes: + +x-envoy-retriable-status-codes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Setting this header informs Envoy about what status codes should be considered retriable when used in +conjunction with the :ref:`retriable-status-code ` retry policy. +When the corresponding retry policy is set, the list of retriable status codes will be considered retriable +in addition to the status codes enabled for retry through other retry policies. + +The list is a comma delimited list of integers: "409" would cause 409 to be considered retriable, while "504,409" +would consider both 504 and 409 retriable. + +This header will only be honored for requests from internal clients. + .. _config_http_filters_router_x-envoy-upstream-alt-stat-name: x-envoy-upstream-alt-stat-name @@ -226,6 +248,16 @@ ingress/response path. They are documented in this section. .. contents:: :local: +.. _config_http_filters_router_x-envoy-attempt-count: + +x-envoy-attempt-count +^^^^^^^^^^^^^^^^^^^^^ + +Sent to the upstream to indicate which attempt the current request is in a series of retries. The value +will be "1" on the initial request, incrementing by one for each retry. Only set if the +:ref:`include_attempt_count_header ` +flag is set to true. + .. _config_http_filters_router_x-envoy-expected-rq-timeout-ms: x-envoy-expected-rq-timeout-ms diff --git a/docs/root/configuration/network_filters/mongo_proxy_filter.rst b/docs/root/configuration/network_filters/mongo_proxy_filter.rst index 0ee4aa111bae4..fd2dd241e36e1 100644 --- a/docs/root/configuration/network_filters/mongo_proxy_filter.rst +++ b/docs/root/configuration/network_filters/mongo_proxy_filter.rst @@ -150,7 +150,7 @@ mongo.mongo.drain_close_enabled mongo.fault.fixed_delay.percent Probability of an eligible MongoDB operation to be affected by the injected fault when there is no active fault. - Defaults to the *percent* specified in the config. + Defaults to the *percentage* specified in the config. mongo.fault.fixed_delay.duration_ms The delay duration in milliseconds. Defaults to the *duration_ms* specified in the config. diff --git a/docs/root/configuration/overload_manager/overload_manager.rst b/docs/root/configuration/overload_manager/overload_manager.rst index 08289db909ba4..ea2e0f42b71d0 100644 --- a/docs/root/configuration/overload_manager/overload_manager.rst +++ b/docs/root/configuration/overload_manager/overload_manager.rst @@ -50,6 +50,7 @@ The following overload actions are supported: envoy.overload_actions.stop_accepting_requests, Envoy will immediately respond with a 503 response code to new requests envoy.overload_actions.disable_http_keepalive, Envoy will disable keepalive on HTTP/1.x responses + envoy.overload_actions.stop_accepting_connections, Envoy will stop accepting new network connections on its configured listeners Statistics ---------- diff --git a/docs/root/configuration/overview/v2_overview.rst b/docs/root/configuration/overview/v2_overview.rst index 412c627427152..a276e9068fa38 100644 --- a/docs/root/configuration/overview/v2_overview.rst +++ b/docs/root/configuration/overview/v2_overview.rst @@ -6,7 +6,7 @@ Overview (v2 API) The Envoy v2 APIs are defined as `proto3 `_ `Protocol Buffers `_ in the `data plane API -repository `_. They evolve the +repository `_. They evolve the existing :ref:`v1 APIs and concepts ` to support: * Streaming delivery of `xDS `_ diff --git a/docs/root/faq/disable_circuit_breaking.rst b/docs/root/faq/disable_circuit_breaking.rst new file mode 100644 index 0000000000000..764de5158f712 --- /dev/null +++ b/docs/root/faq/disable_circuit_breaking.rst @@ -0,0 +1,20 @@ +Is there a way to disable circuit breaking? +=========================================== + +Envoy comes with :ref:`certain defaults ` +for each kind of circuit breaking. Currently, there isn't a switch to turn +circuit breaking off completely; however, you could achieve a similar behavior +by setting these thresholds very high, for example, to `std::numeric_limits::max()`. + +Following is a sample configuration that tries to effectively disable all kinds +of circuit breaking by setting the thresholds to a value of `1000000000`. + +.. code-block:: yaml + + circuit_breakers: + thresholds: + priority: HIGH + max_connections: 1000000000 + max_pending_requests: 1000000000 + max_requests: 1000000000 + max_retries: 1000000000 diff --git a/docs/root/faq/overview.rst b/docs/root/faq/overview.rst index d318fe94d61ac..a4eee6d1077cc 100644 --- a/docs/root/faq/overview.rst +++ b/docs/root/faq/overview.rst @@ -13,3 +13,4 @@ FAQ zipkin_tracing lb_panic_threshold concurrency_lb + disable_circuit_breaking diff --git a/docs/root/intro/arch_overview/http_connection_management.rst b/docs/root/intro/arch_overview/http_connection_management.rst index 67793f94258ff..684d448d2b0b2 100644 --- a/docs/root/intro/arch_overview/http_connection_management.rst +++ b/docs/root/intro/arch_overview/http_connection_management.rst @@ -43,6 +43,72 @@ table `. The route table can be specified in one of * Statically. * Dynamically via the :ref:`RDS API `. +Retry plugin configuration +-------------------------- + +Normally during retries, hosts selected for retry attempts will be selected the same way the +initial request is selected. To modify this behavior retry plugins can be used, which fall into +two categories: + +* :ref:`**Retry host predicate** `. + These can be used to "reject" a host, which will cause host selection to be reattempted. If one or + more predicates have been configured, host selection will continue until either the host predicates + accept the host or a configurable + :ref:`max attempts ` + has been reached. Any number of these predicates can be specified, and the host will be rejected if + any of the predicates reject the host. +* :ref:`**Retry priority** `. These can + be used to adjust the priority load used when selecting a priority for a retry attempt. Only one such + plugin may be specified. + +These plugins can be combined to affect both host selection and priority load. + +For example, to configure retries to prefer hosts that haven't been attempted already, the builtin +`envoy.retry_host_predicates.other_hosts` predicate can be used: + +.. code-block:: yaml + + retry_policy: + retry_host_predicate: + - name: envoy.retry_host_predicates.previous_hosts + host_selection_retry_max_attempts: 3 + +This will reject hosts previously attempted, retrying host selection a maximum of 3 times. The bound +on attempts is necessary in order to deal with scenarios in which finding an acceptable host is either +impossible (no hosts satisfy the predicate) or very unlikely (the only suitable host has a very low +relative weight). + +To configure retries to attempt other priorities during retries, the built in +`envoy.retry_priority.other_priorities` can be used. + +.. code-block:: yaml + + retry_policy: + retry_priority: + name: envoy.retry_priorities.previous_priorities + config: + update_frequency: 2 + +This will keep track of previously attempted priorities, and adjust the priority load such that other +priorites will be targeted in subsequent retry attempts. The `update_frequency` parameter decides how +often the priority load should be recalculated. + +These plugins can be combined, which will exclude both previously attempted hosts as well as +previously attempted priorities. + +.. code-block:: yaml + + retry_policy: + retry_host_predicate: + - name: envoy.retry_host_predicates.previous_hosts + host_selection_retry_max_attempts: 3 + retry_priority: + name: envoy.retry_priorities.previous_priorities + config: + update_frequency: 2 + +Envoy can be extended with custom retry plugins similar to how custom filters can be added. + Timeouts -------- diff --git a/docs/root/intro/arch_overview/http_routing.rst b/docs/root/intro/arch_overview/http_routing.rst index cc05d285a8227..dd7629772635b 100644 --- a/docs/root/intro/arch_overview/http_routing.rst +++ b/docs/root/intro/arch_overview/http_routing.rst @@ -77,6 +77,13 @@ headers `. The following configurat * **Retry conditions**: Envoy can retry on different types of conditions depending on application requirements. For example, network failure, all 5xx response codes, idempotent 4xx response codes, etc. + **Host selection retry plugins**: Envoy can be configured to apply additional logic to the host + selection logic when selecting hosts for retries. Specifying a + :ref:`retry host predicate ` + allows for reattempting host selection when certain hosts are selected (e.g. when an already + attempted host is selected), while a + :ref:`retry prioririty ` can be + configured to adjust the priority load used when selecting a priority for retries. Note that retries may be disabled depending on the contents of the :ref:`x-envoy-overloaded `. diff --git a/docs/root/intro/arch_overview/scripting.rst b/docs/root/intro/arch_overview/scripting.rst index bbc3751a53e2d..413250da5b52a 100644 --- a/docs/root/intro/arch_overview/scripting.rst +++ b/docs/root/intro/arch_overview/scripting.rst @@ -1,5 +1,5 @@ Scripting ========= -Envoy supports experimental `Lua `_ scripting as part of a dedicated +Envoy supports `Lua `_ scripting as part of a dedicated :ref:`HTTP filter `. diff --git a/docs/root/intro/version_history.rst b/docs/root/intro/version_history.rst index e39c46e53f43b..380cb3bb74a4b 100644 --- a/docs/root/intro/version_history.rst +++ b/docs/root/intro/version_history.rst @@ -1,8 +1,25 @@ Version history --------------- -1.8.0 (Pending) +1.9.0 (pending) =============== +* admin: added support for displaying subject alternate names in :ref:`certs` end point. +* fault: removed integer percentage support. +* http: no longer adding whitespace when appending X-Forwarded-For headers. **Warning**: this is not + compatible with 1.7.0 builds prior to `9d3a4eb4ac44be9f0651fcc7f87ad98c538b01ee `_. + See `#3611 `_ for details. +* router: added ability to configure arbitrary :ref:`retriable status codes. ` +* router: added ability to set attempt count in upstream requests, see :ref:`virtual host's include request + attempt count flag `. +* router: added internal :ref:`grpc-retry-on ` policy. +* router: when :ref:`max_grpc_timeout ` + is set, Envoy will now add or update the grpc-timeout header to reflect Envoy's expected timeout. +* stats: added :ref:`stats_matcher ` to the bootstrap config for granular control of stat instantiation. +* stream: renamed the `RequestInfo` namespace to `StreamInfo` to better match + its behaviour within TCP and HTTP implementations. + +1.8.0 (Oct 4, 2018) +=================== * access log: added :ref:`response flag filter ` to filter based on the presence of Envoy response flags. * access log: added RESPONSE_DURATION and RESPONSE_TX_DURATION. @@ -66,8 +83,8 @@ Version history :ref:`destination_port ` and :ref:`prefix_ranges `. * lua: added :ref:`connection() ` wrapper and *ssl()* API. -* lua: added :ref:`requestInfo() ` wrapper and *protocol()* API. -* lua: added :ref:`requestInfo():dynamicMetadata() ` API. +* lua: added :ref:`streamInfo() ` wrapper and *protocol()* API. +* lua: added :ref:`streamInfo():dynamicMetadata() ` API. * network: introduced :ref:`sni_cluster ` network filter that forwards connections to the upstream cluster specified by the SNI value presented by the client during a TLS handshake. * proxy_protocol: added support for HAProxy Proxy Protocol v2 (AF_INET/AF_INET6 only). @@ -85,11 +102,11 @@ Version history * rest-api: added ability to set the :ref:`request timeout ` for REST API requests. * route checker: Added v2 config support and removed support for v1 configs. * router: added ability to set request/response headers at the :ref:`envoy_api_msg_route.Route` level. +* stats: added :ref:`option to configure the DogStatsD metric name prefix` to DogStatsdSink. * tcp_proxy: added support for :ref:`weighted clusters `. * thrift_proxy: introduced thrift routing, moved configuration to correct location * thrift_proxy: introduced thrift configurable decoder filters -* tls: implemented `SecretDiscoveryService `_. +* tls: implemented :ref:`Secret Discovery Service `. * tracing: added support for configuration of :ref:`tracing sampling `. * upstream: added configuration option to the subset load balancer to take locality weights into account when @@ -98,8 +115,8 @@ Version history for overriding destination address when using the :ref:`Original Destination ` load balancing policy. -1.7.0 -=============== +1.7.0 (Jun 21, 2018) +==================== * access log: added ability to log response trailers. * access log: added ability to format START_TIME. * access log: added DYNAMIC_METADATA :ref:`access log formatter `. diff --git a/docs/root/operations/admin.rst b/docs/root/operations/admin.rst index f0df50307c1d6..4096f5b27382c 100644 --- a/docs/root/operations/admin.rst +++ b/docs/root/operations/admin.rst @@ -43,10 +43,12 @@ modify different aspects of the server: Print a textual table of all available options. +.. _operations_admin_interface_certs: + .. http:get:: /certs - List out all loaded TLS certificates, including file name, serial number, and days until - expiration. + List out all loaded TLS certificates, including file name, serial number, subject alternate names and days until + expiration in JSON format conforming to the :ref:`certificate proto definition `. .. _operations_admin_interface_clusters: diff --git a/include/envoy/access_log/BUILD b/include/envoy/access_log/BUILD index 297f856f71484..d05c37b156130 100644 --- a/include/envoy/access_log/BUILD +++ b/include/envoy/access_log/BUILD @@ -14,6 +14,6 @@ envoy_cc_library( deps = [ "//include/envoy/filesystem:filesystem_interface", "//include/envoy/http:header_map_interface", - "//include/envoy/request_info:request_info_interface", + "//include/envoy/stream_info:stream_info_interface", ], ) diff --git a/include/envoy/access_log/access_log.h b/include/envoy/access_log/access_log.h index fc20f50a0bbfa..2d328a22f4c8d 100644 --- a/include/envoy/access_log/access_log.h +++ b/include/envoy/access_log/access_log.h @@ -6,7 +6,7 @@ #include "envoy/common/pure.h" #include "envoy/filesystem/filesystem.h" #include "envoy/http/header_map.h" -#include "envoy/request_info/request_info.h" +#include "envoy/stream_info/stream_info.h" namespace Envoy { namespace AccessLog { @@ -41,7 +41,7 @@ class Filter { * Evaluate whether an access log should be written based on request and response data. * @return TRUE if the log should be written. */ - virtual bool evaluate(const RequestInfo::RequestInfo& info, + virtual bool evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers) PURE; }; @@ -59,12 +59,12 @@ class Instance { * @param request_headers supplies the incoming request headers after filtering. * @param response_headers supplies response headers. * @param response_trailers supplies response trailers. - * @param request_info supplies additional information about the request not contained in - * the request headers. + * @param stream_info supplies additional information about the request not + * contained in the request headers. */ virtual void log(const Http::HeaderMap* request_headers, const Http::HeaderMap* response_headers, const Http::HeaderMap* response_trailers, - const RequestInfo::RequestInfo& request_info) PURE; + const StreamInfo::StreamInfo& stream_info) PURE; }; typedef std::shared_ptr InstanceSharedPtr; @@ -79,10 +79,25 @@ class Formatter { virtual std::string format(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, const Http::HeaderMap& response_trailers, - const RequestInfo::RequestInfo& request_info) const PURE; + const StreamInfo::StreamInfo& stream_info) const PURE; }; typedef std::unique_ptr FormatterPtr; +/** + * Interface for access log provider + */ +class FormatterProvider { +public: + virtual ~FormatterProvider() {} + + virtual std::string format(const Http::HeaderMap& request_headers, + const Http::HeaderMap& response_headers, + const Http::HeaderMap& response_trailers, + const StreamInfo::StreamInfo& request_info) const PURE; +}; + +typedef std::unique_ptr FormatterProviderPtr; + } // namespace AccessLog } // namespace Envoy diff --git a/include/envoy/http/filter.h b/include/envoy/http/filter.h index c0e484ca75ae6..519065fb117d0 100644 --- a/include/envoy/http/filter.h +++ b/include/envoy/http/filter.h @@ -12,6 +12,7 @@ #include "envoy/router/router.h" #include "envoy/ssl/connection.h" #include "envoy/tracing/http_tracer.h" +#include "envoy/upstream/upstream.h" namespace Envoy { namespace Http { @@ -111,6 +112,14 @@ class StreamFilterCallbacks { */ virtual Router::RouteConstSharedPtr route() PURE; + /** + * Returns the clusterInfo for the cached route. + * This method is to avoid multiple look ups in the filter chain, it also provides a consistent + * view of clusterInfo after a route is picked/repicked. + * NOTE: Cached clusterInfo and route will be updated the same time. + */ + virtual Upstream::ClusterInfoConstSharedPtr clusterInfo() PURE; + /** * Clears the route cache for the current request. This must be called when a filter has modified * the headers in a way that would affect routing. @@ -123,10 +132,10 @@ class StreamFilterCallbacks { virtual uint64_t streamId() PURE; /** - * @return requestInfo for logging purposes. Individual filter may add specific information to be + * @return streamInfo for logging purposes. Individual filter may add specific information to be * put into the access log. */ - virtual RequestInfo::RequestInfo& requestInfo() PURE; + virtual StreamInfo::StreamInfo& streamInfo() PURE; /** * @return span context used for tracing purposes. Individual filters may add or modify diff --git a/include/envoy/http/header_map.h b/include/envoy/http/header_map.h index d7af629b84c62..7504ba054bd34 100644 --- a/include/envoy/http/header_map.h +++ b/include/envoy/http/header_map.h @@ -243,6 +243,7 @@ class HeaderEntry { HEADER_FUNC(ContentLength) \ HEADER_FUNC(ContentType) \ HEADER_FUNC(Date) \ + HEADER_FUNC(EnvoyAttemptCount) \ HEADER_FUNC(EnvoyDecoratorOperation) \ HEADER_FUNC(EnvoyDownstreamServiceCluster) \ HEADER_FUNC(EnvoyDownstreamServiceNode) \ @@ -257,6 +258,7 @@ class HeaderEntry { HEADER_FUNC(EnvoyOverloaded) \ HEADER_FUNC(EnvoyRetryOn) \ HEADER_FUNC(EnvoyRetryGrpcOn) \ + HEADER_FUNC(EnvoyRetriableStatusCodes) \ HEADER_FUNC(EnvoyUpstreamAltStatName) \ HEADER_FUNC(EnvoyUpstreamCanary) \ HEADER_FUNC(EnvoyUpstreamHealthCheckedCluster) \ diff --git a/include/envoy/network/BUILD b/include/envoy/network/BUILD index cb785f469f53e..9b672c2ff2261 100644 --- a/include/envoy/network/BUILD +++ b/include/envoy/network/BUILD @@ -24,8 +24,8 @@ envoy_cc_library( ":listen_socket_interface", "//include/envoy/buffer:buffer_interface", "//include/envoy/event:deferred_deletable", - "//include/envoy/request_info:filter_state_interface", "//include/envoy/ssl:connection_interface", + "//include/envoy/stream_info:filter_state_interface", ], ) diff --git a/include/envoy/network/connection.h b/include/envoy/network/connection.h index 899dc5fe7c4fd..1a3722bd79d39 100644 --- a/include/envoy/network/connection.h +++ b/include/envoy/network/connection.h @@ -10,8 +10,8 @@ #include "envoy/network/address.h" #include "envoy/network/filter.h" #include "envoy/network/listen_socket.h" -#include "envoy/request_info/filter_state.h" #include "envoy/ssl/connection.h" +#include "envoy/stream_info/filter_state.h" namespace Envoy { namespace Event { @@ -245,8 +245,8 @@ class Connection : public Event::DeferredDeletable, public FilterManager { * consumed by many other objects. * @return the per-connection state associated with this connection. */ - virtual RequestInfo::FilterState& perConnectionState() PURE; - virtual const RequestInfo::FilterState& perConnectionState() const PURE; + virtual StreamInfo::FilterState& perConnectionState() PURE; + virtual const StreamInfo::FilterState& perConnectionState() const PURE; /** * Set the timeout for delayed connection close()s. diff --git a/include/envoy/network/connection_handler.h b/include/envoy/network/connection_handler.h index 9d3f654d17ea9..f732fbfbaee0d 100644 --- a/include/envoy/network/connection_handler.h +++ b/include/envoy/network/connection_handler.h @@ -56,6 +56,18 @@ class ConnectionHandler { * Stop all listeners. This will not close any connections and is used for draining. */ virtual void stopListeners() PURE; + + /** + * Disable all listeners. This will not close any connections and is used to temporarily + * stop accepting connections on all listeners. + */ + virtual void disableListeners() PURE; + + /** + * Enable all listeners. This is used to re-enable accepting connections on all listeners + * after they have been temporarily disabled. + */ + virtual void enableListeners() PURE; }; typedef std::unique_ptr ConnectionHandlerPtr; diff --git a/include/envoy/network/listener.h b/include/envoy/network/listener.h index d4cbb5fbbf9ac..292e3bec17b1b 100644 --- a/include/envoy/network/listener.h +++ b/include/envoy/network/listener.h @@ -106,6 +106,16 @@ class ListenerCallbacks { class Listener { public: virtual ~Listener() {} + + /** + * Temporarily disable accepting new connections. + */ + virtual void disable() PURE; + + /** + * Enable accepting new connections. + */ + virtual void enable() PURE; }; typedef std::unique_ptr ListenerPtr; diff --git a/include/envoy/router/BUILD b/include/envoy/router/BUILD index 57c0a82fca823..2f7dd861bfb03 100644 --- a/include/envoy/router/BUILD +++ b/include/envoy/router/BUILD @@ -72,6 +72,6 @@ envoy_cc_library( hdrs = ["string_accessor.h"], external_deps = ["abseil_optional"], deps = [ - "//include/envoy/request_info:filter_state_interface", + "//include/envoy/stream_info:filter_state_interface", ], ) diff --git a/include/envoy/router/router.h b/include/envoy/router/router.h index e7442dba4f4a4..97e95101134dd 100644 --- a/include/envoy/router/router.h +++ b/include/envoy/router/router.h @@ -43,10 +43,10 @@ class ResponseEntry { * example, adding or removing headers. This should only be called ONCE immediately after * obtaining the initial response headers. * @param headers supplies the response headers, which may be modified during this call. - * @param request_info holds additional information about the request. + * @param stream_info holds additional information about the request. */ virtual void finalizeResponseHeaders(Http::HeaderMap& headers, - const RequestInfo::RequestInfo& request_info) const PURE; + const StreamInfo::StreamInfo& stream_info) const PURE; }; /** @@ -151,6 +151,8 @@ class RetryPolicy { static const uint32_t RETRY_ON_GRPC_DEADLINE_EXCEEDED = 0x40; static const uint32_t RETRY_ON_GRPC_RESOURCE_EXHAUSTED = 0x80; 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; // clang-format on virtual ~RetryPolicy() {} @@ -186,6 +188,12 @@ class RetryPolicy { * for a retry attempt. */ virtual uint32_t hostSelectionMaxAttempts() const PURE; + + /** + * List of status codes that should trigger a retry when the retriable-status-codes retry + * policy is enabled. + */ + virtual const std::vector& retriableStatusCodes() const PURE; }; /** @@ -345,6 +353,11 @@ class VirtualHost { template const Derived* perFilterConfigTyped(const std::string& name) const { return dynamic_cast(perFilterConfig(name)); } + + /** + * @return bool whether to include the request count header in upstream requests. + */ + virtual bool includeAttemptCount() const PURE; }; /** @@ -480,11 +493,11 @@ class RouteEntry : public ResponseEntry { * example URL prefix rewriting, adding headers, etc. This should only be called ONCE * immediately prior to forwarding. It is done this way vs. copying for performance reasons. * @param headers supplies the request headers, which may be modified during this call. - * @param request_info holds additional information about the request. + * @param stream_info holds additional information about the request. * @param insert_envoy_original_path insert x-envoy-original-path header if path rewritten? */ virtual void finalizeRequestHeaders(Http::HeaderMap& headers, - const RequestInfo::RequestInfo& request_info, + const StreamInfo::StreamInfo& stream_info, bool insert_envoy_original_path) const PURE; /** @@ -566,7 +579,7 @@ class RouteEntry : public ResponseEntry { * in this route. */ virtual Http::WebSocketProxyPtr - createWebSocketProxy(Http::HeaderMap& request_headers, RequestInfo::RequestInfo& request_info, + createWebSocketProxy(Http::HeaderMap& request_headers, StreamInfo::StreamInfo& stream_info, Http::WebSocketProxyCallbacks& callbacks, Upstream::ClusterManager& cluster_manager, Network::ReadFilterCallbacks* read_callbacks) const PURE; @@ -612,7 +625,14 @@ class RouteEntry : public ResponseEntry { */ template const Derived* perFilterConfigTyped(const std::string& name) const { return dynamic_cast(perFilterConfig(name)); - } + }; + + /** + * True if the virtual host this RouteEntry belongs to is configured to include the attempt + * count header. + * @return bool whether x-envoy-attempt-count should be included on the upstream request. + */ + virtual bool includeAttemptCount() const PURE; }; /** diff --git a/include/envoy/router/string_accessor.h b/include/envoy/router/string_accessor.h index f49f37d8e9784..8504bf4edf566 100644 --- a/include/envoy/router/string_accessor.h +++ b/include/envoy/router/string_accessor.h @@ -1,7 +1,7 @@ #pragma once #include "envoy/common/pure.h" -#include "envoy/request_info/filter_state.h" +#include "envoy/stream_info/filter_state.h" #include "absl/strings/string_view.h" @@ -13,7 +13,7 @@ namespace Router { * allows lazy evaluation if needed. All values meant to be accessible to the * custom request/response header mechanism must use this type. */ -class StringAccessor : public RequestInfo::FilterState::Object { +class StringAccessor : public StreamInfo::FilterState::Object { public: /** * @return the string the accessor represents. diff --git a/include/envoy/server/overload_manager.h b/include/envoy/server/overload_manager.h index 38981b5ee8064..b8294e594808b 100644 --- a/include/envoy/server/overload_manager.h +++ b/include/envoy/server/overload_manager.h @@ -58,11 +58,14 @@ class ThreadLocalOverloadState : public ThreadLocal::ThreadLocalObject { */ class OverloadActionNameValues { public: - // Overload action to stop accepting new requests. + // Overload action to stop accepting new HTTP requests. const std::string StopAcceptingRequests = "envoy.overload_actions.stop_accepting_requests"; // Overload action to disable http keepalive (for HTTP1.x). const std::string DisableHttpKeepAlive = "envoy.overload_actions.disable_http_keepalive"; + + // Overload action to stop accepting new connections. + const std::string StopAcceptingConnections = "envoy.overload_actions.stop_accepting_connections"; }; typedef ConstSingleton OverloadActionNames; diff --git a/include/envoy/server/worker.h b/include/envoy/server/worker.h index 9f69a7163e739..cb845b318158c 100644 --- a/include/envoy/server/worker.h +++ b/include/envoy/server/worker.h @@ -3,6 +3,7 @@ #include #include "envoy/server/guarddog.h" +#include "envoy/server/overload_manager.h" namespace Envoy { namespace Server { @@ -84,7 +85,7 @@ class WorkerFactory { /** * @return WorkerPtr a new worker. */ - virtual WorkerPtr createWorker() PURE; + virtual WorkerPtr createWorker(OverloadManager& overload_manager) PURE; }; } // namespace Server diff --git a/include/envoy/ssl/BUILD b/include/envoy/ssl/BUILD index ace87b66039de..f1c2f45d79b5c 100644 --- a/include/envoy/ssl/BUILD +++ b/include/envoy/ssl/BUILD @@ -16,6 +16,9 @@ envoy_cc_library( envoy_cc_library( name = "context_interface", hdrs = ["context.h"], + deps = [ + "@envoy_api//envoy/admin/v2alpha:certs_cc", + ], ) envoy_cc_library( diff --git a/include/envoy/ssl/context.h b/include/envoy/ssl/context.h index b3d63bfe45b78..5f5db65728de8 100644 --- a/include/envoy/ssl/context.h +++ b/include/envoy/ssl/context.h @@ -3,11 +3,14 @@ #include #include +#include "envoy/admin/v2alpha/certs.pb.h" #include "envoy/common/pure.h" namespace Envoy { namespace Ssl { +typedef std::unique_ptr CertificateDetailsPtr; + /** * SSL Context is used as a template for SSL connection configuration. */ @@ -21,16 +24,14 @@ class Context { virtual size_t daysUntilFirstCertExpires() const PURE; /** - * @return a string of ca certificate path, certificate serial number and days until certificate - * expiration + * @return certificate details conforming to proto admin.v2alpha.certs. */ - virtual std::string getCaCertInformation() const PURE; + virtual CertificateDetailsPtr getCaCertInformation() const PURE; /** - * @return a string of cert chain certificate path, certificate serial number and days until - * certificate expiration + * @return certificate details conforming to proto admin.v2alpha.certs. */ - virtual std::string getCertChainInformation() const PURE; + virtual CertificateDetailsPtr getCertChainInformation() const PURE; }; typedef std::shared_ptr ContextSharedPtr; diff --git a/include/envoy/stats/BUILD b/include/envoy/stats/BUILD index 46928ce6ff677..9f1e513135b60 100644 --- a/include/envoy/stats/BUILD +++ b/include/envoy/stats/BUILD @@ -18,6 +18,7 @@ envoy_cc_library( "source.h", "stat_data_allocator.h", "stats.h", + "stats_matcher.h", "stats_options.h", "store.h", "tag.h", diff --git a/include/envoy/stats/stats_matcher.h b/include/envoy/stats/stats_matcher.h new file mode 100644 index 0000000000000..f2ce66fb3d219 --- /dev/null +++ b/include/envoy/stats/stats_matcher.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +#include "envoy/common/pure.h" + +namespace Envoy { +namespace Stats { + +class StatsMatcher { +public: + virtual ~StatsMatcher() {} + + /** + * Take a metric name and report whether or not it should be instantiated. + * @param the name of a Stats::Metric. + * @return bool true if that stat should not be instantiated. + */ + virtual bool rejects(const std::string& name) const PURE; +}; + +typedef std::unique_ptr StatsMatcherPtr; + +} // namespace Stats +} // namespace Envoy diff --git a/include/envoy/stats/store.h b/include/envoy/stats/store.h index 532fa5806558a..cd017f9ad8843 100644 --- a/include/envoy/stats/store.h +++ b/include/envoy/stats/store.h @@ -6,6 +6,7 @@ #include "envoy/common/pure.h" #include "envoy/stats/scope.h" +#include "envoy/stats/stats_matcher.h" #include "envoy/stats/tag_producer.h" namespace Envoy { @@ -66,6 +67,13 @@ class StoreRoot : public Store { */ virtual void setTagProducer(TagProducerPtr&& tag_producer) PURE; + /** + * Attach a StatsMatcher to this StoreRoot to prevent the initialization of stats according to + * some ruleset. + * @param stats_matcher a StatsMatcher to attach to this StoreRoot. + */ + virtual void setStatsMatcher(StatsMatcherPtr&& stats_matcher) PURE; + /** * Initialize the store for threading. This will be called once after all worker threads have * been initialized. At this point the store can initialize itself for multi-threaded operation. diff --git a/include/envoy/request_info/BUILD b/include/envoy/stream_info/BUILD similarity index 88% rename from include/envoy/request_info/BUILD rename to include/envoy/stream_info/BUILD index 632d6cceb0cc4..9ff5757d2ecb4 100644 --- a/include/envoy/request_info/BUILD +++ b/include/envoy/stream_info/BUILD @@ -9,8 +9,8 @@ load( envoy_package() envoy_cc_library( - name = "request_info_interface", - hdrs = ["request_info.h"], + name = "stream_info_interface", + hdrs = ["stream_info.h"], external_deps = ["abseil_optional"], deps = [ ":filter_state_interface", diff --git a/include/envoy/request_info/filter_state.h b/include/envoy/stream_info/filter_state.h similarity index 97% rename from include/envoy/request_info/filter_state.h rename to include/envoy/stream_info/filter_state.h index 1be564497bda8..acc5aa5540c7a 100644 --- a/include/envoy/request_info/filter_state.h +++ b/include/envoy/stream_info/filter_state.h @@ -10,7 +10,7 @@ #include "absl/strings/string_view.h" namespace Envoy { -namespace RequestInfo { +namespace StreamInfo { class FilterState { public: @@ -66,5 +66,5 @@ class FilterState { virtual const Object* getDataGeneric(absl::string_view data_name) const PURE; }; -} // namespace RequestInfo +} // namespace StreamInfo } // namespace Envoy diff --git a/include/envoy/request_info/request_info.h b/include/envoy/stream_info/stream_info.h similarity index 98% rename from include/envoy/request_info/request_info.h rename to include/envoy/stream_info/stream_info.h index 154a46b25488d..58bfeaa970b21 100644 --- a/include/envoy/request_info/request_info.h +++ b/include/envoy/stream_info/stream_info.h @@ -8,7 +8,7 @@ #include "envoy/common/pure.h" #include "envoy/common/time.h" #include "envoy/http/protocol.h" -#include "envoy/request_info/filter_state.h" +#include "envoy/stream_info/filter_state.h" #include "envoy/upstream/upstream.h" #include "absl/types/optional.h" @@ -19,7 +19,7 @@ namespace Router { class RouteEntry; } // namespace Router -namespace RequestInfo { +namespace StreamInfo { enum ResponseFlag { // Local server healthcheck failed. @@ -57,9 +57,9 @@ enum ResponseFlag { /** * Additional information about a completed request for logging. */ -class RequestInfo { +class StreamInfo { public: - virtual ~RequestInfo() {} + virtual ~StreamInfo() {} /** * @param response_flag the response flag. Each filter can set independent response flags. The @@ -324,5 +324,5 @@ class RequestInfo { virtual const std::string& requestedServerName() const PURE; }; -} // namespace RequestInfo +} // namespace StreamInfo } // namespace Envoy diff --git a/include/envoy/tracing/http_tracer.h b/include/envoy/tracing/http_tracer.h index 6cf17f5b29799..74dcc86e916cc 100644 --- a/include/envoy/tracing/http_tracer.h +++ b/include/envoy/tracing/http_tracer.h @@ -135,7 +135,7 @@ class HttpTracer { virtual ~HttpTracer() {} virtual SpanPtr startSpan(const Config& config, Http::HeaderMap& request_headers, - const RequestInfo::RequestInfo& request_info, + const StreamInfo::StreamInfo& stream_info, const Tracing::Decision tracing_decision) PURE; }; diff --git a/include/envoy/upstream/retry.h b/include/envoy/upstream/retry.h index f448b3bc5b998..c601d0fc1fc54 100644 --- a/include/envoy/upstream/retry.h +++ b/include/envoy/upstream/retry.h @@ -109,6 +109,8 @@ class RetryPriorityFactory { const Protobuf::Message& config, uint32_t retry_count) PURE; virtual std::string name() const PURE; + + virtual ProtobufTypes::MessagePtr createEmptyConfigProto() PURE; }; /** @@ -125,6 +127,8 @@ class RetryHostPredicateFactory { * @return name name of this factory. */ virtual std::string name() PURE; + + virtual ProtobufTypes::MessagePtr createEmptyConfigProto() PURE; }; } // namespace Upstream diff --git a/include/envoy/upstream/thread_local_cluster.h b/include/envoy/upstream/thread_local_cluster.h index 009ef64821aaa..9e37b95a02c21 100644 --- a/include/envoy/upstream/thread_local_cluster.h +++ b/include/envoy/upstream/thread_local_cluster.h @@ -20,8 +20,7 @@ class ThreadLocalCluster { /** * @return ClusterInfoConstSharedPtr the info for this cluster. The info is safe to store beyond - * the - * lifetime of the ThreadLocalCluster instance itself. + * the lifetime of the ThreadLocalCluster instance itself. */ virtual ClusterInfoConstSharedPtr info() PURE; diff --git a/source/common/access_log/BUILD b/source/common/access_log/BUILD index afbca0e51e2cf..c7be03032909e 100644 --- a/source/common/access_log/BUILD +++ b/source/common/access_log/BUILD @@ -14,12 +14,12 @@ envoy_cc_library( hdrs = ["access_log_formatter.h"], deps = [ "//include/envoy/access_log:access_log_interface", - "//include/envoy/request_info:request_info_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/request_info:utility_lib", + "//source/common/stream_info:utility_lib", ], ) @@ -52,8 +52,8 @@ envoy_cc_library( "//source/common/http:headers_lib", "//source/common/http:utility_lib", "//source/common/protobuf:utility_lib", - "//source/common/request_info:request_info_lib", "//source/common/runtime:uuid_util_lib", + "//source/common/stream_info:stream_info_lib", "//source/common/tracing:http_tracer_lib", "@envoy_api//envoy/config/filter/accesslog/v2:accesslog_cc", ], diff --git a/source/common/access_log/access_log_formatter.cc b/source/common/access_log/access_log_formatter.cc index 40247819f2cb5..2c0b0d2cabf40 100644 --- a/source/common/access_log/access_log_formatter.cc +++ b/source/common/access_log/access_log_formatter.cc @@ -1,18 +1,19 @@ -#include "common/access_log/access_log_formatter.h" - #include #include #include +#include "common/access_log/access_log_formatter.h" #include "common/common/assert.h" #include "common/common/fmt.h" #include "common/common/utility.h" #include "common/config/metadata.h" #include "common/http/utility.h" -#include "common/request_info/utility.h" +#include "common/stream_info/utility.h" #include "absl/strings/str_split.h" #include "fmt/format.h" +#include "rapidjson/prettywriter.h" +#include "rapidjson/stringbuffer.h" using Envoy::Config::Metadata; @@ -54,24 +55,71 @@ AccessLogFormatUtils::protocolToString(const absl::optional& pro } FormatterImpl::FormatterImpl(const std::string& format) { - formatters_ = AccessLogFormatParser::parse(format); + providers_ = AccessLogFormatParser::parse(format); } std::string FormatterImpl::format(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, const Http::HeaderMap& response_trailers, - const RequestInfo::RequestInfo& request_info) const { + const StreamInfo::StreamInfo& stream_info) const { std::string log_line; log_line.reserve(256); - for (const FormatterPtr& formatter : formatters_) { - log_line += - formatter->format(request_headers, response_headers, response_trailers, request_info); + for (const FormatterProviderPtr& provider : providers_) { + log_line += provider->format(request_headers, response_headers, response_trailers, stream_info); } return log_line; } +JsonFormatterImpl::JsonFormatterImpl( + const std::map& format_mapping) { + for (const auto& pair : format_mapping) { + auto providers = AccessLogFormatParser::parse(pair.second); + + // Enforce that each key only has one format specifier in it + if (providers.size() > 1) { + throw EnvoyException(fmt::format( + "More than one format specifier was provided in the JSON log format: {}", pair.second)); + } + + if (providers.size() < 1) { + throw EnvoyException( + fmt::format("No format specifier was provided in the JSON log format: {}", pair.second)); + } + + json_output_format_.emplace(pair.first, std::move(providers[0])); + } +} + +std::string JsonFormatterImpl::format(const Http::HeaderMap& request_headers, + const Http::HeaderMap& response_headers, + const Http::HeaderMap& response_trailers, + const StreamInfo::StreamInfo& stream_info) const { + rapidjson::StringBuffer strbuf; + rapidjson::Writer writer(strbuf); + + auto output_map = this->to_map(request_headers, response_headers, response_trailers, stream_info); + writer.StartObject(); + for (const auto& pair : output_map) { + writer.Key(pair.first.c_str()); + writer.String(pair.second.c_str()); + } + writer.EndObject(); + return fmt::format("{}\n", strbuf.GetString()); +} + +std::map JsonFormatterImpl::to_map( + const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, + const Http::HeaderMap& response_trailers, const StreamInfo::StreamInfo& stream_info) const { + std::map output; + for (const auto& pair : json_output_format_) { + output.emplace(pair.first, pair.second->format(request_headers, response_headers, + response_trailers, stream_info)); + } + return output; +} + void AccessLogFormatParser::parseCommandHeader(const std::string& token, const size_t start, std::string& main_header, std::string& alternative_header, @@ -131,16 +179,16 @@ void AccessLogFormatParser::parseCommand(const std::string& token, const size_t } // TODO(derekargueta): #2967 - Rewrite AccessLogformatter with parser library & formal grammar -std::vector AccessLogFormatParser::parse(const std::string& format) { +std::vector AccessLogFormatParser::parse(const std::string& format) { std::string current_token; - std::vector formatters; + std::vector formatters; const std::string DYNAMIC_META_TOKEN = "DYNAMIC_METADATA("; const std::regex command_w_args_regex(R"EOF(%([A-Z]|_)+(\([^\)]*\))?(:[0-9]+)?(%))EOF"); for (size_t pos = 0; pos < format.length(); ++pos) { if (format[pos] == '%') { if (!current_token.empty()) { - formatters.emplace_back(new PlainStringFormatter(current_token)); + formatters.emplace_back(FormatterProviderPtr{new PlainStringFormatter(current_token)}); current_token = ""; } @@ -163,24 +211,24 @@ std::vector AccessLogFormatParser::parse(const std::string& format parseCommandHeader(token, ReqParamStart, main_header, alternative_header, max_length); - formatters.emplace_back( - new RequestHeaderFormatter(main_header, alternative_header, max_length)); + formatters.emplace_back(FormatterProviderPtr{ + new RequestHeaderFormatter(main_header, alternative_header, max_length)}); } else if (token.find("RESP(") == 0) { std::string main_header, alternative_header; absl::optional max_length; parseCommandHeader(token, RespParamStart, main_header, alternative_header, max_length); - formatters.emplace_back( - new ResponseHeaderFormatter(main_header, alternative_header, max_length)); + formatters.emplace_back(FormatterProviderPtr{ + new ResponseHeaderFormatter(main_header, alternative_header, max_length)}); } else if (token.find("TRAILER(") == 0) { std::string main_header, alternative_header; absl::optional max_length; parseCommandHeader(token, TrailParamStart, main_header, alternative_header, max_length); - formatters.emplace_back( - new ResponseTrailerFormatter(main_header, alternative_header, max_length)); + formatters.emplace_back(FormatterProviderPtr{ + new ResponseTrailerFormatter(main_header, alternative_header, max_length)}); } else if (token.find(DYNAMIC_META_TOKEN) == 0) { std::string filter_namespace; absl::optional max_length; @@ -188,7 +236,8 @@ std::vector AccessLogFormatParser::parse(const std::string& format const size_t start = DYNAMIC_META_TOKEN.size(); parseCommand(token, start, ":", filter_namespace, path, max_length); - formatters.emplace_back(new DynamicMetadataFormatter(filter_namespace, path, max_length)); + formatters.emplace_back( + FormatterProviderPtr{new DynamicMetadataFormatter(filter_namespace, path, max_length)}); } else if (token.find("START_TIME") == 0) { const size_t parameters_length = pos + StartTimeParamStart + 1; const size_t parameters_end = command_end_position - parameters_length; @@ -196,9 +245,9 @@ std::vector AccessLogFormatParser::parse(const std::string& format const std::string args = token[StartTimeParamStart - 1] == '(' ? token.substr(StartTimeParamStart, parameters_end) : ""; - formatters.emplace_back(new StartTimeFormatter(args)); + formatters.emplace_back(FormatterProviderPtr{new StartTimeFormatter(args)}); } else { - formatters.emplace_back(new RequestInfoFormatter(token)); + formatters.emplace_back(FormatterProviderPtr{new StreamInfoFormatter(token)}); } pos = command_end_position; } else { @@ -207,26 +256,26 @@ std::vector AccessLogFormatParser::parse(const std::string& format } if (!current_token.empty()) { - formatters.emplace_back(new PlainStringFormatter(current_token)); + formatters.emplace_back(FormatterProviderPtr{new PlainStringFormatter(current_token)}); } return formatters; } -RequestInfoFormatter::RequestInfoFormatter(const std::string& field_name) { +StreamInfoFormatter::StreamInfoFormatter(const std::string& field_name) { if (field_name == "REQUEST_DURATION") { - field_extractor_ = [](const RequestInfo::RequestInfo& request_info) { - return AccessLogFormatUtils::durationToString(request_info.lastDownstreamRxByteReceived()); + field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { + return AccessLogFormatUtils::durationToString(stream_info.lastDownstreamRxByteReceived()); }; } else if (field_name == "RESPONSE_DURATION") { - field_extractor_ = [](const RequestInfo::RequestInfo& request_info) { - return AccessLogFormatUtils::durationToString(request_info.firstUpstreamRxByteReceived()); + field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { + return AccessLogFormatUtils::durationToString(stream_info.firstUpstreamRxByteReceived()); }; } else if (field_name == "RESPONSE_TX_DURATION") { - field_extractor_ = [](const RequestInfo::RequestInfo& request_info) { - auto downstream = request_info.lastDownstreamTxByteSent(); - auto upstream = request_info.firstUpstreamRxByteReceived(); + field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { + auto downstream = stream_info.lastDownstreamTxByteSent(); + auto upstream = stream_info.firstUpstreamRxByteReceived(); if (downstream && upstream) { auto val = downstream.value() - upstream.value(); @@ -236,95 +285,95 @@ RequestInfoFormatter::RequestInfoFormatter(const std::string& field_name) { return UnspecifiedValueString; }; } else if (field_name == "BYTES_RECEIVED") { - field_extractor_ = [](const RequestInfo::RequestInfo& request_info) { - return fmt::FormatInt(request_info.bytesReceived()).str(); + field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { + return fmt::FormatInt(stream_info.bytesReceived()).str(); }; } else if (field_name == "PROTOCOL") { - field_extractor_ = [](const RequestInfo::RequestInfo& request_info) { - return AccessLogFormatUtils::protocolToString(request_info.protocol()); + field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { + return AccessLogFormatUtils::protocolToString(stream_info.protocol()); }; } else if (field_name == "RESPONSE_CODE") { - field_extractor_ = [](const RequestInfo::RequestInfo& request_info) { - return request_info.responseCode() ? fmt::FormatInt(request_info.responseCode().value()).str() - : "0"; + field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { + return stream_info.responseCode() ? fmt::FormatInt(stream_info.responseCode().value()).str() + : "0"; }; } else if (field_name == "BYTES_SENT") { - field_extractor_ = [](const RequestInfo::RequestInfo& request_info) { - return fmt::FormatInt(request_info.bytesSent()).str(); + field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { + return fmt::FormatInt(stream_info.bytesSent()).str(); }; } else if (field_name == "DURATION") { - field_extractor_ = [](const RequestInfo::RequestInfo& request_info) { - return AccessLogFormatUtils::durationToString(request_info.requestComplete()); + field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { + return AccessLogFormatUtils::durationToString(stream_info.requestComplete()); }; } else if (field_name == "RESPONSE_FLAGS") { - field_extractor_ = [](const RequestInfo::RequestInfo& request_info) { - return RequestInfo::ResponseFlagUtils::toShortString(request_info); + field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { + return StreamInfo::ResponseFlagUtils::toShortString(stream_info); }; } else if (field_name == "UPSTREAM_HOST") { - field_extractor_ = [](const RequestInfo::RequestInfo& request_info) { - if (request_info.upstreamHost()) { - return request_info.upstreamHost()->address()->asString(); + field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { + if (stream_info.upstreamHost()) { + return stream_info.upstreamHost()->address()->asString(); } else { return UnspecifiedValueString; } }; } else if (field_name == "UPSTREAM_CLUSTER") { - field_extractor_ = [](const RequestInfo::RequestInfo& request_info) { + field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { std::string upstream_cluster_name; - if (nullptr != request_info.upstreamHost()) { - upstream_cluster_name = request_info.upstreamHost()->cluster().name(); + if (nullptr != stream_info.upstreamHost()) { + upstream_cluster_name = stream_info.upstreamHost()->cluster().name(); } return upstream_cluster_name.empty() ? UnspecifiedValueString : upstream_cluster_name; }; } else if (field_name == "UPSTREAM_LOCAL_ADDRESS") { - field_extractor_ = [](const RequestInfo::RequestInfo& request_info) { - return request_info.upstreamLocalAddress() != nullptr - ? request_info.upstreamLocalAddress()->asString() + field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { + return stream_info.upstreamLocalAddress() != nullptr + ? stream_info.upstreamLocalAddress()->asString() : UnspecifiedValueString; }; } else if (field_name == "DOWNSTREAM_LOCAL_ADDRESS") { - field_extractor_ = [](const RequestInfo::RequestInfo& request_info) { - return request_info.downstreamLocalAddress()->asString(); + field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { + return stream_info.downstreamLocalAddress()->asString(); }; } else if (field_name == "DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT") { - field_extractor_ = [](const Envoy::RequestInfo::RequestInfo& request_info) { - return RequestInfo::Utility::formatDownstreamAddressNoPort( - *request_info.downstreamLocalAddress()); + field_extractor_ = [](const Envoy::StreamInfo::StreamInfo& stream_info) { + return StreamInfo::Utility::formatDownstreamAddressNoPort( + *stream_info.downstreamLocalAddress()); }; } else if (field_name == "DOWNSTREAM_REMOTE_ADDRESS") { - field_extractor_ = [](const RequestInfo::RequestInfo& request_info) { - return request_info.downstreamRemoteAddress()->asString(); + field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { + return stream_info.downstreamRemoteAddress()->asString(); }; } else if (field_name == "DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT") { - field_extractor_ = [](const RequestInfo::RequestInfo& request_info) { - return RequestInfo::Utility::formatDownstreamAddressNoPort( - *request_info.downstreamRemoteAddress()); + field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { + return StreamInfo::Utility::formatDownstreamAddressNoPort( + *stream_info.downstreamRemoteAddress()); }; } else if (field_name == "REQUESTED_SERVER_NAME") { - field_extractor_ = [](const RequestInfo::RequestInfo& request_info) { - if (!request_info.requestedServerName().empty()) { - return request_info.requestedServerName(); + field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { + if (!stream_info.requestedServerName().empty()) { + return stream_info.requestedServerName(); } else { return UnspecifiedValueString; } }; } else { - throw EnvoyException(fmt::format("Not supported field in RequestInfo: {}", field_name)); + throw EnvoyException(fmt::format("Not supported field in StreamInfo: {}", field_name)); } } -std::string RequestInfoFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, - const Http::HeaderMap&, - const RequestInfo::RequestInfo& request_info) const { - return field_extractor_(request_info); +std::string StreamInfoFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, + const Http::HeaderMap&, + const StreamInfo::StreamInfo& stream_info) const { + return field_extractor_(stream_info); } PlainStringFormatter::PlainStringFormatter(const std::string& str) : str_(str) {} std::string PlainStringFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const RequestInfo::RequestInfo&) const { + const StreamInfo::StreamInfo&) const { return str_; } @@ -362,7 +411,7 @@ ResponseHeaderFormatter::ResponseHeaderFormatter(const std::string& main_header, std::string ResponseHeaderFormatter::format(const Http::HeaderMap&, const Http::HeaderMap& response_headers, const Http::HeaderMap&, - const RequestInfo::RequestInfo&) const { + const StreamInfo::StreamInfo&) const { return HeaderFormatter::format(response_headers); } @@ -373,7 +422,7 @@ RequestHeaderFormatter::RequestHeaderFormatter(const std::string& main_header, std::string RequestHeaderFormatter::format(const Http::HeaderMap& request_headers, const Http::HeaderMap&, const Http::HeaderMap&, - const RequestInfo::RequestInfo&) const { + const StreamInfo::StreamInfo&) const { return HeaderFormatter::format(request_headers); } @@ -384,7 +433,7 @@ ResponseTrailerFormatter::ResponseTrailerFormatter(const std::string& main_heade std::string ResponseTrailerFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap& response_trailers, - const RequestInfo::RequestInfo&) const { + const StreamInfo::StreamInfo&) const { return HeaderFormatter::format(response_trailers); } @@ -426,19 +475,19 @@ DynamicMetadataFormatter::DynamicMetadataFormatter(const std::string& filter_nam std::string DynamicMetadataFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const RequestInfo::RequestInfo& request_info) const { - return MetadataFormatter::format(request_info.dynamicMetadata()); + const StreamInfo::StreamInfo& stream_info) const { + return MetadataFormatter::format(stream_info.dynamicMetadata()); } StartTimeFormatter::StartTimeFormatter(const std::string& format) : date_formatter_(format) {} std::string StartTimeFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const RequestInfo::RequestInfo& request_info) const { + const StreamInfo::StreamInfo& stream_info) const { if (date_formatter_.formatString().empty()) { - return AccessLogDateTimeFormatter::fromTime(request_info.startTime()); + return AccessLogDateTimeFormatter::fromTime(stream_info.startTime()); } else { - return date_formatter_.fromTime(request_info.startTime()); + return date_formatter_.fromTime(stream_info.startTime()); } } diff --git a/source/common/access_log/access_log_formatter.h b/source/common/access_log/access_log_formatter.h index adaa88afb916a..22d26ba20cfb6 100644 --- a/source/common/access_log/access_log_formatter.h +++ b/source/common/access_log/access_log_formatter.h @@ -6,7 +6,7 @@ #include "envoy/access_log/access_log.h" #include "envoy/common/time.h" -#include "envoy/request_info/request_info.h" +#include "envoy/stream_info/stream_info.h" #include "common/common/utility.h" @@ -20,7 +20,7 @@ namespace AccessLog { */ class AccessLogFormatParser { public: - static std::vector parse(const std::string& format); + static std::vector parse(const std::string& format); private: /** @@ -92,23 +92,43 @@ class FormatterImpl : public Formatter { std::string format(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, const Http::HeaderMap& response_trailers, - const RequestInfo::RequestInfo& request_info) const override; + const StreamInfo::StreamInfo& stream_info) const override; private: - std::vector formatters_; + std::vector providers_; +}; + +class JsonFormatterImpl : public Formatter { +public: + JsonFormatterImpl(const std::map& format_mapping); + + // Formatter::format + std::string format(const Http::HeaderMap& request_headers, + const Http::HeaderMap& response_headers, + const Http::HeaderMap& response_trailers, + const StreamInfo::StreamInfo& stream_info) const override; + + std::map to_map(const Http::HeaderMap& request_headers, + const Http::HeaderMap& response_headers, + const Http::HeaderMap& response_trailers, + const StreamInfo::StreamInfo& stream_info) const; + +private: + std::vector providers_; + std::map json_output_format_; }; /** - * Formatter for string literal. It ignores headers and request info and returns string by which it + * Formatter for string literal. It ignores headers and stream info and returns string by which it * was initialized. */ -class PlainStringFormatter : public Formatter { +class PlainStringFormatter : public FormatterProvider { public: PlainStringFormatter(const std::string& str); // Formatter::format std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const RequestInfo::RequestInfo&) const override; + const StreamInfo::StreamInfo&) const override; private: std::string str_; @@ -130,33 +150,33 @@ class HeaderFormatter { /** * Formatter based on request header. */ -class RequestHeaderFormatter : public Formatter, HeaderFormatter { +class RequestHeaderFormatter : public FormatterProvider, HeaderFormatter { public: RequestHeaderFormatter(const std::string& main_header, const std::string& alternative_header, absl::optional max_length); // Formatter::format std::string format(const Http::HeaderMap& request_headers, const Http::HeaderMap&, - const Http::HeaderMap&, const RequestInfo::RequestInfo&) const override; + const Http::HeaderMap&, const StreamInfo::StreamInfo&) const override; }; /** * Formatter based on the response header. */ -class ResponseHeaderFormatter : public Formatter, HeaderFormatter { +class ResponseHeaderFormatter : public FormatterProvider, HeaderFormatter { public: ResponseHeaderFormatter(const std::string& main_header, const std::string& alternative_header, absl::optional max_length); // Formatter::format std::string format(const Http::HeaderMap&, const Http::HeaderMap& response_headers, - const Http::HeaderMap&, const RequestInfo::RequestInfo&) const override; + const Http::HeaderMap&, const StreamInfo::StreamInfo&) const override; }; /** * Formatter based on the response trailer. */ -class ResponseTrailerFormatter : public Formatter, HeaderFormatter { +class ResponseTrailerFormatter : public FormatterProvider, HeaderFormatter { public: ResponseTrailerFormatter(const std::string& main_header, const std::string& alternative_header, absl::optional max_length); @@ -164,22 +184,22 @@ class ResponseTrailerFormatter : public Formatter, HeaderFormatter { // Formatter::format std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap& response_trailers, - const RequestInfo::RequestInfo&) const override; + const StreamInfo::StreamInfo&) const override; }; /** - * Formatter based on the RequestInfo field. + * Formatter based on the StreamInfo field. */ -class RequestInfoFormatter : public Formatter { +class StreamInfoFormatter : public FormatterProvider { public: - RequestInfoFormatter(const std::string& field_name); + StreamInfoFormatter(const std::string& field_name); // Formatter::format std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const RequestInfo::RequestInfo& request_info) const override; + const StreamInfo::StreamInfo& stream_info) const override; private: - std::function field_extractor_; + std::function field_extractor_; }; /** @@ -199,26 +219,26 @@ class MetadataFormatter { }; /** - * Formatter based on the DynamicMetadata from RequestInfo. + * Formatter based on the DynamicMetadata from StreamInfo. */ -class DynamicMetadataFormatter : public Formatter, MetadataFormatter { +class DynamicMetadataFormatter : public FormatterProvider, MetadataFormatter { public: DynamicMetadataFormatter(const std::string& filter_namespace, const std::vector& path, absl::optional max_length); - // Formatter::format + // FormatterProvider::format std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const RequestInfo::RequestInfo& request_info) const override; + const StreamInfo::StreamInfo& stream_info) const override; }; /** * Formatter */ -class StartTimeFormatter : public Formatter { +class StartTimeFormatter : public FormatterProvider { public: StartTimeFormatter(const std::string& format); std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const RequestInfo::RequestInfo&) const override; + const StreamInfo::StreamInfo&) const override; private: const Envoy::DateFormatter date_formatter_; diff --git a/source/common/access_log/access_log_impl.cc b/source/common/access_log/access_log_impl.cc index 163b695cf0253..7f85426449db3 100644 --- a/source/common/access_log/access_log_impl.cc +++ b/source/common/access_log/access_log_impl.cc @@ -1,5 +1,3 @@ -#include "common/access_log/access_log_impl.h" - #include #include @@ -11,6 +9,7 @@ #include "envoy/upstream/upstream.h" #include "common/access_log/access_log_formatter.h" +#include "common/access_log/access_log_impl.h" #include "common/common/assert.h" #include "common/common/utility.h" #include "common/config/utility.h" @@ -19,8 +18,8 @@ #include "common/http/headers.h" #include "common/http/utility.h" #include "common/protobuf/utility.h" -#include "common/request_info/utility.h" #include "common/runtime/uuid_util.h" +#include "common/stream_info/utility.h" #include "common/tracing/http_tracer_impl.h" #include "absl/types/optional.h" @@ -79,14 +78,14 @@ FilterFactory::fromProto(const envoy::config::filter::accesslog::v2::AccessLogFi } } -bool TraceableRequestFilter::evaluate(const RequestInfo::RequestInfo& info, +bool TraceableRequestFilter::evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers) { Tracing::Decision decision = Tracing::HttpTracerUtility::isTracing(info, request_headers); return decision.traced && decision.reason == Tracing::Reason::ServiceForced; } -bool StatusCodeFilter::evaluate(const RequestInfo::RequestInfo& info, const Http::HeaderMap&) { +bool StatusCodeFilter::evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap&) { if (!info.responseCode()) { return compareAgainstValue(0ULL); } @@ -94,7 +93,7 @@ bool StatusCodeFilter::evaluate(const RequestInfo::RequestInfo& info, const Http return compareAgainstValue(info.responseCode().value()); } -bool DurationFilter::evaluate(const RequestInfo::RequestInfo& info, const Http::HeaderMap&) { +bool DurationFilter::evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap&) { absl::optional final = info.requestComplete(); ASSERT(final); @@ -108,19 +107,19 @@ RuntimeFilter::RuntimeFilter(const envoy::config::filter::accesslog::v2::Runtime percent_(config.percent_sampled()), use_independent_randomness_(config.use_independent_randomness()) {} -bool RuntimeFilter::evaluate(const RequestInfo::RequestInfo&, - const Http::HeaderMap& request_header) { +bool RuntimeFilter::evaluate(const StreamInfo::StreamInfo&, const Http::HeaderMap& request_header) { const Http::HeaderEntry* uuid = request_header.RequestId(); uint64_t random_value; if (use_independent_randomness_ || uuid == nullptr || - !UuidUtils::uuidModBy(uuid->value().c_str(), random_value, - ProtobufPercentHelper::fractionalPercentDenominatorToInt(percent_))) { + !UuidUtils::uuidModBy( + uuid->value().c_str(), random_value, + ProtobufPercentHelper::fractionalPercentDenominatorToInt(percent_.denominator()))) { random_value = random_.random(); } return runtime_.snapshot().featureEnabled( runtime_key_, percent_.numerator(), random_value, - ProtobufPercentHelper::fractionalPercentDenominatorToInt(percent_)); + ProtobufPercentHelper::fractionalPercentDenominatorToInt(percent_.denominator())); } OperatorFilter::OperatorFilter(const Protobuf::RepeatedPtrField< @@ -139,7 +138,7 @@ AndFilter::AndFilter(const envoy::config::filter::accesslog::v2::AndFilter& conf Runtime::Loader& runtime, Runtime::RandomGenerator& random) : OperatorFilter(config.filters(), runtime, random) {} -bool OrFilter::evaluate(const RequestInfo::RequestInfo& info, +bool OrFilter::evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers) { bool result = false; for (auto& filter : filters_) { @@ -153,7 +152,7 @@ bool OrFilter::evaluate(const RequestInfo::RequestInfo& info, return result; } -bool AndFilter::evaluate(const RequestInfo::RequestInfo& info, +bool AndFilter::evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers) { bool result = true; for (auto& filter : filters_) { @@ -167,7 +166,7 @@ bool AndFilter::evaluate(const RequestInfo::RequestInfo& info, return result; } -bool NotHealthCheckFilter::evaluate(const RequestInfo::RequestInfo& info, const Http::HeaderMap&) { +bool NotHealthCheckFilter::evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap&) { return !info.healthCheck(); } @@ -175,23 +174,22 @@ HeaderFilter::HeaderFilter(const envoy::config::filter::accesslog::v2::HeaderFil header_data_.push_back(Http::HeaderUtility::HeaderData(config.header())); } -bool HeaderFilter::evaluate(const RequestInfo::RequestInfo&, - const Http::HeaderMap& request_headers) { +bool HeaderFilter::evaluate(const StreamInfo::StreamInfo&, const Http::HeaderMap& request_headers) { return Http::HeaderUtility::matchHeaders(request_headers, header_data_); } ResponseFlagFilter::ResponseFlagFilter( const envoy::config::filter::accesslog::v2::ResponseFlagFilter& config) { for (int i = 0; i < config.flags_size(); i++) { - absl::optional response_flag = - RequestInfo::ResponseFlagUtils::toResponseFlag(config.flags(i)); + absl::optional response_flag = + StreamInfo::ResponseFlagUtils::toResponseFlag(config.flags(i)); // The config has been validated. Therefore, every flag in the config will have a mapping. ASSERT(response_flag.has_value()); configured_flags_ |= response_flag.value(); } } -bool ResponseFlagFilter::evaluate(const RequestInfo::RequestInfo& info, const Http::HeaderMap&) { +bool ResponseFlagFilter::evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap&) { if (configured_flags_ != 0) { return info.intersectResponseFlags(configured_flags_); } diff --git a/source/common/access_log/access_log_impl.h b/source/common/access_log/access_log_impl.h index cad54fd633012..5c875a33f1770 100644 --- a/source/common/access_log/access_log_impl.h +++ b/source/common/access_log/access_log_impl.h @@ -51,7 +51,7 @@ class StatusCodeFilter : public ComparisonFilter { : ComparisonFilter(config.comparison(), runtime) {} // AccessLog::Filter - bool evaluate(const RequestInfo::RequestInfo& info, + bool evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers) override; }; @@ -65,7 +65,7 @@ class DurationFilter : public ComparisonFilter { : ComparisonFilter(config.comparison(), runtime) {} // AccessLog::Filter - bool evaluate(const RequestInfo::RequestInfo& info, + bool evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers) override; }; @@ -91,7 +91,7 @@ class AndFilter : public OperatorFilter { Runtime::RandomGenerator& random); // AccessLog::Filter - bool evaluate(const RequestInfo::RequestInfo& info, + bool evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers) override; }; @@ -104,7 +104,7 @@ class OrFilter : public OperatorFilter { Runtime::RandomGenerator& random); // AccessLog::Filter - bool evaluate(const RequestInfo::RequestInfo& info, + bool evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers) override; }; @@ -116,7 +116,7 @@ class NotHealthCheckFilter : public Filter { NotHealthCheckFilter() {} // AccessLog::Filter - bool evaluate(const RequestInfo::RequestInfo& info, + bool evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers) override; }; @@ -126,7 +126,7 @@ class NotHealthCheckFilter : public Filter { class TraceableRequestFilter : public Filter { public: // AccessLog::Filter - bool evaluate(const RequestInfo::RequestInfo& info, + bool evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers) override; }; @@ -139,7 +139,7 @@ class RuntimeFilter : public Filter { Runtime::Loader& runtime, Runtime::RandomGenerator& random); // AccessLog::Filter - bool evaluate(const RequestInfo::RequestInfo& info, + bool evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers) override; private: @@ -158,7 +158,7 @@ class HeaderFilter : public Filter { HeaderFilter(const envoy::config::filter::accesslog::v2::HeaderFilter& config); // AccessLog::Filter - bool evaluate(const RequestInfo::RequestInfo& info, + bool evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers) override; private: @@ -173,7 +173,7 @@ class ResponseFlagFilter : public Filter { ResponseFlagFilter(const envoy::config::filter::accesslog::v2::ResponseFlagFilter& config); // AccessLog::Filter - bool evaluate(const RequestInfo::RequestInfo& info, + bool evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers) override; private: diff --git a/source/common/access_log/access_log_manager_impl.cc b/source/common/access_log/access_log_manager_impl.cc index 56933387b348b..e2d10c20861f9 100644 --- a/source/common/access_log/access_log_manager_impl.cc +++ b/source/common/access_log/access_log_manager_impl.cc @@ -1,7 +1,7 @@ -#include "common/access_log/access_log_manager_impl.h" - #include +#include "common/access_log/access_log_manager_impl.h" + namespace Envoy { namespace AccessLog { diff --git a/source/common/config/BUILD b/source/common/config/BUILD index 179a9d32c95b5..9f21c94edef30 100644 --- a/source/common/config/BUILD +++ b/source/common/config/BUILD @@ -334,6 +334,7 @@ envoy_cc_library( "//source/common/protobuf:utility_lib", "//source/common/singleton:const_singleton", "//source/common/stats:stats_lib", + "//source/common/stats:stats_matcher_lib", "//source/common/stats:tag_producer_lib", "@envoy_api//envoy/api/v2/core:base_cc", "@envoy_api//envoy/config/filter/network/http_connection_manager/v2:http_connection_manager_cc", diff --git a/source/common/config/filter_json.cc b/source/common/config/filter_json.cc index f37279fc234da..0324cacfa2893 100644 --- a/source/common/config/filter_json.cc +++ b/source/common/config/filter_json.cc @@ -253,9 +253,11 @@ void FilterJson::translateMongoProxy( if (json_config.hasObject("fault")) { const auto json_fault = json_config.getObject("fault")->getObject("fixed_delay"); auto* delay = proto_config.mutable_delay(); + auto* percentage = delay->mutable_percentage(); delay->set_type(envoy::config::filter::fault::v2::FaultDelay::FIXED); - delay->set_percent(static_cast(json_fault->getInteger("percent"))); + percentage->set_numerator(static_cast(json_fault->getInteger("percent"))); + percentage->set_denominator(envoy::type::FractionalPercent::HUNDRED); JSON_UTIL_SET_DURATION_FROM_FIELD(*json_fault, *delay, fixed_delay, duration); } } @@ -270,7 +272,10 @@ void FilterJson::translateFaultFilter( if (!json_config_abort->empty()) { auto* abort_fault = proto_config.mutable_abort(); - abort_fault->set_percent(static_cast(json_config_abort->getInteger("abort_percent"))); + auto* percentage = abort_fault->mutable_percentage(); + percentage->set_numerator( + static_cast(json_config_abort->getInteger("abort_percent"))); + percentage->set_denominator(envoy::type::FractionalPercent::HUNDRED); // TODO(mattklein123): Throw error if invalid return code is provided abort_fault->set_http_status( @@ -279,8 +284,11 @@ void FilterJson::translateFaultFilter( if (!json_config_delay->empty()) { auto* delay = proto_config.mutable_delay(); + auto* percentage = delay->mutable_percentage(); delay->set_type(envoy::config::filter::fault::v2::FaultDelay::FIXED); - delay->set_percent(static_cast(json_config_delay->getInteger("fixed_delay_percent"))); + percentage->set_numerator( + static_cast(json_config_delay->getInteger("fixed_delay_percent"))); + percentage->set_denominator(envoy::type::FractionalPercent::HUNDRED); JSON_UTIL_SET_DURATION_FROM_FIELD(*json_config_delay, *delay, fixed_delay, fixed_duration); } diff --git a/source/common/config/utility.cc b/source/common/config/utility.cc index 36fa703d21b02..bb41fed9165d4 100644 --- a/source/common/config/utility.cc +++ b/source/common/config/utility.cc @@ -16,6 +16,7 @@ #include "common/json/config_schemas.h" #include "common/protobuf/protobuf.h" #include "common/protobuf/utility.h" +#include "common/stats/stats_matcher_impl.h" #include "common/stats/tag_producer_impl.h" namespace Envoy { @@ -221,6 +222,11 @@ Utility::createTagProducer(const envoy::config::bootstrap::v2::Bootstrap& bootst return std::make_unique(bootstrap.stats_config()); } +Stats::StatsMatcherPtr +Utility::createStatsMatcher(const envoy::config::bootstrap::v2::Bootstrap& bootstrap) { + return std::make_unique(bootstrap.stats_config()); +} + void Utility::checkObjNameLength(const std::string& error_prefix, const std::string& name, const Stats::StatsOptions& stats_options) { if (name.length() > stats_options.maxNameLength()) { diff --git a/source/common/config/utility.h b/source/common/config/utility.h index 9d172f1eb5930..954583db25c94 100644 --- a/source/common/config/utility.h +++ b/source/common/config/utility.h @@ -10,6 +10,7 @@ #include "envoy/registry/registry.h" #include "envoy/server/filter_config.h" #include "envoy/stats/scope.h" +#include "envoy/stats/stats_matcher.h" #include "envoy/stats/stats_options.h" #include "envoy/stats/tag_producer.h" #include "envoy/upstream/cluster_manager.h" @@ -302,6 +303,12 @@ class Utility { static Stats::TagProducerPtr createTagProducer(const envoy::config::bootstrap::v2::Bootstrap& bootstrap); + /** + * Create StatsMatcher instance. + */ + static Stats::StatsMatcherPtr + createStatsMatcher(const envoy::config::bootstrap::v2::Bootstrap& bootstrap); + /** * Check user supplied name in RDS/CDS/LDS for sanity. * It should be within the configured length limit. Throws on error. diff --git a/source/common/http/BUILD b/source/common/http/BUILD index e2a9b4d613e18..1d30921be6694 100644 --- a/source/common/http/BUILD +++ b/source/common/http/BUILD @@ -24,8 +24,8 @@ envoy_cc_library( "//include/envoy/ssl:connection_interface", "//source/common/common:empty_string", "//source/common/common:linked_object", - "//source/common/request_info:request_info_lib", "//source/common/router:router_lib", + "//source/common/stream_info:stream_info_lib", "//source/common/tracing:http_tracer_lib", ], ) @@ -140,8 +140,8 @@ envoy_cc_library( "//source/common/http/http1:codec_lib", "//source/common/http/http2:codec_lib", "//source/common/network:utility_lib", - "//source/common/request_info:request_info_lib", "//source/common/runtime:uuid_util_lib", + "//source/common/stream_info:stream_info_lib", "//source/common/tracing:http_tracer_lib", ], ) diff --git a/source/common/http/async_client_impl.cc b/source/common/http/async_client_impl.cc index 215559e701852..5fd5e7953b1c4 100644 --- a/source/common/http/async_client_impl.cc +++ b/source/common/http/async_client_impl.cc @@ -29,8 +29,8 @@ const AsyncStreamImpl::NullPathMatchCriterion AsyncStreamImpl::RouteEntryImpl::path_match_criterion_; const std::list AsyncStreamImpl::NullConfig::internal_only_headers_; -AsyncClientImpl::AsyncClientImpl(const Upstream::ClusterInfo& cluster, Stats::Store& stats_store, - Event::Dispatcher& dispatcher, +AsyncClientImpl::AsyncClientImpl(Upstream::ClusterInfoConstSharedPtr cluster, + Stats::Store& stats_store, Event::Dispatcher& dispatcher, const LocalInfo::LocalInfo& local_info, Upstream::ClusterManager& cm, Runtime::Loader& runtime, Runtime::RandomGenerator& random, @@ -78,15 +78,15 @@ AsyncStreamImpl::AsyncStreamImpl(AsyncClientImpl& parent, AsyncClient::StreamCal const absl::optional& timeout, bool buffer_body_for_retry) : parent_(parent), stream_callbacks_(callbacks), stream_id_(parent.config_.random_.random()), - router_(parent.config_), request_info_(Protocol::Http11, parent.dispatcher().timeSystem()), + router_(parent.config_), stream_info_(Protocol::Http11, parent.dispatcher().timeSystem()), tracing_config_(Tracing::EgressConfig::get()), - route_(std::make_shared(parent_.cluster_.name(), timeout)) { + route_(std::make_shared(parent_.cluster_->name(), timeout)) { if (buffer_body_for_retry) { buffered_body_.reset(new Buffer::OwnedImpl()); } router_.setDecoderFilterCallbacks(*this); - // TODO(mattklein123): Correctly set protocol in request info when we support access logging. + // TODO(mattklein123): Correctly set protocol in stream info when we support access logging. } void AsyncStreamImpl::encodeHeaders(HeaderMapPtr&& headers, bool end_stream) { diff --git a/source/common/http/async_client_impl.h b/source/common/http/async_client_impl.h index 382a5ac8be3cf..42b0bd1e3e083 100644 --- a/source/common/http/async_client_impl.h +++ b/source/common/http/async_client_impl.h @@ -19,12 +19,13 @@ #include "envoy/router/shadow_writer.h" #include "envoy/ssl/connection.h" #include "envoy/tracing/http_tracer.h" +#include "envoy/upstream/upstream.h" #include "common/common/empty_string.h" #include "common/common/linked_object.h" #include "common/http/message_impl.h" -#include "common/request_info/request_info_impl.h" #include "common/router/router.h" +#include "common/stream_info/stream_info_impl.h" #include "common/tracing/http_tracer_impl.h" namespace Envoy { @@ -35,7 +36,7 @@ class AsyncRequestImpl; class AsyncClientImpl final : public AsyncClient { public: - AsyncClientImpl(const Upstream::ClusterInfo& cluster, Stats::Store& stats_store, + AsyncClientImpl(Upstream::ClusterInfoConstSharedPtr cluster, Stats::Store& stats_store, Event::Dispatcher& dispatcher, const LocalInfo::LocalInfo& local_info, Upstream::ClusterManager& cm, Runtime::Loader& runtime, Runtime::RandomGenerator& random, Router::ShadowWriterPtr&& shadow_writer); @@ -52,7 +53,7 @@ class AsyncClientImpl final : public AsyncClient { Event::Dispatcher& dispatcher() override { return dispatcher_; } private: - const Upstream::ClusterInfo& cluster_; + Upstream::ClusterInfoConstSharedPtr cluster_; Router::FilterConfig config_; Event::Dispatcher& dispatcher_; std::list> active_streams_; @@ -130,6 +131,11 @@ class AsyncStreamImpl : public AsyncClient::Stream, uint32_t hostSelectionMaxAttempts() const override { return 1; } uint32_t numRetries() const override { return 0; } uint32_t retryOn() const override { return 0; } + const std::vector& retriableStatusCodes() const override { + return retriable_status_codes_; + } + + const std::vector retriable_status_codes_; }; struct NullShadowPolicy : public Router::ShadowPolicy { @@ -161,6 +167,7 @@ class AsyncStreamImpl : public AsyncClient::Stream, const Router::RouteSpecificFilterConfig* perFilterConfig(const std::string&) const override { return nullptr; } + bool includeAttemptCount() const override { return false; } static const NullRateLimitPolicy rate_limit_policy_; static const NullConfig route_configuration_; @@ -182,10 +189,9 @@ class AsyncStreamImpl : public AsyncClient::Stream, return Http::Code::InternalServerError; } const Router::CorsPolicy* corsPolicy() const override { return nullptr; } - void finalizeRequestHeaders(Http::HeaderMap&, const RequestInfo::RequestInfo&, + void finalizeRequestHeaders(Http::HeaderMap&, const StreamInfo::StreamInfo&, bool) const override {} - void finalizeResponseHeaders(Http::HeaderMap&, const RequestInfo::RequestInfo&) const override { - } + void finalizeResponseHeaders(Http::HeaderMap&, const StreamInfo::StreamInfo&) const override {} const Router::HashPolicy* hashPolicy() const override { return nullptr; } const Router::MetadataMatchCriteria* metadataMatchCriteria() const override { return nullptr; } Upstream::ResourcePriority priority() const override { @@ -214,7 +220,7 @@ class AsyncStreamImpl : public AsyncClient::Stream, const Router::VirtualHost& virtualHost() const override { return virtual_host_; } bool autoHostRewrite() const override { return false; } bool useOldStyleWebSocket() const override { return false; } - Http::WebSocketProxyPtr createWebSocketProxy(Http::HeaderMap&, RequestInfo::RequestInfo&, + Http::WebSocketProxyPtr createWebSocketProxy(Http::HeaderMap&, StreamInfo::StreamInfo&, Http::WebSocketProxyCallbacks&, Upstream::ClusterManager&, Network::ReadFilterCallbacks*) const override { @@ -230,6 +236,8 @@ class AsyncStreamImpl : public AsyncClient::Stream, return nullptr; } + bool includeAttemptCount() const override { return false; } + static const NullRateLimitPolicy rate_limit_policy_; static const NullRetryPolicy retry_policy_; static const NullShadowPolicy shadow_policy_; @@ -268,9 +276,10 @@ class AsyncStreamImpl : public AsyncClient::Stream, Event::Dispatcher& dispatcher() override { return parent_.dispatcher_; } void resetStream() override; Router::RouteConstSharedPtr route() override { return route_; } + Upstream::ClusterInfoConstSharedPtr clusterInfo() override { return parent_.cluster_; } void clearRouteCache() override {} uint64_t streamId() override { return stream_id_; } - RequestInfo::RequestInfo& requestInfo() override { return request_info_; } + StreamInfo::StreamInfo& streamInfo() override { return stream_info_; } Tracing::Span& activeSpan() override { return active_span_; } const Tracing::Config& tracingConfig() override { return tracing_config_; } void continueDecoding() override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } @@ -306,7 +315,7 @@ class AsyncStreamImpl : public AsyncClient::Stream, AsyncClient::StreamCallbacks& stream_callbacks_; const uint64_t stream_id_; Router::ProdFilter router_; - RequestInfo::RequestInfoImpl request_info_; + StreamInfo::StreamInfoImpl stream_info_; Tracing::NullSpan active_span_; const Tracing::Config& tracing_config_; std::shared_ptr route_; diff --git a/source/common/http/conn_manager_impl.cc b/source/common/http/conn_manager_impl.cc index 966be2858a38d..2c702ab713492 100644 --- a/source/common/http/conn_manager_impl.cc +++ b/source/common/http/conn_manager_impl.cc @@ -205,10 +205,10 @@ StreamDecoder& ConnectionManagerImpl::newStream(StreamEncoder& response_encoder) new_stream->response_encoder_ = &response_encoder; new_stream->response_encoder_->getStream().addCallbacks(*new_stream); new_stream->buffer_limit_ = new_stream->response_encoder_->getStream().bufferLimit(); - // Make sure new streams are apprised that the underlying connection is blocked. - if (read_callbacks_->connection().aboveHighWatermark()) { - new_stream->callHighWatermarkCallbacks(); - } + // If the network connection is backed up, the stream should be made aware of it on creation. + // Both HTTP/1.x and HTTP/2 codecs handle this in StreamCallbackHelper::addCallbacks_. + ASSERT(read_callbacks_->connection().aboveHighWatermark() == false || + new_stream->high_watermark_count_ > 0); new_stream->moveIntoList(std::move(new_stream), streams_); return **streams_.begin(); } @@ -372,7 +372,7 @@ ConnectionManagerImpl::ActiveStream::ActiveStream(ConnectionManagerImpl& connect stream_id_(connection_manager.random_generator_.random()), request_timer_(new Stats::Timespan(connection_manager_.stats_.named_.downstream_rq_time_, connection_manager_.timeSystem())), - request_info_(connection_manager_.codec_->protocol(), connection_manager_.timeSystem()) { + stream_info_(connection_manager_.codec_->protocol(), connection_manager_.timeSystem()) { connection_manager_.stats_.named_.downstream_rq_total_.inc(); connection_manager_.stats_.named_.downstream_rq_active_.inc(); if (connection_manager_.codec_->protocol() == Protocol::Http2) { @@ -380,13 +380,13 @@ ConnectionManagerImpl::ActiveStream::ActiveStream(ConnectionManagerImpl& connect } else { connection_manager_.stats_.named_.downstream_rq_http1_total_.inc(); } - request_info_.setDownstreamLocalAddress( + stream_info_.setDownstreamLocalAddress( connection_manager_.read_callbacks_->connection().localAddress()); // Initially, the downstream remote address is the source address of the // downstream connection. That can change later in the request's lifecycle, // based on XFF processing, but setting the downstream remote address here // prevents surprises for logging code in edge cases. - request_info_.setDownstreamRemoteAddress( + stream_info_.setDownstreamRemoteAddress( connection_manager_.read_callbacks_->connection().remoteAddress()); if (connection_manager_.config_.streamIdleTimeout().count()) { @@ -395,29 +395,29 @@ ConnectionManagerImpl::ActiveStream::ActiveStream(ConnectionManagerImpl& connect [this]() -> void { onIdleTimeout(); }); resetIdleTimer(); } - request_info_.setRequestedServerName( + stream_info_.setRequestedServerName( connection_manager_.read_callbacks_->connection().requestedServerName()); } ConnectionManagerImpl::ActiveStream::~ActiveStream() { - request_info_.onRequestComplete(); + stream_info_.onRequestComplete(); connection_manager_.stats_.named_.downstream_rq_active_.dec(); for (const AccessLog::InstanceSharedPtr& access_log : connection_manager_.config_.accessLogs()) { access_log->log(request_headers_.get(), response_headers_.get(), response_trailers_.get(), - request_info_); + stream_info_); } for (const auto& log_handler : access_log_handlers_) { log_handler->log(request_headers_.get(), response_headers_.get(), response_trailers_.get(), - request_info_); + stream_info_); } - if (request_info_.healthCheck()) { + if (stream_info_.healthCheck()) { connection_manager_.config_.tracingStats().health_check_.inc(); } if (active_span_) { - Tracing::HttpTracerUtility::finalizeSpan(*active_span_, request_headers_.get(), request_info_, + Tracing::HttpTracerUtility::finalizeSpan(*active_span_, request_headers_.get(), stream_info_, *this); } @@ -468,9 +468,9 @@ void ConnectionManagerImpl::ActiveStream::addAccessLogHandler( void ConnectionManagerImpl::ActiveStream::chargeStats(const HeaderMap& headers) { uint64_t response_code = Utility::getResponseStatus(headers); - request_info_.response_code_ = response_code; + stream_info_.response_code_ = response_code; - if (request_info_.hc_request_) { + if (stream_info_.hc_request_) { return; } @@ -541,7 +541,7 @@ void ConnectionManagerImpl::ActiveStream::decodeHeaders(HeaderMapPtr&& headers, // HTTP/1.1. // // The protocol may have shifted in the HTTP/1.0 case so reset it. - request_info_.protocol(protocol); + stream_info_.protocol(protocol); if (!connection_manager_.config_.http1Settings().accept_http_10_) { // Send "Upgrade Required" if HTTP/1.0 support is not explicitly configured on. sendLocalReply(false, Code::UpgradeRequired, "", nullptr, is_head_request_); @@ -606,11 +606,11 @@ void ConnectionManagerImpl::ActiveStream::decodeHeaders(HeaderMapPtr&& headers, } // Modify the downstream remote address depending on configuration and headers. - request_info_.setDownstreamRemoteAddress(ConnectionManagerUtility::mutateRequestHeaders( + stream_info_.setDownstreamRemoteAddress(ConnectionManagerUtility::mutateRequestHeaders( *request_headers_, connection_manager_.read_callbacks_->connection(), connection_manager_.config_, *snapped_route_config_, connection_manager_.random_generator_, connection_manager_.runtime_, connection_manager_.local_info_)); - ASSERT(request_info_.downstreamRemoteAddress() != nullptr); + ASSERT(stream_info_.downstreamRemoteAddress() != nullptr); ASSERT(!cached_route_); refreshCachedRoute(); @@ -628,7 +628,7 @@ void ConnectionManagerImpl::ActiveStream::decodeHeaders(HeaderMapPtr&& headers, ENVOY_STREAM_LOG(debug, "found websocket connection. (end_stream={}):", *this, end_stream); connection_manager_.ws_connection_ = route_entry->createWebSocketProxy( - *request_headers_, request_info_, *this, connection_manager_.cluster_manager_, + *request_headers_, stream_info_, *this, connection_manager_.cluster_manager_, connection_manager_.read_callbacks_); ASSERT(connection_manager_.ws_connection_ != nullptr); connection_manager_.stats_.named_.downstream_cx_websocket_active_.inc(); @@ -677,11 +677,11 @@ void ConnectionManagerImpl::ActiveStream::decodeHeaders(HeaderMapPtr&& headers, void ConnectionManagerImpl::ActiveStream::traceRequest() { Tracing::Decision tracing_decision = - Tracing::HttpTracerUtility::isTracing(request_info_, *request_headers_); + Tracing::HttpTracerUtility::isTracing(stream_info_, *request_headers_); ConnectionManagerImpl::chargeTracingStats(tracing_decision.reason, connection_manager_.config_.tracingStats()); - active_span_ = connection_manager_.tracer_.startSpan(*this, *request_headers_, request_info_, + active_span_ = connection_manager_.tracer_.startSpan(*this, *request_headers_, stream_info_, tracing_decision); if (!active_span_) { @@ -774,7 +774,7 @@ void ConnectionManagerImpl::ActiveStream::decodeHeaders(ActiveStreamDecoderFilte void ConnectionManagerImpl::ActiveStream::decodeData(Buffer::Instance& data, bool end_stream) { maybeEndDecode(end_stream); - request_info_.addBytesReceived(data.length()); + stream_info_.addBytesReceived(data.length()); // If the initial websocket upgrade request had an HTTP body // let's send this up @@ -916,7 +916,7 @@ void ConnectionManagerImpl::ActiveStream::maybeEndDecode(bool end_stream) { ASSERT(!state_.remote_complete_); state_.remote_complete_ = end_stream; if (end_stream) { - request_info_.onLastDownstreamRxByteReceived(); + stream_info_.onLastDownstreamRxByteReceived(); ENVOY_STREAM_LOG(debug, "request end stream", *this); } } @@ -949,8 +949,15 @@ void ConnectionManagerImpl::startDrainSequence() { void ConnectionManagerImpl::ActiveStream::refreshCachedRoute() { Router::RouteConstSharedPtr route = snapped_route_config_->route(*request_headers_, stream_id_); - request_info_.route_entry_ = route ? route->routeEntry() : nullptr; + stream_info_.route_entry_ = route ? route->routeEntry() : nullptr; cached_route_ = std::move(route); + if (nullptr == stream_info_.route_entry_) { + cached_cluster_info_ = nullptr; + } else { + Upstream::ThreadLocalCluster* local_cluster = + connection_manager_.cluster_manager_.get(stream_info_.route_entry_->clusterName()); + cached_cluster_info_ = (nullptr == local_cluster) ? nullptr : local_cluster->info(); + } } void ConnectionManagerImpl::ActiveStream::sendLocalReply( @@ -1121,7 +1128,7 @@ void ConnectionManagerImpl::ActiveStream::encodeHeaders(ActiveStreamEncoderFilte end_stream && continue_data_entry == encoder_filters_.end(), headers); // Now actually encode via the codec. - request_info_.onFirstDownstreamTxByteSent(); + stream_info_.onFirstDownstreamTxByteSent(); response_encoder_->encodeHeaders(headers, end_stream && continue_data_entry == encoder_filters_.end()); @@ -1207,7 +1214,7 @@ void ConnectionManagerImpl::ActiveStream::encodeData(ActiveStreamEncoderFilter* ENVOY_STREAM_LOG(trace, "encoding data via codec (size={} end_stream={})", *this, data.length(), end_stream); - request_info_.addBytesSent(data.length()); + stream_info_.addBytesSent(data.length()); // If trailers were adding during encodeData we need to trigger decodeTrailers in order // to allow filters to process the trailers. @@ -1244,7 +1251,7 @@ void ConnectionManagerImpl::ActiveStream::encodeTrailers(ActiveStreamEncoderFilt void ConnectionManagerImpl::ActiveStream::maybeEndEncode(bool end_stream) { if (end_stream) { - request_info_.onLastDownstreamTxByteSent(); + stream_info_.onLastDownstreamTxByteSent(); request_timer_->complete(); connection_manager_.doEndStream(*this); } @@ -1463,8 +1470,8 @@ Event::Dispatcher& ConnectionManagerImpl::ActiveStreamFilterBase::dispatcher() { return parent_.connection_manager_.read_callbacks_->connection().dispatcher(); } -RequestInfo::RequestInfo& ConnectionManagerImpl::ActiveStreamFilterBase::requestInfo() { - return parent_.request_info_; +StreamInfo::StreamInfo& ConnectionManagerImpl::ActiveStreamFilterBase::streamInfo() { + return parent_.stream_info_; } Tracing::Span& ConnectionManagerImpl::ActiveStreamFilterBase::activeSpan() { @@ -1477,8 +1484,17 @@ Tracing::Span& ConnectionManagerImpl::ActiveStreamFilterBase::activeSpan() { Tracing::Config& ConnectionManagerImpl::ActiveStreamFilterBase::tracingConfig() { return parent_; } +Upstream::ClusterInfoConstSharedPtr ConnectionManagerImpl::ActiveStreamFilterBase::clusterInfo() { + // NOTE: Refreshing route caches clusterInfo as well. + if (!parent_.cached_route_.has_value()) { + parent_.refreshCachedRoute(); + } + + return parent_.cached_cluster_info_.value(); +} + Router::RouteConstSharedPtr ConnectionManagerImpl::ActiveStreamFilterBase::route() { - if (!parent_.cached_route_) { + if (!parent_.cached_route_.has_value()) { parent_.refreshCachedRoute(); } @@ -1487,6 +1503,7 @@ Router::RouteConstSharedPtr ConnectionManagerImpl::ActiveStreamFilterBase::route void ConnectionManagerImpl::ActiveStreamFilterBase::clearRouteCache() { parent_.cached_route_ = absl::optional(); + parent_.cached_cluster_info_ = absl::optional(); } Buffer::WatermarkBufferPtr ConnectionManagerImpl::ActiveStreamDecoderFilter::createBuffer() { diff --git a/source/common/http/conn_manager_impl.h b/source/common/http/conn_manager_impl.h index 4846363e429ce..6106a119ac332 100644 --- a/source/common/http/conn_manager_impl.h +++ b/source/common/http/conn_manager_impl.h @@ -31,7 +31,7 @@ #include "common/http/conn_manager_config.h" #include "common/http/user_agent.h" #include "common/http/utility.h" -#include "common/request_info/request_info_impl.h" +#include "common/stream_info/stream_info_impl.h" #include "common/tracing/http_tracer_impl.h" namespace Envoy { @@ -120,9 +120,10 @@ class ConnectionManagerImpl : Logger::Loggable, Event::Dispatcher& dispatcher() override; void resetStream() override; Router::RouteConstSharedPtr route() override; + Upstream::ClusterInfoConstSharedPtr clusterInfo() override; void clearRouteCache() override; uint64_t streamId() override; - RequestInfo::RequestInfo& requestInfo() override; + StreamInfo::StreamInfo& streamInfo() override; Tracing::Span& activeSpan() override; Tracing::Config& tracingConfig() override; @@ -401,8 +402,9 @@ class ConnectionManagerImpl : Logger::Loggable, Event::TimerPtr idle_timer_; std::chrono::milliseconds idle_timeout_ms_{}; State state_; - RequestInfo::RequestInfoImpl request_info_; + StreamInfo::StreamInfoImpl stream_info_; absl::optional cached_route_; + absl::optional cached_cluster_info_; DownstreamWatermarkCallbacks* watermark_callbacks_{nullptr}; uint32_t buffer_limit_{0}; uint32_t high_watermark_count_{0}; diff --git a/source/common/http/conn_manager_utility.cc b/source/common/http/conn_manager_utility.cc index 5e0bf75222642..737b0eea54bd8 100644 --- a/source/common/http/conn_manager_utility.cc +++ b/source/common/http/conn_manager_utility.cc @@ -127,6 +127,7 @@ Network::Address::InstanceConstSharedPtr ConnectionManagerUtility::mutateRequest request_headers.removeEnvoyDownstreamServiceNode(); } + request_headers.removeEnvoyRetriableStatusCodes(); request_headers.removeEnvoyRetryOn(); request_headers.removeEnvoyRetryGrpcOn(); request_headers.removeEnvoyMaxRetries(); diff --git a/source/common/http/headers.h b/source/common/http/headers.h index abe23615dfa23..feff15b32a0ef 100644 --- a/source/common/http/headers.h +++ b/source/common/http/headers.h @@ -33,6 +33,7 @@ class HeaderValues { const LowerCaseString ContentType{"content-type"}; const LowerCaseString Cookie{"cookie"}; const LowerCaseString Date{"date"}; + const LowerCaseString EnvoyAttemptCount{"x-envoy-attempt-count"}; const LowerCaseString EnvoyDownstreamServiceCluster{"x-envoy-downstream-service-cluster"}; const LowerCaseString EnvoyDownstreamServiceNode{"x-envoy-downstream-service-node"}; const LowerCaseString EnvoyExternalAddress{"x-envoy-external-address"}; @@ -46,6 +47,7 @@ class HeaderValues { const LowerCaseString EnvoyOverloaded{"x-envoy-overloaded"}; const LowerCaseString EnvoyRetryOn{"x-envoy-retry-on"}; const LowerCaseString EnvoyRetryGrpcOn{"x-envoy-retry-grpc-on"}; + const LowerCaseString EnvoyRetriableStatusCodes{"x-envoy-retriable-status-codes"}; const LowerCaseString EnvoyUpstreamAltStatName{"x-envoy-upstream-alt-stat-name"}; const LowerCaseString EnvoyUpstreamCanary{"x-envoy-upstream-canary"}; const LowerCaseString EnvoyUpstreamRequestTimeoutAltResponse{ @@ -145,6 +147,7 @@ class HeaderValues { const std::string ConnectFailure{"connect-failure"}; const std::string RefusedStream{"refused-stream"}; const std::string Retriable4xx{"retriable-4xx"}; + const std::string RetriableStatusCodes{"retriable-status-codes"}; } EnvoyRetryOnValues; struct { @@ -152,6 +155,7 @@ class HeaderValues { const std::string DeadlineExceeded{"deadline-exceeded"}; const std::string ResourceExhausted{"resource-exhausted"}; const std::string Unavailable{"unavailable"}; + const std::string Internal{"internal"}; } EnvoyRetryOnGrpcValues; struct { diff --git a/source/common/http/http1/codec_impl.cc b/source/common/http/http1/codec_impl.cc index 24d9d6d49c3e1..89c34500e551b 100644 --- a/source/common/http/http1/codec_impl.cc +++ b/source/common/http/http1/codec_impl.cc @@ -21,6 +21,12 @@ namespace Http1 { const std::string StreamEncoderImpl::CRLF = "\r\n"; const std::string StreamEncoderImpl::LAST_CHUNK = "0\r\n\r\n"; +StreamEncoderImpl::StreamEncoderImpl(ConnectionImpl& connection) : connection_(connection) { + if (connection_.connection().aboveHighWatermark()) { + runHighWatermarkCallbacks(); + } +} + void StreamEncoderImpl::encodeHeader(const char* key, uint32_t key_size, const char* value, uint32_t value_size) { diff --git a/source/common/http/http1/codec_impl.h b/source/common/http/http1/codec_impl.h index c3ac78cab1433..272dfd2ee2d17 100644 --- a/source/common/http/http1/codec_impl.h +++ b/source/common/http/http1/codec_impl.h @@ -49,7 +49,7 @@ class StreamEncoderImpl : public StreamEncoder, void isResponseToHeadRequest(bool value) { is_response_to_head_request_ = value; } protected: - StreamEncoderImpl(ConnectionImpl& connection) : connection_(connection) {} + StreamEncoderImpl(ConnectionImpl& connection); static const std::string CRLF; static const std::string LAST_CHUNK; diff --git a/source/common/http/utility.cc b/source/common/http/utility.cc index 58e2c3c05ac3f..61ce7ef594863 100644 --- a/source/common/http/utility.cc +++ b/source/common/http/utility.cc @@ -30,14 +30,9 @@ void Utility::appendXff(HeaderMap& headers, const Network::Address::Instance& re return; } - // TODO(alyssawilk) move over to the append utility. HeaderString& header = headers.insertForwardedFor().value(); - if (!header.empty()) { - header.append(", ", 2); - } - const std::string& address_as_string = remote_address.ip()->addressAsString(); - header.append(address_as_string.c_str(), address_as_string.size()); + HeaderMapImpl::appendToHeader(header, address_as_string.c_str()); } void Utility::appendVia(HeaderMap& headers, const std::string& via) { diff --git a/source/common/http/websocket/ws_handler_impl.cc b/source/common/http/websocket/ws_handler_impl.cc index 025c7c28d4178..4b444ceabd3c1 100644 --- a/source/common/http/websocket/ws_handler_impl.cc +++ b/source/common/http/websocket/ws_handler_impl.cc @@ -42,14 +42,14 @@ TcpProxy::ConfigSharedPtr Config(const envoy::api::v2::route::RouteAction& route return std::make_shared(tcp_config, factory_context); } -WsHandlerImpl::WsHandlerImpl(HeaderMap& request_headers, RequestInfo::RequestInfo& request_info, +WsHandlerImpl::WsHandlerImpl(HeaderMap& request_headers, StreamInfo::StreamInfo& stream_info, const Router::RouteEntry& route_entry, WebSocketProxyCallbacks& callbacks, Upstream::ClusterManager& cluster_manager, Network::ReadFilterCallbacks* read_callbacks, TcpProxy::ConfigSharedPtr config, Event::TimeSystem& time_system) : TcpProxy::Filter(config, cluster_manager, time_system), request_headers_(request_headers), - request_info_(request_info), route_entry_(route_entry), ws_callbacks_(callbacks) { + stream_info_(stream_info), route_entry_(route_entry), ws_callbacks_(callbacks) { // set_connection_stats == false because the http connection manager has already set them // and they will be inaccurate if we change them now. @@ -108,7 +108,7 @@ Network::FilterStatus WsHandlerImpl::onData(Buffer::Instance& data, bool end_str void WsHandlerImpl::onConnectionSuccess() { // path and host rewrites - route_entry_.finalizeRequestHeaders(request_headers_, request_info_, true); + route_entry_.finalizeRequestHeaders(request_headers_, stream_info_, true); // for auto host rewrite if (route_entry_.autoHostRewrite() && !read_callbacks_->upstreamHost()->hostname().empty()) { request_headers_.Host()->value(read_callbacks_->upstreamHost()->hostname()); @@ -144,7 +144,7 @@ void WsHandlerImpl::onConnectionSuccess() { } } -RequestInfo::RequestInfo& WsHandlerImpl::getRequestInfo() { return request_info_; } +StreamInfo::StreamInfo& WsHandlerImpl::getStreamInfo() { return stream_info_; } } // namespace WebSocket } // namespace Http diff --git a/source/common/http/websocket/ws_handler_impl.h b/source/common/http/websocket/ws_handler_impl.h index 51feae71ca2d8..31d3c60e39d6a 100644 --- a/source/common/http/websocket/ws_handler_impl.h +++ b/source/common/http/websocket/ws_handler_impl.h @@ -32,7 +32,7 @@ TcpProxy::ConfigSharedPtr Config(const envoy::api::v2::route::RouteAction& route */ class WsHandlerImpl : public TcpProxy::Filter, public Http::WebSocketProxy { public: - WsHandlerImpl(HeaderMap& request_headers, RequestInfo::RequestInfo& request_info, + WsHandlerImpl(HeaderMap& request_headers, StreamInfo::StreamInfo& stream_info, const Router::RouteEntry& route_entry, WebSocketProxyCallbacks& callbacks, Upstream::ClusterManager& cluster_manager, Network::ReadFilterCallbacks* read_callbacks, TcpProxy::ConfigSharedPtr config, @@ -51,7 +51,7 @@ class WsHandlerImpl : public TcpProxy::Filter, public Http::WebSocketProxy { const std::string& getUpstreamCluster() override { return route_entry_.clusterName(); } void onInitFailure(UpstreamFailureReason failure_reason) override; void onConnectionSuccess() override; - RequestInfo::RequestInfo& getRequestInfo() override; + StreamInfo::StreamInfo& getStreamInfo() override; private: struct NullHttpConnectionCallbacks : public ConnectionCallbacks { @@ -62,7 +62,7 @@ class WsHandlerImpl : public TcpProxy::Filter, public Http::WebSocketProxy { enum class ConnectState { PreConnect, Connected, Failed }; HeaderMap& request_headers_; - RequestInfo::RequestInfo& request_info_; + StreamInfo::StreamInfo& stream_info_; const Router::RouteEntry& route_entry_; WebSocketProxyCallbacks& ws_callbacks_; NullHttpConnectionCallbacks http_conn_callbacks_; diff --git a/source/common/network/BUILD b/source/common/network/BUILD index b94beebe8667e..8f55e997a6345 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -58,8 +58,8 @@ envoy_cc_library( "//source/common/common:minimal_logger_lib", "//source/common/event:libevent_lib", "//source/common/network:listen_socket_lib", - "//source/common/request_info:filter_state_lib", "//source/common/ssl:ssl_socket_lib", + "//source/common/stream_info:filter_state_lib", ], ) diff --git a/source/common/network/connection_impl.cc b/source/common/network/connection_impl.cc index e89a00bace5df..28b751366c375 100644 --- a/source/common/network/connection_impl.cc +++ b/source/common/network/connection_impl.cc @@ -68,12 +68,8 @@ ConnectionImpl::ConnectionImpl(Event::Dispatcher& dispatcher, ConnectionSocketPt } ConnectionImpl::~ConnectionImpl() { - ASSERT(fd() == -1, "ConnectionImpl was unexpectedly torn down without being closed."); - - if (delayed_close_timer_) { - // It's ok to disable even if the timer has already fired. - delayed_close_timer_->disableTimer(); - } + ASSERT(fd() == -1 && delayed_close_timer_ == nullptr, + "ConnectionImpl was unexpectedly torn down without being closed."); // In general we assume that owning code has called close() previously to the destructor being // run. This generally must be done so that callbacks run in the correct context (vs. deferred @@ -176,6 +172,12 @@ void ConnectionImpl::closeSocket(ConnectionEvent close_type) { return; } + // No need for a delayed close (if pending) now that the socket is being closed. + if (delayed_close_timer_) { + delayed_close_timer_->disableTimer(); + delayed_close_timer_ = nullptr; + } + ENVOY_CONN_LOG(debug, "closing socket: {}", *this, static_cast(close_type)); transport_socket_->closeSocket(close_type); @@ -583,7 +585,7 @@ bool ConnectionImpl::bothSidesHalfClosed() { void ConnectionImpl::onDelayedCloseTimeout() { ENVOY_CONN_LOG(debug, "triggered delayed close", *this); - if (connection_stats_->delayed_close_timeouts_ != nullptr) { + if (connection_stats_ != nullptr && connection_stats_->delayed_close_timeouts_ != nullptr) { connection_stats_->delayed_close_timeouts_->inc(); } closeSocket(ConnectionEvent::LocalClose); diff --git a/source/common/network/connection_impl.h b/source/common/network/connection_impl.h index 7f1fb01b9bc4e..b9f07c69f1a3f 100644 --- a/source/common/network/connection_impl.h +++ b/source/common/network/connection_impl.h @@ -14,12 +14,14 @@ #include "common/common/logger.h" #include "common/event/libevent.h" #include "common/network/filter_manager_impl.h" -#include "common/request_info/filter_state_impl.h" #include "common/ssl/ssl_socket.h" +#include "common/stream_info/filter_state_impl.h" #include "absl/types/optional.h" namespace Envoy { +class TestPauseFilter; + namespace Network { /** @@ -90,8 +92,8 @@ class ConnectionImpl : public virtual Connection, return socket_->options(); } absl::string_view requestedServerName() const override { return socket_->requestedServerName(); } - RequestInfo::FilterState& perConnectionState() override { return per_connection_state_; } - const RequestInfo::FilterState& perConnectionState() const override { + StreamInfo::FilterState& perConnectionState() override { return per_connection_state_; } + const StreamInfo::FilterState& perConnectionState() const override { return per_connection_state_; } @@ -133,7 +135,7 @@ class ConnectionImpl : public virtual Connection, TransportSocketPtr transport_socket_; FilterManagerImpl filter_manager_; ConnectionSocketPtr socket_; - RequestInfo::FilterStateImpl per_connection_state_; + StreamInfo::FilterStateImpl per_connection_state_; Buffer::OwnedImpl read_buffer_; // This must be a WatermarkBuffer, but as it is created by a factory the ConnectionImpl only has @@ -149,6 +151,8 @@ class ConnectionImpl : public virtual Connection, Event::FileEventPtr file_event_; private: + friend class ::Envoy::TestPauseFilter; + void onFileEvent(uint32_t events); void onRead(uint64_t read_buffer_size); void onReadReady(); diff --git a/source/common/network/listener_impl.cc b/source/common/network/listener_impl.cc index f22bc313648c1..8769f1625f4d7 100644 --- a/source/common/network/listener_impl.cc +++ b/source/common/network/listener_impl.cc @@ -82,5 +82,17 @@ void ListenerImpl::errorCallback(evconnlistener*, void*) { PANIC(fmt::format("listener accept failure: {}", strerror(errno))); } +void ListenerImpl::enable() { + if (listener_.get()) { + evconnlistener_enable(listener_.get()); + } +} + +void ListenerImpl::disable() { + if (listener_.get()) { + evconnlistener_disable(listener_.get()); + } +} + } // namespace Network } // namespace Envoy diff --git a/source/common/network/listener_impl.h b/source/common/network/listener_impl.h index d55ccfc623bd3..26dff27ce24f7 100644 --- a/source/common/network/listener_impl.h +++ b/source/common/network/listener_impl.h @@ -19,6 +19,9 @@ class ListenerImpl : public Listener { ListenerImpl(Event::DispatcherImpl& dispatcher, Socket& socket, ListenerCallbacks& cb, bool bind_to_port, bool hand_off_restored_destination_connections); + void disable(); + void enable(); + protected: virtual Address::InstanceConstSharedPtr getLocalAddress(int fd); diff --git a/source/common/protobuf/utility.cc b/source/common/protobuf/utility.cc index b2b5b82faeaad..d8a3ab138f509 100644 --- a/source/common/protobuf/utility.cc +++ b/source/common/protobuf/utility.cc @@ -20,8 +20,9 @@ uint64_t convertPercent(double percent, uint64_t max_value) { return max_value * (percent / 100.0); } -uint64_t fractionalPercentDenominatorToInt(const envoy::type::FractionalPercent& percent) { - switch (percent.denominator()) { +uint64_t fractionalPercentDenominatorToInt( + const envoy::type::FractionalPercent::DenominatorType& denominator) { + switch (denominator) { case envoy::type::FractionalPercent::HUNDRED: return 100; case envoy::type::FractionalPercent::TEN_THOUSAND: diff --git a/source/common/protobuf/utility.h b/source/common/protobuf/utility.h index b615010f3c000..7dcdddb24c48c 100644 --- a/source/common/protobuf/utility.h +++ b/source/common/protobuf/utility.h @@ -48,16 +48,6 @@ ((message).has_##field_name() ? DurationUtil::durationToSeconds((message).field_name()) \ : throw MissingFieldException(#field_name, (message))) -// Set the value of a FractionalPercent field with the value from a protobuf message if present. -// Otherwise, convert the default field value into FractionalPercent and set it. -#define PROTOBUF_SET_FRACTIONAL_PERCENT_OR_DEFAULT(field, message, field_name, default_field_name) \ - if ((message).has_##field_name()) { \ - field = (message).field_name(); \ - } else { \ - field.set_numerator((message).default_field_name()); \ - field.set_denominator(envoy::type::FractionalPercent::HUNDRED); \ - } - namespace Envoy { namespace ProtobufPercentHelper { @@ -68,10 +58,11 @@ uint64_t convertPercent(double percent, uint64_t max_value); /** * Convert a fractional percent denominator enum into an integer. - * @param percent supplies percent to convert. + * @param denominator supplies denominator to convert. * @return the converted denominator. */ -uint64_t fractionalPercentDenominatorToInt(const envoy::type::FractionalPercent& percent); +uint64_t fractionalPercentDenominatorToInt( + const envoy::type::FractionalPercent::DenominatorType& denominator); } // namespace ProtobufPercentHelper } // namespace Envoy diff --git a/source/common/router/BUILD b/source/common/router/BUILD index 4d23ffff69507..4e97e63cee223 100644 --- a/source/common/router/BUILD +++ b/source/common/router/BUILD @@ -173,7 +173,7 @@ envoy_cc_library( "//source/common/http:headers_lib", "//source/common/http:message_lib", "//source/common/http:utility_lib", - "//source/common/request_info:request_info_lib", + "//source/common/stream_info:stream_info_lib", "//source/common/tracing:http_tracer_lib", "@envoy_api//envoy/config/filter/http/router/v2:router_cc", ], @@ -226,9 +226,9 @@ envoy_cc_library( hdrs = ["header_formatter.h"], external_deps = ["abseil_optional"], deps = [ - "//include/envoy/request_info:filter_state_interface", - "//include/envoy/request_info:request_info_interface", "//include/envoy/router:string_accessor_interface", + "//include/envoy/stream_info:filter_state_interface", + "//include/envoy/stream_info:stream_info_interface", "//source/common/access_log:access_log_formatter_lib", "//source/common/common:minimal_logger_lib", "//source/common/common:utility_lib", diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index 8324948be4706..d6347fdf70f66 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -11,6 +11,7 @@ #include "envoy/http/header_map.h" #include "envoy/runtime/runtime.h" +#include "envoy/type/percent.pb.validate.h" #include "envoy/upstream/cluster_manager.h" #include "envoy/upstream/upstream.h" @@ -18,6 +19,7 @@ #include "common/common/empty_string.h" #include "common/common/fmt.h" #include "common/common/hash.h" +#include "common/common/logger.h" #include "common/common/utility.h" #include "common/config/metadata.h" #include "common/config/rds_json.h" @@ -26,6 +28,7 @@ #include "common/http/headers.h" #include "common/http/utility.h" #include "common/http/websocket/ws_handler_impl.h" +#include "common/protobuf/protobuf.h" #include "common/protobuf/utility.h" #include "common/router/retry_state_impl.h" @@ -43,28 +46,39 @@ RetryPolicyImpl::RetryPolicyImpl(const envoy::api::v2::route::RouteAction& confi return; } - per_try_timeout_ = std::chrono::milliseconds( - PROTOBUF_GET_MS_OR_DEFAULT(config.retry_policy(), per_try_timeout, 0)); - num_retries_ = PROTOBUF_GET_WRAPPED_OR_DEFAULT(config.retry_policy(), num_retries, 1); - retry_on_ = RetryStateImpl::parseRetryOn(config.retry_policy().retry_on()); - retry_on_ |= RetryStateImpl::parseRetryGrpcOn(config.retry_policy().retry_on()); + const auto& retry_policy = config.retry_policy(); + per_try_timeout_ = + std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(retry_policy, per_try_timeout, 0)); + num_retries_ = PROTOBUF_GET_WRAPPED_OR_DEFAULT(retry_policy, num_retries, 1); + retry_on_ = RetryStateImpl::parseRetryOn(retry_policy.retry_on()); + retry_on_ |= RetryStateImpl::parseRetryGrpcOn(retry_policy.retry_on()); - for (const auto& host_predicate : config.retry_policy().retry_host_predicate()) { - Registry::FactoryRegistry::getFactory( - host_predicate.name()) - ->createHostPredicate(*this, host_predicate.config(), num_retries_); + for (const auto& host_predicate : retry_policy.retry_host_predicate()) { + auto& factory = + ::Envoy::Config::Utility::getAndCheckFactory( + host_predicate.name()); + + auto config = ::Envoy::Config::Utility::translateToFactoryConfig(host_predicate, factory); + factory.createHostPredicate(*this, *config, num_retries_); } - const auto retry_priority = config.retry_policy().retry_priority(); + const auto retry_priority = retry_policy.retry_priority(); if (!retry_priority.name().empty()) { - Registry::FactoryRegistry::getFactory(retry_priority.name()) - ->createRetryPriority(*this, retry_priority.config(), num_retries_); + auto& factory = ::Envoy::Config::Utility::getAndCheckFactory( + retry_priority.name()); + + auto config = ::Envoy::Config::Utility::translateToFactoryConfig(retry_priority, factory); + factory.createRetryPriority(*this, *config, num_retries_); } - auto host_selection_attempts = config.retry_policy().host_selection_retry_max_attempts(); + auto host_selection_attempts = retry_policy.host_selection_retry_max_attempts(); if (host_selection_attempts) { host_selection_attempts_ = host_selection_attempts; } + + for (auto code : retry_policy.retriable_status_codes()) { + retriable_status_codes_.emplace_back(code); + } } CorsPolicyImpl::CorsPolicyImpl(const envoy::api::v2::route::CorsPolicy& config) { @@ -258,7 +272,7 @@ RouteEntryImplBase::RouteEntryImplBase(const VirtualHostImpl& vhost, timeout_(PROTOBUF_GET_MS_OR_DEFAULT(route.route(), timeout, DEFAULT_ROUTE_TIMEOUT_MS)), idle_timeout_(PROTOBUF_GET_OPTIONAL_MS(route.route(), idle_timeout)), max_grpc_timeout_(PROTOBUF_GET_OPTIONAL_MS(route.route(), max_grpc_timeout)), - runtime_(loadRuntimeData(route.match())), loader_(factory_context.runtime()), + loader_(factory_context.runtime()), runtime_(loadRuntimeData(route.match())), host_redirect_(route.redirect().host_redirect()), path_redirect_(route.redirect().path_redirect()), https_redirect_(route.redirect().https_redirect()), @@ -346,8 +360,11 @@ bool RouteEntryImplBase::matchRoute(const Http::HeaderMap& headers, uint64_t ran bool matches = true; if (runtime_) { - matches &= loader_.snapshot().featureEnabled(runtime_.value().key_, runtime_.value().default_, - random_value); + matches &= random_value % runtime_->denominator_val_ < runtime_->numerator_val_; + if (!matches) { + // No need to waste further cycles calculating a route match. + return false; + } } if (match_grpc_) { @@ -367,24 +384,24 @@ bool RouteEntryImplBase::matchRoute(const Http::HeaderMap& headers, uint64_t ran const std::string& RouteEntryImplBase::clusterName() const { return cluster_name_; } Http::WebSocketProxyPtr RouteEntryImplBase::createWebSocketProxy( - Http::HeaderMap& request_headers, RequestInfo::RequestInfo& request_info, + Http::HeaderMap& request_headers, StreamInfo::StreamInfo& stream_info, Http::WebSocketProxyCallbacks& callbacks, Upstream::ClusterManager& cluster_manager, Network::ReadFilterCallbacks* read_callbacks) const { return std::make_unique( - request_headers, request_info, *this, callbacks, cluster_manager, read_callbacks, + request_headers, stream_info, *this, callbacks, cluster_manager, read_callbacks, websocket_config_, time_system_); } void RouteEntryImplBase::finalizeRequestHeaders(Http::HeaderMap& headers, - const RequestInfo::RequestInfo& request_info, + const StreamInfo::StreamInfo& stream_info, bool insert_envoy_original_path) const { // Append user-specified request headers in the following order: route-action-level headers, // route-level headers, virtual host level headers and finally global connection manager level // headers. - route_action_request_headers_parser_->evaluateHeaders(headers, request_info); - request_headers_parser_->evaluateHeaders(headers, request_info); - vhost_.requestHeaderParser().evaluateHeaders(headers, request_info); - vhost_.globalRouteConfig().requestHeaderParser().evaluateHeaders(headers, request_info); + route_action_request_headers_parser_->evaluateHeaders(headers, stream_info); + request_headers_parser_->evaluateHeaders(headers, stream_info); + vhost_.requestHeaderParser().evaluateHeaders(headers, stream_info); + vhost_.globalRouteConfig().requestHeaderParser().evaluateHeaders(headers, stream_info); if (!host_rewrite_.empty()) { headers.Host()->value(host_rewrite_); } @@ -395,28 +412,50 @@ void RouteEntryImplBase::finalizeRequestHeaders(Http::HeaderMap& headers, } } -void RouteEntryImplBase::finalizeResponseHeaders( - Http::HeaderMap& headers, const RequestInfo::RequestInfo& request_info) const { +void RouteEntryImplBase::finalizeResponseHeaders(Http::HeaderMap& headers, + const StreamInfo::StreamInfo& stream_info) const { // Append user-specified response headers in the following order: route-action-level headers, // route-level headers, virtual host level headers and finally global connection manager level // headers. - route_action_response_headers_parser_->evaluateHeaders(headers, request_info); - response_headers_parser_->evaluateHeaders(headers, request_info); - vhost_.responseHeaderParser().evaluateHeaders(headers, request_info); - vhost_.globalRouteConfig().responseHeaderParser().evaluateHeaders(headers, request_info); + route_action_response_headers_parser_->evaluateHeaders(headers, stream_info); + response_headers_parser_->evaluateHeaders(headers, stream_info); + vhost_.responseHeaderParser().evaluateHeaders(headers, stream_info); + vhost_.globalRouteConfig().responseHeaderParser().evaluateHeaders(headers, stream_info); } absl::optional RouteEntryImplBase::loadRuntimeData(const envoy::api::v2::route::RouteMatch& route_match) { absl::optional runtime; - if (route_match.has_runtime()) { - RuntimeData data; - data.key_ = route_match.runtime().runtime_key(); - data.default_ = route_match.runtime().default_value(); - runtime = data; + RuntimeData runtime_data; + + if (route_match.runtime_specifier_case() == envoy::api::v2::route::RouteMatch::kRuntimeFraction) { + envoy::type::FractionalPercent fractional_percent; + const std::string& fraction_yaml = + loader_.snapshot().get(route_match.runtime_fraction().runtime_key()); + + try { + MessageUtil::loadFromYamlAndValidate(fraction_yaml, fractional_percent); + } catch (const EnvoyException& ex) { + ENVOY_LOG(error, "failed to parse string value for runtime key {}: {}", + route_match.runtime_fraction().runtime_key(), ex.what()); + fractional_percent = route_match.runtime_fraction().default_value(); + } + + runtime_data.numerator_val_ = fractional_percent.numerator(); + runtime_data.denominator_val_ = + ProtobufPercentHelper::fractionalPercentDenominatorToInt(fractional_percent.denominator()); + } else if (route_match.runtime_specifier_case() == envoy::api::v2::route::RouteMatch::kRuntime) { + // For backwards compatibility, the deprecated 'runtime' field must be converted to a + // RuntimeData format with a variable denominator type. The 'runtime' field assumes a percentage + // (0-100), so the hard-coded denominator value reflects this. + runtime_data.denominator_val_ = 100; + runtime_data.numerator_val_ = loader_.snapshot().getInteger( + route_match.runtime().runtime_key(), route_match.runtime().default_value()); + } else { + return runtime; } - return runtime; + return runtime_data; } void RouteEntryImplBase::finalizePathHeader(Http::HeaderMap& headers, @@ -703,7 +742,8 @@ VirtualHostImpl::VirtualHostImpl(const envoy::api::v2::route::VirtualHost& virtu virtual_host.request_headers_to_remove())), response_headers_parser_(HeaderParser::configure(virtual_host.response_headers_to_add(), virtual_host.response_headers_to_remove())), - per_filter_configs_(virtual_host.per_filter_config(), factory_context) { + per_filter_configs_(virtual_host.per_filter_config(), factory_context), + include_attempt_count_(virtual_host.include_request_attempt_count()) { switch (virtual_host.require_tls()) { case envoy::api::v2::route::VirtualHost::NONE: ssl_requirements_ = SslRequirements::NONE; diff --git a/source/common/router/config_impl.h b/source/common/router/config_impl.h index ce17b763ca014..e7ce350f64648 100644 --- a/source/common/router/config_impl.h +++ b/source/common/router/config_impl.h @@ -68,7 +68,7 @@ typedef std::shared_ptr RouteEntryImplBaseConstSharedP class SslRedirector : public DirectResponseEntry { public: // Router::DirectResponseEntry - void finalizeResponseHeaders(Http::HeaderMap&, const RequestInfo::RequestInfo&) const override {} + void finalizeResponseHeaders(Http::HeaderMap&, const StreamInfo::StreamInfo&) const override {} std::string newPath(const Http::HeaderMap& headers) const override; void rewritePathHeader(Http::HeaderMap&, bool) const override {} Http::Code responseCode() const override { return Http::Code::MovedPermanently; } @@ -140,6 +140,7 @@ class VirtualHostImpl : public VirtualHost { const RateLimitPolicy& rateLimitPolicy() const override { return rate_limit_policy_; } const Config& routeConfig() const override; const RouteSpecificFilterConfig* perFilterConfig(const std::string&) const override; + bool includeAttemptCount() const override { return include_attempt_count_; } private: enum class SslRequirements { NONE, EXTERNAL_ONLY, ALL }; @@ -176,6 +177,7 @@ class VirtualHostImpl : public VirtualHost { HeaderParserPtr request_headers_parser_; HeaderParserPtr response_headers_parser_; PerFilterConfigs per_filter_configs_; + const bool include_attempt_count_; }; typedef std::shared_ptr VirtualHostSharedPtr; @@ -198,6 +200,9 @@ class RetryPolicyImpl : public RetryPolicy, } Upstream::RetryPrioritySharedPtr retryPriority() const override { return retry_priority_; } uint32_t hostSelectionMaxAttempts() const override { return host_selection_attempts_; } + const std::vector& retriableStatusCodes() const override { + return retriable_status_codes_; + } // Upstream::RetryHostPredicateFactoryCallbacks void addHostPredicate(Upstream::RetryHostPredicateSharedPtr predicate) override { @@ -217,6 +222,7 @@ class RetryPolicyImpl : public RetryPolicy, std::vector retry_host_predicates_; Upstream::RetryPrioritySharedPtr retry_priority_; uint32_t host_selection_attempts_{1}; + std::vector retriable_status_codes_; }; /** @@ -291,7 +297,8 @@ class RouteEntryImplBase : public RouteEntry, public DirectResponseEntry, public Route, public PathMatchCriterion, - public std::enable_shared_from_this { + public std::enable_shared_from_this, + Logger::Loggable { public: /** * @throw EnvoyException with reason if the route configuration contains any errors @@ -317,11 +324,10 @@ class RouteEntryImplBase : public RouteEntry, return cluster_not_found_response_code_; } const CorsPolicy* corsPolicy() const override { return cors_policy_.get(); } - void finalizeRequestHeaders(Http::HeaderMap& headers, - const RequestInfo::RequestInfo& request_info, + void finalizeRequestHeaders(Http::HeaderMap& headers, const StreamInfo::StreamInfo& stream_info, bool insert_envoy_original_path) const override; void finalizeResponseHeaders(Http::HeaderMap& headers, - const RequestInfo::RequestInfo& request_info) const override; + const StreamInfo::StreamInfo& stream_info) const override; const HashPolicy* hashPolicy() const override { return hash_policy_.get(); } const MetadataMatchCriteria* metadataMatchCriteria() const override { @@ -343,7 +349,7 @@ class RouteEntryImplBase : public RouteEntry, bool autoHostRewrite() const override { return auto_host_rewrite_; } bool useOldStyleWebSocket() const override { return websocket_config_ != nullptr; } Http::WebSocketProxyPtr - createWebSocketProxy(Http::HeaderMap& request_headers, RequestInfo::RequestInfo& request_info, + createWebSocketProxy(Http::HeaderMap& request_headers, StreamInfo::StreamInfo& stream_info, Http::WebSocketProxyCallbacks& callbacks, Upstream::ClusterManager& cluster_manager, Network::ReadFilterCallbacks* read_callbacks) const override; @@ -353,6 +359,7 @@ class RouteEntryImplBase : public RouteEntry, bool includeVirtualHostRateLimits() const override { return include_vh_rate_limits_; } const envoy::api::v2::core::Metadata& metadata() const override { return metadata_; } const PathMatchCriterion& pathMatchCriterion() const override { return *this; } + bool includeAttemptCount() const override { return vhost_.includeAttemptCount(); } // Router::DirectResponseEntry std::string newPath(const Http::HeaderMap& headers) const override; @@ -386,8 +393,8 @@ class RouteEntryImplBase : public RouteEntry, private: struct RuntimeData { - std::string key_{}; - uint64_t default_{}; + uint64_t numerator_val_{}; + uint64_t denominator_val_{}; }; class DynamicRouteEntry : public RouteEntry, public Route { @@ -401,14 +408,13 @@ class RouteEntryImplBase : public RouteEntry, return parent_->clusterNotFoundResponseCode(); } - void finalizeRequestHeaders(Http::HeaderMap& headers, - const RequestInfo::RequestInfo& request_info, + void finalizeRequestHeaders(Http::HeaderMap& headers, const StreamInfo::StreamInfo& stream_info, bool insert_envoy_original_path) const override { - return parent_->finalizeRequestHeaders(headers, request_info, insert_envoy_original_path); + return parent_->finalizeRequestHeaders(headers, stream_info, insert_envoy_original_path); } void finalizeResponseHeaders(Http::HeaderMap& headers, - const RequestInfo::RequestInfo& request_info) const override { - return parent_->finalizeResponseHeaders(headers, request_info); + const StreamInfo::StreamInfo& stream_info) const override { + return parent_->finalizeResponseHeaders(headers, stream_info); } const CorsPolicy* corsPolicy() const override { return parent_->corsPolicy(); } @@ -440,12 +446,12 @@ class RouteEntryImplBase : public RouteEntry, bool autoHostRewrite() const override { return parent_->autoHostRewrite(); } bool useOldStyleWebSocket() const override { return parent_->useOldStyleWebSocket(); } Http::WebSocketProxyPtr - createWebSocketProxy(Http::HeaderMap& request_headers, RequestInfo::RequestInfo& request_info, + createWebSocketProxy(Http::HeaderMap& request_headers, StreamInfo::StreamInfo& stream_info, Http::WebSocketProxyCallbacks& callbacks, Upstream::ClusterManager& cluster_manager, Network::ReadFilterCallbacks* read_callbacks) const override { - return parent_->createWebSocketProxy(request_headers, request_info, callbacks, - cluster_manager, read_callbacks); + return parent_->createWebSocketProxy(request_headers, stream_info, callbacks, cluster_manager, + read_callbacks); } bool includeVirtualHostRateLimits() const override { return parent_->includeVirtualHostRateLimits(); @@ -455,6 +461,8 @@ class RouteEntryImplBase : public RouteEntry, return parent_->pathMatchCriterion(); } + bool includeAttemptCount() const override { return parent_->includeAttemptCount(); } + // Router::Route const DirectResponseEntry* directResponseEntry() const override { return nullptr; } const RouteEntry* routeEntry() const override { return this; } @@ -492,16 +500,15 @@ class RouteEntryImplBase : public RouteEntry, return DynamicRouteEntry::metadataMatchCriteria(); } - void finalizeRequestHeaders(Http::HeaderMap& headers, - const RequestInfo::RequestInfo& request_info, + void finalizeRequestHeaders(Http::HeaderMap& headers, const StreamInfo::StreamInfo& stream_info, bool insert_envoy_original_path) const override { - request_headers_parser_->evaluateHeaders(headers, request_info); - DynamicRouteEntry::finalizeRequestHeaders(headers, request_info, insert_envoy_original_path); + request_headers_parser_->evaluateHeaders(headers, stream_info); + DynamicRouteEntry::finalizeRequestHeaders(headers, stream_info, insert_envoy_original_path); } void finalizeResponseHeaders(Http::HeaderMap& headers, - const RequestInfo::RequestInfo& request_info) const override { - response_headers_parser_->evaluateHeaders(headers, request_info); - DynamicRouteEntry::finalizeResponseHeaders(headers, request_info); + const StreamInfo::StreamInfo& stream_info) const override { + response_headers_parser_->evaluateHeaders(headers, stream_info); + DynamicRouteEntry::finalizeResponseHeaders(headers, stream_info); } const RouteSpecificFilterConfig* perFilterConfig(const std::string& name) const override; @@ -518,8 +525,7 @@ class RouteEntryImplBase : public RouteEntry, typedef std::shared_ptr WeightedClusterEntrySharedPtr; - static absl::optional - loadRuntimeData(const envoy::api::v2::route::RouteMatch& route); + absl::optional loadRuntimeData(const envoy::api::v2::route::RouteMatch& route); static std::multimap parseOpaqueConfig(const envoy::api::v2::route::Route& route); @@ -540,8 +546,8 @@ class RouteEntryImplBase : public RouteEntry, const std::chrono::milliseconds timeout_; const absl::optional idle_timeout_; const absl::optional max_grpc_timeout_; - const absl::optional runtime_; Runtime::Loader& loader_; + const absl::optional runtime_; const std::string host_redirect_; const std::string path_redirect_; const bool https_redirect_; diff --git a/source/common/router/header_formatter.cc b/source/common/router/header_formatter.cc index 99235da451adc..bb7c0f14845f8 100644 --- a/source/common/router/header_formatter.cc +++ b/source/common/router/header_formatter.cc @@ -11,7 +11,7 @@ #include "common/config/metadata.h" #include "common/http/header_map_impl.h" #include "common/json/json_loader.h" -#include "common/request_info/utility.h" +#include "common/stream_info/utility.h" #include "absl/strings/str_cat.h" #include "absl/types/optional.h" @@ -42,10 +42,10 @@ std::string formatPerRequestStateParseException(absl::string_view params) { } // Parses the parameters for UPSTREAM_METADATA and returns a function suitable for accessing the -// specified metadata from an RequestInfo::RequestInfo. Expects a string formatted as: +// specified metadata from an StreamInfo::StreamInfo. Expects a string formatted as: // (["a", "b", "c"]) // There must be at least 2 array elements (a metadata namespace and at least 1 key). -std::function +std::function parseUpstreamMetadataField(absl::string_view params_str) { params_str = StringUtil::trim(params_str); if (params_str.empty() || params_str.front() != '(' || params_str.back() != ')') { @@ -70,8 +70,8 @@ parseUpstreamMetadataField(absl::string_view params_str) { throw EnvoyException(formatUpstreamMetadataParseException(params_str)); } - return [params](const Envoy::RequestInfo::RequestInfo& request_info) -> std::string { - Upstream::HostDescriptionConstSharedPtr host = request_info.upstreamHost(); + return [params](const Envoy::StreamInfo::StreamInfo& stream_info) -> std::string { + Upstream::HostDescriptionConstSharedPtr host = stream_info.upstreamHost(); if (!host) { return std::string(); } @@ -124,11 +124,11 @@ parseUpstreamMetadataField(absl::string_view params_str) { } // Parses the parameters for PER_REQUEST_STATE and returns a function suitable for accessing the -// specified metadata from an RequestInfo::RequestInfo. Expects a string formatted as: +// specified metadata from an StreamInfo::StreamInfo. Expects a string formatted as: // () // The state name is expected to be in reverse DNS format, though this is not enforced by // this function. -std::function +std::function parsePerRequestStateField(absl::string_view param_str) { absl::string_view modified_param_str = StringUtil::trim(param_str); if (modified_param_str.empty() || modified_param_str.front() != '(' || @@ -141,8 +141,8 @@ parsePerRequestStateField(absl::string_view param_str) { } std::string param(modified_param_str); - return [param](const Envoy::RequestInfo::RequestInfo& request_info) -> std::string { - const Envoy::RequestInfo::FilterState& per_request_state = request_info.perRequestState(); + return [param](const Envoy::StreamInfo::StreamInfo& stream_info) -> std::string { + const Envoy::StreamInfo::FilterState& per_request_state = stream_info.perRequestState(); // No such value means don't output anything. if (!per_request_state.hasDataWithName(param)) { @@ -164,25 +164,25 @@ parsePerRequestStateField(absl::string_view param_str) { } // namespace -RequestInfoHeaderFormatter::RequestInfoHeaderFormatter(absl::string_view field_name, bool append) +StreamInfoHeaderFormatter::StreamInfoHeaderFormatter(absl::string_view field_name, bool append) : append_(append) { if (field_name == "PROTOCOL") { - field_extractor_ = [](const Envoy::RequestInfo::RequestInfo& request_info) { - return Envoy::AccessLog::AccessLogFormatUtils::protocolToString(request_info.protocol()); + field_extractor_ = [](const Envoy::StreamInfo::StreamInfo& stream_info) { + return Envoy::AccessLog::AccessLogFormatUtils::protocolToString(stream_info.protocol()); }; } else if (field_name == "DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT") { - field_extractor_ = [](const Envoy::RequestInfo::RequestInfo& request_info) { - return RequestInfo::Utility::formatDownstreamAddressNoPort( - *request_info.downstreamRemoteAddress()); + field_extractor_ = [](const Envoy::StreamInfo::StreamInfo& stream_info) { + return StreamInfo::Utility::formatDownstreamAddressNoPort( + *stream_info.downstreamRemoteAddress()); }; } else if (field_name == "DOWNSTREAM_LOCAL_ADDRESS") { - field_extractor_ = [](const RequestInfo::RequestInfo& request_info) { - return request_info.downstreamLocalAddress()->asString(); + field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { + return stream_info.downstreamLocalAddress()->asString(); }; } else if (field_name == "DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT") { - field_extractor_ = [](const Envoy::RequestInfo::RequestInfo& request_info) { - return RequestInfo::Utility::formatDownstreamAddressNoPort( - *request_info.downstreamLocalAddress()); + field_extractor_ = [](const Envoy::StreamInfo::StreamInfo& stream_info) { + return StreamInfo::Utility::formatDownstreamAddressNoPort( + *stream_info.downstreamLocalAddress()); }; } else if (field_name.find("START_TIME") == 0) { const std::string pattern = fmt::format("%{}%", field_name); @@ -190,13 +190,13 @@ RequestInfoHeaderFormatter::RequestInfoHeaderFormatter(absl::string_view field_n start_time_formatters_.emplace( std::make_pair(pattern, AccessLog::AccessLogFormatParser::parse(pattern))); } - field_extractor_ = [this, pattern](const Envoy::RequestInfo::RequestInfo& request_info) { + field_extractor_ = [this, pattern](const Envoy::StreamInfo::StreamInfo& stream_info) { const auto& formatters = start_time_formatters_.at(pattern); Http::HeaderMapImpl empty_map; std::string formatted; for (const auto& formatter : formatters) { absl::StrAppend(&formatted, - formatter->format(empty_map, empty_map, empty_map, request_info)); + formatter->format(empty_map, empty_map, empty_map, stream_info)); } return formatted; }; @@ -212,8 +212,8 @@ RequestInfoHeaderFormatter::RequestInfoHeaderFormatter(absl::string_view field_n } const std::string -RequestInfoHeaderFormatter::format(const Envoy::RequestInfo::RequestInfo& request_info) const { - return field_extractor_(request_info); +StreamInfoHeaderFormatter::format(const Envoy::StreamInfo::StreamInfo& stream_info) const { + return field_extractor_(stream_info); } } // namespace Router diff --git a/source/common/router/header_formatter.h b/source/common/router/header_formatter.h index a5edb29f181b1..0c87edc12b644 100644 --- a/source/common/router/header_formatter.h +++ b/source/common/router/header_formatter.h @@ -18,7 +18,7 @@ class HeaderFormatter { public: virtual ~HeaderFormatter() {} - virtual const std::string format(const Envoy::RequestInfo::RequestInfo& request_info) const PURE; + virtual const std::string format(const Envoy::StreamInfo::StreamInfo& stream_info) const PURE; /** * @return bool indicating whether the formatted header should be appended to the existing @@ -30,20 +30,21 @@ class HeaderFormatter { typedef std::unique_ptr HeaderFormatterPtr; /** - * A formatter that expands the request header variable to a value based on info in RequestInfo. + * A formatter that expands the request header variable to a value based on info in StreamInfo. */ -class RequestInfoHeaderFormatter : public HeaderFormatter { +class StreamInfoHeaderFormatter : public HeaderFormatter { public: - RequestInfoHeaderFormatter(absl::string_view field_name, bool append); + StreamInfoHeaderFormatter(absl::string_view field_name, bool append); // HeaderFormatter::format - const std::string format(const Envoy::RequestInfo::RequestInfo& request_info) const override; + const std::string format(const Envoy::StreamInfo::StreamInfo& stream_info) const override; bool append() const override { return append_; } private: - std::function field_extractor_; + std::function field_extractor_; const bool append_; - std::unordered_map> start_time_formatters_; + std::unordered_map> + start_time_formatters_; }; /** @@ -55,7 +56,7 @@ class PlainHeaderFormatter : public HeaderFormatter { : static_value_(static_header_value), append_(append) {} // HeaderFormatter::format - const std::string format(const Envoy::RequestInfo::RequestInfo&) const override { + const std::string format(const Envoy::StreamInfo::StreamInfo&) const override { return static_value_; }; bool append() const override { return append_; } @@ -74,10 +75,10 @@ class CompoundHeaderFormatter : public HeaderFormatter { : formatters_(std::move(formatters)), append_(append) {} // HeaderFormatter::format - const std::string format(const Envoy::RequestInfo::RequestInfo& request_info) const override { + const std::string format(const Envoy::StreamInfo::StreamInfo& stream_info) const override { std::string buf; for (const auto& formatter : formatters_) { - buf += formatter->format(request_info); + buf += formatter->format(stream_info); } return buf; }; diff --git a/source/common/router/header_parser.cc b/source/common/router/header_parser.cc index 0425d53139155..d0383e28f6ea7 100644 --- a/source/common/router/header_parser.cc +++ b/source/common/router/header_parser.cc @@ -34,7 +34,7 @@ std::string unescape(absl::string_view sv) { return absl::StrReplaceAll(sv, {{"% // is either literal text (with % escaped as %%) or part of a %VAR% or %VAR(["args"])% expression. // The statement machine does minimal validation of the arguments (if any) and does not know the // names of valid variables. Interpretation of the variable name and arguments is delegated to -// RequestInfoHeaderFormatter. +// StreamInfoHeaderFormatter. HeaderFormatterPtr parseInternal(const envoy::api::v2::core::HeaderValueOption& header_value_option) { const std::string& key = header_value_option.header().key(); @@ -97,7 +97,7 @@ parseInternal(const envoy::api::v2::core::HeaderValueOption& header_value_option if (ch == '%') { // Found complete variable name, add formatter. formatters.emplace_back( - new RequestInfoHeaderFormatter(format.substr(start, pos - start), append)); + new StreamInfoHeaderFormatter(format.substr(start, pos - start), append)); start = pos + 1; state = ParserState::Literal; break; @@ -178,7 +178,7 @@ parseInternal(const envoy::api::v2::core::HeaderValueOption& header_value_option // Search for closing % of a %VAR(...)% expression if (ch == '%') { formatters.emplace_back( - new RequestInfoHeaderFormatter(format.substr(start, pos - start), append)); + new StreamInfoHeaderFormatter(format.substr(start, pos - start), append)); start = pos + 1; state = ParserState::Literal; break; @@ -240,6 +240,12 @@ HeaderParserPtr HeaderParser::configure( HeaderParserPtr header_parser = configure(headers_to_add); for (const auto& header : headers_to_remove) { + // We reject :-prefix (e.g. :path) removal here. This is dangerous, since other aspects of + // request finalization assume their existence and they are needed for well-formedness in most + // cases. + if (header[0] == ':') { + throw EnvoyException(":-prefixed headers may not be removed"); + } header_parser->headers_to_remove_.emplace_back(header); } @@ -247,9 +253,9 @@ HeaderParserPtr HeaderParser::configure( } void HeaderParser::evaluateHeaders(Http::HeaderMap& headers, - const RequestInfo::RequestInfo& request_info) const { + const StreamInfo::StreamInfo& stream_info) const { for (const auto& formatter : headers_to_add_) { - const std::string value = formatter.second->format(request_info); + const std::string value = formatter.second->format(stream_info); if (!value.empty()) { if (formatter.second->append()) { headers.addReferenceKey(formatter.first, value); diff --git a/source/common/router/header_parser.h b/source/common/router/header_parser.h index c5b4fe96f0b13..aaeacf4152acd 100644 --- a/source/common/router/header_parser.h +++ b/source/common/router/header_parser.h @@ -19,7 +19,7 @@ typedef std::unique_ptr HeaderParserPtr; /** * HeaderParser manipulates Http::HeaderMap instances. Headers to be added are pre-parsed to select * between a constant value implementation and a dynamic value implementation based on - * RequestInfo::RequestInfo fields. + * StreamInfo::StreamInfo fields. */ class HeaderParser { public: @@ -39,8 +39,7 @@ class HeaderParser { const Protobuf::RepeatedPtrField& headers_to_add, const Protobuf::RepeatedPtrField& headers_to_remove); - void evaluateHeaders(Http::HeaderMap& headers, - const RequestInfo::RequestInfo& request_info) const; + void evaluateHeaders(Http::HeaderMap& headers, const StreamInfo::StreamInfo& stream_info) const; protected: HeaderParser() {} diff --git a/source/common/router/retry_state_impl.cc b/source/common/router/retry_state_impl.cc index 0fddc40c2264a..b58af360888a6 100644 --- a/source/common/router/retry_state_impl.cc +++ b/source/common/router/retry_state_impl.cc @@ -21,6 +21,7 @@ const uint32_t RetryPolicy::RETRY_ON_5XX; 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_GRPC_CANCELLED; const uint32_t RetryPolicy::RETRY_ON_GRPC_DEADLINE_EXCEEDED; const uint32_t RetryPolicy::RETRY_ON_GRPC_RESOURCE_EXHAUSTED; @@ -53,7 +54,8 @@ RetryStateImpl::RetryStateImpl(const RetryPolicy& route_policy, Http::HeaderMap& Upstream::ResourcePriority priority) : cluster_(cluster), runtime_(runtime), random_(random), dispatcher_(dispatcher), priority_(priority), retry_host_predicates_(route_policy.retryHostPredicates()), - retry_priority_(route_policy.retryPriority()) { + retry_priority_(route_policy.retryPriority()), + retriable_status_codes_(route_policy.retriableStatusCodes()) { if (request_headers.EnvoyRetryOn()) { retry_on_ = parseRetryOn(request_headers.EnvoyRetryOn()->value().c_str()); @@ -68,6 +70,15 @@ RetryStateImpl::RetryStateImpl(const RetryPolicy& route_policy, Http::HeaderMap& retries_remaining_ = temp; } } + if (request_headers.EnvoyRetriableStatusCodes()) { + for (const auto code : StringUtil::splitToken( + request_headers.EnvoyRetriableStatusCodes()->value().getStringView(), ",")) { + uint64_t out; + if (StringUtil::atoul(std::string(code).c_str(), out)) { + retriable_status_codes_.emplace_back(out); + } + } + } // Merge in the route policy. retry_on_ |= route_policy.retryOn(); @@ -102,6 +113,8 @@ uint32_t RetryStateImpl::parseRetryOn(absl::string_view config) { ret |= RetryPolicy::RETRY_ON_RETRIABLE_4XX; } else if (retry_on == Http::Headers::get().EnvoyRetryOnValues.RefusedStream) { ret |= RetryPolicy::RETRY_ON_REFUSED_STREAM; + } else if (retry_on == Http::Headers::get().EnvoyRetryOnValues.RetriableStatusCodes) { + ret |= RetryPolicy::RETRY_ON_RETRIABLE_STATUS_CODES; } } @@ -119,6 +132,8 @@ uint32_t RetryStateImpl::parseRetryGrpcOn(absl::string_view retry_grpc_on_header ret |= RetryPolicy::RETRY_ON_GRPC_RESOURCE_EXHAUSTED; } else if (retry_on == Http::Headers::get().EnvoyRetryOnGrpcValues.Unavailable) { ret |= RetryPolicy::RETRY_ON_GRPC_UNAVAILABLE; + } else if (retry_on == Http::Headers::get().EnvoyRetryOnGrpcValues.Internal) { + ret |= RetryPolicy::RETRY_ON_GRPC_INTERNAL; } } @@ -216,10 +231,18 @@ bool RetryStateImpl::wouldRetry(const Http::HeaderMap* response_headers, } } + if ((retry_on_ & RetryPolicy::RETRY_ON_RETRIABLE_STATUS_CODES)) { + for (auto code : retriable_status_codes_) { + if (Http::Utility::getResponseStatus(*response_headers) == code) { + return true; + } + } + } + if (retry_on_ & (RetryPolicy::RETRY_ON_GRPC_CANCELLED | RetryPolicy::RETRY_ON_GRPC_DEADLINE_EXCEEDED | - RetryPolicy::RETRY_ON_GRPC_RESOURCE_EXHAUSTED | - RetryPolicy::RETRY_ON_GRPC_UNAVAILABLE) && + RetryPolicy::RETRY_ON_GRPC_RESOURCE_EXHAUSTED | RetryPolicy::RETRY_ON_GRPC_UNAVAILABLE | + RetryPolicy::RETRY_ON_GRPC_INTERNAL) && response_headers) { absl::optional status = Grpc::Common::getGrpcStatus(*response_headers); @@ -231,7 +254,9 @@ bool RetryStateImpl::wouldRetry(const Http::HeaderMap* response_headers, (status.value() == Grpc::Status::ResourceExhausted && (retry_on_ & RetryPolicy::RETRY_ON_GRPC_RESOURCE_EXHAUSTED)) || (status.value() == Grpc::Status::Unavailable && - (retry_on_ & RetryPolicy::RETRY_ON_GRPC_UNAVAILABLE))) { + (retry_on_ & RetryPolicy::RETRY_ON_GRPC_UNAVAILABLE)) || + (status.value() == Grpc::Status::Internal && + (retry_on_ & RetryPolicy::RETRY_ON_GRPC_INTERNAL))) { return true; } } diff --git a/source/common/router/retry_state_impl.h b/source/common/router/retry_state_impl.h index 6d23d0b82c7a6..4d271b3c6fe94 100644 --- a/source/common/router/retry_state_impl.h +++ b/source/common/router/retry_state_impl.h @@ -89,6 +89,7 @@ class RetryStateImpl : public RetryState { std::vector retry_host_predicates_; Upstream::RetryPrioritySharedPtr retry_priority_; uint32_t host_selection_max_attempts_; + std::vector retriable_status_codes_; }; } // namespace Router diff --git a/source/common/router/router.cc b/source/common/router/router.cc index cd7f68fa2b016..9d966e10a67fd 100644 --- a/source/common/router/router.cc +++ b/source/common/router/router.cc @@ -111,6 +111,15 @@ FilterUtility::finalTimeout(const RouteEntry& route, Http::HeaderMap& request_he request_headers.insertEnvoyExpectedRequestTimeoutMs().value(expected_timeout); } + // If we've configured max_grpc_timeout, override the grpc-timeout header with + // the expected timeout. This ensures that the optional per try timeout is reflected + // in grpc-timeout, ensuring that the upstream gRPC server is aware of the actual timeout. + // If the expected timeout is 0 set no timeout, as Envoy treats 0 as infinite timeout. + if (grpc_request && route.maxGrpcTimeout() && expected_timeout != 0) { + Grpc::Common::toGrpcTimeout(std::chrono::milliseconds(expected_timeout), + request_headers.insertGrpcTimeout().value()); + } + return timeout; } @@ -132,7 +141,7 @@ void Filter::chargeUpstreamCode(uint64_t response_status_code, // Passing the response_status_code explicitly is an optimization to avoid // multiple calls to slow Http::Utility::getResponseStatus. ASSERT(response_status_code == Http::Utility::getResponseStatus(response_headers)); - if (config_.emit_dynamic_stats_ && !callbacks_->requestInfo().healthCheck()) { + if (config_.emit_dynamic_stats_ && !callbacks_->streamInfo().healthCheck()) { const Http::HeaderEntry* upstream_canary_header = response_headers.EnvoyUpstreamCanary(); const Http::HeaderEntry* internal_request_header = downstream_headers_->EnvoyInternalRequest(); @@ -210,7 +219,7 @@ Http::FilterHeadersStatus Filter::decodeHeaders(Http::HeaderMap& headers, bool e ENVOY_STREAM_LOG(debug, "no cluster match for URL '{}'", *callbacks_, headers.Path()->value().c_str()); - callbacks_->requestInfo().setResponseFlag(RequestInfo::ResponseFlag::NoRouteFound); + callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::NoRouteFound); callbacks_->sendLocalReply(Http::Code::NotFound, "", nullptr); return Http::FilterHeadersStatus::StopIteration; } @@ -228,7 +237,7 @@ Http::FilterHeadersStatus Filter::decodeHeaders(Http::HeaderMap& headers, bool e if (!new_path.empty()) { response_headers.addReferenceKey(Http::Headers::get().Location, new_path); } - direct_response->finalizeResponseHeaders(response_headers, callbacks_->requestInfo()); + direct_response->finalizeResponseHeaders(response_headers, callbacks_->streamInfo()); }); return Http::FilterHeadersStatus::StopIteration; } @@ -240,7 +249,7 @@ Http::FilterHeadersStatus Filter::decodeHeaders(Http::HeaderMap& headers, bool e config_.stats_.no_cluster_.inc(); ENVOY_STREAM_LOG(debug, "unknown cluster '{}'", *callbacks_, route_entry_->clusterName()); - callbacks_->requestInfo().setResponseFlag(RequestInfo::ResponseFlag::NoRouteFound); + callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::NoRouteFound); callbacks_->sendLocalReply(route_entry_->clusterNotFoundResponseCode(), "", nullptr); return Http::FilterHeadersStatus::StopIteration; } @@ -259,7 +268,7 @@ Http::FilterHeadersStatus Filter::decodeHeaders(Http::HeaderMap& headers, bool e // See if we are supposed to immediately kill some percentage of this cluster's traffic. if (cluster_->maintenanceMode()) { - callbacks_->requestInfo().setResponseFlag(RequestInfo::ResponseFlag::UpstreamOverflow); + callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::UpstreamOverflow); chargeUpstreamCode(Http::Code::ServiceUnavailable, nullptr, true); callbacks_->sendLocalReply( Http::Code::ServiceUnavailable, "maintenance mode", [this](Http::HeaderMap& headers) { @@ -287,7 +296,12 @@ Http::FilterHeadersStatus Filter::decodeHeaders(Http::HeaderMap& headers, bool e headers.removeEnvoyUpstreamRequestTimeoutAltResponse(); } - route_entry_->finalizeRequestHeaders(headers, callbacks_->requestInfo(), + include_attempt_count_ = route_entry_->includeAttemptCount(); + if (include_attempt_count_) { + headers.insertEnvoyAttemptCount().value(attempt_count_); + } + + route_entry_->finalizeRequestHeaders(headers, callbacks_->streamInfo(), !config_.suppress_envoy_headers_); FilterUtility::setUpstreamScheme(headers, *cluster_); @@ -318,7 +332,7 @@ Http::ConnectionPool::Instance* Filter::getConnPool() { Http::Protocol protocol; if (features & Upstream::ClusterInfo::Features::USE_DOWNSTREAM_PROTOCOL) { - protocol = callbacks_->requestInfo().protocol().value(); + protocol = callbacks_->streamInfo().protocol().value(); } else { protocol = (features & Upstream::ClusterInfo::Features::HTTP2) ? Http::Protocol::Http2 : Http::Protocol::Http11; @@ -328,7 +342,7 @@ Http::ConnectionPool::Instance* Filter::getConnPool() { } void Filter::sendNoHealthyUpstreamResponse() { - callbacks_->requestInfo().setResponseFlag(RequestInfo::ResponseFlag::NoHealthyUpstream); + callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::NoHealthyUpstream); chargeUpstreamCode(Http::Code::ServiceUnavailable, nullptr, false); callbacks_->sendLocalReply(Http::Code::ServiceUnavailable, "no healthy upstream", nullptr); } @@ -480,7 +494,7 @@ void Filter::onUpstreamReset(UpstreamResetType type, } return; } else if (retry_status == RetryStatus::NoOverflow) { - callbacks_->requestInfo().setResponseFlag(RequestInfo::ResponseFlag::UpstreamOverflow); + callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::UpstreamOverflow); } } @@ -499,14 +513,14 @@ void Filter::onUpstreamReset(UpstreamResetType type, Http::Code code; const char* body; if (type == UpstreamResetType::GlobalTimeout || type == UpstreamResetType::PerTryTimeout) { - callbacks_->requestInfo().setResponseFlag(RequestInfo::ResponseFlag::UpstreamRequestTimeout); + callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::UpstreamRequestTimeout); code = timeout_response_code_; body = code == Http::Code::GatewayTimeout ? "upstream request timeout" : ""; } else { - RequestInfo::ResponseFlag response_flags = + StreamInfo::ResponseFlag response_flags = streamResetReasonToResponseFlag(reset_reason.value()); - callbacks_->requestInfo().setResponseFlag(response_flags); + callbacks_->streamInfo().setResponseFlag(response_flags); code = Http::Code::ServiceUnavailable; body = "upstream connect error or disconnect/reset before headers"; } @@ -528,21 +542,21 @@ void Filter::onUpstreamReset(UpstreamResetType type, } } -RequestInfo::ResponseFlag +StreamInfo::ResponseFlag Filter::streamResetReasonToResponseFlag(Http::StreamResetReason reset_reason) { switch (reset_reason) { case Http::StreamResetReason::ConnectionFailure: - return RequestInfo::ResponseFlag::UpstreamConnectionFailure; + return StreamInfo::ResponseFlag::UpstreamConnectionFailure; case Http::StreamResetReason::ConnectionTermination: - return RequestInfo::ResponseFlag::UpstreamConnectionTermination; + return StreamInfo::ResponseFlag::UpstreamConnectionTermination; case Http::StreamResetReason::LocalReset: case Http::StreamResetReason::LocalRefusedStreamReset: - return RequestInfo::ResponseFlag::LocalReset; + return StreamInfo::ResponseFlag::LocalReset; case Http::StreamResetReason::Overflow: - return RequestInfo::ResponseFlag::UpstreamOverflow; + return StreamInfo::ResponseFlag::UpstreamOverflow; case Http::StreamResetReason::RemoteReset: case Http::StreamResetReason::RemoteRefusedStreamReset: - return RequestInfo::ResponseFlag::UpstreamRemoteReset; + return StreamInfo::ResponseFlag::UpstreamRemoteReset; } throw std::invalid_argument("Unknown reset_reason"); @@ -606,7 +620,7 @@ void Filter::onUpstreamHeaders(const uint64_t response_code, Http::HeaderMapPtr& upstream_host->stats().rq_error_.inc(); return; } else if (retry_status == RetryStatus::NoOverflow) { - callbacks_->requestInfo().setResponseFlag(RequestInfo::ResponseFlag::UpstreamOverflow); + callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::UpstreamOverflow); } // Make sure any retry timers are destroyed since we may not call cleanup() if end_stream is @@ -642,7 +656,7 @@ void Filter::onUpstreamHeaders(const uint64_t response_code, Http::HeaderMapPtr& // TODO(zuercher): If access to response_headers_to_add (at any level) is ever needed outside // Router::Filter we'll need to find a better location for this work. One possibility is to // provide finalizeResponseHeaders functions on the Router::Config and VirtualHost interfaces. - route_entry_->finalizeResponseHeaders(*headers, callbacks_->requestInfo()); + route_entry_->finalizeResponseHeaders(*headers, callbacks_->streamInfo()); downstream_response_started_ = true; if (end_stream) { @@ -683,7 +697,7 @@ void Filter::onUpstreamComplete() { upstream_request_->resetStream(); } - if (config_.emit_dynamic_stats_ && !callbacks_->requestInfo().healthCheck() && + if (config_.emit_dynamic_stats_ && !callbacks_->streamInfo().healthCheck() && DateUtil::timePointValid(downstream_request_complete_time_)) { Event::Dispatcher& dispatcher = callbacks_->dispatcher(); std::chrono::milliseconds response_time = std::chrono::duration_cast( @@ -747,12 +761,13 @@ bool Filter::setupRetry(bool end_stream) { } upstream_request_.reset(); - callbacks_->requestInfo().resetUpstreamTimings(); + callbacks_->streamInfo().resetUpstreamTimings(); return true; } void Filter::doRetry() { is_retry_ = true; + attempt_count_++; Http::ConnectionPool::Instance* conn_pool = getConnPool(); if (!conn_pool) { sendNoHealthyUpstreamResponse(); @@ -760,6 +775,10 @@ void Filter::doRetry() { return; } + if (include_attempt_count_) { + downstream_headers_->insertEnvoyAttemptCount().value(attempt_count_); + } + ASSERT(response_timeout_ || timeout_.global_timeout_.count() == 0); ASSERT(!upstream_request_); upstream_request_.reset(new UpstreamRequest(*this, *conn_pool)); @@ -782,7 +801,7 @@ void Filter::doRetry() { Filter::UpstreamRequest::UpstreamRequest(Filter& parent, Http::ConnectionPool::Instance& pool) : parent_(parent), conn_pool_(pool), grpc_rq_success_deferred_(false), - request_info_(pool.protocol(), parent_.callbacks_->dispatcher().timeSystem()), + stream_info_(pool.protocol(), parent_.callbacks_->dispatcher().timeSystem()), calling_encode_headers_(false), upstream_canary_(false), encode_complete_(false), encode_trailers_(false) { @@ -793,7 +812,7 @@ Filter::UpstreamRequest::UpstreamRequest(Filter& parent, Http::ConnectionPool::I span_->setTag(Tracing::Tags::get().COMPONENT, Tracing::Tags::get().PROXY); } - request_info_.healthCheck(parent_.callbacks_->requestInfo().healthCheck()); + stream_info_.healthCheck(parent_.callbacks_->streamInfo().healthCheck()); } Filter::UpstreamRequest::~UpstreamRequest() { @@ -807,10 +826,10 @@ Filter::UpstreamRequest::~UpstreamRequest() { } clearRequestEncoder(); - request_info_.onRequestComplete(); + stream_info_.onRequestComplete(); for (const auto& upstream_log : parent_.config_.upstream_logs_) { upstream_log->log(parent_.downstream_headers_, upstream_headers_, upstream_trailers_, - request_info_); + stream_info_); } } @@ -821,19 +840,19 @@ void Filter::UpstreamRequest::decode100ContinueHeaders(Http::HeaderMapPtr&& head void Filter::UpstreamRequest::decodeHeaders(Http::HeaderMapPtr&& headers, bool end_stream) { // TODO(rodaine): This is actually measuring after the headers are parsed and not the first byte. - request_info_.onFirstUpstreamRxByteReceived(); - parent_.callbacks_->requestInfo().onFirstUpstreamRxByteReceived(); + stream_info_.onFirstUpstreamRxByteReceived(); + parent_.callbacks_->streamInfo().onFirstUpstreamRxByteReceived(); maybeEndDecode(end_stream); upstream_headers_ = headers.get(); const uint64_t response_code = Http::Utility::getResponseStatus(*headers); - request_info_.response_code_ = static_cast(response_code); + stream_info_.response_code_ = static_cast(response_code); parent_.onUpstreamHeaders(response_code, std::move(headers), end_stream); } void Filter::UpstreamRequest::decodeData(Buffer::Instance& data, bool end_stream) { maybeEndDecode(end_stream); - request_info_.addBytesReceived(data.length()); + stream_info_.addBytesReceived(data.length()); parent_.onUpstreamData(data, end_stream); } @@ -845,8 +864,8 @@ void Filter::UpstreamRequest::decodeTrailers(Http::HeaderMapPtr&& trailers) { void Filter::UpstreamRequest::maybeEndDecode(bool end_stream) { if (end_stream) { - request_info_.onLastUpstreamRxByteReceived(); - parent_.callbacks_->requestInfo().onLastUpstreamRxByteReceived(); + stream_info_.onLastUpstreamRxByteReceived(); + parent_.callbacks_->streamInfo().onLastUpstreamRxByteReceived(); } } @@ -879,11 +898,11 @@ void Filter::UpstreamRequest::encodeData(Buffer::Instance& data, bool end_stream buffered_request_body_->move(data); } else { ENVOY_STREAM_LOG(trace, "proxying {} bytes", *parent_.callbacks_, data.length()); - request_info_.addBytesSent(data.length()); + stream_info_.addBytesSent(data.length()); request_encoder_->encodeData(data, end_stream); if (end_stream) { - request_info_.onLastUpstreamTxByteSent(); - parent_.callbacks_->requestInfo().onLastUpstreamTxByteSent(); + stream_info_.onLastUpstreamTxByteSent(); + parent_.callbacks_->streamInfo().onLastUpstreamTxByteSent(); } } } @@ -898,15 +917,15 @@ void Filter::UpstreamRequest::encodeTrailers(const Http::HeaderMap& trailers) { } else { ENVOY_STREAM_LOG(trace, "proxying trailers", *parent_.callbacks_); request_encoder_->encodeTrailers(trailers); - request_info_.onLastUpstreamTxByteSent(); - parent_.callbacks_->requestInfo().onLastUpstreamTxByteSent(); + stream_info_.onLastUpstreamTxByteSent(); + parent_.callbacks_->streamInfo().onLastUpstreamTxByteSent(); } } void Filter::UpstreamRequest::onResetStream(Http::StreamResetReason reason) { clearRequestEncoder(); if (!calling_encode_headers_) { - request_info_.setResponseFlag(parent_.streamResetReasonToResponseFlag(reason)); + stream_info_.setResponseFlag(parent_.streamResetReasonToResponseFlag(reason)); parent_.onUpstreamReset(UpstreamResetType::Reset, absl::optional(reason)); } else { @@ -948,7 +967,7 @@ void Filter::UpstreamRequest::onPerTryTimeout() { upstream_host_->stats().rq_timeout_.inc(); } resetStream(); - request_info_.setResponseFlag(RequestInfo::ResponseFlag::UpstreamRequestTimeout); + stream_info_.setResponseFlag(StreamInfo::ResponseFlag::UpstreamRequestTimeout); parent_.onUpstreamReset( UpstreamResetType::PerTryTimeout, absl::optional(Http::StreamResetReason::LocalReset)); @@ -980,7 +999,7 @@ void Filter::UpstreamRequest::onPoolReady(Http::StreamEncoder& request_encoder, Upstream::HostDescriptionConstSharedPtr host) { ENVOY_STREAM_LOG(debug, "pool ready", *parent_.callbacks_); - // TODO(ggreenway): set upstream local address in the RequestInfo. + // TODO(ggreenway): set upstream local address in the StreamInfo. onUpstreamHostSelected(host); request_encoder.getStream().addCallbacks(*this); @@ -995,8 +1014,8 @@ void Filter::UpstreamRequest::onPoolReady(Http::StreamEncoder& request_encoder, span_->injectContext(*parent_.downstream_headers_); } - request_info_.onFirstUpstreamTxByteSent(); - parent_.callbacks_->requestInfo().onFirstUpstreamTxByteSent(); + stream_info_.onFirstUpstreamTxByteSent(); + parent_.callbacks_->streamInfo().onFirstUpstreamTxByteSent(); request_encoder.encodeHeaders(*parent_.downstream_headers_, !buffered_request_body_ && encode_complete_ && !encode_trailers_); calling_encode_headers_ = false; @@ -1010,7 +1029,7 @@ void Filter::UpstreamRequest::onPoolReady(Http::StreamEncoder& request_encoder, onResetStream(deferred_reset_reason_.value()); } else { if (buffered_request_body_) { - request_info_.addBytesSent(buffered_request_body_->length()); + stream_info_.addBytesSent(buffered_request_body_->length()); request_encoder.encodeData(*buffered_request_body_, encode_complete_ && !encode_trailers_); } @@ -1019,8 +1038,8 @@ void Filter::UpstreamRequest::onPoolReady(Http::StreamEncoder& request_encoder, } if (encode_complete_) { - request_info_.onLastUpstreamTxByteSent(); - parent_.callbacks_->requestInfo().onLastUpstreamTxByteSent(); + stream_info_.onLastUpstreamTxByteSent(); + parent_.callbacks_->streamInfo().onLastUpstreamTxByteSent(); } } } diff --git a/source/common/router/router.h b/source/common/router/router.h index 2ec0b265cdfeb..61c8b95656a20 100644 --- a/source/common/router/router.h +++ b/source/common/router/router.h @@ -24,8 +24,8 @@ #include "common/common/logger.h" #include "common/config/well_known_names.h" #include "common/http/utility.h" -#include "common/request_info/request_info_impl.h" #include "common/router/config_impl.h" +#include "common/stream_info/stream_info_impl.h" namespace Envoy { namespace Router { @@ -166,7 +166,7 @@ class Filter : Logger::Loggable, auto hash_policy = route_entry_->hashPolicy(); if (hash_policy) { return hash_policy->generateHash( - callbacks_->requestInfo().downstreamRemoteAddress().get(), *downstream_headers_, + callbacks_->streamInfo().downstreamRemoteAddress().get(), *downstream_headers_, [this](const std::string& key, const std::string& path, std::chrono::seconds max_age) { return addDownstreamSetCookie(key, path, max_age); }); @@ -184,7 +184,7 @@ class Filter : Logger::Loggable, } // The request's metadata, if present, takes precedence over the route's. - const auto& request_metadata = callbacks_->requestInfo().dynamicMetadata().filter_metadata(); + const auto& request_metadata = callbacks_->streamInfo().dynamicMetadata().filter_metadata(); const auto filter_it = request_metadata.find(Envoy::Config::MetadataFilters::get().ENVOY_LB); if (filter_it != request_metadata.end()) { if (route_entry_->metadataMatchCriteria() != nullptr) { @@ -278,9 +278,9 @@ class Filter : Logger::Loggable, void maybeEndDecode(bool end_stream); void onUpstreamHostSelected(Upstream::HostDescriptionConstSharedPtr host) { - request_info_.onUpstreamHostSelected(host); + stream_info_.onUpstreamHostSelected(host); upstream_host_ = host; - parent_.callbacks_->requestInfo().onUpstreamHostSelected(host); + parent_.callbacks_->streamInfo().onUpstreamHostSelected(host); } // Http::StreamDecoder @@ -335,7 +335,7 @@ class Filter : Logger::Loggable, Upstream::HostDescriptionConstSharedPtr upstream_host_; DownstreamWatermarkManager downstream_watermark_manager_{*this}; Tracing::SpanPtr span_; - RequestInfo::RequestInfoImpl request_info_; + StreamInfo::StreamInfoImpl stream_info_; Http::HeaderMap* upstream_headers_{}; Http::HeaderMap* upstream_trailers_{}; @@ -349,7 +349,7 @@ class Filter : Logger::Loggable, enum class UpstreamResetType { Reset, GlobalTimeout, PerTryTimeout }; - RequestInfo::ResponseFlag streamResetReasonToResponseFlag(Http::StreamResetReason reset_reason); + StreamInfo::ResponseFlag streamResetReasonToResponseFlag(Http::StreamResetReason reset_reason); static const std::string upstreamZone(Upstream::HostDescriptionConstSharedPtr upstream_host); void chargeUpstreamCode(uint64_t response_status_code, const Http::HeaderMap& response_headers, @@ -408,6 +408,8 @@ class Filter : Logger::Loggable, bool downstream_end_stream_ : 1; bool do_shadowing_ : 1; bool is_retry_ : 1; + bool include_attempt_count_ : 1; + uint32_t attempt_count_{1}; }; class ProdFilter : public Filter { diff --git a/source/common/router/shadow_writer_impl.cc b/source/common/router/shadow_writer_impl.cc index b54266ea6abaa..7129d88a1f248 100644 --- a/source/common/router/shadow_writer_impl.cc +++ b/source/common/router/shadow_writer_impl.cc @@ -13,6 +13,14 @@ namespace Router { void ShadowWriterImpl::shadow(const std::string& cluster, Http::MessagePtr&& request, std::chrono::milliseconds timeout) { + // It's possible that the cluster specified in the route configuration no longer exists due + // to a CDS removal. Check that it still exists before shadowing. + // TODO(mattklein123): Optimally we would have a stat but for now just fix the crashing issue. + if (!cm_.get(cluster)) { + ENVOY_LOG(debug, "shadow cluster '{}' does not exist", cluster); + return; + } + ASSERT(!request->headers().Host()->value().empty()); // Switch authority to add a shadow postfix. This allows upstream logging to make more sense. auto parts = StringUtil::splitToken(request->headers().Host()->value().c_str(), ":"); @@ -20,8 +28,7 @@ void ShadowWriterImpl::shadow(const std::string& cluster, Http::MessagePtr&& req request->headers().Host()->value( parts.size() == 2 ? absl::StrJoin(parts, "-shadow:") : absl::StrCat(request->headers().Host()->value().c_str(), "-shadow")); - // Configuration should guarantee that cluster exists before calling here. This is basically - // fire and forget. We don't handle cancelling. + // This is basically fire and forget. We don't handle cancelling. cm_.httpAsyncClientForCluster(cluster).send(std::move(request), *this, absl::optional(timeout)); } diff --git a/source/common/router/shadow_writer_impl.h b/source/common/router/shadow_writer_impl.h index 3724795b5b3e9..72da4bc0a7c09 100644 --- a/source/common/router/shadow_writer_impl.h +++ b/source/common/router/shadow_writer_impl.h @@ -13,7 +13,9 @@ namespace Router { * Implementation of ShadowWriter that takes incoming requests to shadow and implements "fire and * forget" behavior using an async client. */ -class ShadowWriterImpl : public ShadowWriter, public Http::AsyncClient::Callbacks { +class ShadowWriterImpl : Logger::Loggable, + public ShadowWriter, + public Http::AsyncClient::Callbacks { public: ShadowWriterImpl(Upstream::ClusterManager& cm) : cm_(cm) {} diff --git a/source/common/ssl/BUILD b/source/common/ssl/BUILD index 9cc5179d0e998..84a29a8c7ec4f 100644 --- a/source/common/ssl/BUILD +++ b/source/common/ssl/BUILD @@ -76,6 +76,8 @@ envoy_cc_library( "//source/common/common:base64_lib", "//source/common/common:hex_lib", "//source/common/common:utility_lib", + "//source/common/protobuf:utility_lib", + "@envoy_api//envoy/admin/v2alpha:certs_cc", ], ) diff --git a/source/common/ssl/context_impl.cc b/source/common/ssl/context_impl.cc index e42e8d666f630..20b3769b4b292 100644 --- a/source/common/ssl/context_impl.cc +++ b/source/common/ssl/context_impl.cc @@ -14,6 +14,7 @@ #include "common/common/fmt.h" #include "common/common/hex.h" #include "common/common/utility.h" +#include "common/protobuf/utility.h" #include "common/ssl/utility.h" #include "openssl/hmac.h" @@ -457,23 +458,38 @@ int32_t ContextImpl::getDaysUntilExpiration(const X509* cert) const { return 0; } -std::string ContextImpl::getCaCertInformation() const { +CertificateDetailsPtr ContextImpl::getCaCertInformation() const { if (ca_cert_ == nullptr) { - return ""; + return nullptr; } - return fmt::format("Certificate Path: {}, Serial Number: {}, Days until Expiration: {}", - getCaFileName(), Utility::getSerialNumberFromCertificate(*ca_cert_.get()), - getDaysUntilExpiration(ca_cert_.get())); + return certificateDetails(ca_cert_.get(), getCaFileName()); } -std::string ContextImpl::getCertChainInformation() const { +CertificateDetailsPtr ContextImpl::getCertChainInformation() const { if (cert_chain_ == nullptr) { - return ""; + return nullptr; } - return fmt::format("Certificate Path: {}, Serial Number: {}, Days until Expiration: {}", - getCertChainFileName(), - Utility::getSerialNumberFromCertificate(*cert_chain_.get()), - getDaysUntilExpiration(cert_chain_.get())); + return certificateDetails(cert_chain_.get(), getCertChainFileName()); +} + +CertificateDetailsPtr ContextImpl::certificateDetails(X509* cert, const std::string& path) const { + CertificateDetailsPtr certificate_details = + std::make_unique(); + certificate_details->set_path(path); + certificate_details->set_serial_number(Utility::getSerialNumberFromCertificate(*cert)); + certificate_details->set_days_until_expiration(getDaysUntilExpiration(cert)); + + for (auto& dns_san : Utility::getSubjectAltNames(*cert, GEN_DNS)) { + envoy::admin::v2alpha::SubjectAlternateName& subject_alt_name = + *certificate_details->add_subject_alt_names(); + subject_alt_name.set_dns(dns_san); + } + for (auto& uri_san : Utility::getSubjectAltNames(*cert, GEN_URI)) { + envoy::admin::v2alpha::SubjectAlternateName& subject_alt_name = + *certificate_details->add_subject_alt_names(); + subject_alt_name.set_uri(uri_san); + } + return certificate_details; } ClientContextImpl::ClientContextImpl(Stats::Scope& scope, const ClientContextConfig& config) diff --git a/source/common/ssl/context_impl.h b/source/common/ssl/context_impl.h index be5bf91d31600..0627bb28ded74 100644 --- a/source/common/ssl/context_impl.h +++ b/source/common/ssl/context_impl.h @@ -71,8 +71,8 @@ class ContextImpl : public virtual Context { // Ssl::Context size_t daysUntilFirstCertExpires() const override; - std::string getCaCertInformation() const override; - std::string getCertChainInformation() const override; + CertificateDetailsPtr getCaCertInformation() const override; + CertificateDetailsPtr getCertChainInformation() const override; protected: ContextImpl(Stats::Scope& scope, const ContextConfig& config); @@ -122,6 +122,8 @@ class ContextImpl : public virtual Context { std::string getCaFileName() const { return ca_file_path_; }; std::string getCertChainFileName() const { return cert_chain_file_path_; }; + CertificateDetailsPtr certificateDetails(X509* cert, const std::string& path) const; + bssl::UniquePtr ctx_; bool verify_trusted_ca_{false}; std::vector verify_subject_alt_name_list_; diff --git a/source/common/ssl/utility.cc b/source/common/ssl/utility.cc index 6f98864c97ac6..3fbbffbbe6775 100644 --- a/source/common/ssl/utility.cc +++ b/source/common/ssl/utility.cc @@ -1,5 +1,8 @@ #include "common/ssl/utility.h" +#include "absl/strings/str_join.h" +#include "openssl/x509v3.h" + namespace Envoy { namespace Ssl { @@ -18,5 +21,22 @@ std::string Utility::getSerialNumberFromCertificate(X509& cert) { return ""; } +std::vector Utility::getSubjectAltNames(X509& cert, int type) { + std::vector subject_alt_names; + bssl::UniquePtr san_names( + static_cast(X509_get_ext_d2i(&cert, NID_subject_alt_name, nullptr, nullptr))); + if (san_names == nullptr) { + return subject_alt_names; + } + for (const GENERAL_NAME* san : san_names.get()) { + if (san->type == type) { + ASN1_STRING* str = san->d.dNSName; + const char* dns_name = reinterpret_cast(ASN1_STRING_data(str)); + subject_alt_names.push_back(std::string(dns_name)); + } + } + return subject_alt_names; +} + } // namespace Ssl } // namespace Envoy diff --git a/source/common/ssl/utility.h b/source/common/ssl/utility.h index cb41056e0f0fb..93b2f81cd325b 100644 --- a/source/common/ssl/utility.h +++ b/source/common/ssl/utility.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "openssl/ssl.h" @@ -9,13 +10,20 @@ namespace Ssl { namespace Utility { /** - * Retrieve the serial number of a certificate. - * @param ssl the certificate + * Retrieves the serial number of a certificate. + * @param cert the certificate * @return std::string the serial number field of the certificate. Returns "" if * there is no serial number. */ std::string getSerialNumberFromCertificate(X509& cert); +/** + * Retrieves the subject alternate names of a certificate of type DNS. + * @param cert the certificate + * @param type type of subject alternate name either GEN_DNS or GEN_URI + * @return std::vector returns the list of subject alternate names. + */ +std::vector getSubjectAltNames(X509& cert, int type); } // namespace Utility } // namespace Ssl } // namespace Envoy diff --git a/source/common/stats/BUILD b/source/common/stats/BUILD index 456562cf16a79..427d272220311 100644 --- a/source/common/stats/BUILD +++ b/source/common/stats/BUILD @@ -162,6 +162,18 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "stats_matcher_lib", + srcs = ["stats_matcher_impl.cc"], + hdrs = ["stats_matcher_impl.h"], + deps = [ + "//include/envoy/stats:stats_interface", + "//source/common/common:matchers_lib", + "//source/common/protobuf", + "@envoy_api//envoy/config/metrics/v2:stats_cc", + ], +) + envoy_cc_library( name = "thread_local_store_lib", srcs = ["thread_local_store.cc"], @@ -169,6 +181,7 @@ envoy_cc_library( deps = [ ":heap_stat_data_lib", ":stats_lib", + ":stats_matcher_lib", ":tag_producer_lib", "//include/envoy/thread_local:thread_local_interface", ], diff --git a/source/common/stats/histogram_impl.h b/source/common/stats/histogram_impl.h index 9afd73d85cf04..f2c70895906c6 100644 --- a/source/common/stats/histogram_impl.h +++ b/source/common/stats/histogram_impl.h @@ -63,5 +63,20 @@ class HistogramImpl : public Histogram, public MetricImpl { const std::string name_; }; +/** + * Null histogram implementation. + * No-ops on all calls and requires no underlying metric or data. + */ +class NullHistogramImpl : public Histogram { +public: + NullHistogramImpl() {} + ~NullHistogramImpl() {} + const std::string name() const override { return ""; } + const std::string& tagExtractedName() const override { CONSTRUCT_ON_FIRST_USE(std::string, ""); } + const std::vector& tags() const override { CONSTRUCT_ON_FIRST_USE(std::vector, {}); } + void recordValue(uint64_t) override {} + bool used() const override { return false; } +}; + } // namespace Stats } // namespace Envoy diff --git a/source/common/stats/stat_data_allocator_impl.h b/source/common/stats/stat_data_allocator_impl.h index 8c31af8d52811..71be9733c7cbd 100644 --- a/source/common/stats/stat_data_allocator_impl.h +++ b/source/common/stats/stat_data_allocator_impl.h @@ -87,6 +87,25 @@ template class CounterImpl : public Counter, public MetricImpl StatDataAllocatorImpl& alloc_; }; +/** + * Null counter implementation. + * No-ops on all calls and requires no underlying metric or data. + */ +class NullCounterImpl : public Counter { +public: + NullCounterImpl() {} + ~NullCounterImpl() {} + const std::string name() const override { return ""; } + const std::string& tagExtractedName() const override { CONSTRUCT_ON_FIRST_USE(std::string, ""); } + const std::vector& tags() const override { CONSTRUCT_ON_FIRST_USE(std::vector, {}); } + void add(uint64_t) override {} + void inc() override {} + uint64_t latch() override { return 0; } + void reset() override {} + bool used() const override { return false; } + uint64_t value() const override { return 0; } +}; + /** * Gauge implementation that wraps a StatData. */ @@ -124,6 +143,26 @@ template class GaugeImpl : public Gauge, public MetricImpl { StatDataAllocatorImpl& alloc_; }; +/** + * Null gauge implementation. + * No-ops on all calls and requires no underlying metric or data. + */ +class NullGaugeImpl : public Gauge { +public: + NullGaugeImpl() {} + ~NullGaugeImpl() {} + const std::string name() const override { return ""; } + const std::string& tagExtractedName() const override { CONSTRUCT_ON_FIRST_USE(std::string, ""); } + const std::vector& tags() const override { CONSTRUCT_ON_FIRST_USE(std::vector, {}); } + void add(uint64_t) override {} + void inc() override {} + void dec() override {} + void set(uint64_t) override {} + void sub(uint64_t) override {} + bool used() const override { return false; } + uint64_t value() const override { return 0; } +}; + template CounterSharedPtr StatDataAllocatorImpl::makeCounter(absl::string_view name, std::string&& tag_extracted_name, diff --git a/source/common/stats/stats_matcher_impl.cc b/source/common/stats/stats_matcher_impl.cc new file mode 100644 index 0000000000000..e4f14872ae4dd --- /dev/null +++ b/source/common/stats/stats_matcher_impl.cc @@ -0,0 +1,55 @@ +#include "common/stats/stats_matcher_impl.h" + +#include +#include + +#include "common/common/utility.h" + +namespace Envoy { +namespace Stats { + +// TODO(ambuc): Refactor this into common/matchers.cc, since StatsMatcher is really just a thin +// wrapper around what might be called a StringMatcherList. +StatsMatcherImpl::StatsMatcherImpl(const envoy::config::metrics::v2::StatsConfig& config) { + switch (config.stats_matcher().stats_matcher_case()) { + case envoy::config::metrics::v2::StatsMatcher::kRejectAll: + // In this scenario, there are no matchers to store. + is_inclusive_ = !config.stats_matcher().reject_all(); + break; + case envoy::config::metrics::v2::StatsMatcher::kInclusionList: + // If we have an inclusion list, we are being default-exclusive. + for (const auto& stats_matcher : config.stats_matcher().inclusion_list().patterns()) { + matchers_.push_back(Matchers::StringMatcher(stats_matcher)); + } + is_inclusive_ = false; + break; + case envoy::config::metrics::v2::StatsMatcher::kExclusionList: + // If we have an exclusion list, we are being default-inclusive. + for (const auto& stats_matcher : config.stats_matcher().exclusion_list().patterns()) { + matchers_.push_back(Matchers::StringMatcher(stats_matcher)); + } + FALLTHRU; + default: + // No matcher was supplied, so we default to inclusion. + is_inclusive_ = true; + break; + } +} + +bool StatsMatcherImpl::rejects(const std::string& name) const { + // + // is_inclusive_ | match | return + // ---------------+-------+-------- + // T | T | T Default-inclusive and matching an (exclusion) matcher, deny. + // T | F | F Otherwise, allow. + // F | T | F Default-exclusive and matching an (inclusion) matcher, allow. + // F | F | T Otherwise, deny. + // + // This is an XNOR, which can be evaluated by checking for equality. + + return (is_inclusive_ == std::any_of(matchers_.begin(), matchers_.end(), + [&name](auto matcher) { return matcher.match(name); })); +} + +} // namespace Stats +} // namespace Envoy diff --git a/source/common/stats/stats_matcher_impl.h b/source/common/stats/stats_matcher_impl.h new file mode 100644 index 0000000000000..a4b7a27fa82c5 --- /dev/null +++ b/source/common/stats/stats_matcher_impl.h @@ -0,0 +1,42 @@ +#pragma once + +#include + +#include "envoy/config/metrics/v2/stats.pb.h" +#include "envoy/stats/stats_matcher.h" + +#include "common/common/matchers.h" +#include "common/protobuf/protobuf.h" + +#include "absl/strings/string_view.h" + +namespace Envoy { +namespace Stats { + +/** + * Supplies a stats matcher. + */ +class StatsMatcherImpl : public StatsMatcher { +public: + explicit StatsMatcherImpl(const envoy::config::metrics::v2::StatsConfig& config); + + // Default constructor simply allows everything. + StatsMatcherImpl() : is_inclusive_(true) {} + + /** + * Take a metric name and report whether or not it should be disallowed. + * @param the name of a Stats::Metric. + * @return bool true if that stat should not be instantiated. + */ + bool rejects(const std::string& name) const override; + +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_; + + std::vector matchers_; +}; + +} // namespace Stats +} // namespace Envoy diff --git a/source/common/stats/thread_local_store.cc b/source/common/stats/thread_local_store.cc index a099810e8d3ba..b6f57e27fb2c1 100644 --- a/source/common/stats/thread_local_store.cc +++ b/source/common/stats/thread_local_store.cc @@ -14,6 +14,7 @@ #include "envoy/stats/stats_options.h" #include "common/common/lock_guard.h" +#include "common/stats/stats_matcher_impl.h" #include "common/stats/tag_producer_impl.h" #include "absl/strings/str_join.h" @@ -25,6 +26,7 @@ ThreadLocalStoreImpl::ThreadLocalStoreImpl(const StatsOptions& stats_options, StatDataAllocator& alloc) : stats_options_(stats_options), alloc_(alloc), default_scope_(createScope("")), tag_producer_(std::make_unique()), + stats_matcher_(std::make_unique()), num_last_resort_stats_(default_scope_->counter("stats.overflow")), source_(*this) {} ThreadLocalStoreImpl::~ThreadLocalStoreImpl() { @@ -233,6 +235,12 @@ Counter& ThreadLocalStoreImpl::ScopeImpl::counter(const std::string& name) { // Determine the final name based on the prefix and the passed name. std::string final_name = prefix_ + name; + // TODO(ambuc): If stats_matcher_ depends on regexes, this operation (on the hot path) could + // become prohibitively expensive. Revisit this usage in the future. + if (parent_.stats_matcher_->rejects(final_name)) { + return null_counter_; + } + // We now try to acquire a *reference* to the TLS cache shared pointer. This might remain null // if we don't have TLS initialized currently. The de-referenced pointer might be null if there // is no cache entry. @@ -271,6 +279,12 @@ Gauge& ThreadLocalStoreImpl::ScopeImpl::gauge(const std::string& name) { // See comments in counter(). There is no super clean way (via templates or otherwise) to // share this code so I'm leaving it largely duplicated for now. std::string final_name = prefix_ + name; + + // See warning/comments in counter(). + if (parent_.stats_matcher_->rejects(final_name)) { + return null_gauge_; + } + GaugeSharedPtr* tls_ref = nullptr; if (!parent_.shutting_down_ && parent_.tls_) { tls_ref = &parent_.tls_->getTyped().scope_cache_[this->scope_id_].gauges_[final_name]; @@ -289,6 +303,12 @@ Histogram& ThreadLocalStoreImpl::ScopeImpl::histogram(const std::string& name) { // See comments in counter(). There is no super clean way (via templates or otherwise) to // share this code so I'm leaving it largely duplicated for now. std::string final_name = prefix_ + name; + + // See warning/comments in counter(). + if (parent_.stats_matcher_->rejects(final_name)) { + return null_histogram_; + } + ParentHistogramSharedPtr* tls_ref = nullptr; if (!parent_.shutting_down_ && parent_.tls_) { @@ -318,6 +338,10 @@ Histogram& ThreadLocalStoreImpl::ScopeImpl::histogram(const std::string& name) { Histogram& ThreadLocalStoreImpl::ScopeImpl::tlsHistogram(const std::string& name, ParentHistogramImpl& parent) { + if (parent_.stats_matcher_->rejects(name)) { + return null_histogram_; + } + // See comments in counter() which explains the logic here. // Here prefix will not be considered because, by the time ParentHistogram calls this method diff --git a/source/common/stats/thread_local_store.h b/source/common/stats/thread_local_store.h index a179e081ef62e..ad3dec0628865 100644 --- a/source/common/stats/thread_local_store.h +++ b/source/common/stats/thread_local_store.h @@ -200,6 +200,9 @@ class ThreadLocalStoreImpl : Logger::Loggable, public StoreRo void setTagProducer(TagProducerPtr&& tag_producer) override { tag_producer_ = std::move(tag_producer); } + void setStatsMatcher(StatsMatcherPtr&& stats_matcher) override { + stats_matcher_ = std::move(stats_matcher); + } void initializeThreading(Event::Dispatcher& main_thread_dispatcher, ThreadLocal::Instance& tls) override; void shutdownThreading() override; @@ -270,6 +273,10 @@ class ThreadLocalStoreImpl : Logger::Loggable, public StoreRo ThreadLocalStoreImpl& parent_; const std::string prefix_; CentralCacheEntry central_cache_; + + NullCounterImpl null_counter_; + NullGaugeImpl null_gauge_; + NullHistogramImpl null_histogram_; }; struct TlsCache : public ThreadLocal::ThreadLocalObject { @@ -298,6 +305,7 @@ class ThreadLocalStoreImpl : Logger::Loggable, public StoreRo ScopePtr default_scope_; std::list> timer_sinks_; TagProducerPtr tag_producer_; + StatsMatcherPtr stats_matcher_; std::atomic shutting_down_{}; std::atomic merge_in_progress_{}; Counter& num_last_resort_stats_; diff --git a/source/common/request_info/BUILD b/source/common/stream_info/BUILD similarity index 70% rename from source/common/request_info/BUILD rename to source/common/stream_info/BUILD index e93d1b545cf50..639805f711f68 100644 --- a/source/common/request_info/BUILD +++ b/source/common/stream_info/BUILD @@ -9,11 +9,11 @@ load( envoy_package() envoy_cc_library( - name = "request_info_lib", - hdrs = ["request_info_impl.h"], + name = "stream_info_lib", + hdrs = ["stream_info_impl.h"], deps = [ ":filter_state_lib", - "//include/envoy/request_info:request_info_interface", + "//include/envoy/stream_info:stream_info_interface", "//source/common/common:assert_lib", ], ) @@ -23,7 +23,7 @@ envoy_cc_library( srcs = ["filter_state_impl.cc"], hdrs = ["filter_state_impl.h"], deps = [ - "//include/envoy/request_info:filter_state_interface", + "//include/envoy/stream_info:filter_state_interface", ], ) @@ -34,6 +34,6 @@ envoy_cc_library( external_deps = ["abseil_optional"], deps = [ "//include/envoy/common:time_interface", - "//include/envoy/request_info:request_info_interface", + "//include/envoy/stream_info:stream_info_interface", ], ) diff --git a/source/common/request_info/filter_state_impl.cc b/source/common/stream_info/filter_state_impl.cc similarity index 92% rename from source/common/request_info/filter_state_impl.cc rename to source/common/stream_info/filter_state_impl.cc index dbbb97fa7c93e..bcfee6298793a 100644 --- a/source/common/request_info/filter_state_impl.cc +++ b/source/common/stream_info/filter_state_impl.cc @@ -1,9 +1,9 @@ -#include "common/request_info/filter_state_impl.h" +#include "common/stream_info/filter_state_impl.h" #include "envoy/common/exception.h" namespace Envoy { -namespace RequestInfo { +namespace StreamInfo { void FilterStateImpl::setData(absl::string_view data_name, std::unique_ptr&& data) { // TODO(Google): Remove string conversion when fixed internally. @@ -31,5 +31,5 @@ const FilterState::Object* FilterStateImpl::getDataGeneric(absl::string_view dat return it->second.get(); } -} // namespace RequestInfo +} // namespace StreamInfo } // namespace Envoy diff --git a/source/common/request_info/filter_state_impl.h b/source/common/stream_info/filter_state_impl.h similarity index 87% rename from source/common/request_info/filter_state_impl.h rename to source/common/stream_info/filter_state_impl.h index b97b5d9ee91f6..14dba83ddbf73 100644 --- a/source/common/request_info/filter_state_impl.h +++ b/source/common/stream_info/filter_state_impl.h @@ -2,12 +2,12 @@ #include -#include "envoy/request_info/filter_state.h" +#include "envoy/stream_info/filter_state.h" #include "absl/strings/string_view.h" namespace Envoy { -namespace RequestInfo { +namespace StreamInfo { class FilterStateImpl : public FilterState { public: @@ -23,5 +23,5 @@ class FilterStateImpl : public FilterState { std::map, std::less<>> data_storage_; }; -} // namespace RequestInfo +} // namespace StreamInfo } // namespace Envoy diff --git a/source/common/request_info/request_info_impl.h b/source/common/stream_info/stream_info_impl.h similarity index 95% rename from source/common/request_info/request_info_impl.h rename to source/common/stream_info/stream_info_impl.h index 0d6a9ef52a732..188cf4aa3f4db 100644 --- a/source/common/request_info/request_info_impl.h +++ b/source/common/stream_info/stream_info_impl.h @@ -4,20 +4,20 @@ #include #include "envoy/common/time.h" -#include "envoy/request_info/request_info.h" +#include "envoy/stream_info/stream_info.h" #include "common/common/assert.h" -#include "common/request_info/filter_state_impl.h" +#include "common/stream_info/filter_state_impl.h" namespace Envoy { -namespace RequestInfo { +namespace StreamInfo { -struct RequestInfoImpl : public RequestInfo { - explicit RequestInfoImpl(TimeSource& time_source) +struct StreamInfoImpl : public StreamInfo { + explicit StreamInfoImpl(TimeSource& time_source) : time_source_(time_source), start_time_(time_source.systemTime()), start_time_monotonic_(time_source.monotonicTime()) {} - RequestInfoImpl(Http::Protocol protocol, TimeSource& time_source) : RequestInfoImpl(time_source) { + StreamInfoImpl(Http::Protocol protocol, TimeSource& time_source) : StreamInfoImpl(time_source) { protocol_ = protocol; } @@ -222,5 +222,5 @@ struct RequestInfoImpl : public RequestInfo { std::string requested_server_name_; }; -} // namespace RequestInfo +} // namespace StreamInfo } // namespace Envoy diff --git a/source/common/request_info/utility.cc b/source/common/stream_info/utility.cc similarity index 76% rename from source/common/request_info/utility.cc rename to source/common/stream_info/utility.cc index 6d71182fff221..e9fa8a243f80a 100644 --- a/source/common/request_info/utility.cc +++ b/source/common/stream_info/utility.cc @@ -1,9 +1,9 @@ -#include "common/request_info/utility.h" +#include "common/stream_info/utility.h" #include namespace Envoy { -namespace RequestInfo { +namespace StreamInfo { const std::string ResponseFlagUtils::NONE = "-"; const std::string ResponseFlagUtils::FAILED_LOCAL_HEALTH_CHECK = "LH"; @@ -29,64 +29,64 @@ void ResponseFlagUtils::appendString(std::string& result, const std::string& app } } -const std::string ResponseFlagUtils::toShortString(const RequestInfo& request_info) { +const std::string ResponseFlagUtils::toShortString(const StreamInfo& stream_info) { std::string result; static_assert(ResponseFlag::LastFlag == 0x2000, "A flag has been added. Fix this code."); - if (request_info.hasResponseFlag(ResponseFlag::FailedLocalHealthCheck)) { + if (stream_info.hasResponseFlag(ResponseFlag::FailedLocalHealthCheck)) { appendString(result, FAILED_LOCAL_HEALTH_CHECK); } - if (request_info.hasResponseFlag(ResponseFlag::NoHealthyUpstream)) { + if (stream_info.hasResponseFlag(ResponseFlag::NoHealthyUpstream)) { appendString(result, NO_HEALTHY_UPSTREAM); } - if (request_info.hasResponseFlag(ResponseFlag::UpstreamRequestTimeout)) { + if (stream_info.hasResponseFlag(ResponseFlag::UpstreamRequestTimeout)) { appendString(result, UPSTREAM_REQUEST_TIMEOUT); } - if (request_info.hasResponseFlag(ResponseFlag::LocalReset)) { + if (stream_info.hasResponseFlag(ResponseFlag::LocalReset)) { appendString(result, LOCAL_RESET); } - if (request_info.hasResponseFlag(ResponseFlag::UpstreamRemoteReset)) { + if (stream_info.hasResponseFlag(ResponseFlag::UpstreamRemoteReset)) { appendString(result, UPSTREAM_REMOTE_RESET); } - if (request_info.hasResponseFlag(ResponseFlag::UpstreamConnectionFailure)) { + if (stream_info.hasResponseFlag(ResponseFlag::UpstreamConnectionFailure)) { appendString(result, UPSTREAM_CONNECTION_FAILURE); } - if (request_info.hasResponseFlag(ResponseFlag::UpstreamConnectionTermination)) { + if (stream_info.hasResponseFlag(ResponseFlag::UpstreamConnectionTermination)) { appendString(result, UPSTREAM_CONNECTION_TERMINATION); } - if (request_info.hasResponseFlag(ResponseFlag::UpstreamOverflow)) { + if (stream_info.hasResponseFlag(ResponseFlag::UpstreamOverflow)) { appendString(result, UPSTREAM_OVERFLOW); } - if (request_info.hasResponseFlag(ResponseFlag::NoRouteFound)) { + if (stream_info.hasResponseFlag(ResponseFlag::NoRouteFound)) { appendString(result, NO_ROUTE_FOUND); } - if (request_info.hasResponseFlag(ResponseFlag::DelayInjected)) { + if (stream_info.hasResponseFlag(ResponseFlag::DelayInjected)) { appendString(result, DELAY_INJECTED); } - if (request_info.hasResponseFlag(ResponseFlag::FaultInjected)) { + if (stream_info.hasResponseFlag(ResponseFlag::FaultInjected)) { appendString(result, FAULT_INJECTED); } - if (request_info.hasResponseFlag(ResponseFlag::RateLimited)) { + if (stream_info.hasResponseFlag(ResponseFlag::RateLimited)) { appendString(result, RATE_LIMITED); } - if (request_info.hasResponseFlag(ResponseFlag::UnauthorizedExternalService)) { + if (stream_info.hasResponseFlag(ResponseFlag::UnauthorizedExternalService)) { appendString(result, UNAUTHORIZED_EXTERNAL_SERVICE); } - if (request_info.hasResponseFlag(ResponseFlag::RateLimitServiceError)) { + if (stream_info.hasResponseFlag(ResponseFlag::RateLimitServiceError)) { appendString(result, RATELIMIT_SERVICE_ERROR); } @@ -127,5 +127,5 @@ Utility::formatDownstreamAddressNoPort(const Network::Address::Instance& address } } -} // namespace RequestInfo +} // namespace StreamInfo } // namespace Envoy diff --git a/source/common/request_info/utility.h b/source/common/stream_info/utility.h similarity index 86% rename from source/common/request_info/utility.h rename to source/common/stream_info/utility.h index 209a8a963ddeb..c7ccc32e29a78 100644 --- a/source/common/request_info/utility.h +++ b/source/common/stream_info/utility.h @@ -3,17 +3,17 @@ #include #include -#include "envoy/request_info/request_info.h" +#include "envoy/stream_info/stream_info.h" namespace Envoy { -namespace RequestInfo { +namespace StreamInfo { /** * Util class for ResponseFlags. */ class ResponseFlagUtils { public: - static const std::string toShortString(const RequestInfo& request_info); + static const std::string toShortString(const StreamInfo& stream_info); static absl::optional toResponseFlag(const std::string& response_flag); private: @@ -38,7 +38,7 @@ class ResponseFlagUtils { }; /** - * Utility class for RequestInfo. + * Utility class for StreamInfo. */ class Utility { public: @@ -50,5 +50,5 @@ class Utility { formatDownstreamAddressNoPort(const Network::Address::Instance& address); }; -} // namespace RequestInfo +} // namespace StreamInfo } // namespace Envoy diff --git a/source/common/tcp_proxy/BUILD b/source/common/tcp_proxy/BUILD index 7a91233803740..0d51ab033a0d2 100644 --- a/source/common/tcp_proxy/BUILD +++ b/source/common/tcp_proxy/BUILD @@ -19,12 +19,12 @@ envoy_cc_library( "//include/envoy/event:dispatcher_interface", "//include/envoy/network:connection_interface", "//include/envoy/network:filter_interface", - "//include/envoy/request_info:filter_state_interface", "//include/envoy/router:router_interface", "//include/envoy/server:filter_config_interface", "//include/envoy/stats:stats_interface", "//include/envoy/stats:stats_macros", "//include/envoy/stats:timespan", + "//include/envoy/stream_info:filter_state_interface", "//include/envoy/tcp:conn_pool_interface", "//include/envoy/upstream:cluster_manager_interface", "//include/envoy/upstream:upstream_interface", @@ -35,8 +35,8 @@ envoy_cc_library( "//source/common/network:cidr_range_lib", "//source/common/network:filter_lib", "//source/common/network:utility_lib", - "//source/common/request_info:request_info_lib", "//source/common/router:metadatamatchcriteria_lib", + "//source/common/stream_info:stream_info_lib", "//source/common/upstream:load_balancer_lib", "@envoy_api//envoy/config/filter/network/tcp_proxy/v2:tcp_proxy_cc", ], diff --git a/source/common/tcp_proxy/tcp_proxy.cc b/source/common/tcp_proxy/tcp_proxy.cc index c44e35c85c944..e04bc1d37f7d1 100644 --- a/source/common/tcp_proxy/tcp_proxy.cc +++ b/source/common/tcp_proxy/tcp_proxy.cc @@ -163,15 +163,15 @@ UpstreamDrainManager& Config::drainManager() { Filter::Filter(ConfigSharedPtr config, Upstream::ClusterManager& cluster_manager, TimeSource& time_source) : config_(config), cluster_manager_(cluster_manager), downstream_callbacks_(*this), - upstream_callbacks_(new UpstreamCallbacks(this)), request_info_(time_source) { + upstream_callbacks_(new UpstreamCallbacks(this)), stream_info_(time_source) { ASSERT(config != nullptr); } Filter::~Filter() { - getRequestInfo().onRequestComplete(); + getStreamInfo().onRequestComplete(); for (const auto& access_log : config_->accessLogs()) { - access_log->log(nullptr, nullptr, nullptr, getRequestInfo()); + access_log->log(nullptr, nullptr, nullptr, getStreamInfo()); } ASSERT(upstream_handle_ == nullptr); @@ -192,8 +192,8 @@ void Filter::initialize(Network::ReadFilterCallbacks& callbacks, bool set_connec read_callbacks_->connection().addConnectionCallbacks(downstream_callbacks_); read_callbacks_->connection().enableHalfClose(true); - getRequestInfo().setDownstreamLocalAddress(read_callbacks_->connection().localAddress()); - getRequestInfo().setDownstreamRemoteAddress(read_callbacks_->connection().remoteAddress()); + getStreamInfo().setDownstreamLocalAddress(read_callbacks_->connection().localAddress()); + getStreamInfo().setDownstreamRemoteAddress(read_callbacks_->connection().remoteAddress()); // Need to disable reads so that we don't write to an upstream that might fail // in onData(). This will get re-enabled when the upstream connection is @@ -333,7 +333,7 @@ Network::FilterStatus Filter::initializeUpstreamConnection() { cluster_name); } else { config_->stats().downstream_cx_no_route_.inc(); - getRequestInfo().setResponseFlag(RequestInfo::ResponseFlag::NoRouteFound); + getStreamInfo().setResponseFlag(StreamInfo::ResponseFlag::NoRouteFound); onInitFailure(UpstreamFailureReason::NO_ROUTE); return Network::FilterStatus::StopIteration; } @@ -343,7 +343,7 @@ Network::FilterStatus Filter::initializeUpstreamConnection() { // Check this here because the TCP conn pool will queue our request waiting for a connection that // will never be released. if (!cluster->resourceManager(Upstream::ResourcePriority::Default).connections().canCreate()) { - getRequestInfo().setResponseFlag(RequestInfo::ResponseFlag::UpstreamOverflow); + getStreamInfo().setResponseFlag(StreamInfo::ResponseFlag::UpstreamOverflow); cluster->stats().upstream_cx_overflow_.inc(); onInitFailure(UpstreamFailureReason::RESOURCE_LIMIT_EXCEEDED); return Network::FilterStatus::StopIteration; @@ -361,7 +361,7 @@ Network::FilterStatus Filter::initializeUpstreamConnection() { if (!conn_pool) { // Either cluster is unknown or there are no healthy hosts. tcpConnPoolForCluster() increments // cluster->stats().upstream_cx_none_healthy in the latter case. - getRequestInfo().setResponseFlag(RequestInfo::ResponseFlag::NoHealthyUpstream); + getStreamInfo().setResponseFlag(StreamInfo::ResponseFlag::NoHealthyUpstream); onInitFailure(UpstreamFailureReason::NO_HEALTHY_UPSTREAM); return Network::FilterStatus::StopIteration; } @@ -380,7 +380,7 @@ void Filter::onPoolFailure(Tcp::ConnectionPool::PoolFailureReason reason, upstream_handle_ = nullptr; read_callbacks_->upstreamHost(host); - getRequestInfo().onUpstreamHostSelected(host); + getStreamInfo().onUpstreamHostSelected(host); switch (reason) { case Tcp::ConnectionPool::PoolFailureReason::Overflow: @@ -413,8 +413,8 @@ void Filter::onPoolReady(Tcp::ConnectionPool::ConnectionDataPtr&& conn_data, connection.enableHalfClose(true); - getRequestInfo().onUpstreamHostSelected(host); - getRequestInfo().setUpstreamLocalAddress(connection.localAddress()); + getStreamInfo().onUpstreamHostSelected(host); + getStreamInfo().setUpstreamLocalAddress(connection.localAddress()); // Simulate the event that onPoolReady represents. upstream_callbacks_->onEvent(Network::ConnectionEvent::Connected); @@ -425,7 +425,7 @@ void Filter::onPoolReady(Tcp::ConnectionPool::ConnectionDataPtr&& conn_data, void Filter::onConnectTimeout() { ENVOY_CONN_LOG(debug, "connect timeout", read_callbacks_->connection()); read_callbacks_->upstreamHost()->outlierDetector().putResult(Upstream::Outlier::Result::TIMEOUT); - getRequestInfo().setResponseFlag(RequestInfo::ResponseFlag::UpstreamConnectionFailure); + getStreamInfo().setResponseFlag(StreamInfo::ResponseFlag::UpstreamConnectionFailure); // Raise LocalClose, which will trigger a reconnect if needed/configured. upstream_callbacks_->onEvent(Network::ConnectionEvent::LocalClose); @@ -434,7 +434,7 @@ void Filter::onConnectTimeout() { Network::FilterStatus Filter::onData(Buffer::Instance& data, bool end_stream) { ENVOY_CONN_LOG(trace, "downstream connection received {} bytes, end_stream={}", read_callbacks_->connection(), data.length(), end_stream); - getRequestInfo().addBytesReceived(data.length()); + getStreamInfo().addBytesReceived(data.length()); upstream_conn_data_->connection().write(data, end_stream); ASSERT(0 == data.length()); resetIdleTimer(); // TODO(ggreenway) PERF: do we need to reset timer on both send and receive? @@ -475,7 +475,7 @@ void Filter::onDownstreamEvent(Network::ConnectionEvent event) { void Filter::onUpstreamData(Buffer::Instance& data, bool end_stream) { ENVOY_CONN_LOG(trace, "upstream connection received {} bytes, end_stream={}", read_callbacks_->connection(), data.length(), end_stream); - getRequestInfo().addBytesSent(data.length()); + getStreamInfo().addBytesSent(data.length()); read_callbacks_->connection().write(data, end_stream); ASSERT(0 == data.length()); resetIdleTimer(); // TODO(ggreenway) PERF: do we need to reset timer on both send and receive? @@ -494,7 +494,7 @@ void Filter::onUpstreamEvent(Network::ConnectionEvent event) { if (connecting) { if (event == Network::ConnectionEvent::RemoteClose) { - getRequestInfo().setResponseFlag(RequestInfo::ResponseFlag::UpstreamConnectionFailure); + getStreamInfo().setResponseFlag(StreamInfo::ResponseFlag::UpstreamConnectionFailure); read_callbacks_->upstreamHost()->outlierDetector().putResult( Upstream::Outlier::Result::CONNECT_FAILED); } @@ -514,9 +514,9 @@ void Filter::onUpstreamEvent(Network::ConnectionEvent event) { Upstream::Outlier::Result::SUCCESS); onConnectionSuccess(); - getRequestInfo().setRequestedServerName(read_callbacks_->connection().requestedServerName()); + getStreamInfo().setRequestedServerName(read_callbacks_->connection().requestedServerName()); ENVOY_LOG(debug, "TCP:onUpstreamEvent(), requestedServerName: {}", - getRequestInfo().requestedServerName()); + getStreamInfo().requestedServerName()); if (config_->idleTimeout()) { // The idle_timer_ can be moved to a Drainer, so related callbacks call into diff --git a/source/common/tcp_proxy/tcp_proxy.h b/source/common/tcp_proxy/tcp_proxy.h index e749400fe1b74..96b44d0b9a177 100644 --- a/source/common/tcp_proxy/tcp_proxy.h +++ b/source/common/tcp_proxy/tcp_proxy.h @@ -11,12 +11,12 @@ #include "envoy/event/timer.h" #include "envoy/network/connection.h" #include "envoy/network/filter.h" -#include "envoy/request_info/filter_state.h" #include "envoy/runtime/runtime.h" #include "envoy/server/filter_config.h" #include "envoy/stats/scope.h" #include "envoy/stats/stats_macros.h" #include "envoy/stats/timespan.h" +#include "envoy/stream_info/filter_state.h" #include "envoy/tcp/conn_pool.h" #include "envoy/upstream/cluster_manager.h" #include "envoy/upstream/upstream.h" @@ -25,7 +25,7 @@ #include "common/network/cidr_range.h" #include "common/network/filter_impl.h" #include "common/network/utility.h" -#include "common/request_info/request_info_impl.h" +#include "common/stream_info/stream_info_impl.h" #include "common/upstream/load_balancer_impl.h" namespace Envoy { @@ -158,7 +158,7 @@ typedef std::shared_ptr ConfigSharedPtr; /** * Per-connection TCP Proxy Cluster configuration. */ -class PerConnectionCluster : public RequestInfo::FilterState::Object { +class PerConnectionCluster : public StreamInfo::FilterState::Object { public: PerConnectionCluster(absl::string_view cluster) : cluster_(cluster) {} const std::string& value() const { return cluster_; } @@ -264,7 +264,7 @@ class Filter : public Network::ReadFilter, virtual void onConnectionSuccess() {} - virtual RequestInfo::RequestInfo& getRequestInfo() { return request_info_; } + virtual StreamInfo::StreamInfo& getStreamInfo() { return stream_info_; } void initialize(Network::ReadFilterCallbacks& callbacks, bool set_connection_stats); Network::FilterStatus initializeUpstreamConnection(); @@ -285,7 +285,7 @@ class Filter : public Network::ReadFilter, Event::TimerPtr idle_timer_; std::shared_ptr upstream_callbacks_; // shared_ptr required for passing as a // read filter. - RequestInfo::RequestInfoImpl request_info_; + StreamInfo::StreamInfoImpl stream_info_; uint32_t connect_attempts_{}; bool connecting_{}; }; diff --git a/source/common/tracing/BUILD b/source/common/tracing/BUILD index 3f1e4ddf8a90d..15061270fbe9c 100644 --- a/source/common/tracing/BUILD +++ b/source/common/tracing/BUILD @@ -34,7 +34,7 @@ envoy_cc_library( "//source/common/http:message_lib", "//source/common/http:utility_lib", "//source/common/json:json_loader_lib", - "//source/common/request_info:utility_lib", "//source/common/runtime:uuid_util_lib", + "//source/common/stream_info:utility_lib", ], ) diff --git a/source/common/tracing/http_tracer_impl.cc b/source/common/tracing/http_tracer_impl.cc index 9f41c870289b2..e0ff6c9c7afa2 100644 --- a/source/common/tracing/http_tracer_impl.cc +++ b/source/common/tracing/http_tracer_impl.cc @@ -11,14 +11,14 @@ #include "common/http/header_map_impl.h" #include "common/http/headers.h" #include "common/http/utility.h" -#include "common/request_info/utility.h" #include "common/runtime/uuid_util.h" +#include "common/stream_info/utility.h" namespace Envoy { namespace Tracing { // TODO(mattklein123) PERF: Avoid string creations/copies in this entire file. -static std::string buildResponseCode(const RequestInfo::RequestInfo& info) { +static std::string buildResponseCode(const StreamInfo::StreamInfo& info) { return info.responseCode() ? std::to_string(info.responseCode().value()) : "0"; } @@ -53,10 +53,10 @@ const std::string& HttpTracerUtility::toString(OperationName operation_name) { NOT_REACHED_GCOVR_EXCL_LINE; } -Decision HttpTracerUtility::isTracing(const RequestInfo::RequestInfo& request_info, +Decision HttpTracerUtility::isTracing(const StreamInfo::StreamInfo& stream_info, const Http::HeaderMap& request_headers) { // Exclude HC requests immediately. - if (request_info.healthCheck()) { + if (stream_info.healthCheck()) { return {Reason::HealthCheck, false}; } @@ -83,7 +83,7 @@ Decision HttpTracerUtility::isTracing(const RequestInfo::RequestInfo& request_in } void HttpTracerUtility::finalizeSpan(Span& span, const Http::HeaderMap* request_headers, - const RequestInfo::RequestInfo& request_info, + const StreamInfo::StreamInfo& stream_info, const Config& tracing_config) { // Pre response data. if (request_headers) { @@ -95,7 +95,7 @@ void HttpTracerUtility::finalizeSpan(Span& span, const Http::HeaderMap* request_ valueOrDefault(request_headers->EnvoyDownstreamServiceCluster(), "-")); span.setTag(Tracing::Tags::get().USER_AGENT, valueOrDefault(request_headers->UserAgent(), "-")); span.setTag(Tracing::Tags::get().HTTP_PROTOCOL, - AccessLog::AccessLogFormatUtils::protocolToString(request_info.protocol())); + AccessLog::AccessLogFormatUtils::protocolToString(stream_info.protocol())); if (request_headers->ClientTraceId()) { span.setTag(Tracing::Tags::get().GUID_X_CLIENT_TRACE_ID, @@ -110,21 +110,20 @@ void HttpTracerUtility::finalizeSpan(Span& span, const Http::HeaderMap* request_ } } } - span.setTag(Tracing::Tags::get().REQUEST_SIZE, std::to_string(request_info.bytesReceived())); + span.setTag(Tracing::Tags::get().REQUEST_SIZE, std::to_string(stream_info.bytesReceived())); - if (nullptr != request_info.upstreamHost()) { + if (nullptr != stream_info.upstreamHost()) { span.setTag(Tracing::Tags::get().UPSTREAM_CLUSTER, - request_info.upstreamHost()->cluster().name()); + stream_info.upstreamHost()->cluster().name()); } // Post response data. - span.setTag(Tracing::Tags::get().HTTP_STATUS_CODE, buildResponseCode(request_info)); - span.setTag(Tracing::Tags::get().RESPONSE_SIZE, std::to_string(request_info.bytesSent())); + span.setTag(Tracing::Tags::get().HTTP_STATUS_CODE, buildResponseCode(stream_info)); + span.setTag(Tracing::Tags::get().RESPONSE_SIZE, std::to_string(stream_info.bytesSent())); span.setTag(Tracing::Tags::get().RESPONSE_FLAGS, - RequestInfo::ResponseFlagUtils::toShortString(request_info)); + StreamInfo::ResponseFlagUtils::toShortString(stream_info)); - if (!request_info.responseCode() || - Http::CodeUtility::is5xx(request_info.responseCode().value())) { + if (!stream_info.responseCode() || Http::CodeUtility::is5xx(stream_info.responseCode().value())) { span.setTag(Tracing::Tags::get().ERROR, Tracing::Tags::get().TRUE); } @@ -135,7 +134,7 @@ HttpTracerImpl::HttpTracerImpl(DriverPtr&& driver, const LocalInfo::LocalInfo& l : driver_(std::move(driver)), local_info_(local_info) {} SpanPtr HttpTracerImpl::startSpan(const Config& config, Http::HeaderMap& request_headers, - const RequestInfo::RequestInfo& request_info, + const StreamInfo::StreamInfo& stream_info, const Tracing::Decision tracing_decision) { std::string span_name = HttpTracerUtility::toString(config.operationName()); @@ -145,7 +144,7 @@ SpanPtr HttpTracerImpl::startSpan(const Config& config, Http::HeaderMap& request } SpanPtr active_span = driver_->startSpan(config, request_headers, span_name, - request_info.startTime(), tracing_decision); + stream_info.startTime(), tracing_decision); if (active_span) { active_span->setTag(Tracing::Tags::get().COMPONENT, Tracing::Tags::get().PROXY); active_span->setTag(Tracing::Tags::get().NODE_ID, local_info_.nodeName()); diff --git a/source/common/tracing/http_tracer_impl.h b/source/common/tracing/http_tracer_impl.h index 9729ae57ee4f4..f426e44ddef4f 100644 --- a/source/common/tracing/http_tracer_impl.h +++ b/source/common/tracing/http_tracer_impl.h @@ -76,7 +76,7 @@ class HttpTracerUtility { * * @return decision if request is traceable or not and Reason why. **/ - static Decision isTracing(const RequestInfo::RequestInfo& request_info, + static Decision isTracing(const StreamInfo::StreamInfo& stream_info, const Http::HeaderMap& request_headers); /** @@ -84,8 +84,7 @@ class HttpTracerUtility { * 2) Finish active span. */ static void finalizeSpan(Span& span, const Http::HeaderMap* request_headers, - const RequestInfo::RequestInfo& request_info, - const Config& tracing_config); + const StreamInfo::StreamInfo& stream_info, const Config& tracing_config); static const std::string INGRESS_OPERATION; static const std::string EGRESS_OPERATION; @@ -126,7 +125,7 @@ class NullSpan : public Span { class HttpNullTracer : public HttpTracer { public: // Tracing::HttpTracer - SpanPtr startSpan(const Config&, Http::HeaderMap&, const RequestInfo::RequestInfo&, + SpanPtr startSpan(const Config&, Http::HeaderMap&, const StreamInfo::StreamInfo&, const Tracing::Decision) override { return SpanPtr{new NullSpan()}; } @@ -138,7 +137,7 @@ class HttpTracerImpl : public HttpTracer { // Tracing::HttpTracer SpanPtr startSpan(const Config& config, Http::HeaderMap& request_headers, - const RequestInfo::RequestInfo& request_info, + const StreamInfo::StreamInfo& stream_info, const Tracing::Decision tracing_decision) override; private: diff --git a/source/common/upstream/cluster_manager_impl.cc b/source/common/upstream/cluster_manager_impl.cc index 664447b771bc5..dd7f461c91319 100644 --- a/source/common/upstream/cluster_manager_impl.cc +++ b/source/common/upstream/cluster_manager_impl.cc @@ -1017,7 +1017,7 @@ ClusterManagerImpl::ThreadLocalClusterManagerImpl::ClusterEntry::ClusterEntry( ThreadLocalClusterManagerImpl& parent, ClusterInfoConstSharedPtr cluster, const LoadBalancerFactorySharedPtr& lb_factory) : parent_(parent), lb_factory_(lb_factory), cluster_info_(cluster), - http_async_client_(*cluster, parent.parent_.stats_, parent.thread_local_dispatcher_, + http_async_client_(cluster, parent.parent_.stats_, parent.thread_local_dispatcher_, parent.parent_.local_info_, parent.parent_, parent.parent_.runtime_, parent.parent_.random_, Router::ShadowWriterPtr{new Router::ShadowWriterImpl(parent.parent_)}) { diff --git a/source/common/upstream/health_checker_impl.cc b/source/common/upstream/health_checker_impl.cc index ccde1d5031948..d9c83c3998d9a 100644 --- a/source/common/upstream/health_checker_impl.cc +++ b/source/common/upstream/health_checker_impl.cc @@ -154,11 +154,11 @@ void HttpHealthCheckerImpl::HttpActiveHealthCheckSession::onInterval() { {Http::Headers::get().Path, parent_.path_}, {Http::Headers::get().UserAgent, Http::Headers::get().UserAgentValues.EnvoyHealthChecker}}; Router::FilterUtility::setUpstreamScheme(request_headers, *parent_.cluster_.info()); - RequestInfo::RequestInfoImpl request_info(protocol_, parent_.dispatcher_.timeSystem()); - request_info.setDownstreamLocalAddress(local_address_); - request_info.setDownstreamRemoteAddress(local_address_); - request_info.onUpstreamHostSelected(host_); - parent_.request_headers_parser_->evaluateHeaders(request_headers, request_info); + StreamInfo::StreamInfoImpl stream_info(protocol_, parent_.dispatcher_.timeSystem()); + stream_info.setDownstreamLocalAddress(local_address_); + stream_info.setDownstreamRemoteAddress(local_address_); + stream_info.onUpstreamHostSelected(host_); + parent_.request_headers_parser_->evaluateHeaders(request_headers, stream_info); request_encoder_->encodeHeaders(request_headers, true); request_encoder_ = nullptr; } diff --git a/source/common/upstream/health_checker_impl.h b/source/common/upstream/health_checker_impl.h index dc86aceb04eba..7fad218c6f486 100644 --- a/source/common/upstream/health_checker_impl.h +++ b/source/common/upstream/health_checker_impl.h @@ -7,8 +7,8 @@ #include "common/common/logger.h" #include "common/grpc/codec.h" #include "common/http/codec_client.h" -#include "common/request_info/request_info_impl.h" #include "common/router/header_parser.h" +#include "common/stream_info/stream_info_impl.h" #include "common/upstream/health_checker_base_impl.h" #include "src/proto/grpc/health/v1/health.pb.h" diff --git a/source/common/upstream/load_balancer_impl.cc b/source/common/upstream/load_balancer_impl.cc index 94cea9fcf9a13..54a0f91865fa9 100644 --- a/source/common/upstream/load_balancer_impl.cc +++ b/source/common/upstream/load_balancer_impl.cc @@ -44,25 +44,29 @@ LoadBalancerBase::LoadBalancerBase(const PrioritySet& priority_set, ClusterStats common_config, healthy_panic_threshold, 100, 50)), priority_set_(priority_set) { for (auto& host_set : priority_set_.hostSetsPerPriority()) { - recalculatePerPriorityState(host_set->priority()); + recalculatePerPriorityState(host_set->priority(), priority_set_, per_priority_load_, + per_priority_health_); } - priority_set_.addMemberUpdateCb( - [this](uint32_t priority, const HostVector&, const HostVector&) -> void { - recalculatePerPriorityState(priority); - }); + priority_set_.addMemberUpdateCb([this](uint32_t priority, const HostVector&, + const HostVector&) -> void { + recalculatePerPriorityState(priority, priority_set_, per_priority_load_, per_priority_health_); + }); } -void LoadBalancerBase::recalculatePerPriorityState(uint32_t priority) { - per_priority_load_.resize(priority_set_.hostSetsPerPriority().size()); - per_priority_health_.resize(priority_set_.hostSetsPerPriority().size()); +void LoadBalancerBase::recalculatePerPriorityState(uint32_t priority, + const PrioritySet& priority_set, + PriorityLoad& per_priority_load, + std::vector& per_priority_health) { + per_priority_load.resize(priority_set.hostSetsPerPriority().size()); + per_priority_health.resize(priority_set.hostSetsPerPriority().size()); // Determine the health of the newly modified priority level. // Health ranges from 0-100, and is the ratio of healthy hosts to total hosts, modified by the // overprovisioning factor. - HostSet& host_set = *priority_set_.hostSetsPerPriority()[priority]; - per_priority_health_[priority] = 0; + HostSet& host_set = *priority_set.hostSetsPerPriority()[priority]; + per_priority_health[priority] = 0; if (host_set.hosts().size() > 0) { - per_priority_health_[priority] = + per_priority_health[priority] = std::min(100, (host_set.overprovisioning_factor() * host_set.healthyHosts().size() / host_set.hosts().size())); } @@ -74,25 +78,32 @@ void LoadBalancerBase::recalculatePerPriorityState(uint32_t priority) { // 3 host sets with 20% / 20% / 10% health they will get 40% / 40% / 20% load to ensure total load // adds up to 100. const uint32_t total_health = std::min( - std::accumulate(per_priority_health_.begin(), per_priority_health_.end(), 0), 100); + std::accumulate(per_priority_health.begin(), per_priority_health.end(), 0), 100); if (total_health == 0) { // Everything is terrible. Send all load to P=0. // In this one case sumEntries(per_priority_load_) != 100 since we sinkhole all traffic in P=0. - per_priority_load_[0] = 100; + per_priority_load[0] = 100; return; } + size_t total_load = 100; - for (size_t i = 0; i < per_priority_health_.size(); ++i) { - // Now assign as much load as possible to the high priority levels and cease assigning load when - // total_load runs out. - per_priority_load_[i] = - std::min(total_load, per_priority_health_[i] * 100 / total_health); - total_load -= per_priority_load_[i]; + int32_t first_healthy_priority = -1; + for (size_t i = 0; i < per_priority_health.size(); ++i) { + if (first_healthy_priority < 0 && per_priority_health[i] > 0) { + first_healthy_priority = i; + } + // Now assign as much load as possible to the high priority levels and cease assigning load + // when total_load runs out. + per_priority_load[i] = + std::min(total_load, per_priority_health[i] * 100 / total_health); + total_load -= per_priority_load[i]; } + if (total_load != 0) { - // Account for rounding errors. - ASSERT(total_load < per_priority_load_.size()); - per_priority_load_[0] += total_load; + ASSERT(first_healthy_priority != -1); + // Account for rounding errors by assigning it to the first healthy priority. + ASSERT(total_load < per_priority_load.size()); + per_priority_load[first_healthy_priority] += total_load; } } diff --git a/source/common/upstream/load_balancer_impl.h b/source/common/upstream/load_balancer_impl.h index e7a75b6d05f33..1a216a1885df9 100644 --- a/source/common/upstream/load_balancer_impl.h +++ b/source/common/upstream/load_balancer_impl.h @@ -70,11 +70,15 @@ class LoadBalancerBase : public LoadBalancer { // The priority-ordered set of hosts to use for load balancing. const PrioritySet& priority_set_; +public: // Called when a host set at the given priority level is updated. This updates - // per_priority_health_ for that priority level, and may update per_priority_load_ for all + // per_priority_health for that priority level, and may update per_priority_load for all // priority levels. - void recalculatePerPriorityState(uint32_t priority); + void static recalculatePerPriorityState(uint32_t priority, const PrioritySet& priority_set, + PriorityLoad& priority_load, + std::vector& per_priority_health); +protected: // The percentage load (0-100) for each priority level std::vector per_priority_load_; // The health (0-100) for each priority level. diff --git a/source/common/upstream/upstream_impl.cc b/source/common/upstream/upstream_impl.cc index 4396308ea6644..f2cbcf38bd50f 100644 --- a/source/common/upstream/upstream_impl.cc +++ b/source/common/upstream/upstream_impl.cc @@ -1125,6 +1125,11 @@ void StrictDnsClusterImpl::updateAllHosts(const HostVector& hosts_added, uint32_t current_priority) { PriorityStateManager priority_state_manager(*this, local_info_); // At this point we know that we are different so make a new host list and notify. + // + // TODO(dio): The uniqueness of a host address resolved in STRICT_DNS cluster per priority is not + // guaranteed. Need a clear agreement on the behavior here, whether it is allowable to have + // duplicated hosts inside a priority. And if we want to enforce this behavior, it should be done + // inside the priority state manager. for (const ResolveTargetPtr& target : resolve_targets_) { priority_state_manager.initializePriorityFor(target->locality_lb_endpoint_); for (const HostSharedPtr& host : target->hosts_) { @@ -1191,8 +1196,27 @@ void StrictDnsClusterImpl::ResolveTarget::startResolve() { return host->priority() == locality_lb_endpoint_.priority(); })); parent_.updateAllHosts(hosts_added, hosts_removed, locality_lb_endpoint_.priority()); + } else { + parent_.info_->stats().update_no_rebuild_.inc(); } + // TODO(dio): As reported in https://github.com/envoyproxy/envoy/issues/4548, we leaked + // cluster members. This happened since whenever a target resolved, it would set its hosts + // as all_hosts_, so that when another target resolved it wouldn't see its own hosts in + // all_hosts_. It would think that they're new hosts, so it would add them to its host list + // over and over again. To completely fix this issue, we need to think through on + // reconciling the differences in behavior between STRICT_DNS and EDS, especially on + // handling host sets updates. This is tracked in + // https://github.com/envoyproxy/envoy/issues/4590. + // + // The following block is acceptable for now as a patch to make sure parent_.all_hosts_ is + // updated with all resolved hosts from all priorities. This reconciliation is required + // since we check each new host against this list. + for (const auto& set : parent_.prioritySet().hostSetsPerPriority()) { + for (const auto& host : set->hosts()) { + updated_hosts.insert({host->address()->asString(), host}); + } + } parent_.updateHostMap(std::move(updated_hosts)); // If there is an initialize callback, fire it now. Note that if the cluster refers to diff --git a/source/extensions/access_loggers/file/config.cc b/source/extensions/access_loggers/file/config.cc index 8490a72eccb04..1228aa5cabf3c 100644 --- a/source/extensions/access_loggers/file/config.cc +++ b/source/extensions/access_loggers/file/config.cc @@ -1,12 +1,12 @@ -#include "extensions/access_loggers/file/config.h" - #include "envoy/config/accesslog/v2/file.pb.validate.h" #include "envoy/registry/registry.h" #include "envoy/server/filter_config.h" #include "common/access_log/access_log_formatter.h" +#include "common/common/logger.h" #include "common/protobuf/protobuf.h" +#include "extensions/access_loggers/file/config.h" #include "extensions/access_loggers/file/file_access_log_impl.h" #include "extensions/access_loggers/well_known_names.h" @@ -22,11 +22,24 @@ FileAccessLogFactory::createAccessLogInstance(const Protobuf::Message& config, const auto& fal_config = MessageUtil::downcastAndValidate(config); AccessLog::FormatterPtr formatter; - if (fal_config.format().empty()) { - formatter = AccessLog::AccessLogFormatUtils::defaultAccessLogFormatter(); + + if (fal_config.access_log_format_case() == envoy::config::accesslog::v2::FileAccessLog::kFormat || + fal_config.access_log_format_case() == + envoy::config::accesslog::v2::FileAccessLog::ACCESS_LOG_FORMAT_NOT_SET) { + if (fal_config.format().empty()) { + formatter = AccessLog::AccessLogFormatUtils::defaultAccessLogFormatter(); + } else { + formatter.reset(new AccessLog::FormatterImpl(fal_config.format())); + } + } else if (fal_config.access_log_format_case() == + envoy::config::accesslog::v2::FileAccessLog::kJsonFormat) { + const auto& json_format_map = this->convert_json_format_to_map(fal_config.json_format()); + formatter.reset(new AccessLog::JsonFormatterImpl(json_format_map)); } else { - formatter.reset(new AccessLog::FormatterImpl(fal_config.format())); + throw EnvoyException( + "Invalid access_log format provided. Only 'format' and 'json_format' are supported."); } + return std::make_shared(fal_config.path(), std::move(filter), std::move(formatter), context.accessLogManager()); } @@ -37,6 +50,18 @@ ProtobufTypes::MessagePtr FileAccessLogFactory::createEmptyConfigProto() { std::string FileAccessLogFactory::name() const { return AccessLogNames::get().File; } +std::map +FileAccessLogFactory::convert_json_format_to_map(ProtobufWkt::Struct json_format) { + std::map output; + for (const auto& pair : json_format.fields()) { + if (pair.second.kind_case() != ProtobufWkt::Value::kStringValue) { + throw EnvoyException("Only string values are supported in the JSON access log format."); + } + output.emplace(pair.first, pair.second.string_value()); + } + return output; +} + /** * Static registration for the file access log. @see RegisterFactory. */ diff --git a/source/extensions/access_loggers/file/config.h b/source/extensions/access_loggers/file/config.h index d3ebf58c352f8..95cf4cf8e08f2 100644 --- a/source/extensions/access_loggers/file/config.h +++ b/source/extensions/access_loggers/file/config.h @@ -19,6 +19,10 @@ class FileAccessLogFactory : public Server::Configuration::AccessLogInstanceFact ProtobufTypes::MessagePtr createEmptyConfigProto() override; std::string name() const override; + +private: + std::map + convert_json_format_to_map(ProtobufWkt::Struct config); }; } // namespace File 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 a0ef56fadae0c..64bcf4b8b9e7b 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,7 @@ -#include "extensions/access_loggers/file/file_access_log_impl.h" - #include "common/http/header_map_impl.h" +#include "extensions/access_loggers/file/file_access_log_impl.h" + namespace Envoy { namespace Extensions { namespace AccessLoggers { @@ -17,7 +17,7 @@ FileAccessLog::FileAccessLog(const std::string& access_log_path, AccessLog::Filt void FileAccessLog::log(const Http::HeaderMap* request_headers, const Http::HeaderMap* response_headers, const Http::HeaderMap* response_trailers, - const RequestInfo::RequestInfo& request_info) { + const StreamInfo::StreamInfo& stream_info) { static Http::HeaderMapImpl empty_headers; if (!request_headers) { request_headers = &empty_headers; @@ -30,13 +30,13 @@ void FileAccessLog::log(const Http::HeaderMap* request_headers, } if (filter_) { - if (!filter_->evaluate(request_info, *request_headers)) { + if (!filter_->evaluate(stream_info, *request_headers)) { return; } } log_file_->write( - formatter_->format(*request_headers, *response_headers, *response_trailers, request_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 472de055b1665..93bee65b0f7ad 100644 --- a/source/extensions/access_loggers/file/file_access_log_impl.h +++ b/source/extensions/access_loggers/file/file_access_log_impl.h @@ -18,7 +18,7 @@ class FileAccessLog : public AccessLog::Instance { // AccessLog::Instance void log(const Http::HeaderMap* request_headers, const Http::HeaderMap* response_headers, const Http::HeaderMap* response_trailers, - const RequestInfo::RequestInfo& request_info) override; + const StreamInfo::StreamInfo& stream_info) override; private: Filesystem::FileSharedPtr log_file_; 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 2453280c35802..ab2bd4d491e24 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,7 @@ #include "common/common/assert.h" #include "common/http/header_map_impl.h" #include "common/network/utility.h" -#include "common/request_info/utility.h" +#include "common/stream_info/utility.h" namespace Envoy { namespace Extensions { @@ -83,66 +83,66 @@ HttpGrpcAccessLog::HttpGrpcAccessLog( void HttpGrpcAccessLog::responseFlagsToAccessLogResponseFlags( envoy::data::accesslog::v2::AccessLogCommon& common_access_log, - const RequestInfo::RequestInfo& request_info) { + const StreamInfo::StreamInfo& stream_info) { - static_assert(RequestInfo::ResponseFlag::LastFlag == 0x2000, + static_assert(StreamInfo::ResponseFlag::LastFlag == 0x2000, "A flag has been added. Fix this code."); - if (request_info.hasResponseFlag(RequestInfo::ResponseFlag::FailedLocalHealthCheck)) { + if (stream_info.hasResponseFlag(StreamInfo::ResponseFlag::FailedLocalHealthCheck)) { common_access_log.mutable_response_flags()->set_failed_local_healthcheck(true); } - if (request_info.hasResponseFlag(RequestInfo::ResponseFlag::NoHealthyUpstream)) { + if (stream_info.hasResponseFlag(StreamInfo::ResponseFlag::NoHealthyUpstream)) { common_access_log.mutable_response_flags()->set_no_healthy_upstream(true); } - if (request_info.hasResponseFlag(RequestInfo::ResponseFlag::UpstreamRequestTimeout)) { + if (stream_info.hasResponseFlag(StreamInfo::ResponseFlag::UpstreamRequestTimeout)) { common_access_log.mutable_response_flags()->set_upstream_request_timeout(true); } - if (request_info.hasResponseFlag(RequestInfo::ResponseFlag::LocalReset)) { + if (stream_info.hasResponseFlag(StreamInfo::ResponseFlag::LocalReset)) { common_access_log.mutable_response_flags()->set_local_reset(true); } - if (request_info.hasResponseFlag(RequestInfo::ResponseFlag::UpstreamRemoteReset)) { + if (stream_info.hasResponseFlag(StreamInfo::ResponseFlag::UpstreamRemoteReset)) { common_access_log.mutable_response_flags()->set_upstream_remote_reset(true); } - if (request_info.hasResponseFlag(RequestInfo::ResponseFlag::UpstreamConnectionFailure)) { + if (stream_info.hasResponseFlag(StreamInfo::ResponseFlag::UpstreamConnectionFailure)) { common_access_log.mutable_response_flags()->set_upstream_connection_failure(true); } - if (request_info.hasResponseFlag(RequestInfo::ResponseFlag::UpstreamConnectionTermination)) { + if (stream_info.hasResponseFlag(StreamInfo::ResponseFlag::UpstreamConnectionTermination)) { common_access_log.mutable_response_flags()->set_upstream_connection_termination(true); } - if (request_info.hasResponseFlag(RequestInfo::ResponseFlag::UpstreamOverflow)) { + if (stream_info.hasResponseFlag(StreamInfo::ResponseFlag::UpstreamOverflow)) { common_access_log.mutable_response_flags()->set_upstream_overflow(true); } - if (request_info.hasResponseFlag(RequestInfo::ResponseFlag::NoRouteFound)) { + if (stream_info.hasResponseFlag(StreamInfo::ResponseFlag::NoRouteFound)) { common_access_log.mutable_response_flags()->set_no_route_found(true); } - if (request_info.hasResponseFlag(RequestInfo::ResponseFlag::DelayInjected)) { + if (stream_info.hasResponseFlag(StreamInfo::ResponseFlag::DelayInjected)) { common_access_log.mutable_response_flags()->set_delay_injected(true); } - if (request_info.hasResponseFlag(RequestInfo::ResponseFlag::FaultInjected)) { + if (stream_info.hasResponseFlag(StreamInfo::ResponseFlag::FaultInjected)) { common_access_log.mutable_response_flags()->set_fault_injected(true); } - if (request_info.hasResponseFlag(RequestInfo::ResponseFlag::RateLimited)) { + if (stream_info.hasResponseFlag(StreamInfo::ResponseFlag::RateLimited)) { common_access_log.mutable_response_flags()->set_rate_limited(true); } - if (request_info.hasResponseFlag(RequestInfo::ResponseFlag::UnauthorizedExternalService)) { + if (stream_info.hasResponseFlag(StreamInfo::ResponseFlag::UnauthorizedExternalService)) { common_access_log.mutable_response_flags()->mutable_unauthorized_details()->set_reason( envoy::data::accesslog::v2::ResponseFlags_Unauthorized_Reason:: ResponseFlags_Unauthorized_Reason_EXTERNAL_SERVICE); } - if (request_info.hasResponseFlag(RequestInfo::ResponseFlag::RateLimitServiceError)) { + if (stream_info.hasResponseFlag(StreamInfo::ResponseFlag::RateLimitServiceError)) { common_access_log.mutable_response_flags()->set_rate_limit_service_error(true); } } @@ -150,7 +150,7 @@ void HttpGrpcAccessLog::responseFlagsToAccessLogResponseFlags( void HttpGrpcAccessLog::log(const Http::HeaderMap* request_headers, const Http::HeaderMap* response_headers, const Http::HeaderMap* response_trailers, - const RequestInfo::RequestInfo& request_info) { + const StreamInfo::StreamInfo& stream_info) { static Http::HeaderMapImpl empty_headers; if (!request_headers) { request_headers = &empty_headers; @@ -163,7 +163,7 @@ void HttpGrpcAccessLog::log(const Http::HeaderMap* request_headers, } if (filter_) { - if (!filter_->evaluate(request_info, *request_headers)) { + if (!filter_->evaluate(stream_info, *request_headers)) { return; } } @@ -177,78 +177,78 @@ void HttpGrpcAccessLog::log(const Http::HeaderMap* request_headers, // TODO(mattklein123): Populate metadata field and wire up to filters. auto* common_properties = log_entry->mutable_common_properties(); - if (request_info.downstreamRemoteAddress() != nullptr) { + if (stream_info.downstreamRemoteAddress() != nullptr) { Network::Utility::addressToProtobufAddress( - *request_info.downstreamRemoteAddress(), + *stream_info.downstreamRemoteAddress(), *common_properties->mutable_downstream_remote_address()); } - if (request_info.downstreamLocalAddress() != nullptr) { + if (stream_info.downstreamLocalAddress() != nullptr) { Network::Utility::addressToProtobufAddress( - *request_info.downstreamLocalAddress(), + *stream_info.downstreamLocalAddress(), *common_properties->mutable_downstream_local_address()); } common_properties->mutable_start_time()->MergeFrom( Protobuf::util::TimeUtil::NanosecondsToTimestamp( std::chrono::duration_cast( - request_info.startTime().time_since_epoch()) + stream_info.startTime().time_since_epoch()) .count())); - absl::optional dur = request_info.lastDownstreamRxByteReceived(); + absl::optional dur = stream_info.lastDownstreamRxByteReceived(); if (dur) { common_properties->mutable_time_to_last_rx_byte()->MergeFrom( Protobuf::util::TimeUtil::NanosecondsToDuration(dur.value().count())); } - dur = request_info.firstUpstreamTxByteSent(); + dur = stream_info.firstUpstreamTxByteSent(); if (dur) { common_properties->mutable_time_to_first_upstream_tx_byte()->MergeFrom( Protobuf::util::TimeUtil::NanosecondsToDuration(dur.value().count())); } - dur = request_info.lastUpstreamTxByteSent(); + dur = stream_info.lastUpstreamTxByteSent(); if (dur) { common_properties->mutable_time_to_last_upstream_tx_byte()->MergeFrom( Protobuf::util::TimeUtil::NanosecondsToDuration(dur.value().count())); } - dur = request_info.firstUpstreamRxByteReceived(); + dur = stream_info.firstUpstreamRxByteReceived(); if (dur) { common_properties->mutable_time_to_first_upstream_rx_byte()->MergeFrom( Protobuf::util::TimeUtil::NanosecondsToDuration(dur.value().count())); } - dur = request_info.lastUpstreamRxByteReceived(); + dur = stream_info.lastUpstreamRxByteReceived(); if (dur) { common_properties->mutable_time_to_last_upstream_rx_byte()->MergeFrom( Protobuf::util::TimeUtil::NanosecondsToDuration(dur.value().count())); } - dur = request_info.firstDownstreamTxByteSent(); + dur = stream_info.firstDownstreamTxByteSent(); if (dur) { common_properties->mutable_time_to_first_downstream_tx_byte()->MergeFrom( Protobuf::util::TimeUtil::NanosecondsToDuration(dur.value().count())); } - dur = request_info.lastDownstreamTxByteSent(); + dur = stream_info.lastDownstreamTxByteSent(); if (dur) { common_properties->mutable_time_to_last_downstream_tx_byte()->MergeFrom( Protobuf::util::TimeUtil::NanosecondsToDuration(dur.value().count())); } - if (request_info.upstreamHost() != nullptr) { + if (stream_info.upstreamHost() != nullptr) { Network::Utility::addressToProtobufAddress( - *request_info.upstreamHost()->address(), + *stream_info.upstreamHost()->address(), *common_properties->mutable_upstream_remote_address()); - common_properties->set_upstream_cluster(request_info.upstreamHost()->cluster().name()); + common_properties->set_upstream_cluster(stream_info.upstreamHost()->cluster().name()); } - if (request_info.upstreamLocalAddress() != nullptr) { + if (stream_info.upstreamLocalAddress() != nullptr) { Network::Utility::addressToProtobufAddress( - *request_info.upstreamLocalAddress(), *common_properties->mutable_upstream_local_address()); + *stream_info.upstreamLocalAddress(), *common_properties->mutable_upstream_local_address()); } - responseFlagsToAccessLogResponseFlags(*common_properties, request_info); + responseFlagsToAccessLogResponseFlags(*common_properties, stream_info); - if (request_info.protocol()) { - switch (request_info.protocol().value()) { + if (stream_info.protocol()) { + switch (stream_info.protocol().value()) { case Http::Protocol::Http10: log_entry->set_protocol_version(envoy::data::accesslog::v2::HTTPAccessLogEntry::HTTP10); break; @@ -289,7 +289,7 @@ void HttpGrpcAccessLog::log(const Http::HeaderMap* request_headers, request_properties->set_original_path(request_headers->EnvoyOriginalPath()->value().c_str()); } request_properties->set_request_headers_bytes(request_headers->byteSize()); - request_properties->set_request_body_bytes(request_info.bytesReceived()); + request_properties->set_request_body_bytes(stream_info.bytesReceived()); if (request_headers->Method() != nullptr) { envoy::api::v2::core::RequestMethod method = envoy::api::v2::core::RequestMethod::METHOD_UNSPECIFIED; @@ -310,11 +310,11 @@ void HttpGrpcAccessLog::log(const Http::HeaderMap* request_headers, // HTTP response properties. auto* response_properties = log_entry->mutable_response(); - if (request_info.responseCode()) { - response_properties->mutable_response_code()->set_value(request_info.responseCode().value()); + if (stream_info.responseCode()) { + response_properties->mutable_response_code()->set_value(stream_info.responseCode().value()); } response_properties->set_response_headers_bytes(response_headers->byteSize()); - response_properties->set_response_body_bytes(request_info.bytesSent()); + response_properties->set_response_body_bytes(stream_info.bytesSent()); if (!response_headers_to_log_.empty()) { auto* logged_headers = response_properties->mutable_response_headers(); 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 9e5f8383fb74c..328bfe6f2b2fc 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 @@ -119,12 +119,12 @@ class HttpGrpcAccessLog : public AccessLog::Instance { static void responseFlagsToAccessLogResponseFlags( envoy::data::accesslog::v2::AccessLogCommon& common_access_log, - const RequestInfo::RequestInfo& request_info); + 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 RequestInfo::RequestInfo& request_info) override; + const StreamInfo::StreamInfo& stream_info) override; private: AccessLog::FilterPtr filter_; diff --git a/source/extensions/extensions_build_config.bzl b/source/extensions/extensions_build_config.bzl index f3d7f9ef60d25..d18bfd70061a5 100644 --- a/source/extensions/extensions_build_config.bzl +++ b/source/extensions/extensions_build_config.bzl @@ -112,6 +112,9 @@ EXTENSIONS = { # Retry host predicates "envoy.retry_host_predicates.other_hosts": "//source/extensions/retry/host/other_hosts:config", + + # Retry priorities + "envoy.retry_priorities.previous_priorities": "//source/extensions/retry/priority/other_priority:config", } WINDOWS_EXTENSIONS = { diff --git a/source/extensions/filters/common/ext_authz/check_request_utils.cc b/source/extensions/filters/common/ext_authz/check_request_utils.cc index 90f82d372def4..4935c2b78e526 100644 --- a/source/extensions/filters/common/ext_authz/check_request_utils.cc +++ b/source/extensions/filters/common/ext_authz/check_request_utils.cc @@ -93,12 +93,12 @@ void CheckRequestUtils::setHttpRequest( // Set size // need to convert to google buffer 64t; - httpreq.set_size(sdfc->requestInfo().bytesReceived()); + httpreq.set_size(sdfc->streamInfo().bytesReceived()); // Set protocol - if (sdfc->requestInfo().protocol()) { + if (sdfc->streamInfo().protocol()) { httpreq.set_protocol( - Envoy::Http::Utility::getProtocolString(sdfc->requestInfo().protocol().value())); + Envoy::Http::Utility::getProtocolString(sdfc->streamInfo().protocol().value())); } // Fill in the headers diff --git a/source/extensions/filters/http/ext_authz/ext_authz.cc b/source/extensions/filters/http/ext_authz/ext_authz.cc index a14a6c8706331..2f241bc91c0de 100644 --- a/source/extensions/filters/http/ext_authz/ext_authz.cc +++ b/source/extensions/filters/http/ext_authz/ext_authz.cc @@ -113,8 +113,7 @@ void Filter::onComplete(Filters::Common::ExtAuthz::ResponsePtr&& response) { header.first.get(), header.second); } }); - callbacks_->requestInfo().setResponseFlag( - RequestInfo::ResponseFlag::UnauthorizedExternalService); + callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::UnauthorizedExternalService); } else { ENVOY_STREAM_LOG(debug, "ext_authz accepted the request", *callbacks_); // Let the filter chain continue. diff --git a/source/extensions/filters/http/fault/fault_filter.cc b/source/extensions/filters/http/fault/fault_filter.cc index 5301565895612..e1bbc9de47ae1 100644 --- a/source/extensions/filters/http/fault/fault_filter.cc +++ b/source/extensions/filters/http/fault/fault_filter.cc @@ -34,15 +34,14 @@ const std::string FaultFilter::ABORT_HTTP_STATUS_KEY = "fault.http.abort.http_st FaultSettings::FaultSettings(const envoy::config::filter::http::fault::v2::HTTPFault& fault) { if (fault.has_abort()) { - PROTOBUF_SET_FRACTIONAL_PERCENT_OR_DEFAULT(abort_percentage_, fault.abort(), percentage, - percent); - http_status_ = fault.abort().http_status(); + const auto& abort = fault.abort(); + abort_percentage_ = abort.percentage(); + http_status_ = abort.http_status(); } if (fault.has_delay()) { - PROTOBUF_SET_FRACTIONAL_PERCENT_OR_DEFAULT(fixed_delay_percentage_, fault.delay(), percentage, - percent); const auto& delay = fault.delay(); + fixed_delay_percentage_ = delay.percentage(); fixed_duration_ms_ = PROTOBUF_GET_MS_OR_DEFAULT(delay, fixed_delay, 0); } @@ -118,7 +117,7 @@ Http::FilterHeadersStatus FaultFilter::decodeHeaders(Http::HeaderMap& headers, b delay_timer_ = callbacks_->dispatcher().createTimer([this]() -> void { postDelayInjection(); }); delay_timer_->enableTimer(std::chrono::milliseconds(duration_ms.value())); recordDelaysInjectedStats(); - callbacks_->requestInfo().setResponseFlag(RequestInfo::ResponseFlag::DelayInjected); + callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::DelayInjected); return Http::FilterHeadersStatus::StopIteration; } @@ -134,13 +133,14 @@ bool FaultFilter::isDelayEnabled() { bool enabled = config_->runtime().snapshot().featureEnabled( DELAY_PERCENT_KEY, fault_settings_->delayPercentage().numerator(), config_->randomGenerator().random(), - ProtobufPercentHelper::fractionalPercentDenominatorToInt(fault_settings_->delayPercentage())); + ProtobufPercentHelper::fractionalPercentDenominatorToInt( + fault_settings_->delayPercentage().denominator())); if (!downstream_cluster_delay_percent_key_.empty()) { enabled |= config_->runtime().snapshot().featureEnabled( downstream_cluster_delay_percent_key_, fault_settings_->delayPercentage().numerator(), config_->randomGenerator().random(), ProtobufPercentHelper::fractionalPercentDenominatorToInt( - fault_settings_->delayPercentage())); + fault_settings_->delayPercentage().denominator())); } return enabled; } @@ -149,13 +149,14 @@ bool FaultFilter::isAbortEnabled() { bool enabled = config_->runtime().snapshot().featureEnabled( ABORT_PERCENT_KEY, fault_settings_->abortPercentage().numerator(), config_->randomGenerator().random(), - ProtobufPercentHelper::fractionalPercentDenominatorToInt(fault_settings_->abortPercentage())); + ProtobufPercentHelper::fractionalPercentDenominatorToInt( + fault_settings_->abortPercentage().denominator())); if (!downstream_cluster_abort_percent_key_.empty()) { enabled |= config_->runtime().snapshot().featureEnabled( downstream_cluster_abort_percent_key_, fault_settings_->abortPercentage().numerator(), config_->randomGenerator().random(), ProtobufPercentHelper::fractionalPercentDenominatorToInt( - fault_settings_->abortPercentage())); + fault_settings_->abortPercentage().denominator())); } return enabled; } @@ -254,7 +255,7 @@ void FaultFilter::postDelayInjection() { } void FaultFilter::abortWithHTTPStatus() { - callbacks_->requestInfo().setResponseFlag(RequestInfo::ResponseFlag::FaultInjected); + callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::FaultInjected); callbacks_->sendLocalReply(static_cast(abortHttpStatus()), "fault filter abort", nullptr); recordAbortsInjectedStats(); 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 ce8d53a69e161..cb9905c0d32c5 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 @@ -30,7 +30,7 @@ Http::FilterHeadersStatus Http1BridgeFilter::decodeHeaders(Http::HeaderMap& head setupStatTracking(headers); } - const absl::optional& protocol = decoder_callbacks_->requestInfo().protocol(); + const absl::optional& protocol = decoder_callbacks_->streamInfo().protocol(); ASSERT(protocol); if (protocol.value() != Http::Protocol::Http2 && grpc_request) { do_bridging_ = true; 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 9c25d0f439c06..bc765c6f2f5ac 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 @@ -399,7 +399,7 @@ Http::FilterTrailersStatus JsonTranscoderFilter::encodeTrailers(Http::HeaderMap& } // remove Trailer headers if the client connection was http/1 - if (encoder_callbacks_->requestInfo().protocol() != Http::Protocol::Http2) { + if (encoder_callbacks_->streamInfo().protocol() != Http::Protocol::Http2) { static const Http::LowerCaseString trailer_key = Http::LowerCaseString("trailer"); response_headers_->remove(trailer_key); } diff --git a/source/extensions/filters/http/header_to_metadata/header_to_metadata_filter.cc b/source/extensions/filters/http/header_to_metadata/header_to_metadata_filter.cc index 722c0d16a59da..cce3aeff1bec4 100644 --- a/source/extensions/filters/http/header_to_metadata/header_to_metadata_filter.cc +++ b/source/extensions/filters/http/header_to_metadata/header_to_metadata_filter.cc @@ -176,7 +176,7 @@ void HeaderToMetadataFilter::writeHeaderToMetadata(Http::HeaderMap& headers, // Any matching rules? if (structs_by_namespace.size() > 0) { for (auto const& entry : structs_by_namespace) { - callbacks.requestInfo().setDynamicMetadata(entry.first, entry.second); + callbacks.streamInfo().setDynamicMetadata(entry.first, entry.second); } } } 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 707e85a8d5067..da37835f8dc0c 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 @@ -108,7 +108,7 @@ class HeaderToMetadataFilter : public Http::StreamFilter, * request headers depending on whether this is called from the encode state or * decode state. * @param rules the header-to-metadata mapping set in configuration. - * @param callbacks the callback used to fetch the RequestInfo (which is then used to get + * @param callbacks the callback used to fetch the StreamInfo (which is then used to get * metadata). Callable with both encoder_callbacks_ and decoder_callbacks_. */ void writeHeaderToMetadata(Http::HeaderMap& headers, const HeaderToMetadataRules& rules, diff --git a/source/extensions/filters/http/health_check/health_check.cc b/source/extensions/filters/http/health_check/health_check.cc index ec55410d2a38f..9d0e3f3205e97 100644 --- a/source/extensions/filters/http/health_check/health_check.cc +++ b/source/extensions/filters/http/health_check/health_check.cc @@ -36,7 +36,7 @@ Http::FilterHeadersStatus HealthCheckFilter::decodeHeaders(Http::HeaderMap& head bool end_stream) { if (Http::HeaderUtility::matchHeaders(headers, *header_match_data_)) { health_check_request_ = true; - callbacks_->requestInfo().healthCheck(true); + callbacks_->streamInfo().healthCheck(true); // Set the 'sampled' status for the span to false. This overrides // any previous sampling decision associated with the trace instance, @@ -97,7 +97,7 @@ void HealthCheckFilter::onComplete() { ASSERT(handling_); Http::Code final_status = Http::Code::OK; if (context_.healthCheckFailed()) { - callbacks_->requestInfo().setResponseFlag(RequestInfo::ResponseFlag::FailedLocalHealthCheck); + callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::FailedLocalHealthCheck); final_status = Http::Code::ServiceUnavailable; } else { if (cache_manager_) { @@ -139,7 +139,7 @@ void HealthCheckFilter::onComplete() { } if (!Http::CodeUtility::is2xx(enumToInt(final_status))) { - callbacks_->requestInfo().setResponseFlag(RequestInfo::ResponseFlag::FailedLocalHealthCheck); + callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::FailedLocalHealthCheck); } } 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 22be63eeb4527..9b43ab02a1217 100644 --- a/source/extensions/filters/http/ip_tagging/ip_tagging_filter.cc +++ b/source/extensions/filters/http/ip_tagging/ip_tagging_filter.cc @@ -28,7 +28,7 @@ Http::FilterHeadersStatus IpTaggingFilter::decodeHeaders(Http::HeaderMap& header } std::vector tags = - config_->trie().getData(callbacks_->requestInfo().downstreamRemoteAddress()); + config_->trie().getData(callbacks_->streamInfo().downstreamRemoteAddress()); if (!tags.empty()) { const std::string tags_join = absl::StrJoin(tags, ","); diff --git a/source/extensions/filters/http/lua/BUILD b/source/extensions/filters/http/lua/BUILD index fbb03ed551fef..de27cd3a70471 100644 --- a/source/extensions/filters/http/lua/BUILD +++ b/source/extensions/filters/http/lua/BUILD @@ -35,7 +35,7 @@ envoy_cc_library( hdrs = ["wrappers.h"], deps = [ "//include/envoy/http:header_map_interface", - "//include/envoy/request_info:request_info_interface", + "//include/envoy/stream_info:stream_info_interface", "//source/common/http:utility_lib", "//source/extensions/filters/common/lua:lua_lib", "//source/extensions/filters/common/lua:wrappers_lib", diff --git a/source/extensions/filters/http/lua/lua_filter.cc b/source/extensions/filters/http/lua/lua_filter.cc index fe6b8ab286bb3..9a9a453b79589 100644 --- a/source/extensions/filters/http/lua/lua_filter.cc +++ b/source/extensions/filters/http/lua/lua_filter.cc @@ -367,12 +367,12 @@ int StreamHandleWrapper::luaMetadata(lua_State* state) { return 1; } -int StreamHandleWrapper::luaRequestInfo(lua_State* state) { +int StreamHandleWrapper::luaStreamInfo(lua_State* state) { ASSERT(state_ == State::Running); - if (request_info_wrapper_.get() != nullptr) { - request_info_wrapper_.pushStack(); + if (stream_info_wrapper_.get() != nullptr) { + stream_info_wrapper_.pushStack(); } else { - request_info_wrapper_.reset(RequestInfoWrapper::create(state, callbacks_.requestInfo()), true); + stream_info_wrapper_.reset(StreamInfoWrapper::create(state, callbacks_.streamInfo()), true); } return 1; } @@ -434,7 +434,7 @@ FilterConfig::FilterConfig(const std::string& lua_code, ThreadLocal::SlotAllocat lua_state_.registerType(); lua_state_.registerType(); lua_state_.registerType(); - lua_state_.registerType(); + lua_state_.registerType(); lua_state_.registerType(); lua_state_.registerType(); lua_state_.registerType(); diff --git a/source/extensions/filters/http/lua/lua_filter.h b/source/extensions/filters/http/lua/lua_filter.h index 8616ad0a87124..2776ee9956556 100644 --- a/source/extensions/filters/http/lua/lua_filter.h +++ b/source/extensions/filters/http/lua/lua_filter.h @@ -70,10 +70,10 @@ class FilterCallbacks { virtual const ProtobufWkt::Struct& metadata() const PURE; /** - * @return RequestInfo::RequestInfo& the current request info handle. This handle is mutable to + * @return StreamInfo::StreamInfo& the current stream info handle. This handle is mutable to * accommodate write API e.g. setDynamicMetadata(). */ - virtual RequestInfo::RequestInfo& requestInfo() PURE; + virtual StreamInfo::StreamInfo& streamInfo() PURE; /** * @return const const Network::Connection* the current network connection handle. @@ -133,7 +133,7 @@ class StreamHandleWrapper : public Filters::Common::Lua::BaseLuaObject body_wrapper_; Filters::Common::Lua::LuaDeathRef trailers_wrapper_; Filters::Common::Lua::LuaDeathRef metadata_wrapper_; - Filters::Common::Lua::LuaDeathRef request_info_wrapper_; + Filters::Common::Lua::LuaDeathRef stream_info_wrapper_; Filters::Common::Lua::LuaDeathRef connection_wrapper_; State state_{State::Running}; std::function yield_callback_; @@ -338,7 +338,7 @@ class Filter : public Http::StreamFilter, Logger::Loggable { void respond(Http::HeaderMapPtr&& headers, Buffer::Instance* body, lua_State* state) override; const ProtobufWkt::Struct& metadata() const override { return getMetadata(callbacks_); } - RequestInfo::RequestInfo& requestInfo() override { return callbacks_->requestInfo(); } + StreamInfo::StreamInfo& streamInfo() override { return callbacks_->streamInfo(); } const Network::Connection* connection() const override { return callbacks_->connection(); } Filter& parent_; @@ -358,7 +358,7 @@ class Filter : public Http::StreamFilter, Logger::Loggable { void respond(Http::HeaderMapPtr&& headers, Buffer::Instance* body, lua_State* state) override; const ProtobufWkt::Struct& metadata() const override { return getMetadata(callbacks_); } - RequestInfo::RequestInfo& requestInfo() override { return callbacks_->requestInfo(); } + StreamInfo::StreamInfo& streamInfo() override { return callbacks_->streamInfo(); } const Network::Connection* connection() const override { return callbacks_->connection(); } Filter& parent_; diff --git a/source/extensions/filters/http/lua/wrappers.cc b/source/extensions/filters/http/lua/wrappers.cc index 62924f4f4fa0b..cec3f527dc3b9 100644 --- a/source/extensions/filters/http/lua/wrappers.cc +++ b/source/extensions/filters/http/lua/wrappers.cc @@ -104,12 +104,12 @@ void HeaderMapWrapper::checkModifiable(lua_State* state) { } } -int RequestInfoWrapper::luaProtocol(lua_State* state) { - lua_pushstring(state, Http::Utility::getProtocolString(request_info_.protocol().value()).c_str()); +int StreamInfoWrapper::luaProtocol(lua_State* state) { + lua_pushstring(state, Http::Utility::getProtocolString(stream_info_.protocol().value()).c_str()); return 1; } -int RequestInfoWrapper::luaDynamicMetadata(lua_State* state) { +int StreamInfoWrapper::luaDynamicMetadata(lua_State* state) { if (dynamic_metadata_wrapper_.get() != nullptr) { dynamic_metadata_wrapper_.pushStack(); } else { @@ -119,13 +119,12 @@ int RequestInfoWrapper::luaDynamicMetadata(lua_State* state) { } DynamicMetadataMapIterator::DynamicMetadataMapIterator(DynamicMetadataMapWrapper& parent) - : parent_{parent}, current_{parent_.requestInfo().dynamicMetadata().filter_metadata().begin()} { -} + : parent_{parent}, current_{parent_.streamInfo().dynamicMetadata().filter_metadata().begin()} {} -RequestInfo::RequestInfo& DynamicMetadataMapWrapper::requestInfo() { return parent_.request_info_; } +StreamInfo::StreamInfo& DynamicMetadataMapWrapper::streamInfo() { return parent_.stream_info_; } int DynamicMetadataMapIterator::luaPairsIterator(lua_State* state) { - if (current_ == parent_.requestInfo().dynamicMetadata().filter_metadata().end()) { + if (current_ == parent_.streamInfo().dynamicMetadata().filter_metadata().end()) { parent_.iterator_.reset(); return 0; } @@ -139,7 +138,7 @@ int DynamicMetadataMapIterator::luaPairsIterator(lua_State* state) { int DynamicMetadataMapWrapper::luaGet(lua_State* state) { const char* filter_name = luaL_checkstring(state, 2); - const auto& metadata = requestInfo().dynamicMetadata().filter_metadata(); + const auto& metadata = streamInfo().dynamicMetadata().filter_metadata(); const auto filter_it = metadata.find(filter_name); if (filter_it == metadata.end()) { return 0; @@ -158,7 +157,7 @@ int DynamicMetadataMapWrapper::luaSet(lua_State* state) { const char* filter_name = luaL_checkstring(state, 2); const char* key = luaL_checkstring(state, 3); const char* value = luaL_checkstring(state, 4); - requestInfo().setDynamicMetadata(filter_name, MessageUtil::keyValueStruct(key, value)); + streamInfo().setDynamicMetadata(filter_name, MessageUtil::keyValueStruct(key, value)); return 0; } diff --git a/source/extensions/filters/http/lua/wrappers.h b/source/extensions/filters/http/lua/wrappers.h index b1dff2962e0fc..b8644afc3dda3 100644 --- a/source/extensions/filters/http/lua/wrappers.h +++ b/source/extensions/filters/http/lua/wrappers.h @@ -1,7 +1,7 @@ #pragma once #include "envoy/http/header_map.h" -#include "envoy/request_info/request_info.h" +#include "envoy/stream_info/stream_info.h" #include "extensions/filters/common/lua/lua.h" @@ -100,7 +100,7 @@ class HeaderMapWrapper : public Filters::Common::Lua::BaseLuaObject { public: - DynamicMetadataMapWrapper(RequestInfoWrapper& parent) : parent_{parent} {} + DynamicMetadataMapWrapper(StreamInfoWrapper& parent) : parent_{parent} {} static ExportedFunctions exportedFunctions() { return {{"get", static_luaGet}, {"set", static_luaSet}, {"__pairs", static_luaPairs}}; @@ -160,21 +160,21 @@ class DynamicMetadataMapWrapper iterator_.reset(); } - // To get reference to parent's (RequestInfoWrapper) request info member. - RequestInfo::RequestInfo& requestInfo(); + // To get reference to parent's (StreamInfoWrapper) stream info member. + StreamInfo::StreamInfo& streamInfo(); - RequestInfoWrapper& parent_; + StreamInfoWrapper& parent_; Filters::Common::Lua::LuaDeathRef iterator_; friend class DynamicMetadataMapIterator; }; /** - * Lua wrapper for a request info. + * Lua wrapper for a stream info. */ -class RequestInfoWrapper : public Filters::Common::Lua::BaseLuaObject { +class StreamInfoWrapper : public Filters::Common::Lua::BaseLuaObject { public: - RequestInfoWrapper(RequestInfo::RequestInfo& request_info) : request_info_{request_info} {} + StreamInfoWrapper(StreamInfo::StreamInfo& stream_info) : stream_info_{stream_info} {} static ExportedFunctions exportedFunctions() { return {{"protocol", static_luaProtocol}, {"dynamicMetadata", static_luaDynamicMetadata}}; } @@ -184,18 +184,18 @@ class RequestInfoWrapper : public Filters::Common::Lua::BaseLuaObject dynamic_metadata_wrapper_; friend class DynamicMetadataMapWrapper; diff --git a/source/extensions/filters/http/ratelimit/ratelimit.cc b/source/extensions/filters/http/ratelimit/ratelimit.cc index d1b31f67e7268..854c784a21e44 100644 --- a/source/extensions/filters/http/ratelimit/ratelimit.cc +++ b/source/extensions/filters/http/ratelimit/ratelimit.cc @@ -146,7 +146,7 @@ void Filter::complete(RateLimit::LimitStatus status, Http::HeaderMapPtr&& header state_ = State::Responded; callbacks_->sendLocalReply(Http::Code::TooManyRequests, "", [this](Http::HeaderMap& headers) { addHeaders(headers); }); - callbacks_->requestInfo().setResponseFlag(RequestInfo::ResponseFlag::RateLimited); + callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::RateLimited); } else if (status == RateLimit::LimitStatus::Error) { if (config_->failureModeAllow()) { cluster_->statsScope().counter("ratelimit.failure_mode_allowed").inc(); @@ -156,7 +156,7 @@ void Filter::complete(RateLimit::LimitStatus status, Http::HeaderMapPtr&& header } else { state_ = State::Responded; callbacks_->sendLocalReply(Http::Code::InternalServerError, "", nullptr); - callbacks_->requestInfo().setResponseFlag(RequestInfo::ResponseFlag::RateLimitServiceError); + callbacks_->streamInfo().setResponseFlag(StreamInfo::ResponseFlag::RateLimitServiceError); } } else if (!initiating_call_) { callbacks_->continueDecoding(); @@ -176,7 +176,7 @@ void Filter::populateRateLimitDescriptors(const Router::RateLimitPolicy& rate_li continue; } rate_limit.populateDescriptors(*route_entry, descriptors, config_->localInfo().clusterName(), - headers, *callbacks_->requestInfo().downstreamRemoteAddress()); + headers, *callbacks_->streamInfo().downstreamRemoteAddress()); } } diff --git a/source/extensions/filters/http/rbac/rbac_filter.cc b/source/extensions/filters/http/rbac/rbac_filter.cc index 8c1c17272d8b0..4da15b4202c41 100644 --- a/source/extensions/filters/http/rbac/rbac_filter.cc +++ b/source/extensions/filters/http/rbac/rbac_filter.cc @@ -62,7 +62,7 @@ Http::FilterHeadersStatus RoleBasedAccessControlFilter::decodeHeaders(Http::Head ", subjectPeerCertificate: " + callbacks_->connection()->ssl()->subjectPeerCertificate() : "none", - headers, callbacks_->requestInfo().dynamicMetadata().DebugString()); + headers, callbacks_->streamInfo().dynamicMetadata().DebugString()); std::string effective_policy_id; const auto& shadow_engine = @@ -71,7 +71,7 @@ Http::FilterHeadersStatus RoleBasedAccessControlFilter::decodeHeaders(Http::Head if (shadow_engine.has_value()) { std::string shadow_resp_code = resp_code_200; if (shadow_engine->allowed(*callbacks_->connection(), headers, - callbacks_->requestInfo().dynamicMetadata(), &effective_policy_id)) { + callbacks_->streamInfo().dynamicMetadata(), &effective_policy_id)) { ENVOY_LOG(debug, "shadow allowed"); config_->stats().shadow_allowed_.inc(); } else { @@ -89,14 +89,14 @@ Http::FilterHeadersStatus RoleBasedAccessControlFilter::decodeHeaders(Http::Head *fields[shadow_resp_code_field].mutable_string_value() = shadow_resp_code; - callbacks_->requestInfo().setDynamicMetadata(HttpFilterNames::get().Rbac, metrics); + callbacks_->streamInfo().setDynamicMetadata(HttpFilterNames::get().Rbac, metrics); } const auto& engine = config_->engine(callbacks_->route(), Filters::Common::RBAC::EnforcementMode::Enforced); if (engine.has_value()) { if (engine->allowed(*callbacks_->connection(), headers, - callbacks_->requestInfo().dynamicMetadata(), nullptr)) { + callbacks_->streamInfo().dynamicMetadata(), nullptr)) { ENVOY_LOG(debug, "enforced allowed"); config_->stats().allowed_.inc(); return Http::FilterHeadersStatus::Continue; diff --git a/source/extensions/filters/network/mongo_proxy/proxy.cc b/source/extensions/filters/network/mongo_proxy/proxy.cc index 4b72b96a0e62f..3c01ced80cf4d 100644 --- a/source/extensions/filters/network/mongo_proxy/proxy.cc +++ b/source/extensions/filters/network/mongo_proxy/proxy.cc @@ -326,7 +326,7 @@ absl::optional ProxyFilter::delayDuration() { fault_config_->delayPercentage().numerator(), generator_.random(), ProtobufPercentHelper::fractionalPercentDenominatorToInt( - fault_config_->delayPercentage()))) { + fault_config_->delayPercentage().denominator()))) { return result; } diff --git a/source/extensions/filters/network/mongo_proxy/proxy.h b/source/extensions/filters/network/mongo_proxy/proxy.h index f413889b3cfb2..5354ee198ca66 100644 --- a/source/extensions/filters/network/mongo_proxy/proxy.h +++ b/source/extensions/filters/network/mongo_proxy/proxy.h @@ -104,10 +104,8 @@ typedef std::shared_ptr AccessLogSharedPtr; class FaultConfig { public: FaultConfig(const envoy::config::filter::fault::v2::FaultDelay& fault_config) - : duration_ms_(PROTOBUF_GET_MS_REQUIRED(fault_config, fixed_delay)) { - PROTOBUF_SET_FRACTIONAL_PERCENT_OR_DEFAULT(delay_percentage_, fault_config, percentage, - percent); - } + : delay_percentage_(fault_config.percentage()), + duration_ms_(PROTOBUF_GET_MS_REQUIRED(fault_config, fixed_delay)) {} envoy::type::FractionalPercent delayPercentage() const { return delay_percentage_; } uint64_t delayDuration() const { return duration_ms_; } diff --git a/source/extensions/retry/host/other_hosts/config.h b/source/extensions/retry/host/other_hosts/config.h index 391b24b0169a2..b8bac31cc18cb 100644 --- a/source/extensions/retry/host/other_hosts/config.h +++ b/source/extensions/retry/host/other_hosts/config.h @@ -18,6 +18,10 @@ class OtherHostsRetryPredicateFactory : public Upstream::RetryHostPredicateFacto } std::string name() override { return RetryHostPredicateValues::get().PreviousHostsPredicate; } + + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return ProtobufTypes::MessagePtr{new Envoy::ProtobufWkt::Empty()}; + } }; } // namespace Host diff --git a/source/extensions/retry/priority/BUILD b/source/extensions/retry/priority/BUILD new file mode 100644 index 0000000000000..6156949edef64 --- /dev/null +++ b/source/extensions/retry/priority/BUILD @@ -0,0 +1,17 @@ +licenses(["notice"]) # Apache 2 + +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_package", +) + +envoy_package() + +envoy_cc_library( + name = "well_known_names", + hdrs = ["well_known_names.h"], + deps = [ + "//source/common/singleton:const_singleton", + ], +) diff --git a/source/extensions/retry/priority/other_priority/BUILD b/source/extensions/retry/priority/other_priority/BUILD new file mode 100644 index 0000000000000..6014100d4b4a0 --- /dev/null +++ b/source/extensions/retry/priority/other_priority/BUILD @@ -0,0 +1,33 @@ +licenses(["notice"]) # Apache 2 + +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_package", +) + +envoy_package() + +envoy_cc_library( + name = "other_priority_lib", + srcs = ["other_priority.cc"], + hdrs = ["other_priority.h"], + deps = [ + "//include/envoy/upstream:retry_interface", + "//source/common/upstream:load_balancer_lib", + ], +) + +envoy_cc_library( + name = "config", + srcs = ["config.cc"], + hdrs = ["config.h"], + deps = [ + ":other_priority_lib", + "//include/envoy/registry", + "//include/envoy/upstream:retry_interface", + "//source/common/protobuf", + "//source/extensions/retry/priority:well_known_names", + "@envoy_api//envoy/config/retry/other_priority:other_priority_cc", + ], +) diff --git a/source/extensions/retry/priority/other_priority/config.cc b/source/extensions/retry/priority/other_priority/config.cc new file mode 100644 index 0000000000000..345e482b048ab --- /dev/null +++ b/source/extensions/retry/priority/other_priority/config.cc @@ -0,0 +1,28 @@ +#include "extensions/retry/priority/other_priority/config.h" + +#include "envoy/config/retry/other_priority/other_priority_config.pb.validate.h" +#include "envoy/registry/registry.h" +#include "envoy/upstream/retry.h" + +namespace Envoy { +namespace Extensions { +namespace Retry { +namespace Priority { + +void OtherPriorityRetryPriorityFactory::createRetryPriority( + Upstream::RetryPriorityFactoryCallbacks& callbacks, const Protobuf::Message& config, + uint32_t max_retries) { + callbacks.addRetryPriority(std::make_shared( + MessageUtil::downcastAndValidate< + const envoy::config::retry::other_priority::OtherPriorityConfig&>(config) + .update_frequency(), + max_retries)); +} + +static Registry::RegisterFactory + register_; + +} // namespace Priority +} // namespace Retry +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/retry/priority/other_priority/config.h b/source/extensions/retry/priority/other_priority/config.h new file mode 100644 index 0000000000000..ece9c89b055a7 --- /dev/null +++ b/source/extensions/retry/priority/other_priority/config.h @@ -0,0 +1,34 @@ +#pragma once + +#include "envoy/config/retry/other_priority/other_priority_config.pb.validate.h" +#include "envoy/upstream/retry.h" + +#include "common/protobuf/protobuf.h" + +#include "extensions/retry/priority/other_priority/other_priority.h" +#include "extensions/retry/priority/well_known_names.h" + +namespace Envoy { +namespace Extensions { +namespace Retry { +namespace Priority { + +class OtherPriorityRetryPriorityFactory : public Upstream::RetryPriorityFactory { +public: + void createRetryPriority(Upstream::RetryPriorityFactoryCallbacks& callbacks, + const Protobuf::Message& config, uint32_t max_retries) override; + + std::string name() const override { + return RetryPriorityValues::get().PreviousPrioritiesRetryPriority; + } + + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return ProtobufTypes::MessagePtr( + new envoy::config::retry::other_priority::OtherPriorityConfig()); + } +}; + +} // namespace Priority +} // namespace Retry +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/retry/priority/other_priority/other_priority.cc b/source/extensions/retry/priority/other_priority/other_priority.cc new file mode 100644 index 0000000000000..1d6cf7a6cebe5 --- /dev/null +++ b/source/extensions/retry/priority/other_priority/other_priority.cc @@ -0,0 +1,95 @@ +#include "extensions/retry/priority/other_priority/other_priority.h" + +namespace Envoy { +namespace Extensions { +namespace Retry { +namespace Priority { +const Upstream::PriorityLoad& OtherPriorityRetryPriority::determinePriorityLoad( + const Upstream::PrioritySet& priority_set, + const Upstream::PriorityLoad& original_priority_load) { + // If we've not seen enough retries to modify the priority load, just + // return the original. + // If this retry should trigger an update, recalculate the priority load by excluding attempted + // priorities. + if (attempted_priorities_.size() < update_frequency_) { + return original_priority_load; + } else if (attempted_priorities_.size() % update_frequency_ == 0) { + if (excluded_priorities_.size() < priority_set.hostSetsPerPriority().size()) { + excluded_priorities_.resize(priority_set.hostSetsPerPriority().size()); + } + + for (const auto priority : attempted_priorities_) { + excluded_priorities_[priority] = true; + } + + adjustForAttemptedPriorities(priority_set); + } + + return per_priority_load_; +} + +void OtherPriorityRetryPriority::adjustForAttemptedPriorities( + const Upstream::PrioritySet& priority_set) { + for (auto& host_set : priority_set.hostSetsPerPriority()) { + recalculatePerPriorityState(host_set->priority(), priority_set); + } + + // If all priorities are unhealthy to begin with, there's nothing to do. + if (!std::accumulate(per_priority_load_.begin(), per_priority_load_.end(), 0)) { + return; + } + + auto adjustedHealthAndSum = adjustedHealth(); + // If there are no healthy priorities left, we reset the attempted priorities and recompute the + // adjusted health. + // This allows us to fall back to the unmodified priority load when we run out of priorites + // instead of failing to route requests. + if (adjustedHealthAndSum.second == 0) { + for (size_t i = 0; i < excluded_priorities_.size(); ++i) { + excluded_priorities_[i] = false; + } + attempted_priorities_.clear(); + adjustedHealthAndSum = adjustedHealth(); + } + + const auto& adjusted_per_priority_health = adjustedHealthAndSum.first; + auto total_health = adjustedHealthAndSum.second; + + std::fill(per_priority_load_.begin(), per_priority_load_.end(), 0); + // We then adjust the load by rebalancing priorities with the adjusted health values. + size_t total_load = 100; + // The outer loop is used to eliminate rounding errors: any remaining load will be assigned to the + // first healthy priority. + while (total_load != 0) { + for (size_t i = 0; i < adjusted_per_priority_health.size(); ++i) { + // Now assign as much load as possible to the high priority levels and cease assigning load + // when total_load runs out. + auto delta = + std::min(total_load, adjusted_per_priority_health[i] * 100 / total_health); + per_priority_load_[i] += delta; + total_load -= delta; + } + } +} + +std::pair, uint32_t> OtherPriorityRetryPriority::adjustedHealth() const { + // Create an adjusted health view of the priorities, where attempted priorities are + // given a zero weight. + uint32_t total_health = 0; + std::vector adjusted_per_priority_health(per_priority_health_.size()); + adjusted_per_priority_health.resize(per_priority_health_.size()); + + for (size_t i = 0; i < per_priority_health_.size(); ++i) { + if (!excluded_priorities_[i]) { + adjusted_per_priority_health[i] = per_priority_health_[i]; + total_health += per_priority_health_[i]; + } + } + + return {std::move(adjusted_per_priority_health), std::min(total_health, 100u)}; +} + +} // namespace Priority +} // namespace Retry +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/retry/priority/other_priority/other_priority.h b/source/extensions/retry/priority/other_priority/other_priority.h new file mode 100644 index 0000000000000..b8fcd8e9e12e0 --- /dev/null +++ b/source/extensions/retry/priority/other_priority/other_priority.h @@ -0,0 +1,50 @@ +#pragma once + +#include "envoy/upstream/retry.h" + +#include "common/upstream/load_balancer_impl.h" + +namespace Envoy { +namespace Extensions { +namespace Retry { +namespace Priority { + +class OtherPriorityRetryPriority : public Upstream::RetryPriority { +public: + OtherPriorityRetryPriority(uint32_t update_frequency, uint32_t max_retries) + : update_frequency_(update_frequency) { + attempted_priorities_.reserve(max_retries); + } + + const Upstream::PriorityLoad& + determinePriorityLoad(const Upstream::PrioritySet& priority_set, + const Upstream::PriorityLoad& original_priority) override; + + void onHostAttempted(Upstream::HostDescriptionConstSharedPtr attempted_host) override { + attempted_priorities_.emplace_back(attempted_host->priority()); + } + +private: + void recalculatePerPriorityState(uint32_t priority, const Upstream::PrioritySet& priority_set) { + // Recalcuate health and priority the same way the load balancer does it. + Upstream::LoadBalancerBase::recalculatePerPriorityState( + priority, priority_set, per_priority_load_, per_priority_health_); + } + + std::pair, uint32_t> adjustedHealth() const; + + // Distributes priority load between priorities that should be considered after + // excluding attempted priorities. + void adjustForAttemptedPriorities(const Upstream::PrioritySet& priority_set); + + const uint32_t update_frequency_; + std::vector attempted_priorities_; + std::vector excluded_priorities_; + Upstream::PriorityLoad per_priority_load_; + std::vector per_priority_health_; +}; + +} // namespace Priority +} // namespace Retry +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/retry/priority/well_known_names.h b/source/extensions/retry/priority/well_known_names.h new file mode 100644 index 0000000000000..70989080e450c --- /dev/null +++ b/source/extensions/retry/priority/well_known_names.h @@ -0,0 +1,24 @@ +#pragma once + +#include "common/singleton/const_singleton.h" + +namespace Envoy { +namespace Extensions { +namespace Retry { +namespace Priority { + +/** + * Well-known retry priority load names. + */ +class RetryPriorityNameValues { +public: + // Previous priority retry priority. Excludes previously attempted priorities during retries. + const std::string PreviousPrioritiesRetryPriority = "envoy.retry_priorities.previous_priorities"; +}; + +typedef ConstSingleton RetryPriorityValues; + +} // namespace Priority +} // namespace Retry +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/stat_sinks/dog_statsd/config.cc b/source/extensions/stat_sinks/dog_statsd/config.cc index 9ae4436ba5eae..fc05fb67aa73b 100644 --- a/source/extensions/stat_sinks/dog_statsd/config.cc +++ b/source/extensions/stat_sinks/dog_statsd/config.cc @@ -22,7 +22,7 @@ Stats::SinkPtr DogStatsdSinkFactory::createStatsSink(const Protobuf::Message& co Network::Address::resolveProtoAddress(sink_config.address()); ENVOY_LOG(debug, "dog_statsd UDP ip address: {}", address->asString()); return std::make_unique(server.threadLocal(), std::move(address), - true); + true, sink_config.prefix()); } ProtobufTypes::MessagePtr DogStatsdSinkFactory::createEmptyConfigProto() { diff --git a/source/extensions/stat_sinks/metrics_service/BUILD b/source/extensions/stat_sinks/metrics_service/BUILD index 82a6110311b9e..1920bf462ec5c 100644 --- a/source/extensions/stat_sinks/metrics_service/BUILD +++ b/source/extensions/stat_sinks/metrics_service/BUILD @@ -18,7 +18,6 @@ envoy_cc_library( "//include/envoy/grpc:async_client_interface", "//include/envoy/local_info:local_info_interface", "//include/envoy/singleton:instance_interface", - "//include/envoy/thread_local:thread_local_interface", "//include/envoy/upstream:cluster_manager_interface", "//source/common/common:assert_lib", "//source/common/grpc:async_client_lib", diff --git a/source/extensions/stat_sinks/metrics_service/config.cc b/source/extensions/stat_sinks/metrics_service/config.cc index 182bcfac2f977..c2e3745ab1348 100644 --- a/source/extensions/stat_sinks/metrics_service/config.cc +++ b/source/extensions/stat_sinks/metrics_service/config.cc @@ -27,7 +27,7 @@ Stats::SinkPtr MetricsServiceSinkFactory::createStatsSink(const Protobuf::Messag std::make_shared( server.clusterManager().grpcAsyncClientManager().factoryForGrpcService( grpc_service, server.stats(), false), - server.threadLocal(), server.localInfo()); + server.localInfo()); return std::make_unique(grpc_metrics_streamer, server.timeSystem()); } diff --git a/source/extensions/stat_sinks/metrics_service/grpc_metrics_service_impl.cc b/source/extensions/stat_sinks/metrics_service/grpc_metrics_service_impl.cc index b42e12520a877..e4d2c73220d83 100644 --- a/source/extensions/stat_sinks/metrics_service/grpc_metrics_service_impl.cc +++ b/source/extensions/stat_sinks/metrics_service/grpc_metrics_service_impl.cc @@ -17,47 +17,19 @@ namespace StatSinks { namespace MetricsService { GrpcMetricsStreamerImpl::GrpcMetricsStreamerImpl(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 GrpcMetricsStreamerImpl::ThreadLocalStream::onRemoteClose(Grpc::Status::GrpcStatus, - const std::string&) { - // Only erase if we have a stream. Otherwise we had an inline failure and we will clear the - // stream data in send(). - if (parent_.thread_local_stream_->stream_ != nullptr) { - parent_.thread_local_stream_ = nullptr; - } -} + : client_(factory->create()), local_info_(local_info) {} -GrpcMetricsStreamerImpl::ThreadLocalStreamer::ThreadLocalStreamer( - const SharedStateSharedPtr& shared_state) - : client_(shared_state->factory_->create()), shared_state_(shared_state) {} - -void GrpcMetricsStreamerImpl::ThreadLocalStreamer::send( - envoy::service::metrics::v2::StreamMetricsMessage& message) { - if (thread_local_stream_ == nullptr) { - thread_local_stream_ = std::make_shared(*this); - } - - if (thread_local_stream_->stream_ == nullptr) { - thread_local_stream_->stream_ = - client_->start(*Protobuf::DescriptorPool::generated_pool()->FindMethodByName( - "envoy.service.metrics.v2.MetricsService.StreamMetrics"), - *thread_local_stream_); +void GrpcMetricsStreamerImpl::send(envoy::service::metrics::v2::StreamMetricsMessage& message) { + if (stream_ == nullptr) { + stream_ = client_->start(*Protobuf::DescriptorPool::generated_pool()->FindMethodByName( + "envoy.service.metrics.v2.MetricsService.StreamMetrics"), + *this); auto* identifier = message.mutable_identifier(); - *identifier->mutable_node() = shared_state_->local_info_.node(); + *identifier->mutable_node() = local_info_.node(); } - - if (thread_local_stream_->stream_ != nullptr) { - thread_local_stream_->stream_->sendMessage(message, false); - } else { - thread_local_stream_ = nullptr; + if (stream_ != nullptr) { + stream_->sendMessage(message, false); } } diff --git a/source/extensions/stat_sinks/metrics_service/grpc_metrics_service_impl.h b/source/extensions/stat_sinks/metrics_service/grpc_metrics_service_impl.h index f2531b18b8f13..5ccf79fcdab49 100644 --- a/source/extensions/stat_sinks/metrics_service/grpc_metrics_service_impl.h +++ b/source/extensions/stat_sinks/metrics_service/grpc_metrics_service_impl.h @@ -10,7 +10,6 @@ #include "envoy/stats/sink.h" #include "envoy/stats/source.h" #include "envoy/stats/stats.h" -#include "envoy/thread_local/thread_local.h" #include "envoy/upstream/cluster_manager.h" #include "common/buffer/buffer_impl.h" @@ -20,13 +19,11 @@ namespace Extensions { namespace StatSinks { namespace MetricsService { -// TODO: Move the common code to a base class so that Accesslog and Metrics Service can reuse. - /** - * Interface for metrics streamer. The streamer deals with threading and sends - * metrics on the correct stream. + * Interface for metrics streamer. */ -class GrpcMetricsStreamer { +class GrpcMetricsStreamer + : public Grpc::TypedAsyncStreamCallbacks { public: virtual ~GrpcMetricsStreamer() {} @@ -35,78 +32,41 @@ class GrpcMetricsStreamer { * @param message supplies the metrics to send. */ virtual void send(envoy::service::metrics::v2::StreamMetricsMessage& message) PURE; + + // Grpc::TypedAsyncStreamCallbacks + void onCreateInitialMetadata(Http::HeaderMap&) override {} + void onReceiveInitialMetadata(Http::HeaderMapPtr&&) override {} + void + onReceiveMessage(std::unique_ptr&&) override { + } + void onReceiveTrailingMetadata(Http::HeaderMapPtr&&) override {} + void onRemoteClose(Grpc::Status::GrpcStatus, const std::string&) override{}; }; typedef std::shared_ptr GrpcMetricsStreamerSharedPtr; /** - * Production implementation of GrpcAccessLogStreamer that supports per-thread - * streams + * Production implementation of GrpcMetricsStreamer */ class GrpcMetricsStreamerImpl : public Singleton::Instance, public GrpcMetricsStreamer { public: - GrpcMetricsStreamerImpl(Grpc::AsyncClientFactoryPtr&& factory, ThreadLocal::SlotAllocator& tls, + GrpcMetricsStreamerImpl(Grpc::AsyncClientFactoryPtr&& factory, const LocalInfo::LocalInfo& local_info); // GrpcMetricsStreamer - void send(envoy::service::metrics::v2::StreamMetricsMessage& message) override { - tls_slot_->getTyped().send(message); - } - -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. - */ - struct SharedState { - SharedState(Grpc::AsyncClientFactoryPtr&& factory, const LocalInfo::LocalInfo& local_info) - : factory_(std::move(factory)), local_info_(local_info) {} - - Grpc::AsyncClientFactoryPtr factory_; - const LocalInfo::LocalInfo& local_info_; - }; - - typedef std::shared_ptr SharedStateSharedPtr; - - struct ThreadLocalStreamer; + void send(envoy::service::metrics::v2::StreamMetricsMessage& message) override; - /** - * Per-thread stream state. - */ - struct ThreadLocalStream - : public Grpc::TypedAsyncStreamCallbacks { - ThreadLocalStream(ThreadLocalStreamer& parent) : parent_(parent) {} - - // Grpc::TypedAsyncStreamCallbacks - void onCreateInitialMetadata(Http::HeaderMap&) override {} - void onReceiveInitialMetadata(Http::HeaderMapPtr&&) override {} - void onReceiveMessage( - std::unique_ptr&&) override {} - void onReceiveTrailingMetadata(Http::HeaderMapPtr&&) override {} - void onRemoteClose(Grpc::Status::GrpcStatus status, const std::string& message) override; + // Grpc::TypedAsyncStreamCallbacks + void onRemoteClose(Grpc::Status::GrpcStatus, const std::string&) override { stream_ = nullptr; } - ThreadLocalStreamer& parent_; - Grpc::AsyncStream* stream_{}; - }; - - typedef std::shared_ptr ThreadLocalStreamSharedPtr; - - /** - * Per-thread multi-stream state. - */ - struct ThreadLocalStreamer : public ThreadLocal::ThreadLocalObject { - ThreadLocalStreamer(const SharedStateSharedPtr& shared_state); - void send(envoy::service::metrics::v2::StreamMetricsMessage& message); - - Grpc::AsyncClientPtr client_; - ThreadLocalStreamSharedPtr thread_local_stream_ = nullptr; - SharedStateSharedPtr shared_state_; - }; - - ThreadLocal::SlotPtr tls_slot_; +private: + Grpc::AsyncStream* stream_{}; + Grpc::AsyncClientPtr client_; + const LocalInfo::LocalInfo& local_info_; }; + /** - * Per thread implementation of a Metric Service flusher. + * Stat Sink implementation of Metrics Service. */ class MetricsServiceSink : public Stats::Sink { public: diff --git a/source/extensions/tracers/dynamic_ot/config.cc b/source/extensions/tracers/dynamic_ot/config.cc index b82f3f8e8b8c1..a8ebd85495278 100644 --- a/source/extensions/tracers/dynamic_ot/config.cc +++ b/source/extensions/tracers/dynamic_ot/config.cc @@ -13,11 +13,19 @@ namespace Extensions { namespace Tracers { namespace DynamicOt { -Tracing::HttpTracerPtr -DynamicOpenTracingTracerFactory::createHttpTracer(const Json::Object& json_config, - Server::Instance& server) { - const std::string library = json_config.getString("library"); - const std::string config = json_config.getObject("config")->asJsonString(); +Tracing::HttpTracerPtr DynamicOpenTracingTracerFactory::createHttpTracer( + const envoy::config::trace::v2::Tracing& configuration, Server::Instance& server) { + ProtobufTypes::MessagePtr config_ptr = createEmptyConfigProto(); + + if (configuration.http().has_config()) { + MessageUtil::jsonConvert(configuration.http().config(), *config_ptr); + } + + const auto& dynaot_config = + dynamic_cast(*config_ptr); + + const std::string library = dynaot_config.library(); + const std::string config = MessageUtil::getJsonStringFromMessage(dynaot_config.config()); Tracing::DriverPtr dynamic_driver{ std::make_unique(server.stats(), library, config)}; return std::make_unique(std::move(dynamic_driver), server.localInfo()); diff --git a/source/extensions/tracers/dynamic_ot/config.h b/source/extensions/tracers/dynamic_ot/config.h index 4db3ed14f7213..7614799883239 100644 --- a/source/extensions/tracers/dynamic_ot/config.h +++ b/source/extensions/tracers/dynamic_ot/config.h @@ -17,8 +17,13 @@ namespace DynamicOt { class DynamicOpenTracingTracerFactory : public Server::Configuration::TracerFactory { public: // TracerFactory - Tracing::HttpTracerPtr createHttpTracer(const Json::Object& json_config, + Tracing::HttpTracerPtr createHttpTracer(const envoy::config::trace::v2::Tracing& configuration, Server::Instance& server) override; + + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); + } + std::string name() override; }; diff --git a/source/extensions/tracers/lightstep/config.cc b/source/extensions/tracers/lightstep/config.cc index e1b1c5a947b35..8fd61fac90e99 100644 --- a/source/extensions/tracers/lightstep/config.cc +++ b/source/extensions/tracers/lightstep/config.cc @@ -15,19 +15,28 @@ namespace Extensions { namespace Tracers { namespace Lightstep { -Tracing::HttpTracerPtr LightstepTracerFactory::createHttpTracer(const Json::Object& json_config, - Server::Instance& server) { +Tracing::HttpTracerPtr +LightstepTracerFactory::createHttpTracer(const envoy::config::trace::v2::Tracing& configuration, + Server::Instance& server) { + ProtobufTypes::MessagePtr config_ptr = createEmptyConfigProto(); + + if (configuration.http().has_config()) { + MessageUtil::jsonConvert(configuration.http().config(), *config_ptr); + } + + const auto& lightstep_config = + dynamic_cast(*config_ptr); std::unique_ptr opts(new lightstep::LightStepTracerOptions()); - const auto access_token_file = - server.api().fileReadToEnd(json_config.getString("access_token_file")); + const auto access_token_file = server.api().fileReadToEnd(lightstep_config.access_token_file()); const auto access_token_sv = StringUtil::rtrim(access_token_file); opts->access_token.assign(access_token_sv.data(), access_token_sv.size()); opts->component_name = server.localInfo().clusterName(); - Tracing::DriverPtr lightstep_driver{new LightStepDriver{ - json_config, server.clusterManager(), server.stats(), server.threadLocal(), server.runtime(), - std::move(opts), Common::Ot::OpenTracingDriver::PropagationMode::TracerNative}}; + Tracing::DriverPtr lightstep_driver{std::make_unique( + lightstep_config, server.clusterManager(), server.stats(), server.threadLocal(), + server.runtime(), std::move(opts), + Common::Ot::OpenTracingDriver::PropagationMode::TracerNative)}; return std::make_unique(std::move(lightstep_driver), server.localInfo()); } diff --git a/source/extensions/tracers/lightstep/config.h b/source/extensions/tracers/lightstep/config.h index 4d29498581bfd..94b88674ac3d5 100644 --- a/source/extensions/tracers/lightstep/config.h +++ b/source/extensions/tracers/lightstep/config.h @@ -17,9 +17,13 @@ namespace Lightstep { class LightstepTracerFactory : public Server::Configuration::TracerFactory { public: // TracerFactory - Tracing::HttpTracerPtr createHttpTracer(const Json::Object& json_config, + Tracing::HttpTracerPtr createHttpTracer(const envoy::config::trace::v2::Tracing& configuration, Server::Instance& server) override; + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); + } + std::string name() override; }; diff --git a/source/extensions/tracers/lightstep/lightstep_tracer_impl.cc b/source/extensions/tracers/lightstep/lightstep_tracer_impl.cc index bc2781b548c5f..68319613bc6f3 100644 --- a/source/extensions/tracers/lightstep/lightstep_tracer_impl.cc +++ b/source/extensions/tracers/lightstep/lightstep_tracer_impl.cc @@ -129,7 +129,7 @@ void LightStepDriver::TlsLightStepTracer::enableTimer() { flush_timer_->enableTimer(std::chrono::milliseconds(flush_interval)); } -LightStepDriver::LightStepDriver(const Json::Object& config, +LightStepDriver::LightStepDriver(const envoy::config::trace::v2::LightstepConfig& lightstep_config, Upstream::ClusterManager& cluster_manager, Stats::Store& stats, ThreadLocal::SlotAllocator& tls, Runtime::Loader& runtime, std::unique_ptr&& options, @@ -138,10 +138,10 @@ LightStepDriver::LightStepDriver(const Json::Object& config, tracer_stats_{LIGHTSTEP_TRACER_STATS(POOL_COUNTER_PREFIX(stats, "tracing.lightstep."))}, tls_{tls.allocateSlot()}, runtime_{runtime}, options_{std::move(options)}, propagation_mode_{propagation_mode} { - Upstream::ThreadLocalCluster* cluster = cm_.get(config.getString("collector_cluster")); + Upstream::ThreadLocalCluster* cluster = cm_.get(lightstep_config.collector_cluster()); if (!cluster) { throw EnvoyException(fmt::format("{} collector cluster is not defined on cluster manager level", - config.getString("collector_cluster"))); + lightstep_config.collector_cluster())); } cluster_ = cluster->info(); diff --git a/source/extensions/tracers/lightstep/lightstep_tracer_impl.h b/source/extensions/tracers/lightstep/lightstep_tracer_impl.h index 14952970d9253..1417678b5016d 100644 --- a/source/extensions/tracers/lightstep/lightstep_tracer_impl.h +++ b/source/extensions/tracers/lightstep/lightstep_tracer_impl.h @@ -50,8 +50,9 @@ class LightStepLogger : Logger::Loggable { */ class LightStepDriver : public Common::Ot::OpenTracingDriver { public: - LightStepDriver(const Json::Object& config, Upstream::ClusterManager& cluster_manager, - Stats::Store& stats, ThreadLocal::SlotAllocator& tls, Runtime::Loader& runtime, + LightStepDriver(const envoy::config::trace::v2::LightstepConfig& lightstep_config, + Upstream::ClusterManager& cluster_manager, Stats::Store& stats, + ThreadLocal::SlotAllocator& tls, Runtime::Loader& runtime, std::unique_ptr&& options, PropagationMode propagation_mode); diff --git a/source/extensions/tracers/zipkin/config.cc b/source/extensions/tracers/zipkin/config.cc index 51a92001032fe..ba7d6e3e4b4f9 100644 --- a/source/extensions/tracers/zipkin/config.cc +++ b/source/extensions/tracers/zipkin/config.cc @@ -13,14 +13,23 @@ namespace Extensions { namespace Tracers { namespace Zipkin { -Tracing::HttpTracerPtr ZipkinTracerFactory::createHttpTracer(const Json::Object& json_config, - Server::Instance& server) { +Tracing::HttpTracerPtr +ZipkinTracerFactory::createHttpTracer(const envoy::config::trace::v2::Tracing& configuration, + Server::Instance& server) { Envoy::Runtime::RandomGenerator& rand = server.random(); + ProtobufTypes::MessagePtr config_ptr = createEmptyConfigProto(); - Tracing::DriverPtr zipkin_driver( - new Zipkin::Driver(json_config, server.clusterManager(), server.stats(), server.threadLocal(), - server.runtime(), server.localInfo(), rand, server.timeSystem())); + if (configuration.http().has_config()) { + MessageUtil::jsonConvert(configuration.http().config(), *config_ptr); + } + + const auto& zipkin_config = + dynamic_cast(*config_ptr); + + Tracing::DriverPtr zipkin_driver{std::make_unique( + zipkin_config, server.clusterManager(), server.stats(), server.threadLocal(), + server.runtime(), server.localInfo(), rand, server.timeSystem())}; return Tracing::HttpTracerPtr( new Tracing::HttpTracerImpl(std::move(zipkin_driver), server.localInfo())); diff --git a/source/extensions/tracers/zipkin/config.h b/source/extensions/tracers/zipkin/config.h index 3ed3b108f8567..424bbe9aeaef3 100644 --- a/source/extensions/tracers/zipkin/config.h +++ b/source/extensions/tracers/zipkin/config.h @@ -15,8 +15,13 @@ namespace Zipkin { class ZipkinTracerFactory : public Server::Configuration::TracerFactory { public: // TracerFactory - Tracing::HttpTracerPtr createHttpTracer(const Json::Object& json_config, + Tracing::HttpTracerPtr createHttpTracer(const envoy::config::trace::v2::Tracing& configuration, Server::Instance& server) override; + + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); + } + std::string name() override; }; diff --git a/source/extensions/tracers/zipkin/zipkin_core_constants.h b/source/extensions/tracers/zipkin/zipkin_core_constants.h index 7ae4803aab1a0..7e90506201c88 100644 --- a/source/extensions/tracers/zipkin/zipkin_core_constants.h +++ b/source/extensions/tracers/zipkin/zipkin_core_constants.h @@ -40,7 +40,6 @@ class ZipkinCoreConstantValues { const std::string NOT_SAMPLED = "0"; const std::string DEFAULT_COLLECTOR_ENDPOINT = "/api/v1/spans"; - const bool DEFAULT_TRACE_ID_128BIT = false; const bool DEFAULT_SHARED_SPAN_CONTEXT = true; }; diff --git a/source/extensions/tracers/zipkin/zipkin_tracer_impl.cc b/source/extensions/tracers/zipkin/zipkin_tracer_impl.cc index 0ce4c240fb380..c5adb06b82a58 100644 --- a/source/extensions/tracers/zipkin/zipkin_tracer_impl.cc +++ b/source/extensions/tracers/zipkin/zipkin_tracer_impl.cc @@ -53,8 +53,9 @@ Tracing::SpanPtr ZipkinSpan::spawnChild(const Tracing::Config& config, const std Driver::TlsTracer::TlsTracer(TracerPtr&& tracer, Driver& driver) : tracer_(std::move(tracer)), driver_(driver) {} -Driver::Driver(const Json::Object& config, Upstream::ClusterManager& cluster_manager, - Stats::Store& stats, ThreadLocal::SlotAllocator& tls, Runtime::Loader& runtime, +Driver::Driver(const envoy::config::trace::v2::ZipkinConfig& zipkin_config, + Upstream::ClusterManager& cluster_manager, Stats::Store& stats, + ThreadLocal::SlotAllocator& tls, Runtime::Loader& runtime, const LocalInfo::LocalInfo& local_info, Runtime::RandomGenerator& random_generator, TimeSource& time_source) : cm_(cluster_manager), tracer_stats_{ZIPKIN_TRACER_STATS( @@ -62,21 +63,22 @@ Driver::Driver(const Json::Object& config, Upstream::ClusterManager& cluster_man tls_(tls.allocateSlot()), runtime_(runtime), local_info_(local_info), time_source_(time_source) { - Upstream::ThreadLocalCluster* cluster = cm_.get(config.getString("collector_cluster")); + Upstream::ThreadLocalCluster* cluster = cm_.get(zipkin_config.collector_cluster()); if (!cluster) { throw EnvoyException(fmt::format("{} collector cluster is not defined on cluster manager level", - config.getString("collector_cluster"))); + zipkin_config.collector_cluster())); } cluster_ = cluster->info(); - const std::string collector_endpoint = - config.getString("collector_endpoint", ZipkinCoreConstants::get().DEFAULT_COLLECTOR_ENDPOINT); + std::string collector_endpoint = ZipkinCoreConstants::get().DEFAULT_COLLECTOR_ENDPOINT; + if (zipkin_config.collector_endpoint().size() > 0) { + collector_endpoint = zipkin_config.collector_endpoint(); + } - const bool trace_id_128bit = - config.getBoolean("trace_id_128bit", ZipkinCoreConstants::get().DEFAULT_TRACE_ID_128BIT); + const bool trace_id_128bit = zipkin_config.trace_id_128bit(); - const bool shared_span_context = config.getBoolean( - "shared_span_context", ZipkinCoreConstants::get().DEFAULT_SHARED_SPAN_CONTEXT); + const bool shared_span_context = PROTOBUF_GET_WRAPPED_OR_DEFAULT( + zipkin_config, shared_span_context, ZipkinCoreConstants::get().DEFAULT_SHARED_SPAN_CONTEXT); tls_->set([this, collector_endpoint, &random_generator, trace_id_128bit, shared_span_context]( Event::Dispatcher& dispatcher) -> ThreadLocal::ThreadLocalObjectSharedPtr { diff --git a/source/extensions/tracers/zipkin/zipkin_tracer_impl.h b/source/extensions/tracers/zipkin/zipkin_tracer_impl.h index cb3754affc1d5..aef3d537ed38f 100644 --- a/source/extensions/tracers/zipkin/zipkin_tracer_impl.h +++ b/source/extensions/tracers/zipkin/zipkin_tracer_impl.h @@ -89,7 +89,8 @@ class Driver : public Tracing::Driver { * Constructor. It adds itself and a newly-created Zipkin::Tracer object to a thread-local store. * Also, it associates the given random-number generator to the Zipkin::Tracer object it creates. */ - Driver(const Json::Object& config, Upstream::ClusterManager& cluster_manager, Stats::Store& stats, + Driver(const envoy::config::trace::v2::ZipkinConfig& zipkin_config, + Upstream::ClusterManager& cluster_manager, Stats::Store& stats, ThreadLocal::SlotAllocator& tls, Runtime::Loader& runtime, const LocalInfo::LocalInfo& localinfo, Runtime::RandomGenerator& random_generator, TimeSource& time_source); diff --git a/source/server/config_validation/server.cc b/source/server/config_validation/server.cc index 2d36b7b8c21e1..5a6f4c4fb88a3 100644 --- a/source/server/config_validation/server.cc +++ b/source/server/config_validation/server.cc @@ -43,8 +43,7 @@ ValidationInstance::ValidationInstance(Options& options, Event::TimeSystem& time api_(new Api::ValidationImpl(options.fileFlushIntervalMsec())), dispatcher_(api_->allocateDispatcher(time_system)), singleton_manager_(new Singleton::ManagerImpl()), - access_log_manager_(*api_, *dispatcher_, access_log_lock, store), - listener_manager_(*this, *this, *this, time_system_) { + access_log_manager_(*api_, *dispatcher_, access_log_lock, store) { try { initialize(options, local_address, component_factory); } catch (const EnvoyException& e) { @@ -80,6 +79,9 @@ void ValidationInstance::initialize(Options& options, options.serviceClusterName(), options.serviceNodeName())); Configuration::InitialImpl initial_config(bootstrap); + overload_manager_.reset( + new OverloadManagerImpl(dispatcher(), stats(), threadLocal(), bootstrap.overload_manager())); + listener_manager_.reset(new ListenerManagerImpl(*this, *this, *this, time_system_)); thread_local_.registerThread(*dispatcher_, true); runtime_loader_ = component_factory.createRuntime(*this, initial_config); secret_manager_.reset(new Secret::SecretManagerImpl()); diff --git a/source/server/config_validation/server.h b/source/server/config_validation/server.h index 6f9dafcaf6c5f..03d0b9538971c 100644 --- a/source/server/config_validation/server.h +++ b/source/server/config_validation/server.h @@ -74,7 +74,7 @@ class ValidationInstance : Logger::Loggable, void getParentStats(HotRestart::GetParentStatsInfo&) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } HotRestart& hotRestart() override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } Init::Manager& initManager() override { return init_manager_; } - ListenerManager& listenerManager() override { return listener_manager_; } + ListenerManager& listenerManager() override { return *listener_manager_; } Secret::SecretManager& secretManager() override { return *secret_manager_; } Runtime::RandomGenerator& random() override { return random_generator_; } RateLimit::ClientPtr @@ -85,7 +85,7 @@ class ValidationInstance : Logger::Loggable, void shutdown() override; void shutdownAdmin() override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } Singleton::Manager& singletonManager() override { return *singleton_manager_; } - OverloadManager& overloadManager() override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } + OverloadManager& overloadManager() override { return *overload_manager_; } bool healthCheckFailed() override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } Options& options() override { return options_; } time_t startTimeCurrentEpoch() override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } @@ -128,7 +128,7 @@ class ValidationInstance : Logger::Loggable, uint64_t nextListenerTag() override { return 0; } // Server::WorkerFactory - WorkerPtr createWorker() override { + WorkerPtr createWorker(OverloadManager&) override { // Returned workers are not currently used so we can return nothing here safely vs. a // validation mock. return nullptr; @@ -154,8 +154,9 @@ class ValidationInstance : Logger::Loggable, AccessLog::AccessLogManagerImpl access_log_manager_; std::unique_ptr cluster_manager_factory_; InitManagerImpl init_manager_; - ListenerManagerImpl listener_manager_; + std::unique_ptr listener_manager_; std::unique_ptr secret_manager_; + std::unique_ptr overload_manager_; }; } // namespace Server diff --git a/source/server/configuration_impl.cc b/source/server/configuration_impl.cc index 8aab546468fb7..abdf41d6274d5 100644 --- a/source/server/configuration_impl.cc +++ b/source/server/configuration_impl.cc @@ -103,13 +103,9 @@ void MainImpl::initializeTracers(const envoy::config::trace::v2::Tracing& config std::string type = configuration.http().name(); ENVOY_LOG(info, " loading tracing driver: {}", type); - // TODO(htuch): Make this dynamically pluggable one day. - Json::ObjectSharedPtr driver_config = - MessageUtil::getJsonObjectFromMessage(configuration.http().config()); - // Now see if there is a factory that will accept the config. auto& factory = Config::Utility::getAndCheckFactory(type); - http_tracer_ = factory.createHttpTracer(*driver_config, server); + http_tracer_ = factory.createHttpTracer(configuration, server); } void MainImpl::initializeStatsSinks(const envoy::config::bootstrap::v2::Bootstrap& bootstrap, diff --git a/source/server/configuration_impl.h b/source/server/configuration_impl.h index 615b8af4c5702..f73afe718ac1c 100644 --- a/source/server/configuration_impl.h +++ b/source/server/configuration_impl.h @@ -43,8 +43,15 @@ class TracerFactory { * @param json_config supplies the general json configuration for the HttpTracer * @param server supplies the server instance */ - virtual Tracing::HttpTracerPtr createHttpTracer(const Json::Object& json_config, - Instance& server) PURE; + virtual Tracing::HttpTracerPtr + createHttpTracer(const envoy::config::trace::v2::Tracing& configuration, Instance& server) PURE; + + /** + * @return ProtobufTypes::MessagePtr create empty config proto message for v2. The tracing + * config, which arrives in an opaque google.protobuf.Struct message, will be converted to + * JSON and then parsed into this empty proto. + */ + virtual ProtobufTypes::MessagePtr createEmptyConfigProto() PURE; /** * Returns the identifying name for a particular implementation of tracer produced by the diff --git a/source/server/connection_handler_impl.cc b/source/server/connection_handler_impl.cc index 02aa8d1124d50..7c73d24a23061 100644 --- a/source/server/connection_handler_impl.cc +++ b/source/server/connection_handler_impl.cc @@ -46,6 +46,18 @@ void ConnectionHandlerImpl::stopListeners() { } } +void ConnectionHandlerImpl::disableListeners() { + for (auto& listener : listeners_) { + listener.second->listener_->disable(); + } +} + +void ConnectionHandlerImpl::enableListeners() { + for (auto& listener : listeners_) { + listener.second->listener_->enable(); + } +} + void ConnectionHandlerImpl::ActiveListener::removeConnection(ActiveConnection& connection) { ENVOY_CONN_LOG_TO_LOGGER(parent_.logger_, debug, "adding to cleanup list", *connection.connection_); diff --git a/source/server/connection_handler_impl.h b/source/server/connection_handler_impl.h index cf55d180c26b7..cf16195bb3f53 100644 --- a/source/server/connection_handler_impl.h +++ b/source/server/connection_handler_impl.h @@ -54,6 +54,8 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler, NonCopyable { void removeListeners(uint64_t listener_tag) override; void stopListeners(uint64_t listener_tag) override; void stopListeners() override; + void disableListeners() override; + void enableListeners() override; Network::Listener* findListenerByAddress(const Network::Address::Instance& address) override; diff --git a/source/server/http/BUILD b/source/server/http/BUILD index d6a388925c9f0..e34615791dda9 100644 --- a/source/server/http/BUILD +++ b/source/server/http/BUILD @@ -58,6 +58,7 @@ envoy_cc_library( "//source/common/stats:stats_lib", "//source/common/upstream:host_utility_lib", "//source/extensions/access_loggers/file:file_access_log_lib", + "@envoy_api//envoy/admin/v2alpha:certs_cc", "@envoy_api//envoy/admin/v2alpha:clusters_cc", "@envoy_api//envoy/admin/v2alpha:config_dump_cc", "@envoy_api//envoy/admin/v2alpha:memory_cc", diff --git a/source/server/http/admin.cc b/source/server/http/admin.cc index d24129b77fff0..ac564b12a6f2d 100644 --- a/source/server/http/admin.cc +++ b/source/server/http/admin.cc @@ -10,6 +10,7 @@ #include #include +#include "envoy/admin/v2alpha/certs.pb.h" #include "envoy/admin/v2alpha/clusters.pb.h" #include "envoy/admin/v2alpha/config_dump.pb.h" #include "envoy/admin/v2alpha/memory.pb.h" @@ -751,22 +752,25 @@ Http::Code AdminImpl::handlerListenerInfo(absl::string_view, Http::HeaderMap& re return Http::Code::OK; } -Http::Code AdminImpl::handlerCerts(absl::string_view, Http::HeaderMap&, Buffer::Instance& response, - AdminStream&) { +Http::Code AdminImpl::handlerCerts(absl::string_view, Http::HeaderMap& response_headers, + Buffer::Instance& response, AdminStream&) { // This set is used to track distinct certificates. We may have multiple listeners, upstreams, etc // using the same cert. - std::unordered_set context_info_set; - std::string context_format = "{{\n\t\"ca_cert\": \"{}\",\n\t\"cert_chain\": \"{}\"\n}}\n"; + response_headers.insertContentType().value().setReference( + Http::Headers::get().ContentTypeValues.Json); + envoy::admin::v2alpha::Certificates certificates; server_.sslContextManager().iterateContexts([&](const Ssl::Context& context) -> void { - context_info_set.insert(fmt::format(context_format, context.getCaCertInformation(), - context.getCertChainInformation())); + envoy::admin::v2alpha::Certificate& certificate = *certificates.add_certificates(); + if (context.getCaCertInformation() != nullptr) { + envoy::admin::v2alpha::CertificateDetails* ca_certificate = certificate.add_ca_cert(); + *ca_certificate = *context.getCaCertInformation(); + } + if (context.getCertChainInformation() != nullptr) { + envoy::admin::v2alpha::CertificateDetails* cert_chain = certificate.add_cert_chain(); + *cert_chain = *context.getCertChainInformation(); + } }); - - std::string cert_result_string; - for (const std::string& context_info : context_info_set) { - cert_result_string += context_info; - } - response.add(cert_result_string); + response.add(MessageUtil::getJsonStringFromMessage(certificates, true, true)); return Http::Code::OK; } diff --git a/source/server/listener_manager_impl.cc b/source/server/listener_manager_impl.cc index c4ece6422abd2..cef9d05a80c13 100644 --- a/source/server/listener_manager_impl.cc +++ b/source/server/listener_manager_impl.cc @@ -579,7 +579,7 @@ ListenerManagerImpl::ListenerManagerImpl(Instance& server, config_tracker_entry_(server.admin().getConfigTracker().add( "listeners", [this] { return dumpListenerConfigs(); })) { for (uint32_t i = 0; i < server.options().concurrency(); i++) { - workers_.emplace_back(worker_factory.createWorker()); + workers_.emplace_back(worker_factory.createWorker(server.overloadManager())); } } diff --git a/source/server/overload_manager_impl.cc b/source/server/overload_manager_impl.cc index 459f3f2fdff48..96c6c2f239a20 100644 --- a/source/server/overload_manager_impl.cc +++ b/source/server/overload_manager_impl.cc @@ -128,18 +128,20 @@ OverloadManagerImpl::OverloadManagerImpl( resource_to_actions_.insert(std::make_pair(resource, name)); } } - - tls_->set([](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { - return std::make_shared(); - }); } void OverloadManagerImpl::start() { ASSERT(!started_); started_ = true; + + tls_->set([](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { + return std::make_shared(); + }); + if (resources_.empty()) { return; } + timer_ = dispatcher_.createTimer([this]() -> void { for (auto& resource : resources_) { resource.second.update(); diff --git a/source/server/server.cc b/source/server/server.cc index 4d857aca72e11..df5da43125e09 100644 --- a/source/server/server.cc +++ b/source/server/server.cc @@ -231,6 +231,7 @@ void InstanceImpl::initialize(Options& options, // Needs to happen as early as possible in the instantiation to preempt the objects that require // stats. stats_store_.setTagProducer(Config::Utility::createTagProducer(bootstrap_)); + stats_store_.setStatsMatcher(Config::Utility::createStatsMatcher(bootstrap_)); server_stats_.reset( new ServerStats{ALL_SERVER_STATS(POOL_GAUGE_PREFIX(stats_store_, "server."))}); @@ -275,6 +276,10 @@ void InstanceImpl::initialize(Options& options, loadServerFlags(initial_config.flagsPath()); + // Initialize the overload manager early so other modules can register for actions. + overload_manager_.reset( + new OverloadManagerImpl(dispatcher(), stats(), threadLocal(), bootstrap_.overload_manager())); + // Workers get created first so they register for thread local updates. listener_manager_.reset( new ListenerManagerImpl(*this, listener_component_factory_, worker_factory_, time_system_)); @@ -283,10 +288,6 @@ void InstanceImpl::initialize(Options& options, // whether it runs on the main thread or on workers can still use TLS. thread_local_.registerThread(*dispatcher_, true); - // Initialize the overload manager early so other modules can register for actions. - overload_manager_.reset( - new OverloadManagerImpl(dispatcher(), stats(), threadLocal(), bootstrap_.overload_manager())); - // We can now initialize stats for threading. stats_store_.initializeThreading(*dispatcher_, thread_local_); @@ -473,6 +474,10 @@ void InstanceImpl::terminate() { // Before the workers start exiting we should disable stat threading. stats_store_.shutdownThreading(); + if (overload_manager_) { + overload_manager_.reset(); + } + // Shutdown all the workers now that the main dispatch loop is done. if (listener_manager_.get() != nullptr) { listener_manager_->stopWorkers(); diff --git a/source/server/worker_impl.cc b/source/server/worker_impl.cc index e2bc51a029016..f4f53dcf0b771 100644 --- a/source/server/worker_impl.cc +++ b/source/server/worker_impl.cc @@ -14,17 +14,22 @@ namespace Envoy { namespace Server { -WorkerPtr ProdWorkerFactory::createWorker() { +WorkerPtr ProdWorkerFactory::createWorker(OverloadManager& overload_manager) { Event::DispatcherPtr dispatcher(api_.allocateDispatcher(time_system_)); return WorkerPtr{new WorkerImpl( tls_, hooks_, std::move(dispatcher), - Network::ConnectionHandlerPtr{new ConnectionHandlerImpl(ENVOY_LOGGER(), *dispatcher)})}; + Network::ConnectionHandlerPtr{new ConnectionHandlerImpl(ENVOY_LOGGER(), *dispatcher)}, + overload_manager)}; } WorkerImpl::WorkerImpl(ThreadLocal::Instance& tls, TestHooks& hooks, - Event::DispatcherPtr&& dispatcher, Network::ConnectionHandlerPtr handler) + Event::DispatcherPtr&& dispatcher, Network::ConnectionHandlerPtr handler, + OverloadManager& overload_manager) : tls_(tls), hooks_(hooks), dispatcher_(std::move(dispatcher)), handler_(std::move(handler)) { tls_.registerThread(*dispatcher_, false); + overload_manager.registerForAction( + OverloadActionNames::get().StopAcceptingConnections, *dispatcher_, + [this](OverloadActionState state) { stopAcceptingConnectionsCb(state); }); } void WorkerImpl::addListener(Network::ListenerConfig& listener, AddListenerCompletion completion) { @@ -104,5 +109,16 @@ void WorkerImpl::threadRoutine(GuardDog& guard_dog) { watchdog.reset(); } +void WorkerImpl::stopAcceptingConnectionsCb(OverloadActionState state) { + switch (state) { + case OverloadActionState::Active: + handler_->disableListeners(); + break; + case OverloadActionState::Inactive: + handler_->enableListeners(); + break; + } +} + } // namespace Server } // namespace Envoy diff --git a/source/server/worker_impl.h b/source/server/worker_impl.h index a0375cab25f5a..a082cd6d1cef9 100644 --- a/source/server/worker_impl.h +++ b/source/server/worker_impl.h @@ -25,7 +25,7 @@ class ProdWorkerFactory : public WorkerFactory, Logger::Loggable { public: WorkerImpl(ThreadLocal::Instance& tls, TestHooks& hooks, Event::DispatcherPtr&& dispatcher, - Network::ConnectionHandlerPtr handler); + Network::ConnectionHandlerPtr handler, OverloadManager& overload_manager); // Server::Worker void addListener(Network::ListenerConfig& listener, AddListenerCompletion completion) override; @@ -53,6 +53,7 @@ class WorkerImpl : public Worker, Logger::Loggable { private: void threadRoutine(GuardDog& guard_dog); + void stopAcceptingConnectionsCb(OverloadActionState state); ThreadLocal::Instance& tls_; TestHooks& hooks_; diff --git a/test/common/access_log/BUILD b/test/common/access_log/BUILD index 177a191fbffc5..16aa83afaac38 100644 --- a/test/common/access_log/BUILD +++ b/test/common/access_log/BUILD @@ -16,7 +16,7 @@ envoy_cc_test_library( name = "test_util", hdrs = ["test_util.h"], deps = [ - "//include/envoy/request_info:request_info_interface", + "//include/envoy/stream_info:stream_info_interface", "//source/common/common:assert_lib", "//test/test_common:test_time_lib", ], @@ -47,7 +47,7 @@ envoy_cc_test( "//source/common/common:utility_lib", "//source/common/http:header_map_lib", "//test/mocks/http:http_mocks", - "//test/mocks/request_info:request_info_mocks", + "//test/mocks/stream_info:stream_info_mocks", "//test/mocks/upstream:upstream_mocks", "//test/test_common:utility_lib", ], @@ -99,7 +99,7 @@ envoy_cc_binary( "//source/common/http:header_map_lib", "//source/common/network:address_lib", "//test/mocks/http:http_mocks", - "//test/mocks/request_info:request_info_mocks", + "//test/mocks/stream_info:stream_info_mocks", "//test/test_common:printers_lib", ], ) diff --git a/test/common/access_log/access_log_formatter_corpus/clusterfuzz-testcase-minimized-access_log_formatter_fuzz_test-5701824317751296 b/test/common/access_log/access_log_formatter_corpus/clusterfuzz-testcase-minimized-access_log_formatter_fuzz_test-5701824317751296 index 542c0daf722bf..bf530003c61f5 100644 --- a/test/common/access_log/access_log_formatter_corpus/clusterfuzz-testcase-minimized-access_log_formatter_fuzz_test-5701824317751296 +++ b/test/common/access_log/access_log_formatter_corpus/clusterfuzz-testcase-minimized-access_log_formatter_fuzz_test-5701824317751296 @@ -1 +1 @@ -format: "%START_TIME(%f)%" request_info { start_time: 18446744073709551615 } +format: "%START_TIME(%f)%" stream_info { start_time: 18446744073709551615 } diff --git a/test/common/access_log/access_log_formatter_corpus/dynamic_metadata b/test/common/access_log/access_log_formatter_corpus/dynamic_metadata index 47bb302f2dc24..4cc14e1b72b63 100644 --- a/test/common/access_log/access_log_formatter_corpus/dynamic_metadata +++ b/test/common/access_log/access_log_formatter_corpus/dynamic_metadata @@ -1,5 +1,5 @@ format: "%DYNAMIC_METADATA(com.test:test_key)%|%DYNAMIC_METADATA(com.test:test_obj)%|%DYNAMIC_METADATA(com.test:test_obj:inner_key)%" -request_info { +stream_info { dynamic_metadata { filter_metadata { key: "com.test" diff --git a/test/common/access_log/access_log_formatter_corpus/response_code b/test/common/access_log/access_log_formatter_corpus/response_code index f3cdf2a1089fc..cf0dac6c040c2 100644 --- a/test/common/access_log/access_log_formatter_corpus/response_code +++ b/test/common/access_log/access_log_formatter_corpus/response_code @@ -1,5 +1,5 @@ format: "%RESPONSE_CODE%" -request_info { +stream_info { response_code { value: 404 } diff --git a/test/common/access_log/access_log_formatter_corpus/start_time_0 b/test/common/access_log/access_log_formatter_corpus/start_time_0 index 426315de43f4b..b1df406e3f82a 100644 --- a/test/common/access_log/access_log_formatter_corpus/start_time_0 +++ b/test/common/access_log/access_log_formatter_corpus/start_time_0 @@ -1,4 +1,4 @@ format: "%START_TIME(%Y/%m/%d)%|%START_TIME(%s)%|%START_TIME(bad_format)%|%START_TIME%|%START_TIME(%f.%1f.%2f.%3f)%" -request_info { +stream_info { start_time: 1522280158 } diff --git a/test/common/access_log/access_log_formatter_corpus/start_time_1 b/test/common/access_log/access_log_formatter_corpus/start_time_1 index 30a32099bec3d..9815b17b3d95b 100644 --- a/test/common/access_log/access_log_formatter_corpus/start_time_1 +++ b/test/common/access_log/access_log_formatter_corpus/start_time_1 @@ -1,4 +1,4 @@ format: "%START_TIME(%s.%3f)%|%START_TIME(%s.%4f)%|%START_TIME(%s.%5f)%|%START_TIME(%s.%6f)%" -request_info { +stream_info { start_time: 1522796769123456 } diff --git a/test/common/access_log/access_log_formatter_corpus/start_time_2 b/test/common/access_log/access_log_formatter_corpus/start_time_2 index b1ec487f3464a..1cd27a48bc170 100644 --- a/test/common/access_log/access_log_formatter_corpus/start_time_2 +++ b/test/common/access_log/access_log_formatter_corpus/start_time_2 @@ -1,4 +1,4 @@ format: "%START_TIME(segment1:%s.%3f|segment2:%s.%4f|seg3:%s.%6f|%s-%3f-asdf-%9f|.%7f:segm5:%Y)%" -request_info { +stream_info { start_time: 1522796769123456 } diff --git a/test/common/access_log/access_log_formatter_corpus/start_time_3 b/test/common/access_log/access_log_formatter_corpus/start_time_3 index fcfd2c6fa9bfb..126db016fa058 100644 --- a/test/common/access_log/access_log_formatter_corpus/start_time_3 +++ b/test/common/access_log/access_log_formatter_corpus/start_time_3 @@ -1,4 +1,4 @@ format: "%START_TIME(%%%%|%%%%%f|%s%%%%%3f|%1f%%%%%s)%" -request_info { +stream_info { start_time: 1522796769123456 } diff --git a/test/common/access_log/access_log_formatter_fuzz.proto b/test/common/access_log/access_log_formatter_fuzz.proto index 9c510e37d73f4..a07182fffc85c 100644 --- a/test/common/access_log/access_log_formatter_fuzz.proto +++ b/test/common/access_log/access_log_formatter_fuzz.proto @@ -11,5 +11,5 @@ message TestCase { test.fuzz.Headers request_headers = 2; test.fuzz.Headers response_headers = 3; test.fuzz.Headers response_trailers = 4; - test.fuzz.RequestInfo request_info = 5; + test.fuzz.StreamInfo stream_info = 5; } diff --git a/test/common/access_log/access_log_formatter_fuzz_test.cc b/test/common/access_log/access_log_formatter_fuzz_test.cc index 9909511d04da0..f6bcfb4bda8c0 100644 --- a/test/common/access_log/access_log_formatter_fuzz_test.cc +++ b/test/common/access_log/access_log_formatter_fuzz_test.cc @@ -9,13 +9,12 @@ namespace Fuzz { DEFINE_PROTO_FUZZER(const test::common::access_log::TestCase& input) { try { - std::vector formatters = + std::vector formatters = AccessLog::AccessLogFormatParser::parse(input.format()); for (const auto& it : formatters) { - it->format(Fuzz::fromHeaders(input.request_headers()), - Fuzz::fromHeaders(input.response_headers()), - Fuzz::fromHeaders(input.response_trailers()), - Fuzz::fromRequestInfo(input.request_info())); + it->format( + Fuzz::fromHeaders(input.request_headers()), Fuzz::fromHeaders(input.response_headers()), + Fuzz::fromHeaders(input.response_trailers()), Fuzz::fromStreamInfo(input.stream_info())); } ENVOY_LOG_MISC(trace, "Success"); } catch (const EnvoyException& e) { diff --git a/test/common/access_log/access_log_formatter_speed_test.cc b/test/common/access_log/access_log_formatter_speed_test.cc index d232515224328..61d2f222af3b3 100644 --- a/test/common/access_log/access_log_formatter_speed_test.cc +++ b/test/common/access_log/access_log_formatter_speed_test.cc @@ -9,7 +9,7 @@ namespace { static std::unique_ptr formatter; -static std::unique_ptr request_info; +static std::unique_ptr stream_info; } // namespace @@ -22,7 +22,7 @@ static void BM_AccessLogFormatter(benchmark::State& state) { Http::TestHeaderMapImpl response_trailers; for (auto _ : state) { output_bytes += - formatter->format(request_headers, response_headers, response_trailers, *request_info) + formatter->format(request_headers, response_headers, response_trailers, *stream_info) .length(); } benchmark::DoNotOptimize(output_bytes); @@ -40,8 +40,8 @@ int main(int argc, char** argv) { "s%RESPONSE_CODE% %BYTES_SENT% %DURATION% %REQ(REFERER)% \"%REQ(USER-AGENT)%\" - - -\n"; formatter = std::make_unique(LogFormat); - request_info = std::make_unique(); - request_info->setDownstreamRemoteAddress( + stream_info = std::make_unique(); + stream_info->setDownstreamRemoteAddress( std::make_shared("203.0.113.1")); benchmark::Initialize(&argc, argv); if (benchmark::ReportUnrecognizedArguments(argc, argv)) { diff --git a/test/common/access_log/access_log_formatter_test.cc b/test/common/access_log/access_log_formatter_test.cc index e3da4a94e08f8..0abe5609e4ee8 100644 --- a/test/common/access_log/access_log_formatter_test.cc +++ b/test/common/access_log/access_log_formatter_test.cc @@ -8,7 +8,7 @@ #include "common/http/header_map_impl.h" #include "test/mocks/http/mocks.h" -#include "test/mocks/request_info/mocks.h" +#include "test/mocks/stream_info/mocks.h" #include "test/mocks/upstream/mocks.h" #include "test/test_common/printers.h" #include "test/test_common/utility.h" @@ -34,177 +34,177 @@ TEST(AccessLogFormatUtilsTest, protocolToString) { TEST(AccessLogFormatterTest, plainStringFormatter) { PlainStringFormatter formatter("plain"); Http::TestHeaderMapImpl header{{":method", "GET"}, {":path", "/"}}; - RequestInfo::MockRequestInfo request_info; + StreamInfo::MockStreamInfo stream_info; - EXPECT_EQ("plain", formatter.format(header, header, header, request_info)); + EXPECT_EQ("plain", formatter.format(header, header, header, stream_info)); } -TEST(AccessLogFormatterTest, requestInfoFormatter) { - EXPECT_THROW(RequestInfoFormatter formatter("unknown_field"), EnvoyException); +TEST(AccessLogFormatterTest, streamInfoFormatter) { + EXPECT_THROW(StreamInfoFormatter formatter("unknown_field"), EnvoyException); - NiceMock request_info; + NiceMock stream_info; Http::TestHeaderMapImpl header{{":method", "GET"}, {":path", "/"}}; { - RequestInfoFormatter request_duration_format("REQUEST_DURATION"); + StreamInfoFormatter request_duration_format("REQUEST_DURATION"); absl::optional dur = std::chrono::nanoseconds(5000000); - EXPECT_CALL(request_info, lastDownstreamRxByteReceived()).WillOnce(Return(dur)); - EXPECT_EQ("5", request_duration_format.format(header, header, header, request_info)); + EXPECT_CALL(stream_info, lastDownstreamRxByteReceived()).WillOnce(Return(dur)); + EXPECT_EQ("5", request_duration_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter request_duration_format("REQUEST_DURATION"); + StreamInfoFormatter request_duration_format("REQUEST_DURATION"); absl::optional dur; - EXPECT_CALL(request_info, lastDownstreamRxByteReceived()).WillOnce(Return(dur)); - EXPECT_EQ("-", request_duration_format.format(header, header, header, request_info)); + EXPECT_CALL(stream_info, lastDownstreamRxByteReceived()).WillOnce(Return(dur)); + EXPECT_EQ("-", request_duration_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter response_duration_format("RESPONSE_DURATION"); + StreamInfoFormatter response_duration_format("RESPONSE_DURATION"); absl::optional dur = std::chrono::nanoseconds(10000000); - EXPECT_CALL(request_info, firstUpstreamRxByteReceived()).WillRepeatedly(Return(dur)); - EXPECT_EQ("10", response_duration_format.format(header, header, header, request_info)); + EXPECT_CALL(stream_info, firstUpstreamRxByteReceived()).WillRepeatedly(Return(dur)); + EXPECT_EQ("10", response_duration_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter response_duration_format("RESPONSE_DURATION"); + StreamInfoFormatter response_duration_format("RESPONSE_DURATION"); absl::optional dur; - EXPECT_CALL(request_info, firstUpstreamRxByteReceived()).WillRepeatedly(Return(dur)); - EXPECT_EQ("-", response_duration_format.format(header, header, header, request_info)); + EXPECT_CALL(stream_info, firstUpstreamRxByteReceived()).WillRepeatedly(Return(dur)); + EXPECT_EQ("-", response_duration_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter ttlb_duration_format("RESPONSE_TX_DURATION"); + StreamInfoFormatter ttlb_duration_format("RESPONSE_TX_DURATION"); absl::optional dur_upstream = std::chrono::nanoseconds(10000000); - EXPECT_CALL(request_info, firstUpstreamRxByteReceived()).WillRepeatedly(Return(dur_upstream)); + EXPECT_CALL(stream_info, firstUpstreamRxByteReceived()).WillRepeatedly(Return(dur_upstream)); absl::optional dur_downstream = std::chrono::nanoseconds(25000000); - EXPECT_CALL(request_info, lastDownstreamTxByteSent()).WillRepeatedly(Return(dur_downstream)); + EXPECT_CALL(stream_info, lastDownstreamTxByteSent()).WillRepeatedly(Return(dur_downstream)); - EXPECT_EQ("15", ttlb_duration_format.format(header, header, header, request_info)); + EXPECT_EQ("15", ttlb_duration_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter ttlb_duration_format("RESPONSE_TX_DURATION"); + StreamInfoFormatter ttlb_duration_format("RESPONSE_TX_DURATION"); absl::optional dur_upstream; - EXPECT_CALL(request_info, firstUpstreamRxByteReceived()).WillRepeatedly(Return(dur_upstream)); + EXPECT_CALL(stream_info, firstUpstreamRxByteReceived()).WillRepeatedly(Return(dur_upstream)); absl::optional dur_downstream; - EXPECT_CALL(request_info, lastDownstreamTxByteSent()).WillRepeatedly(Return(dur_downstream)); + EXPECT_CALL(stream_info, lastDownstreamTxByteSent()).WillRepeatedly(Return(dur_downstream)); - EXPECT_EQ("-", ttlb_duration_format.format(header, header, header, request_info)); + EXPECT_EQ("-", ttlb_duration_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter bytes_received_format("BYTES_RECEIVED"); - EXPECT_CALL(request_info, bytesReceived()).WillOnce(Return(1)); - EXPECT_EQ("1", bytes_received_format.format(header, header, header, request_info)); + StreamInfoFormatter bytes_received_format("BYTES_RECEIVED"); + EXPECT_CALL(stream_info, bytesReceived()).WillOnce(Return(1)); + EXPECT_EQ("1", bytes_received_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter protocol_format("PROTOCOL"); + StreamInfoFormatter protocol_format("PROTOCOL"); absl::optional protocol = Http::Protocol::Http11; - EXPECT_CALL(request_info, protocol()).WillOnce(Return(protocol)); - EXPECT_EQ("HTTP/1.1", protocol_format.format(header, header, header, request_info)); + EXPECT_CALL(stream_info, protocol()).WillOnce(Return(protocol)); + EXPECT_EQ("HTTP/1.1", protocol_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter response_format("RESPONSE_CODE"); + StreamInfoFormatter response_format("RESPONSE_CODE"); absl::optional response_code{200}; - EXPECT_CALL(request_info, responseCode()).WillRepeatedly(Return(response_code)); - EXPECT_EQ("200", response_format.format(header, header, header, request_info)); + EXPECT_CALL(stream_info, responseCode()).WillRepeatedly(Return(response_code)); + EXPECT_EQ("200", response_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter response_code_format("RESPONSE_CODE"); + StreamInfoFormatter response_code_format("RESPONSE_CODE"); absl::optional response_code; - EXPECT_CALL(request_info, responseCode()).WillRepeatedly(Return(response_code)); - EXPECT_EQ("0", response_code_format.format(header, header, header, request_info)); + EXPECT_CALL(stream_info, responseCode()).WillRepeatedly(Return(response_code)); + EXPECT_EQ("0", response_code_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter bytes_sent_format("BYTES_SENT"); - EXPECT_CALL(request_info, bytesSent()).WillOnce(Return(1)); - EXPECT_EQ("1", bytes_sent_format.format(header, header, header, request_info)); + StreamInfoFormatter bytes_sent_format("BYTES_SENT"); + EXPECT_CALL(stream_info, bytesSent()).WillOnce(Return(1)); + EXPECT_EQ("1", bytes_sent_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter duration_format("DURATION"); + StreamInfoFormatter duration_format("DURATION"); absl::optional dur = std::chrono::nanoseconds(15000000); - EXPECT_CALL(request_info, requestComplete()).WillRepeatedly(Return(dur)); - EXPECT_EQ("15", duration_format.format(header, header, header, request_info)); + EXPECT_CALL(stream_info, requestComplete()).WillRepeatedly(Return(dur)); + EXPECT_EQ("15", duration_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter response_flags_format("RESPONSE_FLAGS"); - ON_CALL(request_info, hasResponseFlag(RequestInfo::ResponseFlag::LocalReset)) + StreamInfoFormatter response_flags_format("RESPONSE_FLAGS"); + ON_CALL(stream_info, hasResponseFlag(StreamInfo::ResponseFlag::LocalReset)) .WillByDefault(Return(true)); - EXPECT_EQ("LR", response_flags_format.format(header, header, header, request_info)); + EXPECT_EQ("LR", response_flags_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter upstream_format("UPSTREAM_HOST"); - EXPECT_EQ("10.0.0.1:443", upstream_format.format(header, header, header, request_info)); + StreamInfoFormatter upstream_format("UPSTREAM_HOST"); + EXPECT_EQ("10.0.0.1:443", upstream_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter upstream_format("UPSTREAM_CLUSTER"); + StreamInfoFormatter upstream_format("UPSTREAM_CLUSTER"); const std::string upstream_cluster_name = "cluster_name"; - EXPECT_CALL(request_info.host_->cluster_, name()).WillOnce(ReturnRef(upstream_cluster_name)); - EXPECT_EQ("cluster_name", upstream_format.format(header, header, header, request_info)); + EXPECT_CALL(stream_info.host_->cluster_, name()).WillOnce(ReturnRef(upstream_cluster_name)); + EXPECT_EQ("cluster_name", upstream_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter upstream_format("UPSTREAM_HOST"); - EXPECT_CALL(request_info, upstreamHost()).WillOnce(Return(nullptr)); - EXPECT_EQ("-", upstream_format.format(header, header, header, request_info)); + StreamInfoFormatter upstream_format("UPSTREAM_HOST"); + EXPECT_CALL(stream_info, upstreamHost()).WillOnce(Return(nullptr)); + EXPECT_EQ("-", upstream_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter upstream_format("UPSTREAM_CLUSTER"); - EXPECT_CALL(request_info, upstreamHost()).WillOnce(Return(nullptr)); - EXPECT_EQ("-", upstream_format.format(header, header, header, request_info)); + StreamInfoFormatter upstream_format("UPSTREAM_CLUSTER"); + EXPECT_CALL(stream_info, upstreamHost()).WillOnce(Return(nullptr)); + EXPECT_EQ("-", upstream_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter upstream_format("DOWNSTREAM_LOCAL_ADDRESS"); - EXPECT_EQ("127.0.0.2:0", upstream_format.format(header, header, header, request_info)); + StreamInfoFormatter upstream_format("DOWNSTREAM_LOCAL_ADDRESS"); + EXPECT_EQ("127.0.0.2:0", upstream_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter upstream_format("DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT"); - EXPECT_EQ("127.0.0.2", upstream_format.format(header, header, header, request_info)); + StreamInfoFormatter upstream_format("DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT"); + EXPECT_EQ("127.0.0.2", upstream_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter upstream_format("DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT"); - EXPECT_EQ("127.0.0.1", upstream_format.format(header, header, header, request_info)); + StreamInfoFormatter upstream_format("DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT"); + EXPECT_EQ("127.0.0.1", upstream_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter upstream_format("DOWNSTREAM_REMOTE_ADDRESS"); - EXPECT_EQ("127.0.0.1:0", upstream_format.format(header, header, header, request_info)); + StreamInfoFormatter upstream_format("DOWNSTREAM_REMOTE_ADDRESS"); + EXPECT_EQ("127.0.0.1:0", upstream_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter upstream_format("REQUESTED_SERVER_NAME"); + StreamInfoFormatter upstream_format("REQUESTED_SERVER_NAME"); std::string requested_server_name = "stub_server"; - EXPECT_CALL(request_info, requestedServerName()) + EXPECT_CALL(stream_info, requestedServerName()) .WillRepeatedly(ReturnRef(requested_server_name)); - EXPECT_EQ("stub_server", upstream_format.format(header, header, header, request_info)); + EXPECT_EQ("stub_server", upstream_format.format(header, header, header, stream_info)); } { - RequestInfoFormatter upstream_format("REQUESTED_SERVER_NAME"); + StreamInfoFormatter upstream_format("REQUESTED_SERVER_NAME"); std::string requested_server_name; - EXPECT_CALL(request_info, requestedServerName()) + EXPECT_CALL(stream_info, requestedServerName()) .WillRepeatedly(ReturnRef(requested_server_name)); - EXPECT_EQ("-", upstream_format.format(header, header, header, request_info)); + EXPECT_EQ("-", upstream_format.format(header, header, header, stream_info)); } } TEST(AccessLogFormatterTest, requestHeaderFormatter) { - RequestInfo::MockRequestInfo request_info; + StreamInfo::MockStreamInfo stream_info; Http::TestHeaderMapImpl request_header{{":method", "GET"}, {":path", "/"}}; Http::TestHeaderMapImpl response_header{{":method", "PUT"}}; Http::TestHeaderMapImpl response_trailer{{":method", "POST"}, {"test-2", "test-2"}}; @@ -212,30 +212,30 @@ TEST(AccessLogFormatterTest, requestHeaderFormatter) { { RequestHeaderFormatter formatter(":Method", "", absl::optional()); EXPECT_EQ("GET", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } { RequestHeaderFormatter formatter(":path", ":method", absl::optional()); EXPECT_EQ("/", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } { RequestHeaderFormatter formatter(":TEST", ":METHOD", absl::optional()); EXPECT_EQ("GET", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } { RequestHeaderFormatter formatter("does_not_exist", "", absl::optional()); EXPECT_EQ("-", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } } TEST(AccessLogFormatterTest, responseHeaderFormatter) { - RequestInfo::MockRequestInfo request_info; + StreamInfo::MockStreamInfo stream_info; Http::TestHeaderMapImpl request_header{{":method", "GET"}, {":path", "/"}}; Http::TestHeaderMapImpl response_header{{":method", "PUT"}, {"test", "test"}}; Http::TestHeaderMapImpl response_trailer{{":method", "POST"}, {"test-2", "test-2"}}; @@ -243,30 +243,30 @@ TEST(AccessLogFormatterTest, responseHeaderFormatter) { { ResponseHeaderFormatter formatter(":method", "", absl::optional()); EXPECT_EQ("PUT", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } { ResponseHeaderFormatter formatter("test", ":method", absl::optional()); EXPECT_EQ("test", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } { ResponseHeaderFormatter formatter(":path", ":method", absl::optional()); EXPECT_EQ("PUT", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } { ResponseHeaderFormatter formatter("does_not_exist", "", absl::optional()); EXPECT_EQ("-", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } } TEST(AccessLogFormatterTest, responseTrailerFormatter) { - RequestInfo::MockRequestInfo request_info; + StreamInfo::MockStreamInfo stream_info; Http::TestHeaderMapImpl request_header{{":method", "GET"}, {":path", "/"}}; Http::TestHeaderMapImpl response_header{{":method", "PUT"}, {"test", "test"}}; Http::TestHeaderMapImpl response_trailer{{":method", "POST"}, {"test-2", "test-2"}}; @@ -274,25 +274,25 @@ TEST(AccessLogFormatterTest, responseTrailerFormatter) { { ResponseTrailerFormatter formatter(":method", "", absl::optional()); EXPECT_EQ("POST", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } { ResponseTrailerFormatter formatter("test-2", ":method", absl::optional()); EXPECT_EQ("test-2", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } { ResponseTrailerFormatter formatter(":path", ":method", absl::optional()); EXPECT_EQ("POST", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } { ResponseTrailerFormatter formatter("does_not_exist", "", absl::optional()); EXPECT_EQ("-", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } } @@ -362,28 +362,217 @@ TEST(AccessLogFormatterTest, dynamicMetadataFormatter) { } TEST(AccessLogFormatterTest, startTimeFormatter) { - NiceMock request_info; + NiceMock stream_info; Http::TestHeaderMapImpl header{{":method", "GET"}, {":path", "/"}}; { StartTimeFormatter start_time_format("%Y/%m/%d"); time_t test_epoch = 1522280158; SystemTime time = std::chrono::system_clock::from_time_t(test_epoch); - EXPECT_CALL(request_info, startTime()).WillOnce(Return(time)); - EXPECT_EQ("2018/03/28", start_time_format.format(header, header, header, request_info)); + EXPECT_CALL(stream_info, startTime()).WillOnce(Return(time)); + EXPECT_EQ("2018/03/28", start_time_format.format(header, header, header, stream_info)); } { StartTimeFormatter start_time_format(""); SystemTime time; - EXPECT_CALL(request_info, startTime()).WillOnce(Return(time)); + EXPECT_CALL(stream_info, startTime()).WillOnce(Return(time)); EXPECT_EQ(AccessLogDateTimeFormatter::fromTime(time), - start_time_format.format(header, header, header, request_info)); + start_time_format.format(header, header, header, stream_info)); + } +} + +TEST(AccessLogFormatterTest, JsonFormatterTest) { + { + StreamInfo::MockStreamInfo stream_info; + Http::TestHeaderMapImpl request_header{}; + Http::TestHeaderMapImpl response_header{}; + Http::TestHeaderMapImpl response_trailer{}; + + envoy::api::v2::core::Metadata metadata; + populateMetadataTestData(metadata); + absl::optional protocol = Http::Protocol::Http11; + EXPECT_CALL(stream_info, protocol()).WillRepeatedly(Return(protocol)); + + std::map expected_json_map = {{"plain_string", "plain_string_value"}}; + + const std::map key_mapping = { + {"plain_string", "plain_string_value"}}; + JsonFormatterImpl formatter(key_mapping); + + auto actual_json_map = + formatter.to_map(request_header, response_header, response_trailer, stream_info); + EXPECT_THAT(actual_json_map, ::testing::ContainerEq(expected_json_map)); + + auto actual_string = + formatter.format(request_header, response_header, response_trailer, stream_info); + EXPECT_NO_THROW(Json::Factory::loadFromString(actual_string)); + } + + { + StreamInfo::MockStreamInfo stream_info; + Http::TestHeaderMapImpl request_header{}; + Http::TestHeaderMapImpl response_header{}; + Http::TestHeaderMapImpl response_trailer{}; + + envoy::api::v2::core::Metadata metadata; + populateMetadataTestData(metadata); + absl::optional protocol = Http::Protocol::Http11; + EXPECT_CALL(stream_info, protocol()).WillRepeatedly(Return(protocol)); + + std::map expected_json_map = {{"protocol", "HTTP/1.1"}}; + + const std::map key_mapping = {{"protocol", "%PROTOCOL%"}}; + JsonFormatterImpl formatter(key_mapping); + + auto actual_json_map = + formatter.to_map(request_header, response_header, response_trailer, stream_info); + EXPECT_THAT(actual_json_map, ::testing::ContainerEq(expected_json_map)); + + auto actual_string = + formatter.format(request_header, response_header, response_trailer, stream_info); + EXPECT_NO_THROW(Json::Factory::loadFromString(actual_string)); + } + + { + StreamInfo::MockStreamInfo stream_info; + Http::TestHeaderMapImpl request_header{{"some_request_header", "SOME_REQUEST_HEADER"}}; + Http::TestHeaderMapImpl response_header{{"some_response_header", "SOME_RESPONSE_HEADER"}}; + Http::TestHeaderMapImpl response_trailer{}; + + std::map expected_json_map = { + {"protocol", "HTTP/1.1"}, + {"some_request_header", "SOME_REQUEST_HEADER"}, + {"nonexistent_response_header", "-"}, + {"some_response_header", "SOME_RESPONSE_HEADER"}}; + + const std::map key_mapping = { + {"protocol", "%PROTOCOL%"}, + {"some_request_header", "%REQ(some_request_header)%"}, + {"nonexistent_response_header", "%RESP(nonexistent_response_header)%"}, + {"some_response_header", "%RESP(some_response_header)%"}}; + JsonFormatterImpl formatter(key_mapping); + + absl::optional protocol = Http::Protocol::Http11; + EXPECT_CALL(stream_info, protocol()).WillRepeatedly(Return(protocol)); + + auto actual_json_map = + formatter.to_map(request_header, response_header, response_trailer, stream_info); + EXPECT_THAT(actual_json_map, ::testing::ContainerEq(expected_json_map)); + + auto actual_string = + formatter.format(request_header, response_header, response_trailer, stream_info); + EXPECT_NO_THROW(Json::Factory::loadFromString(actual_string)); + } + + { + StreamInfo::MockStreamInfo stream_info; + Http::TestHeaderMapImpl request_header{{"request_present_header", "REQUEST_PRESENT_HEADER"}}; + Http::TestHeaderMapImpl response_header{{"response_present_header", "RESPONSE_PRESENT_HEADER"}}; + Http::TestHeaderMapImpl response_trailer{}; + + std::map expected_json_map = { + {"request_present_header_or_request_absent_header", "REQUEST_PRESENT_HEADER"}, + {"request_absent_header_or_request_present_header", "REQUEST_PRESENT_HEADER"}, + {"response_absent_header_or_response_absent_header", "RESPONSE_PRESENT_HEADER"}, + {"response_present_header_or_response_absent_header", "RESPONSE_PRESENT_HEADER"}}; + + const std::map key_mapping = { + {"request_present_header_or_request_absent_header", + "%REQ(request_present_header?request_absent_header)%"}, + {"request_absent_header_or_request_present_header", + "%REQ(request_absent_header?request_present_header)%"}, + {"response_absent_header_or_response_absent_header", + "%RESP(response_absent_header?response_present_header)%"}, + {"response_present_header_or_response_absent_header", + "%RESP(response_present_header?response_absent_header)%"}}; + JsonFormatterImpl formatter(key_mapping); + + absl::optional protocol = Http::Protocol::Http11; + EXPECT_CALL(stream_info, protocol()).WillRepeatedly(Return(protocol)); + + auto actual_json_map = + formatter.to_map(request_header, response_header, response_trailer, stream_info); + EXPECT_THAT(actual_json_map, ::testing::ContainerEq(expected_json_map)); + + auto actual_string = + formatter.format(request_header, response_header, response_trailer, stream_info); + EXPECT_NO_THROW(Json::Factory::loadFromString(actual_string)); + } + + { + StreamInfo::MockStreamInfo stream_info; + Http::TestHeaderMapImpl request_header{{"first", "GET"}, {":path", "/"}}; + Http::TestHeaderMapImpl response_header{{"second", "PUT"}, {"test", "test"}}; + Http::TestHeaderMapImpl response_trailer{{"third", "POST"}, {"test-2", "test-2"}}; + + envoy::api::v2::core::Metadata metadata; + populateMetadataTestData(metadata); + EXPECT_CALL(stream_info, dynamicMetadata()).WillRepeatedly(ReturnRef(metadata)); + + std::map expected_json_map = { + {"test_key", "\"test_value\""}, + {"test_obj", "{\"inner_key\":\"inner_value\"}"}, + {"test_obj.inner_key", "\"inner_value\""}}; + + const std::map key_mapping = { + {"test_key", "%DYNAMIC_METADATA(com.test:test_key)%"}, + {"test_obj", "%DYNAMIC_METADATA(com.test:test_obj)%"}, + {"test_obj.inner_key", "%DYNAMIC_METADATA(com.test:test_obj:inner_key)%"}}; + + JsonFormatterImpl formatter(key_mapping); + + auto actual_json_map = + formatter.to_map(request_header, response_header, response_trailer, stream_info); + EXPECT_THAT(actual_json_map, ::testing::ContainerEq(expected_json_map)); + + auto actual_string = + formatter.format(request_header, response_header, response_trailer, stream_info); + EXPECT_NO_THROW(Json::Factory::loadFromString(actual_string)); + } + + { + StreamInfo::MockStreamInfo stream_info; + Http::TestHeaderMapImpl request_header{}; + Http::TestHeaderMapImpl response_header{}; + Http::TestHeaderMapImpl response_trailer{}; + + time_t test_epoch = 1522280158; + SystemTime time = std::chrono::system_clock::from_time_t(test_epoch); + EXPECT_CALL(stream_info, startTime()).WillRepeatedly(Return(time)); + + // Needed to take into account the behavior in non-GMT timezones. + struct tm time_val; + gmtime_r(&test_epoch, &time_val); + time_t expected_time_t = mktime(&time_val); + + std::map expected_json_map = { + {"simple_date", "2018/03/28"}, + {"test_time", fmt::format("{}", expected_time_t)}, + {"bad_format", "bad_format"}, + {"default", "2018-03-28T23:35:58.000Z"}, + {"all_zeroes", "000000000.0.00.000"}}; + + const std::map key_mapping = { + {"simple_date", "%START_TIME(%Y/%m/%d)%"}, + {"test_time", "%START_TIME(%s)%"}, + {"bad_format", "%START_TIME(bad_format)%"}, + {"default", "%START_TIME%"}, + {"all_zeroes", "%START_TIME(%f.%1f.%2f.%3f)%"}}; + JsonFormatterImpl formatter(key_mapping); + + auto actual_json_map = + formatter.to_map(request_header, response_header, response_trailer, stream_info); + EXPECT_THAT(actual_json_map, ::testing::ContainerEq(expected_json_map)); + + auto actual_string = + formatter.format(request_header, response_header, response_trailer, stream_info); + EXPECT_NO_THROW(Json::Factory::loadFromString(actual_string)); } } TEST(AccessLogFormatterTest, CompositeFormatterSuccess) { - RequestInfo::MockRequestInfo request_info; + StreamInfo::MockStreamInfo stream_info; Http::TestHeaderMapImpl request_header{{"first", "GET"}, {":path", "/"}}; Http::TestHeaderMapImpl response_header{{"second", "PUT"}, {"test", "test"}}; Http::TestHeaderMapImpl response_trailer{{"third", "POST"}, {"test-2", "test-2"}}; @@ -395,10 +584,10 @@ TEST(AccessLogFormatterTest, CompositeFormatterSuccess) { FormatterImpl formatter(format); absl::optional protocol = Http::Protocol::Http11; - EXPECT_CALL(request_info, protocol()).WillRepeatedly(Return(protocol)); + EXPECT_CALL(stream_info, protocol()).WillRepeatedly(Return(protocol)); EXPECT_EQ("{{HTTP/1.1}} -++test GET PUT\t@POST@\ttest-2[]", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } { @@ -406,7 +595,7 @@ TEST(AccessLogFormatterTest, CompositeFormatterSuccess) { FormatterImpl formatter(format); EXPECT_EQ(format, - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } { @@ -416,19 +605,19 @@ TEST(AccessLogFormatterTest, CompositeFormatterSuccess) { FormatterImpl formatter(format); EXPECT_EQ("GET|G|PU|GET|POS", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } { envoy::api::v2::core::Metadata metadata; populateMetadataTestData(metadata); - EXPECT_CALL(request_info, dynamicMetadata()).WillRepeatedly(ReturnRef(metadata)); + EXPECT_CALL(stream_info, dynamicMetadata()).WillRepeatedly(ReturnRef(metadata)); const std::string format = "%DYNAMIC_METADATA(com.test:test_key)%|%DYNAMIC_METADATA(com.test:" "test_obj)%|%DYNAMIC_METADATA(com.test:test_obj:inner_key)%"; FormatterImpl formatter(format); EXPECT_EQ("\"test_value\"|{\"inner_key\":\"inner_value\"}|\"inner_value\"", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } { @@ -437,7 +626,7 @@ TEST(AccessLogFormatterTest, CompositeFormatterSuccess) { time_t test_epoch = 1522280158; SystemTime time = std::chrono::system_clock::from_time_t(test_epoch); - EXPECT_CALL(request_info, startTime()).WillRepeatedly(Return(time)); + EXPECT_CALL(stream_info, startTime()).WillRepeatedly(Return(time)); FormatterImpl formatter(format); // Needed to take into account the behavior in non-GMT timezones. @@ -447,7 +636,7 @@ TEST(AccessLogFormatterTest, CompositeFormatterSuccess) { EXPECT_EQ(fmt::format("2018/03/28|{}|bad_format|2018-03-28T23:35:58.000Z|000000000.0.00.000", expected_time_t), - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } { @@ -457,11 +646,11 @@ TEST(AccessLogFormatterTest, CompositeFormatterSuccess) { const time_t test_epoch = 0; const SystemTime time = std::chrono::system_clock::from_time_t(test_epoch); - EXPECT_CALL(request_info, startTime()).WillRepeatedly(Return(time)); + EXPECT_CALL(stream_info, startTime()).WillRepeatedly(Return(time)); FormatterImpl formatter(format); EXPECT_EQ("1970/01/01|0|bad_format|1970-01-01T00:00:00.000Z|000000000.0.00.000", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } { @@ -469,21 +658,21 @@ TEST(AccessLogFormatterTest, CompositeFormatterSuccess) { const std::string format = "%START_TIME(%s.%3f)%|%START_TIME(%s.%4f)%|%START_TIME(%s.%5f)%|%START_TIME(%s.%6f)%"; const SystemTime start_time(std::chrono::microseconds(1522796769123456)); - EXPECT_CALL(request_info, startTime()).WillRepeatedly(Return(start_time)); + EXPECT_CALL(stream_info, startTime()).WillRepeatedly(Return(start_time)); FormatterImpl formatter(format); EXPECT_EQ("1522796769.123|1522796769.1234|1522796769.12345|1522796769.123456", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } { const std::string format = "%START_TIME(segment1:%s.%3f|segment2:%s.%4f|seg3:%s.%6f|%s-%3f-asdf-%9f|.%7f:segm5:%Y)%"; const SystemTime start_time(std::chrono::microseconds(1522796769123456)); - EXPECT_CALL(request_info, startTime()).WillRepeatedly(Return(start_time)); + EXPECT_CALL(stream_info, startTime()).WillRepeatedly(Return(start_time)); FormatterImpl formatter(format); EXPECT_EQ("segment1:1522796769.123|segment2:1522796769.1234|seg3:1522796769.123456|1522796769-" "123-asdf-123456000|.1234560:segm5:2018", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } { @@ -491,10 +680,10 @@ TEST(AccessLogFormatterTest, CompositeFormatterSuccess) { // strftime("%%%%"") equals "%%", %1f will have 1 as its size. const std::string format = "%START_TIME(%%%%|%%%%%f|%s%%%%%3f|%1f%%%%%s)%"; const SystemTime start_time(std::chrono::microseconds(1522796769123456)); - EXPECT_CALL(request_info, startTime()).WillOnce(Return(start_time)); + EXPECT_CALL(stream_info, startTime()).WillOnce(Return(start_time)); FormatterImpl formatter(format); EXPECT_EQ("%%|%%123456000|1522796769%%123|1%%1522796769", - formatter.format(request_header, response_header, response_trailer, request_info)); + formatter.format(request_header, response_header, response_trailer, stream_info)); } } diff --git a/test/common/access_log/access_log_impl_test.cc b/test/common/access_log/access_log_impl_test.cc index 7753db8004a9f..25820484cc7d1 100644 --- a/test/common/access_log/access_log_impl_test.cc +++ b/test/common/access_log/access_log_impl_test.cc @@ -60,7 +60,7 @@ class AccessLogImplTest : public testing::Test { Http::TestHeaderMapImpl request_headers_{{":method", "GET"}, {":path", "/"}}; Http::TestHeaderMapImpl response_headers_; Http::TestHeaderMapImpl response_trailers_; - TestRequestInfo request_info_; + TestStreamInfo stream_info_; std::shared_ptr file_; StringViewSaver output_; @@ -79,13 +79,13 @@ TEST_F(AccessLogImplTest, LogMoreData) { InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromJson(json), context_); EXPECT_CALL(*file_, write(_)); - request_info_.response_flags_ = RequestInfo::ResponseFlag::UpstreamConnectionFailure; + stream_info_.response_flags_ = StreamInfo::ResponseFlag::UpstreamConnectionFailure; request_headers_.addCopy(Http::Headers::get().UserAgent, "user-agent-set"); request_headers_.addCopy(Http::Headers::get().RequestId, "id"); request_headers_.addCopy(Http::Headers::get().Host, "host"); request_headers_.addCopy(Http::Headers::get().ForwardedFor, "x.x.x.x"); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); EXPECT_EQ("[1999-01-01T00:00:00.000Z] \"GET / HTTP/1.1\" 0 UF 1 2 3 - \"x.x.x.x\" " "\"user-agent-set\" \"id\" \"host\" \"-\"\n", output_); @@ -103,7 +103,7 @@ TEST_F(AccessLogImplTest, EnvoyUpstreamServiceTime) { EXPECT_CALL(*file_, write(_)); response_headers_.addCopy(Http::Headers::get().EnvoyUpstreamServiceTime, "999"); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); EXPECT_EQ( "[1999-01-01T00:00:00.000Z] \"GET / HTTP/1.1\" 0 - 1 2 3 999 \"-\" \"-\" \"-\" \"-\" \"-\"\n", output_); @@ -119,7 +119,7 @@ TEST_F(AccessLogImplTest, NoFilter) { InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromJson(json), context_); EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); EXPECT_EQ( "[1999-01-01T00:00:00.000Z] \"GET / HTTP/1.1\" 0 - 1 2 3 - \"-\" \"-\" \"-\" \"-\" \"-\"\n", output_); @@ -127,7 +127,7 @@ TEST_F(AccessLogImplTest, NoFilter) { TEST_F(AccessLogImplTest, UpstreamHost) { std::shared_ptr cluster{new Upstream::MockClusterInfo()}; - request_info_.upstream_host_ = Upstream::makeTestHostDescription(cluster, "tcp://10.0.0.5:1234"); + stream_info_.upstream_host_ = Upstream::makeTestHostDescription(cluster, "tcp://10.0.0.5:1234"); const std::string json = R"EOF( { @@ -138,7 +138,7 @@ TEST_F(AccessLogImplTest, UpstreamHost) { InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromJson(json), context_); EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); EXPECT_EQ("[1999-01-01T00:00:00.000Z] \"GET / HTTP/1.1\" 0 - 1 2 3 - \"-\" \"-\" \"-\" \"-\" " "\"10.0.0.5:1234\"\n", output_); @@ -159,10 +159,10 @@ TEST_F(AccessLogImplTest, WithFilterMiss) { InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromJson(json), context_); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); - request_info_.response_code_ = 200; - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + stream_info_.response_code_ = 200; + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); } TEST_F(AccessLogImplTest, WithFilterHit) { @@ -181,15 +181,15 @@ TEST_F(AccessLogImplTest, WithFilterHit) { InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromJson(json), context_); EXPECT_CALL(*file_, write(_)).Times(3); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); - request_info_.response_code_ = 500; - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + stream_info_.response_code_ = 500; + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); - request_info_.response_code_ = 200; - request_info_.end_time_ = - request_info_.startTimeMonotonic() + std::chrono::microseconds(1001000000000000); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + stream_info_.response_code_ = 200; + stream_info_.end_time_ = + stream_info_.startTimeMonotonic() + std::chrono::microseconds(1001000000000000); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); } TEST_F(AccessLogImplTest, RuntimeFilter) { @@ -207,25 +207,25 @@ TEST_F(AccessLogImplTest, RuntimeFilter) { EXPECT_CALL(runtime_.snapshot_, featureEnabled("access_log.test_key", 0, 42, 100)) .WillOnce(Return(true)); EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); EXPECT_CALL(context_.random_, random()).WillOnce(Return(43)); EXPECT_CALL(runtime_.snapshot_, featureEnabled("access_log.test_key", 0, 43, 100)) .WillOnce(Return(false)); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); // Value is taken from x-request-id. request_headers_.addCopy("x-request-id", "000000ff-0000-0000-0000-000000000000"); EXPECT_CALL(runtime_.snapshot_, featureEnabled("access_log.test_key", 0, 55, 100)) .WillOnce(Return(true)); EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); EXPECT_CALL(runtime_.snapshot_, featureEnabled("access_log.test_key", 0, 55, 100)) .WillOnce(Return(false)); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); } TEST_F(AccessLogImplTest, RuntimeFilterV2) { @@ -248,25 +248,25 @@ name: envoy.file_access_log EXPECT_CALL(runtime_.snapshot_, featureEnabled("access_log.test_key", 5, 42, 10000)) .WillOnce(Return(true)); EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); EXPECT_CALL(context_.random_, random()).WillOnce(Return(43)); EXPECT_CALL(runtime_.snapshot_, featureEnabled("access_log.test_key", 5, 43, 10000)) .WillOnce(Return(false)); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); // Value is taken from x-request-id. request_headers_.addCopy("x-request-id", "000000ff-0000-0000-0000-000000000000"); EXPECT_CALL(runtime_.snapshot_, featureEnabled("access_log.test_key", 5, 255, 10000)) .WillOnce(Return(true)); EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); EXPECT_CALL(runtime_.snapshot_, featureEnabled("access_log.test_key", 5, 255, 10000)) .WillOnce(Return(false)); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); } TEST_F(AccessLogImplTest, RuntimeFilterV2IndependentRandomness) { @@ -291,13 +291,13 @@ name: envoy.file_access_log EXPECT_CALL(runtime_.snapshot_, featureEnabled("access_log.test_key", 5, 42, 1000000)) .WillOnce(Return(true)); EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); EXPECT_CALL(context_.random_, random()).WillOnce(Return(43)); EXPECT_CALL(runtime_.snapshot_, featureEnabled("access_log.test_key", 5, 43, 1000000)) .WillOnce(Return(false)); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); } TEST_F(AccessLogImplTest, PathRewrite) { @@ -313,7 +313,7 @@ TEST_F(AccessLogImplTest, PathRewrite) { InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromJson(json), context_); EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); EXPECT_EQ("[1999-01-01T00:00:00.000Z] \"GET /bar HTTP/1.1\" 0 - 1 2 3 - \"-\" \"-\" \"-\" \"-\" " "\"-\"\n", output_); @@ -330,10 +330,10 @@ TEST_F(AccessLogImplTest, healthCheckTrue) { InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromJson(json), context_); Http::TestHeaderMapImpl header_map{}; - request_info_.hc_request_ = true; + stream_info_.hc_request_ = true; EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&header_map, &response_headers_, &response_trailers_, request_info_); + log->log(&header_map, &response_headers_, &response_trailers_, stream_info_); } TEST_F(AccessLogImplTest, healthCheckFalse) { @@ -349,7 +349,7 @@ TEST_F(AccessLogImplTest, healthCheckFalse) { Http::TestHeaderMapImpl header_map{}; EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); } TEST_F(AccessLogImplTest, requestTracing) { @@ -374,19 +374,19 @@ TEST_F(AccessLogImplTest, requestTracing) { { Http::TestHeaderMapImpl forced_header{{"x-request-id", force_tracing_guid}}; EXPECT_CALL(*file_, write(_)); - log->log(&forced_header, &response_headers_, &response_trailers_, request_info_); + log->log(&forced_header, &response_headers_, &response_trailers_, stream_info_); } { Http::TestHeaderMapImpl not_traceable{{"x-request-id", not_traceable_guid}}; EXPECT_CALL(*file_, write(_)).Times(0); - log->log(¬_traceable, &response_headers_, &response_trailers_, request_info_); + log->log(¬_traceable, &response_headers_, &response_trailers_, stream_info_); } { Http::TestHeaderMapImpl sampled_header{{"x-request-id", sample_tracing_guid}}; EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&sampled_header, &response_headers_, &response_trailers_, request_info_); + log->log(&sampled_header, &response_headers_, &response_trailers_, stream_info_); } } @@ -431,20 +431,20 @@ TEST_F(AccessLogImplTest, andFilter) { )EOF"; InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromJson(json), context_); - request_info_.response_code_ = 500; + stream_info_.response_code_ = 500; { EXPECT_CALL(*file_, write(_)); Http::TestHeaderMapImpl header_map{{"user-agent", "NOT/Envoy/HC"}}; - log->log(&header_map, &response_headers_, &response_trailers_, request_info_); + log->log(&header_map, &response_headers_, &response_trailers_, stream_info_); } { EXPECT_CALL(*file_, write(_)).Times(0); Http::TestHeaderMapImpl header_map{}; - request_info_.hc_request_ = true; - log->log(&header_map, &response_headers_, &response_trailers_, request_info_); + stream_info_.hc_request_ = true; + log->log(&header_map, &response_headers_, &response_trailers_, stream_info_); } } @@ -461,19 +461,19 @@ TEST_F(AccessLogImplTest, orFilter) { )EOF"; InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromJson(json), context_); - request_info_.response_code_ = 500; + stream_info_.response_code_ = 500; { EXPECT_CALL(*file_, write(_)); Http::TestHeaderMapImpl header_map{{"user-agent", "NOT/Envoy/HC"}}; - log->log(&header_map, &response_headers_, &response_trailers_, request_info_); + log->log(&header_map, &response_headers_, &response_trailers_, stream_info_); } { EXPECT_CALL(*file_, write(_)); Http::TestHeaderMapImpl header_map{{"user-agent", "Envoy/HC"}}; - log->log(&header_map, &response_headers_, &response_trailers_, request_info_); + log->log(&header_map, &response_headers_, &response_trailers_, stream_info_); } } @@ -494,21 +494,21 @@ TEST_F(AccessLogImplTest, multipleOperators) { )EOF"; InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromJson(json), context_); - request_info_.response_code_ = 500; + stream_info_.response_code_ = 500; { EXPECT_CALL(*file_, write(_)); Http::TestHeaderMapImpl header_map{}; - log->log(&header_map, &response_headers_, &response_trailers_, request_info_); + log->log(&header_map, &response_headers_, &response_trailers_, stream_info_); } { EXPECT_CALL(*file_, write(_)).Times(0); Http::TestHeaderMapImpl header_map{}; - request_info_.hc_request_ = true; + stream_info_.hc_request_ = true; - log->log(&header_map, &response_headers_, &response_trailers_, request_info_); + log->log(&header_map, &response_headers_, &response_trailers_, stream_info_); } } @@ -527,23 +527,23 @@ TEST(AccessLogFilterTest, DurationWithRuntimeKey) { Config::FilterJson::translateAccessLogFilter(*filter_object, config); DurationFilter filter(config.duration_filter(), runtime); Http::TestHeaderMapImpl request_headers{{":method", "GET"}, {":path", "/"}}; - TestRequestInfo request_info; + TestStreamInfo stream_info; - request_info.end_time_ = request_info.startTimeMonotonic() + std::chrono::microseconds(100000); + stream_info.end_time_ = stream_info.startTimeMonotonic() + std::chrono::microseconds(100000); EXPECT_CALL(runtime.snapshot_, getInteger("key", 1000000)).WillOnce(Return(1)); - EXPECT_TRUE(filter.evaluate(request_info, request_headers)); + EXPECT_TRUE(filter.evaluate(stream_info, request_headers)); EXPECT_CALL(runtime.snapshot_, getInteger("key", 1000000)).WillOnce(Return(1000)); - EXPECT_FALSE(filter.evaluate(request_info, request_headers)); + EXPECT_FALSE(filter.evaluate(stream_info, request_headers)); - request_info.end_time_ = - request_info.startTimeMonotonic() + std::chrono::microseconds(100000001000); + stream_info.end_time_ = + stream_info.startTimeMonotonic() + std::chrono::microseconds(100000001000); EXPECT_CALL(runtime.snapshot_, getInteger("key", 1000000)).WillOnce(Return(100000000)); - EXPECT_TRUE(filter.evaluate(request_info, request_headers)); + EXPECT_TRUE(filter.evaluate(stream_info, request_headers)); - request_info.end_time_ = request_info.startTimeMonotonic() + std::chrono::microseconds(10000); + stream_info.end_time_ = stream_info.startTimeMonotonic() + std::chrono::microseconds(10000); EXPECT_CALL(runtime.snapshot_, getInteger("key", 1000000)).WillOnce(Return(100000000)); - EXPECT_FALSE(filter.evaluate(request_info, request_headers)); + EXPECT_FALSE(filter.evaluate(stream_info, request_headers)); } TEST(AccessLogFilterTest, StatusCodeWithRuntimeKey) { @@ -562,7 +562,7 @@ TEST(AccessLogFilterTest, StatusCodeWithRuntimeKey) { StatusCodeFilter filter(config.status_code_filter(), runtime); Http::TestHeaderMapImpl request_headers{{":method", "GET"}, {":path", "/"}}; - TestRequestInfo info; + TestStreamInfo info; info.response_code_ = 400; EXPECT_CALL(runtime.snapshot_, getInteger("key", 300)).WillOnce(Return(350)); @@ -588,15 +588,15 @@ name: envoy.file_access_log InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromV2Yaml(yaml), context_); - request_info_.response_code_ = 499; + stream_info_.response_code_ = 499; EXPECT_CALL(runtime_.snapshot_, getInteger("hello", 499)).WillOnce(Return(499)); EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); - request_info_.response_code_ = 500; + stream_info_.response_code_ = 500; EXPECT_CALL(runtime_.snapshot_, getInteger("hello", 499)).WillOnce(Return(499)); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); } TEST_F(AccessLogImplTest, HeaderPresence) { @@ -613,11 +613,11 @@ name: envoy.file_access_log InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromV2Yaml(yaml), context_); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); request_headers_.addCopy("test-header", "present"); EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); } TEST_F(AccessLogImplTest, HeaderExactMatch) { @@ -636,16 +636,16 @@ name: envoy.file_access_log InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromV2Yaml(yaml), context_); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); request_headers_.addCopy("test-header", "exact-match-value"); EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); request_headers_.remove("test-header"); request_headers_.addCopy("test-header", "not-exact-match-value"); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); } TEST_F(AccessLogImplTest, HeaderRegexMatch) { @@ -663,21 +663,21 @@ name: envoy.file_access_log InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromV2Yaml(yaml), context_); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); request_headers_.addCopy("test-header", "123"); EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); request_headers_.remove("test-header"); request_headers_.addCopy("test-header", "1234"); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); request_headers_.remove("test-header"); request_headers_.addCopy("test-header", "123.456"); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); } TEST_F(AccessLogImplTest, HeaderRangeMatch) { @@ -697,31 +697,31 @@ name: envoy.file_access_log InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromV2Yaml(yaml), context_); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); request_headers_.addCopy("test-header", "-1"); EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); request_headers_.remove("test-header"); request_headers_.addCopy("test-header", "0"); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); request_headers_.remove("test-header"); request_headers_.addCopy("test-header", "somestring"); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); request_headers_.remove("test-header"); request_headers_.addCopy("test-header", "10.9"); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); request_headers_.remove("test-header"); request_headers_.addCopy("test-header", "-1somestring"); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); } TEST_F(AccessLogImplTest, ResponseFlagFilterAnyFlag) { @@ -736,11 +736,11 @@ name: envoy.file_access_log InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromV2Yaml(yaml), context_); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); - request_info_.setResponseFlag(RequestInfo::ResponseFlag::NoRouteFound); + stream_info_.setResponseFlag(StreamInfo::ResponseFlag::NoRouteFound); EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); } TEST_F(AccessLogImplTest, ResponseFlagFilterSpecificFlag) { @@ -757,15 +757,15 @@ name: envoy.file_access_log InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromV2Yaml(yaml), context_); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); - request_info_.setResponseFlag(RequestInfo::ResponseFlag::NoRouteFound); + stream_info_.setResponseFlag(StreamInfo::ResponseFlag::NoRouteFound); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); - request_info_.setResponseFlag(RequestInfo::ResponseFlag::UpstreamOverflow); + stream_info_.setResponseFlag(StreamInfo::ResponseFlag::UpstreamOverflow); EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); } TEST_F(AccessLogImplTest, ResponseFlagFilterSeveralFlags) { @@ -783,15 +783,15 @@ name: envoy.file_access_log InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromV2Yaml(yaml), context_); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); - request_info_.setResponseFlag(RequestInfo::ResponseFlag::NoRouteFound); + stream_info_.setResponseFlag(StreamInfo::ResponseFlag::NoRouteFound); EXPECT_CALL(*file_, write(_)).Times(0); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); - request_info_.setResponseFlag(RequestInfo::ResponseFlag::UpstreamOverflow); + stream_info_.setResponseFlag(StreamInfo::ResponseFlag::UpstreamOverflow); EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info_); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); } TEST_F(AccessLogImplTest, ResponseFlagFilterAllFlagsInPGV) { @@ -818,33 +818,33 @@ name: envoy.file_access_log path: /dev/null )EOF"; - static_assert(RequestInfo::ResponseFlag::LastFlag == 0x2000, + static_assert(StreamInfo::ResponseFlag::LastFlag == 0x2000, "A flag has been added. Fix this code."); - std::vector all_response_flags = { - RequestInfo::ResponseFlag::FailedLocalHealthCheck, - RequestInfo::ResponseFlag::NoHealthyUpstream, - RequestInfo::ResponseFlag::UpstreamRequestTimeout, - RequestInfo::ResponseFlag::LocalReset, - RequestInfo::ResponseFlag::UpstreamRemoteReset, - RequestInfo::ResponseFlag::UpstreamConnectionFailure, - RequestInfo::ResponseFlag::UpstreamConnectionTermination, - RequestInfo::ResponseFlag::UpstreamOverflow, - RequestInfo::ResponseFlag::NoRouteFound, - RequestInfo::ResponseFlag::DelayInjected, - RequestInfo::ResponseFlag::FaultInjected, - RequestInfo::ResponseFlag::RateLimited, - RequestInfo::ResponseFlag::UnauthorizedExternalService, - RequestInfo::ResponseFlag::RateLimitServiceError, + std::vector all_response_flags = { + StreamInfo::ResponseFlag::FailedLocalHealthCheck, + StreamInfo::ResponseFlag::NoHealthyUpstream, + StreamInfo::ResponseFlag::UpstreamRequestTimeout, + StreamInfo::ResponseFlag::LocalReset, + StreamInfo::ResponseFlag::UpstreamRemoteReset, + StreamInfo::ResponseFlag::UpstreamConnectionFailure, + StreamInfo::ResponseFlag::UpstreamConnectionTermination, + StreamInfo::ResponseFlag::UpstreamOverflow, + StreamInfo::ResponseFlag::NoRouteFound, + StreamInfo::ResponseFlag::DelayInjected, + StreamInfo::ResponseFlag::FaultInjected, + StreamInfo::ResponseFlag::RateLimited, + StreamInfo::ResponseFlag::UnauthorizedExternalService, + StreamInfo::ResponseFlag::RateLimitServiceError, }; InstanceSharedPtr log = AccessLogFactory::fromProto(parseAccessLogFromV2Yaml(yaml), context_); for (const auto response_flag : all_response_flags) { - TestRequestInfo request_info; - request_info.setResponseFlag(response_flag); + TestStreamInfo stream_info; + stream_info.setResponseFlag(response_flag); EXPECT_CALL(*file_, write(_)); - log->log(&request_headers_, &response_headers_, &response_trailers_, request_info); + log->log(&request_headers_, &response_headers_, &response_trailers_, stream_info); } } diff --git a/test/common/access_log/test_util.h b/test/common/access_log/test_util.h index 7c7d8e8a8bd0f..f70a47e702c11 100644 --- a/test/common/access_log/test_util.h +++ b/test/common/access_log/test_util.h @@ -1,17 +1,17 @@ #pragma once -#include "envoy/request_info/request_info.h" +#include "envoy/stream_info/stream_info.h" #include "common/common/assert.h" -#include "common/request_info/filter_state_impl.h" +#include "common/stream_info/filter_state_impl.h" #include "test/test_common/test_time.h" namespace Envoy { -class TestRequestInfo : public RequestInfo::RequestInfo { +class TestStreamInfo : public StreamInfo::StreamInfo { public: - TestRequestInfo() { + TestStreamInfo() { tm fake_time; memset(&fake_time, 0, sizeof(fake_time)); fake_time.tm_year = 99; // tm < 1901-12-13 20:45:52 is not valid on osx @@ -36,11 +36,11 @@ class TestRequestInfo : public RequestInfo::RequestInfo { bool intersectResponseFlags(uint64_t response_flags) const override { return (response_flags_ & response_flags) != 0; } - bool hasResponseFlag(Envoy::RequestInfo::ResponseFlag response_flag) const override { + bool hasResponseFlag(Envoy::StreamInfo::ResponseFlag response_flag) const override { return response_flags_ & response_flag; } bool hasAnyResponseFlag() const override { return response_flags_ != 0; } - void setResponseFlag(Envoy::RequestInfo::ResponseFlag response_flag) override { + void setResponseFlag(Envoy::StreamInfo::ResponseFlag response_flag) override { response_flags_ |= response_flag; } void onUpstreamHostSelected(Upstream::HostDescriptionConstSharedPtr host) override { @@ -159,10 +159,10 @@ class TestRequestInfo : public RequestInfo::RequestInfo { (*metadata_.mutable_filter_metadata())[name].MergeFrom(value); }; - const Envoy::RequestInfo::FilterState& perRequestState() const override { + const Envoy::StreamInfo::FilterState& perRequestState() const override { return per_request_state_; } - Envoy::RequestInfo::FilterState& perRequestState() override { return per_request_state_; } + Envoy::StreamInfo::FilterState& perRequestState() override { return per_request_state_; } void setRequestedServerName(const absl::string_view requested_server_name) override { requested_server_name_ = std::string(requested_server_name); @@ -194,7 +194,7 @@ class TestRequestInfo : public RequestInfo::RequestInfo { Network::Address::InstanceConstSharedPtr downstream_remote_address_; const Router::RouteEntry* route_entry_{}; envoy::api::v2::core::Metadata metadata_{}; - Envoy::RequestInfo::FilterStateImpl per_request_state_{}; + Envoy::StreamInfo::FilterStateImpl per_request_state_{}; std::string requested_server_name_; DangerousDeprecatedTestTime test_time_; }; diff --git a/test/common/config/BUILD b/test/common/config/BUILD index 9b1756a2e9386..d97c5b3daf92b 100644 --- a/test/common/config/BUILD +++ b/test/common/config/BUILD @@ -52,6 +52,7 @@ envoy_cc_test( "//test/mocks/local_info:local_info_mocks", "//test/mocks/runtime:runtime_mocks", "//test/test_common:logging_lib", + "//test/test_common:simulated_time_system_lib", "//test/test_common:utility_lib", "@envoy_api//envoy/api/v2:discovery_cc", "@envoy_api//envoy/api/v2:eds_cc", diff --git a/test/common/config/grpc_mux_impl_test.cc b/test/common/config/grpc_mux_impl_test.cc index 030e7dbe26ec2..fb1abfb5c34fc 100644 --- a/test/common/config/grpc_mux_impl_test.cc +++ b/test/common/config/grpc_mux_impl_test.cc @@ -14,6 +14,7 @@ #include "test/mocks/local_info/mocks.h" #include "test/mocks/runtime/mocks.h" #include "test/test_common/logging.h" +#include "test/test_common/simulated_time_system.h" #include "test/test_common/utility.h" #include "gmock/gmock.h" @@ -36,7 +37,7 @@ namespace { class GrpcMuxImplTest : public testing::Test { public: GrpcMuxImplTest() : async_client_(new Grpc::MockAsyncClient()) { - dispatcher_.setTimeSystem(mock_time_system_); + dispatcher_.setTimeSystem(time_system_); } void setup() { @@ -76,7 +77,7 @@ class GrpcMuxImplTest : public testing::Test { Grpc::MockAsyncStream async_stream_; std::unique_ptr grpc_mux_; NiceMock callbacks_; - NiceMock mock_time_system_; + Event::SimulatedTimeSystem time_system_; NiceMock local_info_; Stats::IsolatedStoreImpl stats_; }; @@ -310,8 +311,17 @@ TEST_F(GrpcMuxImplTest, WatchDemux) { expectSendMessage(type_url, {}, "2"); } +// Exactly one test requires a mock time system to provoke behavior that cannot +// easily be achieved with a SimulatedTimeSystem. +class GrpcMuxImplTestWithMockTimeSystem : public GrpcMuxImplTest { +protected: + GrpcMuxImplTestWithMockTimeSystem() { dispatcher_.setTimeSystem(mock_time_system_); } + + MockTimeSystem mock_time_system_; +}; + // Verifies that warning messages get logged when Envoy detects too many requests. -TEST_F(GrpcMuxImplTest, TooManyRequests) { +TEST_F(GrpcMuxImplTestWithMockTimeSystem, TooManyRequests) { setup(); EXPECT_CALL(async_stream_, sendMessage(_, false)).Times(AtLeast(100)); diff --git a/test/common/grpc/grpc_client_integration_test_harness.h b/test/common/grpc/grpc_client_integration_test_harness.h index 1405c4ab4c1ce..16b786d28ba4a 100644 --- a/test/common/grpc/grpc_client_integration_test_harness.h +++ b/test/common/grpc/grpc_client_integration_test_harness.h @@ -268,7 +268,7 @@ class GrpcClientIntegrationTest : public GrpcClientIntegrationParamTest { EXPECT_CALL(cm_, httpConnPoolForCluster(_, _, _, _)) .WillRepeatedly(Return(http_conn_pool_.get())); http_async_client_ = std::make_unique( - *cluster_info_ptr_, *stats_store_, dispatcher_, local_info_, cm_, runtime_, random_, + cluster_info_ptr_, *stats_store_, dispatcher_, local_info_, cm_, runtime_, random_, std::move(shadow_writer_ptr_)); EXPECT_CALL(cm_, httpAsyncClientForCluster(fake_cluster_name_)) .WillRepeatedly(ReturnRef(*http_async_client_)); diff --git a/test/common/http/BUILD b/test/common/http/BUILD index 93fa583a5c478..b9f6104ed30e5 100644 --- a/test/common/http/BUILD +++ b/test/common/http/BUILD @@ -121,7 +121,7 @@ envoy_cc_fuzz_test( "//test/mocks/ssl:ssl_mocks", "//test/mocks/tracing:tracing_mocks", "//test/mocks/upstream:upstream_mocks", - "//test/test_common:test_time_lib", + "//test/test_common:simulated_time_system_lib", "@envoy_api//envoy/config/filter/network/http_connection_manager/v2:http_connection_manager_cc", ], ) diff --git a/test/common/http/async_client_impl_test.cc b/test/common/http/async_client_impl_test.cc index c81ac4dffcfaf..7503acc4c43ae 100644 --- a/test/common/http/async_client_impl_test.cc +++ b/test/common/http/async_client_impl_test.cc @@ -35,7 +35,7 @@ namespace { class AsyncClientImplTest : public testing::Test { public: AsyncClientImplTest() - : client_(*cm_.thread_local_cluster_.cluster_.info_, stats_store_, dispatcher_, local_info_, + : client_(cm_.thread_local_cluster_.cluster_.info_, stats_store_, dispatcher_, local_info_, cm_, runtime_, random_, Router::ShadowWriterPtr{new NiceMock()}) { message_->headers().insertMethod().value(std::string("GET")); @@ -909,6 +909,9 @@ TEST_F(AsyncClientImplTest, RdsGettersTest) { EXPECT_EQ("", route_config.name()); EXPECT_EQ(0, route_config.internalOnlyHeaders().size()); EXPECT_EQ(nullptr, route_config.route(headers, 0)); + auto cluster_info = filter_callbacks->clusterInfo(); + ASSERT_NE(nullptr, cluster_info); + EXPECT_EQ(cm_.thread_local_cluster_.cluster_.info_, cluster_info); EXPECT_CALL(stream_callbacks_, onReset()); } diff --git a/test/common/http/conn_manager_impl_fuzz_test.cc b/test/common/http/conn_manager_impl_fuzz_test.cc index 4144b141ef8af..7fb359966cdf0 100644 --- a/test/common/http/conn_manager_impl_fuzz_test.cc +++ b/test/common/http/conn_manager_impl_fuzz_test.cc @@ -31,7 +31,7 @@ #include "test/mocks/ssl/mocks.h" #include "test/mocks/tracing/mocks.h" #include "test/mocks/upstream/mocks.h" -#include "test/test_common/test_time.h" +#include "test/test_common/simulated_time_system.h" #include "gmock/gmock.h" @@ -56,7 +56,7 @@ class FuzzConfig : public ConnectionManagerConfig { }; FuzzConfig() - : route_config_provider_(test_time_.timeSystem()), + : route_config_provider_(time_system_), stats_{{ALL_HTTP_CONN_MAN_STATS(POOL_COUNTER(fake_stats_), POOL_GAUGE(fake_stats_), POOL_HISTOGRAM(fake_stats_))}, "", @@ -122,7 +122,7 @@ class FuzzConfig : public ConnectionManagerConfig { MockStreamEncoderFilter* encoder_filter_{}; NiceMock filter_factory_; absl::optional idle_timeout_; - DangerousDeprecatedTestTime test_time_; + Event::SimulatedTimeSystem time_system_; RouteConfigProvider route_config_provider_; std::string server_name_; Stats::IsolatedStoreImpl fake_stats_; @@ -384,7 +384,6 @@ DEFINE_PROTO_FUZZER(const test::common::http::ConnManagerImplTestCase& input) { NiceMock local_info; NiceMock cluster_manager; NiceMock filter_callbacks; - NiceMock time_system; std::unique_ptr ssl_connection; bool connection_alive = true; @@ -398,7 +397,7 @@ DEFINE_PROTO_FUZZER(const test::common::http::ConnManagerImplTestCase& input) { std::make_shared("0.0.0.0"); ConnectionManagerImpl conn_manager(config, drain_close, random, tracer, runtime, local_info, - cluster_manager, nullptr, time_system); + cluster_manager, nullptr, config.time_system_); conn_manager.initializeReadFilterCallbacks(filter_callbacks); std::vector streams; diff --git a/test/common/http/conn_manager_impl_test.cc b/test/common/http/conn_manager_impl_test.cc index c58f3fd8df7d5..acef820b88efa 100644 --- a/test/common/http/conn_manager_impl_test.cc +++ b/test/common/http/conn_manager_impl_test.cc @@ -36,6 +36,7 @@ #include "test/mocks/server/mocks.h" #include "test/mocks/ssl/mocks.h" #include "test/mocks/tracing/mocks.h" +#include "test/mocks/upstream/cluster_info.h" #include "test/mocks/upstream/mocks.h" #include "test/test_common/printers.h" #include "test/test_common/test_time.h" @@ -209,15 +210,15 @@ class HttpConnectionManagerImplTest : public Test, public ConnectionManagerConfi ON_CALL(route_entry, useOldStyleWebSocket()).WillByDefault(Return(true)); ON_CALL(route_entry, createWebSocketProxy(_, _, _, _, _)) .WillByDefault(Invoke([this, &route_entry](Http::HeaderMap& request_headers, - RequestInfo::RequestInfo& request_info, + StreamInfo::StreamInfo& stream_info, Http::WebSocketProxyCallbacks& callbacks, Upstream::ClusterManager& cluster_manager, Network::ReadFilterCallbacks* read_callbacks) { auto config(std::make_shared( envoy::config::filter::network::tcp_proxy::v2::TcpProxy(), factory_context_)); auto ret = std::make_unique( - request_headers, request_info, route_entry, callbacks, cluster_manager, - read_callbacks, config, test_time_.timeSystem()); + request_headers, stream_info, route_entry, callbacks, cluster_manager, read_callbacks, + config, test_time_.timeSystem()); return ret; })); } @@ -344,7 +345,7 @@ TEST_F(HttpConnectionManagerImplTest, HeaderOnlyRequestAndResponse) { EXPECT_NE(nullptr, headers.ForwardedFor()); EXPECT_STREQ("http", headers.ForwardedProto()->value().c_str()); if (headers.Path()->value() == "/healthcheck") { - filter->callbacks_->requestInfo().healthCheck(true); + filter->callbacks_->streamInfo().healthCheck(true); } return FilterHeadersStatus::StopIteration; @@ -566,8 +567,8 @@ TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlow) { NiceMock* span = new NiceMock(); EXPECT_CALL(tracer_, startSpan_(_, _, _, _)) .WillOnce( - Invoke([&](const Tracing::Config& config, const HeaderMap&, - const RequestInfo::RequestInfo&, const Tracing::Decision) -> Tracing::Span* { + Invoke([&](const Tracing::Config& config, const HeaderMap&, const StreamInfo::StreamInfo&, + const Tracing::Decision) -> Tracing::Span* { EXPECT_EQ(Tracing::OperationName::Ingress, config.operationName()); return span; @@ -633,8 +634,8 @@ TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlowIngressDecorat NiceMock* span = new NiceMock(); EXPECT_CALL(tracer_, startSpan_(_, _, _, _)) .WillOnce( - Invoke([&](const Tracing::Config& config, const HeaderMap&, - const RequestInfo::RequestInfo&, const Tracing::Decision) -> Tracing::Span* { + Invoke([&](const Tracing::Config& config, const HeaderMap&, const StreamInfo::StreamInfo&, + const Tracing::Decision) -> Tracing::Span* { EXPECT_EQ(Tracing::OperationName::Ingress, config.operationName()); return span; @@ -695,8 +696,8 @@ TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlowIngressDecorat NiceMock* span = new NiceMock(); EXPECT_CALL(tracer_, startSpan_(_, _, _, _)) .WillOnce( - Invoke([&](const Tracing::Config& config, const HeaderMap&, - const RequestInfo::RequestInfo&, const Tracing::Decision) -> Tracing::Span* { + Invoke([&](const Tracing::Config& config, const HeaderMap&, const StreamInfo::StreamInfo&, + const Tracing::Decision) -> Tracing::Span* { EXPECT_EQ(Tracing::OperationName::Ingress, config.operationName()); return span; @@ -762,8 +763,8 @@ TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlowEgressDecorato NiceMock* span = new NiceMock(); EXPECT_CALL(tracer_, startSpan_(_, _, _, _)) .WillOnce( - Invoke([&](const Tracing::Config& config, const HeaderMap&, - const RequestInfo::RequestInfo&, const Tracing::Decision) -> Tracing::Span* { + Invoke([&](const Tracing::Config& config, const HeaderMap&, const StreamInfo::StreamInfo&, + const Tracing::Decision) -> Tracing::Span* { EXPECT_EQ(Tracing::OperationName::Egress, config.operationName()); return span; @@ -829,8 +830,8 @@ TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlowEgressDecorato NiceMock* span = new NiceMock(); EXPECT_CALL(tracer_, startSpan_(_, _, _, _)) .WillOnce( - Invoke([&](const Tracing::Config& config, const HeaderMap&, - const RequestInfo::RequestInfo&, const Tracing::Decision) -> Tracing::Span* { + Invoke([&](const Tracing::Config& config, const HeaderMap&, const StreamInfo::StreamInfo&, + const Tracing::Decision) -> Tracing::Span* { EXPECT_EQ(Tracing::OperationName::Egress, config.operationName()); return span; @@ -938,12 +939,12 @@ TEST_F(HttpConnectionManagerImplTest, TestAccessLog) { EXPECT_CALL(*handler, log(_, _, _, _)) .WillOnce(Invoke([](const HeaderMap*, const HeaderMap*, const HeaderMap*, - const RequestInfo::RequestInfo& request_info) { - EXPECT_TRUE(request_info.responseCode()); - EXPECT_EQ(request_info.responseCode().value(), uint32_t(200)); - EXPECT_NE(nullptr, request_info.downstreamLocalAddress()); - EXPECT_NE(nullptr, request_info.downstreamRemoteAddress()); - EXPECT_NE(nullptr, request_info.routeEntry()); + const StreamInfo::StreamInfo& stream_info) { + EXPECT_TRUE(stream_info.responseCode()); + EXPECT_EQ(stream_info.responseCode().value(), uint32_t(200)); + EXPECT_NE(nullptr, stream_info.downstreamLocalAddress()); + EXPECT_NE(nullptr, stream_info.downstreamRemoteAddress()); + EXPECT_NE(nullptr, stream_info.routeEntry()); })); StreamDecoder* decoder = nullptr; @@ -982,12 +983,12 @@ TEST_F(HttpConnectionManagerImplTest, TestAccessLogWithTrailers) { EXPECT_CALL(*handler, log(_, _, _, _)) .WillOnce(Invoke([](const HeaderMap*, const HeaderMap*, const HeaderMap*, - const RequestInfo::RequestInfo& request_info) { - EXPECT_TRUE(request_info.responseCode()); - EXPECT_EQ(request_info.responseCode().value(), uint32_t(200)); - EXPECT_NE(nullptr, request_info.downstreamLocalAddress()); - EXPECT_NE(nullptr, request_info.downstreamRemoteAddress()); - EXPECT_NE(nullptr, request_info.routeEntry()); + const StreamInfo::StreamInfo& stream_info) { + EXPECT_TRUE(stream_info.responseCode()); + EXPECT_EQ(stream_info.responseCode().value(), uint32_t(200)); + EXPECT_NE(nullptr, stream_info.downstreamLocalAddress()); + EXPECT_NE(nullptr, stream_info.downstreamRemoteAddress()); + EXPECT_NE(nullptr, stream_info.routeEntry()); })); StreamDecoder* decoder = nullptr; @@ -1029,12 +1030,12 @@ TEST_F(HttpConnectionManagerImplTest, TestAccessLogWithInvalidRequest) { EXPECT_CALL(*handler, log(_, _, _, _)) .WillOnce(Invoke([](const HeaderMap*, const HeaderMap*, const HeaderMap*, - const RequestInfo::RequestInfo& request_info) { - EXPECT_TRUE(request_info.responseCode()); - EXPECT_EQ(request_info.responseCode().value(), uint32_t(400)); - EXPECT_NE(nullptr, request_info.downstreamLocalAddress()); - EXPECT_NE(nullptr, request_info.downstreamRemoteAddress()); - EXPECT_EQ(nullptr, request_info.routeEntry()); + const StreamInfo::StreamInfo& stream_info) { + EXPECT_TRUE(stream_info.responseCode()); + EXPECT_EQ(stream_info.responseCode().value(), uint32_t(400)); + EXPECT_NE(nullptr, stream_info.downstreamLocalAddress()); + EXPECT_NE(nullptr, stream_info.downstreamRemoteAddress()); + EXPECT_EQ(nullptr, stream_info.routeEntry()); })); StreamDecoder* decoder = nullptr; @@ -1507,7 +1508,7 @@ TEST_F(HttpConnectionManagerImplTest, AllowNonWebSocketOnWebSocketRoute) { TEST_F(HttpConnectionManagerImplTest, WebSocketNoThreadLocalCluster) { setup(false, ""); - EXPECT_CALL(cluster_manager_, get(_)).WillOnce(Return(nullptr)); + EXPECT_CALL(cluster_manager_, get(_)).Times(2).WillRepeatedly(Return(nullptr)); expectOnUpstreamInitFailure(); EXPECT_EQ(1U, stats_.named_.downstream_cx_websocket_active_.value()); EXPECT_EQ(1U, stats_.named_.downstream_cx_websocket_total_.value()); @@ -2639,9 +2640,19 @@ TEST_F(HttpConnectionManagerImplTest, FilterClearRouteCache) { })); setupFilterChain(3, 2); + const std::string fake_cluster1_name = "fake_cluster1"; + const std::string fake_cluster2_name = "fake_cluster2"; - Router::RouteConstSharedPtr route1 = std::make_shared>(); - Router::RouteConstSharedPtr route2 = std::make_shared>(); + std::shared_ptr fake_cluster1 = + std::make_shared>(); + EXPECT_CALL(cluster_manager_, get(_)) + .WillOnce(Return(fake_cluster1.get())) + .WillOnce(Return(nullptr)); + + std::shared_ptr route1 = std::make_shared>(); + EXPECT_CALL(route1->route_entry_, clusterName()).WillRepeatedly(ReturnRef(fake_cluster1_name)); + std::shared_ptr route2 = std::make_shared>(); + EXPECT_CALL(route2->route_entry_, clusterName()).WillRepeatedly(ReturnRef(fake_cluster2_name)); EXPECT_CALL(*route_config_provider_.route_config_, route(_, _)) .WillOnce(Return(route1)) @@ -2651,23 +2662,25 @@ TEST_F(HttpConnectionManagerImplTest, FilterClearRouteCache) { EXPECT_CALL(*decoder_filters_[0], decodeHeaders(_, true)) .WillOnce(InvokeWithoutArgs([&]() -> FilterHeadersStatus { EXPECT_EQ(route1, decoder_filters_[0]->callbacks_->route()); - EXPECT_EQ(route1->routeEntry(), - decoder_filters_[0]->callbacks_->requestInfo().routeEntry()); + EXPECT_EQ(route1->routeEntry(), decoder_filters_[0]->callbacks_->streamInfo().routeEntry()); + EXPECT_EQ(fake_cluster1->info(), decoder_filters_[0]->callbacks_->clusterInfo()); decoder_filters_[0]->callbacks_->clearRouteCache(); return FilterHeadersStatus::Continue; })); EXPECT_CALL(*decoder_filters_[1], decodeHeaders(_, true)) .WillOnce(InvokeWithoutArgs([&]() -> FilterHeadersStatus { EXPECT_EQ(route2, decoder_filters_[1]->callbacks_->route()); - EXPECT_EQ(route2->routeEntry(), - decoder_filters_[1]->callbacks_->requestInfo().routeEntry()); + EXPECT_EQ(route2->routeEntry(), decoder_filters_[1]->callbacks_->streamInfo().routeEntry()); + // RDS & CDS consistency problem: route2 points to fake_cluster2, which doesn't exist. + EXPECT_EQ(nullptr, decoder_filters_[1]->callbacks_->clusterInfo()); decoder_filters_[1]->callbacks_->clearRouteCache(); return FilterHeadersStatus::Continue; })); EXPECT_CALL(*decoder_filters_[2], decodeHeaders(_, true)) .WillOnce(InvokeWithoutArgs([&]() -> FilterHeadersStatus { + EXPECT_EQ(nullptr, decoder_filters_[2]->callbacks_->clusterInfo()); EXPECT_EQ(nullptr, decoder_filters_[2]->callbacks_->route()); - EXPECT_EQ(nullptr, decoder_filters_[2]->callbacks_->requestInfo().routeEntry()); + EXPECT_EQ(nullptr, decoder_filters_[2]->callbacks_->streamInfo().routeEntry()); return FilterHeadersStatus::StopIteration; })); @@ -2722,78 +2735,6 @@ TEST_F(HttpConnectionManagerImplTest, UpstreamWatermarkCallbacks) { HeaderMapPtr{new TestHeaderMapImpl{{":status", "200"}}}, true); } -TEST_F(HttpConnectionManagerImplTest, DownstreamWatermarkCallbacks) { - setup(false, ""); - setUpEncoderAndDecoder(); - sendReqestHeadersAndData(); - - // Test what happens when there are no subscribers. - conn_manager_->onAboveWriteBufferHighWatermark(); - conn_manager_->onBelowWriteBufferLowWatermark(); - - // The connection manger will outlive callbacks but never reference them once deleted. - MockDownstreamWatermarkCallbacks callbacks; - - // Network::Connection callbacks are passed through the codec - ASSERT(decoder_filters_[0]->callbacks_ != nullptr); - EXPECT_CALL(*codec_, onUnderlyingConnectionAboveWriteBufferHighWatermark()); - conn_manager_->onAboveWriteBufferHighWatermark(); - EXPECT_CALL(*codec_, onUnderlyingConnectionBelowWriteBufferLowWatermark()); - conn_manager_->onBelowWriteBufferLowWatermark(); - - // Now add a watermark subscriber and make sure both the high and low watermark callbacks are - // propogated. - ASSERT_NE(0, decoder_filters_.size()); - decoder_filters_[0]->callbacks_->addDownstreamWatermarkCallbacks(callbacks); - // Make sure encoder filter callbacks are propogated to the watermark subscriber. - EXPECT_CALL(callbacks, onAboveWriteBufferHighWatermark()); - encoder_filters_[0]->callbacks_->onEncoderFilterAboveWriteBufferHighWatermark(); - EXPECT_CALL(callbacks, onBelowWriteBufferLowWatermark()); - encoder_filters_[0]->callbacks_->onEncoderFilterBelowWriteBufferLowWatermark(); - - ASSERT(stream_callbacks_ != nullptr); - // Finally make sure that watermark events on the downstream stream are passed to the watermark - // subscriber. - EXPECT_CALL(callbacks, onAboveWriteBufferHighWatermark()); - stream_callbacks_->onAboveWriteBufferHighWatermark(); - EXPECT_CALL(callbacks, onBelowWriteBufferLowWatermark()); - stream_callbacks_->onBelowWriteBufferLowWatermark(); - - // Set things up so the callbacks have been called twice. - EXPECT_CALL(callbacks, onAboveWriteBufferHighWatermark()); - stream_callbacks_->onAboveWriteBufferHighWatermark(); - EXPECT_CALL(callbacks, onAboveWriteBufferHighWatermark()); - encoder_filters_[0]->callbacks_->onEncoderFilterAboveWriteBufferHighWatermark(); - - // Now unsubscribe and verify no further callbacks are called. - EXPECT_CALL(callbacks, onBelowWriteBufferLowWatermark()).Times(0); - decoder_filters_[0]->callbacks_->removeDownstreamWatermarkCallbacks(callbacks); -} - -TEST_F(HttpConnectionManagerImplTest, UnderlyingConnectionWatermarksPassedOn) { - setup(false, ""); - - // Make sure codec_ is created. - EXPECT_CALL(*codec_, dispatch(_)); - Buffer::OwnedImpl fake_input(""); - conn_manager_->onData(fake_input, false); - - // Mark the connection manger as backed up before the stream is created. - ASSERT_EQ(decoder_filters_.size(), 0); - EXPECT_CALL(*codec_, onUnderlyingConnectionAboveWriteBufferHighWatermark()); - conn_manager_->onAboveWriteBufferHighWatermark(); - - // Now when the stream is created, it should be informed of the connection - // callbacks immediately. - EXPECT_CALL(filter_callbacks_.connection_, aboveHighWatermark()).WillOnce(Return(true)); - setUpEncoderAndDecoder(); - sendReqestHeadersAndData(); - ASSERT_GE(decoder_filters_.size(), 1); - MockDownstreamWatermarkCallbacks callbacks; - EXPECT_CALL(callbacks, onAboveWriteBufferHighWatermark()); - decoder_filters_[0]->callbacks_->addDownstreamWatermarkCallbacks(callbacks); -} - TEST_F(HttpConnectionManagerImplTest, UnderlyingConnectionWatermarksPassedOnWithLazyCreation) { setup(false, ""); @@ -2814,11 +2755,10 @@ TEST_F(HttpConnectionManagerImplTest, UnderlyingConnectionWatermarksPassedOnWith setUpBufferLimits(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> void { decoder = &conn_manager_->newStream(response_encoder_); + // Call the high buffer callbacks as the codecs do. + stream_callbacks_->onAboveWriteBufferHighWatermark(); })); - // Verify the high watermark is passed on. - EXPECT_CALL(filter_callbacks_.connection_, aboveHighWatermark()).WillOnce(Return(true)); - // Send fake data to kick off newStream being created. Buffer::OwnedImpl fake_input2("asdf"); conn_manager_->onData(fake_input2, false); @@ -2868,11 +2808,10 @@ TEST_F(HttpConnectionManagerImplTest, UnderlyingConnectionWatermarksUnwoundWithL setUpBufferLimits(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> void { decoder = &conn_manager_->newStream(response_encoder_); + // Call the high buffer callbacks as the codecs do. + stream_callbacks_->onAboveWriteBufferHighWatermark(); })); - // Verify the high watermark is passed on. - EXPECT_CALL(filter_callbacks_.connection_, aboveHighWatermark()).WillOnce(Return(true)); - // Send fake data to kick off newStream being created. Buffer::OwnedImpl fake_input2("asdf"); conn_manager_->onData(fake_input2, false); diff --git a/test/common/http/conn_manager_utility_test.cc b/test/common/http/conn_manager_utility_test.cc index 65a9325c52070..57d1fd706e5f0 100644 --- a/test/common/http/conn_manager_utility_test.cc +++ b/test/common/http/conn_manager_utility_test.cc @@ -470,6 +470,7 @@ TEST_F(ConnectionManagerUtilityTest, ExternalAddressExternalRequestUseRemote) { route_config_.internal_only_headers_.push_back(LowerCaseString("custom_header")); TestHeaderMapImpl headers{{"x-envoy-decorator-operation", "foo"}, {"x-envoy-downstream-service-cluster", "foo"}, + {"x-envoy-retriable-status-codes", "123,456"}, {"x-envoy-retry-on", "foo"}, {"x-envoy-retry-grpc-on", "foo"}, {"x-envoy-max-retries", "foo"}, @@ -485,6 +486,7 @@ TEST_F(ConnectionManagerUtilityTest, ExternalAddressExternalRequestUseRemote) { EXPECT_EQ("50.0.0.1", headers.get_("x-envoy-external-address")); EXPECT_FALSE(headers.has("x-envoy-decorator-operation")); EXPECT_FALSE(headers.has("x-envoy-downstream-service-cluster")); + EXPECT_FALSE(headers.has("x-envoy-retriable-status-codes")); EXPECT_FALSE(headers.has("x-envoy-retry-on")); EXPECT_FALSE(headers.has("x-envoy-retry-grpc-on")); EXPECT_FALSE(headers.has("x-envoy-max-retries")); @@ -530,7 +532,7 @@ TEST_F(ConnectionManagerUtilityTest, AppendInternalAddressXffNotInternalRequest) EXPECT_EQ((MutateRequestRet{"10.0.0.1:0", false}), callMutateRequestHeaders(headers, Protocol::Http2)); - EXPECT_EQ("10.0.0.2, 10.0.0.1", headers.get_("x-forwarded-for")); + EXPECT_EQ("10.0.0.2,10.0.0.1", headers.get_("x-forwarded-for")); } // A request that is from an internal address and uses remote address should be an internal request. diff --git a/test/common/http/utility_test.cc b/test/common/http/utility_test.cc index 0e72e83261a3f..7d378857fd7fe 100644 --- a/test/common/http/utility_test.cc +++ b/test/common/http/utility_test.cc @@ -173,7 +173,7 @@ TEST(HttpUtility, appendXff) { TestHeaderMapImpl headers{{"x-forwarded-for", "10.0.0.1"}}; Network::Address::Ipv4Instance address("127.0.0.1"); Utility::appendXff(headers, address); - EXPECT_EQ("10.0.0.1, 127.0.0.1", headers.get_("x-forwarded-for")); + EXPECT_EQ("10.0.0.1,127.0.0.1", headers.get_("x-forwarded-for")); } { diff --git a/test/common/network/BUILD b/test/common/network/BUILD index ba4eadec52082..23b5f1548ccda 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -51,7 +51,7 @@ envoy_cc_test( "//test/mocks/stats:stats_mocks", "//test/test_common:environment_lib", "//test/test_common:network_utility_lib", - "//test/test_common:test_time_lib", + "//test/test_common:simulated_time_system_lib", ], ) diff --git a/test/common/network/connection_impl_test.cc b/test/common/network/connection_impl_test.cc index 24a21b8f45a7f..f85e2ea92bb75 100644 --- a/test/common/network/connection_impl_test.cc +++ b/test/common/network/connection_impl_test.cc @@ -20,7 +20,7 @@ #include "test/test_common/environment.h" #include "test/test_common/network_utility.h" #include "test/test_common/printers.h" -#include "test/test_common/test_time.h" +#include "test/test_common/simulated_time_system.h" #include "test/test_common/utility.h" #include "gmock/gmock.h" @@ -77,7 +77,7 @@ INSTANTIATE_TEST_CASE_P(IpVersions, ConnectionImplDeathTest, TestUtility::ipTestParamsToString); TEST_P(ConnectionImplDeathTest, BadFd) { - MockTimeSystem time_system; + Event::SimulatedTimeSystem time_system; Event::DispatcherImpl dispatcher(time_system); EXPECT_DEATH_LOG_TO_STDERR( ConnectionImpl(dispatcher, std::make_unique(-1, nullptr, nullptr), @@ -169,7 +169,36 @@ class ConnectionImplTest : public testing::TestWithParam { } protected: - MockTimeSystem time_system_; + struct ConnectionMocks { + std::unique_ptr> dispatcher; + Event::MockTimer* timer; + std::unique_ptr> transport_socket; + }; + + ConnectionMocks createConnectionMocks() { + auto dispatcher = std::make_unique>(); + EXPECT_CALL(dispatcher->buffer_factory_, create_(_, _)) + .WillRepeatedly(Invoke([](std::function below_low, + std::function above_high) -> Buffer::Instance* { + // ConnectionImpl calls Envoy::MockBufferFactory::create(), which calls create_() and + // wraps the returned raw pointer below with a unique_ptr. + return new Buffer::WatermarkBuffer(below_low, above_high); + })); + + // This timer will be returned (transferring ownership) to the ConnectionImpl when createTimer() + // is called to allocate the delayed close timer. + auto timer = new Event::MockTimer(dispatcher.get()); + + auto file_event = std::make_unique>(); + EXPECT_CALL(*dispatcher, createFileEvent_(0, _, _, _)).WillOnce(Return(file_event.release())); + + auto transport_socket = std::make_unique>(); + EXPECT_CALL(*transport_socket, canFlushClose()).WillOnce(Return(true)); + + return ConnectionMocks{std::move(dispatcher), timer, std::move(transport_socket)}; + } + + Event::SimulatedTimeSystem time_system_; Event::DispatcherPtr dispatcher_; Stats::IsolatedStoreImpl stats_store_; Network::TcpListenSocket socket_{Network::Test::getAnyAddress(GetParam()), nullptr, true}; @@ -890,9 +919,11 @@ TEST_P(ConnectionImplTest, EmptyReadOnCloseTest) { TEST_P(ConnectionImplTest, FlushWriteCloseTest) { setUpBasicConnection(); connect(); - // Set a very high timeout value to prevent flaking. We are testing the common case where the - // timeout does not trigger. - server_connection_->setDelayedCloseTimeout(std::chrono::milliseconds(50000)); + + InSequence s1; + + time_system_.setMonotonicTime(std::chrono::milliseconds(0)); + server_connection_->setDelayedCloseTimeout(std::chrono::milliseconds(100)); std::shared_ptr client_read_filter(new NiceMock()); client_connection_->addReadFilter(client_read_filter); @@ -906,46 +937,30 @@ TEST_P(ConnectionImplTest, FlushWriteCloseTest) { // Server connection flushes the write and immediately closes the socket. // There shouldn't be a read/close race here (see issue #2929), since the client is blocked on // reading and the connection should close gracefully via FIN. + + EXPECT_CALL(stats.delayed_close_timeouts_, inc()).Times(0); + EXPECT_CALL(server_callbacks_, onEvent(ConnectionEvent::LocalClose)).Times(1); EXPECT_CALL(*client_read_filter, onData(BufferStringEqual("data"), false)) .Times(1) .WillOnce(InvokeWithoutArgs([&]() -> FilterStatus { + time_system_.setMonotonicTime(std::chrono::milliseconds(50)); dispatcher_->exit(); return FilterStatus::StopIteration; })); - EXPECT_CALL(stats.delayed_close_timeouts_, inc()).Times(0); EXPECT_CALL(client_callbacks_, onEvent(ConnectionEvent::RemoteClose)).Times(1); - EXPECT_CALL(server_callbacks_, onEvent(ConnectionEvent::LocalClose)).Times(1); server_connection_->close(ConnectionCloseType::FlushWrite); dispatcher_->run(Event::Dispatcher::RunType::Block); } -// Test that a FlushWrite close will trigger a timeout which closes the connection when the write -// buffer is not flushed within the configured interval. +// Test that a FlushWrite close will create and enable a timer which closes the connection when +// triggered. TEST_P(ConnectionImplTest, FlushWriteCloseTimeoutTest) { - NiceMock dispatcher; - EXPECT_CALL(dispatcher.buffer_factory_, create_(_, _)) - .WillRepeatedly(Invoke([](std::function below_low, - std::function above_high) -> Buffer::Instance* { - // ConnectionImpl calls Envoy::MockBufferFactory::create(), which calls create_() and wraps - // the returned raw pointer below with a unique_ptr. - return new Buffer::WatermarkBuffer(below_low, above_high); - })); - - // This timer will be returned (transferring ownership) to the ConnectionImpl when createTimer() - // is called to allocate the delayed close timer. - auto timer = new Event::MockTimer(&dispatcher); - EXPECT_CALL(*timer, enableTimer(_)).Times(1); - EXPECT_CALL(*timer, disableTimer()).Times(1); - - auto file_event = std::make_unique>(); - EXPECT_CALL(dispatcher, createFileEvent_(0, _, _, _)).WillOnce(Return(file_event.release())); - - auto transport_socket = std::make_unique>(); - EXPECT_CALL(*transport_socket, canFlushClose()).WillOnce(Return(true)); - + ConnectionMocks mocks = createConnectionMocks(); auto server_connection = std::make_unique( - dispatcher, std::make_unique(0, nullptr, nullptr), - std::move(transport_socket), true); + *mocks.dispatcher, std::make_unique(0, nullptr, nullptr), + std::move(mocks.transport_socket), true); + + InSequence s1; // Enable delayed connection close processing by setting a non-zero timeout value. The actual // value (> 0) doesn't matter since the callback is triggered below. @@ -953,16 +968,21 @@ TEST_P(ConnectionImplTest, FlushWriteCloseTimeoutTest) { NiceMockConnectionStats stats; server_connection->setConnectionStats(stats.toBufferStats()); - EXPECT_CALL(stats.delayed_close_timeouts_, inc()).Times(1); Buffer::OwnedImpl data("data"); server_connection->write(data, false); + // Data is pending in the write buffer, which will trigger the FlushWrite close to go into delayed // close processing. + EXPECT_CALL(*mocks.timer, enableTimer(_)).Times(1); server_connection->close(ConnectionCloseType::FlushWrite); + EXPECT_CALL(stats.delayed_close_timeouts_, inc()).Times(1); + // Since the callback is being invoked manually, disableTimer() will be called when the connection + // is closed by the callback. + EXPECT_CALL(*mocks.timer, disableTimer()).Times(1); // Issue the delayed close callback to ensure connection is closed. - timer->callback_(); + mocks.timer->callback_(); } // Test that a FlushWriteAndDelay close causes Envoy to flush the write and wait for the client/peer @@ -976,9 +996,11 @@ TEST_P(ConnectionImplTest, FlushWriteAndDelayCloseTest) { #endif setUpBasicConnection(); connect(); - // Set a very high timeout value to prevent flaking. We are testing the common case where the - // timeout does not trigger. - server_connection_->setDelayedCloseTimeout(std::chrono::milliseconds(50000)); + + InSequence s1; + + time_system_.setMonotonicTime(std::chrono::milliseconds(0)); + server_connection_->setDelayedCloseTimeout(std::chrono::milliseconds(100)); std::shared_ptr client_read_filter(new NiceMock()); client_connection_->addReadFilter(client_read_filter); @@ -992,6 +1014,8 @@ TEST_P(ConnectionImplTest, FlushWriteAndDelayCloseTest) { EXPECT_CALL(*client_read_filter, onData(BufferStringEqual("Connection: Close"), false)) .Times(1) .WillOnce(InvokeWithoutArgs([&]() -> FilterStatus { + // Advance time by 50ms; delayed close timer should _not_ trigger. + time_system_.setMonotonicTime(std::chrono::milliseconds(50)); client_connection_->close(ConnectionCloseType::NoFlush); return FilterStatus::StopIteration; })); @@ -1011,8 +1035,10 @@ TEST_P(ConnectionImplTest, FlushWriteAndDelayCloseTest) { TEST_P(ConnectionImplTest, FlushWriteAndDelayCloseTimerTriggerTest) { setUpBasicConnection(); connect(); - // This timer should always trigger since the client connection does not issue a close() during - // this test. + + InSequence s1; + + // This timer will be forced to trigger by ensuring time advances by >50ms during the test. server_connection_->setDelayedCloseTimeout(std::chrono::milliseconds(50)); std::shared_ptr client_read_filter(new NiceMock()); @@ -1024,23 +1050,30 @@ TEST_P(ConnectionImplTest, FlushWriteAndDelayCloseTimerTriggerTest) { Buffer::OwnedImpl data("Connection: Close"); server_connection_->write(data, false); + time_system_.setMonotonicTime(std::chrono::milliseconds(0)); + // The client _will not_ close the connection. Instead, expect the delayed close timer to trigger // on the server connection. EXPECT_CALL(*client_read_filter, onData(BufferStringEqual("Connection: Close"), false)) .Times(1) - .WillOnce(InvokeWithoutArgs([&]() -> FilterStatus { return FilterStatus::StopIteration; })); + .WillOnce(InvokeWithoutArgs([&]() -> FilterStatus { + time_system_.setMonotonicTime(std::chrono::milliseconds(100)); + return FilterStatus::StopIteration; + })); + server_connection_->close(ConnectionCloseType::FlushWriteAndDelay); EXPECT_CALL(stats.delayed_close_timeouts_, inc()).Times(1); + EXPECT_CALL(server_callbacks_, onEvent(ConnectionEvent::LocalClose)).Times(1); EXPECT_CALL(client_callbacks_, onEvent(ConnectionEvent::RemoteClose)) .Times(1) .WillOnce(Invoke([&](Network::ConnectionEvent) -> void { dispatcher_->exit(); })); - EXPECT_CALL(server_callbacks_, onEvent(ConnectionEvent::LocalClose)).Times(1); - server_connection_->close(ConnectionCloseType::FlushWriteAndDelay); dispatcher_->run(Event::Dispatcher::RunType::Block); } // Test that delayed close processing can be disabled by setting the delayed close timeout interval // to 0. TEST_P(ConnectionImplTest, FlushWriteAndDelayConfigDisabledTest) { + InSequence s1; + NiceMock callbacks; NiceMock dispatcher; EXPECT_CALL(dispatcher.buffer_factory_, create_(_, _)) @@ -1052,6 +1085,8 @@ TEST_P(ConnectionImplTest, FlushWriteAndDelayConfigDisabledTest) { dispatcher, std::make_unique(0, nullptr, nullptr), std::make_unique>(), true)); + time_system_.setMonotonicTime(std::chrono::milliseconds(0)); + // Ensure the delayed close timer is not created when the delayedCloseTimeout config value is set // to 0. server_connection->setDelayedCloseTimeout(std::chrono::milliseconds(0)); @@ -1062,12 +1097,73 @@ TEST_P(ConnectionImplTest, FlushWriteAndDelayConfigDisabledTest) { EXPECT_CALL(stats.delayed_close_timeouts_, inc()).Times(0); server_connection->close(ConnectionCloseType::FlushWriteAndDelay); + // Advance time by a value larger than the delayed close timeout default (1000ms). This would + // trigger the delayed close timer callback if set. + time_system_.setMonotonicTime(std::chrono::milliseconds(10000)); // Since the delayed close timer never triggers, the connection never closes. Close it here to end // the test cleanly due to the (fd == -1) assert in ~ConnectionImpl(). server_connection->close(ConnectionCloseType::NoFlush); } +// Test that tearing down the connection will disable the delayed close timer. +TEST_P(ConnectionImplTest, DelayedCloseTimeoutDisableOnSocketClose) { + ConnectionMocks mocks = createConnectionMocks(); + auto server_connection = std::make_unique( + *mocks.dispatcher, std::make_unique(0, nullptr, nullptr), + std::move(mocks.transport_socket), true); + + InSequence s1; + + // The actual timeout is insignificant, we just need to enable delayed close processing by setting + // it to > 0. + server_connection->setDelayedCloseTimeout(std::chrono::milliseconds(100)); + + Buffer::OwnedImpl data("data"); + server_connection->write(data, false); + EXPECT_CALL(*mocks.timer, enableTimer(_)).Times(1); + // Enable the delayed close timer. + server_connection->close(ConnectionCloseType::FlushWriteAndDelay); + EXPECT_CALL(*mocks.timer, disableTimer()).Times(1); + // This close() will call closeSocket(), which should disable the timer to avoid triggering it + // after the connection's data structures have been reset. + server_connection->close(ConnectionCloseType::NoFlush); +} + +// Test that the delayed close timeout callback is resilient to connection teardown edge cases. +TEST_P(ConnectionImplTest, DelayedCloseTimeoutNullStats) { + ConnectionMocks mocks = createConnectionMocks(); + auto server_connection = std::make_unique( + *mocks.dispatcher, std::make_unique(0, nullptr, nullptr), + std::move(mocks.transport_socket), true); + + InSequence s1; + + // The actual timeout is insignificant, we just need to enable delayed close processing by setting + // it to > 0. + server_connection->setDelayedCloseTimeout(std::chrono::milliseconds(100)); + + // NOTE: Avoid providing stats storage to the connection via setConnectionStats(). This guarantees + // that connection_stats_ is a nullptr and that the callback resiliency validation below tests + // that edge case. + + Buffer::OwnedImpl data("data"); + server_connection->write(data, false); + + EXPECT_CALL(*mocks.timer, enableTimer(_)).Times(1); + server_connection->close(ConnectionCloseType::FlushWriteAndDelay); + EXPECT_CALL(*mocks.timer, disableTimer()).Times(1); + // Copy the callback since mocks.timer will be freed when closeSocket() is called. + Event::TimerCb callback = mocks.timer->callback_; + // The following close() will call closeSocket() and reset internal data structures such as stats. + server_connection->close(ConnectionCloseType::NoFlush); + // Verify the onDelayedCloseTimeout() callback is resilient to the post closeSocket(), pre + // destruction state. This should not actually happen due to the timeout disablement in + // closeSocket(), but there is enough complexity in connection handling codepaths that being + // extra defensive is valuable. + callback(); +} + class MockTransportConnectionImplTest : public testing::Test { public: MockTransportConnectionImplTest() { @@ -1469,7 +1565,7 @@ TEST_P(ReadBufferLimitTest, SomeLimit) { class TcpClientConnectionImplTest : public testing::TestWithParam { protected: TcpClientConnectionImplTest() : dispatcher_(time_system_) {} - MockTimeSystem time_system_; + Event::SimulatedTimeSystem time_system_; Event::DispatcherImpl dispatcher_; }; INSTANTIATE_TEST_CASE_P(IpVersions, TcpClientConnectionImplTest, @@ -1510,7 +1606,7 @@ TEST_P(TcpClientConnectionImplTest, BadConnectConnRefused) { class PipeClientConnectionImplTest : public testing::Test { protected: PipeClientConnectionImplTest() : dispatcher_(time_system_) {} - MockTimeSystem time_system_; + Event::SimulatedTimeSystem time_system_; Event::DispatcherImpl dispatcher_; const std::string path_{TestEnvironment::unixDomainSocketPath("foo")}; }; diff --git a/test/common/network/listener_impl_test.cc b/test/common/network/listener_impl_test.cc index 805a8deb51c81..ada6632049a96 100644 --- a/test/common/network/listener_impl_test.cc +++ b/test/common/network/listener_impl_test.cc @@ -244,5 +244,44 @@ TEST_P(ListenerImplTest, WildcardListenerIpv4Compat) { dispatcher_.run(Event::Dispatcher::RunType::Block); } +TEST_P(ListenerImplTest, DisableAndEnableListener) { + testing::InSequence s1; + + TcpListenSocket socket(Network::Test::getAnyAddress(version_), nullptr, true); + MockListenerCallbacks listener_callbacks; + TestListenerImpl listener(dispatcher_, socket, listener_callbacks, true, true); + + // When listener is disabled, the timer should fire before any connection is accepted. + listener.disable(); + + ClientConnectionPtr client_connection = + dispatcher_.createClientConnection(socket.localAddress(), Address::InstanceConstSharedPtr(), + Network::Test::createRawBufferSocket(), nullptr); + client_connection->connect(); + Event::TimerPtr timer = dispatcher_.createTimer([&] { + client_connection->close(ConnectionCloseType::NoFlush); + dispatcher_.exit(); + }); + timer->enableTimer(std::chrono::milliseconds(2000)); + + EXPECT_CALL(listener_callbacks, onAccept_(_, _)).Times(0); + + dispatcher_.run(Event::Dispatcher::RunType::Block); + + // When the listener is re-enabled, the pending connection should be accepted. + listener.enable(); + + EXPECT_CALL(listener, getLocalAddress(_)) + .WillOnce(Invoke( + [](int fd) -> Address::InstanceConstSharedPtr { return Address::addressFromFd(fd); })); + EXPECT_CALL(listener_callbacks, onAccept_(_, _)) + .WillOnce(Invoke([&](ConnectionSocketPtr&, bool) -> void { + client_connection->close(ConnectionCloseType::NoFlush); + dispatcher_.exit(); + })); + + dispatcher_.run(Event::Dispatcher::RunType::Block); +} + } // namespace Network } // namespace Envoy diff --git a/test/common/router/BUILD b/test/common/router/BUILD index 47afb5c9669c4..8bc1869f8dcd5 100644 --- a/test/common/router/BUILD +++ b/test/common/router/BUILD @@ -190,11 +190,11 @@ envoy_cc_test( deps = [ "//source/common/config:metadata_lib", "//source/common/config:rds_json_lib", - "//source/common/request_info:filter_state_lib", "//source/common/router:header_formatter_lib", "//source/common/router:header_parser_lib", "//source/common/router:string_accessor_lib", - "//test/common/request_info:test_int_accessor_lib", + "//source/common/stream_info:filter_state_lib", + "//test/common/stream_info:test_int_accessor_lib", "//test/mocks/http:http_mocks", "//test/mocks/upstream:upstream_mocks", "//test/test_common:utility_lib", diff --git a/test/common/router/config_impl_test.cc b/test/common/router/config_impl_test.cc index 0c64875cb9293..7e68032790aa9 100644 --- a/test/common/router/config_impl_test.cc +++ b/test/common/router/config_impl_test.cc @@ -266,7 +266,7 @@ TEST(RouteMatcherTest, TestRoutes) { } )EOF"; - NiceMock request_info; + NiceMock stream_info; NiceMock factory_context; TestConfigImpl config(parseRouteConfigurationFromJson(json), factory_context, true); @@ -359,7 +359,7 @@ TEST(RouteMatcherTest, TestRoutes) { const RouteEntry* route = config.route(headers, 0)->routeEntry(); EXPECT_EQ("www2", route->clusterName()); EXPECT_EQ("www2", route->virtualHost().name()); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("/api/new_endpoint/foo", headers.get_(Http::Headers::get().Path)); EXPECT_EQ("/new_endpoint/foo", headers.get_(Http::Headers::get().EnvoyOriginalPath)); } @@ -370,7 +370,7 @@ TEST(RouteMatcherTest, TestRoutes) { const RouteEntry* route = config.route(headers, 0)->routeEntry(); EXPECT_EQ("www2", route->clusterName()); EXPECT_EQ("www2", route->virtualHost().name()); - route->finalizeRequestHeaders(headers, request_info, false); + route->finalizeRequestHeaders(headers, stream_info, false); EXPECT_EQ("/api/new_endpoint/foo", headers.get_(Http::Headers::get().Path)); EXPECT_FALSE(headers.has(Http::Headers::get().EnvoyOriginalPath)); } @@ -380,14 +380,14 @@ TEST(RouteMatcherTest, TestRoutes) { Http::TestHeaderMapImpl headers = genHeaders("api.lyft.com", "/api/locations?works=true", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("/rewrote?works=true", headers.get_(Http::Headers::get().Path)); } { Http::TestHeaderMapImpl headers = genHeaders("api.lyft.com", "/foo", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("/bar", headers.get_(Http::Headers::get().Path)); } @@ -395,7 +395,7 @@ TEST(RouteMatcherTest, TestRoutes) { { Http::TestHeaderMapImpl headers = genHeaders("api.lyft.com", "/host/rewrite/me", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("new_host", headers.get_(Http::Headers::get().Host)); } @@ -404,14 +404,14 @@ TEST(RouteMatcherTest, TestRoutes) { Http::TestHeaderMapImpl headers = genHeaders("api.lyft.com", "/API/locations?works=true", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("/rewrote?works=true", headers.get_(Http::Headers::get().Path)); } { Http::TestHeaderMapImpl headers = genHeaders("api.lyft.com", "/fooD", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("/cAndy", headers.get_(Http::Headers::get().Path)); } @@ -419,14 +419,14 @@ TEST(RouteMatcherTest, TestRoutes) { { Http::TestHeaderMapImpl headers = genHeaders("api.lyft.com", "/FOO", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("/FOO", headers.get_(Http::Headers::get().Path)); } { Http::TestHeaderMapImpl headers = genHeaders("api.lyft.com", "/ApPles", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("/ApPles", headers.get_(Http::Headers::get().Path)); } @@ -434,7 +434,7 @@ TEST(RouteMatcherTest, TestRoutes) { { Http::TestHeaderMapImpl headers = genHeaders("api.lyft.com", "/oLDhost/rewrite/me", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("api.lyft.com", headers.get_(Http::Headers::get().Host)); } @@ -442,7 +442,7 @@ TEST(RouteMatcherTest, TestRoutes) { { Http::TestHeaderMapImpl headers = genHeaders("api.lyft.com", "/Tart", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("/Tart", headers.get_(Http::Headers::get().Path)); } @@ -450,7 +450,7 @@ TEST(RouteMatcherTest, TestRoutes) { { Http::TestHeaderMapImpl headers = genHeaders("api.lyft.com", "/newhost/rewrite/me", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("new_host", headers.get_(Http::Headers::get().Host)); } @@ -458,7 +458,7 @@ TEST(RouteMatcherTest, TestRoutes) { { Http::TestHeaderMapImpl headers = genHeaders("bat.com", "/647", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("/rewrote", headers.get_(Http::Headers::get().Path)); } @@ -466,13 +466,13 @@ TEST(RouteMatcherTest, TestRoutes) { { Http::TestHeaderMapImpl headers = genHeaders("bat.com", "/970?foo=true", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("/rewrote?foo=true", headers.get_(Http::Headers::get().Path)); } { Http::TestHeaderMapImpl headers = genHeaders("bat.com", "/foo/bar/238?bar=true", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("/rewrote?bar=true", headers.get_(Http::Headers::get().Path)); } @@ -586,7 +586,7 @@ TEST(RouteMatcherTest, TestRoutesWithInvalidRegex) { )EOF"; NiceMock factory_context; - NiceMock request_info; + NiceMock stream_info; EXPECT_THROW_WITH_REGEX( TestConfigImpl(parseRouteConfigurationFromV2Yaml(invalid_route), factory_context, true), @@ -682,7 +682,7 @@ TEST(RouteMatcherTest, TestAddRemoveRequestHeaders) { )EOF"; NiceMock factory_context; - NiceMock request_info; + NiceMock stream_info; TestConfigImpl config(parseRouteConfigurationFromJson(json), factory_context, true); @@ -691,7 +691,7 @@ TEST(RouteMatcherTest, TestAddRemoveRequestHeaders) { { Http::TestHeaderMapImpl headers = genHeaders("www.lyft.com", "/new_endpoint/foo", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("route-override", headers.get_("x-global-header1")); EXPECT_EQ("route-override", headers.get_("x-vhost-header1")); EXPECT_EQ("route-new_endpoint", headers.get_("x-route-action-header")); @@ -701,7 +701,7 @@ TEST(RouteMatcherTest, TestAddRemoveRequestHeaders) { { Http::TestHeaderMapImpl headers = genHeaders("www.lyft.com", "/", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("vhost-override", headers.get_("x-global-header1")); EXPECT_EQ("vhost1-www2", headers.get_("x-vhost-header1")); EXPECT_EQ("route-allpath", headers.get_("x-route-action-header")); @@ -711,7 +711,7 @@ TEST(RouteMatcherTest, TestAddRemoveRequestHeaders) { { Http::TestHeaderMapImpl headers = genHeaders("www-staging.lyft.net", "/foo", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("global1", headers.get_("x-global-header1")); EXPECT_EQ("vhost1-www2_staging", headers.get_("x-vhost-header1")); EXPECT_EQ("route-allprefix", headers.get_("x-route-action-header")); @@ -721,7 +721,7 @@ TEST(RouteMatcherTest, TestAddRemoveRequestHeaders) { { Http::TestHeaderMapImpl headers = genHeaders("api.lyft.com", "/", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("global1", headers.get_("x-global-header1")); } } @@ -795,7 +795,7 @@ request_headers_to_remove: ["x-global-nope"] )EOF"; NiceMock factory_context; - NiceMock request_info; + NiceMock stream_info; envoy::api::v2::RouteConfiguration route_config = parseRouteConfigurationFromV2Yaml(yaml); @@ -807,7 +807,7 @@ request_headers_to_remove: ["x-global-nope"] { Http::TestHeaderMapImpl headers = genHeaders("www.lyft.com", "/endpoint", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); // Added headers. EXPECT_EQ("global", headers.get_("x-global-header")); EXPECT_EQ("vhost-www2", headers.get_("x-vhost-header")); @@ -823,7 +823,7 @@ request_headers_to_remove: ["x-global-nope"] { Http::TestHeaderMapImpl headers = genHeaders("www.lyft.com", "/", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); // Added headers. EXPECT_EQ("global", headers.get_("x-global-header")); EXPECT_EQ("vhost-www2", headers.get_("x-vhost-header")); @@ -839,7 +839,7 @@ request_headers_to_remove: ["x-global-nope"] { Http::TestHeaderMapImpl headers = genHeaders("www.example.com", "/", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); // Added headers. EXPECT_EQ("global", headers.get_("x-global-header")); EXPECT_FALSE(headers.has("x-vhost-header")); @@ -926,7 +926,7 @@ response_headers_to_remove: ["x-global-remove"] )EOF"; NiceMock factory_context; - NiceMock request_info; + NiceMock stream_info; TestConfigImpl config(parseRouteConfigurationFromV2Yaml(yaml), factory_context, true); @@ -936,7 +936,7 @@ response_headers_to_remove: ["x-global-remove"] Http::TestHeaderMapImpl req_headers = genHeaders("www.lyft.com", "/new_endpoint/foo", "GET"); const RouteEntry* route = config.route(req_headers, 0)->routeEntry(); Http::TestHeaderMapImpl headers; - route->finalizeResponseHeaders(headers, request_info); + route->finalizeResponseHeaders(headers, stream_info); EXPECT_EQ("route-override", headers.get_("x-global-header1")); EXPECT_EQ("route-override", headers.get_("x-vhost-header1")); EXPECT_EQ("route-new_endpoint", headers.get_("x-route-action-header")); @@ -948,7 +948,7 @@ response_headers_to_remove: ["x-global-remove"] Http::TestHeaderMapImpl req_headers = genHeaders("www.lyft.com", "/", "GET"); const RouteEntry* route = config.route(req_headers, 0)->routeEntry(); Http::TestHeaderMapImpl headers; - route->finalizeResponseHeaders(headers, request_info); + route->finalizeResponseHeaders(headers, stream_info); EXPECT_EQ("vhost-override", headers.get_("x-global-header1")); EXPECT_EQ("vhost1-www2", headers.get_("x-vhost-header1")); EXPECT_EQ("route-allpath", headers.get_("x-route-action-header")); @@ -959,7 +959,7 @@ response_headers_to_remove: ["x-global-remove"] Http::TestHeaderMapImpl req_headers = genHeaders("www-staging.lyft.net", "/foo", "GET"); const RouteEntry* route = config.route(req_headers, 0)->routeEntry(); Http::TestHeaderMapImpl headers; - route->finalizeResponseHeaders(headers, request_info); + route->finalizeResponseHeaders(headers, stream_info); EXPECT_EQ("global1", headers.get_("x-global-header1")); EXPECT_EQ("vhost1-www2_staging", headers.get_("x-vhost-header1")); EXPECT_EQ("route-allprefix", headers.get_("x-route-action-header")); @@ -970,7 +970,7 @@ response_headers_to_remove: ["x-global-remove"] Http::TestHeaderMapImpl req_headers = genHeaders("api.lyft.com", "/", "GET"); const RouteEntry* route = config.route(req_headers, 0)->routeEntry(); Http::TestHeaderMapImpl headers; - route->finalizeResponseHeaders(headers, request_info); + route->finalizeResponseHeaders(headers, stream_info); EXPECT_EQ("global1", headers.get_("x-global-header1")); } } @@ -997,7 +997,7 @@ name: foo header); NiceMock factory_context; - NiceMock request_info; + NiceMock stream_info; envoy::api::v2::RouteConfiguration route_config = parseRouteConfigurationFromV2Yaml(yaml); @@ -1006,6 +1006,30 @@ name: foo } } +// Validate that we can't remove :-prefixed request headers. +TEST(RouteMatcherTest, TestRequestHeadersToRemoveNoPseudoHeader) { + for (const std::string& header : {":path", ":authority", ":method", ":scheme", ":status", + ":protocol", ":no-chunks", ":status"}) { + const std::string yaml = fmt::format(R"EOF( +name: foo +virtual_hosts: + - name: www2 + domains: ["*"] + request_headers_to_remove: + - {} +)EOF", + header); + + NiceMock factory_context; + NiceMock stream_info; + + envoy::api::v2::RouteConfiguration route_config = parseRouteConfigurationFromV2Yaml(yaml); + + EXPECT_THROW_WITH_MESSAGE(TestConfigImpl config(route_config, factory_context, true), + EnvoyException, ":-prefixed headers may not be removed"); + } +} + TEST(RouteMatcherTest, Priority) { std::string json = R"EOF( { @@ -1864,7 +1888,7 @@ TEST(RouteMatcherTest, ClusterHeader) { )EOF"; NiceMock factory_context; - NiceMock request_info; + NiceMock stream_info; TestConfigImpl config(parseRouteConfigurationFromJson(json), factory_context, true); EXPECT_EQ( @@ -1882,7 +1906,7 @@ TEST(RouteMatcherTest, ClusterHeader) { // Make sure things forward and don't crash. EXPECT_EQ(std::chrono::milliseconds(0), route->routeEntry()->timeout()); - route->routeEntry()->finalizeRequestHeaders(headers, request_info, true); + route->routeEntry()->finalizeRequestHeaders(headers, stream_info, true); route->routeEntry()->priority(); route->routeEntry()->rateLimitPolicy(); route->routeEntry()->retryPolicy(); @@ -1970,16 +1994,104 @@ TEST(RouteMatcherTest, Runtime) { Runtime::MockSnapshot snapshot; ON_CALL(factory_context.runtime_loader_, snapshot()).WillByDefault(ReturnRef(snapshot)); + EXPECT_CALL(snapshot, getInteger("some_key", 50)) + .Times(testing::AtLeast(1)) + .WillRepeatedly(Return(42)); TestConfigImpl config(parseRouteConfigurationFromJson(json), factory_context, true); - EXPECT_CALL(snapshot, featureEnabled("some_key", 50, 10)).WillOnce(Return(true)); EXPECT_EQ("something_else", - config.route(genHeaders("www.lyft.com", "/", "GET"), 10)->routeEntry()->clusterName()); + config.route(genHeaders("www.lyft.com", "/", "GET"), 41)->routeEntry()->clusterName()); - EXPECT_CALL(snapshot, featureEnabled("some_key", 50, 20)).WillOnce(Return(false)); EXPECT_EQ("www2", - config.route(genHeaders("www.lyft.com", "/", "GET"), 20)->routeEntry()->clusterName()); + config.route(genHeaders("www.lyft.com", "/", "GET"), 43)->routeEntry()->clusterName()); +} + +TEST(RouteMatcherTest, FractionalRuntime) { + std::string yaml = R"EOF( +virtual_hosts: + - name: "www2" + domains: ["www.lyft.com"] + routes: + - match: + prefix: "/" + runtime_fraction: + default_value: + numerator: 50 + denominator: MILLION + runtime_key: "bogus_key" + route: + cluster: "something_else" + - match: + prefix: "/" + route: + cluster: "www2" + )EOF"; + + NiceMock factory_context; + Runtime::MockSnapshot snapshot; + ON_CALL(factory_context.runtime_loader_, snapshot()).WillByDefault(ReturnRef(snapshot)); + + const std::string runtime_fraction = R"EOF( + numerator: 42 + denominator: HUNDRED + )EOF"; + EXPECT_CALL(snapshot, get("bogus_key")) + .Times(testing::AtLeast(1)) + .WillRepeatedly(ReturnRef(runtime_fraction)); + + TestConfigImpl config(parseRouteConfigurationFromV2Yaml(yaml), factory_context, false); + + EXPECT_EQ( + "something_else", + config.route(genHeaders("www.lyft.com", "/foo", "GET"), 41)->routeEntry()->clusterName()); + + EXPECT_EQ( + "www2", + config.route(genHeaders("www.lyft.com", "/foo", "GET"), 43)->routeEntry()->clusterName()); +} + +TEST(RouteMatcherTest, FractionalRuntimeDefault) { + std::string yaml = R"EOF( +virtual_hosts: + - name: "www2" + domains: ["www.lyft.com"] + routes: + - match: + prefix: "/" + runtime_fraction: + default_value: + numerator: 50 + denominator: MILLION + runtime_key: "bogus_key" + route: + cluster: "something_else" + - match: + prefix: "/" + route: + cluster: "www2" + )EOF"; + + NiceMock factory_context; + Runtime::MockSnapshot snapshot; + ON_CALL(factory_context.runtime_loader_, snapshot()).WillByDefault(ReturnRef(snapshot)); + + const std::string runtime_fraction = R"EOF( + this string is nonsense and should fail parsing + )EOF"; + EXPECT_CALL(snapshot, get("bogus_key")) + .Times(testing::AtLeast(1)) + .WillRepeatedly(ReturnRef(runtime_fraction)); + + TestConfigImpl config(parseRouteConfigurationFromV2Yaml(yaml), factory_context, false); + + EXPECT_EQ( + "something_else", + config.route(genHeaders("www.lyft.com", "/foo", "GET"), 49)->routeEntry()->clusterName()); + + EXPECT_EQ( + "www2", + config.route(genHeaders("www.lyft.com", "/foo", "GET"), 51)->routeEntry()->clusterName()); } TEST(RouteMatcherTest, ShadowClusterNotFound) { @@ -2087,6 +2199,26 @@ TEST(RouteMatcherTest, ClusterNotFoundNotCheckingViaConfig) { TestConfigImpl(parseRouteConfigurationFromJson(json), factory_context, true); } +TEST(RouteMatcherTest, AttemptCountHeader) { + std::string yaml = R"EOF( +virtual_hosts: + - name: "www2" + domains: ["www.lyft.com"] + include_request_attempt_count: true + routes: + - match: { prefix: "/"} + route: + cluster: "whatever" + )EOF"; + + NiceMock factory_context; + TestConfigImpl config(parseRouteConfigurationFromV2Yaml(yaml), factory_context, true); + + EXPECT_TRUE(config.route(genHeaders("www.lyft.com", "/foo", "GET"), 0) + ->routeEntry() + ->includeAttemptCount()); +} + TEST(RouteMatchTest, ClusterNotFoundResponseCode) { std::string yaml = R"EOF( virtual_hosts: @@ -2893,8 +3025,8 @@ TEST(RouteMatcherTest, WeightedClusters) { EXPECT_EQ("hello", route->decorator()->getOperation()); Http::TestHeaderMapImpl response_headers; - RequestInfo::MockRequestInfo request_info; - route_entry->finalizeResponseHeaders(response_headers, request_info); + StreamInfo::MockStreamInfo stream_info; + route_entry->finalizeResponseHeaders(response_headers, stream_info); EXPECT_EQ(response_headers, Http::TestHeaderMapImpl{}); } @@ -3202,7 +3334,7 @@ TEST(RouteMatcherTest, TestWeightedClusterHeaderManipulation) { NiceMock factory_context; TestConfigImpl config(parseRouteConfigurationFromV2Yaml(yaml), factory_context, true); - NiceMock request_info; + NiceMock stream_info; { Http::TestHeaderMapImpl headers = genHeaders("www.lyft.com", "/foo", "GET"); @@ -3210,10 +3342,10 @@ TEST(RouteMatcherTest, TestWeightedClusterHeaderManipulation) { const RouteEntry* route = config.route(headers, 0)->routeEntry(); EXPECT_EQ("cluster1", route->clusterName()); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("cluster1", headers.get_("x-req-cluster")); - route->finalizeResponseHeaders(resp_headers, request_info); + route->finalizeResponseHeaders(resp_headers, stream_info); EXPECT_EQ("cluster1", resp_headers.get_("x-resp-cluster")); EXPECT_FALSE(resp_headers.has("x-remove-cluster1")); } @@ -3224,10 +3356,10 @@ TEST(RouteMatcherTest, TestWeightedClusterHeaderManipulation) { const RouteEntry* route = config.route(headers, 55)->routeEntry(); EXPECT_EQ("cluster2", route->clusterName()); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("cluster2", headers.get_("x-req-cluster")); - route->finalizeResponseHeaders(resp_headers, request_info); + route->finalizeResponseHeaders(resp_headers, stream_info); EXPECT_EQ("cluster2", resp_headers.get_("x-resp-cluster")); EXPECT_FALSE(resp_headers.has("x-remove-cluster2")); } @@ -3790,11 +3922,11 @@ TEST(CustomRequestHeadersTest, AddNewHeader) { } )EOF"; NiceMock factory_context; - NiceMock request_info; + NiceMock stream_info; TestConfigImpl config(parseRouteConfigurationFromJson(json), factory_context, true); Http::TestHeaderMapImpl headers = genHeaders("www.lyft.com", "/new_endpoint/foo", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); - route->finalizeRequestHeaders(headers, request_info, true); + route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("127.0.0.1", headers.get_("x-client-ip")); } @@ -3841,7 +3973,7 @@ TEST(CustomRequestHeadersTest, CustomHeaderWrongFormat) { } )EOF"; NiceMock factory_context; - NiceMock request_info; + NiceMock stream_info; EXPECT_THROW_WITH_MESSAGE( TestConfigImpl config(parseRouteConfigurationFromJson(json), factory_context, true), EnvoyException, @@ -4581,8 +4713,8 @@ name: RegexNoMatch headers.addCopy(":path", "/not-the-original-regex"); // no re-write was specified; so this should not throw - NiceMock request_info; - EXPECT_NO_THROW(route_entry->finalizeRequestHeaders(headers, request_info, false)); + NiceMock stream_info; + EXPECT_NO_THROW(route_entry->finalizeRequestHeaders(headers, stream_info, false)); } } @@ -4646,6 +4778,29 @@ name: ExplicitIdleTimeout EXPECT_EQ(7 * 1000, route_entry->idleTimeout().value().count()); } +TEST(RouteConfigurationV2, RetriableStatusCodes) { + const std::string ExplicitIdleTimeot = R"EOF( +name: RetriableStatusCodes +virtual_hosts: + - name: regex + domains: [idle.lyft.com] + routes: + - match: { regex: "/regex"} + route: + cluster: some-cluster + retry_policy: + retriable_status_codes: [100, 200] + )EOF"; + + NiceMock factory_context; + TestConfigImpl config(parseRouteConfigurationFromV2Yaml(ExplicitIdleTimeot), factory_context, + true); + Http::TestHeaderMapImpl headers = genRedirectHeaders("idle.lyft.com", "/regex", true, false); + const auto& retry_policy = config.route(headers, 0)->routeEntry()->retryPolicy(); + const std::vector expected_codes{100, 200}; + EXPECT_EQ(expected_codes, retry_policy.retriableStatusCodes()); +} + class PerFilterConfigsTest : public testing::Test { public: PerFilterConfigsTest() diff --git a/test/common/router/header_formatter_test.cc b/test/common/router/header_formatter_test.cc index ece062a3fd0e9..46bd6074e9c2e 100644 --- a/test/common/router/header_formatter_test.cc +++ b/test/common/router/header_formatter_test.cc @@ -5,12 +5,12 @@ #include "common/config/metadata.h" #include "common/config/rds_json.h" -#include "common/request_info/filter_state_impl.h" #include "common/router/header_formatter.h" #include "common/router/header_parser.h" #include "common/router/string_accessor_impl.h" +#include "common/stream_info/filter_state_impl.h" -#include "test/common/request_info/test_int_accessor.h" +#include "test/common/stream_info/test_int_accessor.h" #include "test/mocks/http/mocks.h" #include "test/mocks/upstream/mocks.h" #include "test/test_common/utility.h" @@ -39,50 +39,50 @@ static envoy::api::v2::route::Route parseRouteFromV2Yaml(const std::string& yaml return route; } -class RequestInfoHeaderFormatterTest : public testing::Test { +class StreamInfoHeaderFormatterTest : public testing::Test { public: - void testFormatting(const Envoy::RequestInfo::MockRequestInfo& request_info, + void testFormatting(const Envoy::StreamInfo::MockStreamInfo& stream_info, const std::string& variable, const std::string& expected_output) { { - auto f = RequestInfoHeaderFormatter(variable, false); - const std::string formatted_string = f.format(request_info); + auto f = StreamInfoHeaderFormatter(variable, false); + const std::string formatted_string = f.format(stream_info); EXPECT_EQ(expected_output, formatted_string); } } void testFormatting(const std::string& variable, const std::string& expected_output) { - NiceMock request_info; - testFormatting(request_info, variable, expected_output); + NiceMock stream_info; + testFormatting(stream_info, variable, expected_output); } void testInvalidFormat(const std::string& variable) { - EXPECT_THROW_WITH_MESSAGE(RequestInfoHeaderFormatter(variable, false), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(StreamInfoHeaderFormatter(variable, false), EnvoyException, fmt::format("field '{}' not supported as custom header", variable)); } }; -TEST_F(RequestInfoHeaderFormatterTest, TestFormatWithDownstreamRemoteAddressVariable) { +TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithDownstreamRemoteAddressVariable) { testFormatting("DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT", "127.0.0.1"); } -TEST_F(RequestInfoHeaderFormatterTest, TestFormatWithDownstreamLocalAddressVariable) { +TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithDownstreamLocalAddressVariable) { testFormatting("DOWNSTREAM_LOCAL_ADDRESS", "127.0.0.2:0"); } -TEST_F(RequestInfoHeaderFormatterTest, TestFormatWithDownstreamLocalAddressWithoutPortVariable) { +TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithDownstreamLocalAddressWithoutPortVariable) { testFormatting("DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT", "127.0.0.2"); } -TEST_F(RequestInfoHeaderFormatterTest, TestFormatWithProtocolVariable) { - NiceMock request_info; +TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithProtocolVariable) { + NiceMock stream_info; absl::optional protocol = Envoy::Http::Protocol::Http11; - ON_CALL(request_info, protocol()).WillByDefault(ReturnPointee(&protocol)); + ON_CALL(stream_info, protocol()).WillByDefault(ReturnPointee(&protocol)); - testFormatting(request_info, "PROTOCOL", "HTTP/1.1"); + testFormatting(stream_info, "PROTOCOL", "HTTP/1.1"); } -TEST_F(RequestInfoHeaderFormatterTest, TestFormatWithUpstreamMetadataVariable) { - NiceMock request_info; +TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithUpstreamMetadataVariable) { + NiceMock stream_info; std::shared_ptr> host( new NiceMock()); @@ -117,55 +117,54 @@ TEST_F(RequestInfoHeaderFormatterTest, TestFormatWithUpstreamMetadataVariable) { EXPECT_EQ(nested_struct.fields().at("list_key").kind_case(), ProtobufWkt::Value::kListValue); EXPECT_EQ(nested_struct.fields().at("struct_key").kind_case(), ProtobufWkt::Value::kStructValue); - ON_CALL(request_info, upstreamHost()).WillByDefault(Return(host)); + ON_CALL(stream_info, upstreamHost()).WillByDefault(Return(host)); ON_CALL(*host, metadata()).WillByDefault(Return(metadata)); // Top-level value. - testFormatting(request_info, "UPSTREAM_METADATA([\"namespace\", \"key\"])", "value"); + testFormatting(stream_info, "UPSTREAM_METADATA([\"namespace\", \"key\"])", "value"); // Nested string value. - testFormatting(request_info, "UPSTREAM_METADATA([\"namespace\", \"nested\", \"str_key\"])", + testFormatting(stream_info, "UPSTREAM_METADATA([\"namespace\", \"nested\", \"str_key\"])", "str_value"); // Boolean values. - testFormatting(request_info, "UPSTREAM_METADATA([\"namespace\", \"nested\", \"bool_key1\"])", + testFormatting(stream_info, "UPSTREAM_METADATA([\"namespace\", \"nested\", \"bool_key1\"])", "true"); - testFormatting(request_info, "UPSTREAM_METADATA([\"namespace\", \"nested\", \"bool_key2\"])", + testFormatting(stream_info, "UPSTREAM_METADATA([\"namespace\", \"nested\", \"bool_key2\"])", "false"); // Number values. - testFormatting(request_info, "UPSTREAM_METADATA([\"namespace\", \"nested\", \"num_key1\"])", "1"); - testFormatting(request_info, "UPSTREAM_METADATA([\"namespace\", \"nested\", \"num_key2\"])", + testFormatting(stream_info, "UPSTREAM_METADATA([\"namespace\", \"nested\", \"num_key1\"])", "1"); + testFormatting(stream_info, "UPSTREAM_METADATA([\"namespace\", \"nested\", \"num_key2\"])", "3.14"); // Deeply nested value. - testFormatting(request_info, + testFormatting(stream_info, "UPSTREAM_METADATA([\"namespace\", \"nested\", \"struct_key\", \"deep_key\"])", "deep_value"); // Initial metadata lookup fails. - testFormatting(request_info, "UPSTREAM_METADATA([\"wrong_namespace\", \"key\"])", ""); - testFormatting(request_info, "UPSTREAM_METADATA([\"namespace\", \"not_found\"])", ""); - testFormatting(request_info, "UPSTREAM_METADATA([\"namespace\", \"not_found\", \"key\"])", ""); + testFormatting(stream_info, "UPSTREAM_METADATA([\"wrong_namespace\", \"key\"])", ""); + testFormatting(stream_info, "UPSTREAM_METADATA([\"namespace\", \"not_found\"])", ""); + testFormatting(stream_info, "UPSTREAM_METADATA([\"namespace\", \"not_found\", \"key\"])", ""); // Nested metadata lookup fails. - testFormatting(request_info, "UPSTREAM_METADATA([\"namespace\", \"nested\", \"not_found\"])", ""); + testFormatting(stream_info, "UPSTREAM_METADATA([\"namespace\", \"nested\", \"not_found\"])", ""); // Nested metadata lookup returns non-struct intermediate value. - testFormatting(request_info, "UPSTREAM_METADATA([\"namespace\", \"key\", \"invalid\"])", ""); + testFormatting(stream_info, "UPSTREAM_METADATA([\"namespace\", \"key\", \"invalid\"])", ""); // Struct values are not rendered. - testFormatting(request_info, "UPSTREAM_METADATA([\"namespace\", \"nested\", \"struct_key\"])", - ""); + testFormatting(stream_info, "UPSTREAM_METADATA([\"namespace\", \"nested\", \"struct_key\"])", ""); // List values are not rendered. - testFormatting(request_info, "UPSTREAM_METADATA([\"namespace\", \"nested\", \"list_key\"])", ""); + testFormatting(stream_info, "UPSTREAM_METADATA([\"namespace\", \"nested\", \"list_key\"])", ""); } // Breaks tsan/asan builds by trying to allocate a lot of memory. // Works on debug builds and needs to be fixed. See // https://github.com/envoyproxy/envoy/issues/4268 -TEST_F(RequestInfoHeaderFormatterTest, DISABLED_UserDefinedHeadersConsideredHarmful) { +TEST_F(StreamInfoHeaderFormatterTest, DISABLED_UserDefinedHeadersConsideredHarmful) { // This must be an inline header to get the append-in-place semantics. const char* header_name = "connection"; Protobuf::RepeatedPtrField to_add; @@ -182,71 +181,70 @@ TEST_F(RequestInfoHeaderFormatterTest, DISABLED_UserDefinedHeadersConsideredHarm HeaderParserPtr req_header_parser = HeaderParser::configure(to_add); Http::TestHeaderMapImpl header_map{{":method", "POST"}}; - NiceMock request_info; - EXPECT_DEATH_LOG_TO_STDERR(req_header_parser->evaluateHeaders(header_map, request_info), + NiceMock stream_info; + EXPECT_DEATH_LOG_TO_STDERR(req_header_parser->evaluateHeaders(header_map, stream_info), "Trying to allocate overly large headers."); } -TEST_F(RequestInfoHeaderFormatterTest, TestFormatWithUpstreamMetadataVariableMissingHost) { - NiceMock request_info; +TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithUpstreamMetadataVariableMissingHost) { + NiceMock stream_info; std::shared_ptr> host; - ON_CALL(request_info, upstreamHost()).WillByDefault(Return(host)); + ON_CALL(stream_info, upstreamHost()).WillByDefault(Return(host)); - testFormatting(request_info, "UPSTREAM_METADATA([\"namespace\", \"key\"])", ""); + testFormatting(stream_info, "UPSTREAM_METADATA([\"namespace\", \"key\"])", ""); } -TEST_F(RequestInfoHeaderFormatterTest, TestFormatWithPerRequestStateVariable) { - Envoy::RequestInfo::FilterStateImpl per_request_state; +TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithPerRequestStateVariable) { + Envoy::StreamInfo::FilterStateImpl per_request_state; per_request_state.setData("testing", std::make_unique("test_value")); EXPECT_EQ("test_value", per_request_state.getData("testing").asString()); - NiceMock request_info; - ON_CALL(request_info, perRequestState()).WillByDefault(ReturnRef(per_request_state)); - ON_CALL(Const(request_info), perRequestState()).WillByDefault(ReturnRef(per_request_state)); + NiceMock stream_info; + ON_CALL(stream_info, perRequestState()).WillByDefault(ReturnRef(per_request_state)); + ON_CALL(Const(stream_info), perRequestState()).WillByDefault(ReturnRef(per_request_state)); - testFormatting(request_info, "PER_REQUEST_STATE(testing)", "test_value"); - testFormatting(request_info, "PER_REQUEST_STATE(testing2)", ""); + testFormatting(stream_info, "PER_REQUEST_STATE(testing)", "test_value"); + testFormatting(stream_info, "PER_REQUEST_STATE(testing2)", ""); EXPECT_EQ("test_value", per_request_state.getData("testing").asString()); } -TEST_F(RequestInfoHeaderFormatterTest, TestFormatWithNonStringPerRequestStateVariable) { - Envoy::RequestInfo::FilterStateImpl per_request_state; - per_request_state.setData("testing", std::make_unique(1)); - EXPECT_EQ(1, per_request_state.getData("testing").access()); +TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithNonStringPerRequestStateVariable) { + Envoy::StreamInfo::FilterStateImpl per_request_state; + per_request_state.setData("testing", std::make_unique(1)); + EXPECT_EQ(1, per_request_state.getData("testing").access()); - NiceMock request_info; - ON_CALL(request_info, perRequestState()).WillByDefault(ReturnRef(per_request_state)); - ON_CALL(Const(request_info), perRequestState()).WillByDefault(ReturnRef(per_request_state)); + NiceMock stream_info; + ON_CALL(stream_info, perRequestState()).WillByDefault(ReturnRef(per_request_state)); + ON_CALL(Const(stream_info), perRequestState()).WillByDefault(ReturnRef(per_request_state)); - testFormatting(request_info, "PER_REQUEST_STATE(testing)", ""); + testFormatting(stream_info, "PER_REQUEST_STATE(testing)", ""); } -TEST_F(RequestInfoHeaderFormatterTest, WrongFormatOnPerRequestStateVariable) { +TEST_F(StreamInfoHeaderFormatterTest, WrongFormatOnPerRequestStateVariable) { // No parameters - EXPECT_THROW_WITH_MESSAGE(RequestInfoHeaderFormatter("PER_REQUEST_STATE()", false), - EnvoyException, + EXPECT_THROW_WITH_MESSAGE(StreamInfoHeaderFormatter("PER_REQUEST_STATE()", false), EnvoyException, "Invalid header configuration. Expected format " "PER_REQUEST_STATE(), actual format " "PER_REQUEST_STATE()"); // Missing single parens - EXPECT_THROW_WITH_MESSAGE(RequestInfoHeaderFormatter("PER_REQUEST_STATE(testing", false), + EXPECT_THROW_WITH_MESSAGE(StreamInfoHeaderFormatter("PER_REQUEST_STATE(testing", false), EnvoyException, "Invalid header configuration. Expected format " "PER_REQUEST_STATE(), actual format " "PER_REQUEST_STATE(testing"); - EXPECT_THROW_WITH_MESSAGE(RequestInfoHeaderFormatter("PER_REQUEST_STATE testing)", false), + EXPECT_THROW_WITH_MESSAGE(StreamInfoHeaderFormatter("PER_REQUEST_STATE testing)", false), EnvoyException, "Invalid header configuration. Expected format " "PER_REQUEST_STATE(), actual format " "PER_REQUEST_STATE testing)"); } -TEST_F(RequestInfoHeaderFormatterTest, UnknownVariable) { testInvalidFormat("INVALID_VARIABLE"); } +TEST_F(StreamInfoHeaderFormatterTest, UnknownVariable) { testInvalidFormat("INVALID_VARIABLE"); } -TEST_F(RequestInfoHeaderFormatterTest, WrongFormatOnUpstreamMetadataVariable) { +TEST_F(StreamInfoHeaderFormatterTest, WrongFormatOnUpstreamMetadataVariable) { // Invalid JSON. - EXPECT_THROW_WITH_MESSAGE(RequestInfoHeaderFormatter("UPSTREAM_METADATA(abcd)", false), + EXPECT_THROW_WITH_MESSAGE(StreamInfoHeaderFormatter("UPSTREAM_METADATA(abcd)", false), EnvoyException, "Invalid header configuration. Expected format " "UPSTREAM_METADATA([\"namespace\", \"k\", ...]), actual format " @@ -254,38 +252,37 @@ TEST_F(RequestInfoHeaderFormatterTest, WrongFormatOnUpstreamMetadataVariable) { "Error(offset 0, line 1): Invalid value.\n"); // No parameters. - EXPECT_THROW_WITH_MESSAGE(RequestInfoHeaderFormatter("UPSTREAM_METADATA", false), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(StreamInfoHeaderFormatter("UPSTREAM_METADATA", false), EnvoyException, "Invalid header configuration. Expected format " "UPSTREAM_METADATA([\"namespace\", \"k\", ...]), actual format " "UPSTREAM_METADATA"); - EXPECT_THROW_WITH_MESSAGE(RequestInfoHeaderFormatter("UPSTREAM_METADATA()", false), - EnvoyException, + EXPECT_THROW_WITH_MESSAGE(StreamInfoHeaderFormatter("UPSTREAM_METADATA()", false), EnvoyException, "Invalid header configuration. Expected format " "UPSTREAM_METADATA([\"namespace\", \"k\", ...]), actual format " "UPSTREAM_METADATA(), because JSON supplied is not valid. " "Error(offset 0, line 1): The document is empty.\n"); // One parameter. - EXPECT_THROW_WITH_MESSAGE(RequestInfoHeaderFormatter("UPSTREAM_METADATA([\"ns\"])", false), + EXPECT_THROW_WITH_MESSAGE(StreamInfoHeaderFormatter("UPSTREAM_METADATA([\"ns\"])", false), EnvoyException, "Invalid header configuration. Expected format " "UPSTREAM_METADATA([\"namespace\", \"k\", ...]), actual format " "UPSTREAM_METADATA([\"ns\"])"); // Missing close paren. - EXPECT_THROW_WITH_MESSAGE(RequestInfoHeaderFormatter("UPSTREAM_METADATA(", false), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(StreamInfoHeaderFormatter("UPSTREAM_METADATA(", false), EnvoyException, "Invalid header configuration. Expected format " "UPSTREAM_METADATA([\"namespace\", \"k\", ...]), actual format " "UPSTREAM_METADATA("); - EXPECT_THROW_WITH_MESSAGE(RequestInfoHeaderFormatter("UPSTREAM_METADATA([a,b,c,d]", false), + EXPECT_THROW_WITH_MESSAGE(StreamInfoHeaderFormatter("UPSTREAM_METADATA([a,b,c,d]", false), EnvoyException, "Invalid header configuration. Expected format " "UPSTREAM_METADATA([\"namespace\", \"k\", ...]), actual format " "UPSTREAM_METADATA([a,b,c,d]"); - EXPECT_THROW_WITH_MESSAGE(RequestInfoHeaderFormatter("UPSTREAM_METADATA([\"a\",\"b\"]", false), + EXPECT_THROW_WITH_MESSAGE(StreamInfoHeaderFormatter("UPSTREAM_METADATA([\"a\",\"b\"]", false), EnvoyException, "Invalid header configuration. Expected format " "UPSTREAM_METADATA([\"namespace\", \"k\", ...]), actual format " @@ -293,7 +290,7 @@ TEST_F(RequestInfoHeaderFormatterTest, WrongFormatOnUpstreamMetadataVariable) { // Non-string elements. EXPECT_THROW_WITH_MESSAGE( - RequestInfoHeaderFormatter("UPSTREAM_METADATA([\"a\", 1])", false), EnvoyException, + StreamInfoHeaderFormatter("UPSTREAM_METADATA([\"a\", 1])", false), EnvoyException, "Invalid header configuration. Expected format " "UPSTREAM_METADATA([\"namespace\", \"k\", ...]), actual format " "UPSTREAM_METADATA([\"a\", 1]), because JSON field from line 1 accessed with type 'String' " @@ -301,8 +298,7 @@ TEST_F(RequestInfoHeaderFormatterTest, WrongFormatOnUpstreamMetadataVariable) { // Invalid string elements. EXPECT_THROW_WITH_MESSAGE( - RequestInfoHeaderFormatter("UPSTREAM_METADATA([\"a\", \"\\unothex\"])", false), - EnvoyException, + StreamInfoHeaderFormatter("UPSTREAM_METADATA([\"a\", \"\\unothex\"])", false), EnvoyException, "Invalid header configuration. Expected format " "UPSTREAM_METADATA([\"namespace\", \"k\", ...]), actual format " "UPSTREAM_METADATA([\"a\", \"\\unothex\"]), because JSON supplied is not valid. " @@ -310,7 +306,7 @@ TEST_F(RequestInfoHeaderFormatterTest, WrongFormatOnUpstreamMetadataVariable) { // Non-array parameters. EXPECT_THROW_WITH_MESSAGE( - RequestInfoHeaderFormatter("UPSTREAM_METADATA({\"a\":1})", false), EnvoyException, + StreamInfoHeaderFormatter("UPSTREAM_METADATA({\"a\":1})", false), EnvoyException, "Invalid header configuration. Expected format " "UPSTREAM_METADATA([\"namespace\", \"k\", ...]), actual format " "UPSTREAM_METADATA({\"a\":1}), because JSON field from line 1 accessed with type 'Array' " @@ -404,13 +400,13 @@ TEST(HeaderParserTest, TestParseInternal) { "...]), actual format UPSTREAM_METADATA([\"ns\"])"}}, }; - NiceMock request_info; + NiceMock stream_info; absl::optional protocol = Envoy::Http::Protocol::Http11; - ON_CALL(request_info, protocol()).WillByDefault(ReturnPointee(&protocol)); + ON_CALL(stream_info, protocol()).WillByDefault(ReturnPointee(&protocol)); std::shared_ptr> host( new NiceMock()); - ON_CALL(request_info, upstreamHost()).WillByDefault(Return(host)); + ON_CALL(stream_info, upstreamHost()).WillByDefault(Return(host)); // Upstream metadata with percent signs in the key. auto metadata = std::make_shared( @@ -424,12 +420,12 @@ TEST(HeaderParserTest, TestParseInternal) { // "2018-04-03T23:06:09.123Z". const SystemTime start_time(std::chrono::milliseconds(1522796769123)); - ON_CALL(request_info, startTime()).WillByDefault(Return(start_time)); + ON_CALL(stream_info, startTime()).WillByDefault(Return(start_time)); - Envoy::RequestInfo::FilterStateImpl per_request_state; + Envoy::StreamInfo::FilterStateImpl per_request_state; per_request_state.setData("testing", std::make_unique("test_value")); - ON_CALL(request_info, perRequestState()).WillByDefault(ReturnRef(per_request_state)); - ON_CALL(Const(request_info), perRequestState()).WillByDefault(ReturnRef(per_request_state)); + ON_CALL(stream_info, perRequestState()).WillByDefault(ReturnRef(per_request_state)); + ON_CALL(Const(stream_info), perRequestState()).WillByDefault(ReturnRef(per_request_state)); for (const auto& test_case : test_cases) { Protobuf::RepeatedPtrField to_add; @@ -447,7 +443,7 @@ TEST(HeaderParserTest, TestParseInternal) { HeaderParserPtr req_header_parser = HeaderParser::configure(to_add); Http::TestHeaderMapImpl header_map{{":method", "POST"}}; - req_header_parser->evaluateHeaders(header_map, request_info); + req_header_parser->evaluateHeaders(header_map, stream_info); std::string descriptor = fmt::format("for test case input: {}", test_case.input_); @@ -474,8 +470,8 @@ TEST(HeaderParserTest, EvaluateHeaders) { HeaderParserPtr req_header_parser = HeaderParser::configure(parseRouteFromJson(json).route().request_headers_to_add()); Http::TestHeaderMapImpl header_map{{":method", "POST"}}; - NiceMock request_info; - req_header_parser->evaluateHeaders(header_map, request_info); + NiceMock stream_info; + req_header_parser->evaluateHeaders(header_map, stream_info); EXPECT_TRUE(header_map.has("x-client-ip")); } @@ -498,11 +494,11 @@ TEST(HeaderParserTest, EvaluateEmptyHeaders) { Http::TestHeaderMapImpl header_map{{":method", "POST"}}; std::shared_ptr> host( new NiceMock()); - NiceMock request_info; + NiceMock stream_info; auto metadata = std::make_shared(); - ON_CALL(request_info, upstreamHost()).WillByDefault(Return(host)); + ON_CALL(stream_info, upstreamHost()).WillByDefault(Return(host)); ON_CALL(*host, metadata()).WillByDefault(Return(metadata)); - req_header_parser->evaluateHeaders(header_map, request_info); + req_header_parser->evaluateHeaders(header_map, stream_info); EXPECT_FALSE(header_map.has("x-key")); } @@ -523,8 +519,8 @@ TEST(HeaderParserTest, EvaluateStaticHeaders) { HeaderParserPtr req_header_parser = HeaderParser::configure(parseRouteFromJson(json).route().request_headers_to_add()); Http::TestHeaderMapImpl header_map{{":method", "POST"}}; - NiceMock request_info; - req_header_parser->evaluateHeaders(header_map, request_info); + NiceMock stream_info; + req_header_parser->evaluateHeaders(header_map, stream_info); EXPECT_TRUE(header_map.has("static-header")); EXPECT_EQ("static-value", header_map.get_("static-header")); } @@ -569,13 +565,13 @@ request_headers_to_remove: ["x-nope"] HeaderParserPtr req_header_parser = HeaderParser::configure(route.request_headers_to_add(), route.request_headers_to_remove()); Http::TestHeaderMapImpl header_map{{":method", "POST"}, {"x-safe", "safe"}, {"x-nope", "nope"}}; - NiceMock request_info; + NiceMock stream_info; absl::optional protocol = Envoy::Http::Protocol::Http11; - ON_CALL(request_info, protocol()).WillByDefault(ReturnPointee(&protocol)); + ON_CALL(stream_info, protocol()).WillByDefault(ReturnPointee(&protocol)); std::shared_ptr> host( new NiceMock()); - ON_CALL(request_info, upstreamHost()).WillByDefault(Return(host)); + ON_CALL(stream_info, upstreamHost()).WillByDefault(Return(host)); // Metadata with percent signs in the key. auto metadata = std::make_shared( @@ -587,12 +583,12 @@ request_headers_to_remove: ["x-nope"] )EOF")); ON_CALL(*host, metadata()).WillByDefault(Return(metadata)); - Envoy::RequestInfo::FilterStateImpl per_request_state; + Envoy::StreamInfo::FilterStateImpl per_request_state; per_request_state.setData("testing", std::make_unique("test_value")); - ON_CALL(request_info, perRequestState()).WillByDefault(ReturnRef(per_request_state)); - ON_CALL(Const(request_info), perRequestState()).WillByDefault(ReturnRef(per_request_state)); + ON_CALL(stream_info, perRequestState()).WillByDefault(ReturnRef(per_request_state)); + ON_CALL(Const(stream_info), perRequestState()).WillByDefault(ReturnRef(per_request_state)); - req_header_parser->evaluateHeaders(header_map, request_info); + req_header_parser->evaluateHeaders(header_map, stream_info); EXPECT_TRUE(header_map.has("x-prefix")); EXPECT_EQ("prefix-127.0.0.1", header_map.get_("x-prefix")); @@ -667,11 +663,11 @@ TEST(HeaderParserTest, EvaluateHeadersWithAppendFalse) { Http::TestHeaderMapImpl header_map{ {":method", "POST"}, {"static-header", "old-value"}, {"x-client-ip", "0.0.0.0"}}; - NiceMock request_info; + NiceMock stream_info; const SystemTime start_time(std::chrono::microseconds(1522796769123456)); - EXPECT_CALL(request_info, startTime()).Times(3).WillRepeatedly(Return(start_time)); + EXPECT_CALL(stream_info, startTime()).Times(3).WillRepeatedly(Return(start_time)); - req_header_parser->evaluateHeaders(header_map, request_info); + req_header_parser->evaluateHeaders(header_map, stream_info); EXPECT_TRUE(header_map.has("static-header")); EXPECT_EQ("static-value", header_map.get_("static-header")); EXPECT_TRUE(header_map.has("x-client-ip")); @@ -742,13 +738,13 @@ match: { prefix: "/new_endpoint" } HeaderParserPtr resp_header_parser = HeaderParser::configure(route.response_headers_to_add(), route.response_headers_to_remove()); Http::TestHeaderMapImpl header_map{{":method", "POST"}, {"x-safe", "safe"}, {"x-nope", "nope"}}; - NiceMock request_info; + NiceMock stream_info; // Initialize start_time as 2018-04-03T23:06:09.123Z in microseconds. const SystemTime start_time(std::chrono::microseconds(1522796769123456)); - EXPECT_CALL(request_info, startTime()).Times(7).WillRepeatedly(Return(start_time)); + EXPECT_CALL(stream_info, startTime()).Times(7).WillRepeatedly(Return(start_time)); - resp_header_parser->evaluateHeaders(header_map, request_info); + resp_header_parser->evaluateHeaders(header_map, stream_info); EXPECT_TRUE(header_map.has("x-client-ip")); EXPECT_TRUE(header_map.has("x-request-start-multiple")); EXPECT_TRUE(header_map.has("x-safe")); diff --git a/test/common/router/header_parser_corpus/clusterfuzz-testcase-header_parser_fuzz_test-6195059702628352 b/test/common/router/header_parser_corpus/clusterfuzz-testcase-header_parser_fuzz_test-6195059702628352 index b1d85a401670a..5962f652bf7d3 100644 --- a/test/common/router/header_parser_corpus/clusterfuzz-testcase-header_parser_fuzz_test-6195059702628352 +++ b/test/common/router/header_parser_corpus/clusterfuzz-testcase-header_parser_fuzz_test-6195059702628352 @@ -3,6 +3,6 @@ headers_to_add { value: "%START_TIMEY()%T %START_TIME(f, %�{{{{{_�����������85request_i: 1�227 f55555_n555555555555%85nfo 5#555.55f, %1f, %85/5_inf %8,,,,,,,,,,,,,,,,,,,,,,,,,55555 start_timefo 5#5555#555.55f, %1f, %85/55ime: 15227 f %1f, %8555555555 %85/5555Fme: 15227 f-5555_inf 965L5559f)%" } } -request_info { +stream_info { start_time: 1522796769123 } diff --git a/test/common/router/header_parser_corpus/clusterfuzz-testcase-minimized-header_parser_fuzz_test-5630125928873984 b/test/common/router/header_parser_corpus/clusterfuzz-testcase-minimized-header_parser_fuzz_test-5630125928873984 index 51cef79477d3f..e811d288d990f 100644 --- a/test/common/router/header_parser_corpus/clusterfuzz-testcase-minimized-header_parser_fuzz_test-5630125928873984 +++ b/test/common/router/header_parser_corpus/clusterfuzz-testcase-minimized-header_parser_fuzz_test-5630125928873984 @@ -1 +1 @@ -headers_to_add { header { key: " " value: "%START_TIME(�)%" } } request_info { start_time: 72059116831228591 } +headers_to_add { header { key: " " value: "%START_TIME(�)%" } } stream_info { start_time: 72059116831228591 } diff --git a/test/common/router/header_parser_corpus/compound_headers b/test/common/router/header_parser_corpus/compound_headers index 5fd73dfbd45ac..1374175f9f072 100644 --- a/test/common/router/header_parser_corpus/compound_headers +++ b/test/common/router/header_parser_corpus/compound_headers @@ -52,7 +52,7 @@ headers_to_add { value: "%UPSTREAM_METADATA([\"namespace\", \"%key%\"])%" } } -request_info { +stream_info { upstream_metadata { filter_metadata { key: "namespace" diff --git a/test/common/router/header_parser_corpus/foo b/test/common/router/header_parser_corpus/foo index 96289ff509a9b..8a7246f8a8294 100644 --- a/test/common/router/header_parser_corpus/foo +++ b/test/common/router/header_parser_corpus/foo @@ -5,7 +5,7 @@ headers_to_add { } } headers_to_remove: "7" -request_info { +stream_info { upstream_metadata { filter_metadata { key: "" diff --git a/test/common/router/header_parser_corpus/start_time b/test/common/router/header_parser_corpus/start_time index 1e6d53dd7994b..d02acb22e3535 100644 --- a/test/common/router/header_parser_corpus/start_time +++ b/test/common/router/header_parser_corpus/start_time @@ -25,6 +25,6 @@ headers_to_add { value: "%START_TIME%" } } -request_info { +stream_info { start_time: 1522796769123 } diff --git a/test/common/router/header_parser_corpus/upstream_metadata_0 b/test/common/router/header_parser_corpus/upstream_metadata_0 index 0dbabea45655f..b212f5fe5b97b 100644 --- a/test/common/router/header_parser_corpus/upstream_metadata_0 +++ b/test/common/router/header_parser_corpus/upstream_metadata_0 @@ -4,7 +4,7 @@ headers_to_add { value: "%UPSTREAM_METADATA([\"ns\", \"key\"])%" } } -request_info { +stream_info { start_time: 1522796769123 upstream_metadata { filter_metadata { diff --git a/test/common/router/header_parser_corpus/upstream_metadata_1 b/test/common/router/header_parser_corpus/upstream_metadata_1 index df3a7bcaffd8d..d9e32938e676e 100644 --- a/test/common/router/header_parser_corpus/upstream_metadata_1 +++ b/test/common/router/header_parser_corpus/upstream_metadata_1 @@ -4,7 +4,7 @@ headers_to_add { value: "%UPSTREAM_METADATA( \t [ \t \"ns\" \t , \t \"key\" \t ] \t )%" } } -request_info { +stream_info { start_time: 1522796769123 upstream_metadata { filter_metadata { diff --git a/test/common/router/header_parser_fuzz.proto b/test/common/router/header_parser_fuzz.proto index 2a7fc02340eaa..49bd632370ef1 100644 --- a/test/common/router/header_parser_fuzz.proto +++ b/test/common/router/header_parser_fuzz.proto @@ -10,5 +10,5 @@ import "test/fuzz/common.proto"; message TestCase { repeated envoy.api.v2.core.HeaderValueOption headers_to_add = 1; repeated string headers_to_remove = 2; - test.fuzz.RequestInfo request_info = 3; + test.fuzz.StreamInfo stream_info = 3; } diff --git a/test/common/router/header_parser_fuzz_test.cc b/test/common/router/header_parser_fuzz_test.cc index ed28befac9ffd..316b6fae8ea3b 100644 --- a/test/common/router/header_parser_fuzz_test.cc +++ b/test/common/router/header_parser_fuzz_test.cc @@ -14,7 +14,7 @@ DEFINE_PROTO_FUZZER(const test::common::router::TestCase& input) { Router::HeaderParserPtr parser = Router::HeaderParser::configure(input.headers_to_add(), input.headers_to_remove()); Http::HeaderMapImpl header_map; - parser->evaluateHeaders(header_map, fromRequestInfo(input.request_info())); + parser->evaluateHeaders(header_map, fromStreamInfo(input.stream_info())); ENVOY_LOG_MISC(trace, "Success"); } catch (const EnvoyException& e) { ENVOY_LOG_MISC(debug, "EnvoyException: {}", e.what()); diff --git a/test/common/router/retry_state_impl_test.cc b/test/common/router/retry_state_impl_test.cc index f5931569ff351..c0146783f5fdd 100644 --- a/test/common/router/retry_state_impl_test.cc +++ b/test/common/router/retry_state_impl_test.cc @@ -242,6 +242,20 @@ TEST_F(RouterRetryStateImplTest, PolicyGrpcUnavilable) { EXPECT_EQ(RetryStatus::No, state_->shouldRetry(&response_headers, no_reset_, callback_)); } +TEST_F(RouterRetryStateImplTest, PolicyGrpcInternal) { + Http::TestHeaderMapImpl request_headers{{"x-envoy-retry-grpc-on", "internal"}}; + setup(request_headers); + EXPECT_TRUE(state_->enabled()); + + Http::TestHeaderMapImpl response_headers{{":status", "200"}, {"grpc-status", "13"}}; + expectTimerCreateAndEnable(); + EXPECT_EQ(RetryStatus::Yes, state_->shouldRetry(&response_headers, no_reset_, callback_)); + EXPECT_CALL(callback_ready_, ready()); + retry_timer_->callback_(); + + EXPECT_EQ(RetryStatus::No, state_->shouldRetry(&response_headers, no_reset_, callback_)); +} + TEST_F(RouterRetryStateImplTest, Policy5xxRemote200RemoteReset) { // Don't retry after reply start. Http::TestHeaderMapImpl request_headers{{"x-envoy-retry-on", "5xx"}}; @@ -309,6 +323,64 @@ TEST_F(RouterRetryStateImplTest, PolicyRetriable4xxReset) { EXPECT_EQ(RetryStatus::No, state_->shouldRetry(nullptr, remote_reset_, callback_)); } +TEST_F(RouterRetryStateImplTest, RetriableStatusCodes) { + policy_.retriable_status_codes_.push_back(409); + Http::TestHeaderMapImpl request_headers{{"x-envoy-retry-on", "retriable-status-codes"}}; + setup(request_headers); + EXPECT_TRUE(state_->enabled()); + + expectTimerCreateAndEnable(); + + Http::TestHeaderMapImpl response_headers{{":status", "409"}}; + EXPECT_EQ(RetryStatus::Yes, state_->shouldRetry(&response_headers, no_reset_, callback_)); +} + +TEST_F(RouterRetryStateImplTest, RetriableStatusCodesHeader) { + { + Http::TestHeaderMapImpl request_headers{{"x-envoy-retry-on", "retriable-status-codes"}, + {"x-envoy-retriable-status-codes", "200"}}; + setup(request_headers); + EXPECT_TRUE(state_->enabled()); + + expectTimerCreateAndEnable(); + + Http::TestHeaderMapImpl response_headers{{":status", "200"}}; + EXPECT_EQ(RetryStatus::Yes, state_->shouldRetry(&response_headers, no_reset_, callback_)); + } + { + Http::TestHeaderMapImpl request_headers{{"x-envoy-retry-on", "retriable-status-codes"}, + {"x-envoy-retriable-status-codes", "418,200"}}; + setup(request_headers); + EXPECT_TRUE(state_->enabled()); + + expectTimerCreateAndEnable(); + + Http::TestHeaderMapImpl response_headers{{":status", "200"}}; + EXPECT_EQ(RetryStatus::Yes, state_->shouldRetry(&response_headers, no_reset_, callback_)); + } + { + Http::TestHeaderMapImpl request_headers{{"x-envoy-retry-on", "retriable-status-codes"}, + {"x-envoy-retriable-status-codes", " 418 junk,200"}}; + setup(request_headers); + EXPECT_TRUE(state_->enabled()); + + expectTimerCreateAndEnable(); + + Http::TestHeaderMapImpl response_headers{{":status", "200"}}; + EXPECT_EQ(RetryStatus::Yes, state_->shouldRetry(&response_headers, no_reset_, callback_)); + } + { + Http::TestHeaderMapImpl request_headers{ + {"x-envoy-retry-on", "retriable-status-codes"}, + {"x-envoy-retriable-status-codes", " 418 junk,xxx200"}}; + setup(request_headers); + EXPECT_TRUE(state_->enabled()); + + Http::TestHeaderMapImpl response_headers{{":status", "200"}}; + EXPECT_EQ(RetryStatus::No, state_->shouldRetry(&response_headers, no_reset_, callback_)); + } +} + TEST_F(RouterRetryStateImplTest, RouteConfigNoHeaderConfig) { policy_.num_retries_ = 1; policy_.retry_on_ = RetryPolicy::RETRY_ON_CONNECT_FAILURE; diff --git a/test/common/router/route_corpus/clusterfuzz-testcase-minimized-route_fuzz_test-5142800207708160 b/test/common/router/route_corpus/clusterfuzz-testcase-minimized-route_fuzz_test-5142800207708160 new file mode 100644 index 0000000000000..c6926be35c171 --- /dev/null +++ b/test/common/router/route_corpus/clusterfuzz-testcase-minimized-route_fuzz_test-5142800207708160 @@ -0,0 +1 @@ +config { virtual_hosts { name: " " domains: "*" routes { match { path: "/" } route { cluster: " " prefix_rewrite: " " } } } request_headers_to_remove: ":path" } diff --git a/test/common/router/route_fuzz_test.cc b/test/common/router/route_fuzz_test.cc index 72b806de63473..45f8101eb68d0 100644 --- a/test/common/router/route_fuzz_test.cc +++ b/test/common/router/route_fuzz_test.cc @@ -13,7 +13,7 @@ namespace Router { // 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 request_info; + NiceMock stream_info; NiceMock factory_context; MessageUtil::validate(input.config()); ConfigImpl config(input.config(), factory_context, true); @@ -31,7 +31,7 @@ DEFINE_PROTO_FUZZER(const test::common::router::RouteTestCase& input) { } auto route = config.route(headers, input.random_value()); if (route != nullptr && route->routeEntry() != nullptr) { - route->routeEntry()->finalizeRequestHeaders(headers, request_info, true); + route->routeEntry()->finalizeRequestHeaders(headers, stream_info, true); } ENVOY_LOG_MISC(trace, "Success"); } catch (const EnvoyException& e) { diff --git a/test/common/router/router_test.cc b/test/common/router/router_test.cc index c44db40164b02..1c426c2d0f4fc 100644 --- a/test/common/router/router_test.cc +++ b/test/common/router/router_test.cc @@ -118,13 +118,13 @@ class RouterTestBase : public testing::Test { ProtobufWkt::Struct request_struct, route_struct; ProtobufWkt::Value val; - // Populate metadata like RequestInfo.setDynamicMetadata() would. + // Populate metadata like StreamInfo.setDynamicMetadata() would. auto& fields_map = *request_struct.mutable_fields(); val.set_string_value("v3.1"); fields_map["version"] = val; val.set_string_value("devel"); fields_map["stage"] = val; - (*callbacks_.request_info_.metadata_ + (*callbacks_.stream_info_.metadata_ .mutable_filter_metadata())[Envoy::Config::MetadataFilters::get().ENVOY_LB] = request_struct; @@ -210,7 +210,7 @@ class RouterTestSuppressEnvoyHeaders : public RouterTestBase { }; TEST_F(RouterTest, RouteNotFound) { - EXPECT_CALL(callbacks_.request_info_, setResponseFlag(RequestInfo::ResponseFlag::NoRouteFound)); + EXPECT_CALL(callbacks_.stream_info_, setResponseFlag(StreamInfo::ResponseFlag::NoRouteFound)); Http::TestHeaderMapImpl headers; HttpTestUtility::addDefaultHeaders(headers); @@ -222,7 +222,7 @@ TEST_F(RouterTest, RouteNotFound) { } TEST_F(RouterTest, ClusterNotFound) { - EXPECT_CALL(callbacks_.request_info_, setResponseFlag(RequestInfo::ResponseFlag::NoRouteFound)); + EXPECT_CALL(callbacks_.stream_info_, setResponseFlag(StreamInfo::ResponseFlag::NoRouteFound)); Http::TestHeaderMapImpl headers; HttpTestUtility::addDefaultHeaders(headers); @@ -250,9 +250,9 @@ TEST_F(RouterTest, PoolFailureWithPriority) { {":status", "503"}, {"content-length", "57"}, {"content-type", "text/plain"}}; EXPECT_CALL(callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), false)); EXPECT_CALL(callbacks_, encodeData(_, true)); - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::UpstreamConnectionFailure)); - EXPECT_CALL(callbacks_.request_info_, onUpstreamHostSelected(_)) + EXPECT_CALL(callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::UpstreamConnectionFailure)); + EXPECT_CALL(callbacks_.stream_info_, onUpstreamHostSelected(_)) .WillOnce(Invoke([&](const Upstream::HostDescriptionConstSharedPtr host) -> void { EXPECT_EQ(host_address_, host->address()); })); @@ -326,7 +326,7 @@ TEST_F(RouterTest, UseDownstreamProtocol1) { absl::optional downstream_protocol{Http::Protocol::Http11}; EXPECT_CALL(*cm_.thread_local_cluster_.cluster_.info_, features()) .WillOnce(Return(Upstream::ClusterInfo::Features::USE_DOWNSTREAM_PROTOCOL)); - EXPECT_CALL(callbacks_.request_info_, protocol()).WillOnce(ReturnPointee(&downstream_protocol)); + EXPECT_CALL(callbacks_.stream_info_, protocol()).WillOnce(ReturnPointee(&downstream_protocol)); EXPECT_CALL(cm_, httpConnPoolForCluster(_, _, Http::Protocol::Http11, _)); EXPECT_CALL(cm_.conn_pool_, newStream(_, _)).WillOnce(Return(&cancellable_)); @@ -346,7 +346,7 @@ TEST_F(RouterTest, UseDownstreamProtocol2) { absl::optional downstream_protocol{Http::Protocol::Http2}; EXPECT_CALL(*cm_.thread_local_cluster_.cluster_.info_, features()) .WillOnce(Return(Upstream::ClusterInfo::Features::USE_DOWNSTREAM_PROTOCOL)); - EXPECT_CALL(callbacks_.request_info_, protocol()).WillOnce(ReturnPointee(&downstream_protocol)); + EXPECT_CALL(callbacks_.stream_info_, protocol()).WillOnce(ReturnPointee(&downstream_protocol)); EXPECT_CALL(cm_, httpConnPoolForCluster(_, _, Http::Protocol::Http2, _)); EXPECT_CALL(cm_.conn_pool_, newStream(_, _)).WillOnce(Return(&cancellable_)); @@ -644,8 +644,8 @@ TEST_F(RouterTest, NoHost) { {":status", "503"}, {"content-length", "19"}, {"content-type", "text/plain"}}; EXPECT_CALL(callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), false)); EXPECT_CALL(callbacks_, encodeData(_, true)); - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::NoHealthyUpstream)); + EXPECT_CALL(callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::NoHealthyUpstream)); Http::TestHeaderMapImpl headers; HttpTestUtility::addDefaultHeaders(headers); @@ -665,8 +665,7 @@ TEST_F(RouterTest, MaintenanceMode) { {"x-envoy-overloaded", "true"}}; EXPECT_CALL(callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), false)); EXPECT_CALL(callbacks_, encodeData(_, true)); - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::UpstreamOverflow)); + EXPECT_CALL(callbacks_.stream_info_, setResponseFlag(StreamInfo::ResponseFlag::UpstreamOverflow)); Http::TestHeaderMapImpl headers; HttpTestUtility::addDefaultHeaders(headers); @@ -689,8 +688,7 @@ TEST_F(RouterTestSuppressEnvoyHeaders, MaintenanceMode) { {":status", "503"}, {"content-length", "16"}, {"content-type", "text/plain"}}; EXPECT_CALL(callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), false)); EXPECT_CALL(callbacks_, encodeData(_, true)); - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::UpstreamOverflow)); + EXPECT_CALL(callbacks_.stream_info_, setResponseFlag(StreamInfo::ResponseFlag::UpstreamOverflow)); Http::TestHeaderMapImpl headers; HttpTestUtility::addDefaultHeaders(headers); @@ -795,8 +793,7 @@ TEST_F(RouterTest, NoRetriesOverflow) { router_.retry_state_->callback_(); // RetryOverflow kicks in. - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::UpstreamOverflow)); + EXPECT_CALL(callbacks_.stream_info_, setResponseFlag(StreamInfo::ResponseFlag::UpstreamOverflow)); EXPECT_CALL(*router_.retry_state_, shouldRetry(_, _, _)) .WillOnce(Return(RetryStatus::NoOverflow)); EXPECT_CALL(cm_.conn_pool_.host_->health_checker_, setUnhealthy()).Times(0); @@ -841,7 +838,7 @@ TEST_F(RouterTest, UpstreamTimeout) { callbacks.onPoolReady(encoder, cm_.conn_pool_.host_); return nullptr; })); - EXPECT_CALL(callbacks_.request_info_, onUpstreamHostSelected(_)) + EXPECT_CALL(callbacks_.stream_info_, onUpstreamHostSelected(_)) .WillOnce(Invoke([&](const Upstream::HostDescriptionConstSharedPtr host) -> void { EXPECT_EQ(host_address_, host->address()); })); @@ -854,8 +851,8 @@ TEST_F(RouterTest, UpstreamTimeout) { Buffer::OwnedImpl data; router_.decodeData(data, true); - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::UpstreamRequestTimeout)); + EXPECT_CALL(callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::UpstreamRequestTimeout)); EXPECT_CALL(encoder.stream_, resetStream(Http::StreamResetReason::LocalReset)); Http::TestHeaderMapImpl response_headers{ {":status", "504"}, {"content-length", "24"}, {"content-type", "text/plain"}}; @@ -1060,7 +1057,7 @@ TEST_F(RouterTest, UpstreamTimeoutWithAltResponse) { callbacks.onPoolReady(encoder, cm_.conn_pool_.host_); return nullptr; })); - EXPECT_CALL(callbacks_.request_info_, onUpstreamHostSelected(_)) + EXPECT_CALL(callbacks_.stream_info_, onUpstreamHostSelected(_)) .WillOnce(Invoke([&](const Upstream::HostDescriptionConstSharedPtr host) -> void { EXPECT_EQ(host_address_, host->address()); })); @@ -1074,8 +1071,8 @@ TEST_F(RouterTest, UpstreamTimeoutWithAltResponse) { Buffer::OwnedImpl data; router_.decodeData(data, true); - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::UpstreamRequestTimeout)); + EXPECT_CALL(callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::UpstreamRequestTimeout)); EXPECT_CALL(encoder.stream_, resetStream(Http::StreamResetReason::LocalReset)); Http::TestHeaderMapImpl response_headers{{":status", "204"}}; EXPECT_CALL(callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), true)); @@ -1100,7 +1097,7 @@ TEST_F(RouterTest, UpstreamPerTryTimeout) { callbacks.onPoolReady(encoder, cm_.conn_pool_.host_); return nullptr; })); - EXPECT_CALL(callbacks_.request_info_, onUpstreamHostSelected(_)) + EXPECT_CALL(callbacks_.stream_info_, onUpstreamHostSelected(_)) .WillOnce(Invoke([&](const Upstream::HostDescriptionConstSharedPtr host) -> void { EXPECT_EQ(host_address_, host->address()); })); @@ -1115,8 +1112,8 @@ TEST_F(RouterTest, UpstreamPerTryTimeout) { Buffer::OwnedImpl data; router_.decodeData(data, true); - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::UpstreamRequestTimeout)); + EXPECT_CALL(callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::UpstreamRequestTimeout)); EXPECT_CALL(encoder.stream_, resetStream(Http::StreamResetReason::LocalReset)); Http::TestHeaderMapImpl response_headers{ {":status", "504"}, {"content-length", "24"}, {"content-type", "text/plain"}}; @@ -1155,8 +1152,8 @@ TEST_F(RouterTest, PerTryTimeoutWithNoUpstreamHost) { router_.decodeData(data, true); EXPECT_CALL(cancellable_, cancel()); - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::UpstreamRequestTimeout)); + EXPECT_CALL(callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::UpstreamRequestTimeout)); Http::TestHeaderMapImpl response_headers{ {":status", "504"}, {"content-length", "24"}, {"content-type", "text/plain"}}; EXPECT_CALL(callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), false)); @@ -1180,9 +1177,9 @@ TEST_F(RouterTest, RetryRequestNotComplete) { callbacks.onPoolReady(encoder1, cm_.conn_pool_.host_); return nullptr; })); - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::UpstreamRemoteReset)); - EXPECT_CALL(callbacks_.request_info_, onUpstreamHostSelected(_)) + EXPECT_CALL(callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::UpstreamRemoteReset)); + EXPECT_CALL(callbacks_.stream_info_, onUpstreamHostSelected(_)) .WillOnce(Invoke([&](const Upstream::HostDescriptionConstSharedPtr host) -> void { EXPECT_EQ(host_address_, host->address()); })); @@ -1209,7 +1206,7 @@ TEST_F(RouterTest, RetryNoneHealthy) { })); expectResponseTimerCreate(); - EXPECT_CALL(callbacks_.request_info_, onUpstreamHostSelected(_)) + EXPECT_CALL(callbacks_.stream_info_, onUpstreamHostSelected(_)) .WillOnce(Invoke([&](const Upstream::HostDescriptionConstSharedPtr host) -> void { EXPECT_EQ(host_address_, host->address()); })); @@ -1227,8 +1224,8 @@ TEST_F(RouterTest, RetryNoneHealthy) { {":status", "503"}, {"content-length", "19"}, {"content-type", "text/plain"}}; EXPECT_CALL(callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), false)); EXPECT_CALL(callbacks_, encodeData(_, true)); - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::NoHealthyUpstream)); + EXPECT_CALL(callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::NoHealthyUpstream)); router_.retry_state_->callback_(); EXPECT_TRUE(verifyHostUpstreamStats(0, 1)); } @@ -1474,8 +1471,8 @@ TEST_F(RouterTest, RetryTimeoutDuringRetryDelay) { EXPECT_TRUE(verifyHostUpstreamStats(0, 1)); // Fire timeout. - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::UpstreamRequestTimeout)); + EXPECT_CALL(callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::UpstreamRequestTimeout)); EXPECT_CALL(cm_.conn_pool_.host_->outlier_detector_, putResponseTime(_)).Times(0); Http::TestHeaderMapImpl response_headers{ @@ -1520,8 +1517,8 @@ TEST_F(RouterTest, RetryTimeoutDuringRetryDelayWithUpstreamRequestNoHost) { // Fire timeout. EXPECT_CALL(cancellable, cancel()); - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::UpstreamRequestTimeout)); + EXPECT_CALL(callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::UpstreamRequestTimeout)); EXPECT_CALL(cm_.conn_pool_.host_->outlier_detector_, putResponseTime(_)).Times(0); Http::TestHeaderMapImpl response_headers{ @@ -1569,8 +1566,8 @@ TEST_F(RouterTest, RetryTimeoutDuringRetryDelayWithUpstreamRequestNoHostAltRespo // Fire timeout. EXPECT_CALL(cancellable, cancel()); - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::UpstreamRequestTimeout)); + EXPECT_CALL(callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::UpstreamRequestTimeout)); EXPECT_CALL(cm_.conn_pool_.host_->outlier_detector_, putResponseTime(_)).Times(0); Http::TestHeaderMapImpl response_headers{{":status", "204"}}; @@ -1661,7 +1658,7 @@ TEST_F(RouterTest, RetryUpstreamGrpcCancelled) { })); expectResponseTimerCreate(); - Http::TestHeaderMapImpl headers{{"x-envoy-grpc-retry-on", "cancelled"}, + Http::TestHeaderMapImpl headers{{"x-envoy-retry-grpc-on", "cancelled"}, {"x-envoy-internal", "true"}, {"content-type", "application/grpc"}, {"grpc-timeout", "20S"}}; @@ -2004,6 +2001,7 @@ TEST(RouterFilterUtilityTest, FinalTimeout) { EXPECT_EQ(std::chrono::milliseconds(0), timeout.per_try_timeout_); EXPECT_FALSE(headers.has("x-envoy-upstream-rq-timeout-ms")); EXPECT_EQ("15", headers.get_("x-envoy-expected-rq-timeout-ms")); + EXPECT_FALSE(headers.has("grpc-timeout")); } { NiceMock route; @@ -2014,6 +2012,7 @@ TEST(RouterFilterUtilityTest, FinalTimeout) { EXPECT_EQ(std::chrono::milliseconds(0), timeout.per_try_timeout_); EXPECT_FALSE(headers.has("x-envoy-upstream-rq-timeout-ms")); EXPECT_EQ("10", headers.get_("x-envoy-expected-rq-timeout-ms")); + EXPECT_FALSE(headers.has("grpc-timeout")); } { NiceMock route; @@ -2026,6 +2025,7 @@ TEST(RouterFilterUtilityTest, FinalTimeout) { EXPECT_FALSE(headers.has("x-envoy-upstream-rq-timeout-ms")); EXPECT_FALSE(headers.has("x-envoy-upstream-rq-per-try-timeout-ms")); EXPECT_EQ("15", headers.get_("x-envoy-expected-rq-timeout-ms")); + EXPECT_FALSE(headers.has("grpc-timeout")); } { NiceMock route; @@ -2038,6 +2038,7 @@ TEST(RouterFilterUtilityTest, FinalTimeout) { EXPECT_FALSE(headers.has("x-envoy-upstream-rq-timeout-ms")); EXPECT_FALSE(headers.has("x-envoy-upstream-rq-per-try-timeout-ms")); EXPECT_EQ("5", headers.get_("x-envoy-expected-rq-timeout-ms")); + EXPECT_FALSE(headers.has("grpc-timeout")); } { NiceMock route; @@ -2050,6 +2051,7 @@ TEST(RouterFilterUtilityTest, FinalTimeout) { EXPECT_FALSE(headers.has("x-envoy-upstream-rq-timeout-ms")); EXPECT_FALSE(headers.has("x-envoy-upstream-rq-per-try-timeout-ms")); EXPECT_EQ("7", headers.get_("x-envoy-expected-rq-timeout-ms")); + EXPECT_FALSE(headers.has("grpc-timeout")); } { NiceMock route; @@ -2063,6 +2065,7 @@ TEST(RouterFilterUtilityTest, FinalTimeout) { EXPECT_FALSE(headers.has("x-envoy-upstream-rq-timeout-ms")); EXPECT_FALSE(headers.has("x-envoy-upstream-rq-per-try-timeout-ms")); EXPECT_EQ("5", headers.get_("x-envoy-expected-rq-timeout-ms")); + EXPECT_FALSE(headers.has("grpc-timeout")); } { NiceMock route; @@ -2072,6 +2075,7 @@ TEST(RouterFilterUtilityTest, FinalTimeout) { FilterUtility::TimeoutData timeout = FilterUtility::finalTimeout(route, headers, true, true); EXPECT_EQ(std::chrono::milliseconds(0), timeout.global_timeout_); EXPECT_EQ(std::chrono::milliseconds(0), timeout.per_try_timeout_); + EXPECT_FALSE(headers.has("grpc-timeout")); } { NiceMock route; @@ -2081,6 +2085,7 @@ TEST(RouterFilterUtilityTest, FinalTimeout) { FilterUtility::TimeoutData timeout = FilterUtility::finalTimeout(route, headers, true, true); EXPECT_EQ(std::chrono::milliseconds(10), timeout.global_timeout_); EXPECT_EQ(std::chrono::milliseconds(0), timeout.per_try_timeout_); + EXPECT_FALSE(headers.has("grpc-timeout")); } { NiceMock route; @@ -2091,6 +2096,7 @@ TEST(RouterFilterUtilityTest, FinalTimeout) { FilterUtility::TimeoutData timeout = FilterUtility::finalTimeout(route, headers, true, true); EXPECT_EQ(std::chrono::milliseconds(1000), timeout.global_timeout_); EXPECT_EQ(std::chrono::milliseconds(0), timeout.per_try_timeout_); + EXPECT_EQ("1000m", headers.get_("grpc-timeout")); } { NiceMock route; @@ -2101,6 +2107,7 @@ TEST(RouterFilterUtilityTest, FinalTimeout) { FilterUtility::TimeoutData timeout = FilterUtility::finalTimeout(route, headers, true, true); EXPECT_EQ(std::chrono::milliseconds(999), timeout.global_timeout_); EXPECT_EQ(std::chrono::milliseconds(0), timeout.per_try_timeout_); + EXPECT_EQ("999m", headers.get_("grpc-timeout")); } { NiceMock route; @@ -2110,6 +2117,7 @@ TEST(RouterFilterUtilityTest, FinalTimeout) { FilterUtility::TimeoutData timeout = FilterUtility::finalTimeout(route, headers, true, true); EXPECT_EQ(std::chrono::milliseconds(999), timeout.global_timeout_); EXPECT_EQ(std::chrono::milliseconds(0), timeout.per_try_timeout_); + EXPECT_EQ("999m", headers.get_("grpc-timeout")); } { NiceMock route; @@ -2123,6 +2131,7 @@ TEST(RouterFilterUtilityTest, FinalTimeout) { EXPECT_EQ(std::chrono::milliseconds(0), timeout.per_try_timeout_); EXPECT_FALSE(headers.has("x-envoy-upstream-rq-timeout-ms")); EXPECT_EQ("15", headers.get_("x-envoy-expected-rq-timeout-ms")); + EXPECT_EQ("15m", headers.get_("grpc-timeout")); } { NiceMock route; @@ -2136,6 +2145,7 @@ TEST(RouterFilterUtilityTest, FinalTimeout) { EXPECT_EQ(std::chrono::milliseconds(0), timeout.per_try_timeout_); EXPECT_FALSE(headers.has("x-envoy-upstream-rq-timeout-ms")); EXPECT_EQ("1000", headers.get_("x-envoy-expected-rq-timeout-ms")); + EXPECT_EQ("1000m", headers.get_("grpc-timeout")); } { NiceMock route; @@ -2151,6 +2161,7 @@ TEST(RouterFilterUtilityTest, FinalTimeout) { EXPECT_FALSE(headers.has("x-envoy-upstream-rq-timeout-ms")); EXPECT_FALSE(headers.has("x-envoy-upstream-rq-per-try-timeout-ms")); EXPECT_EQ("15", headers.get_("x-envoy-expected-rq-timeout-ms")); + EXPECT_EQ("15m", headers.get_("grpc-timeout")); } { NiceMock route; @@ -2166,6 +2177,7 @@ TEST(RouterFilterUtilityTest, FinalTimeout) { EXPECT_FALSE(headers.has("x-envoy-upstream-rq-timeout-ms")); EXPECT_FALSE(headers.has("x-envoy-upstream-rq-per-try-timeout-ms")); EXPECT_EQ("5", headers.get_("x-envoy-expected-rq-timeout-ms")); + EXPECT_EQ("5m", headers.get_("grpc-timeout")); } { NiceMock route; @@ -2181,6 +2193,7 @@ TEST(RouterFilterUtilityTest, FinalTimeout) { EXPECT_FALSE(headers.has("x-envoy-upstream-rq-timeout-ms")); EXPECT_FALSE(headers.has("x-envoy-upstream-rq-per-try-timeout-ms")); EXPECT_EQ("7", headers.get_("x-envoy-expected-rq-timeout-ms")); + EXPECT_EQ("7m", headers.get_("grpc-timeout")); } { NiceMock route; @@ -2197,6 +2210,7 @@ TEST(RouterFilterUtilityTest, FinalTimeout) { EXPECT_FALSE(headers.has("x-envoy-upstream-rq-timeout-ms")); EXPECT_FALSE(headers.has("x-envoy-upstream-rq-per-try-timeout-ms")); EXPECT_EQ("5", headers.get_("x-envoy-expected-rq-timeout-ms")); + EXPECT_EQ("5m", headers.get_("grpc-timeout")); } } @@ -2361,7 +2375,7 @@ TEST_F(RouterTest, AutoHostRewriteEnabled) { encoder.stream_.resetStream(Http::StreamResetReason::RemoteReset); })); - EXPECT_CALL(callbacks_.request_info_, onUpstreamHostSelected(_)) + EXPECT_CALL(callbacks_.stream_info_, onUpstreamHostSelected(_)) .WillOnce(Invoke([&](const Upstream::HostDescriptionConstSharedPtr host) -> void { EXPECT_EQ(host_address_, host->address()); })); @@ -2396,7 +2410,7 @@ TEST_F(RouterTest, AutoHostRewriteDisabled) { encoder.stream_.resetStream(Http::StreamResetReason::RemoteReset); })); - EXPECT_CALL(callbacks_.request_info_, onUpstreamHostSelected(_)) + EXPECT_CALL(callbacks_.stream_info_, onUpstreamHostSelected(_)) .WillOnce(Invoke([&](const Upstream::HostDescriptionConstSharedPtr host) -> void { EXPECT_EQ(host_address_, host->address()); })); @@ -2531,9 +2545,9 @@ TEST_F(WatermarkTest, RetryRequestNotComplete) { callbacks.onPoolReady(encoder1, cm_.conn_pool_.host_); return nullptr; })); - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::UpstreamRemoteReset)); - EXPECT_CALL(callbacks_.request_info_, onUpstreamHostSelected(_)) + EXPECT_CALL(callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::UpstreamRemoteReset)); + EXPECT_CALL(callbacks_.stream_info_, onUpstreamHostSelected(_)) .WillRepeatedly(Invoke([&](const Upstream::HostDescriptionConstSharedPtr host) -> void { EXPECT_EQ(host_address_, host->address()); })); diff --git a/test/common/router/shadow_writer_impl_test.cc b/test/common/router/shadow_writer_impl_test.cc index 53f979e8826db..a3683bc3e3061 100644 --- a/test/common/router/shadow_writer_impl_test.cc +++ b/test/common/router/shadow_writer_impl_test.cc @@ -11,58 +11,62 @@ #include "gtest/gtest.h" using testing::_; +using testing::InSequence; using testing::Invoke; +using testing::Return; namespace Envoy { namespace Router { -void expectShadowWriter(absl::string_view host, absl::string_view shadowed_host) { - Upstream::MockClusterManager cm; - ShadowWriterImpl writer(cm); +class ShadowWriterImplTest : public testing::Test { +public: + void expectShadowWriter(absl::string_view host, absl::string_view shadowed_host) { + Http::MessagePtr message(new Http::RequestMessageImpl()); + message->headers().insertHost().value(std::string(host)); + EXPECT_CALL(cm_, get("foo")); + EXPECT_CALL(cm_, httpAsyncClientForCluster("foo")).WillOnce(ReturnRef(cm_.async_client_)); + Http::MockAsyncClientRequest request(&cm_.async_client_); + EXPECT_CALL( + cm_.async_client_, + send_(_, _, absl::optional(std::chrono::milliseconds(5)))) + .WillOnce(Invoke( + [&](Http::MessagePtr& inner_message, Http::AsyncClient::Callbacks& callbacks, + const absl::optional&) -> Http::AsyncClient::Request* { + EXPECT_EQ(message, inner_message); + EXPECT_EQ(shadowed_host, message->headers().Host()->value().c_str()); + callback_ = &callbacks; + return &request; + })); + writer_.shadow("foo", std::move(message), std::chrono::milliseconds(5)); + } - // Success case - Http::MessagePtr message(new Http::RequestMessageImpl()); - message->headers().insertHost().value(std::string(host)); - EXPECT_CALL(cm, httpAsyncClientForCluster("foo")).WillOnce(ReturnRef(cm.async_client_)); - Http::MockAsyncClientRequest request(&cm.async_client_); - Http::AsyncClient::Callbacks* callback; - EXPECT_CALL(cm.async_client_, - send_(_, _, absl::optional(std::chrono::milliseconds(5)))) - .WillOnce(Invoke( - [&](Http::MessagePtr& inner_message, Http::AsyncClient::Callbacks& callbacks, - const absl::optional&) -> Http::AsyncClient::Request* { - EXPECT_EQ(message, inner_message); - EXPECT_EQ(shadowed_host, message->headers().Host()->value().c_str()); - callback = &callbacks; - return &request; - })); - writer.shadow("foo", std::move(message), std::chrono::milliseconds(5)); + Upstream::MockClusterManager cm_; + ShadowWriterImpl writer_{cm_}; + Http::AsyncClient::Callbacks* callback_{}; +}; - Http::MessagePtr response(new Http::RequestMessageImpl()); - callback->onSuccess(std::move(response)); +TEST_F(ShadowWriterImplTest, Success) { + InSequence s; - // Failure case - message.reset(new Http::RequestMessageImpl()); - message->headers().insertHost().value(std::string(host)); - EXPECT_CALL(cm, httpAsyncClientForCluster("bar")).WillOnce(ReturnRef(cm.async_client_)); - EXPECT_CALL(cm.async_client_, - send_(_, _, absl::optional(std::chrono::milliseconds(10)))) - .WillOnce(Invoke( - [&](Http::MessagePtr& inner_message, Http::AsyncClient::Callbacks& callbacks, - const absl::optional&) -> Http::AsyncClient::Request* { - EXPECT_EQ(message, inner_message); - EXPECT_EQ(shadowed_host, message->headers().Host()->value().c_str()); - callback = &callbacks; - return &request; - })); - writer.shadow("bar", std::move(message), std::chrono::milliseconds(10)); - callback->onFailure(Http::AsyncClient::FailureReason::Reset); + expectShadowWriter("cluster1", "cluster1-shadow"); + Http::MessagePtr response(new Http::RequestMessageImpl()); + callback_->onSuccess(std::move(response)); } -TEST(ShadowWriterImplTest, All) { - expectShadowWriter("cluster1", "cluster1-shadow"); +TEST_F(ShadowWriterImplTest, Failure) { + InSequence s; + expectShadowWriter("cluster1:8000", "cluster1-shadow:8000"); - expectShadowWriter("cluster1:80", "cluster1-shadow:80"); + callback_->onFailure(Http::AsyncClient::FailureReason::Reset); +} + +TEST_F(ShadowWriterImplTest, NoCluster) { + InSequence s; + + Http::MessagePtr message(new Http::RequestMessageImpl()); + EXPECT_CALL(cm_, get("foo")).WillOnce(Return(nullptr)); + EXPECT_CALL(cm_, httpAsyncClientForCluster("foo")).Times(0); + writer_.shadow("foo", std::move(message), std::chrono::milliseconds(5)); } } // namespace Router diff --git a/test/common/ssl/BUILD b/test/common/ssl/BUILD index 36c928b705e9e..2a3e5eb8bb686 100644 --- a/test/common/ssl/BUILD +++ b/test/common/ssl/BUILD @@ -68,3 +68,18 @@ envoy_cc_test( "//test/test_common:environment_lib", ], ) + +envoy_cc_test( + name = "utility_test", + srcs = [ + "utility_test.cc", + ], + data = [ + "gen_unittest_certs.sh", + "//test/common/ssl/test_data:certs", + ], + deps = [ + "//source/common/ssl:utility_lib", + "//test/test_common:environment_lib", + ], +) diff --git a/test/common/ssl/context_impl_test.cc b/test/common/ssl/context_impl_test.cc index ef9777055abf3..da59a4450d3f5 100644 --- a/test/common/ssl/context_impl_test.cc +++ b/test/common/ssl/context_impl_test.cc @@ -5,6 +5,7 @@ #include "common/secret/sds_api.h" #include "common/ssl/context_config_impl.h" #include "common/ssl/context_impl.h" +#include "common/ssl/utility.h" #include "common/stats/isolated_store_impl.h" #include "test/common/ssl/ssl_certs_test.h" @@ -15,7 +16,9 @@ #include "test/test_common/utility.h" #include "gtest/gtest.h" +#include "openssl/x509v3.h" +using Envoy::Protobuf::util::MessageDifferencer; using testing::NiceMock; using testing::ReturnRef; @@ -155,16 +158,78 @@ TEST_F(SslContextImplTest, TestGetCertInformation) { // For the cert_chain, it is dynamically created when we run_envoy_test.sh which changes the // serial number with // every build. For cert_chain output, we check only for the certificate path. - std::string ca_cert_partial_output(TestEnvironment::substitute( - "Certificate Path: {{ test_rundir }}/test/common/ssl/test_data/ca_cert.pem, Serial Number: " - "eaf3b0ea1d0e579a, " - "Days until Expiration: ")); - std::string cert_chain_partial_output( - TestEnvironment::substitute("Certificate Path: {{ test_tmpdir }}/unittestcert.pem")); + std::string ca_cert_json = R"EOF({ + "path": "{{ test_rundir }}/test/common/ssl/test_data/ca_cert.pem", + "serial_number": "eaf3b0ea1d0e579a", + "subject_alt_names": [], + } +)EOF"; + + std::string cert_chain_json = R"EOF({ + "path": "{{ test_tmpdir }}/unittestcert.pem", + } +)EOF"; + + std::string ca_cert_partial_output(TestEnvironment::substitute(ca_cert_json)); + std::string cert_chain_partial_output(TestEnvironment::substitute(cert_chain_json)); + envoy::admin::v2alpha::CertificateDetails certificate_details, cert_chain_details; + MessageUtil::loadFromJson(ca_cert_partial_output, certificate_details); + MessageUtil::loadFromJson(cert_chain_partial_output, cert_chain_details); + + MessageDifferencer message_differencer; + message_differencer.set_scope(MessageDifferencer::Scope::PARTIAL); + EXPECT_TRUE(message_differencer.Compare(certificate_details, *context->getCaCertInformation())); + EXPECT_TRUE(message_differencer.Compare(cert_chain_details, *context->getCertChainInformation())); +} + +TEST_F(SslContextImplTest, TestGetCertInformationWithSAN) { + std::string json = R"EOF( + { + "cert_chain_file": "{{ test_rundir }}/test/common/ssl/test_data/san_dns_chain3.pem", + "private_key_file": "{{ test_rundir }}/test/common/ssl/test_data/san_dns_key3.pem", + "ca_cert_file": "{{ test_rundir }}/test/common/ssl/test_data/san_dns_cert3.pem" + } + )EOF"; + + Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(json); + ClientContextConfigImpl cfg(*loader, factory_context_); + Runtime::MockLoader runtime; + ContextManagerImpl manager(runtime); + Stats::IsolatedStoreImpl store; + + ClientContextSharedPtr context(manager.createSslClientContext(store, cfg)); + std::string ca_cert_json = R"EOF({ + "path": "{{ test_rundir }}/test/common/ssl/test_data/san_dns_cert3.pem", + "serial_number": "b13ff63f2dbc118d", + "subject_alt_names": [ + { + "dns": "server1.example.com" + } + ] + } +)EOF"; + + std::string cert_chain_json = R"EOF({ + "path": "{{ test_rundir }}/test/common/ssl/test_data/san_dns_chain3.pem", + } +)EOF"; + + // This is similar to the hack above, but right now we generate the ca_cert and it expires in 15 + // days only in the first second that it's valid. We will partially match for up until Days until + // Expiration: 1. + // For the cert_chain, it is dynamically created when we run_envoy_test.sh which changes the + // serial number with + // every build. For cert_chain output, we check only for the certificate path. + std::string ca_cert_partial_output(TestEnvironment::substitute(ca_cert_json)); + std::string cert_chain_partial_output(TestEnvironment::substitute(cert_chain_json)); + envoy::admin::v2alpha::CertificateDetails certificate_details, cert_chain_details; + MessageUtil::loadFromJson(ca_cert_partial_output, certificate_details); + MessageUtil::loadFromJson(cert_chain_partial_output, cert_chain_details); - EXPECT_TRUE(context->getCaCertInformation().find(ca_cert_partial_output) != std::string::npos); - EXPECT_TRUE(context->getCertChainInformation().find(cert_chain_partial_output) != - std::string::npos); + MessageDifferencer message_differencer; + message_differencer.set_scope(MessageDifferencer::Scope::PARTIAL); + EXPECT_TRUE(message_differencer.Compare(certificate_details, *context->getCaCertInformation())); + EXPECT_TRUE(message_differencer.Compare(cert_chain_details, *context->getCertChainInformation())); } TEST_F(SslContextImplTest, TestNoCert) { @@ -174,8 +239,8 @@ TEST_F(SslContextImplTest, TestNoCert) { ContextManagerImpl manager(runtime); Stats::IsolatedStoreImpl store; ClientContextSharedPtr context(manager.createSslClientContext(store, cfg)); - EXPECT_EQ("", context->getCaCertInformation()); - EXPECT_EQ("", context->getCertChainInformation()); + EXPECT_EQ(nullptr, context->getCaCertInformation()); + EXPECT_EQ(nullptr, context->getCertChainInformation()); } class SslServerContextImplTicketTest : public SslContextImplTest { diff --git a/test/common/ssl/utility_test.cc b/test/common/ssl/utility_test.cc new file mode 100644 index 0000000000000..5323369bf9b35 --- /dev/null +++ b/test/common/ssl/utility_test.cc @@ -0,0 +1,53 @@ +#include +#include + +#include "common/ssl/utility.h" + +#include "test/test_common/environment.h" +#include "test/test_common/utility.h" + +#include "gtest/gtest.h" +#include "openssl/x509v3.h" + +namespace Envoy { +namespace Ssl { + +namespace { +bssl::UniquePtr readCertFromFile(const std::string& path) { + FILE* fp = fopen(TestEnvironment::runfilesPath(path).c_str(), "r"); + EXPECT_NE(fp, nullptr); + bssl::UniquePtr cert(PEM_read_X509(fp, nullptr, nullptr, nullptr)); + EXPECT_NE(cert, nullptr); + fclose(fp); + return cert; +} +} // namespace + +TEST(UtilityTest, TestGetSubjectAlternateNamesWithDNS) { + bssl::UniquePtr cert = readCertFromFile("test/common/ssl/test_data/san_dns_cert.pem"); + const std::vector& subject_alt_names = Utility::getSubjectAltNames(*cert, GEN_DNS); + EXPECT_EQ(1, subject_alt_names.size()); +} + +TEST(UtilityTest, TestMultipleGetSubjectAlternateNamesWithDNS) { + bssl::UniquePtr cert = + readCertFromFile("test/common/ssl/test_data/san_multiple_dns_cert.pem"); + const std::vector& subject_alt_names = Utility::getSubjectAltNames(*cert, GEN_DNS); + EXPECT_EQ(2, subject_alt_names.size()); +} + +TEST(UtilityTest, TestGetSubjectAlternateNamesWithUri) { + bssl::UniquePtr cert = readCertFromFile("test/common/ssl/test_data/san_uri_cert.pem"); + const std::vector& subject_alt_names = Utility::getSubjectAltNames(*cert, GEN_URI); + EXPECT_EQ(1, subject_alt_names.size()); +} + +TEST(UtilityTest, TestGetSubjectAlternateNamesWithNoSAN) { + bssl::UniquePtr cert = readCertFromFile("test/common/ssl/test_data/no_san_cert.pem"); + const std::vector& uri_subject_alt_names = + Utility::getSubjectAltNames(*cert, GEN_URI); + EXPECT_EQ(0, uri_subject_alt_names.size()); +} + +} // namespace Ssl +} // namespace Envoy \ No newline at end of file diff --git a/test/common/stats/BUILD b/test/common/stats/BUILD index 27d8daf51b46a..8879f2e1dd13a 100644 --- a/test/common/stats/BUILD +++ b/test/common/stats/BUILD @@ -45,6 +45,15 @@ envoy_cc_test( ], ) +envoy_cc_test( + name = "stats_matcher_test", + srcs = ["stats_matcher_test.cc"], + deps = [ + "//source/common/stats:stats_matcher_lib", + "//test/test_common:utility_lib", + ], +) + envoy_cc_test( name = "tag_producer_test", srcs = ["tag_producer_test.cc"], @@ -69,6 +78,7 @@ envoy_cc_test( name = "thread_local_store_test", srcs = ["thread_local_store_test.cc"], deps = [ + "//source/common/stats:stats_matcher_lib", "//source/common/stats:symbol_table_lib", "//source/common/stats:thread_local_store_lib", "//test/mocks/event:event_mocks", @@ -77,5 +87,6 @@ envoy_cc_test( "//test/mocks/thread_local:thread_local_mocks", "//test/test_common:logging_lib", "//test/test_common:utility_lib", + "@envoy_api//envoy/config/metrics/v2:stats_cc", ], ) diff --git a/test/common/stats/stats_matcher_test.cc b/test/common/stats/stats_matcher_test.cc new file mode 100644 index 0000000000000..3ea99efd41926 --- /dev/null +++ b/test/common/stats/stats_matcher_test.cc @@ -0,0 +1,241 @@ +#include "envoy/config/metrics/v2/stats.pb.h" + +#include "common/stats/stats_matcher_impl.h" + +#include "test/test_common/utility.h" + +#include "gtest/gtest.h" + +using testing::IsFalse; +using testing::IsTrue; + +namespace Envoy { +namespace Stats { + +class StatsMatcherTest : public testing::Test { +protected: + envoy::type::matcher::StringMatcher* inclusionList() { + return stats_config_.mutable_stats_matcher()->mutable_inclusion_list()->add_patterns(); + } + envoy::type::matcher::StringMatcher* exclusionList() { + return stats_config_.mutable_stats_matcher()->mutable_exclusion_list()->add_patterns(); + } + void rejectAll(const bool should_reject) { + stats_config_.mutable_stats_matcher()->set_reject_all(should_reject); + } + void initMatcher() { stats_matcher_impl_ = std::make_unique(stats_config_); } + void expectAccepted(std::vector expected_to_pass) { + for (const auto& stat_name : expected_to_pass) { + EXPECT_FALSE(stats_matcher_impl_->rejects(stat_name)) << "Accepted: " << stat_name; + } + } + void expectDenied(std::vector expected_to_fail) { + for (const auto& stat_name : expected_to_fail) { + EXPECT_TRUE(stats_matcher_impl_->rejects(stat_name)) << "Rejected: " << stat_name; + } + } + +private: + envoy::config::metrics::v2::StatsConfig stats_config_; + std::unique_ptr stats_matcher_impl_; +}; + +TEST_F(StatsMatcherTest, CheckDefault) { + // With no set fields, everything should be allowed through. + initMatcher(); + expectAccepted({"foo", "bar", "foo.bar", "foo.bar.baz", "foobarbaz"}); +} + +// Across-the-board matchers. + +TEST_F(StatsMatcherTest, CheckRejectAll) { + // With reject_all, nothing should be allowed through. + rejectAll(true); + initMatcher(); + expectDenied({"foo", "bar", "foo.bar", "foo.bar.baz", "foobarbaz"}); +} + +TEST_F(StatsMatcherTest, CheckNotRejectAll) { + // With !reject_all, everything should be allowed through. + rejectAll(false); + initMatcher(); + expectAccepted({"foo", "bar", "foo.bar", "foo.bar.baz", "foobarbaz"}); +} + +TEST_F(StatsMatcherTest, CheckIncludeAll) { + inclusionList()->set_regex(".*"); + initMatcher(); + expectAccepted({"foo", "bar", "foo.bar", "foo.bar.baz"}); +} + +TEST_F(StatsMatcherTest, CheckExcludeAll) { + exclusionList()->set_regex(".*"); + initMatcher(); + expectDenied({"foo", "bar", "foo.bar", "foo.bar.baz"}); +} + +// Single exact matchers. + +TEST_F(StatsMatcherTest, CheckIncludeExact) { + inclusionList()->set_exact("abc"); + initMatcher(); + expectAccepted({"abc"}); + expectDenied({"abcd", "abc.d", "d.abc", "dabc", "ab", "ac", "abcc", "Abc", "aBc", "abC", "abc.", + ".abc", "ABC"}); +} + +TEST_F(StatsMatcherTest, CheckExcludeExact) { + exclusionList()->set_exact("abc"); + initMatcher(); + expectAccepted({"abcd", "abc.d", "d.abc", "dabc", "ab", "ac", "abcc", "Abc", "aBc", "abC", "abc.", + ".abc", "ABC"}); + expectDenied({"abc"}); +} + +// Single prefix matchers. + +TEST_F(StatsMatcherTest, CheckIncludePrefix) { + inclusionList()->set_prefix("abc"); + initMatcher(); + expectAccepted({"abc", "abc.foo", "abcfoo"}); + expectDenied({"ABC", "ABC.foo", "ABCfoo", "foo", "abb", "a.b.c", "_abc", "foo.abc", "fooabc"}); +} + +TEST_F(StatsMatcherTest, CheckExcludePrefix) { + exclusionList()->set_prefix("abc"); + initMatcher(); + expectAccepted({"ABC", "ABC.foo", "ABCfoo", "foo", "abb", "a.b.c", "_abc", "foo.abc", "fooabc"}); + expectDenied({"abc", "abc.foo", "abcfoo"}); +} + +// Single suffix matchers. + +TEST_F(StatsMatcherTest, CheckIncludeSuffix) { + inclusionList()->set_suffix("abc"); + initMatcher(); + expectAccepted({"abc", "foo.abc", "fooabc"}); + expectDenied({"ABC", "foo.ABC", "fooABC", "foo", "abb", "a.b.c", "abc_", "abc.foo", "abcfoo"}); +} + +TEST_F(StatsMatcherTest, CheckExcludeSuffix) { + exclusionList()->set_suffix("abc"); + initMatcher(); + expectAccepted({"ABC", "foo.ABC", "fooABC", "foo", "abb", "a.b.c", "abc_", "abc.foo", "abcfoo"}); + expectDenied({"abc", "foo.abc", "fooabc"}); +} + +// Single regex matchers. + +TEST_F(StatsMatcherTest, CheckIncludeRegex) { + inclusionList()->set_regex(".*envoy.*"); + initMatcher(); + expectAccepted({"envoy.matchers.requests", "stats.envoy.2xx", "regex.envoy.matchers"}); + expectDenied({"foo", "Envoy", "EnvoyProxy"}); +} + +TEST_F(StatsMatcherTest, CheckExcludeRegex) { + exclusionList()->set_regex(".*envoy.*"); + initMatcher(); + expectAccepted({"foo", "Envoy", "EnvoyProxy"}); + expectDenied({"envoy.matchers.requests", "stats.envoy.2xx", "regex.envoy.matchers"}); +} + +// Multiple exact matchers. + +TEST_F(StatsMatcherTest, CheckMultipleIncludeExact) { + inclusionList()->set_exact("foo"); + inclusionList()->set_exact("bar"); + initMatcher(); + expectAccepted({"foo", "bar"}); + expectDenied({"foobar", "barfoo", "fo", "ba", "foo.bar"}); +} + +TEST_F(StatsMatcherTest, CheckMultipleExcludeExact) { + exclusionList()->set_exact("foo"); + exclusionList()->set_exact("bar"); + initMatcher(); + expectAccepted({"foobar", "barfoo", "fo", "ba", "foo.bar"}); + expectDenied({"foo", "bar"}); +} + +// Multiple prefix matchers. + +TEST_F(StatsMatcherTest, CheckMultipleIncludePrefix) { + inclusionList()->set_prefix("foo"); + inclusionList()->set_prefix("bar"); + initMatcher(); + expectAccepted({"foo", "foo.abc", "bar", "bar.abc"}); + expectDenied({".foo", "abc.foo", "BAR", "_bar"}); +} + +TEST_F(StatsMatcherTest, CheckMultipleExcludePrefix) { + exclusionList()->set_prefix("foo"); + exclusionList()->set_prefix("bar"); + initMatcher(); + expectAccepted({".foo", "abc.foo", "BAR", "_bar"}); + expectDenied({"foo", "foo.abc", "bar", "bar.abc"}); +} + +// Multiple suffix matchers. + +TEST_F(StatsMatcherTest, CheckMultipleIncludeSuffix) { + inclusionList()->set_suffix("spam"); + inclusionList()->set_suffix("eggs"); + initMatcher(); + expectAccepted( + {"requests.for.spam", "requests.for.eggs", "spam", "eggs", "cannedspam", "fresheggs"}); + expectDenied({"Spam", "EGGS", "spam_", "eggs_"}); +} + +TEST_F(StatsMatcherTest, CheckMultipleExcludeSuffix) { + exclusionList()->set_suffix("spam"); + exclusionList()->set_suffix("eggs"); + initMatcher(); + expectAccepted({"Spam", "EGGS", "spam_", "eggs_"}); + expectDenied( + {"requests.for.spam", "requests.for.eggs", "spam", "eggs", "cannedspam", "fresheggs"}); +} + +// Multiple regex matchers. + +TEST_F(StatsMatcherTest, CheckMultipleIncludeRegex) { + inclusionList()->set_regex(".*envoy.*"); + inclusionList()->set_regex(".*absl.*"); + initMatcher(); + expectAccepted({"envoy.matchers.requests", "stats.absl.2xx", "absl.envoy.matchers"}); + expectDenied({"Abseil", "EnvoyProxy"}); +} + +TEST_F(StatsMatcherTest, CheckMultipleExcludeRegex) { + exclusionList()->set_regex(".*envoy.*"); + exclusionList()->set_regex(".*absl.*"); + initMatcher(); + expectAccepted({"Abseil", "EnvoyProxy"}); + expectDenied({"envoy.matchers.requests", "stats.absl.2xx", "absl.envoy.matchers"}); +} + +// Multiple prefix/suffix/regex matchers. +// +// Matchers are "any_of", so strings matching any of the rules are expected to pass or fail, +// whichever the case may be. + +TEST_F(StatsMatcherTest, CheckMultipleAssortedInclusionMatchers) { + inclusionList()->set_regex(".*envoy.*"); + inclusionList()->set_suffix("requests"); + inclusionList()->set_exact("regex"); + initMatcher(); + expectAccepted({"envoy.matchers.requests", "requests.for.envoy", "envoyrequests", "regex"}); + expectDenied({"requestsEnvoy", "EnvoyProxy", "foo", "regex_etc"}); +} + +TEST_F(StatsMatcherTest, CheckMultipleAssortedExclusionMatchers) { + exclusionList()->set_regex(".*envoy.*"); + exclusionList()->set_suffix("requests"); + exclusionList()->set_exact("regex"); + initMatcher(); + expectAccepted({"requestsEnvoy", "EnvoyProxy", "foo", "regex_etc"}); + expectDenied({"envoy.matchers.requests", "requests.for.envoy", "envoyrequests", "regex"}); +} + +} // namespace Stats +} // namespace Envoy diff --git a/test/common/stats/thread_local_store_test.cc b/test/common/stats/thread_local_store_test.cc index e4e63fcb4e96b..286ce5f348c57 100644 --- a/test/common/stats/thread_local_store_test.cc +++ b/test/common/stats/thread_local_store_test.cc @@ -3,7 +3,10 @@ #include #include +#include "envoy/config/metrics/v2/stats.pb.h" + #include "common/common/c_smart_ptr.h" +#include "common/stats/stats_matcher_impl.h" #include "common/stats/thread_local_store.h" #include "test/mocks/event/mocks.h" @@ -184,10 +187,10 @@ TEST_F(StatsThreadLocalStoreTest, NoTls) { store_->deliverHistogramToSinks(h1, 100); EXPECT_EQ(2UL, store_->counters().size()); - EXPECT_EQ(&c1, store_->counters().front().get()); - EXPECT_EQ(2L, store_->counters().front().use_count()); + EXPECT_EQ(&c1, TestUtility::findCounter(*store_, "c1").get()); + EXPECT_EQ(2L, TestUtility::findCounter(*store_, "c1").use_count()); EXPECT_EQ(1UL, store_->gauges().size()); - EXPECT_EQ(&g1, store_->gauges().front().get()); + EXPECT_EQ(&g1, store_->gauges().front().get()); // front() ok when size()==1 EXPECT_EQ(2L, store_->gauges().front().use_count()); // Includes overflow stat. @@ -212,20 +215,20 @@ TEST_F(StatsThreadLocalStoreTest, Tls) { EXPECT_EQ(&h1, &store_->histogram("h1")); EXPECT_EQ(2UL, store_->counters().size()); - EXPECT_EQ(&c1, store_->counters().front().get()); - EXPECT_EQ(3L, store_->counters().front().use_count()); + EXPECT_EQ(&c1, TestUtility::findCounter(*store_, "c1").get()); + EXPECT_EQ(3L, TestUtility::findCounter(*store_, "c1").use_count()); EXPECT_EQ(1UL, store_->gauges().size()); - EXPECT_EQ(&g1, store_->gauges().front().get()); + EXPECT_EQ(&g1, store_->gauges().front().get()); // front() ok when size()==1 EXPECT_EQ(3L, store_->gauges().front().use_count()); store_->shutdownThreading(); tls_.shutdownThread(); EXPECT_EQ(2UL, store_->counters().size()); - EXPECT_EQ(&c1, store_->counters().front().get()); - EXPECT_EQ(2L, store_->counters().front().use_count()); + EXPECT_EQ(&c1, TestUtility::findCounter(*store_, "c1").get()); + EXPECT_EQ(2L, TestUtility::findCounter(*store_, "c1").use_count()); EXPECT_EQ(1UL, store_->gauges().size()); - EXPECT_EQ(&g1, store_->gauges().front().get()); + EXPECT_EQ(&g1, store_->gauges().front().get()); // front() ok when size()==1 EXPECT_EQ(2L, store_->gauges().front().use_count()); // Includes overflow stat. @@ -291,9 +294,9 @@ TEST_F(StatsThreadLocalStoreTest, ScopeDelete) { EXPECT_CALL(*alloc_, alloc(_)); scope1->counter("c1"); EXPECT_EQ(2UL, store_->counters().size()); - CounterSharedPtr c1 = store_->counters().front(); + CounterSharedPtr c1 = TestUtility::findCounter(*store_, "scope1.c1"); EXPECT_EQ("scope1.c1", c1->name()); - EXPECT_EQ(store_->source().cachedCounters().front(), c1); + EXPECT_EQ(TestUtility::findByName(store_->source().cachedCounters(), "scope1.c1"), c1); EXPECT_CALL(main_thread_dispatcher_, post(_)); EXPECT_CALL(tls_, runOnAllThreads(_)); @@ -460,6 +463,154 @@ TEST_F(StatsThreadLocalStoreTest, HotRestartTruncation) { EXPECT_CALL(*alloc_, free(_)).Times(2); } +class StatsMatcherTLSTest : public StatsThreadLocalStoreTest { +public: + StatsMatcherTLSTest() : StatsThreadLocalStoreTest() {} + envoy::config::metrics::v2::StatsConfig stats_config_; +}; + +TEST_F(StatsMatcherTLSTest, TestNoOpStatImpls) { + InSequence s; + + EXPECT_CALL(*alloc_, alloc(_)).Times(0); + + stats_config_.mutable_stats_matcher()->mutable_exclusion_list()->add_patterns()->set_prefix( + "noop"); + store_->setStatsMatcher(std::make_unique(stats_config_)); + + // Testing No-op counters, gauges, histograms which match the prefix "noop". + + // Counter + Counter& noop_counter = store_->counter("noop_counter"); + EXPECT_EQ(noop_counter.name(), ""); + EXPECT_EQ(noop_counter.value(), 0); + noop_counter.add(1); + EXPECT_EQ(noop_counter.value(), 0); + noop_counter.inc(); + EXPECT_EQ(noop_counter.value(), 0); + noop_counter.reset(); + EXPECT_EQ(noop_counter.value(), 0); + Counter& noop_counter_2 = store_->counter("noop_counter_2"); + EXPECT_EQ(&noop_counter, &noop_counter_2); + + // Gauge + Gauge& noop_gauge = store_->gauge("noop_gauge"); + EXPECT_EQ(noop_gauge.name(), ""); + EXPECT_EQ(noop_gauge.value(), 0); + noop_gauge.add(1); + EXPECT_EQ(noop_gauge.value(), 0); + noop_gauge.inc(); + EXPECT_EQ(noop_gauge.value(), 0); + noop_gauge.dec(); + EXPECT_EQ(noop_gauge.value(), 0); + noop_gauge.set(2); + EXPECT_EQ(noop_gauge.value(), 0); + noop_gauge.sub(2); + EXPECT_EQ(noop_gauge.value(), 0); + Gauge& noop_gauge_2 = store_->gauge("noop_gauge_2"); + EXPECT_EQ(&noop_gauge, &noop_gauge_2); + + // Histogram + Histogram& noop_histogram = store_->histogram("noop_histogram"); + EXPECT_EQ(noop_histogram.name(), ""); + Histogram& noop_histogram_2 = store_->histogram("noop_histogram_2"); + EXPECT_EQ(&noop_histogram, &noop_histogram_2); + + // Includes overflow stat. + EXPECT_CALL(*alloc_, free(_)).Times(1); + + store_->shutdownThreading(); +} + +// We only test the exclusion list -- the inclusion list is the inverse, and both are tested in +// test/common/stats:stats_matcher_test. +TEST_F(StatsMatcherTLSTest, TestExclusionRegex) { + InSequence s; + + // Expected to alloc lowercase_counter, lowercase_gauge, valid_counter, valid_gauge + EXPECT_CALL(*alloc_, alloc(_)).Times(4); + + // Will block all stats containing any capital alphanumeric letter. + stats_config_.mutable_stats_matcher()->mutable_exclusion_list()->add_patterns()->set_regex( + ".*[A-Z].*"); + store_->setStatsMatcher(std::make_unique(stats_config_)); + + // The creation of counters/gauges/histograms which have no uppercase letters should succeed. + Counter& lowercase_counter = store_->counter("lowercase_counter"); + EXPECT_EQ(lowercase_counter.name(), "lowercase_counter"); + Gauge& lowercase_gauge = store_->gauge("lowercase_gauge"); + EXPECT_EQ(lowercase_gauge.name(), "lowercase_gauge"); + Histogram& lowercase_histogram = store_->histogram("lowercase_histogram"); + EXPECT_EQ(lowercase_histogram.name(), "lowercase_histogram"); + + // And the creation of counters/gauges/histograms which have uppercase letters should fail. + Counter& uppercase_counter = store_->counter("UPPERCASE_counter"); + EXPECT_EQ(uppercase_counter.name(), ""); + uppercase_counter.inc(); + EXPECT_EQ(uppercase_counter.value(), 0); + uppercase_counter.inc(); + EXPECT_EQ(uppercase_counter.value(), 0); + + Gauge& uppercase_gauge = store_->gauge("uppercase_GAUGE"); + EXPECT_EQ(uppercase_gauge.name(), ""); + uppercase_gauge.inc(); + EXPECT_EQ(uppercase_gauge.value(), 0); + uppercase_gauge.inc(); + EXPECT_EQ(uppercase_gauge.value(), 0); + + // Histograms are harder to query and test, so we resort to testing that name() returns the empty + // string. + Histogram& uppercase_histogram = store_->histogram("upperCASE_histogram"); + EXPECT_EQ(uppercase_histogram.name(), ""); + + // Adding another exclusion rule -- now we reject not just uppercase stats but those starting with + // the string "invalid". + stats_config_.mutable_stats_matcher()->mutable_exclusion_list()->add_patterns()->set_prefix( + "invalid"); + store_->setStatsMatcher(std::make_unique(stats_config_)); + + Counter& valid_counter = store_->counter("valid_counter"); + valid_counter.inc(); + EXPECT_EQ(valid_counter.value(), 1); + + Counter& invalid_counter = store_->counter("invalid_counter"); + invalid_counter.inc(); + EXPECT_EQ(invalid_counter.value(), 0); + + // But the old exclusion rule still holds. + Counter& invalid_counter_2 = store_->counter("also_INVALID_counter"); + invalid_counter_2.inc(); + EXPECT_EQ(invalid_counter_2.value(), 0); + + // And we expect the same behavior from gauges and histograms. + Gauge& valid_gauge = store_->gauge("valid_gauge"); + valid_gauge.set(2); + EXPECT_EQ(valid_gauge.value(), 2); + + Gauge& invalid_gauge_1 = store_->gauge("invalid_gauge"); + invalid_gauge_1.inc(); + EXPECT_EQ(invalid_gauge_1.value(), 0); + + Gauge& invalid_gauge_2 = store_->gauge("also_INVALID_gauge"); + invalid_gauge_2.inc(); + EXPECT_EQ(invalid_gauge_2.value(), 0); + + Histogram& valid_histogram = store_->histogram("valid_histogram"); + EXPECT_EQ(valid_histogram.name(), "valid_histogram"); + + Histogram& invalid_histogram_1 = store_->histogram("invalid_histogram"); + EXPECT_EQ(invalid_histogram_1.name(), ""); + + Histogram& invalid_histogram_2 = store_->histogram("also_INVALID_histogram"); + EXPECT_EQ(invalid_histogram_2.name(), ""); + + // Expected to free lowercase_counter, lowercase_gauge, valid_counter, + // valid_gauge, overflow.stats + EXPECT_CALL(*alloc_, free(_)).Times(5); + + store_->shutdownThreading(); +} + class HeapStatsThreadLocalStoreTest : public StatsThreadLocalStoreTest { public: void SetUp() override { diff --git a/test/common/request_info/BUILD b/test/common/stream_info/BUILD similarity index 69% rename from test/common/request_info/BUILD rename to test/common/stream_info/BUILD index 3d259b5ae860f..e1d39a9bfe893 100644 --- a/test/common/request_info/BUILD +++ b/test/common/stream_info/BUILD @@ -13,19 +13,19 @@ envoy_cc_test( name = "filter_state_impl_test", srcs = ["filter_state_impl_test.cc"], deps = [ - "//source/common/request_info:filter_state_lib", + "//source/common/stream_info:filter_state_lib", "//test/test_common:utility_lib", ], ) envoy_cc_test( - name = "request_info_impl_test", - srcs = ["request_info_impl_test.cc"], + name = "stream_info_impl_test", + srcs = ["stream_info_impl_test.cc"], deps = [ ":test_int_accessor_lib", "//include/envoy/http:protocol_interface", "//include/envoy/upstream:host_description_interface", - "//source/common/request_info:request_info_lib", + "//source/common/stream_info:stream_info_lib", "//test/mocks/router:router_mocks", "//test/mocks/upstream:upstream_mocks", ], @@ -35,7 +35,7 @@ envoy_cc_test_library( name = "test_int_accessor_lib", hdrs = ["test_int_accessor.h"], deps = [ - "//include/envoy/request_info:filter_state_interface", + "//include/envoy/stream_info:filter_state_interface", ], ) @@ -43,7 +43,7 @@ envoy_cc_test( name = "utility_test", srcs = ["utility_test.cc"], deps = [ - "//source/common/request_info:utility_lib", - "//test/mocks/request_info:request_info_mocks", + "//source/common/stream_info:utility_lib", + "//test/mocks/stream_info:stream_info_mocks", ], ) diff --git a/test/common/request_info/filter_state_impl_test.cc b/test/common/stream_info/filter_state_impl_test.cc similarity index 98% rename from test/common/request_info/filter_state_impl_test.cc rename to test/common/stream_info/filter_state_impl_test.cc index 631074d05156c..ef34a9ee3be94 100644 --- a/test/common/request_info/filter_state_impl_test.cc +++ b/test/common/stream_info/filter_state_impl_test.cc @@ -1,13 +1,13 @@ #include "envoy/common/exception.h" -#include "common/request_info/filter_state_impl.h" +#include "common/stream_info/filter_state_impl.h" #include "test/test_common/utility.h" #include "gtest/gtest.h" namespace Envoy { -namespace RequestInfo { +namespace StreamInfo { namespace { class TestStoredTypeTracking : public FilterState::Object { @@ -166,5 +166,5 @@ TEST_F(FilterStateImplTest, HasData) { EXPECT_FALSE(filter_state().hasDataWithName("test_2")); } -} // namespace RequestInfo +} // namespace StreamInfo } // namespace Envoy diff --git a/test/common/request_info/request_info_impl_test.cc b/test/common/stream_info/stream_info_impl_test.cc similarity index 56% rename from test/common/request_info/request_info_impl_test.cc rename to test/common/stream_info/stream_info_impl_test.cc index 28476cb49d822..dccd9b6234dfa 100644 --- a/test/common/request_info/request_info_impl_test.cc +++ b/test/common/stream_info/stream_info_impl_test.cc @@ -2,14 +2,14 @@ #include #include "envoy/http/protocol.h" -#include "envoy/request_info/filter_state.h" +#include "envoy/stream_info/filter_state.h" #include "envoy/upstream/host_description.h" #include "common/common/fmt.h" #include "common/protobuf/utility.h" -#include "common/request_info/request_info_impl.h" +#include "common/stream_info/stream_info_impl.h" -#include "test/common/request_info/test_int_accessor.h" +#include "test/common/stream_info/test_int_accessor.h" #include "test/mocks/router/mocks.h" #include "test/mocks/upstream/mocks.h" @@ -17,7 +17,7 @@ #include "gtest/gtest.h" namespace Envoy { -namespace RequestInfo { +namespace StreamInfo { namespace { std::chrono::nanoseconds checkDuration(std::chrono::nanoseconds last, @@ -27,14 +27,14 @@ std::chrono::nanoseconds checkDuration(std::chrono::nanoseconds last, return timing.value(); } -class RequestInfoImplTest : public testing::Test { +class StreamInfoImplTest : public testing::Test { protected: DangerousDeprecatedTestTime test_time_; }; -TEST_F(RequestInfoImplTest, TimingTest) { +TEST_F(StreamInfoImplTest, TimingTest) { MonotonicTime pre_start = test_time_.timeSystem().monotonicTime(); - RequestInfoImpl info(Http::Protocol::Http2, test_time_.timeSystem()); + StreamInfoImpl info(Http::Protocol::Http2, test_time_.timeSystem()); MonotonicTime post_start = test_time_.timeSystem().monotonicTime(); const MonotonicTime& start = info.startTimeMonotonic(); @@ -76,20 +76,20 @@ TEST_F(RequestInfoImplTest, TimingTest) { dur = checkDuration(dur, info.requestComplete()); } -TEST_F(RequestInfoImplTest, BytesTest) { - RequestInfoImpl request_info(Http::Protocol::Http2, test_time_.timeSystem()); +TEST_F(StreamInfoImplTest, BytesTest) { + StreamInfoImpl stream_info(Http::Protocol::Http2, test_time_.timeSystem()); const uint64_t bytes_sent = 7; const uint64_t bytes_received = 12; - request_info.addBytesSent(bytes_sent); - request_info.addBytesReceived(bytes_received); + stream_info.addBytesSent(bytes_sent); + stream_info.addBytesReceived(bytes_received); - EXPECT_EQ(bytes_sent, request_info.bytesSent()); - EXPECT_EQ(bytes_received, request_info.bytesReceived()); + EXPECT_EQ(bytes_sent, stream_info.bytesSent()); + EXPECT_EQ(bytes_received, stream_info.bytesReceived()); } -TEST_F(RequestInfoImplTest, ResponseFlagTest) { +TEST_F(StreamInfoImplTest, ResponseFlagTest) { const std::vector responseFlags = {FailedLocalHealthCheck, NoHealthyUpstream, UpstreamRequestTimeout, @@ -103,87 +103,86 @@ TEST_F(RequestInfoImplTest, ResponseFlagTest) { FaultInjected, RateLimited}; - RequestInfoImpl request_info(Http::Protocol::Http2, test_time_.timeSystem()); + StreamInfoImpl stream_info(Http::Protocol::Http2, test_time_.timeSystem()); - EXPECT_FALSE(request_info.hasAnyResponseFlag()); - EXPECT_FALSE(request_info.intersectResponseFlags(0)); + EXPECT_FALSE(stream_info.hasAnyResponseFlag()); + EXPECT_FALSE(stream_info.intersectResponseFlags(0)); for (ResponseFlag flag : responseFlags) { // Test cumulative setting of response flags. - EXPECT_FALSE(request_info.hasResponseFlag(flag)) + EXPECT_FALSE(stream_info.hasResponseFlag(flag)) << fmt::format("Flag: {} was already set", flag); - request_info.setResponseFlag(flag); - EXPECT_TRUE(request_info.hasResponseFlag(flag)) + stream_info.setResponseFlag(flag); + EXPECT_TRUE(stream_info.hasResponseFlag(flag)) << fmt::format("Flag: {} was expected to be set", flag); } - EXPECT_TRUE(request_info.hasAnyResponseFlag()); + EXPECT_TRUE(stream_info.hasAnyResponseFlag()); - RequestInfoImpl request_info2(Http::Protocol::Http2, test_time_.timeSystem()); - request_info2.setResponseFlag(FailedLocalHealthCheck); + StreamInfoImpl stream_info2(Http::Protocol::Http2, test_time_.timeSystem()); + stream_info2.setResponseFlag(FailedLocalHealthCheck); - EXPECT_TRUE(request_info2.intersectResponseFlags(FailedLocalHealthCheck)); + EXPECT_TRUE(stream_info2.intersectResponseFlags(FailedLocalHealthCheck)); } -TEST_F(RequestInfoImplTest, MiscSettersAndGetters) { +TEST_F(StreamInfoImplTest, MiscSettersAndGetters) { { - RequestInfoImpl request_info(Http::Protocol::Http2, test_time_.timeSystem()); + StreamInfoImpl stream_info(Http::Protocol::Http2, test_time_.timeSystem()); - EXPECT_EQ(Http::Protocol::Http2, request_info.protocol().value()); + EXPECT_EQ(Http::Protocol::Http2, stream_info.protocol().value()); - request_info.protocol(Http::Protocol::Http10); - EXPECT_EQ(Http::Protocol::Http10, request_info.protocol().value()); + stream_info.protocol(Http::Protocol::Http10); + EXPECT_EQ(Http::Protocol::Http10, stream_info.protocol().value()); - EXPECT_FALSE(request_info.responseCode()); - request_info.response_code_ = 200; - ASSERT_TRUE(request_info.responseCode()); - EXPECT_EQ(200, request_info.responseCode().value()); + EXPECT_FALSE(stream_info.responseCode()); + stream_info.response_code_ = 200; + ASSERT_TRUE(stream_info.responseCode()); + EXPECT_EQ(200, stream_info.responseCode().value()); - EXPECT_EQ(nullptr, request_info.upstreamHost()); + EXPECT_EQ(nullptr, stream_info.upstreamHost()); Upstream::HostDescriptionConstSharedPtr host(new NiceMock()); - request_info.onUpstreamHostSelected(host); - EXPECT_EQ(host, request_info.upstreamHost()); + stream_info.onUpstreamHostSelected(host); + EXPECT_EQ(host, stream_info.upstreamHost()); - EXPECT_FALSE(request_info.healthCheck()); - request_info.healthCheck(true); - EXPECT_TRUE(request_info.healthCheck()); + EXPECT_FALSE(stream_info.healthCheck()); + stream_info.healthCheck(true); + EXPECT_TRUE(stream_info.healthCheck()); - EXPECT_EQ(nullptr, request_info.routeEntry()); + EXPECT_EQ(nullptr, stream_info.routeEntry()); NiceMock route_entry; - request_info.route_entry_ = &route_entry; - EXPECT_EQ(&route_entry, request_info.routeEntry()); + stream_info.route_entry_ = &route_entry; + EXPECT_EQ(&route_entry, stream_info.routeEntry()); - request_info.perRequestState().setData("test", std::make_unique(1)); - EXPECT_EQ(1, request_info.perRequestState().getData("test").access()); + stream_info.perRequestState().setData("test", std::make_unique(1)); + EXPECT_EQ(1, stream_info.perRequestState().getData("test").access()); - EXPECT_EQ("", request_info.requestedServerName()); + EXPECT_EQ("", stream_info.requestedServerName()); absl::string_view sni_name = "stubserver.org"; - request_info.setRequestedServerName(sni_name); - EXPECT_EQ(std::string(sni_name), request_info.requestedServerName()); + stream_info.setRequestedServerName(sni_name); + EXPECT_EQ(std::string(sni_name), stream_info.requestedServerName()); } } -TEST_F(RequestInfoImplTest, DynamicMetadataTest) { - RequestInfoImpl request_info(Http::Protocol::Http2, test_time_.timeSystem()); +TEST_F(StreamInfoImplTest, DynamicMetadataTest) { + StreamInfoImpl stream_info(Http::Protocol::Http2, test_time_.timeSystem()); - EXPECT_EQ(0, request_info.dynamicMetadata().filter_metadata_size()); - request_info.setDynamicMetadata("com.test", - MessageUtil::keyValueStruct("test_key", "test_value")); + EXPECT_EQ(0, stream_info.dynamicMetadata().filter_metadata_size()); + stream_info.setDynamicMetadata("com.test", MessageUtil::keyValueStruct("test_key", "test_value")); EXPECT_EQ("test_value", - Config::Metadata::metadataValue(request_info.dynamicMetadata(), "com.test", "test_key") + Config::Metadata::metadataValue(stream_info.dynamicMetadata(), "com.test", "test_key") .string_value()); ProtobufWkt::Struct struct_obj2; ProtobufWkt::Value val2; val2.set_string_value("another_value"); (*struct_obj2.mutable_fields())["another_key"] = val2; - request_info.setDynamicMetadata("com.test", struct_obj2); - EXPECT_EQ("another_value", Config::Metadata::metadataValue(request_info.dynamicMetadata(), + stream_info.setDynamicMetadata("com.test", struct_obj2); + EXPECT_EQ("another_value", Config::Metadata::metadataValue(stream_info.dynamicMetadata(), "com.test", "another_key") .string_value()); // make sure "test_key:test_value" still exists EXPECT_EQ("test_value", - Config::Metadata::metadataValue(request_info.dynamicMetadata(), "com.test", "test_key") + Config::Metadata::metadataValue(stream_info.dynamicMetadata(), "com.test", "test_key") .string_value()); ProtobufTypes::String json; - const auto test_struct = request_info.dynamicMetadata().filter_metadata().at("com.test"); + const auto test_struct = stream_info.dynamicMetadata().filter_metadata().at("com.test"); const auto status = Protobuf::util::MessageToJsonString(test_struct, &json); EXPECT_TRUE(status.ok()); // check json contains the key and values we set @@ -192,5 +191,5 @@ TEST_F(RequestInfoImplTest, DynamicMetadataTest) { } } // namespace -} // namespace RequestInfo +} // namespace StreamInfo } // namespace Envoy diff --git a/test/common/request_info/test_int_accessor.h b/test/common/stream_info/test_int_accessor.h similarity index 70% rename from test/common/request_info/test_int_accessor.h rename to test/common/stream_info/test_int_accessor.h index c7d302e4a17e4..da7d381e94d85 100644 --- a/test/common/request_info/test_int_accessor.h +++ b/test/common/stream_info/test_int_accessor.h @@ -1,9 +1,9 @@ #pragma once -#include "envoy/request_info/filter_state.h" +#include "envoy/stream_info/filter_state.h" namespace Envoy { -namespace RequestInfo { +namespace StreamInfo { class TestIntAccessor : public FilterState::Object { public: @@ -15,5 +15,5 @@ class TestIntAccessor : public FilterState::Object { int value_; }; -} // namespace RequestInfo +} // namespace StreamInfo } // namespace Envoy diff --git a/test/common/request_info/utility_test.cc b/test/common/stream_info/utility_test.cc similarity index 79% rename from test/common/request_info/utility_test.cc rename to test/common/stream_info/utility_test.cc index cecf3dd4aefee..b120aa2f9a997 100644 --- a/test/common/request_info/utility_test.cc +++ b/test/common/stream_info/utility_test.cc @@ -1,7 +1,7 @@ #include "common/network/address_impl.h" -#include "common/request_info/utility.h" +#include "common/stream_info/utility.h" -#include "test/mocks/request_info/mocks.h" +#include "test/mocks/stream_info/mocks.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -11,7 +11,7 @@ using testing::NiceMock; using testing::Return; namespace Envoy { -namespace RequestInfo { +namespace StreamInfo { TEST(ResponseFlagUtilsTest, toShortStringConversion) { static_assert(ResponseFlag::LastFlag == 0x2000, "A flag has been added. Fix this code."); @@ -34,27 +34,27 @@ TEST(ResponseFlagUtilsTest, toShortStringConversion) { }; for (const auto& test_case : expected) { - NiceMock request_info; - ON_CALL(request_info, hasResponseFlag(test_case.first)).WillByDefault(Return(true)); - EXPECT_EQ(test_case.second, ResponseFlagUtils::toShortString(request_info)); + NiceMock stream_info; + ON_CALL(stream_info, hasResponseFlag(test_case.first)).WillByDefault(Return(true)); + EXPECT_EQ(test_case.second, ResponseFlagUtils::toShortString(stream_info)); } // No flag is set. { - NiceMock request_info; - ON_CALL(request_info, hasResponseFlag(_)).WillByDefault(Return(false)); - EXPECT_EQ("-", ResponseFlagUtils::toShortString(request_info)); + NiceMock stream_info; + ON_CALL(stream_info, hasResponseFlag(_)).WillByDefault(Return(false)); + EXPECT_EQ("-", ResponseFlagUtils::toShortString(stream_info)); } // Test combinations. // These are not real use cases, but are used to cover multiple response flags case. { - NiceMock request_info; - ON_CALL(request_info, hasResponseFlag(ResponseFlag::DelayInjected)).WillByDefault(Return(true)); - ON_CALL(request_info, hasResponseFlag(ResponseFlag::FaultInjected)).WillByDefault(Return(true)); - ON_CALL(request_info, hasResponseFlag(ResponseFlag::UpstreamRequestTimeout)) + NiceMock stream_info; + ON_CALL(stream_info, hasResponseFlag(ResponseFlag::DelayInjected)).WillByDefault(Return(true)); + ON_CALL(stream_info, hasResponseFlag(ResponseFlag::FaultInjected)).WillByDefault(Return(true)); + ON_CALL(stream_info, hasResponseFlag(ResponseFlag::UpstreamRequestTimeout)) .WillByDefault(Return(true)); - EXPECT_EQ("UT,DI,FI", ResponseFlagUtils::toShortString(request_info)); + EXPECT_EQ("UT,DI,FI", ResponseFlagUtils::toShortString(stream_info)); } } @@ -94,5 +94,5 @@ TEST(UtilityTest, formatDownstreamAddressNoPort) { Utility::formatDownstreamAddressNoPort(Network::Address::PipeInstance("/hello"))); } -} // namespace RequestInfo +} // namespace StreamInfo } // namespace Envoy diff --git a/test/common/tcp_proxy/tcp_proxy_test.cc b/test/common/tcp_proxy/tcp_proxy_test.cc index 48451429e3b02..bff4b1aad858b 100644 --- a/test/common/tcp_proxy/tcp_proxy_test.cc +++ b/test/common/tcp_proxy/tcp_proxy_test.cc @@ -1146,7 +1146,7 @@ TEST_F(TcpProxyRoutingTest, RoutableConnection) { TEST_F(TcpProxyRoutingTest, UseClusterFromPerConnectionCluster) { setup(); - RequestInfo::FilterStateImpl per_connection_state; + StreamInfo::FilterStateImpl per_connection_state; per_connection_state.setData("envoy.tcp_proxy.cluster", std::make_unique("filter_state_cluster")); ON_CALL(connection_, perConnectionState()).WillByDefault(ReturnRef(per_connection_state)); diff --git a/test/common/tracing/http_tracer_impl_test.cc b/test/common/tracing/http_tracer_impl_test.cc index 0dd318316b69f..1dcec1293a1a7 100644 --- a/test/common/tracing/http_tracer_impl_test.cc +++ b/test/common/tracing/http_tracer_impl_test.cc @@ -35,7 +35,7 @@ namespace Envoy { namespace Tracing { TEST(HttpTracerUtilityTest, IsTracing) { - NiceMock request_info; + NiceMock stream_info; NiceMock stats; Runtime::RandomGeneratorImpl random; std::string not_traceable_guid = random.uuid(); @@ -57,18 +57,18 @@ TEST(HttpTracerUtilityTest, IsTracing) { // Force traced. { - EXPECT_CALL(request_info, healthCheck()).WillOnce(Return(false)); + EXPECT_CALL(stream_info, healthCheck()).WillOnce(Return(false)); - Decision result = HttpTracerUtility::isTracing(request_info, forced_header); + Decision result = HttpTracerUtility::isTracing(stream_info, forced_header); EXPECT_EQ(Reason::ServiceForced, result.reason); EXPECT_TRUE(result.traced); } // Sample traced. { - EXPECT_CALL(request_info, healthCheck()).WillOnce(Return(false)); + EXPECT_CALL(stream_info, healthCheck()).WillOnce(Return(false)); - Decision result = HttpTracerUtility::isTracing(request_info, sampled_header); + Decision result = HttpTracerUtility::isTracing(stream_info, sampled_header); EXPECT_EQ(Reason::Sampling, result.reason); EXPECT_TRUE(result.traced); } @@ -76,18 +76,18 @@ TEST(HttpTracerUtilityTest, IsTracing) { // HC request. { Http::TestHeaderMapImpl traceable_header_hc{{"x-request-id", forced_guid}}; - EXPECT_CALL(request_info, healthCheck()).WillOnce(Return(true)); + EXPECT_CALL(stream_info, healthCheck()).WillOnce(Return(true)); - Decision result = HttpTracerUtility::isTracing(request_info, traceable_header_hc); + Decision result = HttpTracerUtility::isTracing(stream_info, traceable_header_hc); EXPECT_EQ(Reason::HealthCheck, result.reason); EXPECT_FALSE(result.traced); } // Client traced. { - EXPECT_CALL(request_info, healthCheck()).WillOnce(Return(false)); + EXPECT_CALL(stream_info, healthCheck()).WillOnce(Return(false)); - Decision result = HttpTracerUtility::isTracing(request_info, client_header); + Decision result = HttpTracerUtility::isTracing(stream_info, client_header); EXPECT_EQ(Reason::ClientForced, result.reason); EXPECT_TRUE(result.traced); } @@ -95,8 +95,8 @@ TEST(HttpTracerUtilityTest, IsTracing) { // No request id. { Http::TestHeaderMapImpl headers; - EXPECT_CALL(request_info, healthCheck()).WillOnce(Return(false)); - Decision result = HttpTracerUtility::isTracing(request_info, headers); + EXPECT_CALL(stream_info, healthCheck()).WillOnce(Return(false)); + Decision result = HttpTracerUtility::isTracing(stream_info, headers); EXPECT_EQ(Reason::NotTraceableRequestId, result.reason); EXPECT_FALSE(result.traced); } @@ -104,8 +104,8 @@ TEST(HttpTracerUtilityTest, IsTracing) { // Broken request id. { Http::TestHeaderMapImpl headers{{"x-request-id", "not-real-x-request-id"}}; - EXPECT_CALL(request_info, healthCheck()).WillOnce(Return(false)); - Decision result = HttpTracerUtility::isTracing(request_info, headers); + EXPECT_CALL(stream_info, healthCheck()).WillOnce(Return(false)); + Decision result = HttpTracerUtility::isTracing(stream_info, headers); EXPECT_EQ(Reason::NotTraceableRequestId, result.reason); EXPECT_FALSE(result.traced); } @@ -121,14 +121,14 @@ TEST(HttpConnManFinalizerImpl, OriginalAndLongPath) { {"x-envoy-original-path", path}, {":method", "GET"}, {"x-forwarded-proto", "http"}}; - NiceMock request_info; + NiceMock stream_info; absl::optional protocol = Http::Protocol::Http2; - EXPECT_CALL(request_info, bytesReceived()).WillOnce(Return(10)); - EXPECT_CALL(request_info, bytesSent()).WillOnce(Return(11)); - EXPECT_CALL(request_info, protocol()).WillOnce(ReturnPointee(&protocol)); + EXPECT_CALL(stream_info, bytesReceived()).WillOnce(Return(10)); + EXPECT_CALL(stream_info, bytesSent()).WillOnce(Return(11)); + EXPECT_CALL(stream_info, protocol()).WillOnce(ReturnPointee(&protocol)); absl::optional response_code; - EXPECT_CALL(request_info, responseCode()).WillRepeatedly(ReturnPointee(&response_code)); + EXPECT_CALL(stream_info, responseCode()).WillRepeatedly(ReturnPointee(&response_code)); EXPECT_CALL(*span, setTag(_, _)).Times(testing::AnyNumber()); EXPECT_CALL(*span, setTag(Tracing::Tags::get().HTTP_URL, path_prefix + expected_path)); @@ -136,18 +136,18 @@ TEST(HttpConnManFinalizerImpl, OriginalAndLongPath) { EXPECT_CALL(*span, setTag(Tracing::Tags::get().HTTP_PROTOCOL, "HTTP/2")); NiceMock config; - HttpTracerUtility::finalizeSpan(*span, &request_headers, request_info, config); + HttpTracerUtility::finalizeSpan(*span, &request_headers, stream_info, config); } TEST(HttpConnManFinalizerImpl, NullRequestHeaders) { std::unique_ptr> span(new NiceMock()); - NiceMock request_info; + NiceMock stream_info; - EXPECT_CALL(request_info, bytesReceived()).WillOnce(Return(10)); - EXPECT_CALL(request_info, bytesSent()).WillOnce(Return(11)); + EXPECT_CALL(stream_info, bytesReceived()).WillOnce(Return(10)); + EXPECT_CALL(stream_info, bytesSent()).WillOnce(Return(11)); absl::optional response_code; - EXPECT_CALL(request_info, responseCode()).WillRepeatedly(ReturnPointee(&response_code)); - EXPECT_CALL(request_info, upstreamHost()).WillOnce(Return(nullptr)); + EXPECT_CALL(stream_info, responseCode()).WillRepeatedly(ReturnPointee(&response_code)); + EXPECT_CALL(stream_info, upstreamHost()).WillOnce(Return(nullptr)); EXPECT_CALL(*span, setTag(Tracing::Tags::get().HTTP_STATUS_CODE, "0")); EXPECT_CALL(*span, setTag(Tracing::Tags::get().ERROR, Tracing::Tags::get().TRUE)); @@ -157,19 +157,19 @@ TEST(HttpConnManFinalizerImpl, NullRequestHeaders) { EXPECT_CALL(*span, setTag(Tracing::Tags::get().UPSTREAM_CLUSTER, _)).Times(0); NiceMock config; - HttpTracerUtility::finalizeSpan(*span, nullptr, request_info, config); + HttpTracerUtility::finalizeSpan(*span, nullptr, stream_info, config); } TEST(HttpConnManFinalizerImpl, UpstreamClusterTagSet) { std::unique_ptr> span(new NiceMock()); - NiceMock request_info; - request_info.host_->cluster_.name_ = "my_upstream_cluster"; + NiceMock stream_info; + stream_info.host_->cluster_.name_ = "my_upstream_cluster"; - EXPECT_CALL(request_info, bytesReceived()).WillOnce(Return(10)); - EXPECT_CALL(request_info, bytesSent()).WillOnce(Return(11)); + EXPECT_CALL(stream_info, bytesReceived()).WillOnce(Return(10)); + EXPECT_CALL(stream_info, bytesSent()).WillOnce(Return(11)); absl::optional response_code; - EXPECT_CALL(request_info, responseCode()).WillRepeatedly(ReturnPointee(&response_code)); - EXPECT_CALL(request_info, upstreamHost()).Times(2); + EXPECT_CALL(stream_info, responseCode()).WillRepeatedly(ReturnPointee(&response_code)); + EXPECT_CALL(stream_info, upstreamHost()).Times(2); EXPECT_CALL(*span, setTag(Tracing::Tags::get().UPSTREAM_CLUSTER, "my_upstream_cluster")); EXPECT_CALL(*span, setTag(Tracing::Tags::get().HTTP_STATUS_CODE, "0")); @@ -179,7 +179,7 @@ TEST(HttpConnManFinalizerImpl, UpstreamClusterTagSet) { EXPECT_CALL(*span, setTag(Tracing::Tags::get().REQUEST_SIZE, "10")); NiceMock config; - HttpTracerUtility::finalizeSpan(*span, nullptr, request_info, config); + HttpTracerUtility::finalizeSpan(*span, nullptr, stream_info, config); } TEST(HttpConnManFinalizerImpl, SpanOptionalHeaders) { @@ -189,11 +189,11 @@ TEST(HttpConnManFinalizerImpl, SpanOptionalHeaders) { {":path", "/test"}, {":method", "GET"}, {"x-forwarded-proto", "https"}}; - NiceMock request_info; + NiceMock stream_info; absl::optional protocol = Http::Protocol::Http10; - EXPECT_CALL(request_info, bytesReceived()).WillOnce(Return(10)); - EXPECT_CALL(request_info, protocol()).WillOnce(ReturnPointee(&protocol)); + EXPECT_CALL(stream_info, bytesReceived()).WillOnce(Return(10)); + EXPECT_CALL(stream_info, protocol()).WillOnce(ReturnPointee(&protocol)); const std::string service_node = "i-453"; // Check that span is populated correctly. @@ -206,9 +206,9 @@ TEST(HttpConnManFinalizerImpl, SpanOptionalHeaders) { EXPECT_CALL(*span, setTag(Tracing::Tags::get().REQUEST_SIZE, "10")); absl::optional response_code; - EXPECT_CALL(request_info, responseCode()).WillRepeatedly(ReturnPointee(&response_code)); - EXPECT_CALL(request_info, bytesSent()).WillOnce(Return(100)); - EXPECT_CALL(request_info, upstreamHost()).WillOnce(Return(nullptr)); + EXPECT_CALL(stream_info, responseCode()).WillRepeatedly(ReturnPointee(&response_code)); + EXPECT_CALL(stream_info, bytesSent()).WillOnce(Return(100)); + EXPECT_CALL(stream_info, upstreamHost()).WillOnce(Return(nullptr)); EXPECT_CALL(*span, setTag(Tracing::Tags::get().HTTP_STATUS_CODE, "0")); EXPECT_CALL(*span, setTag(Tracing::Tags::get().ERROR, Tracing::Tags::get().TRUE)); @@ -217,7 +217,7 @@ TEST(HttpConnManFinalizerImpl, SpanOptionalHeaders) { EXPECT_CALL(*span, setTag(Tracing::Tags::get().UPSTREAM_CLUSTER, _)).Times(0); NiceMock config; - HttpTracerUtility::finalizeSpan(*span, &request_headers, request_info, config); + HttpTracerUtility::finalizeSpan(*span, &request_headers, stream_info, config); } TEST(HttpConnManFinalizerImpl, SpanPopulatedFailureResponse) { @@ -226,7 +226,7 @@ TEST(HttpConnManFinalizerImpl, SpanPopulatedFailureResponse) { {":path", "/test"}, {":method", "GET"}, {"x-forwarded-proto", "http"}}; - NiceMock request_info; + NiceMock stream_info; request_headers.insertHost().value(std::string("api")); request_headers.insertUserAgent().value(std::string("agent")); @@ -234,8 +234,8 @@ TEST(HttpConnManFinalizerImpl, SpanPopulatedFailureResponse) { request_headers.insertClientTraceId().value(std::string("client_trace_id")); absl::optional protocol = Http::Protocol::Http10; - EXPECT_CALL(request_info, protocol()).WillOnce(ReturnPointee(&protocol)); - EXPECT_CALL(request_info, bytesReceived()).WillOnce(Return(10)); + EXPECT_CALL(stream_info, protocol()).WillOnce(ReturnPointee(&protocol)); + EXPECT_CALL(stream_info, bytesReceived()).WillOnce(Return(10)); const std::string service_node = "i-453"; // Check that span is populated correctly. @@ -261,11 +261,11 @@ TEST(HttpConnManFinalizerImpl, SpanPopulatedFailureResponse) { EXPECT_CALL(config, requestHeadersForTags()); absl::optional response_code(503); - EXPECT_CALL(request_info, responseCode()).WillRepeatedly(ReturnPointee(&response_code)); - EXPECT_CALL(request_info, bytesSent()).WillOnce(Return(100)); - ON_CALL(request_info, hasResponseFlag(RequestInfo::ResponseFlag::UpstreamRequestTimeout)) + EXPECT_CALL(stream_info, responseCode()).WillRepeatedly(ReturnPointee(&response_code)); + EXPECT_CALL(stream_info, bytesSent()).WillOnce(Return(100)); + ON_CALL(stream_info, hasResponseFlag(StreamInfo::ResponseFlag::UpstreamRequestTimeout)) .WillByDefault(Return(true)); - EXPECT_CALL(request_info, upstreamHost()).WillOnce(Return(nullptr)); + EXPECT_CALL(stream_info, upstreamHost()).WillOnce(Return(nullptr)); EXPECT_CALL(*span, setTag(Tracing::Tags::get().ERROR, Tracing::Tags::get().TRUE)); EXPECT_CALL(*span, setTag(Tracing::Tags::get().HTTP_STATUS_CODE, "503")); @@ -273,7 +273,7 @@ TEST(HttpConnManFinalizerImpl, SpanPopulatedFailureResponse) { EXPECT_CALL(*span, setTag(Tracing::Tags::get().RESPONSE_FLAGS, "UT")); EXPECT_CALL(*span, setTag(Tracing::Tags::get().UPSTREAM_CLUSTER, _)).Times(0); - HttpTracerUtility::finalizeSpan(*span, &request_headers, request_info, config); + HttpTracerUtility::finalizeSpan(*span, &request_headers, stream_info, config); } TEST(HttpTracerUtilityTest, operationTypeToString) { @@ -284,11 +284,11 @@ TEST(HttpTracerUtilityTest, operationTypeToString) { TEST(HttpNullTracerTest, BasicFunctionality) { HttpNullTracer null_tracer; MockConfig config; - RequestInfo::MockRequestInfo request_info; + StreamInfo::MockStreamInfo stream_info; Http::TestHeaderMapImpl request_headers; SpanPtr span_ptr = - null_tracer.startSpan(config, request_headers, request_info, {Reason::Sampling, true}); + null_tracer.startSpan(config, request_headers, stream_info, {Reason::Sampling, true}); EXPECT_TRUE(dynamic_cast(span_ptr.get()) != nullptr); span_ptr->setOperation("foo"); @@ -308,7 +308,7 @@ class HttpTracerImplTest : public Test { Http::TestHeaderMapImpl request_headers_{ {":path", "/"}, {":method", "GET"}, {"x-request-id", "foo"}, {":authority", "test"}}; - RequestInfo::MockRequestInfo request_info_; + StreamInfo::MockStreamInfo stream_info_; NiceMock local_info_; MockConfig config_; MockDriver* driver_; @@ -317,26 +317,26 @@ class HttpTracerImplTest : public Test { TEST_F(HttpTracerImplTest, BasicFunctionalityNullSpan) { EXPECT_CALL(config_, operationName()).Times(2); - EXPECT_CALL(request_info_, startTime()); + EXPECT_CALL(stream_info_, startTime()); const std::string operation_name = "ingress"; - EXPECT_CALL(*driver_, startSpan_(_, _, operation_name, request_info_.start_time_, _)) + EXPECT_CALL(*driver_, startSpan_(_, _, operation_name, stream_info_.start_time_, _)) .WillOnce(Return(nullptr)); - tracer_->startSpan(config_, request_headers_, request_info_, {Reason::Sampling, true}); + tracer_->startSpan(config_, request_headers_, stream_info_, {Reason::Sampling, true}); } TEST_F(HttpTracerImplTest, BasicFunctionalityNodeSet) { - EXPECT_CALL(request_info_, startTime()); + EXPECT_CALL(stream_info_, startTime()); EXPECT_CALL(local_info_, nodeName()); EXPECT_CALL(config_, operationName()).Times(2).WillRepeatedly(Return(OperationName::Egress)); NiceMock* span = new NiceMock(); const std::string operation_name = "egress test"; - EXPECT_CALL(*driver_, startSpan_(_, _, operation_name, request_info_.start_time_, _)) + EXPECT_CALL(*driver_, startSpan_(_, _, operation_name, stream_info_.start_time_, _)) .WillOnce(Return(span)); EXPECT_CALL(*span, setTag(_, _)).Times(testing::AnyNumber()); EXPECT_CALL(*span, setTag(Tracing::Tags::get().NODE_ID, "node_name")); - tracer_->startSpan(config_, request_headers_, request_info_, {Reason::Sampling, true}); + tracer_->startSpan(config_, request_headers_, stream_info_, {Reason::Sampling, true}); } } // namespace Tracing diff --git a/test/common/upstream/BUILD b/test/common/upstream/BUILD index a308e0881b0ba..789582d242f6f 100644 --- a/test/common/upstream/BUILD +++ b/test/common/upstream/BUILD @@ -158,6 +158,7 @@ envoy_cc_test( "//test/mocks/grpc:grpc_mocks", "//test/mocks/local_info:local_info_mocks", "//test/mocks/upstream:upstream_mocks", + "//test/test_common:simulated_time_system_lib", "//test/test_common:utility_lib", "@envoy_api//envoy/api/v2:eds_cc", "@envoy_api//envoy/api/v2/endpoint:endpoint_cc", diff --git a/test/common/upstream/cluster_manager_impl_test.cc b/test/common/upstream/cluster_manager_impl_test.cc index 377d4018f450b..12ae2f29e615b 100644 --- a/test/common/upstream/cluster_manager_impl_test.cc +++ b/test/common/upstream/cluster_manager_impl_test.cc @@ -757,8 +757,9 @@ TEST_F(ClusterManagerImplTest, ShutdownOrder) { EXPECT_EQ(cluster.prioritySet().hostSetsPerPriority()[0]->hosts()[0], cluster_manager_->get("cluster_1")->loadBalancer().chooseHost(nullptr)); - // Local reference, primary reference, thread local reference, host reference. - EXPECT_EQ(4U, cluster.info().use_count()); + // Local reference, primary reference, thread local reference, host reference, async client + // reference. + EXPECT_EQ(5U, cluster.info().use_count()); // Thread local reference should be gone. factory_.tls_.shutdownThread(); diff --git a/test/common/upstream/load_balancer_impl_test.cc b/test/common/upstream/load_balancer_impl_test.cc index 6111ef75576a6..178b0216ae03c 100644 --- a/test/common/upstream/load_balancer_impl_test.cc +++ b/test/common/upstream/load_balancer_impl_test.cc @@ -219,6 +219,12 @@ TEST_P(LoadBalancerBaseTest, GentleFailoverWithExtraLevels) { updateHostSet(failover_host_set_, 5 /* num_hosts */, 1 /* num_healthy_hosts */); updateHostSet(tertiary_host_set_, 5 /* num_hosts */, 1 /* num_healthy_hosts */); ASSERT_THAT(getLoadPercentage(), ElementsAre(34, 33, 33)); + + // Rounding errors should be picked up by the first healthy priority. + updateHostSet(host_set_, 5 /* num_hosts */, 0 /* num_healthy_hosts */); + updateHostSet(failover_host_set_, 5 /* num_hosts */, 2 /* num_healthy_hosts */); + updateHostSet(tertiary_host_set_, 5 /* num_hosts */, 1 /* num_healthy_hosts */); + ASSERT_THAT(getLoadPercentage(), ElementsAre(0, 67, 33)); } TEST_P(LoadBalancerBaseTest, BoundaryConditions) { diff --git a/test/common/upstream/load_stats_reporter_test.cc b/test/common/upstream/load_stats_reporter_test.cc index 1b69bfb2771a6..86bfaa79cb661 100644 --- a/test/common/upstream/load_stats_reporter_test.cc +++ b/test/common/upstream/load_stats_reporter_test.cc @@ -7,6 +7,7 @@ #include "test/mocks/grpc/mocks.h" #include "test/mocks/local_info/mocks.h" #include "test/mocks/upstream/mocks.h" +#include "test/test_common/simulated_time_system.h" #include "test/test_common/utility.h" #include "gmock/gmock.h" @@ -75,7 +76,7 @@ class LoadStatsReporterTest : public testing::Test { Event::TimerCb response_timer_cb_; Grpc::MockAsyncStream async_stream_; Grpc::MockAsyncClient* async_client_; - MockTimeSystem time_system_; + Event::SimulatedTimeSystem time_system_; NiceMock local_info_; }; @@ -93,14 +94,12 @@ TEST_F(LoadStatsReporterTest, TestPubSub) { EXPECT_CALL(*async_client_, start(_, _)).WillOnce(Return(&async_stream_)); EXPECT_CALL(async_stream_, sendMessage(_, _)); createLoadStatsReporter(); - EXPECT_CALL(time_system_, monotonicTime()); deliverLoadStatsResponse({"foo"}); EXPECT_CALL(async_stream_, sendMessage(_, _)); EXPECT_CALL(*response_timer_, enableTimer(std::chrono::milliseconds(42000))); response_timer_cb_(); - EXPECT_CALL(time_system_, monotonicTime()); deliverLoadStatsResponse({"bar"}); EXPECT_CALL(async_stream_, sendMessage(_, _)); @@ -114,8 +113,7 @@ TEST_F(LoadStatsReporterTest, ExistingClusters) { // Initially, we have no clusters to report on. expectSendMessage({}); createLoadStatsReporter(); - EXPECT_CALL(time_system_, monotonicTime()) - .WillOnce(Return(MonotonicTime(std::chrono::microseconds(3)))); + time_system_.setMonotonicTime(std::chrono::microseconds(3)); // Start reporting on foo. NiceMock foo_cluster; foo_cluster.info_->load_report_stats_.upstream_rq_dropped_.add(2); @@ -125,8 +123,7 @@ TEST_F(LoadStatsReporterTest, ExistingClusters) { deliverLoadStatsResponse({"foo"}); // Initial stats report for foo on timer tick. foo_cluster.info_->load_report_stats_.upstream_rq_dropped_.add(5); - EXPECT_CALL(time_system_, monotonicTime()) - .WillOnce(Return(MonotonicTime(std::chrono::microseconds(4)))); + time_system_.setMonotonicTime(std::chrono::microseconds(4)); { envoy::api::v2::endpoint::ClusterStats foo_cluster_stats; foo_cluster_stats.set_cluster_name("foo"); @@ -143,15 +140,12 @@ TEST_F(LoadStatsReporterTest, ExistingClusters) { bar_cluster.info_->load_report_stats_.upstream_rq_dropped_.add(1); // Start reporting on bar. - EXPECT_CALL(time_system_, monotonicTime()) - .WillOnce(Return(MonotonicTime(std::chrono::microseconds(6)))); + time_system_.setMonotonicTime(std::chrono::microseconds(6)); deliverLoadStatsResponse({"foo", "bar"}); // Stats report foo/bar on timer tick. foo_cluster.info_->load_report_stats_.upstream_rq_dropped_.add(1); bar_cluster.info_->load_report_stats_.upstream_rq_dropped_.add(1); - EXPECT_CALL(time_system_, monotonicTime()) - .Times(2) - .WillRepeatedly(Return(MonotonicTime(std::chrono::microseconds(28)))); + time_system_.setMonotonicTime(std::chrono::microseconds(28)); { envoy::api::v2::endpoint::ClusterStats foo_cluster_stats; foo_cluster_stats.set_cluster_name("foo"); @@ -177,8 +171,7 @@ TEST_F(LoadStatsReporterTest, ExistingClusters) { // Stats report for bar on timer tick. foo_cluster.info_->load_report_stats_.upstream_rq_dropped_.add(5); bar_cluster.info_->load_report_stats_.upstream_rq_dropped_.add(5); - EXPECT_CALL(time_system_, monotonicTime()) - .WillOnce(Return(MonotonicTime(std::chrono::microseconds(33)))); + time_system_.setMonotonicTime(std::chrono::microseconds(33)); { envoy::api::v2::endpoint::ClusterStats bar_cluster_stats; bar_cluster_stats.set_cluster_name("bar"); @@ -195,15 +188,12 @@ TEST_F(LoadStatsReporterTest, ExistingClusters) { bar_cluster.info_->load_report_stats_.upstream_rq_dropped_.add(1); // Start tracking foo again, we should forget earlier history for foo. - EXPECT_CALL(time_system_, monotonicTime()) - .WillOnce(Return(MonotonicTime(std::chrono::microseconds(43)))); + time_system_.setMonotonicTime(std::chrono::microseconds(43)); deliverLoadStatsResponse({"foo", "bar"}); // Stats report foo/bar on timer tick. foo_cluster.info_->load_report_stats_.upstream_rq_dropped_.add(1); bar_cluster.info_->load_report_stats_.upstream_rq_dropped_.add(1); - EXPECT_CALL(time_system_, monotonicTime()) - .Times(2) - .WillRepeatedly(Return(MonotonicTime(std::chrono::microseconds(47)))); + time_system_.setMonotonicTime(std::chrono::microseconds(47)); { envoy::api::v2::endpoint::ClusterStats foo_cluster_stats; foo_cluster_stats.set_cluster_name("foo"); diff --git a/test/common/upstream/upstream_impl_test.cc b/test/common/upstream/upstream_impl_test.cc index e916cee942b53..7a8f4259ea408 100644 --- a/test/common/upstream/upstream_impl_test.cc +++ b/test/common/upstream/upstream_impl_test.cc @@ -521,6 +521,9 @@ TEST(StrictDnsClusterImplTest, LoadAssignmentBasic) { EXPECT_EQ("localhost1", cluster.prioritySet().hostSetsPerPriority()[0]->hosts()[0]->hostname()); EXPECT_EQ("localhost1", cluster.prioritySet().hostSetsPerPriority()[0]->hosts()[1]->hostname()); + // This is the first time we receveived an update for localhost1, we expect to rebuild. + EXPECT_EQ(0UL, stats.counter("cluster.name.update_no_rebuild").value()); + resolver1.expectResolve(*dns_resolver); resolver1.timer_->callback_(); EXPECT_CALL(*resolver1.timer_, enableTimer(std::chrono::milliseconds(4000))); @@ -529,6 +532,9 @@ TEST(StrictDnsClusterImplTest, LoadAssignmentBasic) { std::list({"127.0.0.1:11001", "127.0.0.2:11001"}), ContainerEq(hostListToAddresses(cluster.prioritySet().hostSetsPerPriority()[0]->hosts()))); + // Since no change for localhost1, we expect no rebuild. + EXPECT_EQ(1UL, stats.counter("cluster.name.update_no_rebuild").value()); + resolver1.expectResolve(*dns_resolver); resolver1.timer_->callback_(); EXPECT_CALL(*resolver1.timer_, enableTimer(std::chrono::milliseconds(4000))); @@ -537,17 +543,34 @@ TEST(StrictDnsClusterImplTest, LoadAssignmentBasic) { std::list({"127.0.0.1:11001", "127.0.0.2:11001"}), ContainerEq(hostListToAddresses(cluster.prioritySet().hostSetsPerPriority()[0]->hosts()))); + // Since no change for localhost1, we expect no rebuild. + EXPECT_EQ(2UL, stats.counter("cluster.name.update_no_rebuild").value()); + + EXPECT_CALL(*resolver2.timer_, enableTimer(std::chrono::milliseconds(4000))); + EXPECT_CALL(membership_updated, ready()); + resolver2.dns_callback_(TestUtility::makeDnsResponse({"10.0.0.1", "10.0.0.1"})); + + // We received a new set of hosts for localhost2. Should rebuild the cluster. + EXPECT_EQ(2UL, stats.counter("cluster.name.update_no_rebuild").value()); + + resolver1.expectResolve(*dns_resolver); + resolver1.timer_->callback_(); + EXPECT_CALL(*resolver1.timer_, enableTimer(std::chrono::milliseconds(4000))); + resolver1.dns_callback_(TestUtility::makeDnsResponse({"127.0.0.2", "127.0.0.1"})); + + // We again received the same set as before for localhost1. No rebuild this time. + EXPECT_EQ(3UL, stats.counter("cluster.name.update_no_rebuild").value()); + resolver1.timer_->callback_(); EXPECT_CALL(*resolver1.timer_, enableTimer(std::chrono::milliseconds(4000))); EXPECT_CALL(membership_updated, ready()); resolver1.dns_callback_(TestUtility::makeDnsResponse({"127.0.0.3"})); EXPECT_THAT( - std::list({"127.0.0.3:11001"}), + std::list({"127.0.0.3:11001", "10.0.0.1:11002"}), ContainerEq(hostListToAddresses(cluster.prioritySet().hostSetsPerPriority()[0]->hosts()))); // Make sure we de-dup the same address. EXPECT_CALL(*resolver2.timer_, enableTimer(std::chrono::milliseconds(4000))); - EXPECT_CALL(membership_updated, ready()); resolver2.dns_callback_(TestUtility::makeDnsResponse({"10.0.0.1", "10.0.0.1"})); EXPECT_THAT( std::list({"127.0.0.3:11001", "10.0.0.1:11002"}), diff --git a/test/config/utility.cc b/test/config/utility.cc index 5ecae1359e92b..5501b61189f7c 100644 --- a/test/config/utility.cc +++ b/test/config/utility.cc @@ -328,7 +328,8 @@ void ConfigHelper::addRoute(const std::string& domains, const std::string& prefi const std::string& cluster, bool validate_clusters, envoy::api::v2::route::RouteAction::ClusterNotFoundResponseCode code, envoy::api::v2::route::VirtualHost::TlsRequirementType type, - envoy::api::v2::route::RouteAction::RetryPolicy retry_policy) { + envoy::api::v2::route::RouteAction::RetryPolicy retry_policy, + bool include_attempt_count_header) { RELEASE_ASSERT(!finalized_, ""); envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager hcm_config; loadHttpConnectionManager(hcm_config); @@ -337,6 +338,7 @@ void ConfigHelper::addRoute(const std::string& domains, const std::string& prefi route_config->mutable_validate_clusters()->set_value(validate_clusters); auto* virtual_host = route_config->add_virtual_hosts(); virtual_host->set_name(domains); + virtual_host->set_include_request_attempt_count(include_attempt_count_header); virtual_host->add_domains(domains); virtual_host->add_routes()->mutable_match()->set_prefix(prefix); virtual_host->mutable_routes(0)->mutable_route()->set_cluster(cluster); diff --git a/test/config/utility.h b/test/config/utility.h index 68aee64c332b3..f640b9bdc3abe 100644 --- a/test/config/utility.h +++ b/test/config/utility.h @@ -79,7 +79,8 @@ class ConfigHelper { envoy::api::v2::route::RouteAction::ClusterNotFoundResponseCode code, envoy::api::v2::route::VirtualHost::TlsRequirementType type = envoy::api::v2::route::VirtualHost::NONE, - envoy::api::v2::route::RouteAction::RetryPolicy retry_policy = {}); + envoy::api::v2::route::RouteAction::RetryPolicy retry_policy = {}, + bool include_attempt_count_header = false); // Add an HTTP filter prior to existing filters. void addFilter(const std::string& filter_yaml); diff --git a/test/extensions/access_loggers/file/config_test.cc b/test/extensions/access_loggers/file/config_test.cc index 7bd56fea21107..bc64de7f6ef3f 100644 --- a/test/extensions/access_loggers/file/config_test.cc +++ b/test/extensions/access_loggers/file/config_test.cc @@ -2,6 +2,7 @@ #include "envoy/registry/registry.h" #include "common/access_log/access_log_impl.h" +#include "common/protobuf/protobuf.h" #include "extensions/access_loggers/file/config.h" #include "extensions/access_loggers/file/file_access_log_impl.h" @@ -73,6 +74,86 @@ TEST(FileAccessLogConfigTest, FileAccessLogTest) { EXPECT_NE(nullptr, dynamic_cast(instance.get())); } +TEST(FileAccessLogConfigTest, FileAccessLogJsonTest) { + envoy::config::filter::accesslog::v2::AccessLog config; + + envoy::config::accesslog::v2::FileAccessLog fal_config; + fal_config.set_path("/dev/null"); + + auto json_format = new ProtobufWkt::Struct; + ProtobufWkt::Value string_value; + string_value.set_string_value("%PROTOCOL%"); + (*json_format->mutable_fields())[std::string{"protocol"}] = string_value; + fal_config.set_allocated_json_format(json_format); + + EXPECT_EQ(fal_config.access_log_format_case(), + envoy::config::accesslog::v2::FileAccessLog::kJsonFormat); + MessageUtil::jsonConvert(fal_config, *config.mutable_config()); + + NiceMock context; + EXPECT_THROW_WITH_MESSAGE(AccessLog::AccessLogFactory::fromProto(config, context), EnvoyException, + "Provided name for static registration lookup was empty."); + + config.set_name(AccessLogNames::get().File); + + AccessLog::InstanceSharedPtr log = AccessLog::AccessLogFactory::fromProto(config, context); + + EXPECT_NE(nullptr, log); + EXPECT_NE(nullptr, dynamic_cast(log.get())); + + config.set_name("INVALID"); + + EXPECT_THROW_WITH_MESSAGE(AccessLog::AccessLogFactory::fromProto(config, context), EnvoyException, + "Didn't find a registered implementation for name: 'INVALID'"); +} + +TEST(FileAccessLogConfigTest, FileAccessLogJsonConversionTest) { + { + envoy::config::filter::accesslog::v2::AccessLog config; + config.set_name(AccessLogNames::get().File); + envoy::config::accesslog::v2::FileAccessLog fal_config; + fal_config.set_path("/dev/null"); + + auto json_format = new ProtobufWkt::Struct; + ProtobufWkt::Value string_value; + string_value.set_bool_value(false); + (*json_format->mutable_fields())[std::string{"protocol"}] = string_value; + fal_config.set_allocated_json_format(json_format); + + MessageUtil::jsonConvert(fal_config, *config.mutable_config()); + NiceMock context; + + EXPECT_THROW_WITH_MESSAGE(AccessLog::AccessLogFactory::fromProto(config, context), + EnvoyException, + "Only string values are supported in the JSON access log format."); + } + + { + envoy::config::filter::accesslog::v2::AccessLog config; + config.set_name(AccessLogNames::get().File); + envoy::config::accesslog::v2::FileAccessLog fal_config; + fal_config.set_path("/dev/null"); + + auto json_format = new ProtobufWkt::Struct; + auto nested_struct = new ProtobufWkt::Struct; + ProtobufWkt::Value string_value; + string_value.set_string_value(std::string{"some_nested_value"}); + (*nested_struct->mutable_fields())[std::string{"some_nested_key"}] = string_value; + + ProtobufWkt::Value struct_value; + struct_value.set_allocated_struct_value(nested_struct); + (*json_format->mutable_fields())[std::string{"top_level_key"}] = struct_value; + fal_config.set_allocated_json_format(json_format); + + MessageUtil::jsonConvert(fal_config, *config.mutable_config()); + NiceMock context; + + EXPECT_THROW_WITH_MESSAGE(AccessLog::AccessLogFactory::fromProto(config, context), + EnvoyException, + "Only string values are supported in the JSON access log format."); + } +} + } // namespace File } // namespace AccessLoggers } // namespace Extensions diff --git a/test/extensions/access_loggers/http_grpc/BUILD b/test/extensions/access_loggers/http_grpc/BUILD index 2f2e07aab3ca9..946de36332524 100644 --- a/test/extensions/access_loggers/http_grpc/BUILD +++ b/test/extensions/access_loggers/http_grpc/BUILD @@ -20,7 +20,7 @@ envoy_extension_cc_test( "//test/mocks/access_log:access_log_mocks", "//test/mocks/grpc:grpc_mocks", "//test/mocks/local_info:local_info_mocks", - "//test/mocks/request_info:request_info_mocks", + "//test/mocks/stream_info:stream_info_mocks", "//test/mocks/thread_local:thread_local_mocks", ], ) 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 b3f7a0da39a3e..42e4a9d228ba8 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 @@ -5,7 +5,7 @@ #include "test/mocks/access_log/mocks.h" #include "test/mocks/grpc/mocks.h" #include "test/mocks/local_info/mocks.h" -#include "test/mocks/request_info/mocks.h" +#include "test/mocks/stream_info/mocks.h" #include "test/mocks/thread_local/mocks.h" using namespace std::chrono_literals; @@ -144,13 +144,12 @@ TEST_F(HttpGrpcAccessLogTest, Marshalling) { InSequence s; { - NiceMock request_info; - request_info.host_ = nullptr; - request_info.start_time_ = SystemTime(1h); - request_info.start_time_monotonic_ = MonotonicTime(1h); - request_info.last_downstream_tx_byte_sent_ = 2ms; - request_info.setDownstreamLocalAddress( - std::make_shared("/foo")); + NiceMock stream_info; + stream_info.host_ = nullptr; + stream_info.start_time_ = SystemTime(1h); + stream_info.start_time_monotonic_ = MonotonicTime(1h); + stream_info.last_downstream_tx_byte_sent_ = 2ms; + stream_info.setDownstreamLocalAddress(std::make_shared("/foo")); expectLog(R"EOF( http_logs: @@ -170,14 +169,14 @@ TEST_F(HttpGrpcAccessLogTest, Marshalling) { request: {} response: {} )EOF"); - access_log_->log(nullptr, nullptr, nullptr, request_info); + access_log_->log(nullptr, nullptr, nullptr, stream_info); } { - NiceMock request_info; - request_info.host_ = nullptr; - request_info.start_time_ = SystemTime(1h); - request_info.last_downstream_tx_byte_sent_ = std::chrono::nanoseconds(2000000); + NiceMock stream_info; + stream_info.host_ = nullptr; + stream_info.start_time_ = SystemTime(1h); + stream_info.last_downstream_tx_byte_sent_ = std::chrono::nanoseconds(2000000); expectLog(R"EOF( http_logs: @@ -198,28 +197,28 @@ TEST_F(HttpGrpcAccessLogTest, Marshalling) { request: {} response: {} )EOF"); - access_log_->log(nullptr, nullptr, nullptr, request_info); + access_log_->log(nullptr, nullptr, nullptr, stream_info); } { - NiceMock request_info; - request_info.start_time_ = SystemTime(1h); - - request_info.last_downstream_rx_byte_received_ = 2ms; - request_info.first_upstream_tx_byte_sent_ = 4ms; - request_info.last_upstream_tx_byte_sent_ = 6ms; - request_info.first_upstream_rx_byte_received_ = 8ms; - request_info.last_upstream_rx_byte_received_ = 10ms; - request_info.first_downstream_tx_byte_sent_ = 12ms; - request_info.last_downstream_tx_byte_sent_ = 14ms; - - request_info.setUpstreamLocalAddress( + NiceMock stream_info; + stream_info.start_time_ = SystemTime(1h); + + stream_info.last_downstream_rx_byte_received_ = 2ms; + stream_info.first_upstream_tx_byte_sent_ = 4ms; + stream_info.last_upstream_tx_byte_sent_ = 6ms; + stream_info.first_upstream_rx_byte_received_ = 8ms; + stream_info.last_upstream_rx_byte_received_ = 10ms; + stream_info.first_downstream_tx_byte_sent_ = 12ms; + stream_info.last_downstream_tx_byte_sent_ = 14ms; + + stream_info.setUpstreamLocalAddress( std::make_shared("10.0.0.2")); - request_info.protocol_ = Http::Protocol::Http10; - request_info.addBytesReceived(10); - request_info.addBytesSent(20); - request_info.response_code_ = 200; - ON_CALL(request_info, hasResponseFlag(RequestInfo::ResponseFlag::FaultInjected)) + stream_info.protocol_ = Http::Protocol::Http10; + stream_info.addBytesReceived(10); + stream_info.addBytesSent(20); + stream_info.response_code_ = 200; + ON_CALL(stream_info, hasResponseFlag(StreamInfo::ResponseFlag::FaultInjected)) .WillByDefault(Return(true)); Http::TestHeaderMapImpl request_headers{ @@ -293,13 +292,13 @@ TEST_F(HttpGrpcAccessLogTest, Marshalling) { response_headers_bytes: 10 response_body_bytes: 20 )EOF"); - access_log_->log(&request_headers, &response_headers, nullptr, request_info); + access_log_->log(&request_headers, &response_headers, nullptr, stream_info); } { - NiceMock request_info; - request_info.host_ = nullptr; - request_info.start_time_ = SystemTime(1h); + NiceMock stream_info; + stream_info.host_ = nullptr; + stream_info.start_time_ = SystemTime(1h); Http::TestHeaderMapImpl request_headers{ {":method", "WHACKADOO"}, @@ -323,7 +322,7 @@ TEST_F(HttpGrpcAccessLogTest, Marshalling) { request_method: "METHOD_UNSPECIFIED" response: {} )EOF"); - access_log_->log(nullptr, nullptr, nullptr, request_info); + access_log_->log(nullptr, nullptr, nullptr, stream_info); } } @@ -348,9 +347,9 @@ TEST_F(HttpGrpcAccessLogTest, MarshallingAdditionalHeaders) { init(); { - NiceMock request_info; - request_info.host_ = nullptr; - request_info.start_time_ = SystemTime(1h); + NiceMock stream_info; + stream_info.host_ = nullptr; + stream_info.start_time_ = SystemTime(1h); Http::TestHeaderMapImpl request_headers{ {":scheme", "scheme_value"}, @@ -408,15 +407,15 @@ TEST_F(HttpGrpcAccessLogTest, MarshallingAdditionalHeaders) { "x-logged-trailer": "value" "x-empty-trailer": "" )EOF"); - access_log_->log(&request_headers, &response_headers, &response_trailers, request_info); + access_log_->log(&request_headers, &response_headers, &response_trailers, stream_info); } } TEST(responseFlagsToAccessLogResponseFlagsTest, All) { - NiceMock request_info; - ON_CALL(request_info, hasResponseFlag(_)).WillByDefault(Return(true)); + NiceMock stream_info; + ON_CALL(stream_info, hasResponseFlag(_)).WillByDefault(Return(true)); envoy::data::accesslog::v2::AccessLogCommon common_access_log; - HttpGrpcAccessLog::responseFlagsToAccessLogResponseFlags(common_access_log, request_info); + HttpGrpcAccessLog::responseFlagsToAccessLogResponseFlags(common_access_log, stream_info); envoy::data::accesslog::v2::AccessLogCommon common_access_log_expected; common_access_log_expected.mutable_response_flags()->set_failed_local_healthcheck(true); diff --git a/test/extensions/filters/common/ext_authz/BUILD b/test/extensions/filters/common/ext_authz/BUILD index 27b273c5ee12d..11ea6860febac 100644 --- a/test/extensions/filters/common/ext_authz/BUILD +++ b/test/extensions/filters/common/ext_authz/BUILD @@ -17,8 +17,8 @@ envoy_cc_test( "//source/common/protobuf", "//source/extensions/filters/common/ext_authz:check_request_utils_lib", "//test/mocks/network:network_mocks", - "//test/mocks/request_info:request_info_mocks", "//test/mocks/ssl:ssl_mocks", + "//test/mocks/stream_info:stream_info_mocks", "//test/mocks/upstream:upstream_mocks", "//test/test_common:utility_lib", ], diff --git a/test/extensions/filters/common/ext_authz/check_request_utils_test.cc b/test/extensions/filters/common/ext_authz/check_request_utils_test.cc index d760e61188cef..14c1584d49b67 100644 --- a/test/extensions/filters/common/ext_authz/check_request_utils_test.cc +++ b/test/extensions/filters/common/ext_authz/check_request_utils_test.cc @@ -4,8 +4,8 @@ #include "extensions/filters/common/ext_authz/check_request_utils.h" #include "test/mocks/network/mocks.h" -#include "test/mocks/request_info/mocks.h" #include "test/mocks/ssl/mocks.h" +#include "test/mocks/stream_info/mocks.h" #include "test/mocks/upstream/mocks.h" #include "gmock/gmock.h" @@ -35,7 +35,7 @@ class CheckRequestUtilsTest : public testing::Test { NiceMock net_callbacks_; NiceMock connection_; NiceMock ssl_; - NiceMock req_info_; + NiceMock req_info_; }; // Verify that createTcpCheck's dependencies are invoked when it's called. @@ -58,7 +58,7 @@ TEST_F(CheckRequestUtilsTest, BasicHttp) { EXPECT_CALL(connection_, localAddress()).WillOnce(ReturnRef(addr_)); EXPECT_CALL(Const(connection_), ssl()).Times(2).WillRepeatedly(Return(&ssl_)); EXPECT_CALL(callbacks_, streamId()).WillOnce(Return(0)); - EXPECT_CALL(callbacks_, requestInfo()).Times(3).WillRepeatedly(ReturnRef(req_info_)); + EXPECT_CALL(callbacks_, streamInfo()).Times(3).WillRepeatedly(ReturnRef(req_info_)); EXPECT_CALL(req_info_, protocol()).Times(2).WillRepeatedly(ReturnPointee(&protocol_)); CheckRequestUtils::createHttpCheck(&callbacks_, headers, request); @@ -75,7 +75,7 @@ TEST_F(CheckRequestUtilsTest, CheckAttrContextPeer) { EXPECT_CALL(connection_, localAddress()).WillRepeatedly(ReturnRef(addr_)); EXPECT_CALL(Const(connection_), ssl()).WillRepeatedly(Return(&ssl_)); EXPECT_CALL(callbacks_, streamId()).WillRepeatedly(Return(0)); - EXPECT_CALL(callbacks_, requestInfo()).WillRepeatedly(ReturnRef(req_info_)); + EXPECT_CALL(callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_)); EXPECT_CALL(req_info_, protocol()).WillRepeatedly(ReturnPointee(&protocol_)); EXPECT_CALL(ssl_, uriSanPeerCertificate()).WillOnce(Return("source")); EXPECT_CALL(ssl_, uriSanLocalCertificate()).WillOnce(Return("destination")); diff --git a/test/extensions/filters/http/ext_authz/ext_authz_test.cc b/test/extensions/filters/http/ext_authz/ext_authz_test.cc index 7926855e97adf..3dd246f1b9a9d 100644 --- a/test/extensions/filters/http/ext_authz/ext_authz_test.cc +++ b/test/extensions/filters/http/ext_authz/ext_authz_test.cc @@ -182,8 +182,8 @@ TEST_P(HttpExtAuthzFilterParamTest, OkResponse) { EXPECT_EQ(Http::FilterTrailersStatus::StopIteration, filter_->decodeTrailers(request_headers_)); EXPECT_CALL(filter_callbacks_, continueDecoding()); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(Envoy::RequestInfo::ResponseFlag::UnauthorizedExternalService)) + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(Envoy::StreamInfo::ResponseFlag::UnauthorizedExternalService)) .Times(0); Filters::Common::ExtAuthz::Response response{}; @@ -346,8 +346,8 @@ TEST_P(HttpExtAuthzFilterParamTest, DeniedResponseWith401) { EXPECT_CALL(filter_callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), true)); EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(Envoy::RequestInfo::ResponseFlag::UnauthorizedExternalService)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(Envoy::StreamInfo::ResponseFlag::UnauthorizedExternalService)); Filters::Common::ExtAuthz::Response response{}; response.status = Filters::Common::ExtAuthz::CheckStatus::Denied; @@ -381,8 +381,8 @@ TEST_P(HttpExtAuthzFilterParamTest, DeniedResponseWith403) { EXPECT_CALL(filter_callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), true)); EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(Envoy::RequestInfo::ResponseFlag::UnauthorizedExternalService)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(Envoy::StreamInfo::ResponseFlag::UnauthorizedExternalService)); Filters::Common::ExtAuthz::Response response{}; response.status = Filters::Common::ExtAuthz::CheckStatus::Denied; diff --git a/test/extensions/filters/http/fault/config_test.cc b/test/extensions/filters/http/fault/config_test.cc index 55ff3fd376efc..cac94593579a4 100644 --- a/test/extensions/filters/http/fault/config_test.cc +++ b/test/extensions/filters/http/fault/config_test.cc @@ -45,7 +45,9 @@ TEST(FaultFilterConfigTest, FaultFilterCorrectJson) { TEST(FaultFilterConfigTest, FaultFilterCorrectProto) { envoy::config::filter::http::fault::v2::HTTPFault config{}; - config.mutable_delay()->set_percent(100); + config.mutable_delay()->mutable_percentage()->set_numerator(100); + config.mutable_delay()->mutable_percentage()->set_denominator( + envoy::type::FractionalPercent::HUNDRED); config.mutable_delay()->mutable_fixed_delay()->set_seconds(5); NiceMock context; diff --git a/test/extensions/filters/http/fault/fault_filter_test.cc b/test/extensions/filters/http/fault/fault_filter_test.cc index 127d38b32696e..78da514d895e4 100644 --- a/test/extensions/filters/http/fault/fault_filter_test.cc +++ b/test/extensions/filters/http/fault/fault_filter_test.cc @@ -258,8 +258,7 @@ TEST(FaultFilterBadConfigTest, MissingDelayDuration) { TEST_F(FaultFilterTest, AbortWithHttpStatus) { envoy::config::filter::http::fault::v2::HTTPFault fault; - fault.mutable_abort()->set_percent(50); - fault.mutable_abort()->mutable_percentage()->set_numerator(100); // should override int percent + fault.mutable_abort()->mutable_percentage()->set_numerator(100); fault.mutable_abort()->mutable_percentage()->set_denominator( envoy::type::FractionalPercent::HUNDRED); fault.mutable_abort()->set_http_status(429); @@ -271,8 +270,8 @@ TEST_F(FaultFilterTest, AbortWithHttpStatus) { EXPECT_CALL(runtime_.snapshot_, getInteger("fault.http.delay.fixed_duration_ms", _)).Times(0); EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::DelayInjected)) + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::DelayInjected)) .Times(0); // Abort related calls @@ -287,8 +286,8 @@ TEST_F(FaultFilterTest, AbortWithHttpStatus) { EXPECT_CALL(filter_callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), false)); EXPECT_CALL(filter_callbacks_, encodeData(_, true)); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::FaultInjected)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::FaultInjected)); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders(request_headers_, false)); @@ -317,7 +316,7 @@ TEST_F(FaultFilterTest, FixedDelayZeroDuration) { EXPECT_CALL(runtime_.snapshot_, getInteger("fault.http.abort.http_status", _)).Times(0); EXPECT_CALL(filter_callbacks_, encodeHeaders_(_, _)).Times(0); - EXPECT_CALL(filter_callbacks_.request_info_, setResponseFlag(_)).Times(0); + EXPECT_CALL(filter_callbacks_.stream_info_, setResponseFlag(_)).Times(0); EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); // Expect filter to continue execution when delay is 0ms @@ -332,8 +331,7 @@ TEST_F(FaultFilterTest, FixedDelayZeroDuration) { TEST_F(FaultFilterTest, FixedDelayDeprecatedPercentAndNonZeroDuration) { envoy::config::filter::http::fault::v2::HTTPFault fault; fault.mutable_delay()->set_type(envoy::config::filter::fault::v2::FaultDelay::FIXED); - fault.mutable_delay()->set_percent(100); - fault.mutable_delay()->mutable_percentage()->set_numerator(50); // should override int percent + fault.mutable_delay()->mutable_percentage()->set_numerator(50); fault.mutable_delay()->mutable_percentage()->set_denominator( envoy::type::FractionalPercent::HUNDRED); fault.mutable_delay()->mutable_fixed_delay()->set_seconds(5); @@ -350,8 +348,8 @@ TEST_F(FaultFilterTest, FixedDelayDeprecatedPercentAndNonZeroDuration) { SCOPED_TRACE("FixedDelayDeprecatedPercentAndNonZeroDuration"); expectDelayTimer(5000UL); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::DelayInjected)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::DelayInjected)); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders(request_headers_, false)); @@ -362,8 +360,8 @@ TEST_F(FaultFilterTest, FixedDelayDeprecatedPercentAndNonZeroDuration) { // Delay only case EXPECT_CALL(runtime_.snapshot_, getInteger("fault.http.abort.http_status", _)).Times(0); EXPECT_CALL(filter_callbacks_, encodeHeaders_(_, _)).Times(0); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::FaultInjected)) + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::FaultInjected)) .Times(0); EXPECT_CALL(filter_callbacks_, continueDecoding()); @@ -393,8 +391,8 @@ TEST_F(FaultFilterTest, DelayForDownstreamCluster) { EXPECT_CALL(runtime_.snapshot_, getInteger("fault.http.cluster.delay.fixed_duration_ms", 125UL)) .WillOnce(Return(500UL)); expectDelayTimer(500UL); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::DelayInjected)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::DelayInjected)); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders(request_headers_, false)); @@ -410,8 +408,8 @@ TEST_F(FaultFilterTest, DelayForDownstreamCluster) { EXPECT_CALL(runtime_.snapshot_, getInteger("fault.http.cluster.abort.http_status", _)).Times(0); EXPECT_CALL(runtime_.snapshot_, getInteger("fault.http.abort.http_status", _)).Times(0); EXPECT_CALL(filter_callbacks_, encodeHeaders_(_, _)).Times(0); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::FaultInjected)) + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::FaultInjected)) .Times(0); EXPECT_CALL(filter_callbacks_, continueDecoding()); EXPECT_EQ(Http::FilterDataStatus::StopIterationAndWatermark, filter_->decodeData(data_, false)); @@ -445,8 +443,8 @@ TEST_F(FaultFilterTest, FixedDelayAndAbortDownstream) { .WillOnce(Return(500UL)); expectDelayTimer(500UL); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::DelayInjected)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::DelayInjected)); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders(request_headers_, false)); @@ -468,8 +466,8 @@ TEST_F(FaultFilterTest, FixedDelayAndAbortDownstream) { EXPECT_CALL(filter_callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), false)); EXPECT_CALL(filter_callbacks_, encodeData(_, true)); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::FaultInjected)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::FaultInjected)); EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); @@ -498,8 +496,8 @@ TEST_F(FaultFilterTest, FixedDelayAndAbort) { SCOPED_TRACE("FixedDelayAndAbort"); expectDelayTimer(5000UL); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::DelayInjected)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::DelayInjected)); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders(request_headers_, false)); @@ -516,8 +514,8 @@ TEST_F(FaultFilterTest, FixedDelayAndAbort) { EXPECT_CALL(filter_callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), false)); EXPECT_CALL(filter_callbacks_, encodeData(_, true)); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::FaultInjected)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::FaultInjected)); EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); @@ -542,8 +540,8 @@ TEST_F(FaultFilterTest, FixedDelayAndAbortDownstreamNodes) { expectDelayTimer(5000UL); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::DelayInjected)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::DelayInjected)); request_headers_.addCopy("x-envoy-downstream-service-node", "canary"); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, @@ -560,8 +558,8 @@ TEST_F(FaultFilterTest, FixedDelayAndAbortDownstreamNodes) { EXPECT_CALL(filter_callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), false)); EXPECT_CALL(filter_callbacks_, encodeData(_, true)); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::FaultInjected)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::FaultInjected)); EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); @@ -592,8 +590,8 @@ TEST_F(FaultFilterTest, FixedDelayAndAbortHeaderMatchSuccess) { SCOPED_TRACE("FixedDelayAndAbortHeaderMatchSuccess"); expectDelayTimer(5000UL); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::DelayInjected)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::DelayInjected)); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders(request_headers_, false)); @@ -609,8 +607,8 @@ TEST_F(FaultFilterTest, FixedDelayAndAbortHeaderMatchSuccess) { {":status", "503"}, {"content-length", "18"}, {"content-type", "text/plain"}}; EXPECT_CALL(filter_callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), false)); EXPECT_CALL(filter_callbacks_, encodeData(_, true)); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::FaultInjected)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::FaultInjected)); EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); @@ -635,7 +633,7 @@ TEST_F(FaultFilterTest, FixedDelayAndAbortHeaderMatchFail) { .Times(0); EXPECT_CALL(runtime_.snapshot_, getInteger("fault.http.abort.http_status", _)).Times(0); EXPECT_CALL(filter_callbacks_, encodeHeaders_(_, _)).Times(0); - EXPECT_CALL(filter_callbacks_.request_info_, setResponseFlag(_)).Times(0); + EXPECT_CALL(filter_callbacks_.stream_info_, setResponseFlag(_)).Times(0); EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); // Expect filter to continue execution when headers don't match @@ -662,8 +660,8 @@ TEST_F(FaultFilterTest, TimerResetAfterStreamReset) { timer_ = new Event::MockTimer(&filter_callbacks_.dispatcher_); EXPECT_CALL(*timer_, enableTimer(std::chrono::milliseconds(5000UL))); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::DelayInjected)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::DelayInjected)); EXPECT_EQ(0UL, config_->stats().delays_injected_.value()); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, @@ -679,8 +677,8 @@ TEST_F(FaultFilterTest, TimerResetAfterStreamReset) { .Times(0); EXPECT_CALL(runtime_.snapshot_, getInteger("fault.http.abort.http_status", _)).Times(0); EXPECT_CALL(filter_callbacks_, encodeHeaders_(_, _)).Times(0); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::FaultInjected)) + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::FaultInjected)) .Times(0); EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); EXPECT_EQ(0UL, config_->stats().aborts_injected_.value()); @@ -708,8 +706,8 @@ TEST_F(FaultFilterTest, FaultWithTargetClusterMatchSuccess) { SCOPED_TRACE("FaultWithTargetClusterMatchSuccess"); expectDelayTimer(5000UL); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::DelayInjected)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::DelayInjected)); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders(request_headers_, false)); @@ -720,8 +718,8 @@ TEST_F(FaultFilterTest, FaultWithTargetClusterMatchSuccess) { // Delay only case EXPECT_CALL(runtime_.snapshot_, getInteger("fault.http.abort.http_status", _)).Times(0); EXPECT_CALL(filter_callbacks_, encodeHeaders_(_, _)).Times(0); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::FaultInjected)) + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::FaultInjected)) .Times(0); EXPECT_CALL(filter_callbacks_, continueDecoding()); timer_->callback_(); @@ -746,7 +744,7 @@ TEST_F(FaultFilterTest, FaultWithTargetClusterMatchFail) { .Times(0); EXPECT_CALL(runtime_.snapshot_, getInteger("fault.http.abort.http_status", _)).Times(0); EXPECT_CALL(filter_callbacks_, encodeHeaders_(_, _)).Times(0); - EXPECT_CALL(filter_callbacks_.request_info_, setResponseFlag(_)).Times(0); + EXPECT_CALL(filter_callbacks_.stream_info_, setResponseFlag(_)).Times(0); EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_, false)); @@ -769,7 +767,7 @@ TEST_F(FaultFilterTest, FaultWithTargetClusterNullRoute) { .Times(0); EXPECT_CALL(runtime_.snapshot_, getInteger("fault.http.abort.http_status", _)).Times(0); EXPECT_CALL(filter_callbacks_, encodeHeaders_(_, _)).Times(0); - EXPECT_CALL(filter_callbacks_.request_info_, setResponseFlag(_)).Times(0); + EXPECT_CALL(filter_callbacks_.stream_info_, setResponseFlag(_)).Times(0); EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_, false)); @@ -807,8 +805,8 @@ void FaultFilterTest::TestPerFilterConfigFault( SCOPED_TRACE("PerFilterConfigFault"); expectDelayTimer(5000UL); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::DelayInjected)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::DelayInjected)); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders(request_headers_, false)); 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 13a14036a43f7..03056e960c8a3 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 @@ -27,7 +27,7 @@ class GrpcHttp1BridgeFilterTest : public testing::Test { GrpcHttp1BridgeFilterTest() : filter_(cm_) { filter_.setDecoderFilterCallbacks(decoder_callbacks_); filter_.setEncoderFilterCallbacks(encoder_callbacks_); - ON_CALL(decoder_callbacks_.request_info_, protocol()).WillByDefault(ReturnPointee(&protocol_)); + ON_CALL(decoder_callbacks_.stream_info_, protocol()).WillByDefault(ReturnPointee(&protocol_)); } ~GrpcHttp1BridgeFilterTest() { filter_.onDestroy(); } diff --git a/test/extensions/filters/http/header_to_metadata/header_to_metadata_filter_test.cc b/test/extensions/filters/http/header_to_metadata/header_to_metadata_filter_test.cc index 715a2d45cc4c3..c2b1942786955 100644 --- a/test/extensions/filters/http/header_to_metadata/header_to_metadata_filter_test.cc +++ b/test/extensions/filters/http/header_to_metadata/header_to_metadata_filter_test.cc @@ -3,7 +3,7 @@ #include "extensions/filters/http/header_to_metadata/header_to_metadata_filter.h" #include "test/mocks/http/mocks.h" -#include "test/mocks/request_info/mocks.h" +#include "test/mocks/stream_info/mocks.h" #include "test/test_common/utility.h" #include "gmock/gmock.h" @@ -48,7 +48,7 @@ class HeaderToMetadataTest : public testing::Test { std::shared_ptr filter_; NiceMock decoder_callbacks_; NiceMock encoder_callbacks_; - NiceMock req_info_; + NiceMock req_info_; }; MATCHER_P(MapEq, rhs, "") { @@ -77,7 +77,7 @@ TEST_F(HeaderToMetadataTest, BasicRequestTest) { Http::TestHeaderMapImpl incoming_headers{{"X-VERSION", "0xdeadbeef"}}; std::map expected = {{"version", "0xdeadbeef"}}; - EXPECT_CALL(decoder_callbacks_, requestInfo()).WillRepeatedly(ReturnRef(req_info_)); + EXPECT_CALL(decoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_)); EXPECT_CALL(req_info_, setDynamicMetadata("envoy.lb", MapEq(expected))); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(incoming_headers, false)); } @@ -90,7 +90,7 @@ TEST_F(HeaderToMetadataTest, DefaultEndpointsTest) { Http::TestHeaderMapImpl incoming_headers{{"X-FOO", "bar"}}; std::map expected = {{"default", "true"}}; - EXPECT_CALL(decoder_callbacks_, requestInfo()).WillRepeatedly(ReturnRef(req_info_)); + EXPECT_CALL(decoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_)); EXPECT_CALL(req_info_, setDynamicMetadata("envoy.lb", MapEq(expected))); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(incoming_headers, false)); } @@ -112,7 +112,7 @@ TEST_F(HeaderToMetadataTest, HeaderRemovedTest) { std::map expected = {{"auth", "1"}}; Http::TestHeaderMapImpl empty_headers; - EXPECT_CALL(encoder_callbacks_, requestInfo()).WillRepeatedly(ReturnRef(req_info_)); + EXPECT_CALL(encoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_)); EXPECT_CALL(req_info_, setDynamicMetadata("envoy.filters.http.header_to_metadata", MapEq(expected))); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->encodeHeaders(incoming_headers, false)); @@ -135,7 +135,7 @@ TEST_F(HeaderToMetadataTest, NumberTypeTest) { std::map expected = {{"auth", 1}}; Http::TestHeaderMapImpl empty_headers; - EXPECT_CALL(encoder_callbacks_, requestInfo()).WillRepeatedly(ReturnRef(req_info_)); + EXPECT_CALL(encoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_)); EXPECT_CALL(req_info_, setDynamicMetadata("envoy.filters.http.header_to_metadata", MapEqNum(expected))); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->encodeHeaders(incoming_headers, false)); @@ -156,7 +156,7 @@ TEST_F(HeaderToMetadataTest, HeaderNotPresent) { initializeFilter(config); Http::TestHeaderMapImpl incoming_headers{}; - EXPECT_CALL(decoder_callbacks_, requestInfo()).WillRepeatedly(ReturnRef(req_info_)); + EXPECT_CALL(decoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_)); EXPECT_CALL(req_info_, setDynamicMetadata(_, _)).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(incoming_headers, false)); } @@ -186,7 +186,7 @@ TEST_F(HeaderToMetadataTest, MultipleHeadersMatch) { }; std::map expected = {{"version", "v4.0"}, {"python_version", "3.7"}}; - EXPECT_CALL(decoder_callbacks_, requestInfo()).WillRepeatedly(ReturnRef(req_info_)); + EXPECT_CALL(decoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_)); EXPECT_CALL(req_info_, setDynamicMetadata("envoy.lb", MapEq(expected))); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(incoming_headers, false)); } @@ -198,7 +198,7 @@ TEST_F(HeaderToMetadataTest, EmptyHeaderValue) { initializeFilter(request_config_yaml); Http::TestHeaderMapImpl incoming_headers{{"X-VERSION", ""}}; - EXPECT_CALL(decoder_callbacks_, requestInfo()).WillRepeatedly(ReturnRef(req_info_)); + EXPECT_CALL(decoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_)); EXPECT_CALL(req_info_, setDynamicMetadata(_, _)).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(incoming_headers, false)); } @@ -210,7 +210,7 @@ TEST_F(HeaderToMetadataTest, HeaderValueTooLong) { initializeFilter(request_config_yaml); Http::TestHeaderMapImpl incoming_headers{{"X-VERSION", std::string(101, 'x')}}; - EXPECT_CALL(decoder_callbacks_, requestInfo()).WillRepeatedly(ReturnRef(req_info_)); + EXPECT_CALL(decoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_)); EXPECT_CALL(req_info_, setDynamicMetadata(_, _)).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(incoming_headers, false)); } @@ -233,7 +233,7 @@ TEST_F(HeaderToMetadataTest, IgnoreHeaderValueUseConstant) { std::map expected = {{"something", "else"}}; Http::TestHeaderMapImpl empty_headers; - EXPECT_CALL(encoder_callbacks_, requestInfo()).WillRepeatedly(ReturnRef(req_info_)); + EXPECT_CALL(encoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_)); EXPECT_CALL(req_info_, setDynamicMetadata("envoy.filters.http.header_to_metadata", MapEq(expected))); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->encodeHeaders(incoming_headers, false)); @@ -268,7 +268,7 @@ TEST_F(HeaderToMetadataTest, NoEmptyValues) { initializeFilter(config); Http::TestHeaderMapImpl headers{{"x-version", ""}}; - EXPECT_CALL(decoder_callbacks_, requestInfo()).WillRepeatedly(ReturnRef(req_info_)); + EXPECT_CALL(decoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_)); EXPECT_CALL(req_info_, setDynamicMetadata(_, _)).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(headers, false)); } diff --git a/test/extensions/filters/http/health_check/health_check_test.cc b/test/extensions/filters/http/health_check/health_check_test.cc index cc6fdc5d5b4bd..17f0cf2beee2b 100644 --- a/test/extensions/filters/http/health_check/health_check_test.cc +++ b/test/extensions/filters/http/health_check/health_check_test.cc @@ -91,14 +91,14 @@ class HealthCheckFilterCachingTest : public HealthCheckFilterTest { TEST_F(HealthCheckFilterNoPassThroughTest, OkOrFailed) { EXPECT_CALL(context_, healthCheckFailed()).Times(0); - EXPECT_CALL(callbacks_.request_info_, healthCheck(true)); + EXPECT_CALL(callbacks_.stream_info_, healthCheck(true)); EXPECT_CALL(callbacks_.active_span_, setSampled(false)); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders(request_headers_, false)); } TEST_F(HealthCheckFilterNoPassThroughTest, NotHcRequest) { - EXPECT_CALL(callbacks_.request_info_, healthCheck(_)).Times(0); + EXPECT_CALL(callbacks_.stream_info_, healthCheck(_)).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_no_hc_, true)); @@ -192,7 +192,7 @@ TEST_F(HealthCheckFilterNoPassThroughTest, ComputedHealth) { TEST_F(HealthCheckFilterNoPassThroughTest, HealthCheckFailedCallbackCalled) { EXPECT_CALL(context_, healthCheckFailed()).WillOnce(Return(true)); - EXPECT_CALL(callbacks_.request_info_, healthCheck(true)); + EXPECT_CALL(callbacks_.stream_info_, healthCheck(true)); EXPECT_CALL(callbacks_.active_span_, setSampled(false)); Http::TestHeaderMapImpl health_check_response{{":status", "503"}}; EXPECT_CALL(callbacks_, encodeHeaders_(HeaderMapEqualRef(&health_check_response), true)) @@ -203,8 +203,8 @@ TEST_F(HealthCheckFilterNoPassThroughTest, HealthCheckFailedCallbackCalled) { EXPECT_EQ(nullptr, headers.EnvoyImmediateHealthCheckFail()); })); - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::FailedLocalHealthCheck)); + EXPECT_CALL(callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::FailedLocalHealthCheck)); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders(request_headers_, false)); @@ -216,7 +216,7 @@ TEST_F(HealthCheckFilterNoPassThroughTest, HealthCheckFailedCallbackCalled) { TEST_F(HealthCheckFilterPassThroughTest, Ok) { EXPECT_CALL(context_, healthCheckFailed()).WillOnce(Return(false)); - EXPECT_CALL(callbacks_.request_info_, healthCheck(true)); + EXPECT_CALL(callbacks_.stream_info_, healthCheck(true)); EXPECT_CALL(callbacks_.active_span_, setSampled(false)); EXPECT_CALL(callbacks_, encodeHeaders_(_, _)).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_, false)); @@ -229,7 +229,7 @@ TEST_F(HealthCheckFilterPassThroughTest, Ok) { TEST_F(HealthCheckFilterPassThroughTest, OkWithContinue) { EXPECT_CALL(context_, healthCheckFailed()).WillOnce(Return(false)); - EXPECT_CALL(callbacks_.request_info_, healthCheck(true)); + EXPECT_CALL(callbacks_.stream_info_, healthCheck(true)); EXPECT_CALL(callbacks_.active_span_, setSampled(false)); EXPECT_CALL(callbacks_, encodeHeaders_(_, _)).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_, false)); @@ -247,7 +247,7 @@ TEST_F(HealthCheckFilterPassThroughTest, OkWithContinue) { TEST_F(HealthCheckFilterPassThroughTest, Failed) { EXPECT_CALL(context_, healthCheckFailed()).WillOnce(Return(true)); - EXPECT_CALL(callbacks_.request_info_, healthCheck(true)); + EXPECT_CALL(callbacks_.stream_info_, healthCheck(true)); EXPECT_CALL(callbacks_.active_span_, setSampled(false)); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders(request_headers_, false)); @@ -255,14 +255,14 @@ TEST_F(HealthCheckFilterPassThroughTest, Failed) { TEST_F(HealthCheckFilterPassThroughTest, NotHcRequest) { EXPECT_CALL(context_, healthCheckFailed()).Times(0); - EXPECT_CALL(callbacks_.request_info_, healthCheck(_)).Times(0); + EXPECT_CALL(callbacks_.stream_info_, healthCheck(_)).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_no_hc_, true)); } TEST_F(HealthCheckFilterCachingTest, CachedServiceUnavailableCallbackCalled) { EXPECT_CALL(context_, healthCheckFailed()).WillRepeatedly(Return(false)); - EXPECT_CALL(callbacks_.request_info_, healthCheck(true)); + EXPECT_CALL(callbacks_.stream_info_, healthCheck(true)); EXPECT_CALL(callbacks_.active_span_, setSampled(false)); cache_manager_->setCachedResponseCode(Http::Code::ServiceUnavailable); @@ -274,8 +274,8 @@ TEST_F(HealthCheckFilterCachingTest, CachedServiceUnavailableCallbackCalled) { EXPECT_STREQ("cluster_name", headers.EnvoyUpstreamHealthCheckedCluster()->value().c_str()); })); - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::FailedLocalHealthCheck)); + EXPECT_CALL(callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::FailedLocalHealthCheck)); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders(request_headers_, true)); @@ -283,7 +283,7 @@ TEST_F(HealthCheckFilterCachingTest, CachedServiceUnavailableCallbackCalled) { TEST_F(HealthCheckFilterCachingTest, CachedOkCallbackNotCalled) { EXPECT_CALL(context_, healthCheckFailed()).WillRepeatedly(Return(false)); - EXPECT_CALL(callbacks_.request_info_, healthCheck(true)); + EXPECT_CALL(callbacks_.stream_info_, healthCheck(true)); EXPECT_CALL(callbacks_.active_span_, setSampled(false)); cache_manager_->setCachedResponseCode(Http::Code::OK); @@ -300,7 +300,7 @@ TEST_F(HealthCheckFilterCachingTest, CachedOkCallbackNotCalled) { } TEST_F(HealthCheckFilterCachingTest, All) { - EXPECT_CALL(callbacks_.request_info_, healthCheck(true)).Times(3); + EXPECT_CALL(callbacks_.stream_info_, healthCheck(true)).Times(3); EXPECT_CALL(callbacks_.active_span_, setSampled(false)).Times(3); // Verify that the first request goes through. @@ -313,8 +313,8 @@ TEST_F(HealthCheckFilterCachingTest, All) { // Verify that the next request uses the cached value. prepareFilter(true); - EXPECT_CALL(callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::FailedLocalHealthCheck)); + EXPECT_CALL(callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::FailedLocalHealthCheck)); EXPECT_CALL(callbacks_, encodeHeaders_(HeaderMapEqualRef(&health_check_response), true)) .Times(1) .WillRepeatedly(Invoke([&](Http::HeaderMap& headers, bool end_stream) { @@ -333,7 +333,7 @@ TEST_F(HealthCheckFilterCachingTest, All) { TEST_F(HealthCheckFilterCachingTest, NotHcRequest) { EXPECT_CALL(context_, healthCheckFailed()).Times(0); - EXPECT_CALL(callbacks_.request_info_, healthCheck(_)).Times(0); + EXPECT_CALL(callbacks_.stream_info_, healthCheck(_)).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_no_hc_, true)); } 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 a349db9a1efa7..2d0c64cc8e90a 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 @@ -64,7 +64,7 @@ TEST_F(IpTaggingFilterTest, InternalRequest) { Network::Address::InstanceConstSharedPtr remote_address = Network::Utility::parseInternetAddress("1.2.3.5"); - EXPECT_CALL(filter_callbacks_.request_info_, downstreamRemoteAddress()) + EXPECT_CALL(filter_callbacks_.stream_info_, downstreamRemoteAddress()) .WillOnce(ReturnRef(remote_address)); EXPECT_CALL(stats_, counter("prefix.ip_tagging.internal_request.hit")).Times(1); @@ -99,7 +99,7 @@ request_type: external Network::Address::InstanceConstSharedPtr remote_address = Network::Utility::parseInternetAddress("1.2.3.4"); - EXPECT_CALL(filter_callbacks_.request_info_, downstreamRemoteAddress()) + EXPECT_CALL(filter_callbacks_.stream_info_, downstreamRemoteAddress()) .WillOnce(ReturnRef(remote_address)); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, false)); @@ -136,7 +136,7 @@ request_type: both Network::Address::InstanceConstSharedPtr remote_address = Network::Utility::parseInternetAddress("1.2.3.5"); - EXPECT_CALL(filter_callbacks_.request_info_, downstreamRemoteAddress()) + EXPECT_CALL(filter_callbacks_.stream_info_, downstreamRemoteAddress()) .WillOnce(ReturnRef(remote_address)); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, false)); @@ -144,7 +144,7 @@ request_type: both request_headers = {}; remote_address = Network::Utility::parseInternetAddress("1.2.3.4"); - EXPECT_CALL(filter_callbacks_.request_info_, downstreamRemoteAddress()) + EXPECT_CALL(filter_callbacks_.stream_info_, downstreamRemoteAddress()) .WillOnce(ReturnRef(remote_address)); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, false)); @@ -157,7 +157,7 @@ TEST_F(IpTaggingFilterTest, NoHits) { Network::Address::InstanceConstSharedPtr remote_address = Network::Utility::parseInternetAddress("10.2.3.5"); - EXPECT_CALL(filter_callbacks_.request_info_, downstreamRemoteAddress()) + EXPECT_CALL(filter_callbacks_.stream_info_, downstreamRemoteAddress()) .WillOnce(ReturnRef(remote_address)); EXPECT_CALL(stats_, counter("prefix.ip_tagging.no_hit")).Times(1); EXPECT_CALL(stats_, counter("prefix.ip_tagging.total")).Times(1); @@ -176,7 +176,7 @@ TEST_F(IpTaggingFilterTest, AppendEntry) { Network::Address::InstanceConstSharedPtr remote_address = Network::Utility::parseInternetAddress("1.2.3.5"); - EXPECT_CALL(filter_callbacks_.request_info_, downstreamRemoteAddress()) + EXPECT_CALL(filter_callbacks_.stream_info_, downstreamRemoteAddress()) .WillOnce(ReturnRef(remote_address)); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, false)); @@ -204,7 +204,7 @@ request_type: both Network::Address::InstanceConstSharedPtr remote_address = Network::Utility::parseInternetAddress("1.2.3.4"); - EXPECT_CALL(filter_callbacks_.request_info_, downstreamRemoteAddress()) + EXPECT_CALL(filter_callbacks_.stream_info_, downstreamRemoteAddress()) .WillOnce(ReturnRef(remote_address)); EXPECT_CALL(stats_, counter("prefix.ip_tagging.total")).Times(1); @@ -235,7 +235,7 @@ TEST_F(IpTaggingFilterTest, Ipv6Address) { Network::Address::InstanceConstSharedPtr remote_address = Network::Utility::parseInternetAddress("2001:abcd:ef01:2345::1"); - EXPECT_CALL(filter_callbacks_.request_info_, downstreamRemoteAddress()) + EXPECT_CALL(filter_callbacks_.stream_info_, downstreamRemoteAddress()) .WillOnce(ReturnRef(remote_address)); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, false)); @@ -251,7 +251,7 @@ TEST_F(IpTaggingFilterTest, RuntimeDisabled) { EXPECT_CALL(runtime_.snapshot_, featureEnabled("ip_tagging.http_filter_enabled", 100)) .WillOnce(Return(false)); - EXPECT_CALL(filter_callbacks_.request_info_, downstreamRemoteAddress()).Times(0); + EXPECT_CALL(filter_callbacks_.stream_info_, downstreamRemoteAddress()).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, false)); EXPECT_FALSE(request_headers.has(Http::Headers::get().EnvoyIpTags)); EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); @@ -264,7 +264,7 @@ TEST_F(IpTaggingFilterTest, ClearRouteCache) { Network::Address::InstanceConstSharedPtr remote_address = Network::Utility::parseInternetAddress("1.2.3.5"); - EXPECT_CALL(filter_callbacks_.request_info_, downstreamRemoteAddress()) + EXPECT_CALL(filter_callbacks_.stream_info_, downstreamRemoteAddress()) .WillOnce(ReturnRef(remote_address)); EXPECT_CALL(filter_callbacks_, clearRouteCache()).Times(1); diff --git a/test/extensions/filters/http/lua/BUILD b/test/extensions/filters/http/lua/BUILD index 5f6c20712a8c2..85e31d3780adf 100644 --- a/test/extensions/filters/http/lua/BUILD +++ b/test/extensions/filters/http/lua/BUILD @@ -16,7 +16,7 @@ envoy_extension_cc_test( srcs = ["lua_filter_test.cc"], extension_name = "envoy.filters.http.lua", deps = [ - "//source/common/request_info:request_info_lib", + "//source/common/stream_info:stream_info_lib", "//source/extensions/filters/http/lua:lua_filter_lib", "//test/mocks/http:http_mocks", "//test/mocks/network:network_mocks", @@ -32,10 +32,10 @@ envoy_extension_cc_test( srcs = ["wrappers_test.cc"], extension_name = "envoy.filters.http.lua", deps = [ - "//source/common/request_info:request_info_lib", + "//source/common/stream_info:stream_info_lib", "//source/extensions/filters/http/lua:wrappers_lib", "//test/extensions/filters/common/lua:lua_wrappers_lib", - "//test/mocks/request_info:request_info_mocks", + "//test/mocks/stream_info:stream_info_mocks", "//test/test_common:utility_lib", ], ) diff --git a/test/extensions/filters/http/lua/lua_filter_test.cc b/test/extensions/filters/http/lua/lua_filter_test.cc index 23fe8b3088f27..6eded82aa9fc5 100644 --- a/test/extensions/filters/http/lua/lua_filter_test.cc +++ b/test/extensions/filters/http/lua/lua_filter_test.cc @@ -1,6 +1,6 @@ #include "common/buffer/buffer_impl.h" #include "common/http/message_impl.h" -#include "common/request_info/request_info_impl.h" +#include "common/stream_info/stream_info_impl.h" #include "extensions/filters/http/lua/lua_filter.h" @@ -95,7 +95,7 @@ class LuaHttpFilterTest : public testing::Test { envoy::api::v2::core::Metadata metadata_; NiceMock ssl_; NiceMock connection_; - NiceMock request_info_; + NiceMock stream_info_; const std::string HEADER_ONLY_SCRIPT{R"EOF( function envoy_on_request(request_handle) @@ -1502,27 +1502,27 @@ TEST_F(LuaHttpFilterTest, GetMetadataFromHandleNoLuaMetadata) { TEST_F(LuaHttpFilterTest, GetCurrentProtocol) { const std::string SCRIPT{R"EOF( function envoy_on_request(request_handle) - request_handle:logTrace(request_handle:requestInfo():protocol()) + request_handle:logTrace(request_handle:streamInfo():protocol()) end )EOF"}; InSequence s; setup(SCRIPT); - EXPECT_CALL(decoder_callbacks_, requestInfo()).WillOnce(ReturnRef(request_info_)); - EXPECT_CALL(request_info_, protocol()).WillOnce(Return(Http::Protocol::Http11)); + EXPECT_CALL(decoder_callbacks_, streamInfo()).WillOnce(ReturnRef(stream_info_)); + EXPECT_CALL(stream_info_, protocol()).WillOnce(Return(Http::Protocol::Http11)); Http::TestHeaderMapImpl request_headers{{":path", "/"}}; EXPECT_CALL(*filter_, scriptLog(spdlog::level::trace, StrEq("HTTP/1.1"))); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); } -// Set and get request info dynamic metadata. +// Set and get stream info dynamic metadata. TEST_F(LuaHttpFilterTest, SetGetDynamicMetadata) { const std::string SCRIPT{R"EOF( function envoy_on_request(request_handle) - request_handle:requestInfo():dynamicMetadata():set("envoy.lb", "foo", "bar") - request_handle:logTrace(request_handle:requestInfo():dynamicMetadata():get("envoy.lb")["foo"]) + request_handle:streamInfo():dynamicMetadata():set("envoy.lb", "foo", "bar") + request_handle:logTrace(request_handle:streamInfo():dynamicMetadata():get("envoy.lb")["foo"]) end )EOF"}; @@ -1531,13 +1531,13 @@ TEST_F(LuaHttpFilterTest, SetGetDynamicMetadata) { Http::TestHeaderMapImpl request_headers{{":path", "/"}}; DangerousDeprecatedTestTime test_time; - RequestInfo::RequestInfoImpl request_info(Http::Protocol::Http2, test_time.timeSystem()); - EXPECT_EQ(0, request_info.dynamicMetadata().filter_metadata_size()); - EXPECT_CALL(decoder_callbacks_, requestInfo()).WillOnce(ReturnRef(request_info)); + StreamInfo::StreamInfoImpl stream_info(Http::Protocol::Http2, test_time.timeSystem()); + EXPECT_EQ(0, stream_info.dynamicMetadata().filter_metadata_size()); + EXPECT_CALL(decoder_callbacks_, streamInfo()).WillOnce(ReturnRef(stream_info)); EXPECT_CALL(*filter_, scriptLog(spdlog::level::trace, StrEq("bar"))); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); - EXPECT_EQ(1, request_info.dynamicMetadata().filter_metadata_size()); - EXPECT_EQ("bar", request_info.dynamicMetadata() + EXPECT_EQ(1, stream_info.dynamicMetadata().filter_metadata_size()); + EXPECT_EQ("bar", stream_info.dynamicMetadata() .filter_metadata() .at("envoy.lb") .fields() diff --git a/test/extensions/filters/http/lua/lua_integration_test.cc b/test/extensions/filters/http/lua/lua_integration_test.cc index d53cc36d93bfb..c9c6228663b53 100644 --- a/test/extensions/filters/http/lua/lua_integration_test.cc +++ b/test/extensions/filters/http/lua/lua_integration_test.cc @@ -114,8 +114,8 @@ name: envoy.lua local metadata = request_handle:metadata():get("foo.bar") local body_length = request_handle:body():length() - request_handle:requestInfo():dynamicMetadata():set("envoy.lb", "foo", "bar") - local dynamic_metadata_value = request_handle:requestInfo():dynamicMetadata():get("envoy.lb")["foo"] + request_handle:streamInfo():dynamicMetadata():set("envoy.lb", "foo", "bar") + local dynamic_metadata_value = request_handle:streamInfo():dynamicMetadata():get("envoy.lb")["foo"] request_handle:headers():add("request_body_size", body_length) request_handle:headers():add("request_metadata_foo", metadata["foo"]) @@ -125,7 +125,7 @@ name: envoy.lua else request_handle:headers():add("request_secure", "true") end - request_handle:headers():add("request_protocol", request_handle:requestInfo():protocol()) + request_handle:headers():add("request_protocol", request_handle:streamInfo():protocol()) request_handle:headers():add("request_dynamic_metadata_value", dynamic_metadata_value) end @@ -135,7 +135,7 @@ name: envoy.lua response_handle:headers():add("response_metadata_foo", metadata["foo"]) response_handle:headers():add("response_metadata_baz", metadata["baz"]) response_handle:headers():add("response_body_size", body_length) - response_handle:headers():add("request_protocol", response_handle:requestInfo():protocol()) + response_handle:headers():add("request_protocol", response_handle:streamInfo():protocol()) response_handle:headers():remove("foo") end )EOF"; @@ -345,7 +345,7 @@ name: envoy.lua EXPECT_STREQ("200", response->headers().Status()->value().c_str()); } -// Should survive from 30 calls when calling requestInfo():dynamicMetadata(). This is a regression +// Should survive from 30 calls when calling streamInfo():dynamicMetadata(). This is a regression // test for #4305. TEST_P(LuaIntegrationTest, SurviveMultipleCalls) { const std::string FILTER_AND_CODE = @@ -354,7 +354,7 @@ name: envoy.lua config: inline_code: | function envoy_on_request(request_handle) - request_handle:requestInfo():dynamicMetadata() + request_handle:streamInfo():dynamicMetadata() end )EOF"; diff --git a/test/extensions/filters/http/lua/wrappers_test.cc b/test/extensions/filters/http/lua/wrappers_test.cc index b602006c755cc..00ace25528048 100644 --- a/test/extensions/filters/http/lua/wrappers_test.cc +++ b/test/extensions/filters/http/lua/wrappers_test.cc @@ -1,10 +1,10 @@ #include "common/http/utility.h" -#include "common/request_info/request_info_impl.h" +#include "common/stream_info/stream_info_impl.h" #include "extensions/filters/http/lua/wrappers.h" #include "test/extensions/filters/common/lua/lua_wrappers.h" -#include "test/mocks/request_info/mocks.h" +#include "test/mocks/stream_info/mocks.h" #include "test/test_common/utility.h" using testing::InSequence; @@ -216,11 +216,11 @@ TEST_F(LuaHeaderMapWrapperTest, IteratorAcrossYield) { "[string \"...\"]:5: object used outside of proper scope"); } -class LuaRequestInfoWrapperTest - : public Filters::Common::Lua::LuaWrappersTestBase { +class LuaStreamInfoWrapperTest + : public Filters::Common::Lua::LuaWrappersTestBase { public: virtual void setup(const std::string& script) { - Filters::Common::Lua::LuaWrappersTestBase::setup(script); + Filters::Common::Lua::LuaWrappersTestBase::setup(script); state_->registerType(); state_->registerType(); } @@ -236,10 +236,10 @@ class LuaRequestInfoWrapperTest InSequence s; setup(SCRIPT); - NiceMock request_info; - ON_CALL(request_info, protocol()).WillByDefault(ReturnPointee(&protocol)); - Filters::Common::Lua::LuaDeathRef wrapper( - RequestInfoWrapper::create(coroutine_->luaState(), request_info), true); + NiceMock stream_info; + ON_CALL(stream_info, protocol()).WillByDefault(ReturnPointee(&protocol)); + Filters::Common::Lua::LuaDeathRef wrapper( + StreamInfoWrapper::create(coroutine_->luaState(), stream_info), true); EXPECT_CALL(*this, testPrint(fmt::format("'{}'", Http::Utility::getProtocolString(protocol.value())))); start("callMe"); @@ -256,14 +256,14 @@ class LuaRequestInfoWrapperTest }; // Return the current request protocol. -TEST_F(LuaRequestInfoWrapperTest, ReturnCurrentProtocol) { +TEST_F(LuaStreamInfoWrapperTest, ReturnCurrentProtocol) { expectToPrintCurrentProtocol(Http::Protocol::Http10); expectToPrintCurrentProtocol(Http::Protocol::Http11); expectToPrintCurrentProtocol(Http::Protocol::Http2); } -// Set, get and iterate request info dynamic metadata. -TEST_F(LuaRequestInfoWrapperTest, SetGetAndIterateDynamicMetadata) { +// Set, get and iterate stream info dynamic metadata. +TEST_F(LuaStreamInfoWrapperTest, SetGetAndIterateDynamicMetadata) { const std::string SCRIPT{R"EOF( function callMe(object) testPrint(type(object:dynamicMetadata())) @@ -289,10 +289,10 @@ TEST_F(LuaRequestInfoWrapperTest, SetGetAndIterateDynamicMetadata) { InSequence s; setup(SCRIPT); - RequestInfo::RequestInfoImpl request_info(Http::Protocol::Http2, test_time_.timeSystem()); - EXPECT_EQ(0, request_info.dynamicMetadata().filter_metadata_size()); - Filters::Common::Lua::LuaDeathRef wrapper( - RequestInfoWrapper::create(coroutine_->luaState(), request_info), true); + StreamInfo::StreamInfoImpl stream_info(Http::Protocol::Http2, test_time_.timeSystem()); + EXPECT_EQ(0, stream_info.dynamicMetadata().filter_metadata_size()); + Filters::Common::Lua::LuaDeathRef wrapper( + StreamInfoWrapper::create(coroutine_->luaState(), stream_info), true); EXPECT_CALL(*this, testPrint("userdata")); EXPECT_CALL(*this, testPrint("bar")); EXPECT_CALL(*this, testPrint("cool")); @@ -301,8 +301,8 @@ TEST_F(LuaRequestInfoWrapperTest, SetGetAndIterateDynamicMetadata) { EXPECT_CALL(*this, testPrint("0")); start("callMe"); - EXPECT_EQ(1, request_info.dynamicMetadata().filter_metadata_size()); - EXPECT_EQ("bar", request_info.dynamicMetadata() + EXPECT_EQ(1, stream_info.dynamicMetadata().filter_metadata_size()); + EXPECT_EQ("bar", stream_info.dynamicMetadata() .filter_metadata() .at("envoy.lb") .fields() @@ -312,7 +312,7 @@ TEST_F(LuaRequestInfoWrapperTest, SetGetAndIterateDynamicMetadata) { } // Modify during iteration. -TEST_F(LuaRequestInfoWrapperTest, ModifyDuringIterationForDynamicMetadata) { +TEST_F(LuaStreamInfoWrapperTest, ModifyDuringIterationForDynamicMetadata) { const std::string SCRIPT{R"EOF( function callMe(object) object:dynamicMetadata():set("envoy.lb", "hello", "world") @@ -325,16 +325,16 @@ TEST_F(LuaRequestInfoWrapperTest, ModifyDuringIterationForDynamicMetadata) { InSequence s; setup(SCRIPT); - RequestInfo::RequestInfoImpl request_info(Http::Protocol::Http2, test_time_.timeSystem()); - Filters::Common::Lua::LuaDeathRef wrapper( - RequestInfoWrapper::create(coroutine_->luaState(), request_info), true); + StreamInfo::StreamInfoImpl stream_info(Http::Protocol::Http2, test_time_.timeSystem()); + Filters::Common::Lua::LuaDeathRef wrapper( + StreamInfoWrapper::create(coroutine_->luaState(), stream_info), true); EXPECT_THROW_WITH_MESSAGE( start("callMe"), Filters::Common::Lua::LuaException, "[string \"...\"]:5: dynamic metadata map cannot be modified while iterating"); } // Modify after iteration. -TEST_F(LuaRequestInfoWrapperTest, ModifyAfterIterationForDynamicMetadata) { +TEST_F(LuaStreamInfoWrapperTest, ModifyAfterIterationForDynamicMetadata) { const std::string SCRIPT{R"EOF( function callMe(object) object:dynamicMetadata():set("envoy.lb", "hello", "world") @@ -359,10 +359,10 @@ TEST_F(LuaRequestInfoWrapperTest, ModifyAfterIterationForDynamicMetadata) { InSequence s; setup(SCRIPT); - RequestInfo::RequestInfoImpl request_info(Http::Protocol::Http2, test_time_.timeSystem()); - EXPECT_EQ(0, request_info.dynamicMetadata().filter_metadata_size()); - Filters::Common::Lua::LuaDeathRef wrapper( - RequestInfoWrapper::create(coroutine_->luaState(), request_info), true); + StreamInfo::StreamInfoImpl stream_info(Http::Protocol::Http2, test_time_.timeSystem()); + EXPECT_EQ(0, stream_info.dynamicMetadata().filter_metadata_size()); + Filters::Common::Lua::LuaDeathRef wrapper( + StreamInfoWrapper::create(coroutine_->luaState(), stream_info), true); EXPECT_CALL(*this, testPrint("envoy.lb")); EXPECT_CALL(*this, testPrint("'hello' 'world'")); EXPECT_CALL(*this, testPrint("envoy.proxy")); @@ -373,7 +373,7 @@ TEST_F(LuaRequestInfoWrapperTest, ModifyAfterIterationForDynamicMetadata) { } // Don't finish iteration. -TEST_F(LuaRequestInfoWrapperTest, DontFinishIterationForDynamicMetadata) { +TEST_F(LuaStreamInfoWrapperTest, DontFinishIterationForDynamicMetadata) { const std::string SCRIPT{R"EOF( function callMe(object) object:dynamicMetadata():set("envoy.lb", "foo", "bar") @@ -386,9 +386,9 @@ TEST_F(LuaRequestInfoWrapperTest, DontFinishIterationForDynamicMetadata) { InSequence s; setup(SCRIPT); - RequestInfo::RequestInfoImpl request_info(Http::Protocol::Http2, test_time_.timeSystem()); - Filters::Common::Lua::LuaDeathRef wrapper( - RequestInfoWrapper::create(coroutine_->luaState(), request_info), true); + StreamInfo::StreamInfoImpl stream_info(Http::Protocol::Http2, test_time_.timeSystem()); + Filters::Common::Lua::LuaDeathRef wrapper( + StreamInfoWrapper::create(coroutine_->luaState(), stream_info), true); EXPECT_THROW_WITH_MESSAGE( start("callMe"), Filters::Common::Lua::LuaException, "[string \"...\"]:6: cannot create a second iterator before completing the first"); diff --git a/test/extensions/filters/http/ratelimit/ratelimit_test.cc b/test/extensions/filters/http/ratelimit/ratelimit_test.cc index ba5837d967049..41643e1961905 100644 --- a/test/extensions/filters/http/ratelimit/ratelimit_test.cc +++ b/test/extensions/filters/http/ratelimit/ratelimit_test.cc @@ -215,8 +215,8 @@ TEST_F(HttpRateLimitFilterTest, OkResponse) { EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->encodeTrailers(response_headers_)); EXPECT_CALL(filter_callbacks_, continueDecoding()); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::RateLimited)) + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::RateLimited)) .Times(0); request_callbacks_->complete(RateLimit::LimitStatus::OK, nullptr); @@ -258,8 +258,8 @@ TEST_F(HttpRateLimitFilterTest, OkResponseWithHeaders) { EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->encodeTrailers(response_headers_)); EXPECT_CALL(filter_callbacks_, continueDecoding()); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::RateLimited)) + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::RateLimited)) .Times(0); Http::HeaderMapPtr rl_headers{ @@ -357,8 +357,8 @@ TEST_F(HttpRateLimitFilterTest, ErrorResponse) { EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_headers_)); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::RateLimited)) + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::RateLimited)) .Times(0); EXPECT_EQ( @@ -385,8 +385,8 @@ TEST_F(HttpRateLimitFilterTest, ErrorResponseWithFailureModeAllowOff) { request_callbacks_->complete(RateLimit::LimitStatus::Error, nullptr); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::RateLimitServiceError)) + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::RateLimitServiceError)) .Times(0); EXPECT_EQ( @@ -414,8 +414,8 @@ TEST_F(HttpRateLimitFilterTest, LimitResponse) { Http::TestHeaderMapImpl response_headers{{":status", "429"}}; EXPECT_CALL(filter_callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), true)); EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::RateLimited)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::RateLimited)); request_callbacks_->complete(RateLimit::LimitStatus::OverLimit, nullptr); @@ -456,8 +456,8 @@ TEST_F(HttpRateLimitFilterTest, LimitResponseWithHeaders) { EXPECT_CALL(filter_callbacks_, encodeHeaders_(HeaderMapEqualRef(&expected_headers), true)); EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); - EXPECT_CALL(filter_callbacks_.request_info_, - setResponseFlag(RequestInfo::ResponseFlag::RateLimited)); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::ResponseFlag::RateLimited)); Http::HeaderMapPtr h{new Http::TestHeaderMapImpl(*rl_headers)}; request_callbacks_->complete(RateLimit::LimitStatus::OverLimit, std::move(h)); diff --git a/test/extensions/filters/http/rbac/rbac_filter_test.cc b/test/extensions/filters/http/rbac/rbac_filter_test.cc index 18f4686fab5de..ce6b37184750a 100644 --- a/test/extensions/filters/http/rbac/rbac_filter_test.cc +++ b/test/extensions/filters/http/rbac/rbac_filter_test.cc @@ -45,7 +45,7 @@ class RoleBasedAccessControlFilterTest : public testing::Test { void SetUp() { EXPECT_CALL(callbacks_, connection()).WillRepeatedly(Return(&connection_)); - EXPECT_CALL(callbacks_, requestInfo()).WillRepeatedly(ReturnRef(req_info_)); + EXPECT_CALL(callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_)); filter_.setDecoderFilterCallbacks(callbacks_); } @@ -65,7 +65,7 @@ class RoleBasedAccessControlFilterTest : public testing::Test { NiceMock callbacks_; NiceMock connection_{}; - NiceMock req_info_; + NiceMock req_info_; Stats::IsolatedStoreImpl store_; RoleBasedAccessControlFilterConfigSharedPtr config_; diff --git a/test/extensions/filters/network/mongo_proxy/config_test.cc b/test/extensions/filters/network/mongo_proxy/config_test.cc index f6287c28186c3..2c2c20379b695 100644 --- a/test/extensions/filters/network/mongo_proxy/config_test.cc +++ b/test/extensions/filters/network/mongo_proxy/config_test.cc @@ -255,7 +255,9 @@ TEST(MongoFilterConfigTest, CorrectFaultConfiguration) { TEST(MongoFilterConfigTest, CorrectFaultConfigurationInProto) { envoy::config::filter::network::mongo_proxy::v2::MongoProxy config{}; config.set_stat_prefix("my_stat_prefix"); - config.mutable_delay()->set_percent(50); + config.mutable_delay()->mutable_percentage()->set_numerator(50); + config.mutable_delay()->mutable_percentage()->set_denominator( + envoy::type::FractionalPercent::HUNDRED); config.mutable_delay()->mutable_fixed_delay()->set_seconds(500); NiceMock context; diff --git a/test/extensions/filters/network/mongo_proxy/proxy_test.cc b/test/extensions/filters/network/mongo_proxy/proxy_test.cc index 2cb87fc9a1e1e..a7d066047c559 100644 --- a/test/extensions/filters/network/mongo_proxy/proxy_test.cc +++ b/test/extensions/filters/network/mongo_proxy/proxy_test.cc @@ -86,7 +86,6 @@ class MongoProxyFilterTest : public testing::Test { void setupDelayFault(bool enable_fault) { envoy::config::filter::fault::v2::FaultDelay fault{}; - fault.set_percent(100); fault.mutable_percentage()->set_numerator(50); fault.mutable_percentage()->set_denominator(envoy::type::FractionalPercent::HUNDRED); fault.mutable_fixed_delay()->CopyFrom(Protobuf::util::TimeUtil::MillisecondsToDuration(10)); diff --git a/test/extensions/filters/network/sni_cluster/sni_cluster_test.cc b/test/extensions/filters/network/sni_cluster/sni_cluster_test.cc index 4d833d378efe1..d95d3d7082ab7 100644 --- a/test/extensions/filters/network/sni_cluster/sni_cluster_test.cc +++ b/test/extensions/filters/network/sni_cluster/sni_cluster_test.cc @@ -36,7 +36,7 @@ TEST(SniCluster, ConfigTest) { TEST(SniCluster, SetTcpProxyClusterOnlyIfSniIsPresent) { NiceMock filter_callbacks; - RequestInfo::FilterStateImpl per_connection_state; + StreamInfo::FilterStateImpl per_connection_state; ON_CALL(filter_callbacks.connection_, perConnectionState()) .WillByDefault(ReturnRef(per_connection_state)); ON_CALL(Const(filter_callbacks.connection_), perConnectionState()) diff --git a/test/extensions/retry/priority/other_priority/BUILD b/test/extensions/retry/priority/other_priority/BUILD new file mode 100644 index 0000000000000..59840223e9228 --- /dev/null +++ b/test/extensions/retry/priority/other_priority/BUILD @@ -0,0 +1,23 @@ +licenses(["notice"]) # Apache 2 + +load( + "//bazel:envoy_build_system.bzl", + "envoy_package", +) +load( + "//test/extensions:extensions_build_system.bzl", + "envoy_extension_cc_test", +) + +envoy_package() + +envoy_extension_cc_test( + name = "config_test", + srcs = ["config_test.cc"], + extension_name = "envoy.retry_priorities.previous_priorities", + deps = [ + "//source/extensions/retry/priority:well_known_names", + "//source/extensions/retry/priority/other_priority:config", + "//test/mocks/upstream:upstream_mocks", + ], +) diff --git a/test/extensions/retry/priority/other_priority/config_test.cc b/test/extensions/retry/priority/other_priority/config_test.cc new file mode 100644 index 0000000000000..bc283390d9f4b --- /dev/null +++ b/test/extensions/retry/priority/other_priority/config_test.cc @@ -0,0 +1,161 @@ +#include "envoy/config/retry/other_priority/other_priority_config.pb.validate.h" +#include "envoy/registry/registry.h" +#include "envoy/upstream/retry.h" + +#include "extensions/retry/priority/other_priority/config.h" +#include "extensions/retry/priority/well_known_names.h" + +#include "test/mocks/upstream/mocks.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace testing; + +namespace Envoy { +namespace Extensions { +namespace Retry { +namespace Priority { + +class RetryPriorityTest : public ::testing::Test, Upstream::RetryPriorityFactoryCallbacks { +public: + void initialize() { + auto factory = Registry::FactoryRegistry::getFactory( + RetryPriorityValues::get().PreviousPrioritiesRetryPriority); + + envoy::config::retry::other_priority::OtherPriorityConfig config; + config.set_update_frequency(update_frequency_); + // Use createEmptyConfigProto to exercise that code path. This ensures the proto returned + // by that method is compatible with the downcast in createRetryPriority. + auto empty = factory->createEmptyConfigProto(); + empty->MergeFrom(config); + factory->createRetryPriority(*this, *empty, 3); + } + + // Upstream::RetryPriorityFactoryCallbacks + void addRetryPriority(Upstream::RetryPrioritySharedPtr retry_priority) override { + retry_priority_ = retry_priority; + } + + void addHosts(size_t priority, int count, int healthy_count) { + auto host_set = priority_set_.getMockHostSet(priority); + + host_set->hosts_.resize(count); + host_set->healthy_hosts_.resize(healthy_count); + host_set->runCallbacks({}, {}); + } + + std::vector host_sets_; + uint32_t update_frequency_{1}; + NiceMock priority_set_; + Upstream::RetryPrioritySharedPtr retry_priority_; +}; + +TEST_F(RetryPriorityTest, DefaultFrequency) { + initialize(); + + const Upstream::PriorityLoad original_priority_load{100, 0}; + addHosts(0, 2, 2); + addHosts(1, 2, 2); + + auto host1 = std::make_shared>(); + ON_CALL(*host1, priority()).WillByDefault(Return(0)); + + auto host2 = std::make_shared>(); + ON_CALL(*host2, priority()).WillByDefault(Return(1)); + + // Before any hosts attempted, load should be unchanged. + ASSERT_EQ(original_priority_load, + retry_priority_->determinePriorityLoad(priority_set_, original_priority_load)); + + const Upstream::PriorityLoad expected_priority_load{0, 100}; + // After attempting a host in P0, P1 should receive all the load. + retry_priority_->onHostAttempted(host1); + ASSERT_EQ(expected_priority_load, + retry_priority_->determinePriorityLoad(priority_set_, original_priority_load)); + + // After we've tried host2, we've attempted all priorities and should reset back to the original + // priority load. + retry_priority_->onHostAttempted(host2); + ASSERT_EQ(original_priority_load, + retry_priority_->determinePriorityLoad(priority_set_, original_priority_load)); +} + +// Tests that spillover happens as we ignore attempted priorities. +TEST_F(RetryPriorityTest, DefaultFrequencyDegradedPriorities) { + initialize(); + + const Upstream::PriorityLoad original_priority_load{42, 28, 30}; + addHosts(0, 10, 3); + addHosts(1, 10, 2); + addHosts(2, 10, 10); + + auto host1 = std::make_shared>(); + ON_CALL(*host1, priority()).WillByDefault(Return(0)); + + auto host2 = std::make_shared>(); + ON_CALL(*host2, priority()).WillByDefault(Return(1)); + + auto host3 = std::make_shared>(); + ON_CALL(*host3, priority()).WillByDefault(Return(2)); + + // Before any hosts attempted, load should be unchanged. + ASSERT_EQ(original_priority_load, + retry_priority_->determinePriorityLoad(priority_set_, original_priority_load)); + + { + // After attempting a host in P0, load should be split between P1 and P2 since P1 is degraded. + const Upstream::PriorityLoad expected_priority_load{0, 28, 72}; + retry_priority_->onHostAttempted(host1); + ASSERT_EQ(expected_priority_load, + retry_priority_->determinePriorityLoad(priority_set_, original_priority_load)); + } + + // After we've tried host2, everything should go to P2. + const Upstream::PriorityLoad expected_priority_load{0, 0, 100}; + retry_priority_->onHostAttempted(host2); + ASSERT_EQ(expected_priority_load, + retry_priority_->determinePriorityLoad(priority_set_, original_priority_load)); + + // Once we've exhausted all priorities, we should return to the originial load. + retry_priority_->onHostAttempted(host3); + ASSERT_EQ(original_priority_load, + retry_priority_->determinePriorityLoad(priority_set_, original_priority_load)); +} + +// Tests that we can override the frequency at which we update the priority load with the +// update_frequency parameter. +TEST_F(RetryPriorityTest, OverridenFrequency) { + update_frequency_ = 2; + initialize(); + + const Upstream::PriorityLoad original_priority_load{100, 0}; + addHosts(0, 2, 2); + addHosts(1, 2, 2); + + auto host1 = std::make_shared>(); + ON_CALL(*host1, priority()).WillByDefault(Return(0)); + + auto host2 = std::make_shared>(); + ON_CALL(*host2, priority()).WillByDefault(Return(1)); + + // Before any hosts attempted, load should be unchanged. + ASSERT_EQ(original_priority_load, + retry_priority_->determinePriorityLoad(priority_set_, original_priority_load)); + + // After attempting a single host in P0, we should leave the priority load unchanged. + retry_priority_->onHostAttempted(host1); + ASSERT_EQ(original_priority_load, + retry_priority_->determinePriorityLoad(priority_set_, original_priority_load)); + + // After a second attempt, the prioity load should change. + const Upstream::PriorityLoad expected_priority_load{0, 100}; + retry_priority_->onHostAttempted(host1); + ASSERT_EQ(expected_priority_load, + retry_priority_->determinePriorityLoad(priority_set_, original_priority_load)); +} + +} // namespace Priority +} // namespace Retry +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/stats_sinks/common/statsd/statsd_test.cc b/test/extensions/stats_sinks/common/statsd/statsd_test.cc index 36503764de5f0..ac9b5afcd034a 100644 --- a/test/extensions/stats_sinks/common/statsd/statsd_test.cc +++ b/test/extensions/stats_sinks/common/statsd/statsd_test.cc @@ -101,6 +101,22 @@ TEST_F(TcpStatsdSinkTest, BasicFlow) { tls_.shutdownThread(); } +TEST_F(TcpStatsdSinkTest, WithCustomPrefix) { + sink_.reset(new TcpStatsdSink(local_info_, "fake_cluster", tls_, cluster_manager_, + cluster_manager_.thread_local_cluster_.cluster_.info_->stats_store_, + "test_prefix")); + + auto counter = std::make_shared>(); + counter->name_ = "test_counter"; + counter->latch_ = 1; + counter->used_ = true; + source_.counters_.push_back(counter); + + expectCreateConnection(); + EXPECT_CALL(*connection_, write(BufferStringEqual("test_prefix.test_counter:1|c\n"), _)); + sink_->flush(source_); +} + TEST_F(TcpStatsdSinkTest, BufferReallocate) { InSequence s; diff --git a/test/extensions/stats_sinks/common/statsd/udp_statsd_test.cc b/test/extensions/stats_sinks/common/statsd/udp_statsd_test.cc index e3eeb2f788fff..ef6a6e29723a3 100644 --- a/test/extensions/stats_sinks/common/statsd/udp_statsd_test.cc +++ b/test/extensions/stats_sinks/common/statsd/udp_statsd_test.cc @@ -157,6 +157,26 @@ TEST(UdpStatsdSinkTest, CheckActualStats) { tls_.shutdownThread(); } +TEST(UdpStatsdSinkTest, CheckActualStatsWithCustomPrefix) { + NiceMock source; + auto writer_ptr = std::make_shared>(); + NiceMock tls_; + UdpStatsdSink sink(tls_, writer_ptr, false, "test_prefix"); + + auto counter = std::make_shared>(); + counter->name_ = "test_counter"; + counter->used_ = true; + counter->latch_ = 1; + source.counters_.push_back(counter); + + EXPECT_CALL(*std::dynamic_pointer_cast>(writer_ptr), + write("test_prefix.test_counter:1|c")); + sink.flush(source); + counter->used_ = false; + + tls_.shutdownThread(); +} + TEST(UdpStatsdSinkWithTagsTest, CheckActualStats) { NiceMock source; auto writer_ptr = std::make_shared>(); diff --git a/test/extensions/stats_sinks/dog_statsd/config_test.cc b/test/extensions/stats_sinks/dog_statsd/config_test.cc index a8abc7f8205e4..d83055034d1ea 100644 --- a/test/extensions/stats_sinks/dog_statsd/config_test.cc +++ b/test/extensions/stats_sinks/dog_statsd/config_test.cc @@ -52,8 +52,10 @@ TEST_P(DogStatsdConfigLoopbackTest, ValidUdpIp) { NiceMock server; Stats::SinkPtr sink = factory->createStatsSink(*message, server); EXPECT_NE(sink, nullptr); - EXPECT_NE(dynamic_cast(sink.get()), nullptr); - EXPECT_EQ(dynamic_cast(sink.get())->getUseTagForTest(), true); + auto udp_sink = dynamic_cast(sink.get()); + EXPECT_NE(udp_sink, nullptr); + EXPECT_EQ(udp_sink->getUseTagForTest(), true); + EXPECT_EQ(udp_sink->getPrefix(), Common::Statsd::getDefaultPrefix()); } // Negative test for protoc-gen-validate constraints for dog_statsd. @@ -64,6 +66,35 @@ TEST(DogStatsdConfigTest, ValidateFail) { ProtoValidationException); } +TEST_P(DogStatsdConfigLoopbackTest, WithCustomPrefix) { + const std::string name = StatsSinkNames::get().DogStatsd; + + envoy::config::metrics::v2::DogStatsdSink sink_config; + envoy::api::v2::core::Address& address = *sink_config.mutable_address(); + envoy::api::v2::core::SocketAddress& socket_address = *address.mutable_socket_address(); + socket_address.set_protocol(envoy::api::v2::core::SocketAddress::UDP); + auto loopback_flavor = Network::Test::getCanonicalLoopbackAddress(GetParam()); + socket_address.set_address(loopback_flavor->ip()->addressAsString()); + socket_address.set_port_value(8125); + + const std::string customPrefix = "prefix.test"; + sink_config.set_prefix(customPrefix); + + Server::Configuration::StatsSinkFactory* factory = + Registry::FactoryRegistry::getFactory(name); + ASSERT_NE(factory, nullptr); + + ProtobufTypes::MessagePtr message = factory->createEmptyConfigProto(); + MessageUtil::jsonConvert(sink_config, *message); + + NiceMock server; + Stats::SinkPtr sink = factory->createStatsSink(*message, server); + ASSERT_NE(sink, nullptr); + auto udp_sink = dynamic_cast(sink.get()); + ASSERT_NE(udp_sink, nullptr); + EXPECT_EQ(udp_sink->getPrefix(), customPrefix); +} + } // namespace DogStatsd } // namespace StatSinks } // namespace Extensions diff --git a/test/extensions/stats_sinks/metrics_service/BUILD b/test/extensions/stats_sinks/metrics_service/BUILD index c6b8050fa0e8e..d9759e8df43d6 100644 --- a/test/extensions/stats_sinks/metrics_service/BUILD +++ b/test/extensions/stats_sinks/metrics_service/BUILD @@ -25,6 +25,7 @@ envoy_extension_cc_test( "//test/mocks/local_info:local_info_mocks", "//test/mocks/thread_local:thread_local_mocks", "//test/mocks/upstream:upstream_mocks", + "//test/test_common:simulated_time_system_lib", ], ) 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 ab078fe6953f1..932a5ee8adb38 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 @@ -5,6 +5,7 @@ #include "test/mocks/local_info/mocks.h" #include "test/mocks/stats/mocks.h" #include "test/mocks/thread_local/mocks.h" +#include "test/test_common/simulated_time_system.h" using namespace std::chrono_literals; using testing::_; @@ -29,7 +30,7 @@ class GrpcMetricsStreamerImplTest : public testing::Test { return Grpc::AsyncClientPtr{async_client_}; })); streamer_ = std::make_unique(Grpc::AsyncClientFactoryPtr{factory_}, - tls_, local_info_); + local_info_); } void expectStreamStart(MockMetricsStream& stream, MetricsServiceCallbacks** callbacks_to_set) { @@ -41,7 +42,6 @@ class GrpcMetricsStreamerImplTest : public testing::Test { })); } - NiceMock tls_; LocalInfo::MockLocalInfo local_info_; Grpc::MockAsyncClient* async_client_{new Grpc::MockAsyncClient}; Grpc::MockAsyncClientFactory* factory_{new Grpc::MockAsyncClientFactory}; @@ -99,10 +99,10 @@ class MetricsServiceSinkTest : public testing::Test {}; TEST(MetricsServiceSinkTest, CheckSendCall) { NiceMock source; - NiceMock mock_time; + Event::SimulatedTimeSystem time_system; std::shared_ptr streamer_{new MockGrpcMetricsStreamer()}; - MetricsServiceSink sink(streamer_, mock_time); + MetricsServiceSink sink(streamer_, time_system); auto counter = std::make_shared>(); counter->name_ = "test_counter"; @@ -127,10 +127,10 @@ TEST(MetricsServiceSinkTest, CheckSendCall) { TEST(MetricsServiceSinkTest, CheckStatsCount) { NiceMock source; - NiceMock mock_time; + Event::SimulatedTimeSystem time_system; std::shared_ptr streamer_{new TestGrpcMetricsStreamer()}; - MetricsServiceSink sink(streamer_, mock_time); + MetricsServiceSink sink(streamer_, time_system); auto counter = std::make_shared>(); counter->name_ = "test_counter"; diff --git a/test/extensions/tracers/dynamic_ot/config_test.cc b/test/extensions/tracers/dynamic_ot/config_test.cc index d2c2077bcd7d0..4ca95026c901d 100644 --- a/test/extensions/tracers/dynamic_ot/config_test.cc +++ b/test/extensions/tracers/dynamic_ot/config_test.cc @@ -23,19 +23,21 @@ TEST(DynamicOtTracerConfigTest, DynamicOpentracingHttpTracer) { ON_CALL(*server.cluster_manager_.thread_local_cluster_.cluster_.info_, features()) .WillByDefault(Return(Upstream::ClusterInfo::Features::HTTP2)); - const std::string valid_config = fmt::sprintf(R"EOF( - { - "library": "%s/external/io_opentracing_cpp/mocktracer/libmocktracer_plugin.so", - "config": { - "output_file" : "fake_file" - } - } + const std::string yaml_string = fmt::sprintf(R"EOF( + http: + name: envoy.dynamic.ot + config: + library: %s/external/io_opentracing_cpp/mocktracer/libmocktracer_plugin.so + config: + output_file: fake_file )EOF", - TestEnvironment::runfilesDirectory()); - const Json::ObjectSharedPtr valid_json = Json::Factory::loadFromString(valid_config); + TestEnvironment::runfilesDirectory()); + envoy::config::trace::v2::Tracing configuration; + MessageUtil::loadFromYaml(yaml_string, configuration); + DynamicOpenTracingTracerFactory factory; - const Tracing::HttpTracerPtr tracer = factory.createHttpTracer(*valid_json, server); + const Tracing::HttpTracerPtr tracer = factory.createHttpTracer(configuration, server); EXPECT_NE(nullptr, tracer); } diff --git a/test/extensions/tracers/lightstep/config_test.cc b/test/extensions/tracers/lightstep/config_test.cc index 3eb338d87dd29..b1650ae6bcd15 100644 --- a/test/extensions/tracers/lightstep/config_test.cc +++ b/test/extensions/tracers/lightstep/config_test.cc @@ -21,16 +21,18 @@ TEST(LightstepTracerConfigTest, LightstepHttpTracer) { ON_CALL(*server.cluster_manager_.thread_local_cluster_.cluster_.info_, features()) .WillByDefault(Return(Upstream::ClusterInfo::Features::HTTP2)); - std::string valid_config = R"EOF( - { - "collector_cluster": "fake_cluster", - "access_token_file": "fake_file" - } - )EOF"; - Json::ObjectSharedPtr valid_json = Json::Factory::loadFromString(valid_config); + const std::string yaml_string = R"EOF( + http: + name: envoy.lightstep + config: + collector_cluster: fake_cluster + access_token_file: fake_file + )EOF"; + envoy::config::trace::v2::Tracing configuration; + MessageUtil::loadFromYaml(yaml_string, configuration); LightstepTracerFactory factory; - Tracing::HttpTracerPtr lightstep_tracer = factory.createHttpTracer(*valid_json, server); + Tracing::HttpTracerPtr lightstep_tracer = factory.createHttpTracer(configuration, server); EXPECT_NE(nullptr, lightstep_tracer); } diff --git a/test/extensions/tracers/lightstep/lightstep_tracer_impl_test.cc b/test/extensions/tracers/lightstep/lightstep_tracer_impl_test.cc index 2650ddc7df397..957505015ab8e 100644 --- a/test/extensions/tracers/lightstep/lightstep_tracer_impl_test.cc +++ b/test/extensions/tracers/lightstep/lightstep_tracer_impl_test.cc @@ -42,7 +42,7 @@ namespace Lightstep { class LightStepDriverTest : public Test { public: - void setup(Json::Object& config, bool init_timer, + void setup(envoy::config::trace::v2::LightstepConfig& lightstep_config, bool init_timer, Common::Ot::OpenTracingDriver::PropagationMode propagation_mode = Common::Ot::OpenTracingDriver::PropagationMode::TracerNative) { std::unique_ptr opts( @@ -58,8 +58,8 @@ class LightStepDriverTest : public Test { EXPECT_CALL(*timer_, enableTimer(std::chrono::milliseconds(1000))); } - driver_.reset(new LightStepDriver{config, cm_, stats_, tls_, runtime_, std::move(opts), - propagation_mode}); + driver_.reset(new LightStepDriver{lightstep_config, cm_, stats_, tls_, runtime_, + std::move(opts), propagation_mode}); } void setupValidDriver(Common::Ot::OpenTracingDriver::PropagationMode propagation_mode = @@ -68,12 +68,13 @@ class LightStepDriverTest : public Test { ON_CALL(*cm_.thread_local_cluster_.cluster_.info_, features()) .WillByDefault(Return(Upstream::ClusterInfo::Features::HTTP2)); - std::string valid_config = R"EOF( - {"collector_cluster": "fake_cluster"} + const std::string yaml_string = R"EOF( + collector_cluster: fake_cluster )EOF"; - Json::ObjectSharedPtr loader = Json::Factory::loadFromString(valid_config); + envoy::config::trace::v2::LightstepConfig lightstep_config; + MessageUtil::loadFromYaml(yaml_string, lightstep_config); - setup(*loader, true, propagation_mode); + setup(lightstep_config, true, propagation_mode); } const std::string operation_name_{"test"}; @@ -81,7 +82,7 @@ class LightStepDriverTest : public Test { {":path", "/"}, {":method", "GET"}, {"x-request-id", "foo"}}; const Http::TestHeaderMapImpl response_headers_{{":status", "500"}}; SystemTime start_time_; - RequestInfo::MockRequestInfo request_info_; + StreamInfo::MockStreamInfo stream_info_; NiceMock tls_; std::unique_ptr driver_; @@ -106,31 +107,22 @@ TEST_F(LightStepDriverTest, LightStepLogger) { TEST_F(LightStepDriverTest, InitializeDriver) { { - std::string invalid_config = R"EOF( - {"fake" : "fake"} - )EOF"; - Json::ObjectSharedPtr loader = Json::Factory::loadFromString(invalid_config); - - EXPECT_THROW(setup(*loader, false), EnvoyException); - } - - { - std::string empty_config = "{}"; - Json::ObjectSharedPtr loader = Json::Factory::loadFromString(empty_config); + envoy::config::trace::v2::LightstepConfig lightstep_config; - EXPECT_THROW(setup(*loader, false), EnvoyException); + EXPECT_THROW(setup(lightstep_config, false), EnvoyException); } { // Valid config but not valid cluster. EXPECT_CALL(cm_, get("fake_cluster")).WillOnce(Return(nullptr)); - std::string valid_config = R"EOF( - {"collector_cluster": "fake_cluster"} + const std::string yaml_string = R"EOF( + collector_cluster: fake_cluster )EOF"; - Json::ObjectSharedPtr loader = Json::Factory::loadFromString(valid_config); + envoy::config::trace::v2::LightstepConfig lightstep_config; + MessageUtil::loadFromYaml(yaml_string, lightstep_config); - EXPECT_THROW(setup(*loader, false), EnvoyException); + EXPECT_THROW(setup(lightstep_config, false), EnvoyException); } { @@ -138,12 +130,13 @@ TEST_F(LightStepDriverTest, InitializeDriver) { EXPECT_CALL(cm_, get("fake_cluster")).WillRepeatedly(Return(&cm_.thread_local_cluster_)); ON_CALL(*cm_.thread_local_cluster_.cluster_.info_, features()).WillByDefault(Return(0)); - std::string valid_config = R"EOF( - {"collector_cluster": "fake_cluster"} + const std::string yaml_string = R"EOF( + collector_cluster: fake_cluster )EOF"; - Json::ObjectSharedPtr loader = Json::Factory::loadFromString(valid_config); + envoy::config::trace::v2::LightstepConfig lightstep_config; + MessageUtil::loadFromYaml(yaml_string, lightstep_config); - EXPECT_THROW(setup(*loader, false), EnvoyException); + EXPECT_THROW(setup(lightstep_config, false), EnvoyException); } { @@ -151,12 +144,13 @@ TEST_F(LightStepDriverTest, InitializeDriver) { ON_CALL(*cm_.thread_local_cluster_.cluster_.info_, features()) .WillByDefault(Return(Upstream::ClusterInfo::Features::HTTP2)); - std::string valid_config = R"EOF( - {"collector_cluster": "fake_cluster"} + const std::string yaml_string = R"EOF( + collector_cluster: fake_cluster )EOF"; - Json::ObjectSharedPtr loader = Json::Factory::loadFromString(valid_config); + envoy::config::trace::v2::LightstepConfig lightstep_config; + MessageUtil::loadFromYaml(yaml_string, lightstep_config); - setup(*loader, true); + setup(lightstep_config, true); } } diff --git a/test/extensions/tracers/zipkin/config_test.cc b/test/extensions/tracers/zipkin/config_test.cc index e5326187b683f..3373dc7893861 100644 --- a/test/extensions/tracers/zipkin/config_test.cc +++ b/test/extensions/tracers/zipkin/config_test.cc @@ -17,15 +17,19 @@ TEST(ZipkinTracerConfigTest, ZipkinHttpTracer) { EXPECT_CALL(server.cluster_manager_, get("fake_cluster")) .WillRepeatedly(Return(&server.cluster_manager_.thread_local_cluster_)); - std::string valid_config = R"EOF( - { - "collector_cluster": "fake_cluster", - "collector_endpoint": "/api/v1/spans" - } + const std::string yaml_string = R"EOF( + http: + name: envoy.zipkin + config: + collector_cluster: fake_cluster + collector_endpoint: /api/v1/spans )EOF"; - Json::ObjectSharedPtr valid_json = Json::Factory::loadFromString(valid_config); + + envoy::config::trace::v2::Tracing configuration; + MessageUtil::loadFromYaml(yaml_string, configuration); + ZipkinTracerFactory factory; - Tracing::HttpTracerPtr zipkin_tracer = factory.createHttpTracer(*valid_json, server); + Tracing::HttpTracerPtr zipkin_tracer = factory.createHttpTracer(configuration, server); EXPECT_NE(nullptr, zipkin_tracer); } diff --git a/test/extensions/tracers/zipkin/zipkin_tracer_impl_test.cc b/test/extensions/tracers/zipkin/zipkin_tracer_impl_test.cc index 05ad40b746e84..c2c136122786b 100644 --- a/test/extensions/tracers/zipkin/zipkin_tracer_impl_test.cc +++ b/test/extensions/tracers/zipkin/zipkin_tracer_impl_test.cc @@ -40,7 +40,7 @@ class ZipkinDriverTest : public Test { public: ZipkinDriverTest() : time_source_(test_time_.timeSystem()) {} - void setup(Json::Object& config, bool init_timer) { + void setup(envoy::config::trace::v2::ZipkinConfig& zipkin_config, bool init_timer) { ON_CALL(cm_, httpAsyncClientForCluster("fake_cluster")) .WillByDefault(ReturnRef(cm_.async_client_)); @@ -50,21 +50,20 @@ class ZipkinDriverTest : public Test { } driver_.reset( - new Driver(config, cm_, stats_, tls_, runtime_, local_info_, random_, time_source_)); + new Driver(zipkin_config, cm_, stats_, tls_, runtime_, local_info_, random_, time_source_)); } void setupValidDriver() { EXPECT_CALL(cm_, get("fake_cluster")).WillRepeatedly(Return(&cm_.thread_local_cluster_)); - std::string valid_config = R"EOF( - { - "collector_cluster": "fake_cluster", - "collector_endpoint": "/api/v1/spans" - } + const std::string yaml_string = R"EOF( + collector_cluster: fake_cluster + collector_endpoint: /api/v1/spans )EOF"; - Json::ObjectSharedPtr loader = Json::Factory::loadFromString(valid_config); + envoy::config::trace::v2::ZipkinConfig zipkin_config; + MessageUtil::loadFromYaml(yaml_string, zipkin_config); - setup(*loader, true); + setup(zipkin_config, true); } // TODO(#4160): Currently time_system_ is initialized from DangerousDeprecatedTestTime, which uses @@ -77,7 +76,7 @@ class ZipkinDriverTest : public Test { Http::TestHeaderMapImpl request_headers_{ {":authority", "api.lyft.com"}, {":path", "/"}, {":method", "GET"}, {"x-request-id", "foo"}}; SystemTime start_time_; - RequestInfo::MockRequestInfo request_info_; + StreamInfo::MockStreamInfo stream_info_; NiceMock tls_; std::unique_ptr driver_; @@ -95,34 +94,23 @@ class ZipkinDriverTest : public Test { TEST_F(ZipkinDriverTest, InitializeDriver) { { - std::string invalid_config = R"EOF( - {"fake" : "fake"} - )EOF"; - Json::ObjectSharedPtr loader = Json::Factory::loadFromString(invalid_config); - - EXPECT_THROW(setup(*loader, false), EnvoyException); - } + // Empty config + envoy::config::trace::v2::ZipkinConfig zipkin_config; - { - std::string empty_config = "{}"; - Json::ObjectSharedPtr loader = Json::Factory::loadFromString(empty_config); - - EXPECT_THROW(setup(*loader, false), EnvoyException); + EXPECT_THROW(setup(zipkin_config, false), EnvoyException); } { // Valid config but not valid cluster. EXPECT_CALL(cm_, get("fake_cluster")).WillOnce(Return(nullptr)); - - std::string valid_config = R"EOF( - { - "collector_cluster": "fake_cluster", - "collector_endpoint": "/api/v1/spans" - } + const std::string yaml_string = R"EOF( + collector_cluster: fake_cluster + collector_endpoint: /api/v1/spans )EOF"; - Json::ObjectSharedPtr loader = Json::Factory::loadFromString(valid_config); + envoy::config::trace::v2::ZipkinConfig zipkin_config; + MessageUtil::loadFromYaml(yaml_string, zipkin_config); - EXPECT_THROW(setup(*loader, false), EnvoyException); + EXPECT_THROW(setup(zipkin_config, false), EnvoyException); } { @@ -130,15 +118,14 @@ TEST_F(ZipkinDriverTest, InitializeDriver) { EXPECT_CALL(cm_, get("fake_cluster")).WillRepeatedly(Return(&cm_.thread_local_cluster_)); ON_CALL(*cm_.thread_local_cluster_.cluster_.info_, features()).WillByDefault(Return(0)); - std::string valid_config = R"EOF( - { - "collector_cluster": "fake_cluster", - "collector_endpoint": "/api/v1/spans" - } + const std::string yaml_string = R"EOF( + collector_cluster: fake_cluster + collector_endpoint: /api/v1/spans )EOF"; - Json::ObjectSharedPtr loader = Json::Factory::loadFromString(valid_config); + envoy::config::trace::v2::ZipkinConfig zipkin_config; + MessageUtil::loadFromYaml(yaml_string, zipkin_config); - setup(*loader, true); + setup(zipkin_config, true); } } diff --git a/test/fuzz/common.proto b/test/fuzz/common.proto index 2661012b06902..11cecec91b7c8 100644 --- a/test/fuzz/common.proto +++ b/test/fuzz/common.proto @@ -12,7 +12,7 @@ message Headers { repeated envoy.api.v2.core.HeaderValue headers = 1; } -message RequestInfo { +message StreamInfo { envoy.api.v2.core.Metadata dynamic_metadata = 1; uint64 start_time = 2; google.protobuf.UInt32Value response_code = 3; diff --git a/test/fuzz/utility.h b/test/fuzz/utility.h index 3c5fdf1158db0..f1a923f2199d6 100644 --- a/test/fuzz/utility.h +++ b/test/fuzz/utility.h @@ -33,28 +33,28 @@ inline test::fuzz::Headers toHeaders(const Http::HeaderMap& headers) { return fuzz_headers; } -inline TestRequestInfo fromRequestInfo(const test::fuzz::RequestInfo& request_info) { - TestRequestInfo test_request_info; - test_request_info.metadata_ = request_info.dynamic_metadata(); +inline TestStreamInfo fromStreamInfo(const test::fuzz::StreamInfo& stream_info) { + TestStreamInfo test_stream_info; + test_stream_info.metadata_ = stream_info.dynamic_metadata(); // libc++ clocks don't track at nanosecond on OS X. const auto start_time = - std::numeric_limits::max() < request_info.start_time() + std::numeric_limits::max() < stream_info.start_time() ? 0 - : request_info.start_time() / 1000; - test_request_info.start_time_ = SystemTime(std::chrono::microseconds(start_time)); - if (request_info.has_response_code()) { - test_request_info.response_code_ = request_info.response_code().value(); + : stream_info.start_time() / 1000; + test_stream_info.start_time_ = SystemTime(std::chrono::microseconds(start_time)); + if (stream_info.has_response_code()) { + test_stream_info.response_code_ = stream_info.response_code().value(); } auto upstream_host = std::make_shared>(); auto upstream_metadata = - std::make_shared(request_info.upstream_metadata()); + std::make_shared(stream_info.upstream_metadata()); ON_CALL(*upstream_host, metadata()).WillByDefault(testing::Return(upstream_metadata)); - test_request_info.upstream_host_ = upstream_host; + test_stream_info.upstream_host_ = upstream_host; auto address = Network::Utility::resolveUrl("tcp://10.0.0.1:443"); - test_request_info.upstream_local_address_ = address; - test_request_info.downstream_local_address_ = address; - test_request_info.downstream_remote_address_ = address; - return test_request_info; + test_stream_info.upstream_local_address_ = address; + test_stream_info.downstream_local_address_ = address; + test_stream_info.downstream_remote_address_ = address; + return test_stream_info; } } // namespace Fuzz diff --git a/test/integration/BUILD b/test/integration/BUILD index 2335f5f9bdf76..4f9317b046838 100644 --- a/test/integration/BUILD +++ b/test/integration/BUILD @@ -172,9 +172,11 @@ envoy_cc_test( deps = [ ":http_integration_lib", "//include/envoy/http:header_map_interface", + "//source/common/stats:stats_matcher_lib", "//source/extensions/filters/http/buffer:config", "//source/extensions/filters/http/health_check:config", "@envoy_api//envoy/admin/v2alpha:config_dump_cc", + "@envoy_api//envoy/config/metrics/v2:stats_cc", ], ) @@ -189,22 +191,6 @@ envoy_cc_test_library( ], ) -envoy_cc_test_library( - name = "add_trailers_filter_config_lib", - srcs = [ - "add_trailers_filter.cc", - "add_trailers_filter.h", - "add_trailers_filter_config.cc", - "add_trailers_filter_config.h", - ], - deps = [ - "//include/envoy/http:filter_interface", - "//include/envoy/registry", - "//include/envoy/server:filter_config_interface", - "//source/extensions/filters/http/common:empty_http_filter_config_lib", - ], -) - envoy_cc_test_library( name = "http_integration_lib", srcs = [ @@ -214,13 +200,15 @@ envoy_cc_test_library( "http_integration.h", ], deps = [ - ":add_trailers_filter_config_lib", ":integration_lib", ":test_host_predicate_lib", "//include/envoy/event:timer_interface", + "//source/common/common:thread_annotations", "//source/extensions/filters/http/router:config", "//source/extensions/filters/network/http_connection_manager:config", "//test/common/upstream:utility_lib", + "//test/integration/filters:add_trailers_filter_config_lib", + "//test/integration/filters:pause_filter_lib", "//test/test_common:registry_lib", ], ) diff --git a/test/integration/README.md b/test/integration/README.md index 07b3b8bba4859..d923a0efcbc24 100644 --- a/test/integration/README.md +++ b/test/integration/README.md @@ -149,7 +149,7 @@ The full command might look something like ``` bazel test //test/integration:http2_upstream_integration_test \ --test_arg=--gtest_filter="IpVersions/Http2UpstreamIntegrationTest.RouterRequestAndResponseWithBodyNoBuffer/IPv6" \ ---jobs 60 --local_resources 100000000000,100000000000,10000000 --test_arg="-l trace" +--jobs 60 --local_resources 100000000000,100000000000,10000000 --runs_per_test=1000 --test_arg="-l trace" ``` ## Debugging test flakes diff --git a/test/integration/add_trailers_filter.cc b/test/integration/add_trailers_filter.cc deleted file mode 100644 index d9bfde74668ab..0000000000000 --- a/test/integration/add_trailers_filter.cc +++ /dev/null @@ -1,21 +0,0 @@ -#include "test/integration/add_trailers_filter.h" - -#include - -namespace Envoy { -Http::FilterDataStatus AddTrailersStreamFilter::decodeData(Buffer::Instance&, bool end_stream) { - if (end_stream) { - decoder_callbacks_->addDecodedTrailers().insertGrpcMessage().value(std::string("decode")); - } - - return Http::FilterDataStatus::Continue; -} - -Http::FilterDataStatus AddTrailersStreamFilter::encodeData(Buffer::Instance&, bool end_stream) { - if (end_stream) { - encoder_callbacks_->addEncodedTrailers().insertGrpcMessage().value(std::string("encode")); - } - - return Http::FilterDataStatus::Continue; -} -} // namespace Envoy diff --git a/test/integration/add_trailers_filter_config.cc b/test/integration/add_trailers_filter_config.cc deleted file mode 100644 index 2aad49f9a55c3..0000000000000 --- a/test/integration/add_trailers_filter_config.cc +++ /dev/null @@ -1,20 +0,0 @@ -#include "test/integration/add_trailers_filter_config.h" - -#include "envoy/registry/registry.h" - -#include "test/integration/add_trailers_filter.h" - -namespace Envoy { -Http::FilterFactoryCb -AddTrailersStreamFilterConfig::createFilter(const std::string&, - Server::Configuration::FactoryContext&) { - return [](Http::FilterChainFactoryCallbacks& callbacks) -> void { - callbacks.addStreamFilter(std::make_shared<::Envoy::AddTrailersStreamFilter>()); - }; -} - -// perform static registration -static Registry::RegisterFactory - register_; -} // namespace Envoy diff --git a/test/integration/add_trailers_filter_config.h b/test/integration/add_trailers_filter_config.h deleted file mode 100644 index 8f606ee68e2f7..0000000000000 --- a/test/integration/add_trailers_filter_config.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "envoy/registry/registry.h" -#include "envoy/server/filter_config.h" - -#include "extensions/filters/http/common/empty_http_filter_config.h" - -#include "test/integration/add_trailers_filter.h" - -namespace Envoy { -class AddTrailersStreamFilterConfig - : public Extensions::HttpFilters::Common::EmptyHttpFilterConfig { -public: - AddTrailersStreamFilterConfig() : EmptyHttpFilterConfig("add-trailers-filter") {} - - Http::FilterFactoryCb createFilter(const std::string&, Server::Configuration::FactoryContext&); -}; -} // namespace Envoy diff --git a/test/integration/filters/BUILD b/test/integration/filters/BUILD new file mode 100644 index 0000000000000..2ff2a8fae20e9 --- /dev/null +++ b/test/integration/filters/BUILD @@ -0,0 +1,48 @@ +licenses(["notice"]) # Apache 2 + +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_test_library", + "envoy_package", +) + +envoy_package() + +envoy_cc_test_library( + name = "add_trailers_filter_config_lib", + srcs = [ + "add_trailers_filter.cc", + ], + deps = [ + ":pass_through_filter_lib", + "//include/envoy/http:filter_interface", + "//include/envoy/registry", + "//include/envoy/server:filter_config_interface", + "//source/extensions/filters/http/common:empty_http_filter_config_lib", + ], +) + +envoy_cc_test_library( + name = "pass_through_filter_lib", + srcs = [ + "pass_through_filter.h", + ], + deps = [ + "//include/envoy/http:filter_interface", + "//include/envoy/registry", + "//source/extensions/filters/http/common:empty_http_filter_config_lib", + ], +) + +envoy_cc_test_library( + name = "pause_filter_lib", + srcs = [ + "pause_filter.cc", + ], + deps = [ + ":pass_through_filter_lib", + "//include/envoy/http:filter_interface", + "//include/envoy/registry", + "//source/common/network:connection_lib", + ], +) diff --git a/test/integration/filters/add_trailers_filter.cc b/test/integration/filters/add_trailers_filter.cc new file mode 100644 index 0000000000000..ced23597b2f87 --- /dev/null +++ b/test/integration/filters/add_trailers_filter.cc @@ -0,0 +1,50 @@ +#include + +#include "envoy/http/filter.h" +#include "envoy/registry/registry.h" +#include "envoy/server/filter_config.h" + +#include "extensions/filters/http/common/empty_http_filter_config.h" + +#include "test/integration/filters/pass_through_filter.h" + +namespace Envoy { + +// A test filter that inserts trailers at the end of encode/decode +class AddTrailersStreamFilter : public PassThroughFilter { +public: + Http::FilterDataStatus decodeData(Buffer::Instance&, bool end_stream) { + if (end_stream) { + decoder_callbacks_->addDecodedTrailers().insertGrpcMessage().value(std::string("decode")); + } + + return Http::FilterDataStatus::Continue; + } + + Http::FilterDataStatus encodeData(Buffer::Instance&, bool end_stream) { + if (end_stream) { + encoder_callbacks_->addEncodedTrailers().insertGrpcMessage().value(std::string("encode")); + } + + return Http::FilterDataStatus::Continue; + } +}; + +class AddTrailersStreamFilterConfig + : public Extensions::HttpFilters::Common::EmptyHttpFilterConfig { +public: + AddTrailersStreamFilterConfig() : EmptyHttpFilterConfig("add-trailers-filter") {} + + Http::FilterFactoryCb createFilter(const std::string&, Server::Configuration::FactoryContext&) { + return [](Http::FilterChainFactoryCallbacks& callbacks) -> void { + callbacks.addStreamFilter(std::make_shared<::Envoy::AddTrailersStreamFilter>()); + }; + } +}; + +// perform static registration +static Registry::RegisterFactory + register_; + +} // namespace Envoy diff --git a/test/integration/add_trailers_filter.h b/test/integration/filters/pass_through_filter.h similarity index 77% rename from test/integration/add_trailers_filter.h rename to test/integration/filters/pass_through_filter.h index f86fdc15517db..b9ce41ef9111f 100644 --- a/test/integration/add_trailers_filter.h +++ b/test/integration/filters/pass_through_filter.h @@ -3,8 +3,9 @@ #include "envoy/http/filter.h" namespace Envoy { -// a test filter that inserts trailers at the end of encode/decode -class AddTrailersStreamFilter : public Http::StreamFilter { + +// A filter which passes all data through with Continue status. +class PassThroughFilter : public Http::StreamFilter { public: // Http::StreamFilterBase void onDestroy() override {} @@ -13,7 +14,9 @@ class AddTrailersStreamFilter : public Http::StreamFilter { Http::FilterHeadersStatus decodeHeaders(Http::HeaderMap&, bool) override { return Http::FilterHeadersStatus::Continue; } - Http::FilterDataStatus decodeData(Buffer::Instance&, bool end_stream) override; + Http::FilterDataStatus decodeData(Buffer::Instance&, bool) override { + return Http::FilterDataStatus::Continue; + } Http::FilterTrailersStatus decodeTrailers(Http::HeaderMap&) override { return Http::FilterTrailersStatus::Continue; @@ -29,7 +32,9 @@ class AddTrailersStreamFilter : public Http::StreamFilter { Http::FilterHeadersStatus encodeHeaders(Http::HeaderMap&, bool) override { return Http::FilterHeadersStatus::Continue; } - Http::FilterDataStatus encodeData(Buffer::Instance&, bool end_stream) override; + Http::FilterDataStatus encodeData(Buffer::Instance&, bool) override { + return Http::FilterDataStatus::Continue; + } Http::FilterTrailersStatus encodeTrailers(Http::HeaderMap&) override { return Http::FilterTrailersStatus::Continue; } @@ -37,7 +42,7 @@ class AddTrailersStreamFilter : public Http::StreamFilter { encoder_callbacks_ = &callbacks; } -private: +protected: Http::StreamDecoderFilterCallbacks* decoder_callbacks_{}; Http::StreamEncoderFilterCallbacks* encoder_callbacks_{}; }; diff --git a/test/integration/filters/pause_filter.cc b/test/integration/filters/pause_filter.cc new file mode 100644 index 0000000000000..239c7fcf139fc --- /dev/null +++ b/test/integration/filters/pause_filter.cc @@ -0,0 +1,87 @@ +#include + +#include "envoy/registry/registry.h" + +#include "common/network/connection_impl.h" + +#include "extensions/filters/http/common/empty_http_filter_config.h" + +#include "test/integration/filters/pass_through_filter.h" + +namespace Envoy { + +// This filter exists to synthetically test network backup by faking TCP +// connection back-up when an encode is finished, and unblocking it when the +// next stream starts to decode headers. +// Allows regression tests for https://github.com/envoyproxy/envoy/issues/4541 +// TODO(alyssawilk) turn this up for more tests. +class TestPauseFilter : public PassThroughFilter { +public: + // Pass in a some global filter state to ensure the Network::Connection is + // blocked and unblocked exactly once. + TestPauseFilter(absl::Mutex& encode_lock, uint32_t& number_of_encode_calls_ref, + uint32_t& number_of_decode_calls_ref) + : encode_lock_(encode_lock), number_of_encode_calls_ref_(number_of_encode_calls_ref), + number_of_decode_calls_ref_(number_of_decode_calls_ref) {} + + Http::FilterDataStatus decodeData(Buffer::Instance& buf, bool end_stream) override { + if (end_stream) { + absl::WriterMutexLock m(&encode_lock_); + number_of_decode_calls_ref_++; + if (number_of_decode_calls_ref_ == 2) { + // If this is the second stream to decode headers, force low watermark state. + connection()->onLowWatermark(); + } + } + return PassThroughFilter::decodeData(buf, end_stream); + } + + Http::FilterDataStatus encodeData(Buffer::Instance& buf, bool end_stream) override { + if (end_stream) { + absl::WriterMutexLock m(&encode_lock_); + number_of_encode_calls_ref_++; + if (number_of_encode_calls_ref_ == 1) { + // If this is the first stream to encode headers, force high watermark state. + connection()->onHighWatermark(); + } + } + return PassThroughFilter::encodeData(buf, end_stream); + } + + Network::ConnectionImpl* connection() { + // As long as we're doing horrible things let's do *all* the horrible things. + // Assert the connection we have is a ConnectionImpl and const cast it so we + // can force watermark changes. + auto conn_impl = dynamic_cast(decoder_callbacks_->connection()); + return const_cast(conn_impl); + } + + absl::Mutex& encode_lock_; + uint32_t& number_of_encode_calls_ref_; + uint32_t& number_of_decode_calls_ref_; +}; + +class TestPauseFilterConfig : public Extensions::HttpFilters::Common::EmptyHttpFilterConfig { +public: + TestPauseFilterConfig() : EmptyHttpFilterConfig("pause-filter") {} + + Http::FilterFactoryCb createFilter(const std::string&, Server::Configuration::FactoryContext&) { + 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_); + callbacks.addStreamFilter(std::make_shared<::Envoy::TestPauseFilter>( + encode_lock_, number_of_encode_calls_, number_of_decode_calls_)); + }; + } + + absl::Mutex encode_lock_; + uint32_t number_of_encode_calls_ GUARDED_BY(encode_lock_) = 0; + uint32_t number_of_decode_calls_ GUARDED_BY(encode_lock_) = 0; +}; + +// perform static registration +static Registry::RegisterFactory + register_; + +} // namespace Envoy diff --git a/test/integration/http2_integration_test.cc b/test/integration/http2_integration_test.cc index 60f5c30e9d084..3c4dd561b407b 100644 --- a/test/integration/http2_integration_test.cc +++ b/test/integration/http2_integration_test.cc @@ -87,8 +87,12 @@ TEST_P(Http2IntegrationTest, RouterUpstreamResponseBeforeRequestComplete) { TEST_P(Http2IntegrationTest, TwoRequests) { testTwoRequests(); } +TEST_P(Http2IntegrationTest, TwoRequestsWithForcedBackup) { testTwoRequests(true); } + TEST_P(Http2IntegrationTest, Retry) { testRetry(); } +TEST_P(Http2IntegrationTest, RetryAttemptCount) { testRetryAttemptCountHeader(); } + TEST_P(Http2IntegrationTest, EnvoyHandling100Continue) { testEnvoyHandling100Continue(); } TEST_P(Http2IntegrationTest, EnvoyHandlingDuplicate100Continue) { diff --git a/test/integration/http_integration.cc b/test/integration/http_integration.cc index 2d0a5ed81ebe2..77e868068f923 100644 --- a/test/integration/http_integration.cc +++ b/test/integration/http_integration.cc @@ -10,12 +10,13 @@ #include "envoy/buffer/buffer.h" #include "envoy/event/dispatcher.h" #include "envoy/http/header_map.h" +#include "envoy/registry/registry.h" #include "common/api/api_impl.h" #include "common/buffer/buffer_impl.h" #include "common/common/fmt.h" +#include "common/common/thread_annotations.h" #include "common/http/headers.h" -#include "common/network/connection_impl.h" #include "common/network/utility.h" #include "common/protobuf/utility.h" #include "common/upstream/upstream_impl.h" @@ -734,6 +735,47 @@ void HttpIntegrationTest::testRetry() { EXPECT_EQ(512U, response->body().size()); } +// Tests that the x-envoy-attempt-count header is properly set on the upstream request +// and updated after the request is retried. +void HttpIntegrationTest::testRetryAttemptCountHeader() { + config_helper_.addRoute("host", "/test_retry", "cluster_0", false, + envoy::api::v2::route::RouteAction::NOT_FOUND, + envoy::api::v2::route::VirtualHost::NONE, {}, true); + initialize(); + codec_client_ = makeHttpConnection(lookupPort("http")); + auto response = + codec_client_->makeRequestWithBody(Http::TestHeaderMapImpl{{":method", "POST"}, + {":path", "/test_retry"}, + {":scheme", "http"}, + {":authority", "host"}, + {"x-forwarded-for", "10.0.0.1"}, + {"x-envoy-retry-on", "5xx"}}, + 1024); + waitForNextUpstreamRequest(); + upstream_request_->encodeHeaders(Http::TestHeaderMapImpl{{":status", "503"}}, false); + + EXPECT_EQ(atoi(upstream_request_->headers().EnvoyAttemptCount()->value().c_str()), 1); + + if (fake_upstreams_[0]->httpType() == FakeHttpConnection::Type::HTTP1) { + ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect()); + ASSERT_TRUE(fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, fake_upstream_connection_)); + } else { + ASSERT_TRUE(upstream_request_->waitForReset()); + } + waitForNextUpstreamRequest(); + EXPECT_EQ(atoi(upstream_request_->headers().EnvoyAttemptCount()->value().c_str()), 2); + upstream_request_->encodeHeaders(Http::TestHeaderMapImpl{{":status", "200"}}, false); + upstream_request_->encodeData(512, true); + + response->waitForEndStream(); + EXPECT_TRUE(upstream_request_->complete()); + EXPECT_EQ(1024U, upstream_request_->bodyLength()); + + EXPECT_TRUE(response->complete()); + EXPECT_STREQ("200", response->headers().Status()->value().c_str()); + EXPECT_EQ(512U, response->body().size()); +} + // Change the default route to be restrictive, and send a request to an alternate route. void HttpIntegrationTest::testGrpcRouterNotFound() { config_helper_.setDefaultHostAndRoute("foo.com", "/found"); @@ -1275,7 +1317,20 @@ void HttpIntegrationTest::testUpstreamDisconnectWithTwoRequests() { test_server_->waitForCounterGe("cluster.cluster_0.upstream_rq_200", 2); } -void HttpIntegrationTest::testTwoRequests() { +void HttpIntegrationTest::testTwoRequests(bool network_backup) { + // if network_backup is false, this simply tests that Envoy can handle multiple + // requests on a connection. + // + // If network_backup is true, the first request will explicitly set the TCP level flow control + // as blocked as it finishes the encode and set a timer to unblock. The second stream should be + // created while the socket appears to be in the high watermark state, and regression tests that + // flow control will be corrected as the socket "becomes unblocked" + if (network_backup) { + config_helper_.addFilter(R"EOF( + name: pause-filter + config: {} + )EOF"); + } initialize(); codec_client_ = makeHttpConnection(lookupPort("http")); diff --git a/test/integration/http_integration.h b/test/integration/http_integration.h index 30e2eb905e835..10308c2c6de2b 100644 --- a/test/integration/http_integration.h +++ b/test/integration/http_integration.h @@ -134,7 +134,7 @@ class HttpIntegrationTest : public BaseIntegrationTest { void testRouterDownstreamDisconnectBeforeResponseComplete( ConnectionCreationFunction* creator = nullptr); void testRouterUpstreamResponseBeforeRequestComplete(); - void testTwoRequests(); + void testTwoRequests(bool force_network_backup = false); void testOverlyLongHeaders(); void testIdleTimeoutBasic(); void testIdleTimeoutWithTwoRequests(); @@ -170,6 +170,7 @@ class HttpIntegrationTest : public BaseIntegrationTest { void testDrainClose(); void testRetry(); void testRetryHittingBufferLimit(); + void testRetryAttemptCountHeader(); void testGrpcRouterNotFound(); void testGrpcRetry(); void testRetryPriority(); diff --git a/test/integration/integration_admin_test.cc b/test/integration/integration_admin_test.cc index 075f6136451d1..c950e938bc0e7 100644 --- a/test/integration/integration_admin_test.cc +++ b/test/integration/integration_admin_test.cc @@ -1,9 +1,11 @@ #include "test/integration/integration_admin_test.h" #include "envoy/admin/v2alpha/config_dump.pb.h" +#include "envoy/config/metrics/v2/stats.pb.h" #include "envoy/http/header_map.h" #include "common/common/fmt.h" +#include "common/stats/stats_matcher_impl.h" #include "test/integration/utility.h" #include "test/test_common/utility.h" @@ -300,7 +302,7 @@ TEST_P(IntegrationAdminTest, Admin) { downstreamProtocol(), version_); EXPECT_TRUE(response->complete()); EXPECT_STREQ("200", response->headers().Status()->value().c_str()); - EXPECT_STREQ("text/plain; charset=UTF-8", ContentType(response)); + EXPECT_STREQ("application/json", ContentType(response)); response = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "GET", "/runtime", "", downstreamProtocol(), version_); @@ -442,4 +444,83 @@ TEST_F(IntegrationAdminIpv4Ipv6Test, Ipv4Ipv6Listen) { } } +// Testing the behavior of StatsMatcher, which allows/denies the instantiation of stats based on +// restrictions on their names. +class StatsMatcherIntegrationTest + : public HttpIntegrationTest, + public testing::Test, + public testing::WithParamInterface { +public: + StatsMatcherIntegrationTest() + : HttpIntegrationTest(Http::CodecClient::Type::HTTP1, GetParam(), simTime()) {} + + void initialize() override { + config_helper_.addConfigModifier( + [this](envoy::config::bootstrap::v2::Bootstrap& bootstrap) -> void { + *bootstrap.mutable_stats_config()->mutable_stats_matcher() = stats_matcher_; + }); + HttpIntegrationTest::initialize(); + } + void makeRequest() { + response_ = IntegrationUtil::makeSingleRequest(lookupPort("admin"), "GET", "/stats", "", + downstreamProtocol(), version_); + ASSERT_TRUE(response_->complete()); + EXPECT_STREQ("200", response_->headers().Status()->value().c_str()); + } + + BufferingStreamDecoderPtr response_; + envoy::config::metrics::v2::StatsMatcher stats_matcher_; +}; +INSTANTIATE_TEST_CASE_P(IpVersions, StatsMatcherIntegrationTest, + testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), + TestUtility::ipTestParamsToString); + +// Verify that StatsMatcher prevents the printing of uninstantiated stats. +TEST_P(StatsMatcherIntegrationTest, ExcludePrefixServerDot) { + stats_matcher_.mutable_exclusion_list()->add_patterns()->set_prefix("server."); + initialize(); + makeRequest(); + EXPECT_THAT(response_->body(), testing::Not(testing::HasSubstr("server."))); +} + +TEST_P(StatsMatcherIntegrationTest, ExcludeRequests) { + stats_matcher_.mutable_exclusion_list()->add_patterns()->set_regex(".*requests.*"); + initialize(); + makeRequest(); + EXPECT_THAT(response_->body(), testing::Not(testing::HasSubstr("requests"))); +} + +TEST_P(StatsMatcherIntegrationTest, ExcludeExact) { + stats_matcher_.mutable_exclusion_list()->add_patterns()->set_exact("server.concurrency"); + initialize(); + makeRequest(); + EXPECT_THAT(response_->body(), testing::Not(testing::HasSubstr("server.concurrency"))); +} + +TEST_P(StatsMatcherIntegrationTest, ExcludeMultipleExact) { + stats_matcher_.mutable_exclusion_list()->add_patterns()->set_exact("server.concurrency"); + stats_matcher_.mutable_exclusion_list()->add_patterns()->set_regex(".*live"); + initialize(); + makeRequest(); + EXPECT_THAT(response_->body(), testing::Not(testing::HasSubstr("server.concurrency"))); + EXPECT_THAT(response_->body(), testing::Not(testing::HasSubstr("server.live"))); +} + +// TODO(ambuc): Find a cleaner way to test this. This test has two unfortunate compromises: +// +// - a) `listener_manager.listener_create_success` must be instantiated, because BaseIntegrationTest +// blocks on its creation (see waitForCounterGe and the suite of waitFor* functions), and +// - b) `stats.overflow` isn't blocked from instantiation, because it occurs at ThreadLocalStore +// construction time, before setStatsMatcher() is called. +// +// If either of these invariants is changed, this test must be rewritten. +TEST_P(StatsMatcherIntegrationTest, IncludeExact) { + stats_matcher_.mutable_inclusion_list()->add_patterns()->set_exact( + "listener_manager.listener_create_success"); + initialize(); + makeRequest(); + EXPECT_THAT(response_->body(), + testing::Eq("listener_manager.listener_create_success: 1\nstats.overflow: 0\n")); +} + } // namespace Envoy diff --git a/test/integration/integration_test.cc b/test/integration/integration_test.cc index ed73f001a2538..fe0103724c727 100644 --- a/test/integration/integration_test.cc +++ b/test/integration/integration_test.cc @@ -109,6 +109,8 @@ TEST_P(IntegrationTest, RouterUpstreamResponseBeforeRequestComplete) { TEST_P(IntegrationTest, Retry) { testRetry(); } +TEST_P(IntegrationTest, RetryAttemptCount) { testRetryAttemptCountHeader(); } + TEST_P(IntegrationTest, RetryHostPredicateFilter) { testRetryHostPredicateFilter(); } TEST_P(IntegrationTest, RetryPriority) { testRetryPriority(); } @@ -131,6 +133,8 @@ TEST_P(IntegrationTest, EnvoyProxyingLate100ContinueWithEncoderFilter) { TEST_P(IntegrationTest, TwoRequests) { testTwoRequests(); } +TEST_P(IntegrationTest, TwoRequestsWithForcedBackup) { testTwoRequests(true); } + TEST_P(IntegrationTest, UpstreamDisconnectWithTwoRequests) { testUpstreamDisconnectWithTwoRequests(); } diff --git a/test/integration/overload_integration_test.cc b/test/integration/overload_integration_test.cc index d7068d0fd1961..ddfdb34225b36 100644 --- a/test/integration/overload_integration_test.cc +++ b/test/integration/overload_integration_test.cc @@ -31,6 +31,11 @@ class OverloadIntegrationTest : public HttpProtocolIntegrationTest { - name: "envoy.resource_monitors.injected_resource" threshold: value: 0.8 + - name: "envoy.overload_actions.stop_accepting_connections" + triggers: + - name: "envoy.resource_monitors.injected_resource" + threshold: + value: 0.95 )EOF", injected_resource_filename_); *bootstrap.mutable_overload_manager() = @@ -118,4 +123,32 @@ TEST_P(OverloadIntegrationTest, DisableKeepaliveWhenOverloaded) { EXPECT_EQ(nullptr, response->headers().Connection()); } +TEST_P(OverloadIntegrationTest, StopAcceptingConnectionsWhenOverloaded) { + initialize(); + fake_upstreams_[0]->set_allow_unexpected_disconnects(true); + + // Put envoy in overloaded state and check that it doesn't accept the new client connection. + updateResource(0.95); + test_server_->waitForGaugeEq("overload.envoy.overload_actions.stop_accepting_connections.active", + 1); + codec_client_ = makeHttpConnection(makeClientConnection((lookupPort("http")))); + Http::TestHeaderMapImpl request_headers{ + {":method", "GET"}, {":path", "/test/long/url"}, {":scheme", "http"}, {":authority", "host"}}; + auto response = codec_client_->makeRequestWithBody(request_headers, 10); + EXPECT_FALSE(fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, fake_upstream_connection_, + std::chrono::milliseconds(1000))); + + // Reduce load a little to allow the connection to be accepted but then immediately reject the + // request. + updateResource(0.9); + test_server_->waitForGaugeEq("overload.envoy.overload_actions.stop_accepting_connections.active", + 0); + response->waitForEndStream(); + + EXPECT_TRUE(response->complete()); + EXPECT_STREQ("503", response->headers().Status()->value().c_str()); + EXPECT_EQ("envoy overloaded", response->body()); + codec_client_->close(); +} + } // namespace Envoy diff --git a/test/integration/server.h b/test/integration/server.h index 5cf158e8c2f78..df4ea5b1f6e15 100644 --- a/test/integration/server.h +++ b/test/integration/server.h @@ -198,6 +198,7 @@ class TestIsolatedStoreImpl : public StoreRoot { // Stats::StoreRoot void addSink(Sink&) override {} void setTagProducer(TagProducerPtr&&) override {} + void setStatsMatcher(StatsMatcherPtr&&) override {} void initializeThreading(Event::Dispatcher&, ThreadLocal::Instance&) override {} void shutdownThreading() override {} void mergeHistograms(PostMergeCb) override {} diff --git a/test/integration/test_host_predicate_config.h b/test/integration/test_host_predicate_config.h index 47b092658d4e2..a8668e1b883f6 100644 --- a/test/integration/test_host_predicate_config.h +++ b/test/integration/test_host_predicate_config.h @@ -13,5 +13,8 @@ class TestHostPredicateFactory : public Upstream::RetryHostPredicateFactory { const Protobuf::Message&, uint32_t) override { callbacks.addHostPredicate(std::make_shared()); } + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return ProtobufTypes::MessagePtr{new Envoy::ProtobufWkt::Empty()}; + } }; } // namespace Envoy diff --git a/test/mocks/access_log/BUILD b/test/mocks/access_log/BUILD index 476c8037ffd77..58bbae8a0aa7b 100644 --- a/test/mocks/access_log/BUILD +++ b/test/mocks/access_log/BUILD @@ -14,7 +14,7 @@ envoy_cc_mock( hdrs = ["mocks.h"], deps = [ "//include/envoy/access_log:access_log_interface", - "//include/envoy/request_info:request_info_interface", + "//include/envoy/stream_info:stream_info_interface", "//test/mocks/filesystem:filesystem_mocks", ], ) diff --git a/test/mocks/access_log/mocks.h b/test/mocks/access_log/mocks.h index 2809f3da84bfa..c96aee7c84289 100644 --- a/test/mocks/access_log/mocks.h +++ b/test/mocks/access_log/mocks.h @@ -19,7 +19,7 @@ class MockFilter : public Filter { // AccessLog::Filter MOCK_METHOD2(evaluate, - bool(const RequestInfo::RequestInfo& info, const Http::HeaderMap& request_headers)); + bool(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers)); }; class MockAccessLogManager : public AccessLogManager { @@ -43,7 +43,7 @@ class MockInstance : public Instance { MOCK_METHOD4(log, void(const Http::HeaderMap* request_headers, const Http::HeaderMap* response_headers, const Http::HeaderMap* response_trailers, - const RequestInfo::RequestInfo& request_info)); + const StreamInfo::StreamInfo& stream_info)); }; } // namespace AccessLog diff --git a/test/mocks/http/BUILD b/test/mocks/http/BUILD index 23d388e47b5cc..e76b2102634bb 100644 --- a/test/mocks/http/BUILD +++ b/test/mocks/http/BUILD @@ -28,8 +28,8 @@ envoy_cc_mock( "//include/envoy/tracing:http_tracer_interface", "//source/common/http:header_map_lib", "//test/mocks/event:event_mocks", - "//test/mocks/request_info:request_info_mocks", "//test/mocks/router:router_mocks", + "//test/mocks/stream_info:stream_info_mocks", "//test/mocks/tracing:tracing_mocks", "//test/mocks/upstream:host_mocks", ], diff --git a/test/mocks/http/mocks.cc b/test/mocks/http/mocks.cc index 45e7244bf3fc7..47d115a07dd58 100644 --- a/test/mocks/http/mocks.cc +++ b/test/mocks/http/mocks.cc @@ -68,9 +68,11 @@ MockFilterChainFactory::MockFilterChainFactory() {} MockFilterChainFactory::~MockFilterChainFactory() {} template static void initializeMockStreamFilterCallbacks(T& callbacks) { + callbacks.cluster_info_.reset(new NiceMock()); callbacks.route_.reset(new NiceMock()); ON_CALL(callbacks, dispatcher()).WillByDefault(ReturnRef(callbacks.dispatcher_)); - ON_CALL(callbacks, requestInfo()).WillByDefault(ReturnRef(callbacks.request_info_)); + ON_CALL(callbacks, streamInfo()).WillByDefault(ReturnRef(callbacks.stream_info_)); + ON_CALL(callbacks, clusterInfo()).WillByDefault(Return(callbacks.cluster_info_)); ON_CALL(callbacks, route()).WillByDefault(Return(callbacks.route_)); } diff --git a/test/mocks/http/mocks.h b/test/mocks/http/mocks.h index 6af762bfc7688..ce95ac6c85d5e 100644 --- a/test/mocks/http/mocks.h +++ b/test/mocks/http/mocks.h @@ -19,9 +19,10 @@ #include "test/mocks/common.h" #include "test/mocks/event/mocks.h" -#include "test/mocks/request_info/mocks.h" #include "test/mocks/router/mocks.h" +#include "test/mocks/stream_info/mocks.h" #include "test/mocks/tracing/mocks.h" +#include "test/mocks/upstream/cluster_info.h" #include "test/mocks/upstream/host.h" #include "test/test_common/printers.h" @@ -175,8 +176,9 @@ class MockFilterChainFactory : public FilterChainFactory { class MockStreamFilterCallbacksBase { public: Event::MockDispatcher dispatcher_; - testing::NiceMock request_info_; + testing::NiceMock stream_info_; std::shared_ptr route_; + std::shared_ptr cluster_info_; }; class MockStreamDecoderFilterCallbacks : public StreamDecoderFilterCallbacks, @@ -189,10 +191,11 @@ class MockStreamDecoderFilterCallbacks : public StreamDecoderFilterCallbacks, MOCK_METHOD0(connection, const Network::Connection*()); MOCK_METHOD0(dispatcher, Event::Dispatcher&()); MOCK_METHOD0(resetStream, void()); + MOCK_METHOD0(clusterInfo, Upstream::ClusterInfoConstSharedPtr()); MOCK_METHOD0(route, Router::RouteConstSharedPtr()); MOCK_METHOD0(clearRouteCache, void()); MOCK_METHOD0(streamId, uint64_t()); - MOCK_METHOD0(requestInfo, RequestInfo::RequestInfo&()); + MOCK_METHOD0(streamInfo, StreamInfo::StreamInfo&()); MOCK_METHOD0(activeSpan, Tracing::Span&()); MOCK_METHOD0(tracingConfig, Tracing::Config&()); MOCK_METHOD0(onDecoderFilterAboveWriteBufferHighWatermark, void()); @@ -252,10 +255,11 @@ class MockStreamEncoderFilterCallbacks : public StreamEncoderFilterCallbacks, MOCK_METHOD0(connection, const Network::Connection*()); MOCK_METHOD0(dispatcher, Event::Dispatcher&()); MOCK_METHOD0(resetStream, void()); + MOCK_METHOD0(clusterInfo, Upstream::ClusterInfoConstSharedPtr()); MOCK_METHOD0(route, Router::RouteConstSharedPtr()); MOCK_METHOD0(clearRouteCache, void()); MOCK_METHOD0(streamId, uint64_t()); - MOCK_METHOD0(requestInfo, RequestInfo::RequestInfo&()); + MOCK_METHOD0(streamInfo, StreamInfo::StreamInfo&()); MOCK_METHOD0(activeSpan, Tracing::Span&()); MOCK_METHOD0(tracingConfig, Tracing::Config&()); MOCK_METHOD0(onEncoderFilterAboveWriteBufferHighWatermark, void()); diff --git a/test/mocks/network/BUILD b/test/mocks/network/BUILD index d4902e224b870..8d71ea0f4ed24 100644 --- a/test/mocks/network/BUILD +++ b/test/mocks/network/BUILD @@ -22,8 +22,8 @@ envoy_cc_mock( "//include/envoy/server:listener_manager_interface", "//source/common/network:address_lib", "//source/common/network:utility_lib", - "//source/common/request_info:filter_state_lib", "//source/common/stats:isolated_store_lib", + "//source/common/stream_info:filter_state_lib", "//test/mocks/event:event_mocks", "//test/test_common:printers_lib", "@envoy_api//envoy/api/v2/core:base_cc", diff --git a/test/mocks/network/mocks.h b/test/mocks/network/mocks.h index a7b8303d40b51..c3b9e05f9bfa3 100644 --- a/test/mocks/network/mocks.h +++ b/test/mocks/network/mocks.h @@ -13,8 +13,8 @@ #include "envoy/network/transport_socket.h" #include "envoy/stats/scope.h" -#include "common/request_info/filter_state_impl.h" #include "common/stats/isolated_store_impl.h" +#include "common/stream_info/filter_state_impl.h" #include "test/mocks/event/mocks.h" #include "test/test_common/printers.h" @@ -51,7 +51,7 @@ class MockConnectionBase { Address::InstanceConstSharedPtr remote_address_; Address::InstanceConstSharedPtr local_address_; bool read_enabled_{true}; - RequestInfo::FilterStateImpl per_connection_state_; + StreamInfo::FilterStateImpl per_connection_state_; Connection::State state_{Connection::State::Open}; }; @@ -88,8 +88,8 @@ class MockConnection : public Connection, public MockConnectionBase { MOCK_CONST_METHOD0(localAddressRestored, bool()); MOCK_CONST_METHOD0(aboveHighWatermark, bool()); MOCK_CONST_METHOD0(socketOptions, const Network::ConnectionSocket::OptionsSharedPtr&()); - MOCK_METHOD0(perConnectionState, RequestInfo::FilterState&()); - MOCK_CONST_METHOD0(perConnectionState, const RequestInfo::FilterState&()); + MOCK_METHOD0(perConnectionState, StreamInfo::FilterState&()); + MOCK_CONST_METHOD0(perConnectionState, const StreamInfo::FilterState&()); MOCK_METHOD1(setDelayedCloseTimeout, void(std::chrono::milliseconds)); MOCK_CONST_METHOD0(delayedCloseTimeout, std::chrono::milliseconds()); }; @@ -131,8 +131,8 @@ class MockClientConnection : public ClientConnection, public MockConnectionBase MOCK_CONST_METHOD0(localAddressRestored, bool()); MOCK_CONST_METHOD0(aboveHighWatermark, bool()); MOCK_CONST_METHOD0(socketOptions, const Network::ConnectionSocket::OptionsSharedPtr&()); - MOCK_METHOD0(perConnectionState, RequestInfo::FilterState&()); - MOCK_CONST_METHOD0(perConnectionState, const RequestInfo::FilterState&()); + MOCK_METHOD0(perConnectionState, StreamInfo::FilterState&()); + MOCK_CONST_METHOD0(perConnectionState, const StreamInfo::FilterState&()); MOCK_METHOD1(setDelayedCloseTimeout, void(std::chrono::milliseconds)); MOCK_CONST_METHOD0(delayedCloseTimeout, std::chrono::milliseconds()); @@ -382,6 +382,8 @@ class MockListener : public Listener { ~MockListener(); MOCK_METHOD0(onDestroy, void()); + MOCK_METHOD0(enable, void()); + MOCK_METHOD0(disable, void()); }; class MockConnectionHandler : public ConnectionHandler { @@ -396,6 +398,8 @@ class MockConnectionHandler : public ConnectionHandler { MOCK_METHOD1(removeListeners, void(uint64_t listener_tag)); MOCK_METHOD1(stopListeners, void(uint64_t listener_tag)); MOCK_METHOD0(stopListeners, void()); + MOCK_METHOD0(disableListeners, void()); + MOCK_METHOD0(enableListeners, void()); }; class MockIp : public Address::Ip { diff --git a/test/mocks/router/mocks.h b/test/mocks/router/mocks.h index 78f5640d7ce87..1bc5bffc590b6 100644 --- a/test/mocks/router/mocks.h +++ b/test/mocks/router/mocks.h @@ -33,7 +33,7 @@ class MockDirectResponseEntry : public DirectResponseEntry { // DirectResponseEntry MOCK_CONST_METHOD2(finalizeResponseHeaders, - void(Http::HeaderMap& headers, const RequestInfo::RequestInfo& request_info)); + void(Http::HeaderMap& headers, const StreamInfo::StreamInfo& stream_info)); MOCK_CONST_METHOD1(newPath, std::string(const Http::HeaderMap& headers)); MOCK_CONST_METHOD2(rewritePathHeader, void(Http::HeaderMap& headers, bool insert_envoy_original_path)); @@ -72,11 +72,15 @@ class TestRetryPolicy : public RetryPolicy { MOCK_CONST_METHOD0(retryHostPredicates, std::vector()); MOCK_CONST_METHOD0(retryPriority, Upstream::RetryPrioritySharedPtr()); uint32_t hostSelectionMaxAttempts() const override { return host_selection_max_attempts_; } + const std::vector& retriableStatusCodes() const override { + return retriable_status_codes_; + } std::chrono::milliseconds per_try_timeout_{0}; uint32_t num_retries_{}; uint32_t retry_on_{}; uint32_t host_selection_max_attempts_; + std::vector retriable_status_codes_; }; class MockRetryState : public RetryState { @@ -175,6 +179,7 @@ class MockVirtualHost : public VirtualHost { MOCK_CONST_METHOD0(corsPolicy, const CorsPolicy*()); MOCK_CONST_METHOD0(routeConfig, const Config&()); MOCK_CONST_METHOD1(perFilterConfig, const RouteSpecificFilterConfig*(const std::string&)); + MOCK_CONST_METHOD0(includeAttemptCount, bool()); MOCK_METHOD0(retryPriority, Upstream::RetryPrioritySharedPtr()); MOCK_METHOD0(retryHostPredicate, Upstream::RetryHostPredicateSharedPtr()); @@ -228,10 +233,10 @@ class MockRouteEntry : public RouteEntry { MOCK_CONST_METHOD0(clusterName, const std::string&()); MOCK_CONST_METHOD0(clusterNotFoundResponseCode, Http::Code()); MOCK_CONST_METHOD3(finalizeRequestHeaders, - void(Http::HeaderMap& headers, const RequestInfo::RequestInfo& request_info, + void(Http::HeaderMap& headers, const StreamInfo::StreamInfo& stream_info, bool insert_envoy_original_path)); MOCK_CONST_METHOD2(finalizeResponseHeaders, - void(Http::HeaderMap& headers, const RequestInfo::RequestInfo& request_info)); + void(Http::HeaderMap& headers, const StreamInfo::StreamInfo& stream_info)); MOCK_CONST_METHOD0(hashPolicy, const HashPolicy*()); MOCK_CONST_METHOD0(metadataMatchCriteria, const Router::MetadataMatchCriteria*()); MOCK_CONST_METHOD0(priority, Upstream::ResourcePriority()); @@ -248,7 +253,7 @@ class MockRouteEntry : public RouteEntry { MOCK_CONST_METHOD0(useOldStyleWebSocket, bool()); MOCK_CONST_METHOD5(createWebSocketProxy, Http::WebSocketProxyPtr(Http::HeaderMap& request_headers, - RequestInfo::RequestInfo& request_info, + StreamInfo::StreamInfo& stream_info, Http::WebSocketProxyCallbacks& callbacks, Upstream::ClusterManager& cluster_manager, Network::ReadFilterCallbacks* read_callbacks)); @@ -258,6 +263,7 @@ class MockRouteEntry : public RouteEntry { MOCK_CONST_METHOD0(metadata, const envoy::api::v2::core::Metadata&()); MOCK_CONST_METHOD0(pathMatchCriterion, const PathMatchCriterion&()); MOCK_CONST_METHOD1(perFilterConfig, const RouteSpecificFilterConfig*(const std::string&)); + MOCK_CONST_METHOD0(includeAttemptCount, bool()); std::string cluster_name_{"fake_cluster"}; std::multimap opaque_config_; diff --git a/test/mocks/server/mocks.h b/test/mocks/server/mocks.h index fea43729f4d43..a50559e3e5483 100644 --- a/test/mocks/server/mocks.h +++ b/test/mocks/server/mocks.h @@ -244,7 +244,7 @@ class MockWorkerFactory : public WorkerFactory { ~MockWorkerFactory(); // Server::WorkerFactory - WorkerPtr createWorker() override { return WorkerPtr{createWorker_()}; } + WorkerPtr createWorker(OverloadManager&) override { return WorkerPtr{createWorker_()}; } MOCK_METHOD0(createWorker_, Worker*()); }; diff --git a/test/mocks/ssl/mocks.h b/test/mocks/ssl/mocks.h index 8ab686d1aa370..5e268cdb35b03 100644 --- a/test/mocks/ssl/mocks.h +++ b/test/mocks/ssl/mocks.h @@ -53,8 +53,8 @@ class MockClientContext : public ClientContext { ~MockClientContext(); MOCK_CONST_METHOD0(daysUntilFirstCertExpires, size_t()); - MOCK_CONST_METHOD0(getCaCertInformation, std::string()); - MOCK_CONST_METHOD0(getCertChainInformation, std::string()); + MOCK_CONST_METHOD0(getCaCertInformation, CertificateDetailsPtr()); + MOCK_CONST_METHOD0(getCertChainInformation, CertificateDetailsPtr()); }; } // namespace Ssl diff --git a/test/mocks/request_info/BUILD b/test/mocks/stream_info/BUILD similarity index 77% rename from test/mocks/request_info/BUILD rename to test/mocks/stream_info/BUILD index 7519d0922397c..cacb79ac8006f 100644 --- a/test/mocks/request_info/BUILD +++ b/test/mocks/stream_info/BUILD @@ -9,11 +9,11 @@ load( envoy_package() envoy_cc_mock( - name = "request_info_mocks", + name = "stream_info_mocks", srcs = ["mocks.cc"], hdrs = ["mocks.h"], deps = [ - "//include/envoy/request_info:request_info_interface", + "//include/envoy/stream_info:stream_info_interface", "//include/envoy/upstream:upstream_interface", "//test/mocks/upstream:host_mocks", ], diff --git a/test/mocks/request_info/mocks.cc b/test/mocks/stream_info/mocks.cc similarity index 95% rename from test/mocks/request_info/mocks.cc rename to test/mocks/stream_info/mocks.cc index 61505d529196b..d535c16fa2842 100644 --- a/test/mocks/request_info/mocks.cc +++ b/test/mocks/stream_info/mocks.cc @@ -1,4 +1,4 @@ -#include "test/mocks/request_info/mocks.h" +#include "test/mocks/stream_info/mocks.h" #include "common/network/address_impl.h" @@ -12,9 +12,9 @@ using testing::ReturnPointee; using testing::ReturnRef; namespace Envoy { -namespace RequestInfo { +namespace StreamInfo { -MockRequestInfo::MockRequestInfo() +MockStreamInfo::MockStreamInfo() : downstream_local_address_(new Network::Address::Ipv4Instance("127.0.0.2")), downstream_remote_address_(new Network::Address::Ipv4Instance("127.0.0.1")) { ON_CALL(*this, upstreamHost()).WillByDefault(ReturnPointee(&host_)); @@ -72,7 +72,7 @@ MockRequestInfo::MockRequestInfo() ON_CALL(*this, requestedServerName()).WillByDefault(ReturnRef(requested_server_name_)); } -MockRequestInfo::~MockRequestInfo() {} +MockStreamInfo::~MockStreamInfo() {} -} // namespace RequestInfo +} // namespace StreamInfo } // namespace Envoy diff --git a/test/mocks/request_info/mocks.h b/test/mocks/stream_info/mocks.h similarity index 94% rename from test/mocks/request_info/mocks.h rename to test/mocks/stream_info/mocks.h index 31f95894e792a..efe147060707d 100644 --- a/test/mocks/request_info/mocks.h +++ b/test/mocks/stream_info/mocks.h @@ -1,22 +1,22 @@ #pragma once -#include "envoy/request_info/request_info.h" +#include "envoy/stream_info/stream_info.h" -#include "common/request_info/filter_state_impl.h" +#include "common/stream_info/filter_state_impl.h" #include "test/mocks/upstream/host.h" #include "gmock/gmock.h" namespace Envoy { -namespace RequestInfo { +namespace StreamInfo { -class MockRequestInfo : public RequestInfo { +class MockStreamInfo : public StreamInfo { public: - MockRequestInfo(); - ~MockRequestInfo(); + MockStreamInfo(); + ~MockStreamInfo(); - // RequestInfo::RequestInfo + // StreamInfo::StreamInfo MOCK_METHOD1(setResponseFlag, void(ResponseFlag response_flag)); MOCK_CONST_METHOD1(intersectResponseFlags, bool(uint64_t)); MOCK_METHOD1(onUpstreamHostSelected, void(Upstream::HostDescriptionConstSharedPtr host)); @@ -91,5 +91,5 @@ class MockRequestInfo : public RequestInfo { std::string requested_server_name_; }; -} // namespace RequestInfo +} // namespace StreamInfo } // namespace Envoy diff --git a/test/mocks/tracing/mocks.h b/test/mocks/tracing/mocks.h index a9b48ccd1afdf..524baacd6fc37 100644 --- a/test/mocks/tracing/mocks.h +++ b/test/mocks/tracing/mocks.h @@ -48,13 +48,13 @@ class MockHttpTracer : public HttpTracer { ~MockHttpTracer(); SpanPtr startSpan(const Config& config, Http::HeaderMap& request_headers, - const RequestInfo::RequestInfo& request_info, + const StreamInfo::StreamInfo& stream_info, const Tracing::Decision tracing_decision) override { - return SpanPtr{startSpan_(config, request_headers, request_info, tracing_decision)}; + return SpanPtr{startSpan_(config, request_headers, stream_info, tracing_decision)}; } MOCK_METHOD4(startSpan_, Span*(const Config& config, Http::HeaderMap& request_headers, - const RequestInfo::RequestInfo& request_info, + const StreamInfo::StreamInfo& stream_info, const Tracing::Decision tracing_decision)); }; diff --git a/test/mocks/upstream/mocks.h b/test/mocks/upstream/mocks.h index db7b7f34c69c1..d6e51b61c5da4 100644 --- a/test/mocks/upstream/mocks.h +++ b/test/mocks/upstream/mocks.h @@ -124,6 +124,9 @@ class MockRetryPriorityFactory : public RetryPriorityFactory { } std::string name() const override { return "envoy.mock_retry_priority"; } + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return ProtobufTypes::MessagePtr{new Envoy::ProtobufWkt::Empty()}; + } private: RetryPrioritySharedPtr retry_priority_; diff --git a/test/server/http/BUILD b/test/server/http/BUILD index cf1fdc52859cd..10d71e76d41ed 100644 --- a/test/server/http/BUILD +++ b/test/server/http/BUILD @@ -19,6 +19,7 @@ envoy_cc_test( "//source/common/profiler:profiler_lib", "//source/common/protobuf", "//source/common/protobuf:utility_lib", + "//source/common/ssl:context_config_lib", "//source/common/stats:thread_local_store_lib", "//source/server/http:admin_lib", "//test/mocks/runtime:runtime_mocks", diff --git a/test/server/http/admin_test.cc b/test/server/http/admin_test.cc index ea248805d2a37..78a95bcda9622 100644 --- a/test/server/http/admin_test.cc +++ b/test/server/http/admin_test.cc @@ -12,6 +12,7 @@ #include "common/profiler/profiler.h" #include "common/protobuf/protobuf.h" #include "common/protobuf/utility.h" +#include "common/ssl/context_config_impl.h" #include "common/stats/thread_local_store.h" #include "server/http/admin.h" @@ -834,6 +835,35 @@ TEST_P(AdminInstanceTest, Memory) { Property(&envoy::admin::v2alpha::Memory::heap_size, Ge(0)))); } +TEST_P(AdminInstanceTest, ContextThatReturnsNullCertDetails) { + Http::HeaderMapImpl header_map; + Buffer::OwnedImpl response; + + // Setup a context that returns null cert details. + testing::NiceMock factory_context; + Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString("{}"); + Ssl::ClientContextConfigImpl cfg(*loader, factory_context); + Stats::IsolatedStoreImpl store; + Ssl::ClientContextSharedPtr client_ctx( + server_.sslContextManager().createSslClientContext(store, cfg)); + + const std::string expected_empty_json = R"EOF({ + "certificates": [ + { + "ca_cert": [], + "cert_chain": [] + } + ] +} +)EOF"; + + // Validate that cert details are null and /certs handles it correctly. + EXPECT_EQ(nullptr, client_ctx->getCaCertInformation()); + EXPECT_EQ(nullptr, client_ctx->getCertChainInformation()); + EXPECT_EQ(Http::Code::OK, getCallback("/certs", header_map, response)); + EXPECT_EQ(expected_empty_json, response.toString()); +} + TEST_P(AdminInstanceTest, Runtime) { Http::HeaderMapImpl header_map; Buffer::OwnedImpl response; diff --git a/test/server/worker_impl_test.cc b/test/server/worker_impl_test.cc index 6bb93191ea327..7dca863734795 100644 --- a/test/server/worker_impl_test.cc +++ b/test/server/worker_impl_test.cc @@ -34,9 +34,10 @@ class WorkerImplTest : public testing::Test { Event::DispatcherImpl* dispatcher_ = new Event::DispatcherImpl(test_time.timeSystem()); Network::MockConnectionHandler* handler_ = new Network::MockConnectionHandler(); NiceMock guard_dog_; + NiceMock overload_manager_; DefaultTestHooks hooks_; WorkerImpl worker_{tls_, hooks_, Event::DispatcherPtr{dispatcher_}, - Network::ConnectionHandlerPtr{handler_}}; + Network::ConnectionHandlerPtr{handler_}, overload_manager_}; Event::TimerPtr no_exit_timer_ = dispatcher_->createTimer([]() -> void {}); }; diff --git a/test/test_common/utility.cc b/test/test_common/utility.cc index 04709a85027da..fb9d62512f81e 100644 --- a/test/test_common/utility.cc +++ b/test/test_common/utility.cc @@ -119,21 +119,11 @@ void TestUtility::feedBufferWithRandomCharacters(Buffer::Instance& buffer, uint6 } Stats::CounterSharedPtr TestUtility::findCounter(Stats::Store& store, const std::string& name) { - for (auto counter : store.counters()) { - if (counter->name() == name) { - return counter; - } - } - return nullptr; + return findByName(store.counters(), name); } Stats::GaugeSharedPtr TestUtility::findGauge(Stats::Store& store, const std::string& name) { - for (auto gauge : store.gauges()) { - if (gauge->name() == name) { - return gauge; - } - } - return nullptr; + return findByName(store.gauges(), name); } std::list diff --git a/test/test_common/utility.h b/test/test_common/utility.h index 99857901a36d7..8abb5477d1d78 100644 --- a/test/test_common/utility.h +++ b/test/test_common/utility.h @@ -129,6 +129,21 @@ class TestUtility { static void feedBufferWithRandomCharacters(Buffer::Instance& buffer, uint64_t n_char, uint64_t seed = 0); + /** + * Finds a stat in a vector with the given name. + * @param name the stat name to look for. + * @param v the vector of stats. + * @return the stat + */ + template static T findByName(const std::vector& v, const std::string& name) { + auto pos = std::find_if(v.begin(), v.end(), + [&name](const T& stat) -> bool { return stat->name() == name; }); + if (pos == v.end()) { + return nullptr; + } + return *pos; + } + /** * Find a counter in a stats store. * @param store supplies the stats store. diff --git a/test/tools/router_check/router.cc b/test/tools/router_check/router.cc index 84503eb90e813..786a50e8d718f 100644 --- a/test/tools/router_check/router.cc +++ b/test/tools/router_check/router.cc @@ -7,7 +7,7 @@ #include "common/network/utility.h" #include "common/protobuf/utility.h" -#include "common/request_info/request_info_impl.h" +#include "common/stream_info/stream_info_impl.h" #include "test/test_common/printers.h" @@ -154,10 +154,10 @@ bool RouterCheckTool::compareVirtualHost(ToolConfig& tool_config, const std::str bool RouterCheckTool::compareRewritePath(ToolConfig& tool_config, const std::string& expected) { std::string actual = ""; - Envoy::RequestInfo::RequestInfoImpl request_info(Envoy::Http::Protocol::Http11, - factory_context_->dispatcher().timeSystem()); + Envoy::StreamInfo::StreamInfoImpl stream_info(Envoy::Http::Protocol::Http11, + factory_context_->dispatcher().timeSystem()); if (tool_config.route_->routeEntry() != nullptr) { - tool_config.route_->routeEntry()->finalizeRequestHeaders(*tool_config.headers_, request_info, + tool_config.route_->routeEntry()->finalizeRequestHeaders(*tool_config.headers_, stream_info, true); actual = tool_config.headers_->get_(Http::Headers::get().Path); } @@ -166,10 +166,10 @@ bool RouterCheckTool::compareRewritePath(ToolConfig& tool_config, const std::str bool RouterCheckTool::compareRewriteHost(ToolConfig& tool_config, const std::string& expected) { std::string actual = ""; - Envoy::RequestInfo::RequestInfoImpl request_info(Envoy::Http::Protocol::Http11, - factory_context_->dispatcher().timeSystem()); + Envoy::StreamInfo::StreamInfoImpl stream_info(Envoy::Http::Protocol::Http11, + factory_context_->dispatcher().timeSystem()); if (tool_config.route_->routeEntry() != nullptr) { - tool_config.route_->routeEntry()->finalizeRequestHeaders(*tool_config.headers_, request_info, + tool_config.route_->routeEntry()->finalizeRequestHeaders(*tool_config.headers_, stream_info, true); actual = tool_config.headers_->get_(Http::Headers::get().Host); } @@ -194,11 +194,11 @@ bool RouterCheckTool::compareHeaderField(ToolConfig& tool_config, const std::str bool RouterCheckTool::compareCustomHeaderField(ToolConfig& tool_config, const std::string& field, const std::string& expected) { std::string actual = ""; - Envoy::RequestInfo::RequestInfoImpl request_info(Envoy::Http::Protocol::Http11, - factory_context_->dispatcher().timeSystem()); - request_info.setDownstreamRemoteAddress(Network::Utility::getCanonicalIpv4LoopbackAddress()); + Envoy::StreamInfo::StreamInfoImpl stream_info(Envoy::Http::Protocol::Http11, + factory_context_->dispatcher().timeSystem()); + stream_info.setDownstreamRemoteAddress(Network::Utility::getCanonicalIpv4LoopbackAddress()); if (tool_config.route_->routeEntry() != nullptr) { - tool_config.route_->routeEntry()->finalizeRequestHeaders(*tool_config.headers_, request_info, + tool_config.route_->routeEntry()->finalizeRequestHeaders(*tool_config.headers_, stream_info, true); actual = tool_config.headers_->get_(field); } diff --git a/tools/gen_compilation_database.py b/tools/gen_compilation_database.py new file mode 100755 index 0000000000000..c312eefb2bee4 --- /dev/null +++ b/tools/gen_compilation_database.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +import argparse +import os +import json + +def generateCompilationDatabase(): + os.system("bazel/gen_compilation_database.sh //source/... //test/... //tools/...") + +def isCompileTarget(target, args): + filename = target["file"] + if not args.include_headers: + for ext in (".h", ".hh", ".hpp", ".hxx"): + if filename.endswith(".h") or filename.endswith(ext): + return False + + if not args.include_genfiles: + if filename.startswith("bazel-out/"): + return False + + if not args.include_external: + if filename.startswith("external/"): + return False + + return True + +def modifyCompileCommand(target): + cxx, options = target["command"].split(" ", 1) + + # Workaround for bazel added C++11 options, those doesn't affect build itself but + # clang-tidy will misinterpret them. + options = options.replace("-std=c++0x ", "") + options = options.replace("-std=c++11 ", "") + + target["command"] = " ".join(["clang++", options]) + return target + +def fixCompilationDatabase(args): + with open("compile_commands.json", "r") as db_file: + db = json.load(db_file) + + db = [modifyCompileCommand(target) for target in db if isCompileTarget(target, args)] + with open("compile_commands.json", "w") as db_file: + json.dump(db, db_file, indent=2) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Generate JSON compilation database') + parser.add_argument('--include_external', type=bool, default=False) + parser.add_argument('--include_genfiles', type=bool, default=False) + parser.add_argument('--include_headers', type=bool, default=False) + args = parser.parse_args() + generateCompilationDatabase() + fixCompilationDatabase(args) diff --git a/tools/spelling_whitelist_words.txt b/tools/spelling_whitelist_words.txt index 7594b1c61fe4d..c2924df99f678 100644 --- a/tools/spelling_whitelist_words.txt +++ b/tools/spelling_whitelist_words.txt @@ -1,4 +1,4 @@ -# One word per line, these words are not spell checked. +# One word per line, these words are not spell checked. # you can add a comment to each word to explain why you don't need to do a spell check. # bazel keywords in bazel/cc_configure.bzl diff --git a/windows/tools/bazel.rc b/windows/tools/bazel.rc index 234d5bc4a85a3..9da9954a452c2 100644 --- a/windows/tools/bazel.rc +++ b/windows/tools/bazel.rc @@ -1,7 +1,7 @@ # Windows/Envoy specific Bazel build/test options. -// TODO: remove experimental_shortened_obj_file_path for Bazel 0.16.0 -build --experimental_shortened_obj_file_path build --define signal_trace=disabled build --define hot_restart=disabled build --define tcmalloc=disabled +# Build GRPC without c-ares support -- otherwise it will not link +build --define grpc_no_ares=true