mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-08-04 14:26:07 +00:00
Merge branch 'main' into optimize-sub-object-description
This commit is contained in:
@@ -18,6 +18,7 @@ package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/fips140"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -173,7 +174,13 @@ func (m *manager) PrepareRepo(repo *velerov1api.BackupRepository) error {
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
return prd.PrepareRepo(context.Background(), param)
|
||||
|
||||
// Disable FIPS-140 compliance check, because Kopia doesn't support FIPS-140 yet.
|
||||
var prepareErr error
|
||||
fips140.WithoutEnforcement(func() {
|
||||
prepareErr = prd.PrepareRepo(context.Background(), param)
|
||||
})
|
||||
return prepareErr
|
||||
}
|
||||
|
||||
func (m *manager) PruneRepo(repo *velerov1api.BackupRepository) error {
|
||||
@@ -244,11 +251,20 @@ func (m *manager) BatchForget(ctx context.Context, repo *velerov1api.BackupRepos
|
||||
return []error{errors.WithStack(err)}
|
||||
}
|
||||
|
||||
if err := prd.BoostRepoConnect(context.Background(), param); err != nil {
|
||||
// Disable FIPS-140 compliance check, because Kopia doesn't support FIPS-140 yet.
|
||||
var connectErr error
|
||||
fips140.WithoutEnforcement(func() {
|
||||
connectErr = prd.BoostRepoConnect(context.Background(), param)
|
||||
})
|
||||
if connectErr != nil {
|
||||
return []error{errors.WithStack(err)}
|
||||
}
|
||||
|
||||
return prd.BatchForget(context.Background(), snapshots, param)
|
||||
forgetErr := make([]error, 0)
|
||||
fips140.WithoutEnforcement(func() {
|
||||
forgetErr = prd.BatchForget(context.Background(), snapshots, param)
|
||||
})
|
||||
return forgetErr
|
||||
}
|
||||
|
||||
func (m *manager) DefaultMaintenanceFrequency(repo *velerov1api.BackupRepository) (time.Duration, error) {
|
||||
|
||||
@@ -1208,6 +1208,10 @@ func TestKopiaObjectWriterEx_MixedWriteAndWriteAt(t *testing.T) {
|
||||
assert.Equal(t, int64(3072), kow.entries[3].Start)
|
||||
}
|
||||
|
||||
// TestKopiaObjectWriterEx_ConcurrentAsyncErrors verifies the async error contract
|
||||
// under real scheduling: once an async block write fails, the error either fails a
|
||||
// subsequent Write call fast or surfaces at Result — it is never lost. Which of the
|
||||
// two happens first depends on goroutine scheduling, and both are correct.
|
||||
func TestKopiaObjectWriterEx_ConcurrentAsyncErrors(t *testing.T) {
|
||||
mockRepoWriter := repomocks.NewMockRepositoryWriter(t)
|
||||
mockWriter := repomocks.NewWriter(t)
|
||||
@@ -1231,14 +1235,65 @@ func TestKopiaObjectWriterEx_ConcurrentAsyncErrors(t *testing.T) {
|
||||
|
||||
data := make([]byte, 1024)
|
||||
|
||||
// Issue multiple writes so they all spawn async goroutines
|
||||
// First few writes shouldn't fail immediately until getWriteError catches the asynchronous fault
|
||||
// Issue multiple writes so they all spawn async goroutines. A later Write may
|
||||
// observe the stored async error and fail fast — that is correct behavior.
|
||||
for i := 0; i < 10; i++ {
|
||||
l, err := kow.Write(data)
|
||||
if err != nil {
|
||||
assert.Contains(t, err.Error(), "simulated async error")
|
||||
break
|
||||
}
|
||||
assert.Equal(t, 1024, l)
|
||||
}
|
||||
|
||||
// Regardless of whether a Write observed the error first, Result must report it.
|
||||
id, err := kow.Result()
|
||||
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "simulated async error")
|
||||
assert.Equal(t, udmrepo.ID(""), id)
|
||||
}
|
||||
|
||||
// TestKopiaObjectWriterEx_AsyncErrorSurfacesAtResult pins the late-error schedule:
|
||||
// async writes are held until all writes have been queued, so no Write call observes
|
||||
// the failure and Result alone must report it.
|
||||
func TestKopiaObjectWriterEx_AsyncErrorSurfacesAtResult(t *testing.T) {
|
||||
mockRepoWriter := repomocks.NewMockRepositoryWriter(t)
|
||||
mockWriter := repomocks.NewWriter(t)
|
||||
|
||||
releaseWrites := make(chan struct{})
|
||||
mockWriter.On("Write", mock.Anything).Run(func(mock.Arguments) {
|
||||
<-releaseWrites
|
||||
}).Return(0, errors.New("simulated async error"))
|
||||
mockWriter.On("Close").Return(nil)
|
||||
|
||||
mockRepoWriter.On("NewObjectWriter", mock.Anything, mock.Anything).Return(mockWriter)
|
||||
|
||||
sem := make(chan struct{}, 10)
|
||||
buf := freelist.New(10*1024, 1024)
|
||||
|
||||
kow := &kopiaObjectWriterEx{
|
||||
ctx: context.Background(),
|
||||
rawRepoWriter: mockRepoWriter,
|
||||
blockSize: 1024,
|
||||
asyncWritesSem: sem,
|
||||
asyncBuffer: buf,
|
||||
logger: velerotest.NewLogger(),
|
||||
}
|
||||
|
||||
data := make([]byte, 1024)
|
||||
|
||||
// All async writes block on releaseWrites, so no error can be stored yet and
|
||||
// every Write must succeed.
|
||||
for i := 0; i < 10; i++ {
|
||||
l, err := kow.Write(data)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1024, l)
|
||||
}
|
||||
|
||||
close(releaseWrites)
|
||||
|
||||
// Result waits for the async writers to finish and must report their error.
|
||||
id, err := kow.Result()
|
||||
|
||||
require.Error(t, err)
|
||||
|
||||
Reference in New Issue
Block a user