corso/src/pkg/control/restore.go
2023-10-18 15:26:52 +05:30

162 lines
4.3 KiB
Go

package control
import (
"context"
"encoding/json"
"fmt"
"strings"
"github.com/alcionai/clues"
"github.com/alcionai/corso/src/internal/common/dttm"
"github.com/alcionai/corso/src/pkg/logger"
"github.com/alcionai/corso/src/pkg/path"
)
const (
DefaultRestoreLocation = "Corso_Restore_"
)
// CollisionPolicy describes how the datalayer behaves in case of a collision.
type CollisionPolicy string
const (
Unknown CollisionPolicy = ""
Skip CollisionPolicy = "skip"
Copy CollisionPolicy = "copy"
Replace CollisionPolicy = "replace"
)
func IsValidCollisionPolicy(cp CollisionPolicy) bool {
switch cp {
case Skip, Copy, Replace:
return true
}
return false
}
const RootLocation = "/"
type RestoreConfigSubService struct {
ID string
Type path.ServiceType
}
// RestoreConfig contains
type RestoreConfig struct {
// Defines the per-item collision handling policy.
// Defaults to Skip.
OnCollision CollisionPolicy `json:"onCollision"`
// ProtectedResource specifies which resource the data will be restored to.
// If empty, restores to the same resource that was backed up.
// Defaults to empty.
ProtectedResource string `json:"protectedResource"`
// SubService specifies the sub-service which we are restoring in
// case of services that are constructed out of multiple services
// like Groups.
SubService RestoreConfigSubService
// Location specifies the container into which the data will be restored.
// Only accepts container names, does not accept IDs.
// If empty or "/", data will get restored in place, beginning at the root.
// Defaults to "Corso_Restore_<current_dttm>"
Location string `json:"location"`
// Drive specifies the name of the drive into which the data will be
// restored. If empty, data is restored to the same drive that was backed
// up.
// Defaults to empty.
Drive string `json:"drive"`
// IncludePermissions toggles whether the restore will include the original
// folder- and item-level permissions.
IncludePermissions bool `json:"includePermissions"`
}
func DefaultRestoreConfig(timeFormat dttm.TimeFormat) RestoreConfig {
return RestoreConfig{
OnCollision: Skip,
Location: DefaultRestoreLocation + dttm.FormatNow(timeFormat),
}
}
func DefaultRestoreContainerName(timeFormat dttm.TimeFormat) string {
return DefaultRestoreLocation + dttm.FormatNow(timeFormat)
}
// EnsureRestoreConfigDefaults sets all non-supported values in the config
// struct to the default value.
func EnsureRestoreConfigDefaults(
ctx context.Context,
rc RestoreConfig,
) RestoreConfig {
if !IsValidCollisionPolicy(rc.OnCollision) {
logger.Ctx(ctx).
With(
"bad_collision_policy", rc.OnCollision,
"default_collision_policy", Skip).
Info("setting collision policy to default")
rc.OnCollision = Skip
}
rc.Location = strings.TrimPrefix(strings.TrimSpace(rc.Location), "/")
return rc
}
// ---------------------------------------------------------------------------
// pii control
// ---------------------------------------------------------------------------
var (
// interface compliance required for handling PII
_ clues.Concealer = &RestoreConfig{}
_ fmt.Stringer = &RestoreConfig{}
)
func (rc RestoreConfig) marshal() string {
bs, err := json.Marshal(rc)
if err != nil {
return "err marshalling"
}
return string(bs)
}
func (rc RestoreConfig) concealed() RestoreConfig {
return RestoreConfig{
OnCollision: rc.OnCollision,
ProtectedResource: clues.Conceal(rc.ProtectedResource),
Location: path.LoggableDir(rc.Location),
Drive: clues.Conceal(rc.Drive),
IncludePermissions: rc.IncludePermissions,
}
}
// Conceal produces a concealed representation of the config, suitable for
// logging, storing in errors, and other output.
func (rc RestoreConfig) Conceal() string {
return rc.concealed().marshal()
}
// Format produces a concealed representation of the config, even when
// used within a PrintF, suitable for logging, storing in errors,
// and other output.
func (rc RestoreConfig) Format(fs fmt.State, _ rune) {
fmt.Fprint(fs, rc.concealed().marshal())
}
// String returns a plain text version of the restoreConfig.
func (rc RestoreConfig) String() string {
return rc.PlainString()
}
// PlainString returns an unescaped, unmodified string of the restore configuration.
func (rc RestoreConfig) PlainString() string {
return rc.marshal()
}