// Copyright 2023 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/timestamp.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 = "RestoreProto";
option java_package = "com.google.cloud.gkebackup.v1";
option php_namespace = "Google\\Cloud\\GkeBackup\\V1";
option ruby_package = "Google::Cloud::GkeBackup::V1";

// Represents both a request to Restore some portion of a Backup into
// a target GKE cluster and a record of the restore operation itself.
// Next id: 18
message Restore {
  option (google.api.resource) = {
    type: "gkebackup.googleapis.com/Restore"
    pattern: "projects/{project}/locations/{location}/restorePlans/{restore_plan}/restores/{restore}"
  };

  // Possible values for state of the Restore.
  enum State {
    // The Restore resource is in the process of being created.
    STATE_UNSPECIFIED = 0;

    // The Restore resource has been created and the associated RestoreJob
    // Kubernetes resource has been injected into target cluster.
    CREATING = 1;

    // The gkebackup agent in the cluster has begun executing the restore
    // operation.
    IN_PROGRESS = 2;

    // The restore operation has completed successfully. Restored workloads may
    // not yet be operational.
    SUCCEEDED = 3;

    // The restore operation has failed.
    FAILED = 4;

    // This Restore resource is in the process of being deleted.
    DELETING = 5;
  }

  // Output only. The full name of the Restore resource.
  // Format: `projects/*/locations/*/restorePlans/*/restores/*`
  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 Restore resource was created.
  google.protobuf.Timestamp create_time = 3
      [(google.api.field_behavior) = OUTPUT_ONLY];

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

  // User specified descriptive string for this Restore.
  string description = 5;

  // Required. Immutable. A reference to the
  // [Backup][google.cloud.gkebackup.v1.Backup] used as the source from which
  // this Restore will restore. Note that this Backup must be a sub-resource of
  // the RestorePlan's
  // [backup_plan][google.cloud.gkebackup.v1.RestorePlan.backup_plan]. Format:
  // `projects/*/locations/*/backupPlans/*/backups/*`.
  string backup = 6 [
    (google.api.field_behavior) = IMMUTABLE,
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "gkebackup.googleapis.com/Backup"
    }
  ];

  // Output only. The target cluster into which this Restore will restore data.
  // Valid formats:
  //
  //   - `projects/*/locations/*/clusters/*`
  //   - `projects/*/zones/*/clusters/*`
  //
  // Inherited from parent RestorePlan's
  // [cluster][google.cloud.gkebackup.v1.RestorePlan.cluster] value.
  string cluster = 7 [
    (google.api.field_behavior) = OUTPUT_ONLY,
    (google.api.resource_reference) = {
      type: "container.googleapis.com/Cluster"
    }
  ];

  // Output only. Configuration of the Restore.  Inherited from parent
  // RestorePlan's
  // [restore_config][google.cloud.gkebackup.v1.RestorePlan.restore_config].
  RestoreConfig restore_config = 8 [(google.api.field_behavior) = OUTPUT_ONLY];

  // A set of custom labels supplied by user.
  map<string, string> labels = 9;

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

  // Output only. Human-readable description of why the Restore is in its
  // current state.
  string state_reason = 11 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Timestamp of when the restore operation completed.
  google.protobuf.Timestamp complete_time = 12
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Number of resources restored during the restore execution.
  int32 resources_restored_count = 13
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Number of resources excluded during the restore execution.
  int32 resources_excluded_count = 14
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Number of resources that failed to be restored during the
  // restore execution.
  int32 resources_failed_count = 15 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Number of volumes restored during the restore execution.
  int32 volumes_restored_count = 16 [(google.api.field_behavior) = OUTPUT_ONLY];

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

// Configuration of a restore.
// Next id: 12
message RestoreConfig {
  // Defines how volume data should be restored.
  enum VolumeDataRestorePolicy {
    // Unspecified (illegal).
    VOLUME_DATA_RESTORE_POLICY_UNSPECIFIED = 0;

    // For each PVC to be restored, create a new underlying volume and PV
    // from the corresponding VolumeBackup contained within the Backup.
    RESTORE_VOLUME_DATA_FROM_BACKUP = 1;

    // For each PVC to be restored, attempt to reuse the original PV contained
    // in the Backup (with its original underlying volume). This option
    // is likely only usable when restoring a workload to its original cluster.
    REUSE_VOLUME_HANDLE_FROM_BACKUP = 2;

    // For each PVC to be restored, create PVC without any particular
    // action to restore data. In this case, the normal Kubernetes provisioning
    // logic would kick in, and this would likely result in either dynamically
    // provisioning blank PVs or binding to statically provisioned PVs.
    NO_VOLUME_DATA_RESTORATION = 3;
  }

  // Defines the behavior for handling the situation where cluster-scoped
  // resources being restored already exist in the target cluster.
  enum ClusterResourceConflictPolicy {
    // Unspecified. Only allowed if no cluster-scoped resources will be
    // restored.
    CLUSTER_RESOURCE_CONFLICT_POLICY_UNSPECIFIED = 0;

    // Do not attempt to restore the conflicting resource.
    USE_EXISTING_VERSION = 1;

    // Delete the existing version before re-creating it from the Backup.
    // This is a dangerous option which could cause unintentional
    // data loss if used inappropriately. For example, deleting a CRD will
    // cause Kubernetes to delete all CRs of that type.
    USE_BACKUP_VERSION = 2;
  }

  // Defines the behavior for handling the situation where sets of namespaced
  // resources being restored already exist in the target cluster.
  enum NamespacedResourceRestoreMode {
    // Unspecified (invalid).
    NAMESPACED_RESOURCE_RESTORE_MODE_UNSPECIFIED = 0;

    // When conflicting top-level resources (either Namespaces or
    // ProtectedApplications, depending upon the scope) are encountered, this
    // will first trigger a delete of the conflicting resource AND ALL OF ITS
    // REFERENCED RESOURCES (e.g., all resources in the Namespace or all
    // resources referenced by the ProtectedApplication) before restoring the
    // resources from the Backup. This mode should only be used when you are
    // intending to revert some portion of a cluster to an earlier state.
    DELETE_AND_RESTORE = 1;

    // If conflicting top-level resources (either Namespaces or
    // ProtectedApplications, depending upon the scope) are encountered at the
    // beginning of a restore process, the Restore will fail.  If a conflict
    // occurs during the restore process itself (e.g., because an out of band
    // process creates conflicting resources), a conflict will be reported.
    FAIL_ON_CONFLICT = 2;
  }

  // This is a direct map to the Kubernetes GroupKind type
  // [GroupKind](https://godoc.org/k8s.io/apimachinery/pkg/runtime/schema#GroupKind)
  // and is used for identifying specific "types" of resources to restore.
  message GroupKind {
    // API group string of a Kubernetes resource, e.g.
    // "apiextensions.k8s.io", "storage.k8s.io", etc.
    // Note: use empty string for core API group
    string resource_group = 1;

    // Kind of a Kubernetes resource, e.g.
    // "CustomResourceDefinition", "StorageClass", etc.
    string resource_kind = 2;
  }

  // Defines the scope of cluster-scoped resources to restore.
  //
  // Some group kinds are not reasonable choices for a restore, and will cause
  // an error if selected here. Any scope selection that would restore
  // "all valid" resources automatically excludes these group kinds.
  // - gkebackup.gke.io/BackupJob
  // - gkebackup.gke.io/RestoreJob
  // - metrics.k8s.io/NodeMetrics
  // - migration.k8s.io/StorageState
  // - migration.k8s.io/StorageVersionMigration
  // - Node
  // - snapshot.storage.k8s.io/VolumeSnapshotContent
  // - storage.k8s.io/CSINode
  //
  // Some group kinds are driven by restore configuration elsewhere,
  // and will cause an error if selected here.
  // - Namespace
  // - PersistentVolume
  message ClusterResourceRestoreScope {
    // A list of cluster-scoped resource group kinds to restore from the
    // backup. If specified, only the selected resources will be restored.
    // Mutually exclusive to any other field in the message.
    repeated GroupKind selected_group_kinds = 1;

    // A list of cluster-scoped resource group kinds to NOT restore from the
    // backup. If specified, all valid cluster-scoped resources will be
    // restored except for those specified in the list.
    // Mutually exclusive to any other field in the message.
    repeated GroupKind excluded_group_kinds = 2;

    // If True, all valid cluster-scoped resources will be restored.
    // Mutually exclusive to any other field in the message.
    bool all_group_kinds = 3;

    // If True, no cluster-scoped resources will be restored.
    // This has the same restore scope as if the message is not defined.
    // Mutually exclusive to any other field in the message.
    bool no_group_kinds = 4;
  }

  // A transformation rule to be applied against Kubernetes resources as they
  // are selected for restoration from a Backup. A rule contains both filtering
  // logic (which resources are subject to substitution) and substitution logic.
  message SubstitutionRule {
    // (Filtering parameter) Any resource subject to substitution must be
    // contained within one of the listed Kubernetes Namespace in the Backup.
    // If this field is not provided, no namespace filtering will be performed
    // (all resources in all Namespaces, including all cluster-scoped resources,
    // will be candidates for substitution).
    // To mix cluster-scoped and namespaced resources in the same rule, use an
    // empty string ("") as one of the target namespaces.
    repeated string target_namespaces = 1;

    // (Filtering parameter) Any resource subject to substitution must belong to
    // one of the listed "types".
    // If this field is not provided, no type filtering will be performed (all
    // resources of all types matching previous filtering parameters will be
    // candidates for substitution).
    repeated GroupKind target_group_kinds = 2;

    // Required. This is a [JSONPath]
    // (https://kubernetes.io/docs/reference/kubectl/jsonpath/)
    // expression that matches specific fields of candidate
    // resources and it operates as both a filtering parameter (resources that
    // are not matched with this expression will not be candidates for
    // substitution) as well as a field identifier (identifies exactly which
    // fields out of the candidate resources will be modified).
    string target_json_path = 3 [(google.api.field_behavior) = REQUIRED];

    // (Filtering parameter) This is a [regular expression]
    // (https://en.wikipedia.org/wiki/Regular_expression)
    // that is compared against the fields matched by the target_json_path
    // expression (and must also have passed the previous filters).
    // Substitution will not be performed against fields whose
    // value does not match this expression. If this field is NOT specified,
    // then ALL fields matched by the target_json_path expression will undergo
    // substitution. Note that an empty (e.g., "", rather than unspecified)
    // value for this field will only match empty fields.
    string original_value_pattern = 4;

    // This is the new value to set for any fields that pass the filtering and
    // selection criteria. To remove a value from a Kubernetes resource, either
    // leave this field unspecified, or set it to the empty string ("").
    string new_value = 5;
  }

  // TransformationRuleAction defines a TransformationRule action based on the
  // JSON Patch RFC (https://www.rfc-editor.org/rfc/rfc6902)
  message TransformationRuleAction {
    // Possible values for operations of a transformation rule action.
    enum Op {
      // Unspecified operation
      OP_UNSPECIFIED = 0;

      // The "remove" operation removes the value at the target location.
      REMOVE = 1;

      // The "move" operation removes the value at a specified location and
      // adds it to the target location.
      MOVE = 2;

      // The "copy" operation copies the value at a specified location to the
      // target location.
      COPY = 3;

      // The "add" operation performs one of the following functions,
      // depending upon what the target location references:
      // 1. If the target location specifies an array index, a new value is
      // inserted into the array at the specified index.
      // 2. If the target location specifies an object member that does not
      // already exist, a new member is added to the object.
      // 3. If the target location specifies an object member that does exist,
      // that member's value is replaced.
      ADD = 4;

      // The "test" operation tests that a value at the target location is
      // equal to a specified value.
      TEST = 5;

      // The "replace" operation replaces the value at the target location
      // with a new value.  The operation object MUST contain a "value" member
      // whose content specifies the replacement value.
      REPLACE = 6;
    }

    // Required. op specifies the operation to perform.
    Op op = 1 [(google.api.field_behavior) = REQUIRED];

    // A string containing a JSON Pointer value that references the location in
    // the target document to move the value from.
    string from_path = 2;

    // A string containing a JSON-Pointer value that references a location
    // within the target document where the operation is performed.
    string path = 3;

    // A string that specifies the desired value in string format to
    // use for transformation.
    string value = 4;
  }

  // ResourceFilter specifies matching criteria to limit the scope of a
  // change to a specific set of kubernetes resources that are selected for
  // restoration from a backup.
  message ResourceFilter {
    // (Filtering parameter) Any resource subject to transformation must be
    // contained within one of the listed Kubernetes Namespace in the Backup.
    // If this field is not provided, no namespace filtering will be performed
    // (all resources in all Namespaces, including all cluster-scoped resources,
    // will be candidates for transformation).
    // To mix cluster-scoped and namespaced resources in the same rule, use an
    // empty string ("") as one of the target namespaces.
    repeated string namespaces = 1;

    // (Filtering parameter) Any resource subject to transformation must belong
    // to one of the listed "types". If this field is not provided, no type
    // filtering will be performed (all resources of all types matching previous
    // filtering parameters will be candidates for transformation).
    repeated GroupKind group_kinds = 2;

    // This is a [JSONPath]
    // (https://github.com/json-path/JsonPath/blob/master/README.md)
    // expression that matches specific fields of candidate
    // resources and it operates as a filtering parameter (resources that
    // are not matched with this expression will not be candidates for
    // transformation).
    string json_path = 3;
  }

  // A transformation rule to be applied against Kubernetes resources as they
  // are selected for restoration from a Backup. A rule contains both filtering
  // logic (which resources are subject to transform) and transformation logic.
  message TransformationRule {
    // Required. A list of transformation rule actions to take against candidate
    // resources. Actions are executed in order defined - this order matters, as
    // they could potentially interfere with each other and the first operation
    // could affect the outcome of the second operation.
    repeated TransformationRuleAction field_actions = 1
        [(google.api.field_behavior) = REQUIRED];

    // This field is used to specify a set of fields that should be used to
    // determine which resources in backup should be acted upon by the supplied
    // transformation rule actions, and this will ensure that only specific
    // resources are affected by transformation rule actions.
    ResourceFilter resource_filter = 2;

    // The description is a user specified string description of the
    // transformation rule.
    string description = 3;
  }

  // Specifies the mechanism to be used to restore volume data.
  // Default: VOLUME_DATA_RESTORE_POLICY_UNSPECIFIED (will be treated as
  // NO_VOLUME_DATA_RESTORATION).
  VolumeDataRestorePolicy volume_data_restore_policy = 1;

  // Defines the behavior for handling the situation where cluster-scoped
  // resources being restored already exist in the target cluster. This MUST be
  // set to a value other than CLUSTER_RESOURCE_CONFLICT_POLICY_UNSPECIFIED if
  // [cluster_resource_restore_scope][google.cloud.gkebackup.v1.RestoreConfig.cluster_resource_restore_scope]
  // is not empty.
  ClusterResourceConflictPolicy cluster_resource_conflict_policy = 2;

  // Defines the behavior for handling the situation where sets of namespaced
  // resources being restored already exist in the target cluster. This MUST be
  // set to a value other than NAMESPACED_RESOURCE_RESTORE_MODE_UNSPECIFIED.
  NamespacedResourceRestoreMode namespaced_resource_restore_mode = 3;

  // Identifies the cluster-scoped resources to restore from the Backup.
  // Not specifying it means NO cluster resource will be restored.
  ClusterResourceRestoreScope cluster_resource_restore_scope = 4;

  // Specifies the namespaced resources to restore from the Backup.
  // Only one of the entries may be specified. If not specified, NO namespaced
  // resources will be restored.
  //
  // Note: Resources will never be restored into *managed* namespaces such as
  // `kube-system`, `kube-public`, or `kube-node-lease`. These namespaces
  // are silently skipped when
  // [all_namespaces][google.cloud.gkebackup.v1.RestoreConfig.all_namespaces] is
  // selected. Listing them explicitly will result in an error.
  oneof namespaced_resource_restore_scope {
    // Restore all namespaced resources in the Backup if set to "True".
    // Specifying this field to "False" is an error.
    bool all_namespaces = 5;

    // A list of selected Namespaces to restore from the Backup. The listed
    // Namespaces and all resources contained in them will be restored.
    Namespaces selected_namespaces = 6;

    // A list of selected ProtectedApplications to restore. The listed
    // ProtectedApplications and all the resources to which they refer will be
    // restored.
    NamespacedNames selected_applications = 7;

    // Do not restore any namespaced resources if set to "True".
    // Specifying this field to "False" is not allowed.
    bool no_namespaces = 9;

    // A list of selected namespaces excluded from restoration. All
    // namespaces except those in this list will be restored.
    Namespaces excluded_namespaces = 10;
  }

  // A list of transformation rules to be applied against Kubernetes resources
  // as they are selected for restoration from a Backup. Rules are executed in
  // order defined - this order matters, as changes made by a rule may impact
  // the filtering logic of subsequent rules. An empty list means no
  // substitution will occur.
  repeated SubstitutionRule substitution_rules = 8;

  // A list of transformation rules to be applied against Kubernetes resources
  // as they are selected for restoration from a Backup. Rules are executed in
  // order defined - this order matters, as changes made by a rule may impact
  // the filtering logic of subsequent rules. An empty list means no
  // transformation will occur.
  repeated TransformationRule transformation_rules = 11;
}
