Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

thrift: allow translation between downstream and upstream protocols #4136

Merged
merged 10 commits into from
Aug 20, 2018
1 change: 1 addition & 0 deletions api/docs/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ proto_library(
"//envoy/config/filter/network/rbac/v2:rbac",
"//envoy/config/filter/network/redis_proxy/v2:redis_proxy",
"//envoy/config/filter/network/tcp_proxy/v2:tcp_proxy",
"//envoy/config/filter/network/thrift_proxy/v2alpha1:thrift_proxy",
"//envoy/config/grpc_credential/v2alpha:file_based_metadata",
"//envoy/config/health_checker/redis/v2:redis",
"//envoy/config/metrics/v2:metrics_service",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ option go_package = "v2";
import "validate/validate.proto";
import "gogoproto/gogo.proto";

// [#protodoc-title: Thrift route configuration]
// [#protodoc-title: Thrift Proxy Route Configuration]
// Thrift Proxy :ref:`configuration overview <config_network_filters_thrift_proxy>`.

// [#comment:next free field: 3]
message RouteConfiguration {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,53 +8,79 @@ import "envoy/config/filter/network/thrift_proxy/v2alpha1/route.proto";
import "validate/validate.proto";
import "gogoproto/gogo.proto";

// [#protodoc-title: Extensions Thrift Proxy]
// Thrift Proxy filter configuration.
// [#protodoc-title: Thrift Proxy]
// Thrift Proxy :ref:`configuration overview <config_network_filters_thrift_proxy>`.

// [#comment:next free field: 5]
message ThriftProxy {
enum TransportType {
option (gogoproto.goproto_enum_prefix) = false;
// Supplies the type of transport that the Thrift proxy should use. Defaults to
// :ref:`AUTO_TRANSPORT<envoy_api_enum_value_config.filter.network.thrift_proxy.v2alpha1.TransportType.AUTO_TRANSPORT>`.
TransportType transport = 2 [(validate.rules).enum.defined_only = true];

// For every new connection, the Thrift proxy will determine which transport to use.
AUTO_TRANSPORT = 0;
// Supplies the type of protocol that the Thrift proxy should use. Defaults to
// :ref:`AUTO_PROTOCOL<envoy_api_enum_value_config.filter.network.thrift_proxy.v2alpha1.ProtocolType.AUTO_PROTOCOL>`.
ProtocolType protocol = 3 [(validate.rules).enum.defined_only = true];

// The Thrift proxy will assume the client is using the Thrift framed transport.
FRAMED = 1;
// The human readable prefix to use when emitting statistics.
string stat_prefix = 1 [(validate.rules).string.min_bytes = 1];

// The Thrift proxy will assume the client is using the Thrift unframed transport.
UNFRAMED = 2;
// The route table for the connection manager is static and is specified in this property.
RouteConfiguration route_config = 4;
}

// The Thrift proxy will assume the client is using the Thrift header transport.
HEADER = 3;
}
// Thrift transport types supported by Envoy.
enum TransportType {
option (gogoproto.goproto_enum_prefix) = false;

// Supplies the type of transport that the Thrift proxy should use. Defaults to `AUTO_TRANSPORT`.
TransportType transport = 2 [(validate.rules).enum.defined_only = true];
// For downstream connections, the Thrift proxy will attempt to determine which transport to use.
// For upstream connections, the Thrift proxy will use same transport as the downstream
// connection.
AUTO_TRANSPORT = 0;

enum ProtocolType {
option (gogoproto.goproto_enum_prefix) = false;
// The Thrift proxy will use the Thrift framed transport.
FRAMED = 1;

// For every new connection, the Thrift proxy will determine which protocol to use.
// N.B. The older, non-strict binary protocol is not included in automatic protocol
// detection.
AUTO_PROTOCOL = 0;
// The Thrift proxy will use the Thrift unframed transport.
UNFRAMED = 2;

// The Thrift proxy will assume the client is using the Thrift binary protocol.
BINARY = 1;
// The Thrift proxy will assume the client is using the Thrift header transport.
HEADER = 3;
}

// The Thrift proxy will assume the client is using the Thrift non-strict binary protocol.
LAX_BINARY = 2;
// Thrift Protocol types supported by Envoy.
enum ProtocolType {
option (gogoproto.goproto_enum_prefix) = false;

// The Thrift proxy will assume the client is using the Thrift compact protocol.
COMPACT = 3;
}
// For downstream connections, the Thrift proxy will attempt to determine which protocol to use.
// Note that the older, non-strict (or lax) binary protocol is not included in automatic protocol
// detection. For upstream connections, the Thrift proxy will use the same protocol as the
// downstream connection.
AUTO_PROTOCOL = 0;

// Supplies the type of protocol that the Thrift proxy should use. Defaults to `AUTO_PROTOCOL`.
ProtocolType protocol = 3 [(validate.rules).enum.defined_only = true];
// The Thrift proxy will use the Thrift binary protocol.
BINARY = 1;

// The human readable prefix to use when emitting statistics.
string stat_prefix = 1 [(validate.rules).string.min_bytes = 1];
// The Thrift proxy will use Thrift non-strict binary protocol.
LAX_BINARY = 2;

// The route table for the connection manager is static and is specified in this property.
RouteConfiguration route_config = 4;
// The Thrift proxy will use the Thrift compact protocol.
COMPACT = 3;
}

// ThriftProtocolOptions specifies Thrift upstream protocol options. This object is used in
// in :ref:`extension_protocol_options<envoy_api_field_Cluster.extension_protocol_options>`, keyed
// by the name `envoy.filters.network.thrift_proxy`.
// [#comment:next free field: 3]
message ThriftProtocolOptions {
// Supplies the type of transport that the Thrift proxy should use for upstream connections.
// Selecting
// :ref:`AUTO_TRANSPORT<envoy_api_enum_value_config.filter.network.thrift_proxy.v2alpha1.TransportType.AUTO_TRANSPORT>`,
// which is the default, causes the proxy to use the same transport as the downstream connection.
TransportType transport = 1 [(validate.rules).enum.defined_only = true];

// Supplies the type of protocol that the Thrift proxy should use for upstream connections.
// Selecting
// :ref:`AUTO_PROTOCOL<envoy_api_enum_value_config.filter.network.thrift_proxy.v2alpha1.ProtocolType.AUTO_PROTOCOL>`,
// which is the default, causes the proxy to use the same protocol as the downstream connection.
ProtocolType protocol = 2 [(validate.rules).enum.defined_only = true];
}
2 changes: 2 additions & 0 deletions docs/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ PROTO_RST="
/envoy/config/filter/network/rbac/v2/rbac/envoy/config/filter/network/rbac/v2/rbac.proto.rst
/envoy/config/filter/network/redis_proxy/v2/redis_proxy/envoy/config/filter/network/redis_proxy/v2/redis_proxy.proto.rst
/envoy/config/filter/network/tcp_proxy/v2/tcp_proxy/envoy/config/filter/network/tcp_proxy/v2/tcp_proxy.proto.rst
/envoy/config/filter/network/thrift_proxy/v2alpha1/thrift_proxy/envoy/config/filter/network/thrift_proxy/v2alpha1/thrift_proxy.proto.rst
/envoy/config/filter/network/thrift_proxy/v2alpha1/thrift_proxy/envoy/config/filter/network/thrift_proxy/v2alpha1/route.proto.rst
/envoy/config/health_checker/redis/v2/redis/envoy/config/health_checker/redis/v2/redis.proto.rst
/envoy/config/overload/v2alpha/overload/envoy/config/overload/v2alpha/overload.proto.rst
/envoy/config/rbac/v2alpha/rbac/envoy/config/rbac/v2alpha/rbac.proto.rst
Expand Down
1 change: 1 addition & 0 deletions docs/root/api-v2/config/filter/network/network.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ Network filters
:maxdepth: 2

*/v2/*
*/v2alpha1/*
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ filters.
rbac_filter
redis_proxy_filter
tcp_proxy_filter
thrift_proxy_filter
15 changes: 15 additions & 0 deletions docs/root/configuration/network_filters/thrift_proxy_filter.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.. _config_network_filters_thrift_proxy:

Thrift proxy
============

* :ref:`v2 API reference <envoy_api_msg_config.filter.network.thrift_proxy.v2alpha1.ThriftProxy>`

Cluster Protocol Options
------------------------

Thrift connections to upstream hosts can be configured by adding an entry to the appropriate
Cluster's :ref:`extension_protocol_options<envoy_api_field_Cluster.extension_protocol_options>`
keyed by `envoy.filters.network.thrift_proxy`. The
:ref:`ThriftProtocolOptions<envoy_api_msg_config.filter.network.thrift_proxy.v2alpha1.ThriftProtocolOptions>`
message describes the available options.
86 changes: 49 additions & 37 deletions source/extensions/filters/network/thrift_proxy/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,50 +25,81 @@ namespace NetworkFilters {
namespace ThriftProxy {
namespace {

typedef std::map<envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProxy_TransportType,
typedef std::map<envoy::config::filter::network::thrift_proxy::v2alpha1::TransportType,
TransportType>
TransportTypeMap;

static const TransportTypeMap& transportTypeMap() {
CONSTRUCT_ON_FIRST_USE(
TransportTypeMap,
{
{envoy::config::filter::network::thrift_proxy::v2alpha1::
ThriftProxy_TransportType_AUTO_TRANSPORT,
{envoy::config::filter::network::thrift_proxy::v2alpha1::TransportType::AUTO_TRANSPORT,
TransportType::Auto},
{envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProxy_TransportType_FRAMED,
{envoy::config::filter::network::thrift_proxy::v2alpha1::TransportType::FRAMED,
TransportType::Framed},
{envoy::config::filter::network::thrift_proxy::v2alpha1::
ThriftProxy_TransportType_UNFRAMED,
{envoy::config::filter::network::thrift_proxy::v2alpha1::TransportType::UNFRAMED,
TransportType::Unframed},
{envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProxy_TransportType_HEADER,
{envoy::config::filter::network::thrift_proxy::v2alpha1::TransportType::HEADER,
TransportType::Header},
});
}

typedef std::map<envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProxy_ProtocolType,
ProtocolType>
typedef std::map<envoy::config::filter::network::thrift_proxy::v2alpha1::ProtocolType, ProtocolType>
ProtocolTypeMap;

static const ProtocolTypeMap& protocolTypeMap() {
CONSTRUCT_ON_FIRST_USE(
ProtocolTypeMap,
{
{envoy::config::filter::network::thrift_proxy::v2alpha1::
ThriftProxy_ProtocolType_AUTO_PROTOCOL,
{envoy::config::filter::network::thrift_proxy::v2alpha1::ProtocolType::AUTO_PROTOCOL,
ProtocolType::Auto},
{envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProxy_ProtocolType_BINARY,
{envoy::config::filter::network::thrift_proxy::v2alpha1::ProtocolType::BINARY,
ProtocolType::Binary},
{envoy::config::filter::network::thrift_proxy::v2alpha1::
ThriftProxy_ProtocolType_LAX_BINARY,
{envoy::config::filter::network::thrift_proxy::v2alpha1::ProtocolType::LAX_BINARY,
ProtocolType::LaxBinary},
{envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProxy_ProtocolType_COMPACT,
{envoy::config::filter::network::thrift_proxy::v2alpha1::ProtocolType::COMPACT,
ProtocolType::Compact},
});
}

TransportType
lookupTransport(envoy::config::filter::network::thrift_proxy::v2alpha1::TransportType transport) {
const auto& transport_iter = transportTypeMap().find(transport);
if (transport_iter == transportTypeMap().end()) {
throw EnvoyException(fmt::format(
"unknown transport {}",
envoy::config::filter::network::thrift_proxy::v2alpha1::TransportType_Name(transport)));
}

return transport_iter->second;
}

ProtocolType
lookupProtocol(envoy::config::filter::network::thrift_proxy::v2alpha1::ProtocolType protocol) {
const auto& protocol_iter = protocolTypeMap().find(protocol);
if (protocol_iter == protocolTypeMap().end()) {
throw EnvoyException(fmt::format(
"unknown protocol {}",
envoy::config::filter::network::thrift_proxy::v2alpha1::ProtocolType_Name(protocol)));
}
return protocol_iter->second;
}

} // namespace

ProtocolOptionsConfigImpl::ProtocolOptionsConfigImpl(
const envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProtocolOptions& config)
: transport_(lookupTransport(config.transport())),
protocol_(lookupProtocol(config.protocol())) {}

TransportType ProtocolOptionsConfigImpl::transport(TransportType downstream_transport) const {
return (transport_ == TransportType::Auto) ? downstream_transport : transport_;
}

ProtocolType ProtocolOptionsConfigImpl::protocol(ProtocolType downstream_protocol) const {
return (protocol_ == ProtocolType::Auto) ? downstream_protocol : protocol_;
}

Network::FilterFactoryCb ThriftProxyFilterConfigFactory::createFilterFactoryFromProtoTyped(
const envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProxy& proto_config,
Server::Configuration::FactoryContext& context) {
Expand All @@ -91,23 +122,9 @@ ConfigImpl::ConfigImpl(
Server::Configuration::FactoryContext& context)
: context_(context), stats_prefix_(fmt::format("thrift.{}.", config.stat_prefix())),
stats_(ThriftFilterStats::generateStats(stats_prefix_, context_.scope())),
transport_(config.transport()), proto_(config.protocol()),
transport_(lookupTransport(config.transport())), proto_(lookupProtocol(config.protocol())),
route_matcher_(new Router::RouteMatcher(config.route_config())) {

if (transportTypeMap().find(transport_) == transportTypeMap().end()) {
throw EnvoyException(fmt::format(
"unknown transport {}",
envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProxy_TransportType_Name(
transport_)));
}

if (protocolTypeMap().find(proto_) == protocolTypeMap().end()) {
throw EnvoyException(fmt::format(
"unknown protocol {}",
envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProxy_ProtocolType_Name(
proto_)));
}

// Construct the only Thrift DecoderFilter: the Router
auto& factory =
Envoy::Config::Utility::getAndCheckFactory<ThriftFilters::NamedThriftFilterConfigFactory>(
Expand All @@ -130,16 +147,11 @@ DecoderPtr ConfigImpl::createDecoder(DecoderCallbacks& callbacks) {
}

TransportPtr ConfigImpl::createTransport() {
TransportTypeMap::const_iterator i = transportTypeMap().find(transport_);
ASSERT(i != transportTypeMap().end());

return NamedTransportConfigFactory::getFactory(i->second).createTransport();
return NamedTransportConfigFactory::getFactory(transport_).createTransport();
}

ProtocolPtr ConfigImpl::createProtocol() {
ProtocolTypeMap::const_iterator i = protocolTypeMap().find(proto_);
ASSERT(i != protocolTypeMap().end());
return NamedProtocolConfigFactory::getFactory(i->second).createProtocol();
return NamedProtocolConfigFactory::getFactory(proto_).createProtocol();
}

} // namespace ThriftProxy
Expand Down
31 changes: 28 additions & 3 deletions source/extensions/filters/network/thrift_proxy/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,44 @@ namespace Extensions {
namespace NetworkFilters {
namespace ThriftProxy {

/**
* Provides Thrift-specific cluster options.
*/
class ProtocolOptionsConfigImpl : public ProtocolOptionsConfig {
public:
ProtocolOptionsConfigImpl(
const envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProtocolOptions&
proto_config);

// ProtocolOptionsConfig
TransportType transport(TransportType downstream_transport) const override;
ProtocolType protocol(ProtocolType downstream_protocol) const override;

private:
const TransportType transport_;
const ProtocolType protocol_;
};

/**
* Config registration for the thrift proxy filter. @see NamedNetworkFilterConfigFactory.
*/
class ThriftProxyFilterConfigFactory
: public Common::FactoryBase<
envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProxy> {
envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProxy,
envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProtocolOptions> {
public:
ThriftProxyFilterConfigFactory() : FactoryBase(NetworkFilterNames::get().ThriftProxy) {}

private:
Network::FilterFactoryCb createFilterFactoryFromProtoTyped(
const envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProxy& proto_config,
Server::Configuration::FactoryContext& context) override;

Upstream::ProtocolOptionsConfigConstSharedPtr createProtocolOptionsTyped(
const envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProtocolOptions&
proto_config) override {
return std::make_shared<ProtocolOptionsConfigImpl>(proto_config);
}
};

class ConfigImpl : public Config,
Expand Down Expand Up @@ -61,8 +86,8 @@ class ConfigImpl : public Config,
Server::Configuration::FactoryContext& context_;
const std::string stats_prefix_;
ThriftFilterStats stats_;
envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProxy_TransportType transport_;
envoy::config::filter::network::thrift_proxy::v2alpha1::ThriftProxy_ProtocolType proto_;
const TransportType transport_;
const ProtocolType proto_;
std::unique_ptr<Router::RouteMatcher> route_matcher_;

std::list<ThriftFilters::FilterFactoryCb> filter_factories_;
Expand Down
11 changes: 11 additions & 0 deletions source/extensions/filters/network/thrift_proxy/conn_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ class Config {
virtual Router::Config& routerConfig() PURE;
};

/**
* Extends Upstream::ProtocolOptionsConfig with Thrift-specific cluster options.
*/
class ProtocolOptionsConfig : public Upstream::ProtocolOptionsConfig {
public:
virtual ~ProtocolOptionsConfig() {}

virtual TransportType transport(TransportType downstream_transport) const PURE;
virtual ProtocolType protocol(ProtocolType downstream_protocol) const PURE;
};

/**
* ConnectionManager is a Network::Filter that will perform Thrift request handling on a connection.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ envoy_cc_library(
"//include/envoy/upstream:load_balancer_interface",
"//include/envoy/upstream:thread_local_cluster_interface",
"//source/common/common:logger_lib",
"//source/extensions/filters/network:well_known_names",
"//source/extensions/filters/network/thrift_proxy:app_exception_lib",
"//source/extensions/filters/network/thrift_proxy:conn_manager_lib",
"//source/extensions/filters/network/thrift_proxy:protocol_converter_lib",
Expand Down
Loading