// 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.status.v3;

import "envoy/admin/v3/config_dump_shared.proto";
import "envoy/config/core/v3/base.proto";
import "envoy/type/matcher/v3/node.proto";

import "google/api/annotations.proto";
import "google/protobuf/any.proto";
import "google/protobuf/timestamp.proto";

import "envoy/annotations/deprecation.proto";
import "udpa/annotations/status.proto";
import "udpa/annotations/versioning.proto";

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

// [#protodoc-title: Client status discovery service (CSDS)]

// CSDS is Client Status Discovery Service. It can be used to get the status of
// an xDS-compliant client from the management server's point of view. It can
// also be used to get the current xDS states directly from the client.
service ClientStatusDiscoveryService {
  rpc StreamClientStatus(stream ClientStatusRequest) returns (stream ClientStatusResponse) {
  }

  rpc FetchClientStatus(ClientStatusRequest) returns (ClientStatusResponse) {
    option (google.api.http).post = "/v3/discovery:client_status";
    option (google.api.http).body = "*";
  }
}

// Status of a config from a management server view.
enum ConfigStatus {
  // Status info is not available/unknown.
  UNKNOWN = 0;

  // Management server has sent the config to client and received ACK.
  SYNCED = 1;

  // Config is not sent.
  NOT_SENT = 2;

  // Management server has sent the config to client but hasn’t received
  // ACK/NACK.
  STALE = 3;

  // Management server has sent the config to client but received NACK. The
  // attached config dump will be the latest config (the rejected one), since
  // it is the persisted version in the management server.
  ERROR = 4;
}

// Config status from a client-side view.
enum ClientConfigStatus {
  // Config status is not available/unknown.
  CLIENT_UNKNOWN = 0;

  // Client requested the config but hasn't received any config from management
  // server yet.
  CLIENT_REQUESTED = 1;

  // Client received the config and replied with ACK.
  CLIENT_ACKED = 2;

  // Client received the config and replied with NACK. Notably, the attached
  // config dump is not the NACKed version, but the most recent accepted one. If
  // no config is accepted yet, the attached config dump will be empty.
  CLIENT_NACKED = 3;

  // Client received an error from the control plane. The attached config
  // dump is the most recent accepted one. If no config is accepted yet,
  // the attached config dump will be empty.
  CLIENT_RECEIVED_ERROR = 4;
}

// Request for client status of clients identified by a list of NodeMatchers.
message ClientStatusRequest {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.service.status.v2.ClientStatusRequest";

  // Management server can use these match criteria to identify clients.
  // The match follows OR semantics.
  repeated type.matcher.v3.NodeMatcher node_matchers = 1;

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

  // If true, the server will not include the resource contents in the response
  // (i.e., the generic_xds_configs.xds_config field will not be populated).
  // [#not-implemented-hide:]
  bool exclude_resource_contents = 3;
}

// Detailed config (per xDS) with status.
// [#next-free-field: 8]
message PerXdsConfig {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.service.status.v2.PerXdsConfig";

  // Config status generated by management servers. Will not be present if the
  // CSDS server is an xDS client.
  ConfigStatus status = 1;

  // Client config status is populated by xDS clients. Will not be present if
  // the CSDS server is an xDS server. No matter what the client config status
  // is, xDS clients should always dump the most recent accepted xDS config.
  //
  // .. attention::
  //   This field is deprecated. Use :ref:`ClientResourceStatus
  //   <envoy_v3_api_enum_admin.v3.ClientResourceStatus>` for per-resource
  //   config status instead.
  ClientConfigStatus client_status = 7
      [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"];

  oneof per_xds_config {
    admin.v3.ListenersConfigDump listener_config = 2;

    admin.v3.ClustersConfigDump cluster_config = 3;

    admin.v3.RoutesConfigDump route_config = 4;

    admin.v3.ScopedRoutesConfigDump scoped_route_config = 5;

    admin.v3.EndpointsConfigDump endpoint_config = 6;
  }
}

// All xds configs for a particular client.
message ClientConfig {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.service.status.v2.ClientConfig";

  // GenericXdsConfig is used to specify the config status and the dump
  // of any xDS resource identified by their type URL. It is the generalized
  // version of the now deprecated ListenersConfigDump, ClustersConfigDump etc
  // [#next-free-field: 10]
  message GenericXdsConfig {
    // Type_url represents the fully qualified name of xDS resource type
    // like envoy.v3.Cluster, envoy.v3.ClusterLoadAssignment etc.
    string type_url = 1;

    // Name of the xDS resource
    string name = 2;

    // This is the :ref:`version_info <envoy_v3_api_field_service.discovery.v3.DiscoveryResponse.version_info>`
    // in the last processed xDS discovery response. If there are only
    // static bootstrap listeners, this field will be ""
    string version_info = 3;

    // The xDS resource config. Actual content depends on the type
    google.protobuf.Any xds_config = 4;

    // Timestamp when the xDS resource was last updated
    google.protobuf.Timestamp last_updated = 5;

    // Per xDS resource config status. It is generated by management servers.
    // It will not be present if the CSDS server is an xDS client.
    ConfigStatus config_status = 6;

    // Per xDS resource status from the view of a xDS client
    admin.v3.ClientResourceStatus client_status = 7;

    // Set if the last update failed, cleared after the next successful
    // update. The *error_state* field contains the rejected version of
    // this particular resource along with the reason and timestamp. For
    // successfully updated or acknowledged resource, this field should
    // be empty.
    // [#not-implemented-hide:]
    admin.v3.UpdateFailureState error_state = 8;

    // Is static resource is true if it is specified in the config supplied
    // through the file at the startup.
    bool is_static_resource = 9;
  }

  // Node for a particular client.
  config.core.v3.Node node = 1;

  // This field is deprecated in favor of generic_xds_configs which is
  // much simpler and uniform in structure.
  repeated PerXdsConfig xds_config = 2
      [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"];

  // Represents generic xDS config and the exact config structure depends on
  // the type URL (like Cluster if it is CDS)
  repeated GenericXdsConfig generic_xds_configs = 3;

  // For xDS clients, the scope in which the data is used.
  // For example, gRPC indicates the data plane target or that the data is
  // associated with gRPC server(s).
  string client_scope = 4;
}

message ClientStatusResponse {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.service.status.v2.ClientStatusResponse";

  // Client configs for the clients specified in the ClientStatusRequest.
  repeated ClientConfig config = 1;
}
