From 216f29888f3dd0ad688958e718fb7713f866ce18 Mon Sep 17 00:00:00 2001 From: Ashlie Martinez Date: Wed, 4 Oct 2023 13:19:15 -0700 Subject: [PATCH] Move BackupBases interface and structs definitions Move the interfact and struct definitions from the kopia package to the backup package so that we can initialize the backup model with lineage information sourced from BackupBases in a later PR. --- src/internal/kopia/backup_bases.go | 25 +------ src/internal/kopia/base_finder.go | 47 ------------ src/pkg/backup/backup_bases.go | 110 +++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 71 deletions(-) create mode 100644 src/pkg/backup/backup_bases.go diff --git a/src/internal/kopia/backup_bases.go b/src/internal/kopia/backup_bases.go index 18624236b..e96024692 100644 --- a/src/internal/kopia/backup_bases.go +++ b/src/internal/kopia/backup_bases.go @@ -12,30 +12,7 @@ import ( "github.com/alcionai/corso/src/pkg/logger" ) -// TODO(ashmrtn): Move this into some inject package. Here to avoid import -// cycles. -type BackupBases interface { - // ConvertToAssistBase converts the base with the given item data snapshot ID - // from a merge base to an assist base. - ConvertToAssistBase(manifestID manifest.ID) - Backups() []BackupEntry - UniqueAssistBackups() []BackupEntry - MinBackupVersion() int - MergeBases() []ManifestEntry - DisableMergeBases() - UniqueAssistBases() []ManifestEntry - DisableAssistBases() - MergeBackupBases( - ctx context.Context, - other BackupBases, - reasonToKey func(identity.Reasoner) string, - ) BackupBases - // SnapshotAssistBases returns the set of bases to use for kopia assisted - // incremental snapshot operations. It consists of the union of merge bases - // and assist bases. If DisableAssistBases has been called then it returns - // nil. - SnapshotAssistBases() []ManifestEntry -} +var _ backup.BackupBases = &backupBases{} type backupBases struct { // backups and mergeBases should be modified together as they relate similar diff --git a/src/internal/kopia/base_finder.go b/src/internal/kopia/base_finder.go index 4a8a7631a..a77a350ed 100644 --- a/src/internal/kopia/base_finder.go +++ b/src/internal/kopia/base_finder.go @@ -17,19 +17,6 @@ import ( "github.com/alcionai/corso/src/pkg/store" ) -const ( - // Kopia does not do comparisons properly for empty tags right now so add some - // placeholder value to them. - defaultTagValue = "0" - - // Kopia CLI prefixes all user tags with "tag:"[1]. Maintaining this will - // ensure we don't accidentally take reserved tags and that tags can be - // displayed with kopia CLI. - // (permalinks) - // [1] https://github.com/kopia/kopia/blob/05e729a7858a6e86cb48ba29fb53cb6045efce2b/cli/command_snapshot_create.go#L169 - userTagPrefix = "tag:" -) - func NewReason( tenant, resource string, service path.ServiceType, @@ -91,44 +78,10 @@ func reasonKey(r identity.Reasoner) string { return r.ProtectedResource() + r.Service().String() + r.Category().String() } -type BackupEntry struct { - *backup.Backup - Reasons []identity.Reasoner -} - -type ManifestEntry struct { - *snapshot.Manifest - // Reasons contains the ResourceOwners and Service/Categories that caused this - // snapshot to be selected as a base. We can't reuse OwnersCats here because - // it's possible some ResourceOwners will have a subset of the Categories as - // the reason for selecting a snapshot. For example: - // 1. backup user1 email,contacts -> B1 - // 2. backup user1 contacts -> B2 (uses B1 as base) - // 3. backup user1 email,contacts,events (uses B1 for email, B2 for contacts) - Reasons []identity.Reasoner -} - -func (me ManifestEntry) GetTag(key string) (string, bool) { - k, _ := makeTagKV(key) - v, ok := me.Tags[k] - - return v, ok -} - func serviceCatString(s path.ServiceType, c path.CategoryType) string { return s.String() + c.String() } -// MakeTagKV normalizes the provided key to protect it from clobbering -// similarly named tags from non-user input (user inputs are still open -// to collisions amongst eachother). -// Returns the normalized Key plus a default value. If you're embedding a -// key-only tag, the returned default value msut be used instead of an -// empty string. -func makeTagKV(k string) (string, string) { - return userTagPrefix + k, defaultTagValue -} - func normalizeTagKVs(tags map[string]string) map[string]string { t2 := make(map[string]string, len(tags)) diff --git a/src/pkg/backup/backup_bases.go b/src/pkg/backup/backup_bases.go new file mode 100644 index 000000000..bf977f7ea --- /dev/null +++ b/src/pkg/backup/backup_bases.go @@ -0,0 +1,110 @@ +package backup + +import ( + "context" + + "github.com/kopia/kopia/repo/manifest" + "github.com/kopia/kopia/snapshot" + + "github.com/alcionai/corso/src/pkg/backup/identity" + "github.com/alcionai/corso/src/pkg/path" +) + +const ( + // Kopia does not do comparisons properly for empty tags right now so add some + // placeholder value to them. + legacyDefaultTagValue = "0" + + // Kopia CLI prefixes all user tags with "tag:"[1]. Maintaining this will + // ensure we don't accidentally take reserved tags and that tags can be + // displayed with kopia CLI. + // (permalinks) + // [1] https://github.com/kopia/kopia/blob/05e729a7858a6e86cb48ba29fb53cb6045efce2b/cli/command_snapshot_create.go#L169 + LegacyUserTagPrefix = "tag:" + + tenantIDKey = "tenant" + resourceIDKey = "resource" + serviceCatPrefix = "sc-" + + // Sentinel value for tags. Could technically be empty but we'll store + // something for now. + //nolint + defaultTagValue = "1" +) + +func serviceCatString( + service path.ServiceType, + category path.CategoryType, +) string { + return serviceCatPrefix + service.String() + category.String() +} + +// reasonTags returns the set of key-value pairs that can be used as tags to +// represent this Reason. +// nolint +func reasonTags(r identity.Reasoner) map[string]string { + return map[string]string{ + tenantIDKey: r.Tenant(), + resourceIDKey: r.ProtectedResource(), + serviceCatString(r.Service(), r.Category()): defaultTagValue, + } +} + +// nolint +type BackupEntry struct { + *Backup + Reasons []identity.Reasoner +} + +type ManifestEntry struct { + *snapshot.Manifest + // Reasons contains the ResourceOwners and Service/Categories that caused this + // snapshot to be selected as a base. We can't reuse OwnersCats here because + // it's possible some ResourceOwners will have a subset of the Categories as + // the reason for selecting a snapshot. For example: + // 1. backup user1 email,contacts -> B1 + // 2. backup user1 contacts -> B2 (uses B1 as base) + // 3. backup user1 email,contacts,events (uses B1 for email, B2 for contacts) + Reasons []identity.Reasoner +} + +// MakeTagKV normalizes the provided key to protect it from clobbering +// similarly named tags from non-user input (user inputs are still open +// to collisions amongst eachother). +// Returns the normalized Key plus a default value. If you're embedding a +// key-only tag, the returned default value msut be used instead of an +// empty string. +func MakeTagKV(k string) (string, string) { + return LegacyUserTagPrefix + k, legacyDefaultTagValue +} + +func (me ManifestEntry) GetTag(key string) (string, bool) { + k, _ := MakeTagKV(key) + v, ok := me.Tags[k] + + return v, ok +} + +// nolint +type BackupBases interface { + // ConvertToAssistBase converts the base with the given item data snapshot ID + // from a merge base to an assist base. + ConvertToAssistBase(manifestID manifest.ID) + Backups() []BackupEntry + UniqueAssistBackups() []BackupEntry + MinBackupVersion() int + MergeBases() []ManifestEntry + DisableMergeBases() + UniqueAssistBases() []ManifestEntry + DisableAssistBases() + MergeBackupBases( + ctx context.Context, + other BackupBases, + reasonToKey func(identity.Reasoner) string, + ) BackupBases + // SnapshotAssistBases returns the set of bases to use for kopia assisted + // incremental snapshot operations. It consists of the union of merge bases + // and assist bases. If DisableAssistBases has been called then it returns + // nil. + SnapshotAssistBases() []ManifestEntry +}