Skip to content

Commit

Permalink
alter authority when shadowing (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattklein123 authored Sep 1, 2016
1 parent d9a1f1e commit 29ea37b
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 0 deletions.
8 changes: 8 additions & 0 deletions docs/configuration/http_conn_man/route_config/route.rst
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,14 @@ global
Shadow
------

The router is capable of shadowing traffic from one cluster to another. The current implementation
is "fire and forget," meaning Envoy will not wait for the shadow cluster to respond before returning
the response from the primary cluster. All normal statistics are collected however for the shadow
cluster making thie feature useful for testing.

During shadowing, the host/authority header is altered such that *-shadow* is appended. This is
useful for logging. For example, *cluster1* becomes *cluster1-shadow*.

.. code-block:: json
{
Expand Down
9 changes: 9 additions & 0 deletions source/common/router/shadow_writer_impl.cc
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
#include "shadow_writer_impl.h"

#include "common/common/assert.h"
#include "common/http/headers.h"

namespace Router {

void ShadowWriterImpl::shadow(const std::string& cluster, Http::MessagePtr&& request,
std::chrono::milliseconds timeout) {
// Switch authority to add a shadow postfix. This allows upstream logging to make a more sense.
std::string host = request->headers().get(Http::Headers::get().Host);
ASSERT(!host.empty());
host += "-shadow";
request->headers().replaceViaMoveValue(Http::Headers::get().Host, std::move(host));

// Configuration should guarantee that cluster exists before calling here. This is basically
// fire and forget. We don't handle cancelling.
cm_.httpAsyncClientForCluster(cluster)
Expand Down
5 changes: 5 additions & 0 deletions test/common/router/shadow_writer_impl_test.cc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "common/http/headers.h"
#include "common/router/shadow_writer_impl.h"

#include "test/mocks/upstream/mocks.h"
Expand All @@ -13,6 +14,7 @@ TEST(ShadowWriterImplTest, All) {

// Success case
Http::MessagePtr message(new Http::RequestMessageImpl());
message->headers().addViaCopy(Http::Headers::get().Host, "cluster1");
EXPECT_CALL(cm, httpAsyncClientForCluster("foo")).WillOnce(ReturnRef(cm.async_client_));
Http::MockAsyncClientRequest request(&cm.async_client_);
Http::AsyncClient::Callbacks* callback;
Expand All @@ -22,6 +24,7 @@ TEST(ShadowWriterImplTest, All) {
Invoke([&](Http::MessagePtr& inner_message, Http::AsyncClient::Callbacks& callbacks,
const Optional<std::chrono::milliseconds>&) -> Http::AsyncClient::Request* {
EXPECT_EQ(message, inner_message);
EXPECT_EQ("cluster1-shadow", message->headers().get(Http::Headers::get().Host));
callback = &callbacks;
return &request;
}));
Expand All @@ -32,13 +35,15 @@ TEST(ShadowWriterImplTest, All) {

// Failure case
message.reset(new Http::RequestMessageImpl());
message->headers().addViaCopy(Http::Headers::get().Host, "cluster2");
EXPECT_CALL(cm, httpAsyncClientForCluster("bar")).WillOnce(ReturnRef(cm.async_client_));
EXPECT_CALL(cm.async_client_,
send_(_, _, Optional<std::chrono::milliseconds>(std::chrono::milliseconds(10))))
.WillOnce(
Invoke([&](Http::MessagePtr& inner_message, Http::AsyncClient::Callbacks& callbacks,
const Optional<std::chrono::milliseconds>&) -> Http::AsyncClient::Request* {
EXPECT_EQ(message, inner_message);
EXPECT_EQ("cluster2-shadow", message->headers().get(Http::Headers::get().Host));
callback = &callbacks;
return &request;
}));
Expand Down

0 comments on commit 29ea37b

Please sign in to comment.