From 47549136e298fff5aec8d404a83352dd1ce1d3b5 Mon Sep 17 00:00:00 2001 From: Reuven Lazarus Date: Fri, 19 May 2017 15:34:08 -0400 Subject: [PATCH 01/10] docs: fix a load-bearing typo; add a link to gcovr (#999) --- bazel/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bazel/README.md b/bazel/README.md index 0cce0a6e756d..7065d67ca8ed 100644 --- a/bazel/README.md +++ b/bazel/README.md @@ -214,8 +214,9 @@ https://github.com/bazelbuild/bazel/issues/2805. # Coverage builds -To generate coverage results, make sure you have `gcov` 3.3 in your `PATH` (or -set `GCOVR` to point at it). Then run: +To generate coverage results, make sure you have +[`gcovr`](https://github.com/gcovr/gcovr) 3.3 in your `PATH` (or set `GCOVR` to +point at it). Then run: ``` test/run_envoy_bazel_coverage.sh From 600964ce13eaab1e60a749f3de03b7a6998e78da Mon Sep 17 00:00:00 2001 From: htuch Date: Fri, 19 May 2017 15:36:33 -0400 Subject: [PATCH 02/10] bazel-test-gdb: support source code listing. (#997) Execute GDB in the current working tree, fixup the test with its Bazel cache directory to allow GDB to know where it lives via an absolute path. This supports 'list' in GDB. --- tools/gen_gdb_wrapper_script.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/gen_gdb_wrapper_script.py b/tools/gen_gdb_wrapper_script.py index c4021e848565..6487be554f13 100755 --- a/tools/gen_gdb_wrapper_script.py +++ b/tools/gen_gdb_wrapper_script.py @@ -18,7 +18,6 @@ for k, v in env.iteritems(): os.environ[k] = v -os.chdir('${working_dir}') os.system("${gdb} --args ${test_args}") """) @@ -26,11 +25,11 @@ gdb = sys.argv[1] generated_path = sys.argv[2] test_args = sys.argv[3:] + test_args[0] = os.path.abspath(test_args[0]) with open(generated_path, 'w') as f: f.write( GDB_RUNNER_SCRIPT.substitute( b64env=str(dict(os.environ)), - working_dir=os.getcwd(), gdb=gdb, test_args=' '.join(pipes.quote(arg) for arg in test_args))) # To make bazel consider the test a failure we exit non-zero. From 320a55294645fd4cc955aa0c56c0b50ba0ac4877 Mon Sep 17 00:00:00 2001 From: Derek Argueta Date: Sun, 21 May 2017 08:03:34 -0600 Subject: [PATCH 03/10] Fix documentation typo (#1003) --- docs/intro/arch_overview/hot_restart.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/intro/arch_overview/hot_restart.rst b/docs/intro/arch_overview/hot_restart.rst index 980eb372547f..0add1f3fb2f1 100644 --- a/docs/intro/arch_overview/hot_restart.rst +++ b/docs/intro/arch_overview/hot_restart.rst @@ -6,7 +6,7 @@ Hot restart Ease of operation is one of the primary goals of Envoy. In addition to robust statistics and a local administration interface, Envoy has the ability to “hot” or “live” restart itself. This means that Envoy can fully reload itself (both code and configuration) without dropping any connections. The -hot restart functionality has has the following general architecture: +hot restart functionality has the following general architecture: * Statistics and some locks are kept in a shared memory region. This means that gauges will be consistent across both processes as restart is taking place. From 6cf5f8579bcf1b98a70baeec4f8150766b4f18fb Mon Sep 17 00:00:00 2001 From: htuch Date: Mon, 22 May 2017 13:10:21 -0400 Subject: [PATCH 04/10] coverage: some safeguards to avoid clang silent failure. (#1004) clang isn't compatible with gcov (see #858). We plan to switch to lcov in the future (see #1000). For now, just make sure we fail visibly and document. --- bazel/README.md | 3 ++- test/coverage/gcc_only_test.cc | 12 ++++++++++++ test/coverage/gen_build.sh | 8 ++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 test/coverage/gcc_only_test.cc diff --git a/bazel/README.md b/bazel/README.md index 7065d67ca8ed..8649587468ad 100644 --- a/bazel/README.md +++ b/bazel/README.md @@ -216,7 +216,8 @@ https://github.com/bazelbuild/bazel/issues/2805. To generate coverage results, make sure you have [`gcovr`](https://github.com/gcovr/gcovr) 3.3 in your `PATH` (or set `GCOVR` to -point at it). Then run: +point at it) and are using a GCC toolchain (clang does not work currently, see +https://github.com/lyft/envoy/issues/1000). Then run: ``` test/run_envoy_bazel_coverage.sh diff --git a/test/coverage/gcc_only_test.cc b/test/coverage/gcc_only_test.cc new file mode 100644 index 000000000000..44e38a0d5536 --- /dev/null +++ b/test/coverage/gcc_only_test.cc @@ -0,0 +1,12 @@ +#include "gtest/gtest.h" + +namespace Envoy { + +TEST(GccOnly, CompilerCheck) { +#if defined(__clang__) or not defined(__GNUC__) + // clang is incompatible with gcov. + FAIL() << "GCC is required for coverage runs"; +#endif +} + +} // Envoy diff --git a/test/coverage/gen_build.sh b/test/coverage/gen_build.sh index 196624443f22..ebf229ba1abb 100755 --- a/test/coverage/gen_build.sh +++ b/test/coverage/gen_build.sh @@ -40,10 +40,18 @@ load( envoy_package() +envoy_cc_test( + name = "gcc_only_test", + srcs = ["gcc_only_test.cc"], + tags = ["manual"], + coverage = False, +) + envoy_cc_test( name = "coverage_tests", repository = "${REPOSITORY}", deps = [ + ":gcc_only_test_lib", # gcov requires gcc EOF for t in ${TARGETS} do From 5dc7c06e8e1673439de9492113d7deec5ba3c6c5 Mon Sep 17 00:00:00 2001 From: ccaraman Date: Mon, 22 May 2017 13:49:56 -0700 Subject: [PATCH 05/10] Update docs to say 301 (#1007) --- .../http_conn_man/route_config/route.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/configuration/http_conn_man/route_config/route.rst b/docs/configuration/http_conn_man/route_config/route.rst index fffc95883e18..981c9f60126b 100644 --- a/docs/configuration/http_conn_man/route_config/route.rst +++ b/docs/configuration/http_conn_man/route_config/route.rst @@ -79,14 +79,14 @@ cluster_header host_redirect *(sometimes required, string)* Indicates that the route is a redirect rule. If there is a match, - a 302 redirect response will be sent which swaps the host portion of the URL with this value. + a 301 redirect response will be sent which swaps the host portion of the URL with this value. *path_redirect* can also be specified along with this option. .. _config_http_conn_man_route_table_route_path_redirect: path_redirect *(sometimes required, string)* Indicates that the route is a redirect rule. If there is a match, - a 302 redirect response will be sent which swaps the path portion of the URL with this value. + a 301 redirect response will be sent which swaps the path portion of the URL with this value. *host_redirect* can also be specified along with this option. .. _config_http_conn_man_route_table_route_prefix_rewrite: @@ -225,13 +225,13 @@ num_retries per_try_timeout_ms *(optional, integer)* specifies a non-zero timeout per retry attempt. This parameter is optional. - The same conditions documented for + The same conditions documented for :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms` apply. **Note:** If left unspecified, Envoy will use the global - :ref:`route timeout ` for the request. - Consequently, when using a :ref:`5xx ` based - retry policy, a request that times out will not be retried as the total timeout budget + :ref:`route timeout ` for the request. + Consequently, when using a :ref:`5xx ` based + retry policy, a request that times out will not be retried as the total timeout budget would have been exhausted. .. _config_http_conn_man_route_table_route_shadow: From c29962b38576439215b56976f130a46141288c2f Mon Sep 17 00:00:00 2001 From: Jose Ulises Nino Rivera Date: Mon, 22 May 2017 15:31:33 -0700 Subject: [PATCH 06/10] docs: fix BUILD_DIR path (#1008) --- docs/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/build.sh b/docs/build.sh index 83a733e1642d..6f1ca820fb57 100755 --- a/docs/build.sh +++ b/docs/build.sh @@ -1,7 +1,7 @@ #!/bin/bash SCRIPT_DIR=$(dirname "$0") -BUILD_DIR=build/docs +BUILD_DIR=build_docs [[ -z "${DOCS_OUTPUT_DIR}" ]] && DOCS_OUTPUT_DIR=generated/docs rm -rf "${DOCS_OUTPUT_DIR}" From d3d59e6689aed42d105e6b20b2caabd1463444b4 Mon Sep 17 00:00:00 2001 From: Christian Posta Date: Tue, 23 May 2017 09:53:10 -0700 Subject: [PATCH 07/10] identify outlier_detection correctly as an object in the high-level config overview (#1010) --- docs/configuration/cluster_manager/cluster.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/cluster_manager/cluster.rst b/docs/configuration/cluster_manager/cluster.rst index 117959eb8b0e..21c84243f37f 100644 --- a/docs/configuration/cluster_manager/cluster.rst +++ b/docs/configuration/cluster_manager/cluster.rst @@ -20,7 +20,7 @@ Cluster "features": "...", "http_codec_options": "...", "dns_refresh_rate_ms": "...", - "outlier_detection": "..." + "outlier_detection": "{...}" } .. _config_cluster_manager_cluster_name: From 34d308e9839d8c10e4ba5c06e323dd35ac6149c6 Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Tue, 23 May 2017 10:03:15 -0700 Subject: [PATCH 08/10] grpc to support empty response. (#1009) --- source/common/grpc/rpc_channel_impl.cc | 2 +- test/common/grpc/rpc_channel_impl_test.cc | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/source/common/grpc/rpc_channel_impl.cc b/source/common/grpc/rpc_channel_impl.cc index bfe059a18a1e..c53e5ea61047 100644 --- a/source/common/grpc/rpc_channel_impl.cc +++ b/source/common/grpc/rpc_channel_impl.cc @@ -54,7 +54,7 @@ void RpcChannelImpl::onSuccess(Http::MessagePtr&& http_response) { // A gRPC response contains a 5 byte header. Currently we only support unary responses so we // ignore the header. @see serializeBody(). - if (!http_response->body() || !(http_response->body()->length() > 5)) { + if (!http_response->body() || (http_response->body()->length() < 5)) { throw Exception(Optional(), "bad serialized body"); } diff --git a/test/common/grpc/rpc_channel_impl_test.cc b/test/common/grpc/rpc_channel_impl_test.cc index 4de0d07a9b6f..5e7dd426bf2c 100644 --- a/test/common/grpc/rpc_channel_impl_test.cc +++ b/test/common/grpc/rpc_channel_impl_test.cc @@ -212,6 +212,28 @@ TEST_F(GrpcRequestImplTest, ShortBodyInResponse) { http_callbacks_->onSuccess(std::move(response_http_message)); } +TEST_F(GrpcRequestImplTest, EmptyBodyInResponse) { + expectNormalRequest(); + + helloworld::HelloRequest request; + request.set_name("a name"); + helloworld::HelloReply response; + EXPECT_CALL(grpc_callbacks_, onPreRequestCustomizeHeaders(_)); + service_.SayHello(nullptr, &request, &response, nullptr); + + Http::MessagePtr response_http_message(new Http::ResponseMessageImpl( + Http::HeaderMapPtr{new Http::TestHeaderMapImpl{{":status", "200"}}})); + helloworld::HelloReply empty_response; + response_http_message->body() = Common::serializeBody(empty_response); + EXPECT_EQ(response_http_message->body()->length(), 5); + response_http_message->trailers( + Http::HeaderMapPtr{new Http::TestHeaderMapImpl{{"grpc-status", "0"}}}); + + EXPECT_CALL(grpc_callbacks_, onSuccess()); + http_callbacks_->onSuccess(std::move(response_http_message)); + EXPECT_EQ(response.SerializeAsString(), empty_response.SerializeAsString()); +} + TEST_F(GrpcRequestImplTest, BadMessageInResponse) { expectNormalRequest(); From 115434a9dd9db02e3ca9ed1d5d8f09ff524635b3 Mon Sep 17 00:00:00 2001 From: Shriram Rajagopalan Date: Tue, 23 May 2017 14:14:35 -0400 Subject: [PATCH 09/10] Zipkin end to end example (#993) This PR describes how to setup Zipkin tracing in Envoy with a simple end to end example (reuses the front proxy sandbox). PR #962 and the current one address #628 --- docs/install/install.rst | 2 +- .../front_proxy.rst} | 96 +------------ docs/install/sandboxes/grpc_bridge.rst | 52 +++++++ docs/install/sandboxes/local_docker_build.rst | 35 +++++ docs/install/sandboxes/sandboxes.rst | 16 +++ docs/install/sandboxes/zipkin_tracing.rst | 82 +++++++++++ docs/operations/faq/overview.rst | 1 + docs/operations/faq/zipkin_tracing.rst | 7 + examples/BUILD | 3 + examples/front-proxy/Dockerfile-frontenvoy | 2 +- examples/front-proxy/service.py | 26 ++++ examples/front-proxy/start_service.sh | 3 +- examples/zipkin-tracing/README.md | 2 + examples/zipkin-tracing/docker-compose.yml | 61 ++++++++ .../zipkin-tracing/front-envoy-zipkin.json | 85 +++++++++++ .../zipkin-tracing/service1-envoy-zipkin.json | 133 ++++++++++++++++++ .../zipkin-tracing/service2-envoy-zipkin.json | 83 +++++++++++ test/config_test/example_configs_test.cc | 2 +- 18 files changed, 593 insertions(+), 98 deletions(-) rename docs/install/{sandboxes.rst => sandboxes/front_proxy.rst} (76%) create mode 100644 docs/install/sandboxes/grpc_bridge.rst create mode 100644 docs/install/sandboxes/local_docker_build.rst create mode 100644 docs/install/sandboxes/sandboxes.rst create mode 100644 docs/install/sandboxes/zipkin_tracing.rst create mode 100644 docs/operations/faq/zipkin_tracing.rst create mode 100644 examples/zipkin-tracing/README.md create mode 100644 examples/zipkin-tracing/docker-compose.yml create mode 100644 examples/zipkin-tracing/front-envoy-zipkin.json create mode 100644 examples/zipkin-tracing/service1-envoy-zipkin.json create mode 100644 examples/zipkin-tracing/service2-envoy-zipkin.json diff --git a/docs/install/install.rst b/docs/install/install.rst index e764d42a33b6..ada462336eba 100644 --- a/docs/install/install.rst +++ b/docs/install/install.rst @@ -10,5 +10,5 @@ Building and installation building installation ref_configs - sandboxes + sandboxes/sandboxes.rst tools diff --git a/docs/install/sandboxes.rst b/docs/install/sandboxes/front_proxy.rst similarity index 76% rename from docs/install/sandboxes.rst rename to docs/install/sandboxes/front_proxy.rst index c88bfd80c458..ff27de78fe70 100644 --- a/docs/install/sandboxes.rst +++ b/docs/install/sandboxes/front_proxy.rst @@ -1,14 +1,7 @@ -.. _install_sandboxes: - -Sandboxes -========= - -The docker-compose sandboxes give you different environments to test out Envoy's -features. As we gauge people's interests we will add more sandboxes demonstrating -different features. +.. _install_sandboxes_front_proxy: Front Proxy ------------ +=========== To get a flavor of what Envoy has to offer as a front proxy, we are releasing a `docker compose `_ sandbox that deploys a front @@ -233,88 +226,3 @@ statistics. For example inside ``frontenvoy`` we can get:: Notice that we can get the number of members of upstream clusters, number of requests fulfilled by them, information about http ingress, and a plethora of other useful stats. - -gRPC bridge ------------ - -Envoy gRPC -~~~~~~~~~~ - -The gRPC bridge sandbox is an example usage of Envoy's -:ref:`gRPC bridge filter `. -Included in the sandbox is a gRPC in memory Key/Value store with a Python HTTP -client. The Python client makes HTTP/1 requests through the Envoy sidecar -process which are upgraded into HTTP/2 gRPC requests. Response trailers are then -buffered and sent back to the client as a HTTP/1 header payload. - -Another Envoy feature demonstrated in this example is Envoy's ability to do authority -base routing via its route configuration. - -Building the Go service -~~~~~~~~~~~~~~~~~~~~~~~ - -To build the Go gRPC service run:: - - $ pwd - ~/src/envoy/examples/grpc-bridge - $ script/bootstrap - $ script/build - -Docker compose -~~~~~~~~~~~~~~ - -To run the docker compose file, and set up both the Python and the gRPC containers -run:: - - $ pwd - ~/src/envoy/examples/grpc-bridge - $ docker-compose up --build - -Sending requests to the Key/Value store -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To use the python service and sent gRPC requests:: - - $ pwd - ~/src/envoy/examples/grpc-bridge - # set a key - $ docker-compose exec python /client/client.py set foo bar - setf foo to bar - - # get a key - $ docker-compose exec python /client/client.py get foo - bar - -Locally building a docker image with an envoy binary ----------------------------------------------------- - -The following steps guide you through building your own envoy binary, and -putting that in a clean ubuntu container. - -**Step 1: Build Envoy** - -Using ``lyft/envoy-build`` you will compile envoy. -This image has all software needed to build envoy. From your envoy directory:: - - $ pwd - src/envoy - $ ./ci/run_envoy_docker.sh './ci/do_ci.sh bazel.dev' - -That command will take some time to run because it is compiling an envoy binary and running tests. - -For more information on building and different build targets, please refer to :repo:`ci/README.md`. - -**Step 2: Build image with only envoy binary** - -In this step we'll build an image that only has the envoy binary, and none -of the software used to build it.:: - - $ pwd - src/envoy/ - $ docker build -f ci/Dockerfile-envoy-image -t envoy . - -Now you can use this ``envoy`` image to build the any of the sandboxes if you change -the ``FROM`` line in any dockerfile. - -This will be particularly useful if you are interested in modifying envoy, and testing -your changes. diff --git a/docs/install/sandboxes/grpc_bridge.rst b/docs/install/sandboxes/grpc_bridge.rst new file mode 100644 index 000000000000..29b60d4b6bd1 --- /dev/null +++ b/docs/install/sandboxes/grpc_bridge.rst @@ -0,0 +1,52 @@ +.. _install_sandboxes_grpc_bridge: + +gRPC Bridge +=========== + +Envoy gRPC +~~~~~~~~~~ + +The gRPC bridge sandbox is an example usage of Envoy's +:ref:`gRPC bridge filter `. +Included in the sandbox is a gRPC in-memory Key/Value store with a Python HTTP +client. The Python client makes HTTP/1 requests through the Envoy sidecar +process which are upgraded into HTTP/2 gRPC requests. Response trailers are then +buffered and sent back to the client as a HTTP/1 header payload. + +Another Envoy feature demonstrated in this example is Envoy's ability to do authority +base routing via its route configuration. + +Building the Go service +~~~~~~~~~~~~~~~~~~~~~~~ + +To build the Go gRPC service run:: + + $ pwd + ~/src/envoy/examples/grpc-bridge + $ script/bootstrap + $ script/build + +Docker compose +~~~~~~~~~~~~~~ + +To run the docker compose file, and set up both the Python and the gRPC containers +run:: + + $ pwd + ~/src/envoy/examples/grpc-bridge + $ docker-compose up --build + +Sending requests to the Key/Value store +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To use the Python service and send gRPC requests:: + + $ pwd + ~/src/envoy/examples/grpc-bridge + # set a key + $ docker-compose exec python /client/client.py set foo bar + setf foo to bar + + # get a key + $ docker-compose exec python /client/client.py get foo + bar diff --git a/docs/install/sandboxes/local_docker_build.rst b/docs/install/sandboxes/local_docker_build.rst new file mode 100644 index 000000000000..bffe39823835 --- /dev/null +++ b/docs/install/sandboxes/local_docker_build.rst @@ -0,0 +1,35 @@ +.. _install_sandboxes_local_docker_build: + +Building an Envoy Docker image +============================== + +The following steps guide you through building your own Envoy binary, and +putting that in a clean Ubuntu container. + +**Step 1: Build Envoy** + +Using ``lyft/envoy-build`` you will compile Envoy. +This image has all software needed to build Envoy. From your Envoy directory:: + + $ pwd + src/envoy + $ ./ci/run_envoy_docker.sh './ci/do_ci.sh bazel.release' + +That command will take some time to run because it is compiling an Envoy binary and running tests. + +For more information on building and different build targets, please refer to :repo:`ci/README.md`. + +**Step 2: Build image with only envoy binary** + +In this step we'll build an image that only has the Envoy binary, and none +of the software used to build it.:: + + $ pwd + src/envoy/ + $ docker build -f ci/Dockerfile-envoy-image -t envoy . + +Now you can use this ``envoy`` image to build the any of the sandboxes if you change +the ``FROM`` line in any Dockerfile. + +This will be particularly useful if you are interested in modifying Envoy, and testing +your changes. diff --git a/docs/install/sandboxes/sandboxes.rst b/docs/install/sandboxes/sandboxes.rst new file mode 100644 index 000000000000..03e025c2b077 --- /dev/null +++ b/docs/install/sandboxes/sandboxes.rst @@ -0,0 +1,16 @@ +.. _install_sandboxes: + +Sandboxes +========= + +The docker-compose sandboxes give you different environments to test out Envoy's +features. As we gauge people's interests we will add more sandboxes demonstrating +different features. The following sandboxes are available: + +.. toctree:: + :maxdepth: 1 + + front_proxy + zipkin_tracing + grpc_bridge + local_docker_build diff --git a/docs/install/sandboxes/zipkin_tracing.rst b/docs/install/sandboxes/zipkin_tracing.rst new file mode 100644 index 000000000000..81c93cf14357 --- /dev/null +++ b/docs/install/sandboxes/zipkin_tracing.rst @@ -0,0 +1,82 @@ +.. _install_sandboxes_zipkin_tracing: + +Zipkin Tracing +============== + +The Zipkin tracing sandbox demonstrates Envoy's :ref:`request tracing ` +capabilities using `Zipkin `_ as the tracing provider. This sandbox +is very similar to the front proxy architecture described above, with one difference: +service1 makes an API call to service2 before returning a response. +The three containers will be deployed inside a virtual network called ``envoymesh``. + +All incoming requests are routed via the front envoy, which is acting as a reverse proxy +sitting on the edge of the ``envoymesh`` network. Port ``80`` is mapped to port ``8000`` +by docker compose (see :repo:`/examples/zipkin-tracing/docker-compose.yml`). Notice that +all envoys are configured to collect request traces (e.g., http_connection_manager/config/tracing setup in +:repo:`/examples/zipkin-tracing/front-envoy-zipkin.json`) and setup to propagate the spans generated +by the Zipkin tracer to a Zipkin cluster (trace driver setup +in :repo:`/examples/zipkin-tracing/front-envoy-zipkin.json`). + +Before routing a request to the appropriate service envoy or the application, Envoy will take +care of generating the appropriate spans for tracing (parent/child/shared context spans). +At a high-level, each span records the latency of upstream API calls as well as information +needed to correlate the span with other related spans (e.g., the trace ID). + +One of the most important benefits of tracing from Envoy is that it will take care of +propagating the traces to the Zipkin service cluster. However, in order to fully take advantage +of tracing, the application has to propagate trace headers that Envoy generates, while making +calls to other services. In the sandbox we have provided, the simple flask app +(see trace function in :repo:`/examples/front-proxy/service.py`) acting as service1 propagates +the trace headers while making an outbound call to service2. + + +Running the Sandbox +~~~~~~~~~~~~~~~~~~~ + +The following documentation runs through the setup of an envoy cluster organized +as is described in the image above. + +**Step 1: Build the sandbox** + +To build this sandbox example, and start the example apps run the following commands:: + + $ pwd + envoy/examples/zipkin-tracing + $ docker-compose up --build -d + $ docker-compose ps + Name Command State Ports + ------------------------------------------------------------------------------------------------------------- + zipkintracing_service1_1 /bin/sh -c /usr/local/bin/ ... Up 80/tcp + zipkintracing_service2_1 /bin/sh -c /usr/local/bin/ ... Up 80/tcp + zipkintracing_front-envoy_1 /bin/sh -c /usr/local/bin/ ... Up 0.0.0.0:8000->80/tcp, 0.0.0.0:8001->8001/tcp + +**Step 2: Generate some load** + +You can now send a request to service1 via the front-envoy as follows:: + + $ curl -v $(docker-machine ip default):8000/trace/1 + * Trying 192.168.99.100... + * Connected to 192.168.99.100 (192.168.99.100) port 8000 (#0) + > GET /trace/1 HTTP/1.1 + > Host: 192.168.99.100:8000 + > User-Agent: curl/7.43.0 + > Accept: */* + > + < HTTP/1.1 200 OK + < content-type: text/html; charset=utf-8 + < content-length: 89 + < x-envoy-upstream-service-time: 1 + < server: envoy + < date: Fri, 26 Aug 2016 19:39:19 GMT + < x-envoy-protocol-version: HTTP/1.1 + < + Hello from behind Envoy (service 1)! hostname: f26027f1ce28 resolvedhostname: 172.19.0.6 + * Connection #0 to host 192.168.99.100 left intact + +**Step 3: View the traces in Zipkin UI** + +Point your browser to http://localhost:9411 . You should see the Zipkin dashboard. +Set the service to "front-proxy" and set the start time to a few minutes before +the start of the test (step 2) and hit enter. You should see traces from the front-proxy. +Click on a trace to explore the path taken by the request from front-proxy to service1 +to service2, as well as the latency incurred at each hop. diff --git a/docs/operations/faq/overview.rst b/docs/operations/faq/overview.rst index a95617376e03..757ffeddae79 100644 --- a/docs/operations/faq/overview.rst +++ b/docs/operations/faq/overview.rst @@ -9,3 +9,4 @@ The purpose of this document is to link examples of commonly used deployment sce :maxdepth: 1 zone_aware_routing + zipkin_tracing diff --git a/docs/operations/faq/zipkin_tracing.rst b/docs/operations/faq/zipkin_tracing.rst new file mode 100644 index 000000000000..edbc0a263527 --- /dev/null +++ b/docs/operations/faq/zipkin_tracing.rst @@ -0,0 +1,7 @@ +.. _common_configuration_zipkin_tracing: + +Request tracing with Zipkin +=========================== + +Refer to the :ref:`zipkin sandbox setup ` +for an example of zipkin tracing configuration. diff --git a/examples/BUILD b/examples/BUILD index 23c50f75f6c1..31b9eb72be36 100644 --- a/examples/BUILD +++ b/examples/BUILD @@ -14,5 +14,8 @@ filegroup( "front-proxy/service-envoy.json", "grpc-bridge/config/s2s-grpc-envoy.json", "grpc-bridge/config/s2s-python-envoy.json", + "zipkin-tracing/front-envoy-zipkin.json", + "zipkin-tracing/service1-envoy-zipkin.json", + "zipkin-tracing/service2-envoy-zipkin.json", ], ) diff --git a/examples/front-proxy/Dockerfile-frontenvoy b/examples/front-proxy/Dockerfile-frontenvoy index 3ecf7aa89b38..5fc98e5cfc1e 100644 --- a/examples/front-proxy/Dockerfile-frontenvoy +++ b/examples/front-proxy/Dockerfile-frontenvoy @@ -2,4 +2,4 @@ FROM lyft/envoy:latest RUN apt-get update && apt-get -q install -y \ curl -CMD /usr/local/bin/envoy -c /etc/front-envoy.json +CMD /usr/local/bin/envoy -c /etc/front-envoy.json --service-cluster front-proxy diff --git a/examples/front-proxy/service.py b/examples/front-proxy/service.py index b44d084a6821..003129423021 100644 --- a/examples/front-proxy/service.py +++ b/examples/front-proxy/service.py @@ -1,9 +1,21 @@ from flask import Flask +from flask import request import socket import os +import sys +import requests app = Flask(__name__) +TRACE_HEADERS_TO_PROPAGATE = [ + 'X-Ot-Span-Context', + 'X-Request-Id', + 'X-B3-TraceId', + 'X-B3-SpanId', + 'X-B3-ParentSpanId', + 'X-B3-Sampled', + 'X-B3-Flags' +] @app.route('/service/') def hello(service_number): @@ -12,5 +24,19 @@ def hello(service_number): socket.gethostname(), socket.gethostbyname(socket.gethostname()))) +@app.route('/trace/') +def trace(service_number): + headers = {} + # call service 2 from service 1 + if int(os.environ['SERVICE_NAME']) == 1 : + for header in TRACE_HEADERS_TO_PROPAGATE: + if header in request.headers: + headers[header] = request.headers[header] + ret = requests.get("http://localhost:9000/trace/2", headers=headers) + return ('Hello from behind Envoy (service {})! hostname: {} resolved' + 'hostname: {}\n'.format(os.environ['SERVICE_NAME'], + socket.gethostname(), + socket.gethostbyname(socket.gethostname()))) + if __name__ == "__main__": app.run(host='127.0.0.1', port=8080, debug=True) diff --git a/examples/front-proxy/start_service.sh b/examples/front-proxy/start_service.sh index cf98f2c5b926..d4e6ad85dc3e 100644 --- a/examples/front-proxy/start_service.sh +++ b/examples/front-proxy/start_service.sh @@ -1,2 +1,3 @@ +#!/bin/bash python /code/service.py & -envoy -c /etc/service-envoy.json +envoy -c /etc/service-envoy.json --service-cluster service${SERVICE_NAME} diff --git a/examples/zipkin-tracing/README.md b/examples/zipkin-tracing/README.md new file mode 100644 index 000000000000..200f212150c5 --- /dev/null +++ b/examples/zipkin-tracing/README.md @@ -0,0 +1,2 @@ +To learn about this sandbox and for instructions on how to run it please head over +to the [envoy docs](https://lyft.github.io/envoy/docs/install/sandboxes.html#zipkin-tracing) diff --git a/examples/zipkin-tracing/docker-compose.yml b/examples/zipkin-tracing/docker-compose.yml new file mode 100644 index 000000000000..287bf7e64bc1 --- /dev/null +++ b/examples/zipkin-tracing/docker-compose.yml @@ -0,0 +1,61 @@ +version: '2' +services: + + front-envoy: + build: + context: ../ + dockerfile: front-proxy/Dockerfile-frontenvoy + volumes: + - ./front-envoy-zipkin.json:/etc/front-envoy.json + networks: + - envoymesh + expose: + - "80" + - "8001" + ports: + - "8000:80" + - "8001:8001" + + service1: + build: + context: ../front-proxy + dockerfile: Dockerfile-service + volumes: + - ./service1-envoy-zipkin.json:/etc/service-envoy.json + networks: + envoymesh: + aliases: + - service1 + environment: + - SERVICE_NAME=1 + expose: + - "80" + + service2: + build: + context: ../front-proxy + dockerfile: Dockerfile-service + volumes: + - ./service2-envoy-zipkin.json:/etc/service-envoy.json + networks: + envoymesh: + aliases: + - service2 + environment: + - SERVICE_NAME=2 + expose: + - "80" + + zipkin: + image: openzipkin/zipkin + networks: + envoymesh: + aliases: + - zipkin + expose: + - "9411" + ports: + - "9411:9411" + +networks: + envoymesh: {} diff --git a/examples/zipkin-tracing/front-envoy-zipkin.json b/examples/zipkin-tracing/front-envoy-zipkin.json new file mode 100644 index 000000000000..9a59280983ab --- /dev/null +++ b/examples/zipkin-tracing/front-envoy-zipkin.json @@ -0,0 +1,85 @@ +{ + "listeners": [ + { + "address": "tcp://0.0.0.0:80", + "filters": [ + { + "type": "read", + "name": "http_connection_manager", + "config": { + "generate_request_id": true, + "tracing": { + "operation_name": "ingress" + }, + "codec_type": "auto", + "stat_prefix": "ingress_http", + "route_config": { + "virtual_hosts": [ + { + "name": "backend", + "domains": ["*"], + "routes": [ + { + "timeout_ms": 0, + "prefix": "/trace/1", + "cluster": "service1" + } + ] + } + ] + }, + "filters": [ + { + "type": "decoder", + "name": "router", + "config": {} + } + ] + } + } + ] + } + ], + "tracing": { + "http": { + "driver": { + "type": "zipkin", + "config": { + "collector_cluster": "zipkin", + "collector_endpoint": "/api/v1/spans" + } + } + } + }, + "admin": { + "access_log_path": "/dev/null", + "address": "tcp://0.0.0.0:8001" + }, + "cluster_manager": { + "clusters": [ + { + "name": "service1", + "connect_timeout_ms": 250, + "type": "strict_dns", + "lb_type": "round_robin", + "features": "http2", + "hosts": [ + { + "url": "tcp://service1:80" + } + ] + }, + { + "name": "zipkin", + "connect_timeout_ms": 1000, + "type": "strict_dns", + "lb_type": "round_robin", + "hosts": [ + { + "url": "tcp://zipkin:9411" + } + ] + } + ] + } +} diff --git a/examples/zipkin-tracing/service1-envoy-zipkin.json b/examples/zipkin-tracing/service1-envoy-zipkin.json new file mode 100644 index 000000000000..13ed9f7087a9 --- /dev/null +++ b/examples/zipkin-tracing/service1-envoy-zipkin.json @@ -0,0 +1,133 @@ +{ + "listeners": [ + { + "address": "tcp://0.0.0.0:80", + "filters": [ + { + "type": "read", + "name": "http_connection_manager", + "config": { + "tracing": { + "operation_name": "ingress" + }, + "codec_type": "auto", + "stat_prefix": "ingress_http", + "route_config": { + "virtual_hosts": [ + { + "name": "service1", + "domains": ["*"], + "routes": [ + { + "timeout_ms": 0, + "prefix": "/", + "cluster": "local_service" + } + ] + } + ] + }, + "filters": [ + { + "type": "decoder", + "name": "router", + "config": {} + } + ] + } + } + ] + }, + { + "address": "tcp://0.0.0.0:9000", + "filters": [ + { + "type": "read", + "name": "http_connection_manager", + "config": { + "tracing": { + "operation_name": "egress" + }, + "codec_type": "auto", + "stat_prefix": "egress_http", + "route_config": { + "virtual_hosts": [ + { + "name": "service2", + "domains": ["*"], + "routes": [ + { + "timeout_ms": 0, + "prefix": "/trace/2", + "cluster": "service2" + } + ] + } + ] + }, + "filters": [ + { + "type": "decoder", + "name": "router", + "config": {} + } + ] + } + } + ] + } + ], + "tracing": { + "http": { + "driver": { + "type": "zipkin", + "config": { + "collector_cluster": "zipkin", + "collector_endpoint": "/api/v1/spans" + } + } + } + }, + "admin": { + "access_log_path": "/dev/null", + "address": "tcp://0.0.0.0:8001" + }, + "cluster_manager": { + "clusters": [ + { + "name": "local_service", + "connect_timeout_ms": 250, + "type": "strict_dns", + "lb_type": "round_robin", + "hosts": [ + { + "url": "tcp://127.0.0.1:8080" + } + ] + }, + { + "name": "service2", + "connect_timeout_ms": 250, + "type": "strict_dns", + "lb_type": "round_robin", + "features": "http2", + "hosts": [ + { + "url": "tcp://service2:80" + } + ] + }, + { + "name": "zipkin", + "connect_timeout_ms": 1000, + "type": "strict_dns", + "lb_type": "round_robin", + "hosts": [ + { + "url": "tcp://zipkin:9411" + } + ] + } + ] + } +} diff --git a/examples/zipkin-tracing/service2-envoy-zipkin.json b/examples/zipkin-tracing/service2-envoy-zipkin.json new file mode 100644 index 000000000000..f22c4e9614d8 --- /dev/null +++ b/examples/zipkin-tracing/service2-envoy-zipkin.json @@ -0,0 +1,83 @@ +{ + "listeners": [ + { + "address": "tcp://0.0.0.0:80", + "filters": [ + { + "type": "read", + "name": "http_connection_manager", + "config": { + "tracing": { + "operation_name": "ingress" + }, + "codec_type": "auto", + "stat_prefix": "ingress_http", + "route_config": { + "virtual_hosts": [ + { + "name": "service2", + "domains": ["*"], + "routes": [ + { + "timeout_ms": 0, + "prefix": "/", + "cluster": "local_service" + } + ] + } + ] + }, + "filters": [ + { + "type": "decoder", + "name": "router", + "config": {} + } + ] + } + } + ] + } + ], + "tracing": { + "http": { + "driver": { + "type": "zipkin", + "config": { + "collector_cluster": "zipkin", + "collector_endpoint": "/api/v1/spans" + } + } + } + }, + "admin": { + "access_log_path": "/dev/null", + "address": "tcp://0.0.0.0:8001" + }, + "cluster_manager": { + "clusters": [ + { + "name": "local_service", + "connect_timeout_ms": 250, + "type": "strict_dns", + "lb_type": "round_robin", + "hosts": [ + { + "url": "tcp://127.0.0.1:8080" + } + ] + }, + { + "name": "zipkin", + "connect_timeout_ms": 1000, + "type": "strict_dns", + "lb_type": "round_robin", + "hosts": [ + { + "url": "tcp://zipkin:9411" + } + ] + } + ] + } +} diff --git a/test/config_test/example_configs_test.cc b/test/config_test/example_configs_test.cc index ea2861094a1f..72de44895459 100644 --- a/test/config_test/example_configs_test.cc +++ b/test/config_test/example_configs_test.cc @@ -8,6 +8,6 @@ namespace Envoy { TEST(ExampleConfigsTest, All) { TestEnvironment::exec( {TestEnvironment::runfilesPath("test/config_test/example_configs_test_setup.sh")}); - EXPECT_EQ(8UL, ConfigTest::run(TestEnvironment::temporaryDirectory() + "/test/config_test")); + EXPECT_EQ(11UL, ConfigTest::run(TestEnvironment::temporaryDirectory() + "/test/config_test")); } } // Envoy From 3a466c3506a97df38a9efb15dff85e2a7e75b556 Mon Sep 17 00:00:00 2001 From: mrice32 Date: Wed, 24 May 2017 00:50:15 -0400 Subject: [PATCH 10/10] Added static registration for http tracers. (#967) (#994) Added a static registration mechanism (following the pattern of filters mentioned in the comments on #967) for http tracers. This will likely be expanded to a more general registration mechanism in future work. This PR is part of the work towards solving #967. This commit deprecates the existing HttpFilterConfigFactory filter API in favor of NamedHttpFilterConfigFactory. --- source/exe/BUILD | 2 + source/server/config/http/BUILD | 22 +++ source/server/config/http/buffer.cc | 20 +- source/server/config/http/buffer.h | 12 +- source/server/config/http/dynamo.cc | 20 +- source/server/config/http/dynamo.h | 9 +- source/server/config/http/fault.cc | 20 +- source/server/config/http/fault.h | 12 +- .../server/config/http/grpc_http1_bridge.cc | 20 +- source/server/config/http/grpc_http1_bridge.h | 10 +- .../config/http/lightstep_http_tracer.cc | 46 +++++ .../config/http/lightstep_http_tracer.h | 27 +++ source/server/config/http/ratelimit.cc | 20 +- source/server/config/http/ratelimit.h | 10 +- source/server/config/http/router.cc | 20 +- source/server/config/http/router.h | 12 +- .../server/config/http/zipkin_http_tracer.cc | 36 ++++ .../server/config/http/zipkin_http_tracer.h | 26 +++ .../server/config/network/client_ssl_auth.cc | 17 +- .../server/config/network/client_ssl_auth.h | 13 +- source/server/config/network/echo.cc | 21 ++- .../config/network/http_connection_manager.cc | 50 +++-- .../config/network/http_connection_manager.h | 115 ++++++++++-- source/server/config/network/mongo_proxy.cc | 16 +- source/server/config/network/mongo_proxy.h | 13 +- source/server/config/network/ratelimit.cc | 18 +- source/server/config/network/ratelimit.h | 14 +- source/server/config/network/redis_proxy.cc | 16 +- source/server/config/network/redis_proxy.h | 12 +- source/server/config/network/tcp_proxy.cc | 18 +- source/server/config/network/tcp_proxy.h | 12 +- source/server/configuration_impl.cc | 61 +++---- source/server/configuration_impl.h | 171 +++++++++++++++++- source/server/http/health_check.cc | 22 ++- source/server/http/health_check.h | 8 +- test/integration/BUILD | 2 + test/server/BUILD | 2 + test/server/config/http/BUILD | 3 + test/server/config/http/config_test.cc | 85 +++++++-- test/server/config/network/BUILD | 2 + test/server/config/network/config_test.cc | 103 +++++++++-- test/server/configuration_impl_test.cc | 114 ++++++++++++ test/server/http/health_check_test.cc | 13 +- 43 files changed, 971 insertions(+), 294 deletions(-) create mode 100644 source/server/config/http/lightstep_http_tracer.cc create mode 100644 source/server/config/http/lightstep_http_tracer.h create mode 100644 source/server/config/http/zipkin_http_tracer.cc create mode 100644 source/server/config/http/zipkin_http_tracer.h diff --git a/source/exe/BUILD b/source/exe/BUILD index 192c7ca8fd58..ed61583b45f2 100644 --- a/source/exe/BUILD +++ b/source/exe/BUILD @@ -35,8 +35,10 @@ envoy_cc_library( "//source/server/config/http:dynamo_lib", "//source/server/config/http:fault_lib", "//source/server/config/http:grpc_http1_bridge_lib", + "//source/server/config/http:lightstep_lib", "//source/server/config/http:ratelimit_lib", "//source/server/config/http:router_lib", + "//source/server/config/http:zipkin_lib", "//source/server/config/network:client_ssl_auth_lib", "//source/server/config/network:echo_lib", "//source/server/config/network:http_connection_manager_lib", diff --git a/source/server/config/http/BUILD b/source/server/config/http/BUILD index 49800b12c349..2aad7bb20b21 100644 --- a/source/server/config/http/BUILD +++ b/source/server/config/http/BUILD @@ -53,6 +53,17 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "lightstep_lib", + srcs = ["lightstep_http_tracer.cc"], + hdrs = ["lightstep_http_tracer.h"], + deps = [ + "//include/envoy/server:instance_interface", + "//source/common/tracing:http_tracer_lib", + "//source/server:configuration_lib", + ], +) + envoy_cc_library( name = "ratelimit_lib", srcs = ["ratelimit.cc"], @@ -77,3 +88,14 @@ envoy_cc_library( "//source/server/config/network:http_connection_manager_lib", ], ) + +envoy_cc_library( + name = "zipkin_lib", + srcs = ["zipkin_http_tracer.cc"], + hdrs = ["zipkin_http_tracer.h"], + deps = [ + "//include/envoy/server:instance_interface", + "//source/common/tracing/zipkin:zipkin_lib", + "//source/server:configuration_lib", + ], +) diff --git a/source/server/config/http/buffer.cc b/source/server/config/http/buffer.cc index 9c777e46f40d..d5ced667dd44 100644 --- a/source/server/config/http/buffer.cc +++ b/source/server/config/http/buffer.cc @@ -11,13 +11,13 @@ namespace Envoy { namespace Server { namespace Configuration { -HttpFilterFactoryCb BufferFilterConfig::tryCreateFilterFactory(HttpFilterType type, - const std::string& name, - const Json::Object& json_config, - const std::string& stats_prefix, - Server::Instance& server) { - if (type != HttpFilterType::Decoder || name != "buffer") { - return nullptr; +HttpFilterFactoryCb BufferFilterConfig::createFilterFactory(HttpFilterType type, + const Json::Object& json_config, + const std::string& stats_prefix, + Server::Instance& server) { + if (type != HttpFilterType::Decoder) { + throw EnvoyException( + fmt::format("{} http filter must be configured as a decoder filter.", name())); } json_config.validateSchema(Json::Schema::BUFFER_HTTP_FILTER_SCHEMA); @@ -32,10 +32,12 @@ HttpFilterFactoryCb BufferFilterConfig::tryCreateFilterFactory(HttpFilterType ty }; } +std::string BufferFilterConfig::name() { return "buffer"; } + /** - * Static registration for the buffer filter. @see RegisterHttpFilterConfigFactory. + * Static registration for the buffer filter. @see RegisterNamedHttpFilterConfigFactory. */ -static RegisterHttpFilterConfigFactory register_; +static RegisterNamedHttpFilterConfigFactory register_; } // Configuration } // Server diff --git a/source/server/config/http/buffer.h b/source/server/config/http/buffer.h index bbfa2ee2dc33..c72eb35a6f7d 100644 --- a/source/server/config/http/buffer.h +++ b/source/server/config/http/buffer.h @@ -11,14 +11,14 @@ namespace Server { namespace Configuration { /** - * Config registration for the buffer filter. @see HttpFilterConfigFactory. + * Config registration for the buffer filter. @see NamedHttpFilterConfigFactory. */ -class BufferFilterConfig : public HttpFilterConfigFactory { +class BufferFilterConfig : public NamedHttpFilterConfigFactory { public: - HttpFilterFactoryCb tryCreateFilterFactory(HttpFilterType type, const std::string& name, - const Json::Object& json_config, - const std::string& stats_prefix, - Server::Instance& server) override; + HttpFilterFactoryCb createFilterFactory(HttpFilterType type, const Json::Object& json_config, + const std::string& stats_prefix, + Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/config/http/dynamo.cc b/source/server/config/http/dynamo.cc index 843fffcf4bd9..1184e4de0795 100644 --- a/source/server/config/http/dynamo.cc +++ b/source/server/config/http/dynamo.cc @@ -8,13 +8,13 @@ namespace Envoy { namespace Server { namespace Configuration { -HttpFilterFactoryCb DynamoFilterConfig::tryCreateFilterFactory(HttpFilterType type, - const std::string& name, - const Json::Object&, - const std::string& stat_prefix, - Server::Instance& server) { - if (type != HttpFilterType::Both || name != "http_dynamo_filter") { - return nullptr; +HttpFilterFactoryCb DynamoFilterConfig::createFilterFactory(HttpFilterType type, + const Json::Object&, + const std::string& stat_prefix, + Server::Instance& server) { + if (type != HttpFilterType::Both) { + throw EnvoyException(fmt::format( + "{} http filter must be configured as both a decoder and encoder filter.", name())); } return [&server, stat_prefix](Http::FilterChainFactoryCallbacks& callbacks) -> void { @@ -23,10 +23,12 @@ HttpFilterFactoryCb DynamoFilterConfig::tryCreateFilterFactory(HttpFilterType ty }; } +std::string DynamoFilterConfig::name() { return "http_dynamo_filter"; } + /** - * Static registration for the http dynamodb filter. @see RegisterHttpFilterConfigFactory. + * Static registration for the http dynamodb filter. @see RegisterNamedHttpFilterConfigFactory. */ -static RegisterHttpFilterConfigFactory register_; +static RegisterNamedHttpFilterConfigFactory register_; } // Configuration } // Server diff --git a/source/server/config/http/dynamo.h b/source/server/config/http/dynamo.h index cfaa9f36360b..dae2852e217c 100644 --- a/source/server/config/http/dynamo.h +++ b/source/server/config/http/dynamo.h @@ -11,11 +11,12 @@ namespace Configuration { /** * Config registration for http dynamodb filter. */ -class DynamoFilterConfig : public HttpFilterConfigFactory { +class DynamoFilterConfig : public NamedHttpFilterConfigFactory { public: - HttpFilterFactoryCb tryCreateFilterFactory(HttpFilterType type, const std::string& name, - const Json::Object&, const std::string& stat_prefix, - Server::Instance& server) override; + HttpFilterFactoryCb createFilterFactory(HttpFilterType type, const Json::Object&, + const std::string& stat_prefix, + Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/config/http/fault.cc b/source/server/config/http/fault.cc index 69c7402faf29..d4002d54bbd5 100644 --- a/source/server/config/http/fault.cc +++ b/source/server/config/http/fault.cc @@ -9,13 +9,13 @@ namespace Envoy { namespace Server { namespace Configuration { -HttpFilterFactoryCb FaultFilterConfig::tryCreateFilterFactory(HttpFilterType type, - const std::string& name, - const Json::Object& json_config, - const std::string& stats_prefix, - Server::Instance& server) { - if (type != HttpFilterType::Decoder || name != "fault") { - return nullptr; +HttpFilterFactoryCb FaultFilterConfig::createFilterFactory(HttpFilterType type, + const Json::Object& json_config, + const std::string& stats_prefix, + Server::Instance& server) { + if (type != HttpFilterType::Decoder) { + throw EnvoyException( + fmt::format("{} http filter must be configured as a decoder filter.", name())); } Http::FaultFilterConfigSharedPtr config( @@ -26,10 +26,12 @@ HttpFilterFactoryCb FaultFilterConfig::tryCreateFilterFactory(HttpFilterType typ }; } +std::string FaultFilterConfig::name() { return "fault"; } + /** - * Static registration for the fault filter. @see RegisterHttpFilterConfigFactory. + * Static registration for the fault filter. @see RegisterNamedHttpFilterConfigFactory. */ -static RegisterHttpFilterConfigFactory register_; +static RegisterNamedHttpFilterConfigFactory register_; } // Configuration } // Server diff --git a/source/server/config/http/fault.h b/source/server/config/http/fault.h index 530e13aafd88..dfe810f9867d 100644 --- a/source/server/config/http/fault.h +++ b/source/server/config/http/fault.h @@ -11,14 +11,14 @@ namespace Server { namespace Configuration { /** - * Config registration for the fault injection filter. @see HttpFilterConfigFactory. + * Config registration for the fault injection filter. @see NamedHttpFilterConfigFactory. */ -class FaultFilterConfig : public HttpFilterConfigFactory { +class FaultFilterConfig : public NamedHttpFilterConfigFactory { public: - HttpFilterFactoryCb tryCreateFilterFactory(HttpFilterType type, const std::string& name, - const Json::Object& json_config, - const std::string& stats_prefix, - Server::Instance& server) override; + HttpFilterFactoryCb createFilterFactory(HttpFilterType type, const Json::Object& json_config, + const std::string& stats_prefix, + Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/config/http/grpc_http1_bridge.cc b/source/server/config/http/grpc_http1_bridge.cc index 079c4f79c836..5eac2197dbbc 100644 --- a/source/server/config/http/grpc_http1_bridge.cc +++ b/source/server/config/http/grpc_http1_bridge.cc @@ -8,13 +8,13 @@ namespace Envoy { namespace Server { namespace Configuration { -HttpFilterFactoryCb GrpcHttp1BridgeFilterConfig::tryCreateFilterFactory(HttpFilterType type, - const std::string& name, - const Json::Object&, - const std::string&, - Server::Instance& server) { - if (type != HttpFilterType::Both || name != "grpc_http1_bridge") { - return nullptr; +HttpFilterFactoryCb GrpcHttp1BridgeFilterConfig::createFilterFactory(HttpFilterType type, + const Json::Object&, + const std::string&, + Server::Instance& server) { + if (type != HttpFilterType::Both) { + throw EnvoyException(fmt::format( + "{} http filter must be configured as both a decoder and encoder filter.", name())); } return [&server](Http::FilterChainFactoryCallbacks& callbacks) -> void { @@ -23,10 +23,12 @@ HttpFilterFactoryCb GrpcHttp1BridgeFilterConfig::tryCreateFilterFactory(HttpFilt }; } +std::string GrpcHttp1BridgeFilterConfig::name() { return "grpc_http1_bridge"; } + /** - * Static registration for the grpc HTTP1 bridge filter. @see RegisterHttpFilterConfigFactory. + * Static registration for the grpc HTTP1 bridge filter. @see RegisterNamedHttpFilterConfigFactory. */ -static RegisterHttpFilterConfigFactory register_; +static RegisterNamedHttpFilterConfigFactory register_; } // Configuration } // Server diff --git a/source/server/config/http/grpc_http1_bridge.h b/source/server/config/http/grpc_http1_bridge.h index fef25d1e57b1..8d7aa767592c 100644 --- a/source/server/config/http/grpc_http1_bridge.h +++ b/source/server/config/http/grpc_http1_bridge.h @@ -11,13 +11,13 @@ namespace Server { namespace Configuration { /** - * Config registration for the grpc HTTP1 bridge filter. @see HttpFilterConfigFactory. + * Config registration for the grpc HTTP1 bridge filter. @see NamedHttpFilterConfigFactory. */ -class GrpcHttp1BridgeFilterConfig : public HttpFilterConfigFactory { +class GrpcHttp1BridgeFilterConfig : public NamedHttpFilterConfigFactory { public: - HttpFilterFactoryCb tryCreateFilterFactory(HttpFilterType type, const std::string& name, - const Json::Object&, const std::string&, - Server::Instance& server) override; + HttpFilterFactoryCb createFilterFactory(HttpFilterType type, const Json::Object&, + const std::string&, Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/config/http/lightstep_http_tracer.cc b/source/server/config/http/lightstep_http_tracer.cc new file mode 100644 index 000000000000..980bdeaa2056 --- /dev/null +++ b/source/server/config/http/lightstep_http_tracer.cc @@ -0,0 +1,46 @@ +#include "server/config/http/lightstep_http_tracer.h" + +#include + +#include "common/common/utility.h" +#include "common/tracing/http_tracer_impl.h" +#include "common/tracing/lightstep_tracer_impl.h" + +#include "lightstep/options.h" +#include "lightstep/tracer.h" + +namespace Envoy { +namespace Server { +namespace Configuration { + +Tracing::HttpTracerPtr +LightstepHttpTracerFactory::createHttpTracer(const Json::Object& json_config, + Server::Instance& server, + Upstream::ClusterManager& cluster_manager) { + + Envoy::Runtime::RandomGenerator& rand = server.random(); + + std::unique_ptr opts(new lightstep::TracerOptions()); + opts->access_token = server.api().fileReadToEnd(json_config.getString("access_token_file")); + StringUtil::rtrim(opts->access_token); + + opts->tracer_attributes["lightstep.component_name"] = server.localInfo().clusterName(); + opts->guid_generator = [&rand]() { return rand.random(); }; + + Tracing::DriverPtr lightstep_driver( + new Tracing::LightStepDriver(json_config, cluster_manager, server.stats(), + server.threadLocal(), server.runtime(), std::move(opts))); + return Tracing::HttpTracerPtr( + new Tracing::HttpTracerImpl(std::move(lightstep_driver), server.localInfo())); +} + +std::string LightstepHttpTracerFactory::name() { return "lightstep"; } + +/** + * Static registration for the lightstep http tracer. @see RegisterHttpTracerFactory. + */ +static RegisterHttpTracerFactory register_; + +} // Configuration +} // Server +} // Envoy diff --git a/source/server/config/http/lightstep_http_tracer.h b/source/server/config/http/lightstep_http_tracer.h new file mode 100644 index 000000000000..721ea7458025 --- /dev/null +++ b/source/server/config/http/lightstep_http_tracer.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include "envoy/server/instance.h" + +#include "server/configuration_impl.h" + +namespace Envoy { +namespace Server { +namespace Configuration { + +/** + * Config registration for the lightstep tracer. @see HttpTracerFactory. + */ +class LightstepHttpTracerFactory : public HttpTracerFactory { +public: + // HttpTracerFactory + Tracing::HttpTracerPtr createHttpTracer(const Json::Object& json_config, Server::Instance& server, + Upstream::ClusterManager& cluster_manager) override; + + std::string name() override; +}; + +} // Configuration +} // Server +} // Envoy diff --git a/source/server/config/http/ratelimit.cc b/source/server/config/http/ratelimit.cc index f2b5ad9541ba..a08dab171e80 100644 --- a/source/server/config/http/ratelimit.cc +++ b/source/server/config/http/ratelimit.cc @@ -9,13 +9,13 @@ namespace Envoy { namespace Server { namespace Configuration { -HttpFilterFactoryCb RateLimitFilterConfig::tryCreateFilterFactory(HttpFilterType type, - const std::string& name, - const Json::Object& config, - const std::string&, - Server::Instance& server) { - if (type != HttpFilterType::Decoder || name != "rate_limit") { - return nullptr; +HttpFilterFactoryCb RateLimitFilterConfig::createFilterFactory(HttpFilterType type, + const Json::Object& config, + const std::string&, + Server::Instance& server) { + if (type != HttpFilterType::Decoder) { + throw EnvoyException( + fmt::format("{} http filter must be configured as a decoder filter.", name())); } Http::RateLimit::FilterConfigSharedPtr filter_config(new Http::RateLimit::FilterConfig( @@ -26,10 +26,12 @@ HttpFilterFactoryCb RateLimitFilterConfig::tryCreateFilterFactory(HttpFilterType }; } +std::string RateLimitFilterConfig::name() { return "rate_limit"; } + /** - * Static registration for the rate limit filter. @see RegisterHttpFilterConfigFactory. + * Static registration for the rate limit filter. @see RegisterNamedHttpFilterConfigFactory. */ -static RegisterHttpFilterConfigFactory register_; +static RegisterNamedHttpFilterConfigFactory register_; } // Configuration } // Server diff --git a/source/server/config/http/ratelimit.h b/source/server/config/http/ratelimit.h index 8988e0d82ef7..b26faee251e6 100644 --- a/source/server/config/http/ratelimit.h +++ b/source/server/config/http/ratelimit.h @@ -11,13 +11,13 @@ namespace Server { namespace Configuration { /** - * Config registration for the rate limit filter. @see HttpFilterConfigFactory. + * Config registration for the rate limit filter. @see NamedHttpFilterConfigFactory. */ -class RateLimitFilterConfig : public HttpFilterConfigFactory { +class RateLimitFilterConfig : public NamedHttpFilterConfigFactory { public: - HttpFilterFactoryCb tryCreateFilterFactory(HttpFilterType type, const std::string& name, - const Json::Object& config, const std::string&, - Server::Instance& server) override; + HttpFilterFactoryCb createFilterFactory(HttpFilterType type, const Json::Object& config, + const std::string&, Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/config/http/router.cc b/source/server/config/http/router.cc index 8e7b8332524f..eea5977f1c40 100644 --- a/source/server/config/http/router.cc +++ b/source/server/config/http/router.cc @@ -10,13 +10,13 @@ namespace Envoy { namespace Server { namespace Configuration { -HttpFilterFactoryCb RouterFilterConfig::tryCreateFilterFactory(HttpFilterType type, - const std::string& name, - const Json::Object& json_config, - const std::string& stat_prefix, - Server::Instance& server) { - if (type != HttpFilterType::Decoder || name != "router") { - return nullptr; +HttpFilterFactoryCb RouterFilterConfig::createFilterFactory(HttpFilterType type, + const Json::Object& json_config, + const std::string& stat_prefix, + Server::Instance& server) { + if (type != HttpFilterType::Decoder) { + throw EnvoyException( + fmt::format("{} http filter must be configured as a decoder filter.", name())); } json_config.validateSchema(Json::Schema::ROUTER_HTTP_FILTER_SCHEMA); @@ -31,10 +31,12 @@ HttpFilterFactoryCb RouterFilterConfig::tryCreateFilterFactory(HttpFilterType ty -> void { callbacks.addStreamDecoderFilter(std::make_shared(*config)); }; } +std::string RouterFilterConfig::name() { return "router"; } + /** - * Static registration for the router filter. @see RegisterHttpFilterConfigFactory. + * Static registration for the router filter. @see RegisterNamedHttpFilterConfigFactory. */ -static RegisterHttpFilterConfigFactory register_; +static RegisterNamedHttpFilterConfigFactory register_; } // Configuration } // Server diff --git a/source/server/config/http/router.h b/source/server/config/http/router.h index b8136c6f8234..41434beacb74 100644 --- a/source/server/config/http/router.h +++ b/source/server/config/http/router.h @@ -11,14 +11,14 @@ namespace Server { namespace Configuration { /** - * Config registration for the router filter. @see HttpFilterConfigFactory. + * Config registration for the router filter. @see NamedHttpFilterConfigFactory. */ -class RouterFilterConfig : public HttpFilterConfigFactory { +class RouterFilterConfig : public NamedHttpFilterConfigFactory { public: - HttpFilterFactoryCb tryCreateFilterFactory(HttpFilterType type, const std::string& name, - const Json::Object& json_config, - const std::string& stat_prefix, - Server::Instance& server) override; + HttpFilterFactoryCb createFilterFactory(HttpFilterType type, const Json::Object& json_config, + const std::string& stat_prefix, + Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/config/http/zipkin_http_tracer.cc b/source/server/config/http/zipkin_http_tracer.cc new file mode 100644 index 000000000000..ae002740aaae --- /dev/null +++ b/source/server/config/http/zipkin_http_tracer.cc @@ -0,0 +1,36 @@ +#include "server/config/http/zipkin_http_tracer.h" + +#include + +#include "common/common/utility.h" +#include "common/tracing/http_tracer_impl.h" +#include "common/tracing/zipkin/zipkin_tracer_impl.h" + +namespace Envoy { +namespace Server { +namespace Configuration { + +Tracing::HttpTracerPtr +ZipkinHttpTracerFactory::createHttpTracer(const Json::Object& json_config, Server::Instance& server, + Upstream::ClusterManager& cluster_manager) { + + Envoy::Runtime::RandomGenerator& rand = server.random(); + + Tracing::DriverPtr zipkin_driver(new Zipkin::Driver(json_config, cluster_manager, server.stats(), + server.threadLocal(), server.runtime(), + server.localInfo(), rand)); + + return Tracing::HttpTracerPtr( + new Tracing::HttpTracerImpl(std::move(zipkin_driver), server.localInfo())); +} + +std::string ZipkinHttpTracerFactory::name() { return "zipkin"; } + +/** + * Static registration for the lightstep http tracer. @see RegisterHttpTracerFactory. + */ +static RegisterHttpTracerFactory register_; + +} // Configuration +} // Server +} // Envoy diff --git a/source/server/config/http/zipkin_http_tracer.h b/source/server/config/http/zipkin_http_tracer.h new file mode 100644 index 000000000000..fc464f6c99f0 --- /dev/null +++ b/source/server/config/http/zipkin_http_tracer.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include "envoy/server/instance.h" + +#include "server/configuration_impl.h" + +namespace Envoy { +namespace Server { +namespace Configuration { + +/** + * Config registration for the zipkin http tracer. @see HttpTracerFactory. + */ +class ZipkinHttpTracerFactory : public HttpTracerFactory { +public: + // HttpTracerFactory + Tracing::HttpTracerPtr createHttpTracer(const Json::Object& json_config, Server::Instance& server, + Upstream::ClusterManager& cluster_manager) override; + std::string name() override; +}; + +} // Configuration +} // Server +} // Envoy \ No newline at end of file diff --git a/source/server/config/network/client_ssl_auth.cc b/source/server/config/network/client_ssl_auth.cc index 7ead762cdbc6..6362648ba28e 100644 --- a/source/server/config/network/client_ssl_auth.cc +++ b/source/server/config/network/client_ssl_auth.cc @@ -11,12 +11,11 @@ namespace Envoy { namespace Server { namespace Configuration { -NetworkFilterFactoryCb -ClientSslAuthConfigFactory::tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object& json_config, - Server::Instance& server) { - if (type != NetworkFilterType::Read || name != "client_ssl_auth") { - return nullptr; +NetworkFilterFactoryCb ClientSslAuthConfigFactory::createFilterFactory( + NetworkFilterType type, const Json::Object& json_config, Server::Instance& server) { + if (type != NetworkFilterType::Read) { + throw EnvoyException( + fmt::format("{} network filter must be configured as a read filter.", name())); } Filter::Auth::ClientSsl::ConfigSharedPtr config(Filter::Auth::ClientSsl::Config::create( @@ -28,10 +27,12 @@ ClientSslAuthConfigFactory::tryCreateFilterFactory(NetworkFilterType type, const }; } +std::string ClientSslAuthConfigFactory::name() { return "client_ssl_auth"; } + /** - * Static registration for the client SSL auth filter. @see RegisterNetworkFilterConfigFactory. + * Static registration for the client SSL auth filter. @see RegisterNamedNetworkFilterConfigFactory. */ -static RegisterNetworkFilterConfigFactory registered_; +static RegisterNamedNetworkFilterConfigFactory registered_; } // Configuration } // Server diff --git a/source/server/config/network/client_ssl_auth.h b/source/server/config/network/client_ssl_auth.h index 56bb6ecf9696..5818d4b1e870 100644 --- a/source/server/config/network/client_ssl_auth.h +++ b/source/server/config/network/client_ssl_auth.h @@ -9,14 +9,15 @@ namespace Server { namespace Configuration { /** - * Config registration for the client SSL auth filter. @see NetworkFilterConfigFactory. + * Config registration for the client SSL auth filter. @see NamedNetworkFilterConfigFactory. */ -class ClientSslAuthConfigFactory : public NetworkFilterConfigFactory { +class ClientSslAuthConfigFactory : public NamedNetworkFilterConfigFactory { public: - // NetworkFilterConfigFactory - NetworkFilterFactoryCb tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object& json_config, - Server::Instance& server); + // NamedNetworkFilterConfigFactory + NetworkFilterFactoryCb createFilterFactory(NetworkFilterType type, + const Json::Object& json_config, + Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/config/network/echo.cc b/source/server/config/network/echo.cc index 63e14de6f9e5..136d0202e742 100644 --- a/source/server/config/network/echo.cc +++ b/source/server/config/network/echo.cc @@ -11,26 +11,29 @@ namespace Server { namespace Configuration { /** - * Config registration for the echo filter. @see NetworkFilterConfigFactory. + * Config registration for the echo filter. @see NamedNetworkFilterConfigFactory. */ -class EchoConfigFactory : public NetworkFilterConfigFactory { +class EchoConfigFactory : public NamedNetworkFilterConfigFactory { public: - // NetworkFilterConfigFactory - NetworkFilterFactoryCb tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object&, Server::Instance&) { - if (type != NetworkFilterType::Read || name != "echo") { - return nullptr; + // NamedNetworkFilterConfigFactory + NetworkFilterFactoryCb createFilterFactory(NetworkFilterType type, const Json::Object&, + Server::Instance&) override { + if (type != NetworkFilterType::Read) { + throw EnvoyException( + fmt::format("{} network filter must be configured as a read filter.", name())); } return [](Network::FilterManager& filter_manager) -> void { filter_manager.addReadFilter(Network::ReadFilterSharedPtr{new Filter::Echo()}); }; } + + std::string name() override { return "echo"; } }; /** - * Static registration for the echo filter. @see RegisterNetworkFilterConfigFactory. + * Static registration for the echo filter. @see RegisterNamedNetworkFilterConfigFactory. */ -static RegisterNetworkFilterConfigFactory registered_; +static RegisterNamedNetworkFilterConfigFactory registered_; } // Configuration } // Server diff --git a/source/server/config/network/http_connection_manager.cc b/source/server/config/network/http_connection_manager.cc index 252b41b94571..a78ee2c82a7c 100644 --- a/source/server/config/network/http_connection_manager.cc +++ b/source/server/config/network/http_connection_manager.cc @@ -26,11 +26,11 @@ namespace Configuration { const std::string HttpConnectionManagerConfig::DEFAULT_SERVER_STRING = "envoy"; -NetworkFilterFactoryCb HttpConnectionManagerFilterConfigFactory::tryCreateFilterFactory( - NetworkFilterType type, const std::string& name, const Json::Object& config, - Server::Instance& server) { - if (type != NetworkFilterType::Read || name != "http_connection_manager") { - return nullptr; +NetworkFilterFactoryCb HttpConnectionManagerFilterConfigFactory::createFilterFactory( + NetworkFilterType type, const Json::Object& config, Server::Instance& server) { + if (type != NetworkFilterType::Read) { + throw EnvoyException( + fmt::format("{} network filter must be configured as a read filter.", name())); } std::shared_ptr http_config( @@ -42,11 +42,14 @@ NetworkFilterFactoryCb HttpConnectionManagerFilterConfigFactory::tryCreateFilter }; } +std::string HttpConnectionManagerFilterConfigFactory::name() { return "http_connection_manager"; } + /** * Static registration for the HTTP connection manager filter. @see - * RegisterNetworkFilterConfigFactory. + * RegisterNamedNetworkFilterConfigFactory. */ -static RegisterNetworkFilterConfigFactory registered_; +static RegisterNamedNetworkFilterConfigFactory + registered_; std::string HttpConnectionManagerConfigUtility::determineNextProtocol(Network::Connection& connection, @@ -152,20 +155,31 @@ HttpConnectionManagerConfig::HttpConnectionManagerConfig(const Json::Object& con log().info(" name: {}", string_name); HttpFilterType type = stringToType(string_type); - bool found_filter = false; - for (HttpFilterConfigFactory* factory : filterConfigFactories()) { + + // Now see if there is a factory that will accept the config. + auto search_it = namedFilterConfigFactories().find(string_name); + if (search_it != namedFilterConfigFactories().end()) { HttpFilterFactoryCb callback = - factory->tryCreateFilterFactory(type, string_name, *config_object, stats_prefix_, server); - if (callback) { - filter_factories_.push_back(callback); - found_filter = true; - break; + search_it->second->createFilterFactory(type, *config_object, stats_prefix_, server); + filter_factories_.push_back(callback); + } else { + // DEPRECATED + // This name wasn't found in the named map, so search in the deprecated list registry. + bool found_filter = false; + for (HttpFilterConfigFactory* config_factory : filterConfigFactories()) { + HttpFilterFactoryCb callback = config_factory->tryCreateFilterFactory( + type, string_name, *config_object, stats_prefix_, server); + if (callback) { + filter_factories_.push_back(callback); + found_filter = true; + break; + } } - } - if (!found_filter) { - throw EnvoyException(fmt::format("unable to create http filter factory for '{}'/'{}'", - string_name, string_type)); + if (!found_filter) { + throw EnvoyException(fmt::format("unable to create http filter factory for '{}'/'{}'", + string_name, string_type)); + } } } } diff --git a/source/server/config/network/http_connection_manager.h b/source/server/config/network/http_connection_manager.h index b040329d4d21..304874056d26 100644 --- a/source/server/config/network/http_connection_manager.h +++ b/source/server/config/network/http_connection_manager.h @@ -24,15 +24,16 @@ namespace Configuration { enum class HttpFilterType { Decoder, Encoder, Both }; /** - * Config registration for the HTTP connection manager filter. @see NetworkFilterConfigFactory. + * Config registration for the HTTP connection manager filter. @see NamedNetworkFilterConfigFactory. */ class HttpConnectionManagerFilterConfigFactory : Logger::Loggable, - public NetworkFilterConfigFactory { + public NamedNetworkFilterConfigFactory { public: - // NetworkFilterConfigFactory - NetworkFilterFactoryCb tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object& config, - Server::Instance& server); + // NamedNetworkFilterConfigFactory + NetworkFilterFactoryCb createFilterFactory(NetworkFilterType type, const Json::Object& config, + Server::Instance& server) override; + + std::string name() override; }; /** @@ -41,8 +42,8 @@ class HttpConnectionManagerFilterConfigFactory : Logger::Loggable HttpFilterFactoryCb; /** - * Implemented by each HTTP filter and registered via registerHttpFilterConfigFactory() or the - * convenience class RegisterHttpFilterConfigFactory. + * DEPRECATED - Implemented by each HTTP filter and registered via registerHttpFilterConfigFactory() + * or the convenience class RegisterHttpFilterConfigFactory. */ class HttpFilterConfigFactory { public: @@ -54,6 +55,35 @@ class HttpFilterConfigFactory { Server::Instance& server) PURE; }; +/** + * Implemented by each HTTP filter and registered via registerNamedHttpFilterConfigFactory() or the + * convenience class RegisterNamedHttpFilterConfigFactory. + */ +class NamedHttpFilterConfigFactory { +public: + virtual ~NamedHttpFilterConfigFactory() {} + + /** + * Create a particular http filter factory implementation. If the implementation is unable to + * produce a factory with the provided parameters, it should throw an EnvoyException in the case of + * general error or a Json::Exception if the json configuration is erroneous. The returned + * callback should always be initialized. + * @param type supplies type of filter to initialize (decoder, encoder, or both) + * @param config supplies the general json configuration for the filter + * @param stat_prefix prefix for stat logging + * @param server supplies the server instance + */ + virtual HttpFilterFactoryCb createFilterFactory(HttpFilterType type, const Json::Object& config, + const std::string& stat_prefix, + Server::Instance& server) PURE; + + /** + * Returns the identifying name for a particular implementation of an http filter produced by the + * factory. + */ + virtual std::string name() PURE; +}; + /** * Utilities for the HTTP connection manager that facilitate testing. */ @@ -104,18 +134,56 @@ class HttpConnectionManagerConfig : Logger::Loggable, const Network::Address::Instance& localAddress() override; const Optional& userAgent() override { return user_agent_; } + /** + * DEPRECATED - Register an HttpFilterConfigFactory implementation as an option to create + * instances of HttpFilterFactoryCb. + * @param factory the HttpFilterConfigFactory implementation + */ static void registerHttpFilterConfigFactory(HttpFilterConfigFactory& factory) { filterConfigFactories().push_back(&factory); } + /** + * Register a NamedHttpFilterConfigFactory implementation as an option to create instances of + * HttpFilterFactoryCb. + * @param factory the NamedHttpFilterConfigFactory implementation + */ + static void registerNamedHttpFilterConfigFactory(NamedHttpFilterConfigFactory& factory) { + auto result = namedFilterConfigFactories().emplace(std::make_pair(factory.name(), &factory)); + + // result is a pair whose second member is a boolean indicating, if false, that the key exists + // and that the value was not inserted. + if (!result.second) { + throw EnvoyException(fmt::format( + "Attempted to register multiple NamedHttpFilterConfigFactory objects with name: '{}'", + factory.name())); + } + } + static const std::string DEFAULT_SERVER_STRING; private: enum class CodecType { HTTP1, HTTP2, AUTO }; + /** + * DEPRECATED - Returns a list of the currently registered HttpFilterConfigFactory + * implementations. + */ static std::list& filterConfigFactories() { - static std::list filter_config_factories; - return filter_config_factories; + static std::list* filter_config_factories = + new std::list; + return *filter_config_factories; + } + + /** + * Returns a map of the currently registered NamedHttpFilterConfigFactory implementations. + */ + static std::unordered_map& + namedFilterConfigFactories() { + static std::unordered_map* + named_filter_config_factories = + new std::unordered_map; + return *named_filter_config_factories; } HttpFilterType stringToType(const std::string& type); @@ -140,13 +208,34 @@ class HttpConnectionManagerConfig : Logger::Loggable, }; /** - * @see HttpFilterConfigFactory. + * @see NamedHttpFilterConfigFactory. An instantiation of this class registers a + * NamedHttpFilterConfigFactory implementation (T) so it can be used to create instances of + * HttpFilterFactoryCb. + */ +template class RegisterNamedHttpFilterConfigFactory { +public: + /** + * Registers the implementation. + */ + RegisterNamedHttpFilterConfigFactory() { + static T* instance = new T; + HttpConnectionManagerConfig::registerNamedHttpFilterConfigFactory(*instance); + } +}; + +/** + * DEPRECATED @see HttpFilterConfigFactory. An instantiation of this class registers a + * HttpFilterConfigFactory implementation (T) so it can be used to create instances of + * HttpFilterFactoryCb. */ template class RegisterHttpFilterConfigFactory { public: + /** + * Registers the implementation. + */ RegisterHttpFilterConfigFactory() { - static T instance; - HttpConnectionManagerConfig::registerHttpFilterConfigFactory(instance); + static T* instance = new T; + HttpConnectionManagerConfig::registerHttpFilterConfigFactory(*instance); } }; diff --git a/source/server/config/network/mongo_proxy.cc b/source/server/config/network/mongo_proxy.cc index db8462252c03..9a05b496b31a 100644 --- a/source/server/config/network/mongo_proxy.cc +++ b/source/server/config/network/mongo_proxy.cc @@ -12,11 +12,11 @@ namespace Envoy { namespace Server { namespace Configuration { -NetworkFilterFactoryCb MongoProxyFilterConfigFactory::tryCreateFilterFactory( - NetworkFilterType type, const std::string& name, const Json::Object& config, - Server::Instance& server) { - if (type != NetworkFilterType::Both || name != "mongo_proxy") { - return nullptr; +NetworkFilterFactoryCb MongoProxyFilterConfigFactory::createFilterFactory( + NetworkFilterType type, const Json::Object& config, Server::Instance& server) { + if (type != NetworkFilterType::Both) { + throw EnvoyException(fmt::format( + "{} network filter must be configured as both a read and write filter.", name())); } config.validateSchema(Json::Schema::MONGO_PROXY_NETWORK_FILTER_SCHEMA); @@ -34,10 +34,12 @@ NetworkFilterFactoryCb MongoProxyFilterConfigFactory::tryCreateFilterFactory( }; } +std::string MongoProxyFilterConfigFactory::name() { return "mongo_proxy"; } + /** - * Static registration for the mongo filter. @see RegisterNetworkFilterConfigFactory. + * Static registration for the mongo filter. @see RegisterNamedNetworkFilterConfigFactory. */ -static RegisterNetworkFilterConfigFactory registered_; +static RegisterNamedNetworkFilterConfigFactory registered_; } // Configuration } // Server diff --git a/source/server/config/network/mongo_proxy.h b/source/server/config/network/mongo_proxy.h index 678ad40e2a82..901b0297c28c 100644 --- a/source/server/config/network/mongo_proxy.h +++ b/source/server/config/network/mongo_proxy.h @@ -9,14 +9,15 @@ namespace Server { namespace Configuration { /** - * Config registration for the mongo proxy filter. @see NetworkFilterConfigFactory. + * Config registration for the mongo proxy filter. @see NamedNetworkFilterConfigFactory. */ -class MongoProxyFilterConfigFactory : public NetworkFilterConfigFactory { +class MongoProxyFilterConfigFactory : public NamedNetworkFilterConfigFactory { public: - // NetworkFilterConfigFactory - NetworkFilterFactoryCb tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object& config, - Server::Instance& server); + // NamedNetworkFilterConfigFactory + NetworkFilterFactoryCb createFilterFactory(NetworkFilterType type, const Json::Object& config, + Server::Instance& server) override; + + std::string name() override; }; } // Configuration diff --git a/source/server/config/network/ratelimit.cc b/source/server/config/network/ratelimit.cc index 0f46b20cedde..23c7a781afee 100644 --- a/source/server/config/network/ratelimit.cc +++ b/source/server/config/network/ratelimit.cc @@ -11,12 +11,12 @@ namespace Envoy { namespace Server { namespace Configuration { -NetworkFilterFactoryCb -RateLimitConfigFactory::tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object& json_config, - Server::Instance& server) { - if (type != NetworkFilterType::Read || name != "ratelimit") { - return nullptr; +NetworkFilterFactoryCb RateLimitConfigFactory::createFilterFactory(NetworkFilterType type, + const Json::Object& json_config, + Server::Instance& server) { + if (type != NetworkFilterType::Read) { + throw EnvoyException( + fmt::format("{} network filter must be configured as a read filter.", name())); } RateLimit::TcpFilter::ConfigSharedPtr config( @@ -27,10 +27,12 @@ RateLimitConfigFactory::tryCreateFilterFactory(NetworkFilterType type, const std }; } +std::string RateLimitConfigFactory::name() { return "ratelimit"; } + /** - * Static registration for the rate limit filter. @see RegisterNetworkFilterConfigFactory. + * Static registration for the rate limit filter. @see RegisterNamedNetworkFilterConfigFactory. */ -static RegisterNetworkFilterConfigFactory registered_; +static RegisterNamedNetworkFilterConfigFactory registered_; } // Configuration } // Server diff --git a/source/server/config/network/ratelimit.h b/source/server/config/network/ratelimit.h index 972b4f346edb..d6bb11672c3a 100644 --- a/source/server/config/network/ratelimit.h +++ b/source/server/config/network/ratelimit.h @@ -9,14 +9,16 @@ namespace Server { namespace Configuration { /** - * Config registration for the rate limit filter. @see NetworkFilterConfigFactory. + * Config registration for the rate limit filter. @see NamedNetworkFilterConfigFactory. */ -class RateLimitConfigFactory : public NetworkFilterConfigFactory { +class RateLimitConfigFactory : public NamedNetworkFilterConfigFactory { public: - // NetworkFilterConfigFactory - NetworkFilterFactoryCb tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object& json_config, - Server::Instance& server); + // NamedNetworkFilterConfigFactory + NetworkFilterFactoryCb createFilterFactory(NetworkFilterType type, + const Json::Object& json_config, + Server::Instance& server) override; + + std::string name() override; }; } // Configuration diff --git a/source/server/config/network/redis_proxy.cc b/source/server/config/network/redis_proxy.cc index c614298318bb..c950d8b71b97 100644 --- a/source/server/config/network/redis_proxy.cc +++ b/source/server/config/network/redis_proxy.cc @@ -12,11 +12,11 @@ namespace Envoy { namespace Server { namespace Configuration { -NetworkFilterFactoryCb RedisProxyFilterConfigFactory::tryCreateFilterFactory( - NetworkFilterType type, const std::string& name, const Json::Object& config, - Server::Instance& server) { - if (type != NetworkFilterType::Read || name != "redis_proxy") { - return nullptr; +NetworkFilterFactoryCb RedisProxyFilterConfigFactory::createFilterFactory( + NetworkFilterType type, const Json::Object& config, Server::Instance& server) { + if (type != NetworkFilterType::Read) { + throw EnvoyException( + fmt::format("{} network filter must be configured as a read filter.", name())); } Redis::ProxyFilterConfigSharedPtr filter_config( @@ -35,10 +35,12 @@ NetworkFilterFactoryCb RedisProxyFilterConfigFactory::tryCreateFilterFactory( }; } +std::string RedisProxyFilterConfigFactory::name() { return "redis_proxy"; } + /** - * Static registration for the redis filter. @see RegisterNetworkFilterConfigFactory. + * Static registration for the redis filter. @see RegisterNamedNetworkFilterConfigFactory. */ -static RegisterNetworkFilterConfigFactory registered_; +static RegisterNamedNetworkFilterConfigFactory registered_; } // Configuration } // Server diff --git a/source/server/config/network/redis_proxy.h b/source/server/config/network/redis_proxy.h index 058da13ec6ad..a162a2a26633 100644 --- a/source/server/config/network/redis_proxy.h +++ b/source/server/config/network/redis_proxy.h @@ -9,14 +9,14 @@ namespace Server { namespace Configuration { /** - * Config registration for the redis proxy filter. @see NetworkFilterConfigFactory. + * Config registration for the redis proxy filter. @see NamedNetworkFilterConfigFactory. */ -class RedisProxyFilterConfigFactory : public NetworkFilterConfigFactory { +class RedisProxyFilterConfigFactory : public NamedNetworkFilterConfigFactory { public: - // NetworkFilterConfigFactory - NetworkFilterFactoryCb tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object& config, - Server::Instance& server); + // NamedNetworkFilterConfigFactory + NetworkFilterFactoryCb createFilterFactory(NetworkFilterType type, const Json::Object& config, + Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/config/network/tcp_proxy.cc b/source/server/config/network/tcp_proxy.cc index f1f4afad0513..7365a3de727e 100644 --- a/source/server/config/network/tcp_proxy.cc +++ b/source/server/config/network/tcp_proxy.cc @@ -11,12 +11,12 @@ namespace Envoy { namespace Server { namespace Configuration { -NetworkFilterFactoryCb TcpProxyConfigFactory::tryCreateFilterFactory(NetworkFilterType type, - const std::string& name, - const Json::Object& config, - Server::Instance& server) { - if (type != NetworkFilterType::Read || name != "tcp_proxy") { - return nullptr; +NetworkFilterFactoryCb TcpProxyConfigFactory::createFilterFactory(NetworkFilterType type, + const Json::Object& config, + Server::Instance& server) { + if (type != NetworkFilterType::Read) { + throw EnvoyException( + fmt::format("{} network filter must be configured as a read filter.", name())); } Filter::TcpProxyConfigSharedPtr filter_config( @@ -27,10 +27,12 @@ NetworkFilterFactoryCb TcpProxyConfigFactory::tryCreateFilterFactory(NetworkFilt }; } +std::string TcpProxyConfigFactory::name() { return "tcp_proxy"; } + /** - * Static registration for the tcp_proxy filter. @see RegisterNetworkFilterConfigFactory. + * Static registration for the tcp_proxy filter. @see RegisterNamedNetworkFilterConfigFactory. */ -static RegisterNetworkFilterConfigFactory registered_; +static RegisterNamedNetworkFilterConfigFactory registered_; } // Configuration } // Server diff --git a/source/server/config/network/tcp_proxy.h b/source/server/config/network/tcp_proxy.h index 94a817a517c4..6ce37826ba85 100644 --- a/source/server/config/network/tcp_proxy.h +++ b/source/server/config/network/tcp_proxy.h @@ -9,14 +9,14 @@ namespace Server { namespace Configuration { /** - * Config registration for the tcp proxy filter. @see NetworkFilterConfigFactory. + * Config registration for the tcp proxy filter. @see NamedNetworkFilterConfigFactory. */ -class TcpProxyConfigFactory : public NetworkFilterConfigFactory { +class TcpProxyConfigFactory : public NamedNetworkFilterConfigFactory { public: - // NetworkFilterConfigFactory - NetworkFilterFactoryCb tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object& config, - Server::Instance& server); + // NamedNetworkFilterConfigFactory + NetworkFilterFactoryCb createFilterFactory(NetworkFilterType type, const Json::Object& config, + Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/configuration_impl.cc b/source/server/configuration_impl.cc index d98f8e605734..ecce1aa5424f 100644 --- a/source/server/configuration_impl.cc +++ b/source/server/configuration_impl.cc @@ -116,32 +116,14 @@ void MainImpl::initializeTracers(const Json::Object& configuration) { std::string type = driver->getString("type"); log().info(fmt::format(" loading tracing driver: {}", type)); - Envoy::Runtime::RandomGenerator& rand = server_.random(); + Json::ObjectSharedPtr driver_config = driver->getObject("config"); - if (type == "lightstep") { - Json::ObjectSharedPtr lightstep_config = driver->getObject("config"); - - std::unique_ptr opts(new lightstep::TracerOptions()); - opts->access_token = - server_.api().fileReadToEnd(lightstep_config->getString("access_token_file")); - StringUtil::rtrim(opts->access_token); - - opts->tracer_attributes["lightstep.component_name"] = server_.localInfo().clusterName(); - opts->guid_generator = [&rand]() { return rand.random(); }; - - Tracing::DriverPtr lightstep_driver( - new Tracing::LightStepDriver(*lightstep_config, *cluster_manager_, server_.stats(), - server_.threadLocal(), server_.runtime(), std::move(opts))); - http_tracer_.reset( - new Tracing::HttpTracerImpl(std::move(lightstep_driver), server_.localInfo())); + // Now see if there is a factory that will accept the config. + auto search_it = httpTracerFactories().find(type); + if (search_it != httpTracerFactories().end()) { + http_tracer_ = search_it->second->createHttpTracer(*driver_config, server_, *cluster_manager_); } else { - ASSERT(type == "zipkin"); - - Tracing::DriverPtr zipkin_driver( - new Zipkin::Driver(*driver->getObject("config"), *cluster_manager_, server_.stats(), - server_.threadLocal(), server_.runtime(), server_.localInfo(), rand)); - - http_tracer_.reset(new Tracing::HttpTracerImpl(std::move(zipkin_driver), server_.localInfo())); + throw EnvoyException(fmt::format("No HttpTracerFactory found for type: {}", type)); } } @@ -193,20 +175,29 @@ MainImpl::ListenerConfig::ListenerConfig(MainImpl& parent, Json::Object& json) : } // Now see if there is a factory that will accept the config. - bool found_filter = false; - for (NetworkFilterConfigFactory* config_factory : filterConfigFactories()) { + auto search_it = namedFilterConfigFactories().find(string_name); + if (search_it != namedFilterConfigFactories().end()) { NetworkFilterFactoryCb callback = - config_factory->tryCreateFilterFactory(type, string_name, *config, parent_.server_); - if (callback) { - filter_factories_.push_back(callback); - found_filter = true; - break; + search_it->second->createFilterFactory(type, *config, parent_.server_); + filter_factories_.push_back(callback); + } else { + // DEPRECATED + // This name wasn't found in the named map, so search in the deprecated list registry. + bool found_filter = false; + for (NetworkFilterConfigFactory* config_factory : filterConfigFactories()) { + NetworkFilterFactoryCb callback = + config_factory->tryCreateFilterFactory(type, string_name, *config, parent_.server_); + if (callback) { + filter_factories_.push_back(callback); + found_filter = true; + break; + } } - } - if (!found_filter) { - throw EnvoyException( - fmt::format("unable to create filter factory for '{}'/'{}'", string_name, string_type)); + if (!found_filter) { + throw EnvoyException( + fmt::format("unable to create filter factory for '{}'/'{}'", string_name, string_type)); + } } } } diff --git a/source/server/configuration_impl.h b/source/server/configuration_impl.h index b339dda5f289..9ae0bf38444c 100644 --- a/source/server/configuration_impl.h +++ b/source/server/configuration_impl.h @@ -6,11 +6,14 @@ #include #include #include +#include +#include #include "envoy/http/filter.h" #include "envoy/network/filter.h" #include "envoy/server/configuration.h" #include "envoy/server/instance.h" +#include "envoy/tracing/http_tracer.h" #include "common/common/logger.h" #include "common/json/json_loader.h" @@ -30,8 +33,8 @@ enum class NetworkFilterType { Read, Write, Both }; typedef std::function NetworkFilterFactoryCb; /** - * Implemented by each network filter and registered via registerNetworkFilterConfigFactory() or - * the convenience class RegisterNetworkFilterConfigFactory. + * DEPRECATED - Implemented by each network filter and registered via + * registerNetworkFilterConfigFactory() or the convenience class RegisterNetworkFilterConfigFactory. */ class NetworkFilterConfigFactory { public: @@ -43,6 +46,62 @@ class NetworkFilterConfigFactory { Server::Instance& server) PURE; }; +/** + * Implemented by each network filter and registered via registerNamedNetworkFilterConfigFactory() + * or the convenience class RegisterNamedNetworkFilterConfigFactory. + */ +class NamedNetworkFilterConfigFactory { +public: + virtual ~NamedNetworkFilterConfigFactory() {} + + /** + * Create a particular network filter factory implementation. If the implementation is unable to + * produce a factory with the provided parameters, it should throw an EnvoyException in the case + * of general error or a Json::Exception if the json configuration is erroneous. The returned + * callback should always be initialized. + * @param type supplies type of filter to initialize (read, write, or both) + * @param config supplies the general json configuration for the filter + * @param server supplies the server instance + */ + virtual NetworkFilterFactoryCb createFilterFactory(NetworkFilterType type, + const Json::Object& config, + Server::Instance& server) PURE; + + /** + * Returns the identifying name for a particular implementation of a network filter produced by + * the factory. + */ + virtual std::string name() PURE; +}; + +/** + * Implemented by each HttpTracer and registered via registerHttpTracerFactory() or + * the convenience class RegisterHttpTracerFactory. + */ +class HttpTracerFactory { +public: + virtual ~HttpTracerFactory() {} + + /** + * Create a particular HttpTracer implementation. If the implementation is unable to produce an + * HttpTracer with the provided parameters, it should throw an EnvoyException in the case of + * general error or a Json::Exception if the json configuration is erroneous. The returned pointer + * should always be valid. + * @param json_config supplies the general json configuration for the HttpTracer + * @param server supplies the server instance + * @param cluster_manager supplies the cluster_manager instance + */ + virtual Tracing::HttpTracerPtr createHttpTracer(const Json::Object& json_config, + Server::Instance& server, + Upstream::ClusterManager& cluster_manager) PURE; + + /** + * Returns the identifying name for a particular implementation of HttpTracer produced by the + * factory. + */ + virtual std::string name() PURE; +}; + /** * Utilities for creating a filter chain for a network connection. */ @@ -63,10 +122,48 @@ class MainImpl : Logger::Loggable, public Main { public: MainImpl(Server::Instance& server); + /** + * DEPRECATED - Register an NetworkFilterConfigFactory implementation as an option to create + * instances of NetworkFilterFactoryCb. + * @param factory the NetworkFilterConfigFactory implementation + */ static void registerNetworkFilterConfigFactory(NetworkFilterConfigFactory& factory) { filterConfigFactories().push_back(&factory); } + /** + * Register an NamedNetworkFilterConfigFactory implementation as an option to create instances of + * NetworkFilterFactoryCb. + * @param factory the NamedNetworkFilterConfigFactory implementation + */ + static void registerNamedNetworkFilterConfigFactory(NamedNetworkFilterConfigFactory& factory) { + auto result = namedFilterConfigFactories().emplace(std::make_pair(factory.name(), &factory)); + + // result is a pair whose second member is a boolean indicating, if false, that the key exists + // and that the value was not inserted. + if (!result.second) { + throw EnvoyException(fmt::format( + "Attempted to register multiple NamedNetworkFilterConfigFactory objects with name: '{}'", + factory.name())); + } + } + + /** + * Register an HttpTracerFactory as an option to create instances of HttpTracers. + * @param factory the HttpTracerFactory implementation + */ + static void registerHttpTracerFactory(HttpTracerFactory& factory) { + auto result = httpTracerFactories().emplace(std::make_pair(factory.name(), &factory)); + + // result is a pair whose second member is a boolean indicating, if false, that the key exists + // and that the value was not inserted. + if (!result.second) { + throw EnvoyException( + fmt::format("Attempted to register multiple HttpTracerFactory objects with name: '{}'", + factory.name())); + } + } + /** * Initialize the configuration. This happens here vs. the constructor because the initialization * will call through the server to get the cluster manager so the server variable must be @@ -130,9 +227,33 @@ class MainImpl : Logger::Loggable, public Main { std::list filter_factories_; }; + /** + * DEPRECATED - Returns a list of the currently registered NetworkConfigFactories. + */ static std::list& filterConfigFactories() { - static std::list filter_config_factories; - return filter_config_factories; + static std::list* filter_config_factories = + new std::list; + return *filter_config_factories; + } + + /** + * Returns a map of the currently registered NamedNetworkConfigFactories. + */ + static std::unordered_map& + namedFilterConfigFactories() { + static std::unordered_map* + named_filter_config_factories = + new std::unordered_map; + return *named_filter_config_factories; + } + + /** + * Returns a map of the currently registered HttpTracerFactories. + */ + static std::unordered_map& httpTracerFactories() { + static std::unordered_map* http_tracer_factories = + new std::unordered_map; + return *http_tracer_factories; } Server::Instance& server_; @@ -151,13 +272,49 @@ class MainImpl : Logger::Loggable, public Main { }; /** - * @see NetworkFilterConfigFactory. + * DEPRECATED - @see NetworkFilterConfigFactory. An instantiation of this class registers a + * NetworkFilterConfigFactory implementation (T) so it can be used to create instances of + * NetworkFilterFactoryCb. */ template class RegisterNetworkFilterConfigFactory { public: + /** + * Registers the implementation. + */ RegisterNetworkFilterConfigFactory() { - static T instance; - MainImpl::registerNetworkFilterConfigFactory(instance); + static T* instance = new T; + MainImpl::registerNetworkFilterConfigFactory(*instance); + } +}; + +/** + * @see NamedNetworkFilterConfigFactory. An instantiation of this class registers a + * NamedNetworkFilterConfigFactory implementation (T) so it can be used to create instances of + * NetworkFilterFactoryCb. + */ +template class RegisterNamedNetworkFilterConfigFactory { +public: + /** + * Registers the implementation. + */ + RegisterNamedNetworkFilterConfigFactory() { + static T* instance = new T; + MainImpl::registerNamedNetworkFilterConfigFactory(*instance); + } +}; + +/** + * @see HttpTracerFactory. An instantiation of this class registers an HttpTracerFactory + * implementation (T) so it can be used to create instances of HttpTracer. + */ +template class RegisterHttpTracerFactory { +public: + /** + * Registers the implementation. + */ + RegisterHttpTracerFactory() { + static T* instance = new T; + MainImpl::registerHttpTracerFactory(*instance); } }; diff --git a/source/server/http/health_check.cc b/source/server/http/health_check.cc index 96df845baebb..00b722341eab 100644 --- a/source/server/http/health_check.cc +++ b/source/server/http/health_check.cc @@ -22,15 +22,15 @@ namespace Server { namespace Configuration { /** - * Config registration for the health check filter. @see HttpFilterConfigFactory. + * Config registration for the health check filter. @see NamedHttpFilterConfigFactory. */ -HttpFilterFactoryCb HealthCheckFilterConfig::tryCreateFilterFactory(HttpFilterType type, - const std::string& name, - const Json::Object& config, - const std::string&, - Server::Instance& server) { - if (type != HttpFilterType::Both || name != "health_check") { - return nullptr; +HttpFilterFactoryCb HealthCheckFilterConfig::createFilterFactory(HttpFilterType type, + const Json::Object& config, + const std::string&, + Server::Instance& server) { + if (type != HttpFilterType::Both) { + throw EnvoyException(fmt::format( + "{} network filter must be configured as both a read and write filter.", name())); } config.validateSchema(Json::Schema::HEALTH_CHECK_HTTP_FILTER_SCHEMA); @@ -56,10 +56,12 @@ HttpFilterFactoryCb HealthCheckFilterConfig::tryCreateFilterFactory(HttpFilterTy }; } +std::string HealthCheckFilterConfig::name() { return "health_check"; } + /** - * Static registration for the health check filter. @see RegisterHttpFilterConfigFactory. + * Static registration for the health check filter. @see RegisterNamedHttpFilterConfigFactory. */ -static RegisterHttpFilterConfigFactory register_; +static RegisterNamedHttpFilterConfigFactory register_; } // Configuration } // Server diff --git a/source/server/http/health_check.h b/source/server/http/health_check.h index 6237573ec1c7..7430cbb97ae3 100644 --- a/source/server/http/health_check.h +++ b/source/server/http/health_check.h @@ -14,11 +14,11 @@ namespace Envoy { namespace Server { namespace Configuration { -class HealthCheckFilterConfig : public HttpFilterConfigFactory { +class HealthCheckFilterConfig : public NamedHttpFilterConfigFactory { public: - HttpFilterFactoryCb tryCreateFilterFactory(HttpFilterType type, const std::string& name, - const Json::Object& config, const std::string&, - Server::Instance& server) override; + HttpFilterFactoryCb createFilterFactory(HttpFilterType type, const Json::Object& config, + const std::string&, Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/test/integration/BUILD b/test/integration/BUILD index d33c5e2510d8..9ba65c128035 100644 --- a/test/integration/BUILD +++ b/test/integration/BUILD @@ -128,8 +128,10 @@ envoy_cc_test_library( "//source/server/config/http:dynamo_lib", "//source/server/config/http:fault_lib", "//source/server/config/http:grpc_http1_bridge_lib", + "//source/server/config/http:lightstep_lib", "//source/server/config/http:ratelimit_lib", "//source/server/config/http:router_lib", + "//source/server/config/http:zipkin_lib", "//source/server/config/network:client_ssl_auth_lib", "//source/server/config/network:echo_lib", "//source/server/config/network:http_connection_manager_lib", diff --git a/test/server/BUILD b/test/server/BUILD index 77ea8fc38a61..3339c39e3b05 100644 --- a/test/server/BUILD +++ b/test/server/BUILD @@ -21,11 +21,13 @@ envoy_cc_test( data = ["//test/common/ssl/test_data:certs"], deps = [ "//source/common/event:dispatcher_lib", + "//source/common/filter:echo_lib", "//source/server:configuration_lib", "//test/mocks:common_lib", "//test/mocks/network:network_mocks", "//test/mocks/server:server_mocks", "//test/test_common:environment_lib", + "//test/test_common:utility_lib", ], ) diff --git a/test/server/config/http/BUILD b/test/server/config/http/BUILD index 373c8530f437..1de16b1b075f 100644 --- a/test/server/config/http/BUILD +++ b/test/server/config/http/BUILD @@ -16,9 +16,12 @@ envoy_cc_test( "//source/server/config/http:dynamo_lib", "//source/server/config/http:fault_lib", "//source/server/config/http:grpc_http1_bridge_lib", + "//source/server/config/http:lightstep_lib", "//source/server/config/http:ratelimit_lib", "//source/server/config/http:router_lib", + "//source/server/config/http:zipkin_lib", "//source/server/http:health_check_lib", "//test/mocks/server:server_mocks", + "//test/test_common:utility_lib", ], ) diff --git a/test/server/config/http/config_test.cc b/test/server/config/http/config_test.cc index 42f8e3bb39b0..2469caafe049 100644 --- a/test/server/config/http/config_test.cc +++ b/test/server/config/http/config_test.cc @@ -4,11 +4,14 @@ #include "server/config/http/dynamo.h" #include "server/config/http/fault.h" #include "server/config/http/grpc_http1_bridge.h" +#include "server/config/http/lightstep_http_tracer.h" #include "server/config/http/ratelimit.h" #include "server/config/http/router.h" +#include "server/config/http/zipkin_http_tracer.h" #include "server/http/health_check.h" #include "test/mocks/server/mocks.h" +#include "test/test_common/utility.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -16,6 +19,7 @@ namespace Envoy { using testing::_; using testing::NiceMock; +using testing::Return; namespace Server { namespace Configuration { @@ -31,8 +35,8 @@ TEST(HttpFilterConfigTest, BufferFilter) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; BufferFilterConfig factory; - HttpFilterFactoryCb cb = factory.tryCreateFilterFactory(HttpFilterType::Decoder, "buffer", - *json_config, "stats", server); + HttpFilterFactoryCb cb = + factory.createFilterFactory(HttpFilterType::Decoder, *json_config, "stats", server); Http::MockFilterChainFactoryCallbacks filter_callback; EXPECT_CALL(filter_callback, addStreamDecoderFilter(_)); cb(filter_callback); @@ -49,8 +53,7 @@ TEST(HttpFilterConfigTest, BadBufferFilterConfig) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; BufferFilterConfig factory; - EXPECT_THROW(factory.tryCreateFilterFactory(HttpFilterType::Decoder, "buffer", *json_config, - "stats", server), + EXPECT_THROW(factory.createFilterFactory(HttpFilterType::Decoder, *json_config, "stats", server), Json::Exception); } @@ -63,8 +66,8 @@ TEST(HttpFilterConfigTest, DynamoFilter) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; DynamoFilterConfig factory; - HttpFilterFactoryCb cb = factory.tryCreateFilterFactory( - HttpFilterType::Both, "http_dynamo_filter", *json_config, "stats", server); + HttpFilterFactoryCb cb = + factory.createFilterFactory(HttpFilterType::Both, *json_config, "stats", server); Http::MockFilterChainFactoryCallbacks filter_callback; EXPECT_CALL(filter_callback, addStreamFilter(_)); cb(filter_callback); @@ -84,8 +87,8 @@ TEST(HttpFilterConfigTest, FaultFilter) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; FaultFilterConfig factory; - HttpFilterFactoryCb cb = factory.tryCreateFilterFactory(HttpFilterType::Decoder, "fault", - *json_config, "stats", server); + HttpFilterFactoryCb cb = + factory.createFilterFactory(HttpFilterType::Decoder, *json_config, "stats", server); Http::MockFilterChainFactoryCallbacks filter_callback; EXPECT_CALL(filter_callback, addStreamDecoderFilter(_)); cb(filter_callback); @@ -100,8 +103,8 @@ TEST(HttpFilterConfigTest, GrpcHttp1BridgeFilter) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; GrpcHttp1BridgeFilterConfig factory; - HttpFilterFactoryCb cb = factory.tryCreateFilterFactory(HttpFilterType::Both, "grpc_http1_bridge", - *json_config, "stats", server); + HttpFilterFactoryCb cb = + factory.createFilterFactory(HttpFilterType::Both, *json_config, "stats", server); Http::MockFilterChainFactoryCallbacks filter_callback; EXPECT_CALL(filter_callback, addStreamFilter(_)); cb(filter_callback); @@ -118,8 +121,8 @@ TEST(HttpFilterConfigTest, HealthCheckFilter) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; HealthCheckFilterConfig factory; - HttpFilterFactoryCb cb = factory.tryCreateFilterFactory(HttpFilterType::Both, "health_check", - *json_config, "stats", server); + HttpFilterFactoryCb cb = + factory.createFilterFactory(HttpFilterType::Both, *json_config, "stats", server); Http::MockFilterChainFactoryCallbacks filter_callback; EXPECT_CALL(filter_callback, addStreamFilter(_)); cb(filter_callback); @@ -137,8 +140,7 @@ TEST(HttpFilterConfigTest, BadHealthCheckFilterConfig) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; HealthCheckFilterConfig factory; - EXPECT_THROW(factory.tryCreateFilterFactory(HttpFilterType::Both, "health_check", *json_config, - "stats", server), + EXPECT_THROW(factory.createFilterFactory(HttpFilterType::Both, *json_config, "stats", server), Json::Exception); } @@ -152,8 +154,8 @@ TEST(HttpFilterConfigTest, RouterFilter) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; RouterFilterConfig factory; - HttpFilterFactoryCb cb = factory.tryCreateFilterFactory(HttpFilterType::Decoder, "router", - *json_config, "stats", server); + HttpFilterFactoryCb cb = + factory.createFilterFactory(HttpFilterType::Decoder, *json_config, "stats", server); Http::MockFilterChainFactoryCallbacks filter_callback; EXPECT_CALL(filter_callback, addStreamDecoderFilter(_)); cb(filter_callback); @@ -170,11 +172,58 @@ TEST(HttpFilterConfigTest, BadRouterFilterConfig) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; RouterFilterConfig factory; - EXPECT_THROW(factory.tryCreateFilterFactory(HttpFilterType::Decoder, "router", *json_config, - "stats", server), + EXPECT_THROW(factory.createFilterFactory(HttpFilterType::Decoder, *json_config, "stats", server), Json::Exception); } +TEST(HttpFilterConfigTest, DoubleRegistrationTest) { + EXPECT_THROW_WITH_MESSAGE( + RegisterNamedHttpFilterConfigFactory(), EnvoyException, + "Attempted to register multiple NamedHttpFilterConfigFactory objects with name: 'router'"); +} + +TEST(HttpTracerConfigTest, LightstepHttpTracer) { + NiceMock cm; + EXPECT_CALL(cm, get("fake_cluster")).WillRepeatedly(Return(&cm.thread_local_cluster_)); + 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", + "access_token_file": "fake_file" + } + )EOF"; + Json::ObjectSharedPtr valid_json = Json::Factory::loadFromString(valid_config); + NiceMock server; + LightstepHttpTracerFactory factory; + Tracing::HttpTracerPtr lightstep_tracer = factory.createHttpTracer(*valid_json, server, cm); + EXPECT_NE(nullptr, lightstep_tracer); +} + +TEST(HttpTracerConfigTest, ZipkinHttpTracer) { + NiceMock cm; + 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" + } + )EOF"; + Json::ObjectSharedPtr valid_json = Json::Factory::loadFromString(valid_config); + NiceMock server; + ZipkinHttpTracerFactory factory; + Tracing::HttpTracerPtr zipkin_tracer = factory.createHttpTracer(*valid_json, server, cm); + EXPECT_NE(nullptr, zipkin_tracer); +} + +TEST(HttpTracerConfigTest, DoubleRegistrationTest) { + EXPECT_THROW_WITH_MESSAGE( + RegisterHttpTracerFactory(), EnvoyException, + "Attempted to register multiple HttpTracerFactory objects with name: 'zipkin'"); +} + } // Configuration } // Server } // Envoy diff --git a/test/server/config/network/BUILD b/test/server/config/network/BUILD index d825cfc00d67..75e17b1c21a9 100644 --- a/test/server/config/network/BUILD +++ b/test/server/config/network/BUILD @@ -12,6 +12,7 @@ envoy_cc_test( name = "config_test", srcs = ["config_test.cc"], deps = [ + "//source/common/dynamo:dynamo_filter_lib", "//source/server/config/network:client_ssl_auth_lib", "//source/server/config/network:http_connection_manager_lib", "//source/server/config/network:mongo_proxy_lib", @@ -19,6 +20,7 @@ envoy_cc_test( "//source/server/config/network:redis_proxy_lib", "//source/server/config/network:tcp_proxy_lib", "//test/mocks/server:server_mocks", + "//test/test_common:utility_lib", ], ) diff --git a/test/server/config/network/config_test.cc b/test/server/config/network/config_test.cc index fcae5c40ff43..3319714f730e 100644 --- a/test/server/config/network/config_test.cc +++ b/test/server/config/network/config_test.cc @@ -1,5 +1,7 @@ #include +#include "common/dynamo/dynamo_filter.h" + #include "server/config/network/client_ssl_auth.h" #include "server/config/network/http_connection_manager.h" #include "server/config/network/mongo_proxy.h" @@ -8,6 +10,7 @@ #include "server/config/network/tcp_proxy.h" #include "test/mocks/server/mocks.h" +#include "test/test_common/utility.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -34,7 +37,7 @@ TEST(NetworkFilterConfigTest, RedisProxy) { NiceMock server; RedisProxyFilterConfigFactory factory; NetworkFilterFactoryCb cb = - factory.tryCreateFilterFactory(NetworkFilterType::Read, "redis_proxy", *json_config, server); + factory.createFilterFactory(NetworkFilterType::Read, *json_config, server); Network::MockConnection connection; EXPECT_CALL(connection, addReadFilter(_)); cb(connection); @@ -52,7 +55,7 @@ TEST(NetworkFilterConfigTest, MongoProxy) { NiceMock server; MongoProxyFilterConfigFactory factory; NetworkFilterFactoryCb cb = - factory.tryCreateFilterFactory(NetworkFilterType::Both, "mongo_proxy", *json_config, server); + factory.createFilterFactory(NetworkFilterType::Both, *json_config, server); Network::MockConnection connection; EXPECT_CALL(connection, addFilter(_)); cb(connection); @@ -70,9 +73,8 @@ TEST(NetworkFilterConfigTest, BadMongoProxyConfig) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; MongoProxyFilterConfigFactory factory; - EXPECT_THROW( - factory.tryCreateFilterFactory(NetworkFilterType::Both, "mongo_proxy", *json_config, server), - Json::Exception); + EXPECT_THROW(factory.createFilterFactory(NetworkFilterType::Both, *json_config, server), + Json::Exception); } TEST(NetworkFilterConfigTest, TcpProxy) { @@ -107,13 +109,13 @@ TEST(NetworkFilterConfigTest, TcpProxy) { NiceMock server; TcpProxyConfigFactory factory; NetworkFilterFactoryCb cb = - factory.tryCreateFilterFactory(NetworkFilterType::Read, "tcp_proxy", *json_config, server); + factory.createFilterFactory(NetworkFilterType::Read, *json_config, server); Network::MockConnection connection; EXPECT_CALL(connection, addReadFilter(_)); cb(connection); - EXPECT_EQ(nullptr, factory.tryCreateFilterFactory(NetworkFilterType::Both, "tcp_proxy", - *json_config, server)); + EXPECT_THROW(factory.createFilterFactory(NetworkFilterType::Both, *json_config, server), + EnvoyException); } TEST(NetworkFilterConfigTest, ClientSslAuth) { @@ -128,8 +130,8 @@ TEST(NetworkFilterConfigTest, ClientSslAuth) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; ClientSslAuthConfigFactory factory; - NetworkFilterFactoryCb cb = factory.tryCreateFilterFactory( - NetworkFilterType::Read, "client_ssl_auth", *json_config, server); + NetworkFilterFactoryCb cb = + factory.createFilterFactory(NetworkFilterType::Read, *json_config, server); Network::MockConnection connection; EXPECT_CALL(connection, addReadFilter(_)); cb(connection); @@ -148,7 +150,7 @@ TEST(NetworkFilterConfigTest, Ratelimit) { NiceMock server; RateLimitConfigFactory factory; NetworkFilterFactoryCb cb = - factory.tryCreateFilterFactory(NetworkFilterType::Read, "ratelimit", *json_config, server); + factory.createFilterFactory(NetworkFilterType::Read, *json_config, server); Network::MockConnection connection; EXPECT_CALL(connection, addReadFilter(_)); cb(connection); @@ -180,8 +182,7 @@ TEST(NetworkFilterConfigTest, BadHttpConnectionMangerConfig) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); HttpConnectionManagerFilterConfigFactory factory; NiceMock server; - EXPECT_THROW(factory.tryCreateFilterFactory(NetworkFilterType::Read, "http_connection_manager", - *json_config, server), + EXPECT_THROW(factory.createFilterFactory(NetworkFilterType::Read, *json_config, server), Json::Exception); } @@ -223,8 +224,7 @@ TEST(NetworkFilterConfigTest, BadAccessLogConfig) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); HttpConnectionManagerFilterConfigFactory factory; NiceMock server; - EXPECT_THROW(factory.tryCreateFilterFactory(NetworkFilterType::Read, "http_connection_manager", - *json_config, server), + EXPECT_THROW(factory.createFilterFactory(NetworkFilterType::Read, *json_config, server), Json::Exception); } @@ -268,8 +268,7 @@ TEST(NetworkFilterConfigTest, BadAccessLogType) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); HttpConnectionManagerFilterConfigFactory factory; NiceMock server; - EXPECT_THROW(factory.tryCreateFilterFactory(NetworkFilterType::Read, "http_connection_manager", - *json_config, server), + EXPECT_THROW(factory.createFilterFactory(NetworkFilterType::Read, *json_config, server), Json::Exception); } @@ -323,11 +322,77 @@ TEST(NetworkFilterConfigTest, BadAccessLogNestedTypes) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); HttpConnectionManagerFilterConfigFactory factory; NiceMock server; - EXPECT_THROW(factory.tryCreateFilterFactory(NetworkFilterType::Read, "http_connection_manager", - *json_config, server), + EXPECT_THROW(factory.createFilterFactory(NetworkFilterType::Read, *json_config, server), Json::Exception); } +/** + * Deprecated version of config registration for http dynamodb filter. + */ +class TestDeprecatedDynamoFilterConfig : public HttpFilterConfigFactory { +public: + HttpFilterFactoryCb tryCreateFilterFactory(HttpFilterType type, const std::string& name, + const Json::Object&, const std::string& stat_prefix, + Server::Instance& server) override { + if (type != HttpFilterType::Both || name != "http_dynamo_filter_deprecated") { + return nullptr; + } + + return [&server, stat_prefix](Http::FilterChainFactoryCallbacks& callbacks) -> void { + callbacks.addStreamFilter(Http::StreamFilterSharedPtr{ + new Dynamo::DynamoFilter(server.runtime(), stat_prefix, server.stats())}); + }; + } +}; + +TEST(NetworkFilterConfigTest, DeprecatedHttpFilterConfigFactoryTest) { + // Test just ensures that the deprecated http filter registration still works without error. + + // Register the config factory + RegisterHttpFilterConfigFactory registered; + + std::string json = R"EOF( + { + "codec_type" : "http1", + "stat_prefix" : "my_stat_prefix", + "route_config" : { + "virtual_hosts" : [ + { + "name" : "default", + "domains" : ["*"], + "routes" : [ + { + "prefix" : "/", + "cluster": "fake_cluster" + } + ] + } + ] + }, + "filters" : [ + { + "type" : "both", + "name" : "http_dynamo_filter_deprecated", + "config" : {} + } + ] + } + )EOF"; + + Json::ObjectSharedPtr loader = Json::Factory::loadFromString(json); + + HttpConnectionManagerFilterConfigFactory factory; + NiceMock server; + factory.createFilterFactory(NetworkFilterType::Read, *loader, server); +} + +TEST(NetworkFilterConfigTest, DoubleRegistrationTest) { + EXPECT_THROW_WITH_MESSAGE(RegisterNamedNetworkFilterConfigFactory(), + EnvoyException, "Attempted to register multiple " + "NamedNetworkFilterConfigFactory objects with name: " + "'client_ssl_auth'"); +} + } // Configuration } // Server } // Envoy diff --git a/test/server/configuration_impl_test.cc b/test/server/configuration_impl_test.cc index 7bcb89e8ed62..62a168bb638b 100644 --- a/test/server/configuration_impl_test.cc +++ b/test/server/configuration_impl_test.cc @@ -2,12 +2,15 @@ #include #include +#include "common/filter/echo.h" + #include "server/configuration_impl.h" #include "test/mocks/common.h" #include "test/mocks/network/mocks.h" #include "test/mocks/server/mocks.h" #include "test/test_common/environment.h" +#include "test/test_common/utility.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -275,6 +278,35 @@ TEST(ConfigurationImplTest, BadFilterConfig) { EXPECT_THROW(config.initialize(*loader), Json::Exception); } +TEST(ConfigurationImplTest, BadFilterName) { + std::string json = R"EOF( + { + "listeners" : [ + { + "address": "tcp://127.0.0.1:1234", + "filters": [ + { + "type" : "read", + "name" : "invalid", + "config" : {} + } + ] + } + ], + "cluster_manager": { + "clusters": [] + } + } + )EOF"; + + Json::ObjectSharedPtr loader = Json::Factory::loadFromString(json); + + NiceMock server; + MainImpl config(server); + EXPECT_THROW_WITH_MESSAGE(config.initialize(*loader), EnvoyException, + "unable to create filter factory for 'invalid'/'read'"); +} + TEST(ConfigurationImplTest, ServiceClusterNotSetWhenLSTracing) { std::string json = R"EOF( { @@ -368,6 +400,88 @@ TEST(ConfigurationImplTest, NullTracerSetWhenHttpKeyAbsentFromTracerConfiguratio EXPECT_NE(nullptr, dynamic_cast(&config.httpTracer())); } +TEST(ConfigurationImplTest, ConfigurationFailsWhenInvalidTracerSpecified) { + std::string json = R"EOF( + { + "listeners" : [ + { + "address": "tcp://127.0.0.1:1234", + "filters": [] + } + ], + "cluster_manager": { + "clusters": [] + }, + "tracing": { + "http": { + "driver": { + "type": "invalid", + "config": { + "access_token_file": "/etc/envoy/envoy.cfg" + } + } + } + } + } + )EOF"; + + Json::ObjectSharedPtr loader = Json::Factory::loadFromString(json); + + NiceMock server; + MainImpl config(server); + EXPECT_THROW_WITH_MESSAGE(config.initialize(*loader), EnvoyException, + "No HttpTracerFactory found for type: invalid"); +} + +/** + * Config registration for the echo filter using the deprecated registration class. + */ +class TestDeprecatedEchoConfigFactory : public NetworkFilterConfigFactory { +public: + // NetworkFilterConfigFactory + NetworkFilterFactoryCb tryCreateFilterFactory(NetworkFilterType type, const std::string& name, + const Json::Object&, Server::Instance&) override { + if (type != NetworkFilterType::Read || name != "echo_deprecated") { + return nullptr; + } + + return [](Network::FilterManager& filter_manager) + -> void { filter_manager.addReadFilter(Network::ReadFilterSharedPtr{new Filter::Echo()}); }; + } +}; + +TEST(NetworkFilterConfigTest, DeprecatedFilterConfigFactoryRegistrationTest) { + // Test ensures that the deprecated network filter registration still works without error. + + // Register the config factory + RegisterNetworkFilterConfigFactory registered; + + std::string json = R"EOF( + { + "listeners" : [ + { + "address": "tcp://127.0.0.1:1234", + "filters": [ + { + "type" : "read", + "name" : "echo_deprecated", + "config" : {} + } + ] + } + ], + "cluster_manager": { + "clusters": [] + } + } + )EOF"; + + Json::ObjectSharedPtr loader = Json::Factory::loadFromString(json); + + NiceMock server; + MainImpl config(server); + config.initialize(*loader); +} } // Configuration } // Server } // Envoy diff --git a/test/server/http/health_check_test.cc b/test/server/http/health_check_test.cc index 49755cd24864..977342ffe2ce 100644 --- a/test/server/http/health_check_test.cc +++ b/test/server/http/health_check_test.cc @@ -208,10 +208,10 @@ TEST(HealthCheckFilterConfig, failsWhenNotPassThroughButTimeoutSet) { "{\"pass_through_mode\":false, \"cache_time_ms\":234, \"endpoint\":\"foo\"}"); NiceMock serverMock; - EXPECT_THROW(healthCheckFilterConfig.tryCreateFilterFactory( - Server::Configuration::HttpFilterType::Both, "health_check", *config, - "dummy_stats_prefix", serverMock), - EnvoyException); + EXPECT_THROW( + healthCheckFilterConfig.createFilterFactory(Server::Configuration::HttpFilterType::Both, + *config, "dummy_stats_prefix", serverMock), + EnvoyException); } TEST(HealthCheckFilterConfig, notFailingWhenNotPassThroughAndTimeoutNotSet) { @@ -220,8 +220,7 @@ TEST(HealthCheckFilterConfig, notFailingWhenNotPassThroughAndTimeoutNotSet) { Json::Factory::loadFromString("{\"pass_through_mode\":false, \"endpoint\":\"foo\"}"); NiceMock serverMock; - healthCheckFilterConfig.tryCreateFilterFactory(Server::Configuration::HttpFilterType::Both, - "health_check", *config, "dummy_stats_prefix", - serverMock); + healthCheckFilterConfig.createFilterFactory(Server::Configuration::HttpFilterType::Both, *config, + "dummy_stats_prefix", serverMock); } } // Envoy