corso/src/pkg/control/options.go
Keepers 46eedc0ad1
add default restore config normalizer (#3613)
Adds a func that normalizes the restore config in case inputs don't match accepted or expected values.

Also moves DefaultTestRestoreConfig out of /tester and into /control/testdata to avoid circular dependency issues.

---

#### Does this PR need a docs update or release note?

- [x]  No

#### Type of change

- [x] 🌻 Feature

#### Issue(s)

* #3562

#### Test Plan

- [x]  Unit test
2023-06-15 16:04:42 +00:00

159 lines
5.2 KiB
Go

package control
import (
"context"
"strings"
"golang.org/x/exp/slices"
"github.com/alcionai/corso/src/internal/common/dttm"
"github.com/alcionai/corso/src/pkg/control/repository"
"github.com/alcionai/corso/src/pkg/logger"
)
// Options holds the optional configurations for a process
type Options struct {
DisableMetrics bool `json:"disableMetrics"`
FailureHandling FailurePolicy `json:"failureHandling"`
RestorePermissions bool `json:"restorePermissions"`
SkipReduce bool `json:"skipReduce"`
ToggleFeatures Toggles `json:"toggleFeatures"`
Parallelism Parallelism `json:"parallelism"`
Repo repository.Options `json:"repo"`
}
type Parallelism struct {
// sets the collection buffer size before blocking.
CollectionBuffer int
// sets the parallelism of item population within a collection.
ItemFetch int
}
type FailurePolicy string
const (
// fails and exits the run immediately
FailFast FailurePolicy = "fail-fast"
// recovers whenever possible, reports non-zero recoveries as a failure
FailAfterRecovery FailurePolicy = "fail-after-recovery"
// recovers whenever possible, does not report recovery as failure
BestEffort FailurePolicy = "best-effort"
)
// Defaults provides an Options with the default values set.
func Defaults() Options {
return Options{
FailureHandling: FailAfterRecovery,
ToggleFeatures: Toggles{},
Parallelism: Parallelism{
CollectionBuffer: 4,
ItemFetch: 4,
},
}
}
// ---------------------------------------------------------------------------
// Restore Configuration
// ---------------------------------------------------------------------------
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"
)
const RootLocation = "/"
// RestoreConfig contains
type RestoreConfig struct {
// Defines the per-item collision handling policy.
// Defaults to Skip.
OnCollision CollisionPolicy
// 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
// 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
// Drive specifies 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
}
func DefaultRestoreConfig(timeFormat dttm.TimeFormat) RestoreConfig {
return RestoreConfig{
OnCollision: Skip,
Location: 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 !slices.Contains([]CollisionPolicy{Skip, Copy, Replace}, rc.OnCollision) {
logger.Ctx(ctx).
With(
"bad_collision_policy", rc.OnCollision,
"default_collision_policy", Skip).
Info("setting collision policy to default")
rc.OnCollision = Skip
}
if strings.TrimSpace(rc.Location) == RootLocation {
rc.Location = ""
}
return rc
}
// ---------------------------------------------------------------------------
// Feature Flags and Toggles
// ---------------------------------------------------------------------------
// Toggles allows callers to force corso to behave in ways that deviate from
// the default expectations by turning on or shutting off certain features.
// The default state for every toggle is false; toggles are only turned on
// if specified by the caller.
type Toggles struct {
// DisableIncrementals prevents backups from using incremental lookups,
// forcing a new, complete backup of all data regardless of prior state.
DisableIncrementals bool `json:"exchangeIncrementals,omitempty"`
// DisableDelta prevents backups from using delta based lookups,
// forcing a backup by enumerating all items. This is different
// from DisableIncrementals in that this does not even makes use of
// delta endpoints with or without a delta token. This is necessary
// when the user has filled up the mailbox storage available to the
// user as Microsoft prevents the API from being able to make calls
// to delta endpoints.
DisableDelta bool `json:"exchangeDelta,omitempty"`
// ExchangeImmutableIDs denotes whether Corso should store items with
// immutable Exchange IDs. This is only safe to set if the previous backup for
// incremental backups used immutable IDs or if a full backup is being done.
ExchangeImmutableIDs bool `json:"exchangeImmutableIDs,omitempty"`
RunMigrations bool `json:"runMigrations"`
// DisableConcurrencyLimiter removes concurrency limits when communicating with
// graph API. This flag is only relevant for exchange backups for now
DisableConcurrencyLimiter bool `json:"disableConcurrencyLimiter,omitempty"`
}