[#641] Rework CORS bucket behaviour

Signed-off-by: Marina Biryukova <m.biryukova@yadro.com>
This commit is contained in:
Marina Biryukova 2025-02-19 19:09:19 +03:00 committed by Alexey Vanin
parent 1fac8e3ef2
commit 9edec7d573
16 changed files with 490 additions and 138 deletions

View file

@ -15,9 +15,11 @@ import (
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/crdt"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object"
apiobject "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
)
@ -175,24 +177,42 @@ func (n *Layer) getCORS(ctx context.Context, bkt *data.BucketInfo, decoder func(
return cors, nil
}
addr, err := n.treeService.GetBucketCORS(ctx, bkt)
objNotFound := errors.Is(err, tree.ErrNodeNotFound)
if err != nil && !objNotFound {
corsVersions, err := n.getCORSVersions(ctx, bkt)
if err != nil {
return nil, err
}
if objNotFound {
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchCORSConfiguration), err.Error())
}
var (
prmAuth frostfs.PrmAuth
objID oid.ID
corsBkt = bkt
lastCORS = corsVersions.GetLast()
)
var prmAuth frostfs.PrmAuth
corsBkt := bkt
if !addr.Container().Equals(bkt.CID) && !addr.Container().Equals(cid.ID{}) {
corsBkt = &data.BucketInfo{CID: addr.Container()}
if lastCORS != nil {
prmAuth.PrivateKey = &n.gateKey.PrivateKey
corsBkt = n.corsCnrInfo
objID = lastCORS.ObjID
} else {
addr, err := n.treeService.GetBucketCORS(ctx, bkt)
objNotFound := errors.Is(err, tree.ErrNodeNotFound)
if err != nil && !objNotFound {
return nil, err
}
if objNotFound {
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchCORSConfiguration), err.Error())
}
if !addr.Container().Equals(bkt.CID) && !addr.Container().Equals(cid.ID{}) {
corsBkt = &data.BucketInfo{CID: addr.Container()}
prmAuth.PrivateKey = &n.gateKey.PrivateKey
}
objID = addr.Object()
}
obj, err := n.objectGetWithAuth(ctx, corsBkt, addr.Object(), prmAuth)
obj, err := n.objectGetWithAuth(ctx, corsBkt, objID, prmAuth)
if err != nil {
return nil, fmt.Errorf("get cors object: %w", err)
}
@ -207,6 +227,56 @@ func (n *Layer) getCORS(ctx context.Context, bkt *data.BucketInfo, decoder func(
return cors, nil
}
func (n *Layer) getCORSVersions(ctx context.Context, bkt *data.BucketInfo) (*crdt.ObjectVersions, error) {
corsVersions, err := n.frostFS.SearchObjects(ctx, frostfs.PrmObjectSearch{
Container: n.corsCnrInfo.CID,
ExactAttribute: [2]string{object.AttributeFilePath, bkt.CORSObjectFilePath()},
})
if err != nil {
return nil, fmt.Errorf("search cors objects: %w", err)
}
versions := crdt.NewObjectVersions(bkt.CORSObjectFilePath())
versions.SetLessFunc(func(ov1, ov2 *crdt.ObjectVersion) bool {
versionID1, versionID2 := ov1.VersionID(), ov2.VersionID()
timestamp1, timestamp2 := ov1.Headers[object.AttributeTimestamp], ov2.Headers[object.AttributeTimestamp]
if ov1.CreationEpoch != ov2.CreationEpoch {
return ov1.CreationEpoch < ov2.CreationEpoch
}
if len(timestamp1) > 0 && len(timestamp2) > 0 && timestamp1 != timestamp2 {
unixTime1, err := strconv.ParseInt(timestamp1, 10, 64)
if err != nil {
return versionID1 < versionID2
}
unixTime2, err := strconv.ParseInt(timestamp2, 10, 64)
if err != nil {
return versionID1 < versionID2
}
return unixTime1 < unixTime2
}
return versionID1 < versionID2
})
for _, id := range corsVersions {
objVersion, err := n.frostFS.HeadObject(ctx, frostfs.PrmObjectHead{
Container: n.corsCnrInfo.CID,
Object: id,
})
if err != nil {
return nil, fmt.Errorf("head cors object '%s': %w", id.EncodeToString(), err)
}
versions.AppendVersion(crdt.NewObjectVersion(objVersion))
}
return versions, nil
}
func lockObjectKey(objVersion *data.ObjectVersion) string {
// todo reconsider forming name since versionID can be "null" or ""
return ".lock." + objVersion.BktInfo.CID.EncodeToString() + "." + objVersion.ObjectName + "." + objVersion.VersionID
@ -274,7 +344,7 @@ func (n *Layer) attributesFromLock(ctx context.Context, lock *data.ObjectLock) (
if expEpoch != 0 {
result = append(result, [2]string{
object.SysAttributeExpEpoch, strconv.FormatUint(expEpoch, 10),
apiobject.SysAttributeExpEpoch, strconv.FormatUint(expEpoch, 10),
})
}