// Copyright 2025 Envoy Project Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package envoy.service.discovery.v3;

import "envoy/config/core/v3/base.proto";

import "google/protobuf/any.proto";
import "google/protobuf/duration.proto";
import "google/rpc/status.proto";

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

option java_package = "io.envoyproxy.envoy.service.discovery.v3";
option java_outer_classname = "DiscoveryProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3;discoveryv3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: Common discovery API components]

// 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;
}

// 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;
}

// [#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;
}

// 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;

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

  // List of resources to subscribe to, e.g. list of cluster names or a route
  // configuration name. If this is empty, all resources for the API are
  // returned. LDS/CDS may have empty ``resource_names``, which will cause all
  // resources for the Envoy instance to be returned. The LDS and CDS responses
  // will then imply a number of resources that need to be fetched via EDS/RDS,
  // which will be explicitly enumerated in ``resource_names``.
  repeated string resource_names = 3;

  // [#not-implemented-hide:]
  // Alternative to ``resource_names`` field that allows specifying dynamic
  // parameters along with each resource name. Clients that populate this
  // field must be able to handle responses from the server where resources
  // are wrapped in a Resource message.
  //
  // .. note::
  //   It is legal for a request to have some resources listed
  //   in ``resource_names`` and others in ``resource_locators``.
  //
  repeated ResourceLocator resource_locators = 7;

  // Type of the resource that is being requested, e.g.
  // ``type.googleapis.com/envoy.api.v2.ClusterLoadAssignment``. This is implicit
  // in requests made via singleton xDS APIs such as CDS, LDS, etc. but is
  // required for ADS.
  string type_url = 4;

  // nonce corresponding to ``DiscoveryResponse`` being ACK/NACKed. See above
  // discussion on ``version_info`` and the ``DiscoveryResponse`` nonce comment. This
  // may be empty only if:
  //
  // * This is a non-persistent-stream xDS such as HTTP, or
  // * The client has not yet accepted an update in this xDS stream (unlike
  //   delta, where it is populated only for new explicit ACKs).
  //
  string response_nonce = 5;

  // This is populated when the previous :ref:`DiscoveryResponse <envoy_v3_api_msg_service.discovery.v3.DiscoveryResponse>`
  // failed to update configuration. The ``message`` field in ``error_details`` provides the Envoy
  // internal exception related to the failure. It is only intended for consumption during manual
  // debugging, the string provided is not guaranteed to be stable across Envoy versions.
  google.rpc.Status error_detail = 6;
}

// [#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:
  //
  // * ``--terminate-on-canary-transition-failure``. When set, Envoy is able to
  //   terminate if it detects that configuration is stuck at canary. Consider
  //   this example sequence of updates:
  //
  //   * Management server applies a canary config successfully.
  //   * Management server rolls back to a production config.
  //   * Envoy rejects the new production config.
  //
  //   Since there is no sensible way to continue receiving configuration
  //   updates, Envoy will then terminate and apply production config from a
  //   clean slate.
  //
  // * ``--dry-run-canary``. When set, a canary response will never be applied, only
  //   validated via a dry run.
  //
  bool canary = 3;

  // Type URL for resources. Identifies the xDS API when muxing over ADS.
  // Must be consistent with the ``type_url`` in the 'resources' repeated Any (if non-empty).
  string type_url = 4;

  // For gRPC based subscriptions, the nonce provides a way to explicitly ack a
  // specific ``DiscoveryResponse`` in a following ``DiscoveryRequest``. Additional
  // messages may have been sent by Envoy to the management server for the
  // previous version on the stream prior to this ``DiscoveryResponse``, that were
  // unprocessed at response send time. The nonce allows the management server
  // to ignore any further ``DiscoveryRequests`` for the previous version until a
  // ``DiscoveryRequest`` bearing the nonce. The nonce is optional and is not
  // required for non-stream based xDS implementations.
  string nonce = 5;

  // The control plane instance that sent the response.
  config.core.v3.ControlPlane control_plane = 6;

  // [#not-implemented-hide:]
  // Errors associated with specific resources. Clients are expected to
  // remember the most recent error for a given resource across responses;
  // the error condition is not considered to be cleared until a response is
  // received that contains the resource in the 'resources' field.
  repeated ResourceError resource_errors = 7;
}

// DeltaDiscoveryRequest and DeltaDiscoveryResponse are used in a new gRPC
// endpoint for Delta xDS.
//
// With Delta xDS, the DeltaDiscoveryResponses do not need to include a full
// snapshot of the tracked resources. Instead, DeltaDiscoveryResponses are a
// diff to the state of a xDS client.
// In Delta XDS there are per-resource versions, which allow tracking state at
// the resource granularity.
// An xDS Delta session is always in the context of a gRPC bidirectional
// stream. This allows the xDS server to keep track of the state of xDS clients
// connected to it.
//
// In Delta xDS the nonce field is required and used to pair
// ``DeltaDiscoveryResponse`` to a ``DeltaDiscoveryRequest`` ACK or NACK.
// Optionally, a response message level ``system_version_info`` is present for
// debugging purposes only.
//
// ``DeltaDiscoveryRequest`` plays two independent roles. Any ``DeltaDiscoveryRequest``
// can be either or both of:
//
// * Informing the server of what resources the client has gained/lost interest in
//   (using ``resource_names_subscribe`` and ``resource_names_unsubscribe``), or
// * (N)ACKing an earlier resource update from the server (using ``response_nonce``,
//   with presence of ``error_detail`` making it a NACK).
//
// Additionally, the first message (for a given ``type_url``) of a reconnected gRPC stream
// has a third role: informing the server of the resources (and their versions)
// that the client already possesses, using the ``initial_resource_versions`` field.
//
// As with state-of-the-world, when multiple resource types are multiplexed (ADS),
// 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;

  // DeltaDiscoveryRequests allow the client to add or remove individual
  // resources to the set of tracked resources in the context of a stream.
  // All resource names in the ``resource_names_subscribe`` list are added to the
  // set of tracked resources and all resource names in the ``resource_names_unsubscribe``
  // list are removed from the set of tracked resources.
  //
  // *Unlike* state-of-the-world xDS, an empty ``resource_names_subscribe`` or
  // ``resource_names_unsubscribe`` list simply means that no resources are to be
  // added or removed to the resource list.
  // *Like* state-of-the-world xDS, the server must send updates for all tracked
  // resources, but can also send updates for resources the client has not subscribed to.
  //
  // .. note::
  //   The server must respond with all resources listed in ``resource_names_subscribe``,
  //   even if it believes the client has the most recent version of them. The reason:
  //   the client may have dropped them, but then regained interest before it had a chance
  //   to send the unsubscribe message. See DeltaSubscriptionStateTest.RemoveThenAdd.
  //
  // These two fields can be set in any ``DeltaDiscoveryRequest``, including ACKs
  // and ``initial_resource_versions``.
  //
  // A list of Resource names to add to the list of tracked resources.
  repeated string resource_names_subscribe = 3;

  // A list of Resource names to remove from the list of tracked resources.
  repeated string resource_names_unsubscribe = 4;

  // [#not-implemented-hide:]
  // Alternative to ``resource_names_subscribe`` field that allows specifying dynamic parameters
  // along with each resource name.
  //
  // .. note::
  //   It is legal for a request to have some resources listed
  //   in ``resource_names_subscribe`` and others in ``resource_locators_subscribe``.
  //
  repeated ResourceLocator resource_locators_subscribe = 8;

  // [#not-implemented-hide:]
  // Alternative to ``resource_names_unsubscribe`` field that allows specifying dynamic parameters
  // along with each resource name.
  //
  // .. note::
  //   It is legal for a request to have some resources listed
  //   in ``resource_names_unsubscribe`` and others in ``resource_locators_unsubscribe``.
  //
  repeated ResourceLocator resource_locators_unsubscribe = 9;

  // Informs the server of the versions of the resources the xDS client knows of, to enable the
  // client to continue the same logical xDS session even in the face of gRPC stream reconnection.
  // It will not be populated:
  //
  // * In the very first stream of a session, since the client will not yet have any resources.
  // * In any message after the first in a stream (for a given ``type_url``), since the server will
  //   already be correctly tracking the client's state.
  //
  // (In ADS, the first message ``of each type_url`` of a reconnected stream populates this map.)
  // The map's keys are names of xDS resources known to the xDS client.
  // The map's values are opaque resource versions.
  map<string, string> initial_resource_versions = 5;

  // When the ``DeltaDiscoveryRequest`` is a ACK or NACK message in response
  // to a previous ``DeltaDiscoveryResponse``, the ``response_nonce`` must be the
  // nonce in the ``DeltaDiscoveryResponse``.
  // Otherwise (unlike in ``DiscoveryRequest``) ``response_nonce`` must be omitted.
  string response_nonce = 6;

  // This is populated when the previous :ref:`DiscoveryResponse <envoy_v3_api_msg_service.discovery.v3.DiscoveryResponse>`
  // failed to update configuration. The ``message`` field in ``error_details``
  // provides the Envoy internal exception related to the failure.
  google.rpc.Status error_detail = 7;
}

// [#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!

  // Type URL for resources. Identifies the xDS API when muxing over ADS.
  // Must be consistent with the ``type_url`` in the Any within 'resources' if 'resources' is non-empty.
  string type_url = 4;

  // Resource names of resources that have been deleted and to be removed from the xDS Client.
  // Removed resources for missing resources can be ignored.
  repeated string removed_resources = 6;

  // Alternative to ``removed_resources`` that allows specifying which variant of
  // a resource is being removed. This variant must be used for any resource
  // for which dynamic parameter constraints were sent to the client.
  repeated ResourceName removed_resource_names = 8;

  // The nonce provides a way for ``DeltaDiscoveryRequests`` to uniquely
  // reference a ``DeltaDiscoveryResponse`` when (N)ACKing. The nonce is required.
  string nonce = 5;

  // [#not-implemented-hide:]
  // The control plane instance that sent the response.
  config.core.v3.ControlPlane control_plane = 7;

  // [#not-implemented-hide:]
  // Errors associated with specific resources.
  //
  // .. note::
  //   A resource in this field with a status of NOT_FOUND should be treated the same as
  //   a resource listed in the ``removed_resources`` or ``removed_resource_names`` fields.
  //
  repeated ResourceError resource_errors = 9;
}

// 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;

      // Matches this exact value.
      string value = 2;

      // Key is present (matches any value except for the key being absent).
      // This allows setting a default constraint for clients that do
      // not send a key at all, while there may be other clients that need
      // special configuration based on that key.
      Exists exists = 3;
    }
  }

  message ConstraintList {
    repeated DynamicParameterConstraints constraints = 1;
  }

  oneof type {
    // A single constraint to evaluate.
    SingleConstraint constraint = 1;

    // A list of constraints that match if any one constraint in the list
    // matches.
    ConstraintList or_constraints = 2;

    // A list of constraints that must all match.
    ConstraintList and_constraints = 3;

    // The inverse (NOT) of a set of constraints.
    DynamicParameterConstraints not_constraints = 4;
  }
}

// [#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.
    //
    bool do_not_cache = 1;
  }

  // The resource's name, to distinguish it from others of the same type of resource.
  // Only one of ``name`` or ``resource_name`` may be set.
  string name = 3;

  // Alternative to the ``name`` field, to be used when the server supports
  // multiple variants of the named resource that are differentiated by
  // dynamic parameter constraints.
  // Only one of ``name`` or ``resource_name`` may be set.
  ResourceName resource_name = 8;

  // The aliases are a list of other names that this resource can go by.
  repeated string aliases = 4;

  // The resource level version. It allows xDS to track the state of individual
  // resources.
  string version = 1;

  // The resource being tracked.
  google.protobuf.Any resource = 2;

  // Time-to-live value for the resource. For each resource, a timer is started. The timer is
  // reset each time the resource is received with a new TTL. If the resource is received with
  // no TTL set, the timer is removed for the resource. Upon expiration of the timer, the
  // configuration for the resource will be removed.
  //
  // The TTL can be refreshed or changed by sending a response that doesn't change the resource
  // version. In this case the ``resource`` field does not need to be populated, which allows for
  // light-weight "heartbeat" updates to keep a resource with a TTL alive.
  //
  // The TTL feature is meant to support configurations that should be removed in the event of
  // a management server failure. For example, the feature may be used for fault injection
  // testing where the fault injection should be terminated in the event that Envoy loses contact
  // with the management server.
  google.protobuf.Duration ttl = 6;

  // Cache control properties for the resource.
  // [#not-implemented-hide:]
  CacheControl cache_control = 7;

  // The Metadata field can be used to provide additional information for the resource.
  // E.g. the trace data for debugging.
  config.core.v3.Metadata metadata = 9;
}
