// 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.gkebackup.v1;

import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/cloud/gkebackup/v1/common.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";
import "google/type/date.proto";
import "google/type/dayofweek.proto";
import "google/type/timeofday.proto";

option csharp_namespace = "Google.Cloud.GkeBackup.V1";
option go_package = "cloud.google.com/go/gkebackup/apiv1/gkebackuppb;gkebackuppb";
option java_multiple_files = true;
option java_outer_classname = "BackupPlanProto";
option java_package = "com.google.cloud.gkebackup.v1";
option php_namespace = "Google\\Cloud\\GkeBackup\\V1";
option ruby_package = "Google::Cloud::GkeBackup::V1";

// Defines the configuration and scheduling for a "line" of Backups.
message BackupPlan {
  option (google.api.resource) = {
    type: "gkebackup.googleapis.com/BackupPlan"
    pattern: "projects/{project}/locations/{location}/backupPlans/{backup_plan}"
  };

  // RetentionPolicy defines a Backup retention policy for a BackupPlan.
  message RetentionPolicy {
    // Optional. Minimum age for Backups created via this BackupPlan (in days).
    // This field MUST be an integer value between 0-90 (inclusive).
    // A Backup created under this BackupPlan will NOT be deletable until it
    // reaches Backup's (create_time + backup_delete_lock_days).
    // Updating this field of a BackupPlan does NOT affect existing Backups
    // under it. Backups created AFTER a successful update will inherit
    // the new value.
    //
    // Default: 0 (no delete blocking)
    int32 backup_delete_lock_days = 1 [(google.api.field_behavior) = OPTIONAL];

    // Optional. The default maximum age of a Backup created via this
    // BackupPlan. This field MUST be an integer value >= 0 and <= 365. If
    // specified, a Backup created under this BackupPlan will be automatically
    // deleted after its age reaches (create_time + backup_retain_days). If not
    // specified, Backups created under this BackupPlan will NOT be subject to
    // automatic deletion. Updating this field does NOT affect existing Backups
    // under it. Backups created AFTER a successful update will automatically
    // pick up the new value. NOTE: backup_retain_days must be >=
    // [backup_delete_lock_days][google.cloud.gkebackup.v1.BackupPlan.RetentionPolicy.backup_delete_lock_days].
    // If
    // [cron_schedule][google.cloud.gkebackup.v1.BackupPlan.Schedule.cron_schedule]
    // is defined, then this must be
    // <= 360 * the creation interval. If
    // [rpo_config][google.cloud.gkebackup.v1.BackupPlan.Schedule.rpo_config] is
    // defined, then this must be
    // <= 360 * [target_rpo_minutes][Schedule.rpo_config.target_rpo_minutes] /
    // (1440minutes/day).
    //
    // Default: 0 (no automatic deletion)
    int32 backup_retain_days = 2 [(google.api.field_behavior) = OPTIONAL];

    // Optional. This flag denotes whether the retention policy of this
    // BackupPlan is locked.  If set to True, no further update is allowed on
    // this policy, including the `locked` field itself.
    //
    // Default: False
    bool locked = 3 [(google.api.field_behavior) = OPTIONAL];
  }

  // Defines scheduling parameters for automatically creating Backups
  // via this BackupPlan.
  message Schedule {
    // Optional. A standard [cron](https://wikipedia.com/wiki/cron) string that
    // defines a repeating schedule for creating Backups via this BackupPlan.
    // This is mutually exclusive with the
    // [rpo_config][google.cloud.gkebackup.v1.BackupPlan.Schedule.rpo_config]
    // field since at most one schedule can be defined for a BackupPlan. If this
    // is defined, then
    // [backup_retain_days][google.cloud.gkebackup.v1.BackupPlan.RetentionPolicy.backup_retain_days]
    // must also be defined.
    //
    // Default (empty): no automatic backup creation will occur.
    string cron_schedule = 1 [(google.api.field_behavior) = OPTIONAL];

    // Optional. This flag denotes whether automatic Backup creation is paused
    // for this BackupPlan.
    //
    // Default: False
    bool paused = 2 [(google.api.field_behavior) = OPTIONAL];

    // Optional. Defines the RPO schedule configuration for this BackupPlan.
    // This is mutually exclusive with the
    // [cron_schedule][google.cloud.gkebackup.v1.BackupPlan.Schedule.cron_schedule]
    // field since at most one schedule can be defined for a BackupPLan. If this
    // is defined, then
    // [backup_retain_days][google.cloud.gkebackup.v1.BackupPlan.RetentionPolicy.backup_retain_days]
    // must also be defined.
    //
    // Default (empty): no automatic backup creation will occur.
    RpoConfig rpo_config = 3 [(google.api.field_behavior) = OPTIONAL];

    // Output only. Start time of next scheduled backup under this BackupPlan by
    // either cron_schedule or rpo config.
    google.protobuf.Timestamp next_scheduled_backup_time = 4
        [(google.api.field_behavior) = OUTPUT_ONLY];
  }

  // BackupConfig defines the configuration of Backups created via this
  // BackupPlan.
  message BackupConfig {
    // This defines the "scope" of the Backup - which namespaced
    // resources in the cluster will be included in a Backup.
    // Exactly one of the fields of backup_scope MUST be specified.
    oneof backup_scope {
      // If True, include all namespaced resources
      bool all_namespaces = 1;

      // If set, include just the resources in the listed namespaces.
      Namespaces selected_namespaces = 2;

      // If set, include just the resources referenced by the listed
      // ProtectedApplications.
      NamespacedNames selected_applications = 3;
    }

    // Optional. This flag specifies whether volume data should be backed up
    // when PVCs are included in the scope of a Backup.
    //
    // Default: False
    bool include_volume_data = 4 [(google.api.field_behavior) = OPTIONAL];

    // Optional. This flag specifies whether Kubernetes Secret resources should
    // be included when they fall into the scope of Backups.
    //
    // Default: False
    bool include_secrets = 5 [(google.api.field_behavior) = OPTIONAL];

    // Optional. This defines a customer managed encryption key that will be
    // used to encrypt the "config" portion (the Kubernetes resources) of
    // Backups created via this plan.
    //
    // Default (empty): Config backup artifacts will not be encrypted.
    EncryptionKey encryption_key = 6 [(google.api.field_behavior) = OPTIONAL];

    // Optional. If false, Backups will fail when Backup for GKE detects
    // Kubernetes configuration that is non-standard or
    // requires additional setup to restore.
    //
    // Default: False
    bool permissive_mode = 7 [(google.api.field_behavior) = OPTIONAL];
  }

  // State
  enum State {
    // Default first value for Enums.
    STATE_UNSPECIFIED = 0;

    // Waiting for cluster state to be RUNNING.
    CLUSTER_PENDING = 1;

    // The BackupPlan is in the process of being created.
    PROVISIONING = 2;

    // The BackupPlan has successfully been created and is ready for Backups.
    READY = 3;

    // BackupPlan creation has failed.
    FAILED = 4;

    // The BackupPlan has been deactivated.
    DEACTIVATED = 5;

    // The BackupPlan is in the process of being deleted.
    DELETING = 6;
  }

  // Output only. The full name of the BackupPlan resource.
  // Format: `projects/*/locations/*/backupPlans/*`
  string name = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Server generated global unique identifier of
  // [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) format.
  string uid = 2 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The timestamp when this BackupPlan resource was created.
  google.protobuf.Timestamp create_time = 3
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The timestamp when this BackupPlan resource was last
  // updated.
  google.protobuf.Timestamp update_time = 4
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. User specified descriptive string for this BackupPlan.
  string description = 5 [(google.api.field_behavior) = OPTIONAL];

  // Required. Immutable. The source cluster from which Backups will be created
  // via this BackupPlan. Valid formats:
  //
  // - `projects/*/locations/*/clusters/*`
  // - `projects/*/zones/*/clusters/*`
  string cluster = 6 [
    (google.api.field_behavior) = IMMUTABLE,
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "container.googleapis.com/Cluster"
    }
  ];

  // Optional. RetentionPolicy governs lifecycle of Backups created under this
  // plan.
  RetentionPolicy retention_policy = 7 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A set of custom labels supplied by user.
  map<string, string> labels = 8 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Defines a schedule for automatic Backup creation via this
  // BackupPlan.
  Schedule backup_schedule = 9 [(google.api.field_behavior) = OPTIONAL];

  // Output only. `etag` is used for optimistic concurrency control as a way to
  // help prevent simultaneous updates of a backup plan from overwriting each
  // other. It is strongly suggested that systems make use of the 'etag' in the
  // read-modify-write cycle to perform BackupPlan updates in order to avoid
  // race conditions: An `etag` is returned in the response to `GetBackupPlan`,
  // and systems are expected to put that etag in the request to
  // `UpdateBackupPlan` or `DeleteBackupPlan` to ensure that their change
  // will be applied to the same version of the resource.
  string etag = 10 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. This flag indicates whether this BackupPlan has been deactivated.
  // Setting this field to True locks the BackupPlan such that no further
  // updates will be allowed (except deletes), including the deactivated field
  // itself. It also prevents any new Backups from being created via this
  // BackupPlan (including scheduled Backups).
  //
  // Default: False
  bool deactivated = 11 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Defines the configuration of Backups created via this BackupPlan.
  BackupConfig backup_config = 12 [(google.api.field_behavior) = OPTIONAL];

  // Output only. The number of Kubernetes Pods backed up in the
  // last successful Backup created via this BackupPlan.
  int32 protected_pod_count = 13 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. State of the BackupPlan. This State field reflects the
  // various stages a BackupPlan can be in
  // during the Create operation. It will be set to "DEACTIVATED"
  // if the BackupPlan is deactivated on an Update
  State state = 14 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Human-readable description of why BackupPlan is in the current
  // `state`. This field is only meant for human readability and should not be
  // used programmatically as this field is not guaranteed to be consistent.
  string state_reason = 15 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. A number that represents the current risk level of this
  // BackupPlan from RPO perspective with 1 being no risk and 5 being highest
  // risk.
  int32 rpo_risk_level = 16 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Human-readable description of why the BackupPlan is in the
  // current rpo_risk_level and action items if any.
  string rpo_risk_reason = 17 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The fully qualified name of the BackupChannel to be used to
  // create a backup. This field is set only if the cluster being backed up is
  // in a different project.
  // `projects/*/locations/*/backupChannels/*`
  string backup_channel = 18 [
    (google.api.field_behavior) = OUTPUT_ONLY,
    (google.api.resource_reference) = {
      type: "gkebackup.googleapis.com/BackupChannel"
    }
  ];

  // Output only. Completion time of the last successful Backup. This is sourced
  // from a successful Backup's complete_time field. This field is added to
  // maintain consistency with BackupPlanBinding to display last successful
  // backup time.
  google.protobuf.Timestamp last_successful_backup_time = 19
      [(google.api.field_behavior) = OUTPUT_ONLY];
}

// Defines RPO scheduling configuration for automatically creating
// Backups via this BackupPlan.
message RpoConfig {
  // Required. Defines the target RPO for the BackupPlan in minutes, which means
  // the target maximum data loss in time that is acceptable for this
  // BackupPlan. This must be at least 60, i.e., 1 hour, and at most 86400,
  // i.e., 60 days.
  int32 target_rpo_minutes = 1 [(google.api.field_behavior) = REQUIRED];

  // Optional. User specified time windows during which backup can NOT happen
  // for this BackupPlan - backups should start and finish outside of any given
  // exclusion window. Note: backup jobs will be scheduled to start and
  // finish outside the duration of the window as much as possible, but
  // running jobs will not get canceled when it runs into the window.
  // All the time and date values in exclusion_windows entry in the API are in
  // UTC.
  // We only allow <=1 recurrence (daily or weekly) exclusion window for a
  // BackupPlan while no restriction on number of single occurrence
  // windows.
  repeated ExclusionWindow exclusion_windows = 2
      [(google.api.field_behavior) = OPTIONAL];
}

// Defines a time window during which no backup should
// happen. All time and date are in UTC.
message ExclusionWindow {
  // Holds repeated DaysOfWeek values as a container.
  message DayOfWeekList {
    // Optional. A list of days of week.
    repeated google.type.DayOfWeek days_of_week = 1
        [(google.api.field_behavior) = OPTIONAL];
  }

  // Required. Specifies the start time of the window using time of the day in
  // UTC.
  google.type.TimeOfDay start_time = 1 [(google.api.field_behavior) = REQUIRED];

  // Required. Specifies duration of the window.
  // Duration must be >= 5 minutes and < (target RPO - 20 minutes).
  // Additional restrictions based on the recurrence type to allow some time for
  // backup to happen:
  // - single_occurrence_date:  no restriction, but UI may warn about this when
  // duration >= target RPO
  // - daily window: duration < 24 hours
  // - weekly window:
  //   - days of week includes all seven days of a week: duration < 24 hours
  //   - all other weekly window: duration < 168 hours (i.e., 24 * 7 hours)
  google.protobuf.Duration duration = 2
      [(google.api.field_behavior) = REQUIRED];

  // Required. Specifies the day(s) on which the exclusion window takes
  // effect. Exactly one of the fields MUST be specified.
  oneof recurrence {
    // No recurrence. The exclusion window occurs only once and on this
    // date in UTC.
    google.type.Date single_occurrence_date = 3;

    // The exclusion window occurs every day if set to "True".
    // Specifying this field to "False" is an error.
    bool daily = 4;

    // The exclusion window occurs on these days of each week in UTC.
    DayOfWeekList days_of_week = 5;
  }
}
