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

matching: add support for generic inputs and add environment variable input #15410

Merged
merged 16 commits into from
Apr 1, 2021
2 changes: 2 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,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/generic_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 @@ -243,6 +243,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/generic_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.generic_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.generic_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.generic_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.generic_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 @@ -126,6 +126,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/generic_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 @@ -82,6 +82,7 @@ EXTENSION_CATEGORIES = [
"envoy.health_checkers",
"envoy.internal_redirect_predicates",
"envoy.io_socket",
"envoy.matching.generic_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 @@ -25,3 +25,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/generic_inputs/environment/v3/environment.proto
1 change: 1 addition & 0 deletions generated_api_shadow/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,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/generic_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.

22 changes: 21 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,24 @@ template <class DataType> class DataInputFactory : public Config::TypedFactory {
}
};

class GenericDataInput {
htuch marked this conversation as resolved.
Show resolved Hide resolved
public:
virtual ~GenericDataInput() = default;
virtual absl::optional<absl::string_view> get() PURE;
};
using GenericDataInputPtr = std::unique_ptr<GenericDataInput>;

class GenericDataInputFactory : public Config::TypedFactory {
public:
/**
* Creates a GenericDataInput from the provided config.
*/
virtual GenericDataInputPtr
createGenericDataInput(const Protobuf::Message& config,
Server::Configuration::FactoryContext& factory_context) PURE;

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

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

// Wrapper around a GenericDataInput that allows it to be used as a DataInput<DataType>.
class GenericDataInputWrapper : public DataInput<DataType> {
public:
explicit GenericDataInputWrapper(GenericDataInputPtr&& generic_data_input)
: generic_data_input_(std::move(generic_data_input)) {}

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

private:
const GenericDataInputPtr generic_data_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 a generic input.
auto& generic_factory = Config::Utility::getAndCheckFactory<GenericDataInputFactory>(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(), generic_factory);
return std::make_unique<GenericDataInputWrapper>(
generic_factory.createGenericDataInput(*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 @@ -50,6 +50,12 @@ EXTENSIONS = {

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

#
# Generic Inputs
#

"envoy.matching.generic_inputs.environment_variable": "//source/extensions/matching/generic_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.generic_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/generic_inputs/environment_variable/v3:pkg_cc_proto",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include "extensions/matching/generic_inputs/environment_variable/config.h"

#include <memory>

#include "envoy/matcher/matcher.h"

namespace Envoy {
namespace Extensions {
namespace Matching {
namespace GenericInputs {
namespace EnvironmentVariable {

Envoy::Matcher::GenericDataInputPtr
Config::createGenericDataInput(const Protobuf::Message& config,
Server::Configuration::FactoryContext& factory_context) {
const auto& environment_config = MessageUtil::downcastAndValidate<
const envoy::extensions::matching::generic_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::GenericDataInputFactory);

} // namespace EnvironmentVariable
} // namespace GenericInputs
} // 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/generic_inputs/environment_variable/v3/input.pb.h"
#include "envoy/extensions/matching/generic_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/generic_inputs/environment_variable/input.h"

namespace Envoy {
namespace Extensions {
namespace Matching {
namespace GenericInputs {
namespace EnvironmentVariable {

class Config : public Envoy::Matcher::GenericDataInputFactory {
public:
Envoy::Matcher::GenericDataInputPtr
createGenericDataInput(const Protobuf::Message& config,
Server::Configuration::FactoryContext& factory_context) override;

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

ProtobufTypes::MessagePtr createEmptyConfigProto() override {
return std::make_unique<
envoy::extensions::matching::generic_inputs::environment_variable::v3::Config>();
}
};
} // namespace EnvironmentVariable
} // namespace GenericInputs
} // 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 GenericInputs {
namespace EnvironmentVariable {

class Input : public Envoy::Matcher::GenericDataInput {
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 GenericInputs
} // namespace Matching
} // namespace Extensions
} // namespace Envoy
Loading