syntax = "proto3";

package envoy.type.metadata.v3;

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

option java_package = "io.envoyproxy.envoy.type.metadata.v3";
option java_outer_classname = "MetadataProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/type/metadata/v3;metadatav3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: Metadata]

// MetadataKey provides a general interface using ``key`` and ``path`` to retrieve value from
// :ref:`Metadata <envoy_v3_api_msg_config.core.v3.Metadata>`.
//
// For example, for the following Metadata:
//
// .. code-block:: yaml
//
//    filter_metadata:
//      envoy.xxx:
//        prop:
//          foo: bar
//          xyz:
//            hello: envoy
//
// The following MetadataKey will retrieve a string value "bar" from the Metadata.
//
// .. code-block:: yaml
//
//    key: envoy.xxx
//    path:
//    - key: prop
//    - key: foo
//
message MetadataKey {
  option (udpa.annotations.versioning).previous_message_type = "envoy.type.metadata.v2.MetadataKey";

  // Specifies the segment in a path to retrieve value from Metadata.
  // Currently it is only supported to specify the key, i.e. field name, as one segment of a path.
  message PathSegment {
    option (udpa.annotations.versioning).previous_message_type =
        "envoy.type.metadata.v2.MetadataKey.PathSegment";

    oneof segment {
      option (validate.required) = true;

      // If specified, use the key to retrieve the value in a Struct.
      string key = 1 [(validate.rules).string = {min_len: 1}];
    }
  }

  // The key name of Metadata to retrieve the Struct from the metadata.
  // Typically, it represents a builtin subsystem or custom extension.
  string key = 1 [(validate.rules).string = {min_len: 1}];

  // The path to retrieve the Value from the Struct. It can be a prefix or a full path,
  // e.g. ``[prop, xyz]`` for a struct or ``[prop, foo]`` for a string in the example,
  // which depends on the particular scenario.
  //
  // Note: Due to that only the key type segment is supported, the path can not specify a list
  // unless the list is the last segment.
  repeated PathSegment path = 2 [(validate.rules).repeated = {min_items: 1}];
}

// Describes what kind of metadata.
message MetadataKind {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.type.metadata.v2.MetadataKind";

  // Represents dynamic metadata associated with the request.
  message Request {
    option (udpa.annotations.versioning).previous_message_type =
        "envoy.type.metadata.v2.MetadataKind.Request";
  }

  // Represents metadata from :ref:`the route<envoy_v3_api_field_config.route.v3.Route.metadata>`.
  message Route {
    option (udpa.annotations.versioning).previous_message_type =
        "envoy.type.metadata.v2.MetadataKind.Route";
  }

  // Represents metadata from :ref:`the upstream cluster<envoy_v3_api_field_config.cluster.v3.Cluster.metadata>`.
  message Cluster {
    option (udpa.annotations.versioning).previous_message_type =
        "envoy.type.metadata.v2.MetadataKind.Cluster";
  }

  // Represents metadata from :ref:`the upstream
  // host<envoy_v3_api_field_config.endpoint.v3.LbEndpoint.metadata>`.
  message Host {
    option (udpa.annotations.versioning).previous_message_type =
        "envoy.type.metadata.v2.MetadataKind.Host";
  }

  oneof kind {
    option (validate.required) = true;

    // Request kind of metadata.
    Request request = 1;

    // Route kind of metadata.
    Route route = 2;

    // Cluster kind of metadata.
    Cluster cluster = 3;

    // Host kind of metadata.
    Host host = 4;
  }
}
