Skip to content

Commit

Permalink
matching: add support for generic inputs and add environment variable…
Browse files Browse the repository at this point in the history
… input (#15410)

Adds support for a "generic input" extension point that allows specifying inputs that are not dependent on protocol data.

Adds an environment variable generic input that allows matching on the value of an environment variable.

Signed-off-by: Snow Pettersen <[email protected]>
  • Loading branch information
snowp authored Apr 1, 2021
1 parent 74f203d commit 758a9a9
Show file tree
Hide file tree
Showing 26 changed files with 442 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ extensions/filters/http/oauth2 @rgs1 @derekargueta @snowp
/*/extensions/rate_limit_descriptors/expr @kyessenov @lizan
# hash input matcher
/*/extensions/matching/input_matchers/consistent_hashing @snowp @donyu
# environment generic input
/*/extensions/matching/common_inputs/environment @snowp @donyu
# user space socket pair and event
/*/extensions/io_socket/user_space @lambdai @antoniovicente
# Default UUID4 request ID extension
Expand Down
1 change: 1 addition & 0 deletions api/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ proto_library(
"//envoy/extensions/internal_redirect/allow_listed_routes/v3:pkg",
"//envoy/extensions/internal_redirect/previous_routes/v3:pkg",
"//envoy/extensions/internal_redirect/safe_cross_scheme/v3:pkg",
"//envoy/extensions/matching/common_inputs/environment_variable/v3:pkg",
"//envoy/extensions/matching/input_matchers/consistent_hashing/v3:pkg",
"//envoy/extensions/network/socket_interface/v3:pkg",
"//envoy/extensions/rate_limit_descriptors/expr/v3:pkg",
Expand Down
1 change: 1 addition & 0 deletions api/envoy/config/common/matcher/v3/matcher.proto
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ message Matcher {
// Predicate for a single input field.
message SinglePredicate {
// Protocol-specific specification of input field to match on.
// [#extension-category: envoy.matching.common_inputs]
core.v3.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}];

oneof matcher {
Expand Down
1 change: 1 addition & 0 deletions api/envoy/config/common/matcher/v4alpha/matcher.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py.

load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package")

licenses(["notice"]) # Apache 2

api_proto_package(
deps = ["@com_github_cncf_udpa//udpa/annotations:pkg"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
syntax = "proto3";

package envoy.extensions.matching.common_inputs.environment_variable.v3;

import "udpa/annotations/migrate.proto";
import "udpa/annotations/status.proto";
import "udpa/annotations/versioning.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.extensions.matching.common_inputs.environment_variable.v3";
option java_outer_classname = "InputProto";
option java_multiple_files = true;
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: Environment Variable Input]
// [#extension: envoy.matching.common_inputs.environment_variable]

// Reads an environment variable to provide an input for matching.
message Config {
// Name of the environment variable to read from.
string name = 1 [(validate.rules).string = {min_len: 1}];
}
1 change: 1 addition & 0 deletions api/versioning/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ proto_library(
"//envoy/extensions/internal_redirect/allow_listed_routes/v3:pkg",
"//envoy/extensions/internal_redirect/previous_routes/v3:pkg",
"//envoy/extensions/internal_redirect/safe_cross_scheme/v3:pkg",
"//envoy/extensions/matching/common_inputs/environment_variable/v3:pkg",
"//envoy/extensions/matching/input_matchers/consistent_hashing/v3:pkg",
"//envoy/extensions/network/socket_interface/v3:pkg",
"//envoy/extensions/rate_limit_descriptors/expr/v3:pkg",
Expand Down
1 change: 1 addition & 0 deletions bazel/envoy_library.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ EXTENSION_CATEGORIES = [
"envoy.http.stateful_header_formatters",
"envoy.internal_redirect_predicates",
"envoy.io_socket",
"envoy.matching.common_inputs",
"envoy.matching.input_matchers",
"envoy.rate_limit_descriptors",
"envoy.request_id",
Expand Down
1 change: 1 addition & 0 deletions docs/root/api-v3/common_messages/common_messages.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ Common messages
../extensions/filters/common/dependency/v3/dependency.proto
../extensions/filters/common/matcher/action/v3/skip_action.proto
../extensions/matching/input_matchers/consistent_hashing/v3/consistent_hashing.proto
../extensions/matching/common_inputs/environment_variable/v3/input.proto
1 change: 1 addition & 0 deletions generated_api_shadow/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ proto_library(
"//envoy/extensions/internal_redirect/allow_listed_routes/v3:pkg",
"//envoy/extensions/internal_redirect/previous_routes/v3:pkg",
"//envoy/extensions/internal_redirect/safe_cross_scheme/v3:pkg",
"//envoy/extensions/matching/common_inputs/environment_variable/v3:pkg",
"//envoy/extensions/matching/input_matchers/consistent_hashing/v3:pkg",
"//envoy/extensions/network/socket_interface/v3:pkg",
"//envoy/extensions/rate_limit_descriptors/expr/v3:pkg",
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 28 additions & 1 deletion include/envoy/matcher/matcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,8 @@ struct DataInputGetResult {
};

/**
* Interface for types providing a way to extract a string from the DataType to perform matching on.
* Interface for types providing a way to extract a string from the DataType to perform matching
* on.
*/
template <class DataType> class DataInput {
public:
Expand Down Expand Up @@ -236,5 +237,31 @@ template <class DataType> class DataInputFactory : public Config::TypedFactory {
}
};

/**
* Interface for types providing a way to use a string for matching without depending on protocol
* data. As a result, these can be used for all protocols.
*/
class CommonProtocolInput {
public:
virtual ~CommonProtocolInput() = default;
virtual absl::optional<absl::string_view> get() PURE;
};
using CommonProtocolInputPtr = std::unique_ptr<CommonProtocolInput>;

/**
* Factory for CommonProtocolInput.
*/
class CommonProtocolInputFactory : public Config::TypedFactory {
public:
/**
* Creates a CommonProtocolInput from the provided config.
*/
virtual CommonProtocolInputPtr
createCommonProtocolInput(const Protobuf::Message& config,
Server::Configuration::FactoryContext& factory_context) PURE;

std::string category() const override { return "envoy.matching.common_inputs"; }
};

} // namespace Matcher
} // namespace Envoy
32 changes: 29 additions & 3 deletions source/common/matcher/matcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,12 +155,38 @@ template <class DataType> class MatchTreeFactory {
return absl::nullopt;
}

// Wrapper around a CommonProtocolInput that allows it to be used as a DataInput<DataType>.
class CommonProtocolInputWrapper : public DataInput<DataType> {
public:
explicit CommonProtocolInputWrapper(CommonProtocolInputPtr&& common_protocol_input)
: common_protocol_input_(std::move(common_protocol_input)) {}

DataInputGetResult get(const DataType&) override {
return DataInputGetResult{DataInputGetResult::DataAvailability::AllDataAvailable,
common_protocol_input_->get()};
}

private:
const CommonProtocolInputPtr common_protocol_input_;
};

DataInputPtr<DataType>
createDataInput(const envoy::config::core::v3::TypedExtensionConfig& config) {
auto& factory = Config::Utility::getAndCheckFactory<DataInputFactory<DataType>>(config);
auto* factory = Config::Utility::getFactory<DataInputFactory<DataType>>(config);
if (factory != nullptr) {
ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig(
config.typed_config(), factory_context_.messageValidationVisitor(), *factory);
return factory->createDataInput(*message, factory_context_);
}

// If the provided config doesn't match a typed input, assume that this is one of the common
// inputs.
auto& common_input_factory =
Config::Utility::getAndCheckFactory<CommonProtocolInputFactory>(config);
ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig(
config.typed_config(), factory_context_.messageValidationVisitor(), factory);
return factory.createDataInput(*message, factory_context_);
config.typed_config(), factory_context_.messageValidationVisitor(), common_input_factory);
return std::make_unique<CommonProtocolInputWrapper>(
common_input_factory.createCommonProtocolInput(*message, factory_context_));
}

InputMatcherPtr createInputMatcher(
Expand Down
6 changes: 6 additions & 0 deletions source/extensions/extensions_build_config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ EXTENSIONS = {

"envoy.matching.input_matchers.consistent_hashing": "//source/extensions/matching/input_matchers/consistent_hashing:config",

#
# Generic Inputs
#

"envoy.matching.common_inputs.environment_variable": "//source/extensions/matching/common_inputs/environment_variable:config",

#
# HTTP filters
#
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_extension",
"envoy_cc_library",
"envoy_extension_package",
)

licenses(["notice"]) # Apache 2

envoy_extension_package()

envoy_cc_library(
name = "input_lib",
hdrs = ["input.h"],
deps = [
"//include/envoy/matcher:matcher_interface",
"//source/common/common:hash_lib",
],
)

envoy_cc_extension(
name = "config",
srcs = ["config.cc"],
hdrs = ["config.h"],
category = "envoy.matching.common_inputs",
security_posture = "robust_to_untrusted_downstream",
deps = [
":input_lib",
"//include/envoy/matcher:matcher_interface",
"//include/envoy/registry",
"//include/envoy/server:factory_context_interface",
"@envoy_api//envoy/extensions/matching/common_inputs/environment_variable/v3:pkg_cc_proto",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include "extensions/matching/common_inputs/environment_variable/config.h"

#include <memory>

#include "envoy/matcher/matcher.h"

namespace Envoy {
namespace Extensions {
namespace Matching {
namespace CommonInputs {
namespace EnvironmentVariable {

Envoy::Matcher::CommonProtocolInputPtr
Config::createCommonProtocolInput(const Protobuf::Message& config,
Server::Configuration::FactoryContext& factory_context) {
const auto& environment_config = MessageUtil::downcastAndValidate<
const envoy::extensions::matching::common_inputs::environment_variable::v3::Config&>(
config, factory_context.messageValidationVisitor());

// We read the env variable at construction time to avoid repeat lookups.
// This assumes that the environment remains stable during the process lifetime.
auto* value = getenv(environment_config.name().data());
if (value != nullptr) {
return std::make_unique<Input>(std::string(value));
}

return std::make_unique<Input>(absl::nullopt);
}

/**
* Static registration for the environment data input. @see RegisterFactory.
*/
REGISTER_FACTORY(Config, Envoy::Matcher::CommonProtocolInputFactory);

} // namespace EnvironmentVariable
} // namespace CommonInputs
} // namespace Matching
} // namespace Extensions
} // namespace Envoy
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include "envoy/extensions/matching/common_inputs/environment_variable/v3/input.pb.h"
#include "envoy/extensions/matching/common_inputs/environment_variable/v3/input.pb.validate.h"
#include "envoy/matcher/matcher.h"
#include "envoy/server/factory_context.h"

#include "common/protobuf/utility.h"

#include "extensions/matching/common_inputs/environment_variable/input.h"

namespace Envoy {
namespace Extensions {
namespace Matching {
namespace CommonInputs {
namespace EnvironmentVariable {

class Config : public Envoy::Matcher::CommonProtocolInputFactory {
public:
Envoy::Matcher::CommonProtocolInputPtr
createCommonProtocolInput(const Protobuf::Message& config,
Server::Configuration::FactoryContext& factory_context) override;

std::string name() const override { return "envoy.matching.common_inputs.environment_variable"; }

ProtobufTypes::MessagePtr createEmptyConfigProto() override {
return std::make_unique<
envoy::extensions::matching::common_inputs::environment_variable::v3::Config>();
}
};
} // namespace EnvironmentVariable
} // namespace CommonInputs
} // namespace Matching
} // namespace Extensions
} // namespace Envoy
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

#include "envoy/matcher/matcher.h"

namespace Envoy {
namespace Extensions {
namespace Matching {
namespace CommonInputs {
namespace EnvironmentVariable {

class Input : public Matcher::CommonProtocolInput {
public:
explicit Input(absl::optional<std::string>&& value) : storage_(std::move(value)) {}

absl::optional<absl::string_view> get() override { return storage_; }

private:
const absl::optional<std::string> storage_;
};
} // namespace EnvironmentVariable
} // namespace CommonInputs
} // namespace Matching
} // namespace Extensions
} // namespace Envoy
Loading

0 comments on commit 758a9a9

Please sign in to comment.