Skip to content

Commit

Permalink
Merge pull request #222 from alcionai/staging-immutable-caching
Browse files Browse the repository at this point in the history
Fix in-memory caching issue with storage blob config blob which could lead to using old settings
  • Loading branch information
ashmrtn authored Aug 3, 2023
2 parents 4c85869 + da3c371 commit 5f2a35e
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 0 deletions.
137 changes: 137 additions & 0 deletions repo/format/format_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import (
"time"

"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/kopia/kopia/internal/blobtesting"
"github.com/kopia/kopia/internal/cache"
"github.com/kopia/kopia/internal/epoch"
"github.com/kopia/kopia/internal/faketime"
"github.com/kopia/kopia/internal/feature"
Expand Down Expand Up @@ -169,6 +171,141 @@ func TestInitialize(t *testing.T) {
format.ErrAlreadyInitialized)
}

func TestInitializeWithRetention(t *testing.T) {
ctx := testlogging.Context(t)

startTime := time.Date(2020, 1, 1, 12, 0, 0, 0, time.UTC)
ta := faketime.NewTimeAdvance(startTime, 0)
nowFunc := ta.NowFunc()

st := blobtesting.NewVersionedMapStorage(nowFunc).(cache.Storage)
cache := format.NewMemoryBlobCache(nowFunc)
mode := blob.Governance
period := time.Hour * 48

// success
require.NoError(t, format.Initialize(
ctx,
st,
&format.KopiaRepositoryJSON{},
rc,
format.BlobStorageConfiguration{
RetentionMode: mode,
RetentionPeriod: period,
},
"some-password",
))

mgr, err := format.NewManagerWithCache(ctx, st, cacheDuration, "some-password", nowFunc, cache)
require.NoError(t, err, "getting format manager")

// New retention parameters should be available from the format manager.
blobCfg := mustGetBlobStorageConfiguration(t, mgr)
assert.Equal(t, mode, blobCfg.RetentionMode)
assert.Equal(t, period, blobCfg.RetentionPeriod)

// Attempting to touch the blobs the format manager writes should return
// errors as they should have retention enabled. Mod time adjustment (duration
// param) doesn't matter in this context.
_, err = st.TouchBlob(ctx, format.KopiaRepositoryBlobID, time.Minute)
assert.ErrorIs(t, err, blobtesting.ErrBlobLocked, "Altering locked repo blob should fail")

_, err = st.TouchBlob(ctx, format.KopiaBlobCfgBlobID, time.Minute)
assert.ErrorIs(t, err, blobtesting.ErrBlobLocked, "Altering locked blob storage config should fail")
}

func TestUpdateRetention(t *testing.T) {
ctx := testlogging.Context(t)

startTime := time.Date(2020, 1, 1, 12, 0, 0, 0, time.UTC)
ta := faketime.NewTimeAdvance(startTime, 0)
nowFunc := ta.NowFunc()

st := blobtesting.NewVersionedMapStorage(nowFunc).(cache.Storage)
cache := format.NewMemoryBlobCache(nowFunc)
mode := blob.Governance
period := time.Hour * 48

// success
require.NoError(t, format.Initialize(ctx, st, &format.KopiaRepositoryJSON{}, rc, format.BlobStorageConfiguration{}, "some-password"))

mgr, err := format.NewManagerWithCache(ctx, st, cacheDuration, "some-password", nowFunc, cache)
require.NoError(t, err, "getting format manager")

mp := mustGetMutableParameters(t, mgr)
rf := mustGetRequiredFeatures(t, mgr)

err = mgr.SetParameters(
ctx,
mp,
format.BlobStorageConfiguration{
RetentionMode: mode,
RetentionPeriod: period,
},
rf,
)
require.NoError(t, err, "setting repo parameters")

// New retention parameters should be available from the format manager.
blobCfg := mustGetBlobStorageConfiguration(t, mgr)
assert.Equal(t, mode, blobCfg.RetentionMode)
assert.Equal(t, period, blobCfg.RetentionPeriod)

// Attempting to touch the blobs the format manager writes should return
// errors as they should have retention enabled. Mod time adjustment (duration
// param) doesn't matter in this context.
_, err = st.TouchBlob(ctx, format.KopiaRepositoryBlobID, time.Minute)
assert.ErrorIs(t, err, blobtesting.ErrBlobLocked, "Altering locked repo blob should fail")

_, err = st.TouchBlob(ctx, format.KopiaBlobCfgBlobID, time.Minute)
assert.ErrorIs(t, err, blobtesting.ErrBlobLocked, "Altering locked blob storage config should fail")
}

func TestUpdateRetentionNegativeValue(t *testing.T) {
ctx := testlogging.Context(t)

startTime := time.Date(2020, 1, 1, 12, 0, 0, 0, time.UTC)
ta := faketime.NewTimeAdvance(startTime, 0)
nowFunc := ta.NowFunc()

st := blobtesting.NewVersionedMapStorage(nowFunc).(cache.Storage)
cache := format.NewMemoryBlobCache(nowFunc)
mode := blob.Governance
period := -time.Hour * 48

// success
require.NoError(t, format.Initialize(ctx, st, &format.KopiaRepositoryJSON{}, rc, format.BlobStorageConfiguration{}, "some-password"))

mgr, err := format.NewManagerWithCache(ctx, st, cacheDuration, "some-password", nowFunc, cache)
require.NoError(t, err, "getting format manager")

mp := mustGetMutableParameters(t, mgr)
rf := mustGetRequiredFeatures(t, mgr)

err = mgr.SetParameters(
ctx,
mp,
format.BlobStorageConfiguration{
RetentionMode: mode,
RetentionPeriod: period,
},
rf,
)
require.Error(t, err, "setting repo parameters")

// Old retention parameters should be available from the format manager.
blobCfg := mustGetBlobStorageConfiguration(t, mgr)
assert.Empty(t, blobCfg.RetentionMode)
assert.Zero(t, blobCfg.RetentionPeriod)

// Retention wasn't set so no error should occur.
_, err = st.TouchBlob(ctx, format.KopiaRepositoryBlobID, time.Minute)
assert.NoError(t, err, "altering repo blob")

_, err = st.TouchBlob(ctx, format.KopiaBlobCfgBlobID, time.Minute)
assert.NoError(t, err, "altering storage config")
}

func TestChangePassword(t *testing.T) {
ctx := testlogging.Context(t)

Expand Down
5 changes: 5 additions & 0 deletions repo/format/format_set_parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ func (m *Manager) SetParameters(
return errors.Wrap(err, "unable to write blobcfg blob")
}

// At this point the new blobcfg is persisted in the blob layer. Setting this
// here also ensures the call below properly sets retention on the kopia
// repository blob.
m.blobCfgBlob = blobcfg

if err := m.j.WriteKopiaRepositoryBlob(ctx, m.blobs, m.blobCfgBlob); err != nil {
return errors.Wrap(err, "unable to write format blob")
}
Expand Down

0 comments on commit 5f2a35e

Please sign in to comment.