sheaf · fragmentation scan · envoy.service.discovery.v3 · 2026-05-29 03:42 UTC

1 Services

Concept documentation
100%
1 with doc evidence
show the 1
Implementations
N/A
no impl tree in scope
Worked examples
0%
0 in docs / RFCs
1 missing

2 Methods

Concept documentation
50%
1 with doc evidence
show the 1
Implementations
N/A
no impl tree in scope
Worked examples
0%
0 in docs / RFCs
2 missing

13 Gaps · Worklist

Concept docs cover 7 methods; tests cover 7; examples cover Zero. Examples is the bottleneck — every Completed method needs all three. Closing the largest group would move 54% of the debt — the biggest single shift available.

7
Established
DOCS EXAMPLES
explained and verified, no example
AggregatedDiscoveryServiceAggregatedDiscoveryService.StreamAggregatedResourcesDeltaDiscoveryRequestDeltaDiscoveryResponseDiscoveryRequestDiscoveryResponse
6
Unclaimed
DOCS EXAMPLES
only the contract, nothing else
AdsDummyAggregatedDiscoveryService.DeltaAggregatedResourcesDynamicParameterConstraintsResourceErrorResourceLocatorResourceName
6
REPLACE THE STUB Replace the inherited boilerplate with prose that explains the actual behavior.
7
ADD AN EXAMPLE Add a runnable snippet, or promote an existing test into an example.

Depth

Full
00%
Brief
00%
Stub
150%
None
150%

Evidence

6
REPLACE THE STUB Signature-only — documented in name only
AdsDummy
AggregatedDiscoveryService.DeltaAggregatedResources
DynamicParameterConstraints
ResourceError
ResourceLocator
ResourceName
7
ADD AN EXAMPLE No runnable example
AggregatedDiscoveryService
AggregatedDiscoveryService.StreamAggregatedResources
DeltaDiscoveryRequest
DeltaDiscoveryResponse
DiscoveryRequest
DiscoveryResponse
Resource
CONTRACT
// [#not-implemented-hide:] Not configuration. Workaround c++ protobuf issue with importing
// services: https://github.com/google/protobuf/issues/4221
message AdsDummy {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.service.discovery.v2.AdsDummy";
}
DOCS

N/A

TESTS

N/A

IMPLS

N/A · no in-tree implementor

EXAMPLES

N/A

WORKFLOWS

N/A

CONTRACT
// See https://github.com/envoyproxy/envoy-api#apis for a description of the role of
// ADS and how it is intended to be used by a management server. ADS requests
// have the same structure as their singleton xDS counterparts, but can
// multiplex many resource types on a single stream. The type_url in the
// DiscoveryRequest/DiscoveryResponse provides sufficient information to recover
// the multiplexed singleton APIs at the Envoy instance and management server.
service AggregatedDiscoveryService {
  // This is a gRPC-only API.
  rpc StreamAggregatedResources(stream DiscoveryRequest) returns (stream DiscoveryResponse) {
  }

  rpc DeltaAggregatedResources(stream DeltaDiscoveryRequest)
      returns (stream DeltaDiscoveryResponse) {
  }
}
DOCS

See :repo:`discovery.proto <api/envoy/service/discovery/v3/discovery.proto>` for the service definition. This is used by Envoy as a client when

+ 16 more paragraphs · read full section
TESTS
test/extensions/config_subscription/grpc/grpc_mux_impl_test.cc:1522GrpcMuxImplTest.MaybeCreateLoadStatsReporter · C++ · 48 lines
TEST_P(GrpcMuxImplTest, MaybeCreateLoadStatsReporter) {
  TestScopedRuntime scoped_runtime;
  scoped_runtime.mergeValues({{"envoy.reloadable_features.enable_lrs_server_self_ads", "true"}});

  bool factory_called = false;
  auto lrs_factory = [&]() -> std::unique_ptr<Upstream::LoadStatsReporter> {
    factory_called = true;
    return std::make_unique<Upstream::MockLoadStatsReporter>();
  };

  // Re-setup with the factory
  GrpcMuxContext grpc_mux_context{
      /*async_client_=*/std::unique_ptr<Grpc::MockAsyncClient>(async_client_),
      /*failover_async_client_=*/nullptr,
      /*dispatcher_=*/dispatcher_,
      /*service_method_=*/
      *Protobuf::DescriptorPool::generated_pool()->FindMethodByName(
          "envoy.service.discovery.v3.AggregatedDiscoveryService.StreamAggregatedResources"),
      /*local_info_=*/local_info_,
      /*rate_limit_settings_=*/rate_limit_settings_,
      /*scope_=*/*stats_.rootScope(),
      /*config_validators_=*/std::move(config_validators_),
      /*xds_resources_delegate_=*/XdsResourcesDelegateOptRef(),
      /*xds_config_tracker_=*/XdsConfigTrackerOptRef(),
      /*backoff_strategy_=*/
      std::make_unique<JitteredExponentialBackOffStrategy>(
          SubscriptionFactory::RetryInitialDelayMs, SubscriptionFactory::RetryMaxDelayMs, random_),
      /*target_xds_authority_=*/"",
      /*eds_resources_cache_=*/std::unique_ptr<MockEdsResourcesCache>(eds_resources_cache_),
      /*skip_subsequent_node_=*/true,
+ 18 more lines · read full file
test/extensions/config_subscription/grpc/grpc_mux_impl_test.cc:1574GrpcMuxImplTest.MaybeCreateLoadStatsReporterRuntimeDisabled · C++ · 32 lines
TEST_P(GrpcMuxImplTest, MaybeCreateLoadStatsReporterRuntimeDisabled) {
  TestScopedRuntime scoped_runtime;
  scoped_runtime.mergeValues({{"envoy.reloadable_features.enable_lrs_server_self_ads", "false"}});

  auto lrs_factory = [&]() -> std::unique_ptr<Upstream::LoadStatsReporter> {
    return nullptr; // Should not be called
  };

  GrpcMuxContext grpc_mux_context{
      /*async_client_=*/std::unique_ptr<Grpc::MockAsyncClient>(async_client_),
      /*failover_async_client_=*/nullptr,
      /*dispatcher_=*/dispatcher_,
      /*service_method_=*/
      *Protobuf::DescriptorPool::generated_pool()->FindMethodByName(
          "envoy.service.discovery.v3.AggregatedDiscoveryService.StreamAggregatedResources"),
      /*local_info_=*/local_info_,
      /*rate_limit_settings_=*/rate_limit_settings_,
      /*scope_=*/*stats_.rootScope(),
      /*config_validators_=*/std::move(config_validators_),
      /*xds_resources_delegate_=*/XdsResourcesDelegateOptRef(),
      /*xds_config_tracker_=*/XdsConfigTrackerOptRef(),
      /*backoff_strategy_=*/
      std::make_unique<JitteredExponentialBackOffStrategy>(
          SubscriptionFactory::RetryInitialDelayMs, SubscriptionFactory::RetryMaxDelayMs, random_),
      /*target_xds_authority_=*/"",
      /*eds_resources_cache_=*/std::unique_ptr<MockEdsResourcesCache>(eds_resources_cache_),
      /*skip_subsequent_node_=*/true,
      /*load_stats_reporter_factory_=*/lrs_factory};
  grpc_mux_ = std::make_unique<GrpcMuxImpl>(grpc_mux_context);
+ 3 more lines · read full file
test/extensions/config_subscription/grpc/xds_grpc_mux_impl_test.cc:928GrpcMuxImplTest.BadLocalInfoEmptyClusterName · C++ · 26 lines
TEST_P(GrpcMuxImplTest, BadLocalInfoEmptyClusterName) {
  EXPECT_CALL(local_info_, clusterName()).WillOnce(ReturnRef(EMPTY_STRING));
  GrpcMuxContext grpc_mux_context{
      /*async_client_=*/std::unique_ptr<Grpc::MockAsyncClient>(async_client_),
      /*failover_async_client_=*/nullptr,
      /*dispatcher_=*/dispatcher_,
      /*service_method_=*/
      *Protobuf::DescriptorPool::generated_pool()->FindMethodByName(
          "envoy.service.discovery.v3.AggregatedDiscoveryService.StreamAggregatedResources"),
      /*local_info_=*/local_info_,
      /*rate_limit_settings_=*/rate_limit_settings_,
      /*scope_=*/*stats_.rootScope(),
      /*config_validators_=*/std::make_unique<NiceMock<MockCustomConfigValidators>>(),
      /*xds_resources_delegate_=*/XdsResourcesDelegateOptRef(),
      /*xds_config_tracker_=*/XdsConfigTrackerOptRef(),
      /*backoff_strategy_=*/
      std::make_unique<JitteredExponentialBackOffStrategy>(
          SubscriptionFactory::RetryInitialDelayMs, SubscriptionFactory::RetryMaxDelayMs, random_),
      /*target_xds_authority_=*/"",
      /*eds_resources_cache_=*/nullptr,
      /*skip_subsequent_node_=*/true};
  EXPECT_THROW_WITH_MESSAGE(
      (XdsMux::GrpcMuxSotw(grpc_mux_context)), EnvoyException,
      "ads: node 'id' and 'cluster' are required. Set it either in 'node' config or via "
      "--service-node and --service-cluster options.");
}
+ 2 more tests · open all in source
IMPLS

N/A · no in-tree implementor

EXAMPLES

N/A

WORKFLOWS

N/A

CONTRACT
rpc DeltaAggregatedResources(stream DeltaDiscoveryRequest)
DOCS

N/A

TESTS

N/A

IMPLS

N/A · no in-tree implementor

EXAMPLES

N/A

WORKFLOWS

N/A

CONTRACT
// This is a gRPC-only API.
rpc StreamAggregatedResources(stream DiscoveryRequest) returns (stream DiscoveryResponse) {
}
DOCS

See :repo:`discovery.proto <api/envoy/service/discovery/v3/discovery.proto>` for the service definition. This is used by Envoy as a client when

+ 16 more paragraphs · read full section
TESTS
test/extensions/config_subscription/grpc/grpc_mux_impl_test.cc:1522GrpcMuxImplTest.MaybeCreateLoadStatsReporter · C++ · 48 lines
TEST_P(GrpcMuxImplTest, MaybeCreateLoadStatsReporter) {
  TestScopedRuntime scoped_runtime;
  scoped_runtime.mergeValues({{"envoy.reloadable_features.enable_lrs_server_self_ads", "true"}});

  bool factory_called = false;
  auto lrs_factory = [&]() -> std::unique_ptr<Upstream::LoadStatsReporter> {
    factory_called = true;
    return std::make_unique<Upstream::MockLoadStatsReporter>();
  };

  // Re-setup with the factory
  GrpcMuxContext grpc_mux_context{
      /*async_client_=*/std::unique_ptr<Grpc::MockAsyncClient>(async_client_),
      /*failover_async_client_=*/nullptr,
      /*dispatcher_=*/dispatcher_,
      /*service_method_=*/
      *Protobuf::DescriptorPool::generated_pool()->FindMethodByName(
          "envoy.service.discovery.v3.AggregatedDiscoveryService.StreamAggregatedResources"),
      /*local_info_=*/local_info_,
      /*rate_limit_settings_=*/rate_limit_settings_,
      /*scope_=*/*stats_.rootScope(),
      /*config_validators_=*/std::move(config_validators_),
      /*xds_resources_delegate_=*/XdsResourcesDelegateOptRef(),
      /*xds_config_tracker_=*/XdsConfigTrackerOptRef(),
      /*backoff_strategy_=*/
      std::make_unique<JitteredExponentialBackOffStrategy>(
          SubscriptionFactory::RetryInitialDelayMs, SubscriptionFactory::RetryMaxDelayMs, random_),
      /*target_xds_authority_=*/"",
      /*eds_resources_cache_=*/std::unique_ptr<MockEdsResourcesCache>(eds_resources_cache_),
      /*skip_subsequent_node_=*/true,
+ 18 more lines · read full file
test/extensions/config_subscription/grpc/grpc_mux_impl_test.cc:1574GrpcMuxImplTest.MaybeCreateLoadStatsReporterRuntimeDisabled · C++ · 32 lines
TEST_P(GrpcMuxImplTest, MaybeCreateLoadStatsReporterRuntimeDisabled) {
  TestScopedRuntime scoped_runtime;
  scoped_runtime.mergeValues({{"envoy.reloadable_features.enable_lrs_server_self_ads", "false"}});

  auto lrs_factory = [&]() -> std::unique_ptr<Upstream::LoadStatsReporter> {
    return nullptr; // Should not be called
  };

  GrpcMuxContext grpc_mux_context{
      /*async_client_=*/std::unique_ptr<Grpc::MockAsyncClient>(async_client_),
      /*failover_async_client_=*/nullptr,
      /*dispatcher_=*/dispatcher_,
      /*service_method_=*/
      *Protobuf::DescriptorPool::generated_pool()->FindMethodByName(
          "envoy.service.discovery.v3.AggregatedDiscoveryService.StreamAggregatedResources"),
      /*local_info_=*/local_info_,
      /*rate_limit_settings_=*/rate_limit_settings_,
      /*scope_=*/*stats_.rootScope(),
      /*config_validators_=*/std::move(config_validators_),
      /*xds_resources_delegate_=*/XdsResourcesDelegateOptRef(),
      /*xds_config_tracker_=*/XdsConfigTrackerOptRef(),
      /*backoff_strategy_=*/
      std::make_unique<JitteredExponentialBackOffStrategy>(
          SubscriptionFactory::RetryInitialDelayMs, SubscriptionFactory::RetryMaxDelayMs, random_),
      /*target_xds_authority_=*/"",
      /*eds_resources_cache_=*/std::unique_ptr<MockEdsResourcesCache>(eds_resources_cache_),
      /*skip_subsequent_node_=*/true,
      /*load_stats_reporter_factory_=*/lrs_factory};
  grpc_mux_ = std::make_unique<GrpcMuxImpl>(grpc_mux_context);
+ 3 more lines · read full file
test/extensions/config_subscription/grpc/xds_grpc_mux_impl_test.cc:928GrpcMuxImplTest.BadLocalInfoEmptyClusterName · C++ · 26 lines
TEST_P(GrpcMuxImplTest, BadLocalInfoEmptyClusterName) {
  EXPECT_CALL(local_info_, clusterName()).WillOnce(ReturnRef(EMPTY_STRING));
  GrpcMuxContext grpc_mux_context{
      /*async_client_=*/std::unique_ptr<Grpc::MockAsyncClient>(async_client_),
      /*failover_async_client_=*/nullptr,
      /*dispatcher_=*/dispatcher_,
      /*service_method_=*/
      *Protobuf::DescriptorPool::generated_pool()->FindMethodByName(
          "envoy.service.discovery.v3.AggregatedDiscoveryService.StreamAggregatedResources"),
      /*local_info_=*/local_info_,
      /*rate_limit_settings_=*/rate_limit_settings_,
      /*scope_=*/*stats_.rootScope(),
      /*config_validators_=*/std::make_unique<NiceMock<MockCustomConfigValidators>>(),
      /*xds_resources_delegate_=*/XdsResourcesDelegateOptRef(),
      /*xds_config_tracker_=*/XdsConfigTrackerOptRef(),
      /*backoff_strategy_=*/
      std::make_unique<JitteredExponentialBackOffStrategy>(
          SubscriptionFactory::RetryInitialDelayMs, SubscriptionFactory::RetryMaxDelayMs, random_),
      /*target_xds_authority_=*/"",
      /*eds_resources_cache_=*/nullptr,
      /*skip_subsequent_node_=*/true};
  EXPECT_THROW_WITH_MESSAGE(
      (XdsMux::GrpcMuxSotw(grpc_mux_context)), EnvoyException,
      "ads: node 'id' and 'cluster' are required. Set it either in 'node' config or via "
      "--service-node and --service-cluster options.");
}
+ 2 more tests · open all in source
IMPLS

N/A · no in-tree implementor

EXAMPLES

N/A

WORKFLOWS

N/A

CONTRACT
// all requests/acknowledgments/updates are logically walled off by ``type_url``:
// a Cluster ACK exists in a completely separate world from a prior Route NACK.
// In particular, ``initial_resource_versions`` being sent at the "start" of every
// gRPC stream actually entails a message for each ``type_url``, each with its own
// ``initial_resource_versions``.
// [#next-free-field: 10]
message DeltaDiscoveryRequest {
  option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.DeltaDiscoveryRequest";

  // The node making the request.
  config.core.v3.Node node = 1;

  // Type of the resource that is being requested, e.g.
  // ``type.googleapis.com/envoy.api.v2.ClusterLoadAssignment``. This does not need to be set if
  // resources are only referenced via ``xds_resource_subscribe`` and
  // ``xds_resources_unsubscribe``.
  string type_url = 2;
DOCS
docs/root/api-docs/xds_protocol.rst:509reStructuredText · 31 words

non-empty :ref:`resource_names_subscribe <envoy_v3_api_field_service.discovery.v3.DeltaDiscoveryRequest.resource_names_subscribe>` field), the server should treat that identically to how it would treat the client having explicitly subscribed to ``*``. However, once the client does explicitly subscribe to a resource name (whether it be ``*`` or any other name), then this legacy semantic is no longer available; at that point, clearing the list of subscribed resources is interpretted as an unsubscription (see :ref:`Unsubscribing From Resources<xds_protocol_unsubscribing>`) rather than as a subscr…

+ 87 more paragraphs · read full section
docs/root/api-docs/xds_protocol.rst:528reStructuredText · 30 words

- Client sends a request with :ref:`resource_names_unsubscribe <envoy_v3_api_field_service.discovery.v3.DeltaDiscoveryRequest.resource_names_unsubscribe>` set to ``*``. Server interprets this as unsubscribing to ``*`` and continuing the existing subscription to ``A``. - Client sends a request with :ref:`resource_names_unsubscribe <envoy_v3_api_field_service.discovery.v3.DeltaDiscoveryRequest.resource_names_unsubscribe>` set to ``A``. Server interprets this as unsubscribing to ``A`` (i.e., the client has now unsubscribed to all resources). Although the set of subscribed resources is now empty, …

+ 83 more paragraphs · read full section
docs/root/api-docs/xds_protocol.rst:921reStructuredText · 29 words

A :ref:`resource_names_subscribe <envoy_v3_api_field_service.discovery.v3.DeltaDiscoveryRequest.resource_names_subscribe>` field may contain resource names that the server believes the client is already subscribed to, and furthermore has the most recent versions of. However, the server *must* still provide those resources in the response; due to implementation details hidden from the server, the client may have "forgotten" those resources despite apparently remaining subscribed.

+ 10 more paragraphs · read full section
+ 21 more refs · open all in source
TESTS
test/extensions/config_subscription/common/subscription_impl_test.cc:129SubscriptionImplTest.InitialRequestResponse · C++ · 7 lines
TEST_P(SubscriptionImplTest, InitialRequestResponse) {
  startSubscription({"cluster0", "cluster1"});
  EXPECT_TRUE(statsAre(1, 0, 0, 0, 0, 0, 0, ""));
  deliverConfigUpdate({"cluster0", "cluster1"}, "v25-ubuntu18-beta", true);
  EXPECT_TRUE(
      statsAre(2, 1, 0, 0, 0, TEST_TIME_MILLIS, 18202868392629624077U, "v25-ubuntu18-beta"));
}
test/extensions/config_subscription/common/subscription_impl_test.cc:138SubscriptionImplTest.ResponseStream · C++ · 8 lines
TEST_P(SubscriptionImplTest, ResponseStream) {
  startSubscription({"cluster0", "cluster1"});
  EXPECT_TRUE(statsAre(1, 0, 0, 0, 0, 0, 0, ""));
  deliverConfigUpdate({"cluster0", "cluster1"}, "1.2.3.4", true);
  EXPECT_TRUE(statsAre(2, 1, 0, 0, 0, TEST_TIME_MILLIS, 14026795738668939420U, "1.2.3.4"));
  deliverConfigUpdate({"cluster0", "cluster1"}, "5_6_7", true);
  EXPECT_TRUE(statsAre(3, 2, 0, 0, 0, TEST_TIME_MILLIS, 7612520132475921171U, "5_6_7"));
}
test/extensions/config_subscription/common/subscription_impl_test.cc:148SubscriptionImplTest.RejectConfig · C++ · 6 lines
TEST_P(SubscriptionImplTest, RejectConfig) {
  startSubscription({"cluster0", "cluster1"});
  EXPECT_TRUE(statsAre(1, 0, 0, 0, 0, 0, 0, ""));
  deliverConfigUpdate({"cluster0", "cluster1"}, "0", false);
  EXPECT_TRUE(statsAre(2, 0, 1, 0, 0, 0, 0, ""));
}
+ 15 more tests · open all in source
IMPLS

N/A · no in-tree implementor

EXAMPLES

N/A

WORKFLOWS

N/A

CONTRACT
// [#next-free-field: 10]
message DeltaDiscoveryResponse {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.api.v2.DeltaDiscoveryResponse";

  // The version of the response data (used for debugging).
  string system_version_info = 1;

  // The response resources. These are typed resources, whose types must match
  // the ``type_url`` field.
  repeated Resource resources = 2;

  // field id 3 IS available!
DOCS
docs/root/api-docs/xds_protocol.rst:906reStructuredText · 33 words

resource of a :ref:`DeltaDiscoveryResponse <envoy_v3_api_msg_service.discovery.v3.DeltaDiscoveryResponse>`. The resource name will be returned in the name field in the resource of a :ref:`DeltaDiscoveryResponse <envoy_v3_api_msg_service.discovery.v3.DeltaDiscoveryResponse>`.

+ 13 more paragraphs · read full section
docs/root/api-docs/xds_protocol.rst:572reStructuredText · 31 words

deleted via the :ref:`removed_resources <envoy_v3_api_field_service.discovery.v3.DeltaDiscoveryResponse.removed_resources>` field of the response. This tells the client to remove the resource from its local cache.

+ 73 more paragraphs · read full section
docs/root/api-docs/xds_protocol.rst:946reStructuredText · 30 words

:ref:`removed_resources <envoy_v3_api_field_service.discovery.v3.DeltaDiscoveryResponse.removed_resources>` field.

+ 6 more paragraphs · read full section
+ 11 more refs · open all in source
TESTS
test/extensions/config_subscription/common/subscription_impl_test.cc:129SubscriptionImplTest.InitialRequestResponse · C++ · 7 lines
TEST_P(SubscriptionImplTest, InitialRequestResponse) {
  startSubscription({"cluster0", "cluster1"});
  EXPECT_TRUE(statsAre(1, 0, 0, 0, 0, 0, 0, ""));
  deliverConfigUpdate({"cluster0", "cluster1"}, "v25-ubuntu18-beta", true);
  EXPECT_TRUE(
      statsAre(2, 1, 0, 0, 0, TEST_TIME_MILLIS, 18202868392629624077U, "v25-ubuntu18-beta"));
}
test/extensions/config_subscription/common/subscription_impl_test.cc:138SubscriptionImplTest.ResponseStream · C++ · 8 lines
TEST_P(SubscriptionImplTest, ResponseStream) {
  startSubscription({"cluster0", "cluster1"});
  EXPECT_TRUE(statsAre(1, 0, 0, 0, 0, 0, 0, ""));
  deliverConfigUpdate({"cluster0", "cluster1"}, "1.2.3.4", true);
  EXPECT_TRUE(statsAre(2, 1, 0, 0, 0, TEST_TIME_MILLIS, 14026795738668939420U, "1.2.3.4"));
  deliverConfigUpdate({"cluster0", "cluster1"}, "5_6_7", true);
  EXPECT_TRUE(statsAre(3, 2, 0, 0, 0, TEST_TIME_MILLIS, 7612520132475921171U, "5_6_7"));
}
test/extensions/config_subscription/common/subscription_impl_test.cc:148SubscriptionImplTest.RejectConfig · C++ · 6 lines
TEST_P(SubscriptionImplTest, RejectConfig) {
  startSubscription({"cluster0", "cluster1"});
  EXPECT_TRUE(statsAre(1, 0, 0, 0, 0, 0, 0, ""));
  deliverConfigUpdate({"cluster0", "cluster1"}, "0", false);
  EXPECT_TRUE(statsAre(2, 0, 1, 0, 0, 0, 0, ""));
}
+ 25 more tests · open all in source
IMPLS

N/A · no in-tree implementor

EXAMPLES

N/A

WORKFLOWS

N/A

CONTRACT
// A DiscoveryRequest requests a set of versioned resources of the same type for
// a given Envoy node on some API.
// [#next-free-field: 8]
message DiscoveryRequest {
  option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.DiscoveryRequest";

  // The ``version_info`` provided in the request messages will be the ``version_info``
  // received with the most recent successfully processed response or empty on
  // the first request. It is expected that no new request is sent after a
  // response is received until the Envoy instance is ready to ACK/NACK the new
  // configuration. ACK/NACK takes place by returning the new API config version
  // as applied or the previous API config version respectively. Each ``type_url``
  // (see below) has an independent version associated with it.
  string version_info = 1;
DOCS
docs/root/api-docs/xds_protocol.rst:425reStructuredText · 33 words

:ref:`error_detail <envoy_v3_api_field_service.discovery.v3.DiscoveryRequest.error_detail>` field in the request sent by the client. Some older servers may instead detect a NACK by looking at both the version and the nonce in the request: if the version in the request is not equal to the one sent by the server with that nonce, then the client has rejected the most recent version. However, this approach does not work for APIs other than LDS and CDS for clients that may dynamically change the set of resources that they are subscribing to, unless the server has somehow arranged to increment the r…

+ 98 more paragraphs · read full section
docs/root/api-docs/xds_protocol.rst:507reStructuredText · 33 words

resource type have had an empty :ref:`resource_names <envoy_v3_api_field_service.discovery.v3.DiscoveryRequest.resource_names>` field, or in incremental, having never sent a request on the stream for that resource type with a non-empty :ref:`resource_names_subscribe <envoy_v3_api_field_service.discovery.v3.DeltaDiscoveryRequest.resource_names_subscribe>` field), the server should treat that identically to how it would treat the client having explicitly subscribed to ``*``. However, once the client does explicitly subscribe to a resource name (whether it be ``*`` or any other name), then this l…

+ 87 more paragraphs · read full section
docs/root/api-docs/xds_protocol.rst:634reStructuredText · 31 words

subscribed to in the :ref:`resource_names <envoy_v3_api_field_service.discovery.v3.DiscoveryRequest.resource_names>` field, so unsubscribing to a set of resources is done by sending a new request containing all resource names that are still being subscribed to but not containing the resource names being unsubscribed to. For example, if the client had previously been subscribed to resources ``A`` and ``B`` but wishes to unsubscribe from ``B``, it must send a new request containing only resource ``A``.

+ 63 more paragraphs · read full section
+ 37 more refs · open all in source
TESTS
test/common/config/grpc_subscription_impl_test.cc:22GrpcSubscriptionImplTest.StreamCreationFailure · C++ · 24 lines
TEST_P(GrpcSubscriptionImplTest, StreamCreationFailure) {
  InSequence s;
  EXPECT_CALL(*async_client_, startRaw(_, _, _, _)).WillOnce(Return(nullptr));

  // onConfigUpdateFailed() should not be called for gRPC stream connection failure
  EXPECT_CALL(callbacks_,
              onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason::ConnectionFailure, _))
      .Times(0);
  EXPECT_CALL(random_, random());
  EXPECT_CALL(*timer_, enableTimer(_, _));
  subscription_->start({"cluster0", "cluster1"});
  EXPECT_TRUE(statsAre(2, 0, 0, 1, 0, 0, 0, ""));
  // Ensure this doesn't cause an issue by sending a request, since we don't
  // have a gRPC stream.
  subscription_->updateResourceInterest({"cluster2"});

  // Retry and succeed.
  EXPECT_CALL(*async_client_, startRaw(_, _, _, _)).WillOnce(Return(&async_stream_));

  expectSendMessage({"cluster2"}, "", true);
  timer_->invokeCallback();
  EXPECT_TRUE(statsAre(3, 0, 0, 1, 0, 0, 0, ""));
  verifyControlPlaneStats(1);
}
test/common/config/grpc_subscription_impl_test.cc:48GrpcSubscriptionImplTest.RemoteStreamClose · C++ · 19 lines
TEST_P(GrpcSubscriptionImplTest, RemoteStreamClose) {
  startSubscription({"cluster0", "cluster1"});
  EXPECT_TRUE(statsAre(1, 0, 0, 0, 0, 0, 0, ""));
  // onConfigUpdateFailed() should not be called for gRPC stream connection failure
  EXPECT_CALL(callbacks_,
              onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason::ConnectionFailure, _))
      .Times(0);
  EXPECT_CALL(*timer_, enableTimer(_, _));
  EXPECT_CALL(random_, random());
  onRemoteClose();
  EXPECT_TRUE(statsAre(2, 0, 0, 1, 0, 0, 0, ""));
  verifyControlPlaneStats(0);

  // Retry and succeed.
  EXPECT_CALL(*async_client_, startRaw(_, _, _, _)).WillOnce(Return(&async_stream_));
  expectSendMessage({"cluster0", "cluster1"}, "", true);
  timer_->invokeCallback();
  EXPECT_TRUE(statsAre(2, 0, 0, 1, 0, 0, 0, ""));
}
test/common/config/grpc_subscription_impl_test.cc:70GrpcSubscriptionImplTest.RepeatedNonce · C++ · 19 lines
TEST_P(GrpcSubscriptionImplTest, RepeatedNonce) {
  InSequence s;
  startSubscription({"cluster0", "cluster1"});
  EXPECT_TRUE(statsAre(1, 0, 0, 0, 0, 0, 0, ""));
  // First with the initial, empty version update to "0".
  updateResourceInterest({"cluster2"});
  EXPECT_TRUE(statsAre(2, 0, 0, 0, 0, 0, 0, ""));
  deliverConfigUpdate({"cluster0", "cluster2"}, "0", false);
  EXPECT_TRUE(statsAre(3, 0, 1, 0, 0, 0, 0, ""));
  deliverConfigUpdate({"cluster0", "cluster2"}, "0", true);
  EXPECT_TRUE(statsAre(4, 1, 1, 0, 0, TEST_TIME_MILLIS, 7148434200721666028, "0"));
  // Now with version "0" update to "1".
  updateResourceInterest({"cluster3"});
  EXPECT_TRUE(statsAre(5, 1, 1, 0, 0, TEST_TIME_MILLIS, 7148434200721666028, "0"));
  deliverConfigUpdate({"cluster3"}, "42", false);
  EXPECT_TRUE(statsAre(6, 1, 2, 0, 0, TEST_TIME_MILLIS, 7148434200721666028, "0"));
  deliverConfigUpdate({"cluster3"}, "42", true);
  EXPECT_TRUE(statsAre(7, 2, 2, 0, 0, TEST_TIME_MILLIS, 7919287270473417401, "42"));
}
+ 13 more tests · open all in source
IMPLS

N/A · no in-tree implementor

EXAMPLES

N/A

WORKFLOWS

N/A

CONTRACT
// [#next-free-field: 8]
message DiscoveryResponse {
  option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.DiscoveryResponse";

  // The version of the response data.
  string version_info = 1;

  // The response resources. These resources are typed and depend on the API being called.
  repeated google.protobuf.Any resources = 2;

  // [#not-implemented-hide:]
  // Canary is used to support two Envoy command line flags:
  //
DOCS
docs/root/api-docs/xds_protocol.rst:692reStructuredText · 32 words

:ref:`DiscoveryResponse <envoy_v3_api_msg_service.discovery.v3.DiscoveryResponse>`. A management server does not need to send an update until it determines a new version is available. Earlier requests at a version then also become stale. It may process multiple :ref:`DiscoveryRequests <envoy_v3_api_msg_service.discovery.v3.DiscoveryRequest>` at a version until a new version is ready.

+ 53 more paragraphs · read full section
docs/root/api-docs/xds_protocol.rst:682reStructuredText · 31 words

``X`` :ref:`version_info <envoy_v3_api_field_service.discovery.v3.DiscoveryResponse.version_info>`. To avoid this, the management server provides a ``nonce`` that Envoy uses to indicate the specific :ref:`DiscoveryResponse <envoy_v3_api_msg_service.discovery.v3.DiscoveryResponse>` each :ref:`DiscoveryRequest <envoy_v3_api_msg_service.discovery.v3.DiscoveryRequest>` corresponds to:

+ 55 more paragraphs · read full section
docs/root/api-docs/xds_protocol.rst:79reStructuredText · 30 words

:ref:`DiscoveryResponse <envoy_v3_api_msg_service.discovery.v3.DiscoveryResponse>` proto in the file on update. Binary protobufs, JSON, YAML and proto text are supported formats for the :ref:`DiscoveryResponse <envoy_v3_api_msg_service.discovery.v3.DiscoveryResponse>`.

+ 173 more paragraphs · read full section
+ 27 more refs · open all in source
TESTS
test/common/config/grpc_subscription_impl_test.cc:22GrpcSubscriptionImplTest.StreamCreationFailure · C++ · 24 lines
TEST_P(GrpcSubscriptionImplTest, StreamCreationFailure) {
  InSequence s;
  EXPECT_CALL(*async_client_, startRaw(_, _, _, _)).WillOnce(Return(nullptr));

  // onConfigUpdateFailed() should not be called for gRPC stream connection failure
  EXPECT_CALL(callbacks_,
              onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason::ConnectionFailure, _))
      .Times(0);
  EXPECT_CALL(random_, random());
  EXPECT_CALL(*timer_, enableTimer(_, _));
  subscription_->start({"cluster0", "cluster1"});
  EXPECT_TRUE(statsAre(2, 0, 0, 1, 0, 0, 0, ""));
  // Ensure this doesn't cause an issue by sending a request, since we don't
  // have a gRPC stream.
  subscription_->updateResourceInterest({"cluster2"});

  // Retry and succeed.
  EXPECT_CALL(*async_client_, startRaw(_, _, _, _)).WillOnce(Return(&async_stream_));

  expectSendMessage({"cluster2"}, "", true);
  timer_->invokeCallback();
  EXPECT_TRUE(statsAre(3, 0, 0, 1, 0, 0, 0, ""));
  verifyControlPlaneStats(1);
}
test/common/config/grpc_subscription_impl_test.cc:48GrpcSubscriptionImplTest.RemoteStreamClose · C++ · 19 lines
TEST_P(GrpcSubscriptionImplTest, RemoteStreamClose) {
  startSubscription({"cluster0", "cluster1"});
  EXPECT_TRUE(statsAre(1, 0, 0, 0, 0, 0, 0, ""));
  // onConfigUpdateFailed() should not be called for gRPC stream connection failure
  EXPECT_CALL(callbacks_,
              onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason::ConnectionFailure, _))
      .Times(0);
  EXPECT_CALL(*timer_, enableTimer(_, _));
  EXPECT_CALL(random_, random());
  onRemoteClose();
  EXPECT_TRUE(statsAre(2, 0, 0, 1, 0, 0, 0, ""));
  verifyControlPlaneStats(0);

  // Retry and succeed.
  EXPECT_CALL(*async_client_, startRaw(_, _, _, _)).WillOnce(Return(&async_stream_));
  expectSendMessage({"cluster0", "cluster1"}, "", true);
  timer_->invokeCallback();
  EXPECT_TRUE(statsAre(2, 0, 0, 1, 0, 0, 0, ""));
}
test/common/config/grpc_subscription_impl_test.cc:70GrpcSubscriptionImplTest.RepeatedNonce · C++ · 19 lines
TEST_P(GrpcSubscriptionImplTest, RepeatedNonce) {
  InSequence s;
  startSubscription({"cluster0", "cluster1"});
  EXPECT_TRUE(statsAre(1, 0, 0, 0, 0, 0, 0, ""));
  // First with the initial, empty version update to "0".
  updateResourceInterest({"cluster2"});
  EXPECT_TRUE(statsAre(2, 0, 0, 0, 0, 0, 0, ""));
  deliverConfigUpdate({"cluster0", "cluster2"}, "0", false);
  EXPECT_TRUE(statsAre(3, 0, 1, 0, 0, 0, 0, ""));
  deliverConfigUpdate({"cluster0", "cluster2"}, "0", true);
  EXPECT_TRUE(statsAre(4, 1, 1, 0, 0, TEST_TIME_MILLIS, 7148434200721666028, "0"));
  // Now with version "0" update to "1".
  updateResourceInterest({"cluster3"});
  EXPECT_TRUE(statsAre(5, 1, 1, 0, 0, TEST_TIME_MILLIS, 7148434200721666028, "0"));
  deliverConfigUpdate({"cluster3"}, "42", false);
  EXPECT_TRUE(statsAre(6, 1, 2, 0, 0, TEST_TIME_MILLIS, 7148434200721666028, "0"));
  deliverConfigUpdate({"cluster3"}, "42", true);
  EXPECT_TRUE(statsAre(7, 2, 2, 0, 0, TEST_TIME_MILLIS, 7919287270473417401, "42"));
}
+ 70 more tests · open all in source
IMPLS

N/A · no in-tree implementor

EXAMPLES

N/A

WORKFLOWS

N/A

CONTRACT
// A set of dynamic parameter constraints associated with a variant of an individual xDS resource.
// These constraints determine whether the resource matches a subscription based on the set of
// dynamic parameters in the subscription, as specified in the
// :ref:`ResourceLocator.dynamic_parameters <envoy_v3_api_field_service.discovery.v3.ResourceLocator.dynamic_parameters>`
// field. This allows xDS implementations (clients, servers, and caching proxies) to determine
// which variant of a resource is appropriate for a given client.
message DynamicParameterConstraints {
  // A single constraint for a given key.
  message SingleConstraint {
    message Exists {
    }

    // The key to match against.
    string key = 1;

    oneof constraint_type {
      option (validate.required) = true;
DOCS

N/A

TESTS

N/A

IMPLS

N/A · no in-tree implementor

EXAMPLES

N/A

WORKFLOWS

N/A

CONTRACT
// [#next-free-field: 10]
message Resource {
  option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.Resource";

  // Cache control properties for the resource.
  // [#not-implemented-hide:]
  message CacheControl {
    // If true, xDS proxies may not cache this resource.
    //
    // .. note::
    //   This does not apply to clients other than xDS proxies, which must cache resources
    //   for their own use, regardless of the value of this field.
    //
DOCS
docs/root/api-docs/xds_protocol.rst:805reStructuredText · 34 words

:ref:`Resource <envoy_v3_api_msg_service.discovery.v3.Resource>`. This allows setting the same TTL field that is used for Delta xDS with SotW, without changing the SotW API. Heartbeats are supported for SotW as well: any resource within the response that look like a heartbeat resource will only be used to update the TTL.

+ 34 more paragraphs · read full section
docs/root/api-docs/xds_protocol.rst:789reStructuredText · 28 words

be specified on each :ref:`Resource <envoy_v3_api_msg_service.discovery.v3.Resource>`. Each resource will have its own TTL expiry time, at which point the resource will be expired. Each xDS type may have different ways of handling such an expiry.

+ 38 more paragraphs · read full section
docs/root/api-docs/xds_protocol.rst:797reStructuredText · 19 words

:ref:`Resource <envoy_v3_api_msg_service.discovery.v3.Resource>` with the :ref:`resource <envoy_v3_api_msg_service.discovery.v3.Resource>` unset and version matching the most recently sent version can be used to update the TTL. These resources will not be treated as resource updates, but only as TTL updates.

+ 36 more paragraphs · read full section
+ 2 more refs · open all in source
TESTS
test/common/config/decoded_resource_impl_test.cc:15DecodedResourceImplTest.All · C++ · 137 lines
TEST(DecodedResourceImplTest, All) {
  MockOpaqueResourceDecoder resource_decoder;
  Protobuf::Any some_opaque_resource;
  some_opaque_resource.set_type_url("some_type_url");

  {
    EXPECT_CALL(resource_decoder, decodeResource(ProtoEq(some_opaque_resource)))
        .WillOnce(InvokeWithoutArgs(
            []() -> ProtobufTypes::MessagePtr { return std::make_unique<Protobuf::Empty>(); }));
    EXPECT_CALL(resource_decoder, resourceName(ProtoEq(Protobuf::Empty())))
        .WillOnce(Return("some_name"));
    auto decoded_resource =
        *DecodedResourceImpl::fromResource(resource_decoder, some_opaque_resource, "foo");
    EXPECT_EQ("some_name", decoded_resource->name());
    EXPECT_TRUE(decoded_resource->aliases().empty());
    EXPECT_EQ("foo", decoded_resource->version());
    EXPECT_THAT(decoded_resource->resource(), ProtoEq(Protobuf::Empty()));
    EXPECT_TRUE(decoded_resource->hasResource());
  }

  {
    envoy::service::discovery::v3::Resource resource_wrapper;
    resource_wrapper.set_name("real_name");
    resource_wrapper.add_aliases("bar");
    resource_wrapper.add_aliases("baz");
    resource_wrapper.mutable_resource()->MergeFrom(some_opaque_resource);
    resource_wrapper.set_version("foo");
    EXPECT_CALL(resource_decoder, decodeResource(ProtoEq(some_opaque_resource)))
        .WillOnce(InvokeWithoutArgs(
            []() -> ProtobufTypes::MessagePtr { return std::make_unique<Protobuf::Empty>(); }));
+ 107 more lines · read full file
test/common/upstream/cds_api_impl_test.cc:184CdsApiImplTest.DeltaConfigUpdate · C++ · 51 lines
TEST_F(CdsApiImplTest, DeltaConfigUpdate) {
  {
    InSequence s;
    setup();
  }
  EXPECT_CALL(initialized_, ready());

  {
    Protobuf::RepeatedPtrField<envoy::service::discovery::v3::Resource> resources;
    {
      envoy::config::cluster::v3::Cluster cluster;
      cluster.set_name("cluster_1");
      expectAdd("cluster_1", "v1");
      auto* resource = resources.Add();
      resource->mutable_resource()->PackFrom(cluster);
      resource->set_name("cluster_1");
      resource->set_version("v1");
    }
    {
      envoy::config::cluster::v3::Cluster cluster;
      cluster.set_name("cluster_2");
      expectAdd("cluster_2", "v1");
      auto* resource = resources.Add();
      resource->mutable_resource()->PackFrom(cluster);
      resource->set_name("cluster_2");
      resource->set_version("v1");
    }
    const auto decoded_resources =
        TestUtility::decodeResources<envoy::config::cluster::v3::Cluster>(resources);
    EXPECT_TRUE(cds_callbacks_->onConfigUpdate(decoded_resources.refvec_, {}, "v1").ok());
+ 21 more lines · read full file
test/extensions/clusters/eds/eds_test.cc:306EdsTest.DeltaOnConfigUpdateSuccess · C++ · 18 lines
TEST_F(EdsTest, DeltaOnConfigUpdateSuccess) {
  envoy::config::endpoint::v3::ClusterLoadAssignment cluster_load_assignment;
  cluster_load_assignment.set_cluster_name("fare");
  initialize();

  Protobuf::RepeatedPtrField<envoy::service::discovery::v3::Resource> resources;
  auto* resource = resources.Add();
  resource->mutable_resource()->PackFrom(cluster_load_assignment);
  resource->set_version("v1");
  const auto decoded_resources =
      TestUtility::decodeResources<envoy::config::endpoint::v3::ClusterLoadAssignment>(
          resources, "cluster_name");
  EXPECT_TRUE(eds_callbacks_->onConfigUpdate(decoded_resources.refvec_, {}, "v1").ok());

  EXPECT_TRUE(initialized_);
  EXPECT_EQ(1UL,
            stats_.findCounterByString("cluster.name.update_no_rebuild").value().get().value());
}
+ 23 more tests · open all in source
IMPLS

N/A · no in-tree implementor

EXAMPLES

N/A

WORKFLOWS

N/A

CONTRACT
// [#not-implemented-hide:]
// An error associated with a specific resource name, returned to the
// client by the server.
message ResourceError {
  // The name of the resource.
  ResourceName resource_name = 1;

  // The error reported for the resource.
  google.rpc.Status error_detail = 2;
}
DOCS

N/A

TESTS

N/A

IMPLS

N/A · no in-tree implementor

EXAMPLES

N/A

WORKFLOWS

N/A

CONTRACT
// Specifies a resource to be subscribed to.
message ResourceLocator {
  // The resource name to subscribe to.
  string name = 1;

  // A set of dynamic parameters used to match against the dynamic parameter
  // constraints on the resource. This allows clients to select between
  // multiple variants of the same resource.
  map<string, string> dynamic_parameters = 2;
}
DOCS

N/A

TESTS

N/A

IMPLS

N/A · no in-tree implementor

EXAMPLES

N/A

WORKFLOWS

N/A

CONTRACT
// Specifies a concrete resource name.
message ResourceName {
  // The name of the resource.
  string name = 1;

  // Dynamic parameter constraints associated with this resource. To be used by client-side caches
  // (including xDS proxies) when matching subscribed resource locators.
  DynamicParameterConstraints dynamic_parameter_constraints = 2;
}
DOCS

N/A

TESTS

N/A

IMPLS

N/A · no in-tree implementor

EXAMPLES

N/A

WORKFLOWS

N/A

Workflows

Workflow coverage
No workflow corpus configured. The substance and worklist views above measure whether elements are documented, tested, and demonstrated in isolation — they do not measure whether elements appear together in any documented sequence. Configure a workflows rendered-reference block to surface this layer.
Low-coverage threshold. The red chip and matching tile border fire when a metric is at or below 20% — a figure picked because "one in five" is the folk-defensible floor at which a reasonable engineer agrees the surface is too thin to be discoverable. The threshold is absolute today; once the cross-project scan corpus crosses 100 libraries it migrates to a per-tier percentile (bottom decile fires the chip).
sheaf scanner · 13 methods · proto surface · 2026-05-29 03:42 UTC