// Copyright 2025 Google LLC
//
// 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 google.cloud.managedkafka.v1;

import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";

option csharp_namespace = "Google.Cloud.ManagedKafka.V1";
option go_package = "cloud.google.com/go/managedkafka/apiv1/managedkafkapb;managedkafkapb";
option java_multiple_files = true;
option java_outer_classname = "ResourcesProto";
option java_package = "com.google.cloud.managedkafka.v1";
option php_namespace = "Google\\Cloud\\ManagedKafka\\V1";
option ruby_package = "Google::Cloud::ManagedKafka::V1";
option (google.api.resource_definition) = {
  type: "cloudkms.googleapis.com/CryptoKey"
  pattern: "projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}"
};
option (google.api.resource_definition) = {
  type: "secretmanager.googleapis.com/SecretVersion"
  pattern: "projects/{project}/secrets/{secret}/versions/{secret_version}"
};
option (google.api.resource_definition) = {
  type: "privateca.googleapis.com/CaPool"
  pattern: "projects/{project}/locations/{location}/caPools/{ca_pool}"
};

// An Apache Kafka cluster deployed in a location.
message Cluster {
  option (google.api.resource) = {
    type: "managedkafka.googleapis.com/Cluster"
    pattern: "projects/{project}/locations/{location}/clusters/{cluster}"
    plural: "clusters"
    singular: "cluster"
  };

  // The state of the cluster.
  enum State {
    // A state was not specified.
    STATE_UNSPECIFIED = 0;

    // The cluster is being created.
    CREATING = 1;

    // The cluster is active.
    ACTIVE = 2;

    // The cluster is being deleted.
    DELETING = 3;
  }

  // Platform specific configuration properties for a Kafka cluster.
  oneof platform_config {
    // Required. Configuration properties for a Kafka cluster deployed to Google
    // Cloud Platform.
    GcpConfig gcp_config = 9 [(google.api.field_behavior) = REQUIRED];
  }

  // Identifier. The name of the cluster. Structured like:
  // projects/{project_number}/locations/{location}/clusters/{cluster_id}
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  // Output only. The time when the cluster was created.
  google.protobuf.Timestamp create_time = 2
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The time when the cluster was last updated.
  google.protobuf.Timestamp update_time = 3
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. Labels as key value pairs.
  map<string, string> labels = 4 [(google.api.field_behavior) = OPTIONAL];

  // Required. Capacity configuration for the Kafka cluster.
  CapacityConfig capacity_config = 5 [(google.api.field_behavior) = REQUIRED];

  // Optional. Rebalance configuration for the Kafka cluster.
  RebalanceConfig rebalance_config = 8 [(google.api.field_behavior) = OPTIONAL];

  // Output only. The current state of the cluster.
  State state = 10 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Reserved for future use.
  optional bool satisfies_pzi = 11 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Reserved for future use.
  optional bool satisfies_pzs = 12 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// A capacity configuration of a Kafka cluster.
message CapacityConfig {
  // Required. The number of vCPUs to provision for the cluster. Minimum: 3.
  int64 vcpu_count = 1 [(google.api.field_behavior) = REQUIRED];

  // Required. The memory to provision for the cluster in bytes.
  // The CPU:memory ratio (vCPU:GiB) must be between 1:1 and 1:8.
  // Minimum: 3221225472 (3 GiB).
  int64 memory_bytes = 2 [(google.api.field_behavior) = REQUIRED];
}

// Defines rebalancing behavior of a Kafka cluster.
message RebalanceConfig {
  // The partition rebalance mode for the cluster.
  enum Mode {
    // A mode was not specified. Do not use.
    MODE_UNSPECIFIED = 0;

    // Do not rebalance automatically.
    NO_REBALANCE = 1;

    // Automatically rebalance topic partitions among brokers when the
    // cluster is scaled up.
    AUTO_REBALANCE_ON_SCALE_UP = 2;
  }

  // Optional. The rebalance behavior for the cluster.
  // When not specified, defaults to `NO_REBALANCE`.
  Mode mode = 1 [(google.api.field_behavior) = OPTIONAL];
}

// The configuration of a Virtual Private Cloud (VPC) network that can access
// the Kafka cluster.
message NetworkConfig {
  // Required. Name of the VPC subnet in which to create Private Service Connect
  // (PSC) endpoints for the Kafka brokers and bootstrap address. Structured
  // like: projects/{project}/regions/{region}/subnetworks/{subnet_id}
  //
  // The subnet must be located in the same region as the Kafka cluster. The
  // project may differ. Multiple subnets from the same parent network must not
  // be specified.
  string subnet = 2 [(google.api.field_behavior) = REQUIRED];
}

// The configuration of access to the Kafka cluster.
message AccessConfig {
  // Required. Virtual Private Cloud (VPC) networks that must be granted direct
  // access to the Kafka cluster. Minimum of 1 network is required. Maximum 10
  // networks can be specified.
  repeated NetworkConfig network_configs = 1
      [(google.api.field_behavior) = REQUIRED];
}

// Configuration properties for a Kafka cluster deployed to Google Cloud
// Platform.
message GcpConfig {
  // Required. Access configuration for the Kafka cluster.
  AccessConfig access_config = 3 [(google.api.field_behavior) = REQUIRED];

  // Optional. Immutable. The Cloud KMS Key name to use for encryption. The key
  // must be located in the same region as the cluster and cannot be changed.
  // Structured like:
  // projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}.
  string kms_key = 2 [
    (google.api.field_behavior) = OPTIONAL,
    (google.api.field_behavior) = IMMUTABLE,
    (google.api.resource_reference) = {
      type: "cloudkms.googleapis.com/CryptoKey"
    }
  ];
}

// A Kafka topic in a given cluster.
message Topic {
  option (google.api.resource) = {
    type: "managedkafka.googleapis.com/Topic"
    pattern: "projects/{project}/locations/{location}/clusters/{cluster}/topics/{topic}"
    plural: "topics"
    singular: "topic"
  };

  // Identifier. The name of the topic. The `topic` segment is used when
  // connecting directly to the cluster. Structured like:
  // projects/{project}/locations/{location}/clusters/{cluster}/topics/{topic}
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  // Required. The number of partitions this topic has. The partition count can
  // only be increased, not decreased. Please note that if partitions are
  // increased for a topic that has a key, the partitioning logic or the
  // ordering of the messages will be affected.
  int32 partition_count = 2 [(google.api.field_behavior) = REQUIRED];

  // Required. Immutable. The number of replicas of each partition. A
  // replication factor of 3 is recommended for high availability.
  int32 replication_factor = 3 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.field_behavior) = IMMUTABLE
  ];

  // Optional. Configurations for the topic that are overridden from the cluster
  // defaults. The key of the map is a Kafka topic property name, for example:
  // `cleanup.policy`, `compression.type`.
  map<string, string> configs = 4 [(google.api.field_behavior) = OPTIONAL];
}

// Metadata for a consumer group corresponding to a specific topic.
message ConsumerTopicMetadata {
  // Optional. Metadata for this consumer group and topic for all partition
  // indexes it has metadata for.
  map<int32, ConsumerPartitionMetadata> partitions = 1
      [(google.api.field_behavior) = OPTIONAL];
}

// Metadata for a consumer group corresponding to a specific partition.
message ConsumerPartitionMetadata {
  // Required. The current offset for this partition, or 0 if no offset has been
  // committed.
  int64 offset = 1 [(google.api.field_behavior) = REQUIRED];

  // Optional. The associated metadata for this partition, or empty if it does
  // not exist.
  string metadata = 2 [(google.api.field_behavior) = OPTIONAL];
}

// A Kafka consumer group in a given cluster.
message ConsumerGroup {
  option (google.api.resource) = {
    type: "managedkafka.googleapis.com/ConsumerGroup"
    pattern: "projects/{project}/locations/{location}/clusters/{cluster}/consumerGroups/{consumer_group}"
    plural: "consumerGroups"
    singular: "consumerGroup"
  };

  // Identifier. The name of the consumer group. The `consumer_group` segment is
  // used when connecting directly to the cluster. Structured like:
  // projects/{project}/locations/{location}/clusters/{cluster}/consumerGroups/{consumer_group}
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  // Optional. Metadata for this consumer group for all topics it has metadata
  // for. The key of the map is a topic name, structured like:
  // projects/{project}/locations/{location}/clusters/{cluster}/topics/{topic}
  map<string, ConsumerTopicMetadata> topics = 2
      [(google.api.field_behavior) = OPTIONAL];
}

// Represents the metadata of the long-running operation.
message OperationMetadata {
  // Output only. The time the operation was created.
  google.protobuf.Timestamp create_time = 1
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The time the operation finished running.
  google.protobuf.Timestamp end_time = 2
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Server-defined resource path for the target of the operation.
  string target = 3 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Name of the verb executed by the operation.
  string verb = 4 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Human-readable status of the operation, if any.
  string status_message = 5 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Identifies whether the user has requested cancellation
  // of the operation. Operations that have been cancelled successfully
  // have [Operation.error][] value with a
  // [google.rpc.Status.code][google.rpc.Status.code] of 1, corresponding to
  // `Code.CANCELLED`.
  bool requested_cancellation = 6 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. API version used to start the operation.
  string api_version = 7 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// An Apache Kafka Connect cluster deployed in a location.
message ConnectCluster {
  option (google.api.resource) = {
    type: "managedkafka.googleapis.com/ConnectCluster"
    pattern: "projects/{project}/locations/{location}/connectClusters/{connect_cluster}"
    plural: "connectClusters"
    singular: "connectCluster"
  };

  // The state of the cluster.
  enum State {
    // A state was not specified.
    STATE_UNSPECIFIED = 0;

    // The cluster is being created.
    CREATING = 1;

    // The cluster is active.
    ACTIVE = 2;

    // The cluster is being deleted.
    DELETING = 3;
  }

  // Platform specific configuration properties for a Kafka Connect cluster.
  oneof platform_config {
    // Required. Configuration properties for a Kafka Connect cluster deployed
    // to Google Cloud Platform.
    ConnectGcpConfig gcp_config = 7 [(google.api.field_behavior) = REQUIRED];
  }

  // Identifier. The name of the Kafka Connect cluster. Structured like:
  // projects/{project_number}/locations/{location}/connectClusters/{connect_cluster_id}
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  // Required. Immutable. The name of the Kafka cluster this Kafka Connect
  // cluster is attached to. Structured like:
  // projects/{project}/locations/{location}/clusters/{cluster}
  string kafka_cluster = 2 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.field_behavior) = IMMUTABLE
  ];

  // Output only. The time when the cluster was created.
  google.protobuf.Timestamp create_time = 3
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The time when the cluster was last updated.
  google.protobuf.Timestamp update_time = 4
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. Labels as key value pairs.
  map<string, string> labels = 5 [(google.api.field_behavior) = OPTIONAL];

  // Required. Capacity configuration for the Kafka Connect cluster.
  CapacityConfig capacity_config = 6 [(google.api.field_behavior) = REQUIRED];

  // Output only. The current state of the cluster.
  State state = 8 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. Configurations for the worker that are overridden from the
  // defaults. The key of the map is a Kafka Connect worker property name, for
  // example: `exactly.once.source.support`.
  map<string, string> config = 9 [(google.api.field_behavior) = OPTIONAL];
}

// The configuration of a Virtual Private Cloud (VPC) network that can access
// the Kafka Connect cluster.
message ConnectNetworkConfig {
  // Required. VPC subnet to make available to the Kafka Connect cluster.
  // Structured like:
  // projects/{project}/regions/{region}/subnetworks/{subnet_id}
  //
  // It is used to create a Private Service Connect (PSC) interface for the
  // Kafka Connect workers. It must be located in the same region as the
  // Kafka Connect cluster.
  //
  // The CIDR range of the subnet must be within the IPv4 address ranges for
  // private networks, as specified in RFC 1918. The primary subnet CIDR range
  // must have a minimum size of /22 (1024 addresses).
  string primary_subnet = 3 [(google.api.field_behavior) = REQUIRED];

  // Optional. Additional subnets may be specified. They may be in another
  // region, but must be in the same VPC network. The Connect workers can
  // communicate with network endpoints in either the primary or additional
  // subnets.
  repeated string additional_subnets = 4
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. Additional DNS domain names from the subnet's network to be made
  // visible to the Connect Cluster. When using MirrorMaker2, it's necessary to
  // add the bootstrap address's dns domain name of the target cluster to make
  // it visible to the connector. For example:
  // my-kafka-cluster.us-central1.managedkafka.my-project.cloud.goog
  repeated string dns_domain_names = 2 [(google.api.field_behavior) = OPTIONAL];
}

// The configuration of access to the Kafka Connect cluster.
message ConnectAccessConfig {
  // Required.
  // Virtual Private Cloud (VPC) networks that must be granted direct access to
  // the Kafka Connect cluster. Minimum of 1 network is required. Maximum 10
  // networks can be specified.
  repeated ConnectNetworkConfig network_configs = 1
      [(google.api.field_behavior) = REQUIRED];
}

// Configuration properties for a Kafka Connect cluster deployed to Google Cloud
// Platform.
message ConnectGcpConfig {
  // Required. Access configuration for the Kafka Connect cluster.
  ConnectAccessConfig access_config = 1
      [(google.api.field_behavior) = REQUIRED];

  // Optional. Secrets to load into workers. Exact SecretVersions from Secret
  // Manager must be provided -- aliases are not supported. Up to 32 secrets may
  // be loaded into one cluster. Format:
  // projects/<project-id>/secrets/<secret-name>/versions/<version-id>
  repeated string secret_paths = 2 [
    (google.api.field_behavior) = OPTIONAL,
    (google.api.resource_reference) = {
      type: "secretmanager.googleapis.com/SecretVersion"
    }
  ];
}

// A Kafka Connect connector in a given ConnectCluster.
message Connector {
  option (google.api.resource) = {
    type: "managedkafka.googleapis.com/Connector"
    pattern: "projects/{project}/locations/{location}/connectClusters/{connect_cluster}/connectors/{connector}"
    plural: "connectors"
    singular: "connector"
  };

  // The state of the connector.
  enum State {
    // A state was not specified.
    STATE_UNSPECIFIED = 0;

    // The connector is not assigned to any tasks, usually transient.
    UNASSIGNED = 1;

    // The connector is running.
    RUNNING = 2;

    // The connector has been paused.
    PAUSED = 3;

    // The connector has failed. See logs for why.
    FAILED = 4;

    // The connector is restarting.
    RESTARTING = 5;

    // The connector has been stopped.
    STOPPED = 6;
  }

  // A policy that specifies how to restart the failed connectors/tasks in a
  // Cluster resource. If not set, the failed connectors/tasks won't be
  // restarted.
  oneof restart_policy {
    // Optional. Restarts the individual tasks of a Connector.
    TaskRetryPolicy task_restart_policy = 4
        [(google.api.field_behavior) = OPTIONAL];
  }

  // Identifier. The name of the connector.
  // Structured like:
  // projects/{project}/locations/{location}/connectClusters/{connect_cluster}/connectors/{connector}
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  // Optional. Connector config as keys/values.
  // The keys of the map are connector property names, for example:
  // `connector.class`, `tasks.max`, `key.converter`.
  map<string, string> configs = 2 [(google.api.field_behavior) = OPTIONAL];

  // Output only. The current state of the connector.
  State state = 3 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// Task Retry Policy is implemented on a best-effort
// basis.
// Retry delay will be exponential based on provided minimum and maximum
// backoffs. https://en.wikipedia.org/wiki/Exponential_backoff.
// Note that the delay between consecutive task restarts may not always
// precisely match the configured settings. This can happen when the
// ConnectCluster is in rebalancing state or if the ConnectCluster is
// unresponsive etc. The default values for minimum and maximum backoffs are
// 60 seconds and 30 minutes respectively.
message TaskRetryPolicy {
  // Optional. The minimum amount of time to wait before retrying a failed task.
  // This sets a lower bound for the backoff delay.
  google.protobuf.Duration minimum_backoff = 1
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. The maximum amount of time to wait before retrying a failed task.
  // This sets an upper bound for the backoff delay.
  google.protobuf.Duration maximum_backoff = 2
      [(google.api.field_behavior) = OPTIONAL];
}
