mirror of
https://github.com/pgsty/minio.git
synced 2026-10-09 19:25:59 +03:00
fix(replication): retry marker purges through persisted MRF
(cherry picked from commit cf381a7151ef25fc95ace5fedcd767fa19410de2) Signed-off-by: Feng Ruohang <rh@vonng.com>
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
package cmd
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"github.com/minio/minio-go/v7"
|
||||
"github.com/minio/minio/internal/bucket/replication"
|
||||
xhttp "github.com/minio/minio/internal/http"
|
||||
)
|
||||
func TestReviewR6LegacyPurgeRetries(t *testing.T) {
|
||||
var deletes atomic.Int32
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == http.MethodHead {
|
||||
w.Header().Set(xhttp.AmzDeleteMarker, "true")
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
deletes.Add(1)
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}))
|
||||
defer server.Close()
|
||||
client, err := minio.New(strings.TrimPrefix(server.URL, "http://"), &minio.Options{Region: "us-east-1", MaxRetries: 1})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
old := globalBucketTargetSys
|
||||
globalBucketTargetSys = &BucketTargetSys{hc: map[string]epHealth{client.EndpointURL().Host: {Online: true}}}
|
||||
defer func() { globalBucketTargetSys = old }()
|
||||
d := DeletedObjectReplicationInfo{Bucket: "source", DeletedObject: DeletedObject{ObjectName: "marker", DeleteMarker: true, DeleteMarkerVersionID: mustGetUUID()}}
|
||||
d.ReplicationState.Targets = map[string]replication.StatusType{"arn1": replication.Completed}
|
||||
d.ReplicationState.PurgeTargets = map[string]VersionPurgeStatusType{"arn1": replication.VersionPurgePending}
|
||||
result := replicateDeleteToTarget(t.Context(), d, &TargetClient{Client: client, ARN: "arn1", Bucket: "target"})
|
||||
t.Logf("remote DELETE calls=%d, creation=%s, purge=%s", deletes.Load(), result.ReplicationStatus, result.VersionPurgeStatus)
|
||||
if deletes.Load() != 1 || result.VersionPurgeStatus != replication.VersionPurgeComplete {
|
||||
t.Error("pending legacy purge was not delivered")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func TestReviewR6PurgeExits(t *testing.T) {
|
||||
for _, tc := range []struct{name string; creation replication.StatusType; purge VersionPurgeStatusType; head int; existing bool; want VersionPurgeStatusType; wantCalls int; wantReset bool}{
|
||||
{"head_forbidden", replication.Pending, replication.VersionPurgePending, 403, false, replication.VersionPurgeFailed, 1, false},
|
||||
{"failed_resync", replication.Completed, replication.VersionPurgePending, 405, true, replication.VersionPurgeFailed, 2, false},
|
||||
{"already_purged", replication.Pending, replication.VersionPurgeComplete, 405, false, replication.VersionPurgeComplete, 0, false},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T){
|
||||
var calls atomic.Int32
|
||||
server:=httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter,r *http.Request){
|
||||
calls.Add(1)
|
||||
if r.Method==http.MethodHead {w.Header().Set(xhttp.AmzDeleteMarker,"true"); w.WriteHeader(tc.head);return}
|
||||
w.WriteHeader(403);fmt.Fprint(w,`<Error><Code>AccessDenied</Code></Error>`)
|
||||
}))
|
||||
defer server.Close()
|
||||
client,err:=minio.New(strings.TrimPrefix(server.URL,"http://"),&minio.Options{Region:"us-east-1",MaxRetries:1});if err!=nil{t.Fatal(err)}
|
||||
old:=globalBucketTargetSys;globalBucketTargetSys=&BucketTargetSys{hc:map[string]epHealth{client.EndpointURL().Host:{Online:true}}};defer func(){globalBucketTargetSys=old}()
|
||||
d:=DeletedObjectReplicationInfo{Bucket:"source",DeletedObject:DeletedObject{ObjectName:"marker",DeleteMarker:true,DeleteMarkerVersionID:mustGetUUID()}}
|
||||
d.ReplicationState.Targets=map[string]replication.StatusType{"arn1":tc.creation}
|
||||
d.ReplicationState.PurgeTargets=map[string]VersionPurgeStatusType{"arn1":tc.purge}
|
||||
if tc.existing {d.OpType=replication.ExistingObjectReplicationType}
|
||||
got:=replicateDeleteToTarget(t.Context(),d,&TargetClient{Client:client,ARN:"arn1",Bucket:"target",ResetID:"new-reset"})
|
||||
t.Logf("calls=%d, creation=%s, purge=%s, reset=%q",calls.Load(),got.ReplicationStatus,got.VersionPurgeStatus,got.ResyncTimestamp)
|
||||
if got.ReplicationStatus!=tc.creation || got.VersionPurgeStatus!=tc.want || int(calls.Load())!=tc.wantCalls || (got.ResyncTimestamp!="")!=tc.wantReset {t.Errorf("operation classified inconsistently: %+v",got)}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user