Skip to content
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
4d2c47e
intitial commit for xds tracer extension point
botengyao Oct 13, 2022
b5234d2
clean up
botengyao Oct 13, 2022
ba27917
clean up
botengyao Oct 13, 2022
43b5983
add some docs
botengyao Oct 24, 2022
bdc4b16
Merge remote-tracking branch 'upstream/main' into xds-metadata-extens…
botengyao Oct 24, 2022
12bb4f3
clean up
botengyao Oct 24, 2022
51533cf
clean up
botengyao Oct 24, 2022
7ac3748
clean up
botengyao Oct 24, 2022
a04823a
fix format
botengyao Oct 25, 2022
5f4ed83
Merge remote-tracking branch 'upstream/main' into xds-metadata-extens…
botengyao Oct 26, 2022
2ab302b
Add more comments
botengyao Oct 28, 2022
340d71e
fix typo
botengyao Oct 28, 2022
ca58505
Merge remote-tracking branch 'upstream/main' into xds-metadata-extens…
botengyao Nov 4, 2022
acfb636
make it more generic
botengyao Nov 8, 2022
fe3066e
Merge remote-tracking branch 'upstream/main' into xds-metadata-extens…
botengyao Nov 8, 2022
2c11de7
clean up
botengyao Nov 8, 2022
f19005e
fix format
botengyao Nov 8, 2022
8a4b472
changed name to onConfigReceivedOrFailed
botengyao Nov 9, 2022
11c8def
changed name to onConfigReceivedOrFailed
botengyao Nov 9, 2022
a48502a
clean up
botengyao Nov 9, 2022
3efd2b3
add unified mux xds
botengyao Nov 15, 2022
1a65c33
Merge remote-tracking branch 'upstream/main' into xds-metadata-extens…
botengyao Nov 15, 2022
6796419
add comments
botengyao Nov 15, 2022
7aec7d1
fix spell
botengyao Nov 15, 2022
adaf244
fix ci
botengyao Nov 16, 2022
621327d
Merge remote-tracking branch 'upstream/main' into xds-metadata-extens…
botengyao Nov 16, 2022
a144dbd
fix ci
botengyao Nov 16, 2022
bf8105c
fix clang
botengyao Nov 17, 2022
91dc002
fix intergration test
botengyao Nov 18, 2022
b897721
clean up
botengyao Nov 18, 2022
b805acb
fix comments
botengyao Nov 23, 2022
ac31b6e
Merge remote-tracking branch 'upstream/main' into xds-metadata-extens…
botengyao Nov 23, 2022
a382c6d
Merge remote-tracking branch 'upstream/main' into xds-metadata-extens…
botengyao Nov 30, 2022
9b23b37
simplify test
botengyao Dec 5, 2022
41a3f13
Merge remote-tracking branch 'upstream/main' into xds-metadata-extens…
botengyao Dec 5, 2022
27d1072
add more integration tests
botengyao Dec 6, 2022
982cd9d
Merge remote-tracking branch 'upstream/main' into xds-metadata-extens…
botengyao Dec 6, 2022
cf96f4b
fix typo
botengyao Dec 6, 2022
cb9dddb
modify comments and make test specific
botengyao Dec 9, 2022
e5a9acc
Merge remote-tracking branch 'upstream/main' into xds-metadata-extens…
botengyao Dec 9, 2022
348aa7f
fix typo
botengyao Dec 10, 2022
7a90bcc
modify api comments and add release notes
botengyao Dec 13, 2022
9003a4d
Merge remote-tracking branch 'upstream/main' into xds-metadata-extens…
botengyao Dec 13, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion api/envoy/config/bootstrap/v3/bootstrap.proto
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// <config_overview_bootstrap>` for more detail.

// Bootstrap :ref:`configuration overview <config_overview_bootstrap>`.
// [#next-free-field: 36]
// [#next-free-field: 37]
message Bootstrap {
option (udpa.annotations.versioning).previous_message_type =
"envoy.config.bootstrap.v2.Bootstrap";
Expand Down Expand Up @@ -342,6 +342,13 @@ message Bootstrap {
// TODO(abeyad): Add public-facing documentation.
// [#not-implemented-hide:]
core.v3.TypedExtensionConfig xds_delegate_extension = 35;

// Optional XdsConfigTracker configuration, which allows tracking xDS responses in external components,
// e.g., external tracer or monitor. It provides the process point when receive, ingest, or fail to
// process xDS resources and messages.
// If a value is not specified, no XdsConfigTracker will be used.
// [#not-implemented-hide:]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this not-implemented-hide? Isn't it implemented? Also, can you please add a release note? Thank you.

/wait

Copy link
Copy Markdown
Member Author

@botengyao botengyao Dec 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! This PR only adds an api extension interface right now, and there is no actual extension implementation. This enables the ability to extend this interface for different use cases. Should I add a release note only for this interface?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact that it can be implemented means it's implemented, so I would remove the not-implemented-hide and still add a release note for it. It would be also good to :repo: link to the test extension so people can look at an example of the API, and I would also mention there are no in-repo extensions currently, etc.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Done, and waiting CI.

core.v3.TypedExtensionConfig xds_config_tracker_extension = 36;
}

// Administration interface :ref:`operations documentation
Expand Down
13 changes: 13 additions & 0 deletions envoy/config/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,16 @@ envoy_cc_library(
"@envoy_api//envoy/service/discovery/v3:pkg_cc_proto",
],
)

envoy_cc_library(
name = "xds_config_tracker_interface",
hdrs = ["xds_config_tracker.h"],
deps = [
":subscription_interface",
":typed_config_interface",
"//envoy/protobuf:message_validator_interface",
"//source/common/config:update_ack_lib",
"//source/common/protobuf",
"@com_google_googleapis//google/rpc:status_cc_proto",
],
)
6 changes: 6 additions & 0 deletions envoy/config/subscription.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <vector>

#include "envoy/common/exception.h"
#include "envoy/common/optref.h"
#include "envoy/common/pure.h"
#include "envoy/service/discovery/v3/discovery.pb.h"
#include "envoy/stats/stats_macros.h"
Expand Down Expand Up @@ -59,6 +60,11 @@ class DecodedResource {
* @return bool does the xDS discovery response have a set resource payload?
*/
virtual bool hasResource() const PURE;

/**
* @return optional ref<envoy::config::core::v3::Metadata> of a resource.
*/
virtual const OptRef<const envoy::config::core::v3::Metadata> metadata() const PURE;
};

using DecodedResourcePtr = std::unique_ptr<DecodedResource>;
Expand Down
109 changes: 109 additions & 0 deletions envoy/config/xds_config_tracker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#pragma once

#include <string>
#include <vector>

#include "envoy/common/optref.h"
#include "envoy/config/subscription.h"
#include "envoy/config/typed_config.h"
#include "envoy/protobuf/message_validator.h"
#include "envoy/stats/scope.h"

#include "source/common/protobuf/protobuf.h"

#include "google/rpc/status.pb.h"

namespace Envoy {
namespace Config {

/**
* An interface for hooking into xDS update events to provide the ablility to use some external
* processor in xDS update. This tracker provides the process point when the discovery response
* is received, when the resources are successfully processed and applied, and when there is any
* failure.
*
* Instance of this interface get invoked on the main Envoy thread. Thus, it is important
* for implementations of this interface to not execute any blocking operations on the same
* thread.
*/
class XdsConfigTracker {
public:
virtual ~XdsConfigTracker() = default;

/**
* Invoked when SotW xDS configuration updates have been successfully parsed, applied on
* the Envoy instance, and are about to be ACK'ed.
*
* For SotW, the passed resources contain all the received resources except for the heart-beat
* ones in the original message. The call of this method means there is a subscriber for this
* type_url and the type of resource is same as the message's type_url.
*
* Note: this method is called when *all* the resouces in a response are accepted.
Comment thread
botengyao marked this conversation as resolved.
Outdated
*
* @param type_url The type url of xDS message.
* @param resources A list of decoded resources to add to the current state.
Comment thread
botengyao marked this conversation as resolved.
*/
virtual void onConfigAccepted(const absl::string_view type_url,
const std::vector<DecodedResourcePtr>& resources) PURE;

/**
* Invoked when Delta xDS configuration updates have been successfully accepted, applied on
* the Envoy instance, and are about to be ACK'ed.
*
* For Delta, added_resources contains all the received added resources except for the heart-beat
* ones in the original message, and the removed resouces are the same in the xDS message.
Comment thread
botengyao marked this conversation as resolved.
Outdated
*
* Note: this method is called when *all* the resouces in a response are accepted.
Comment thread
botengyao marked this conversation as resolved.
Outdated
*
* @param type_url The type url of xDS message.
* @param added_resources A list of decoded resources to add to the current state.
Comment thread
botengyao marked this conversation as resolved.
* @param removed_resources A list of resources to remove from the current state.
*/
virtual void onConfigAccepted(
const absl::string_view type_url,
const Protobuf::RepeatedPtrField<envoy::service::discovery::v3::Resource>& added_resources,
const Protobuf::RepeatedPtrField<std::string>& removed_resources) PURE;

/**
* Invoked when xds configs are rejected during xDS ingestion.
*
* @param message The SotW discovery response message body.
* @param details The process state and error details.
*/
virtual void onConfigRejected(const envoy::service::discovery::v3::DiscoveryResponse& message,
const absl::string_view error_detail) PURE;

/**
* Invoked when xds configs are rejected during xDS ingestion.
*
* @param message The Delta discovery response message body.
* @param details The process state and error details.
*/
virtual void
onConfigRejected(const envoy::service::discovery::v3::DeltaDiscoveryResponse& message,
const absl::string_view error_detail) PURE;
};

using XdsConfigTrackerPtr = std::unique_ptr<XdsConfigTracker>;
using XdsConfigTrackerOptRef = OptRef<XdsConfigTracker>;

/**
* A factory abstract class for creating instances of XdsConfigTracker.
*/
class XdsConfigTrackerFactory : public Config::TypedFactory {
public:
~XdsConfigTrackerFactory() override = default;

/**
* Creates an XdsConfigTracker using the given config.
*/
virtual XdsConfigTrackerPtr
createXdsConfigTracker(const ProtobufWkt::Any& config,
ProtobufMessage::ValidationVisitor& validation_visitor,
Event::Dispatcher& dispatcher, Stats::Scope& stats) PURE;

std::string category() const override { return "envoy.config.xds_tracker"; }
};

} // namespace Config
} // namespace Envoy
4 changes: 4 additions & 0 deletions source/common/config/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ envoy_cc_library(
":xds_source_id_lib",
"//envoy/config:grpc_mux_interface",
"//envoy/config:subscription_interface",
"//envoy/config:xds_config_tracker_interface",
"//envoy/config:xds_resources_delegate_interface",
"//envoy/upstream:cluster_manager_interface",
"//source/common/common:cleanup_lib",
Expand Down Expand Up @@ -203,6 +204,7 @@ envoy_cc_library(
":watch_map_lib",
":xds_context_params_lib",
":xds_resource_lib",
"//envoy/config:xds_config_tracker_interface",
"//envoy/event:dispatcher_interface",
"//envoy/grpc:async_client_interface",
"//source/common/memory:utils_lib",
Expand Down Expand Up @@ -329,6 +331,7 @@ envoy_cc_library(
":xds_resource_lib",
"//envoy/config:subscription_factory_interface",
"//envoy/config:subscription_interface",
"//envoy/config:xds_config_tracker_interface",
"//envoy/config:xds_resources_delegate_interface",
"//envoy/server:instance_interface",
"//envoy/upstream:cluster_manager_interface",
Expand Down Expand Up @@ -434,6 +437,7 @@ envoy_cc_library(
":utility_lib",
":xds_resource_lib",
"//envoy/config:subscription_interface",
"//envoy/config:xds_config_tracker_interface",
"//source/common/common:assert_lib",
"//source/common/common:cleanup_lib",
"//source/common/common:minimal_logger_lib",
Expand Down
33 changes: 22 additions & 11 deletions source/common/config/decoded_resource_impl.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "envoy/common/optref.h"
#include "envoy/config/subscription.h"
#include "envoy/service/discovery/v3/discovery.pb.h"

Expand Down Expand Up @@ -40,7 +41,7 @@ class DecodedResourceImpl : public DecodedResource {

return std::unique_ptr<DecodedResourceImpl>(new DecodedResourceImpl(
resource_decoder, absl::nullopt, Protobuf::RepeatedPtrField<std::string>(), resource, true,
version, absl::nullopt));
version, absl::nullopt, absl::nullopt));
}

static DecodedResourceImplPtr
Expand All @@ -51,21 +52,22 @@ class DecodedResourceImpl : public DecodedResource {

DecodedResourceImpl(OpaqueResourceDecoder& resource_decoder,
const envoy::service::discovery::v3::Resource& resource)
: DecodedResourceImpl(resource_decoder, resource.name(), resource.aliases(),
resource.resource(), resource.has_resource(), resource.version(),
resource.has_ttl()
? absl::make_optional(std::chrono::milliseconds(
DurationUtil::durationToMilliseconds(resource.ttl())))
: absl::nullopt) {}
: DecodedResourceImpl(
resource_decoder, resource.name(), resource.aliases(), resource.resource(),
resource.has_resource(), resource.version(),
resource.has_ttl() ? absl::make_optional(std::chrono::milliseconds(
DurationUtil::durationToMilliseconds(resource.ttl())))
: absl::nullopt,
resource.has_metadata() ? makeOptRef(resource.metadata()) : absl::nullopt) {}
DecodedResourceImpl(OpaqueResourceDecoder& resource_decoder,
const xds::core::v3::CollectionEntry::InlineEntry& inline_entry)
: DecodedResourceImpl(resource_decoder, inline_entry.name(),
Protobuf::RepeatedPtrField<std::string>(), inline_entry.resource(),
true, inline_entry.version(), absl::nullopt) {}
true, inline_entry.version(), absl::nullopt, absl::nullopt) {}
DecodedResourceImpl(ProtobufTypes::MessagePtr resource, const std::string& name,
const std::vector<std::string>& aliases, const std::string& version)
: resource_(std::move(resource)), has_resource_(true), name_(name), aliases_(aliases),
version_(version), ttl_(absl::nullopt) {}
version_(version), ttl_(absl::nullopt), metadata_(absl::nullopt) {}

// Config::DecodedResource
const std::string& name() const override { return name_; }
Expand All @@ -74,15 +76,20 @@ class DecodedResourceImpl : public DecodedResource {
const Protobuf::Message& resource() const override { return *resource_; };
bool hasResource() const override { return has_resource_; }
absl::optional<std::chrono::milliseconds> ttl() const override { return ttl_; }
const OptRef<const envoy::config::core::v3::Metadata> metadata() const override {
return metadata_;
}

private:
DecodedResourceImpl(OpaqueResourceDecoder& resource_decoder, absl::optional<std::string> name,
const Protobuf::RepeatedPtrField<std::string>& aliases,
const ProtobufWkt::Any& resource, bool has_resource,
const std::string& version, absl::optional<std::chrono::milliseconds> ttl)
const std::string& version, absl::optional<std::chrono::milliseconds> ttl,
const OptRef<const envoy::config::core::v3::Metadata> metadata)
: resource_(resource_decoder.decodeResource(resource)), has_resource_(has_resource),
name_(name ? *name : resource_decoder.resourceName(*resource_)),
aliases_(repeatedPtrFieldToVector(aliases)), version_(version), ttl_(ttl) {}
aliases_(repeatedPtrFieldToVector(aliases)), version_(version), ttl_(ttl),
metadata_(metadata) {}

const ProtobufTypes::MessagePtr resource_;
const bool has_resource_;
Expand All @@ -91,6 +98,10 @@ class DecodedResourceImpl : public DecodedResource {
const std::string version_;
// Per resource TTL.
const absl::optional<std::chrono::milliseconds> ttl_;

// This is the metadata info under the Resource wrapper.
// It is intended to be consumed in the xds_config_tracker extension.
const OptRef<const envoy::config::core::v3::Metadata> metadata_;
Comment thread
botengyao marked this conversation as resolved.
};

struct DecodedResourcesWrapper {
Expand Down
15 changes: 10 additions & 5 deletions source/common/config/delta_subscription_state.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ namespace {
DeltaSubscriptionStateVariant getState(std::string type_url,
UntypedConfigUpdateCallbacks& watch_map,
const LocalInfo::LocalInfo& local_info,
Event::Dispatcher& dispatcher) {
Event::Dispatcher& dispatcher,
XdsConfigTrackerOptRef xds_config_tracker) {
if (Runtime::runtimeFeatureEnabled("envoy.restart_features.explicit_wildcard_resource")) {
return DeltaSubscriptionStateVariant(absl::in_place_type<NewDeltaSubscriptionState>,
std::move(type_url), watch_map, local_info, dispatcher);
std::move(type_url), watch_map, local_info, dispatcher,
xds_config_tracker);
} else {
return DeltaSubscriptionStateVariant(absl::in_place_type<OldDeltaSubscriptionState>,
std::move(type_url), watch_map, local_info, dispatcher);
std::move(type_url), watch_map, local_info, dispatcher,
xds_config_tracker);
}
}

Expand All @@ -24,8 +27,10 @@ DeltaSubscriptionStateVariant getState(std::string type_url,
DeltaSubscriptionState::DeltaSubscriptionState(std::string type_url,
UntypedConfigUpdateCallbacks& watch_map,
const LocalInfo::LocalInfo& local_info,
Event::Dispatcher& dispatcher)
: state_(getState(std::move(type_url), watch_map, local_info, dispatcher)) {}
Event::Dispatcher& dispatcher,
XdsConfigTrackerOptRef xds_config_tracker)
: state_(getState(std::move(type_url), watch_map, local_info, dispatcher, xds_config_tracker)) {
}

void DeltaSubscriptionState::updateSubscriptionInterest(
const absl::flat_hash_set<std::string>& cur_added,
Expand Down
5 changes: 4 additions & 1 deletion source/common/config/delta_subscription_state.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "envoy/config/subscription.h"
#include "envoy/config/xds_config_tracker.h"
#include "envoy/local_info/local_info.h"
#include "envoy/service/discovery/v3/discovery.pb.h"

Expand All @@ -20,7 +21,8 @@ using DeltaSubscriptionStateVariant =
class DeltaSubscriptionState : public Logger::Loggable<Logger::Id::config> {
public:
DeltaSubscriptionState(std::string type_url, UntypedConfigUpdateCallbacks& watch_map,
const LocalInfo::LocalInfo& local_info, Event::Dispatcher& dispatcher);
const LocalInfo::LocalInfo& local_info, Event::Dispatcher& dispatcher,
XdsConfigTrackerOptRef xds_config_tracker);

void updateSubscriptionInterest(const absl::flat_hash_set<std::string>& cur_added,
const absl::flat_hash_set<std::string>& cur_removed);
Expand All @@ -37,6 +39,7 @@ class DeltaSubscriptionState : public Logger::Loggable<Logger::Id::config> {

private:
DeltaSubscriptionStateVariant state_;
XdsConfigTrackerOptRef xds_config_tracker_;
};

} // namespace Config
Expand Down
14 changes: 13 additions & 1 deletion source/common/config/grpc_mux_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,13 @@ GrpcMuxImpl::GrpcMuxImpl(const LocalInfo::LocalInfo& local_info,
Random::RandomGenerator& random, Stats::Scope& scope,
const RateLimitSettings& rate_limit_settings, bool skip_subsequent_node,
CustomConfigValidatorsPtr&& config_validators,
XdsConfigTrackerOptRef xds_config_tracker,
XdsResourcesDelegateOptRef xds_resources_delegate,
const std::string& target_xds_authority)
: grpc_stream_(this, std::move(async_client), service_method, random, dispatcher, scope,
rate_limit_settings),
local_info_(local_info), skip_subsequent_node_(skip_subsequent_node),
config_validators_(std::move(config_validators)),
config_validators_(std::move(config_validators)), xds_config_tracker_(xds_config_tracker),
xds_resources_delegate_(xds_resources_delegate), target_xds_authority_(target_xds_authority),
first_stream_request_(true), dispatcher_(dispatcher),
dynamic_update_callback_handle_(local_info.contextProvider().addDynamicContextUpdateCallback(
Expand Down Expand Up @@ -219,6 +220,7 @@ void GrpcMuxImpl::onDiscoveryResponse(
ControlPlaneStats& control_plane_stats) {
const std::string type_url = message->type_url();
ENVOY_LOG(debug, "Received gRPC message for {} at version {}", type_url, message->version_info());

if (api_state_.count(type_url) == 0) {
// TODO(yuval-k): This should never happen. consider dropping the stream as this is a
// protocol violation
Expand Down Expand Up @@ -286,6 +288,11 @@ void GrpcMuxImpl::onDiscoveryResponse(

processDiscoveryResources(resources, api_state, type_url, message->version_info(),
/*call_delegate=*/true);

// Processing point when resources are successfully ingested.
if (xds_config_tracker_.has_value()) {
xds_config_tracker_->onConfigAccepted(type_url, resources);
}
}
END_TRY
catch (const EnvoyException& e) {
Expand All @@ -296,6 +303,11 @@ void GrpcMuxImpl::onDiscoveryResponse(
::google::rpc::Status* error_detail = api_state.request_.mutable_error_detail();
error_detail->set_code(Grpc::Status::WellKnownGrpcStatus::Internal);
error_detail->set_message(Config::Utility::truncateGrpcStatusMessage(e.what()));

// Processing point when there is any exception during the parse and ingestion process.
if (xds_config_tracker_.has_value()) {
xds_config_tracker_->onConfigRejected(*message, error_detail->message());
}
}
previously_fetched_data_ = true;
api_state.request_.set_response_nonce(message->nonce());
Expand Down
Loading