Basic validation checks that make sure maintenance and retention options are consistent with each other. This at least makes sure retention is either enabled and maintenance extends locks or nothing is locked at all. Going to be part of a set of PRs for validating the kopia config --- #### Does this PR need a docs update or release note? - [ ] ✅ Yes, it's included - [ ] 🕐 Yes, but in a later PR - [x] ⛔ No #### Type of change - [x] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [x] 🤖 Supportability/Tests - [ ] 💻 CI/Deployment - [ ] 🧹 Tech Debt/Cleanup #### Test Plan - [ ] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
170 lines
3.9 KiB
Go
170 lines
3.9 KiB
Go
package retention
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/alcionai/clues"
|
|
"github.com/kopia/kopia/repo/blob"
|
|
"github.com/kopia/kopia/repo/format"
|
|
"github.com/kopia/kopia/repo/maintenance"
|
|
|
|
"github.com/alcionai/corso/src/pkg/control/repository"
|
|
)
|
|
|
|
type Opts struct {
|
|
blobCfg format.BlobStorageConfiguration
|
|
params maintenance.Params
|
|
|
|
blobChanged bool
|
|
paramsChanged bool
|
|
}
|
|
|
|
func NewOpts() *Opts {
|
|
return &Opts{}
|
|
}
|
|
|
|
func OptsFromConfigs(
|
|
blobCfg format.BlobStorageConfiguration,
|
|
params maintenance.Params,
|
|
) *Opts {
|
|
return &Opts{
|
|
blobCfg: blobCfg,
|
|
params: params,
|
|
}
|
|
}
|
|
|
|
func (r *Opts) AsConfigs(
|
|
ctx context.Context,
|
|
) (format.BlobStorageConfiguration, maintenance.Params, error) {
|
|
// Check the new config is valid.
|
|
if r.blobCfg.IsRetentionEnabled() {
|
|
if err := maintenance.CheckExtendRetention(ctx, r.blobCfg, &r.params); err != nil {
|
|
return format.BlobStorageConfiguration{}, maintenance.Params{}, clues.WrapWC(
|
|
ctx,
|
|
err,
|
|
"invalid retention config")
|
|
}
|
|
}
|
|
|
|
return r.blobCfg, r.params, nil
|
|
}
|
|
|
|
func (r *Opts) BlobChanged() bool {
|
|
return r.blobChanged
|
|
}
|
|
|
|
func (r *Opts) ParamsChanged() bool {
|
|
return r.paramsChanged
|
|
}
|
|
|
|
func (r *Opts) Set(opts repository.Retention) error {
|
|
r.setMaintenanceParams(opts.Extend)
|
|
|
|
return clues.Wrap(
|
|
r.setBlobConfigParams(opts.Mode, opts.Duration),
|
|
"setting mode or duration").OrNil()
|
|
}
|
|
|
|
func (r *Opts) setMaintenanceParams(extend *bool) {
|
|
if extend != nil && r.params.ExtendObjectLocks != *extend {
|
|
r.params.ExtendObjectLocks = *extend
|
|
r.paramsChanged = true
|
|
}
|
|
}
|
|
|
|
func (r *Opts) setBlobConfigParams(
|
|
mode *repository.RetentionMode,
|
|
duration *time.Duration,
|
|
) error {
|
|
err := r.setBlobConfigMode(mode)
|
|
if err != nil {
|
|
return clues.Stack(err)
|
|
}
|
|
|
|
r.setBlobConfigDuration(duration)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *Opts) setBlobConfigDuration(duration *time.Duration) {
|
|
if duration != nil && r.blobCfg.RetentionPeriod != *duration {
|
|
r.blobCfg.RetentionPeriod = *duration
|
|
r.blobChanged = true
|
|
}
|
|
}
|
|
|
|
func (r *Opts) setBlobConfigMode(
|
|
mode *repository.RetentionMode,
|
|
) error {
|
|
if mode == nil {
|
|
return nil
|
|
}
|
|
|
|
startMode := r.blobCfg.RetentionMode
|
|
|
|
switch *mode {
|
|
case repository.NoRetention:
|
|
if !r.blobCfg.IsRetentionEnabled() {
|
|
return nil
|
|
}
|
|
|
|
r.blobCfg.RetentionMode = ""
|
|
r.blobCfg.RetentionPeriod = 0
|
|
|
|
case repository.GovernanceRetention:
|
|
r.blobCfg.RetentionMode = blob.Governance
|
|
|
|
case repository.ComplianceRetention:
|
|
r.blobCfg.RetentionMode = blob.Compliance
|
|
|
|
default:
|
|
return clues.New("unknown retention mode").
|
|
With("provided_retention_mode", mode.String())
|
|
}
|
|
|
|
// Only check if the retention mode is not empty. IsValid errors out if it's
|
|
// empty.
|
|
if len(r.blobCfg.RetentionMode) > 0 && !r.blobCfg.RetentionMode.IsValid() {
|
|
return clues.New("invalid retention mode").
|
|
With("retention_mode", r.blobCfg.RetentionMode)
|
|
}
|
|
|
|
// Take into account previous operations on r that could have already updated
|
|
// blobChanged.
|
|
r.blobChanged = r.blobChanged || startMode != r.blobCfg.RetentionMode
|
|
|
|
return nil
|
|
}
|
|
|
|
// Verify checks that the config info in r passes kopia's retention validation
|
|
// checks when it comes to locking durations and that if retention is requested
|
|
// in the blob config blob then lock extension is also configured to run during
|
|
// maintenance. If rentention is not enabled in the blob config blob then lock
|
|
// extension should be disabled during maintenance.
|
|
func (r Opts) Verify(ctx context.Context) error {
|
|
if !r.blobCfg.IsRetentionEnabled() {
|
|
if r.params.ExtendObjectLocks {
|
|
return clues.NewWC(
|
|
ctx,
|
|
"retention disabled but maintenance lock extension enabled")
|
|
}
|
|
|
|
// Both disabled.
|
|
return nil
|
|
}
|
|
|
|
// Rest of function handles case where retention is enabled in the blob config
|
|
// blob.
|
|
if !r.params.ExtendObjectLocks {
|
|
return clues.NewWC(
|
|
ctx,
|
|
"retention enabled but maintenance lock extension disabled")
|
|
}
|
|
|
|
return clues.Stack(maintenance.CheckExtendRetention(
|
|
ctx,
|
|
r.blobCfg,
|
|
&r.params)).OrNil()
|
|
}
|