// Copyright 2024 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.redis.cluster.v1beta1;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/longrunning/operations.proto";
import "google/protobuf/any.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/timestamp.proto";

option go_package = "cloud.google.com/go/redis/cluster/apiv1beta1/clusterpb;clusterpb";
option java_multiple_files = true;
option java_outer_classname = "CloudRedisClusterProto";
option java_package = "com.google.cloud.redis.cluster.v1beta1";
option ruby_package = "Google::Cloud::Redis::Cluster::V1beta1";

// Configures and manages Cloud Memorystore for Redis clusters
//
// Google Cloud Memorystore for Redis Cluster
//
// The `redis.googleapis.com` service implements the Google Cloud Memorystore
// for Redis API and defines the following resource model for managing Redis
// clusters:
// * The service works with a collection of cloud projects, named: `/projects/*`
// * Each project has a collection of available locations, named: `/locations/*`
// * Each location has a collection of Redis clusters, named: `/clusters/*`
// * As such, Redis clusters are resources of the form:
//   `/projects/{project_id}/locations/{location_id}/clusters/{instance_id}`
//
// Note that location_id must be a GCP `region`; for example:
// * `projects/redpepper-1290/locations/us-central1/clusters/my-redis`
//
// We use API version selector for Flex APIs
// * The versioning strategy is release-based versioning
// * Our backend CLH only deals with the superset version (called v1main)
// * Existing backend for Redis Gen1 and MRR is not touched.
// * More details in go/redis-flex-api-versioning
service CloudRedisCluster {
  option (google.api.default_host) = "redis.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform";

  // Lists all Redis clusters owned by a project in either the specified
  // location (region) or all locations.
  //
  // The location should have the following format:
  //
  // * `projects/{project_id}/locations/{location_id}`
  //
  // If `location_id` is specified as `-` (wildcard), then all regions
  // available to the project are queried, and the results are aggregated.
  rpc ListClusters(ListClustersRequest) returns (ListClustersResponse) {
    option (google.api.http) = {
      get: "/v1beta1/{parent=projects/*/locations/*}/clusters"
    };
    option (google.api.method_signature) = "parent";
  }

  // Gets the details of a specific Redis cluster.
  rpc GetCluster(GetClusterRequest) returns (Cluster) {
    option (google.api.http) = {
      get: "/v1beta1/{name=projects/*/locations/*/clusters/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Updates the metadata and configuration of a specific Redis cluster.
  //
  // Completed longrunning.Operation will contain the new cluster object
  // in the response field. The returned operation is automatically deleted
  // after a few hours, so there is no need to call DeleteOperation.
  rpc UpdateCluster(UpdateClusterRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      patch: "/v1beta1/{cluster.name=projects/*/locations/*/clusters/*}"
      body: "cluster"
    };
    option (google.api.method_signature) = "cluster,update_mask";
    option (google.longrunning.operation_info) = {
      response_type: "Cluster"
      metadata_type: "google.protobuf.Any"
    };
  }

  // Deletes a specific Redis cluster. Cluster stops serving and data is
  // deleted.
  rpc DeleteCluster(DeleteClusterRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      delete: "/v1beta1/{name=projects/*/locations/*/clusters/*}"
    };
    option (google.api.method_signature) = "name";
    option (google.longrunning.operation_info) = {
      response_type: "google.protobuf.Empty"
      metadata_type: "google.protobuf.Any"
    };
  }

  // Creates a Redis cluster based on the specified properties.
  // The creation is executed asynchronously and callers may check the returned
  // operation to track its progress. Once the operation is completed the Redis
  // cluster will be fully functional. The completed longrunning.Operation will
  // contain the new cluster object in the response field.
  //
  // The returned operation is automatically deleted after a few hours, so there
  // is no need to call DeleteOperation.
  rpc CreateCluster(CreateClusterRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v1beta1/{parent=projects/*/locations/*}/clusters"
      body: "cluster"
    };
    option (google.api.method_signature) = "parent,cluster,cluster_id";
    option (google.longrunning.operation_info) = {
      response_type: "Cluster"
      metadata_type: "google.protobuf.Any"
    };
  }

  // Gets the details of certificate authority information for Redis cluster.
  rpc GetClusterCertificateAuthority(GetClusterCertificateAuthorityRequest)
      returns (CertificateAuthority) {
    option (google.api.http) = {
      get: "/v1beta1/{name=projects/*/locations/*/clusters/*/certificateAuthority}"
    };
    option (google.api.method_signature) = "name";
  }
}

// Available authorization mode of a Redis cluster.
enum AuthorizationMode {
  // Not set.
  AUTH_MODE_UNSPECIFIED = 0;

  // IAM basic authorization mode
  AUTH_MODE_IAM_AUTH = 1;

  // Authorization disabled mode
  AUTH_MODE_DISABLED = 2;
}

// NodeType of a redis cluster node,
enum NodeType {
  NODE_TYPE_UNSPECIFIED = 0;

  // Redis shared core nano node_type.
  REDIS_SHARED_CORE_NANO = 1;

  // Redis highmem medium node_type.
  REDIS_HIGHMEM_MEDIUM = 2;

  // Redis highmem xlarge node_type.
  REDIS_HIGHMEM_XLARGE = 3;

  // Redis standard small node_type.
  REDIS_STANDARD_SMALL = 4;
}

// Available mode of in-transit encryption.
enum TransitEncryptionMode {
  // In-transit encryption not set.
  TRANSIT_ENCRYPTION_MODE_UNSPECIFIED = 0;

  // In-transit encryption disabled.
  TRANSIT_ENCRYPTION_MODE_DISABLED = 1;

  // Use server managed encryption for in-transit encryption.
  TRANSIT_ENCRYPTION_MODE_SERVER_AUTHENTICATION = 2;
}

// Request for [CreateCluster][CloudRedis.CreateCluster].
message CreateClusterRequest {
  // Required. The resource name of the cluster location using the form:
  //     `projects/{project_id}/locations/{location_id}`
  // where `location_id` refers to a GCP region.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "locations.googleapis.com/Location"
    }
  ];

  // Required. The logical name of the Redis cluster in the customer project
  // with the following restrictions:
  //
  // * Must contain only lowercase letters, numbers, and hyphens.
  // * Must start with a letter.
  // * Must be between 1-63 characters.
  // * Must end with a number or a letter.
  // * Must be unique within the customer project / location
  string cluster_id = 2 [(google.api.field_behavior) = REQUIRED];

  // Required. The cluster that is to be created.
  Cluster cluster = 3 [(google.api.field_behavior) = REQUIRED];

  // Idempotent request UUID.
  string request_id = 4;
}

// Request for [ListClusters][CloudRedis.ListClusters].
message ListClustersRequest {
  // Required. The resource name of the cluster location using the form:
  //     `projects/{project_id}/locations/{location_id}`
  // where `location_id` refers to a GCP region.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "locations.googleapis.com/Location"
    }
  ];

  // The maximum number of items to return.
  //
  // If not specified, a default value of 1000 will be used by the service.
  // Regardless of the page_size value, the response may include a partial list
  // and a caller should only rely on response's
  // [`next_page_token`][google.cloud.redis.cluster.v1beta1.ListClustersResponse.next_page_token]
  // to determine if there are more clusters left to be queried.
  int32 page_size = 2;

  // The `next_page_token` value returned from a previous
  // [ListClusters][CloudRedis.ListClusters] request, if any.
  string page_token = 3;
}

// Response for [ListClusters][CloudRedis.ListClusters].
message ListClustersResponse {
  // A list of Redis clusters in the project in the specified location,
  // or across all locations.
  //
  // If the `location_id` in the parent field of the request is "-", all regions
  // available to the project are queried, and the results aggregated.
  // If in such an aggregated query a location is unavailable, a placeholder
  // Redis entry is included in the response with the `name` field set to a
  // value of the form
  // `projects/{project_id}/locations/{location_id}/clusters/`- and the
  // `status` field set to ERROR and `status_message` field set to "location not
  // available for ListClusters".
  repeated Cluster clusters = 1;

  // Token to retrieve the next page of results, or empty if there are no more
  // results in the list.
  string next_page_token = 2;

  // Locations that could not be reached.
  repeated string unreachable = 3;
}

// Request for [UpdateCluster][CloudRedis.UpdateCluster].
message UpdateClusterRequest {
  // Required. Mask of fields to update. At least one path must be supplied in
  // this field. The elements of the repeated paths field may only include these
  // fields from [Cluster][google.cloud.redis.cluster.v1beta1.Cluster]:
  //
  //  *   `size_gb`
  //  *   `replica_count`
  google.protobuf.FieldMask update_mask = 1
      [(google.api.field_behavior) = REQUIRED];

  // Required. Update description.
  // Only fields specified in update_mask are updated.
  Cluster cluster = 2 [(google.api.field_behavior) = REQUIRED];

  // Idempotent request UUID.
  string request_id = 3;
}

// Request for [GetCluster][CloudRedis.GetCluster].
message GetClusterRequest {
  // Required. Redis cluster resource name using the form:
  //     `projects/{project_id}/locations/{location_id}/clusters/{cluster_id}`
  // where `location_id` refers to a GCP region.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "redis.googleapis.com/Cluster" }
  ];
}

// Request for [DeleteCluster][CloudRedis.DeleteCluster].
message DeleteClusterRequest {
  // Required. Redis cluster resource name using the form:
  //     `projects/{project_id}/locations/{location_id}/clusters/{cluster_id}`
  // where `location_id` refers to a GCP region.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "redis.googleapis.com/Cluster" }
  ];

  // Idempotent request UUID.
  string request_id = 2;
}

// Request for
// [GetClusterCertificateAuthorityRequest][CloudRedis.GetClusterCertificateAuthorityRequest].
message GetClusterCertificateAuthorityRequest {
  // Required. Redis cluster certificate authority resource name using the form:
  //     `projects/{project_id}/locations/{location_id}/clusters/{cluster_id}/certificateAuthority`
  // where `location_id` refers to a GCP region.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "redis.googleapis.com/CertificateAuthority"
    }
  ];
}

// A cluster instance.
message Cluster {
  option (google.api.resource) = {
    type: "redis.googleapis.com/Cluster"
    pattern: "projects/{project}/locations/{location}/clusters/{cluster}"
  };

  // Represents additional information about the state of the cluster.
  message StateInfo {
    // Represents information about an updating cluster.
    message UpdateInfo {
      // Target number of shards for redis cluster
      optional int32 target_shard_count = 1;

      // Target number of replica nodes per shard.
      optional int32 target_replica_count = 2;
    }

    oneof info {
      // Describes ongoing update on the cluster when cluster state is UPDATING.
      UpdateInfo update_info = 1;
    }
  }

  // Represents the different states of a Redis cluster.
  enum State {
    // Not set.
    STATE_UNSPECIFIED = 0;

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

    // Redis cluster has been created and is fully usable.
    ACTIVE = 2;

    // Redis cluster configuration is being updated.
    UPDATING = 3;

    // Redis cluster is being deleted.
    DELETING = 4;
  }

  // Required. Unique name of the resource in this scope including project and
  // location using the form:
  //     `projects/{project_id}/locations/{location_id}/clusters/{cluster_id}`
  string name = 1 [(google.api.field_behavior) = REQUIRED];

  // Output only. The timestamp associated with the cluster creation request.
  google.protobuf.Timestamp create_time = 3
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The current state of this cluster.
  // Can be CREATING, READY, UPDATING, DELETING and SUSPENDED
  State state = 4 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. System assigned, unique identifier for the cluster.
  string uid = 5 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. The number of replica nodes per shard.
  optional int32 replica_count = 8 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The authorization mode of the Redis cluster.
  // If not provided, auth feature is disabled for the cluster.
  AuthorizationMode authorization_mode = 11
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. The in-transit encryption for the Redis cluster.
  // If not provided, encryption  is disabled for the cluster.
  TransitEncryptionMode transit_encryption_mode = 12
      [(google.api.field_behavior) = OPTIONAL];

  // Output only. Redis memory size in GB for the entire cluster rounded up to
  // the next integer.
  optional int32 size_gb = 13 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Required. Number of shards for the Redis cluster.
  optional int32 shard_count = 14 [(google.api.field_behavior) = REQUIRED];

  // Required. Each PscConfig configures the consumer network where IPs will
  // be designated to the cluster for client access through Private Service
  // Connect Automation. Currently, only one PscConfig is supported.
  repeated PscConfig psc_configs = 15 [(google.api.field_behavior) = REQUIRED];

  // Output only. Endpoints created on each given network, for Redis clients to
  // connect to the cluster. Currently only one discovery endpoint is supported.
  repeated DiscoveryEndpoint discovery_endpoints = 16
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. PSC connections for discovery of the cluster topology and
  // accessing the cluster.
  repeated PscConnection psc_connections = 17
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Additional information about the current state of the cluster.
  StateInfo state_info = 18 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. The type of a redis node in the cluster. NodeType determines the
  // underlying machine-type of a redis node.
  NodeType node_type = 19 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Persistence config (RDB, AOF) for the cluster.
  ClusterPersistenceConfig persistence_config = 20
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. Key/Value pairs of customer overrides for mutable Redis Configs
  map<string, string> redis_configs = 21
      [(google.api.field_behavior) = OPTIONAL];

  // Output only. Precise value of redis memory size in GB for the entire
  // cluster.
  optional double precise_size_gb = 22
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. This config will be used to determine how the customer wants us
  // to distribute cluster resources within the region.
  ZoneDistributionConfig zone_distribution_config = 23
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. The delete operation will fail when the value is set to true.
  optional bool deletion_protection_enabled = 25
      [(google.api.field_behavior) = OPTIONAL];
}

message PscConfig {
  // Required. The network where the IP address of the discovery endpoint will
  // be reserved, in the form of
  // projects/{network_project}/global/networks/{network_id}.
  string network = 2 [(google.api.field_behavior) = REQUIRED];
}

// Endpoints on each network, for Redis clients to connect to the cluster.
message DiscoveryEndpoint {
  // Output only. Address of the exposed Redis endpoint used by clients to
  // connect to the service. The address could be either IP or hostname.
  string address = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The port number of the exposed Redis endpoint.
  int32 port = 2 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Customer configuration for where the endpoint is created and
  // accessed from.
  PscConfig psc_config = 3 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// Details of consumer resources in a PSC connection.
message PscConnection {
  // Output only. The PSC connection id of the forwarding rule connected to the
  // service attachment.
  string psc_connection_id = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The IP allocated on the consumer network for the PSC
  // forwarding rule.
  string address = 2 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The URI of the consumer side forwarding rule.
  // Example:
  // projects/{projectNumOrId}/regions/us-east1/forwardingRules/{resourceId}.
  string forwarding_rule = 3 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The consumer project_id where the forwarding rule is created
  // from.
  string project_id = 4 [(google.api.field_behavior) = OUTPUT_ONLY];

  // The consumer network where the IP address resides, in the form of
  // projects/{project_id}/global/networks/{network_id}.
  string network = 5;
}

// Pre-defined metadata fields.
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 successfully been cancelled
  // 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];
}

// Redis cluster certificate authority
message CertificateAuthority {
  option (google.api.resource) = {
    type: "redis.googleapis.com/CertificateAuthority"
    pattern: "projects/{project}/locations/{location}/clusters/{cluster}/certificateAuthority"
  };

  message ManagedCertificateAuthority {
    message CertChain {
      // The certificates that form the CA chain, from leaf to root order.
      repeated string certificates = 1;
    }

    // The PEM encoded CA certificate chains for redis managed
    // server authentication
    repeated CertChain ca_certs = 1;
  }

  // server ca information
  oneof server_ca {
    ManagedCertificateAuthority managed_server_ca = 1;
  }

  // Identifier. Unique name of the resource in this scope including project,
  // location and cluster using the form:
  //     `projects/{project}/locations/{location}/clusters/{cluster}/certificateAuthority`
  string name = 2 [(google.api.field_behavior) = IDENTIFIER];
}

// Configuration of the persistence functionality.
message ClusterPersistenceConfig {
  // Configuration of the RDB based persistence.
  message RDBConfig {
    // Available snapshot periods.
    enum SnapshotPeriod {
      // Not set.
      SNAPSHOT_PERIOD_UNSPECIFIED = 0;

      // One hour.
      ONE_HOUR = 1;

      // Six hours.
      SIX_HOURS = 2;

      // Twelve hours.
      TWELVE_HOURS = 3;

      // Twenty four hours.
      TWENTY_FOUR_HOURS = 4;
    }

    // Optional. Period between RDB snapshots.
    SnapshotPeriod rdb_snapshot_period = 1
        [(google.api.field_behavior) = OPTIONAL];

    // Optional. The time that the first snapshot was/will be attempted, and to
    // which future snapshots will be aligned. If not provided, the current time
    // will be used.
    google.protobuf.Timestamp rdb_snapshot_start_time = 2
        [(google.api.field_behavior) = OPTIONAL];
  }

  // Configuration of the AOF based persistence.
  message AOFConfig {
    // Available fsync modes.
    enum AppendFsync {
      // Not set. Default: EVERYSEC
      APPEND_FSYNC_UNSPECIFIED = 0;

      // Never fsync. Normally Linux will flush data every 30 seconds with this
      // configuration, but it's up to the kernel's exact tuning.
      NO = 1;

      // fsync every second. Fast enough, and you may lose 1 second of data if
      // there is a disaster
      EVERYSEC = 2;

      // fsync every time new commands are appended to the AOF. It has the best
      // data loss protection at the cost of performance
      ALWAYS = 3;
    }

    // Optional. fsync configuration.
    AppendFsync append_fsync = 1 [(google.api.field_behavior) = OPTIONAL];
  }

  // Available persistence modes.
  enum PersistenceMode {
    // Not set.
    PERSISTENCE_MODE_UNSPECIFIED = 0;

    // Persistence is disabled, and any snapshot data is deleted.
    DISABLED = 1;

    // RDB based persistence is enabled.
    RDB = 2;

    // AOF based persistence is enabled.
    AOF = 3;
  }

  // Optional. The mode of persistence.
  PersistenceMode mode = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. RDB configuration. This field will be ignored if mode is not RDB.
  RDBConfig rdb_config = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. AOF configuration. This field will be ignored if mode is not AOF.
  AOFConfig aof_config = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Zone distribution config for allocation of cluster resources.
message ZoneDistributionConfig {
  // Defines various modes of zone distribution.
  // Currently supports two modes, can be expanded in future to support more
  // types of distribution modes.
  // design doc: go/same-zone-cluster
  enum ZoneDistributionMode {
    // Not Set. Default: MULTI_ZONE
    ZONE_DISTRIBUTION_MODE_UNSPECIFIED = 0;

    // Distribute all resources across 3 zones picked at random, within the
    // region.
    MULTI_ZONE = 1;

    // Distribute all resources in a single zone. The zone field must be
    // specified, when this mode is selected.
    SINGLE_ZONE = 2;
  }

  // Optional. The mode of zone distribution. Defaults to MULTI_ZONE, when not
  // specified.
  ZoneDistributionMode mode = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. When SINGLE ZONE distribution is selected, zone field would be
  // used to allocate all resources in that zone. This is not applicable to
  // MULTI_ZONE, and would be ignored for MULTI_ZONE clusters.
  string zone = 2 [(google.api.field_behavior) = OPTIONAL];
}
