forked from TrueCloudLab/frostfs-s3-gw
[#306] acl: Handle put/get acl for APE buckets
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
1f2cf0ed67
commit
3d0d2032c6
13 changed files with 280 additions and 42 deletions
|
@ -8,6 +8,7 @@ import (
|
|||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -61,9 +62,10 @@ type (
|
|||
|
||||
// BucketSettings stores settings such as versioning.
|
||||
BucketSettings struct {
|
||||
Versioning string `json:"versioning"`
|
||||
LockConfiguration *ObjectLockConfiguration `json:"lock_configuration"`
|
||||
APE bool `json:"ape"`
|
||||
Versioning string
|
||||
LockConfiguration *ObjectLockConfiguration
|
||||
CannedACL string
|
||||
OwnerKey *keys.PublicKey
|
||||
}
|
||||
|
||||
// CORSConfiguration stores CORS configuration of a request.
|
||||
|
|
|
@ -26,6 +26,7 @@ type (
|
|||
const (
|
||||
_ ErrorCode = iota
|
||||
ErrAccessDenied
|
||||
ErrAccessControlListNotSupported
|
||||
ErrBadDigest
|
||||
ErrEntityTooSmall
|
||||
ErrEntityTooLarge
|
||||
|
@ -376,6 +377,12 @@ var errorCodes = errorCodeMap{
|
|||
Description: "Access Denied.",
|
||||
HTTPStatusCode: http.StatusForbidden,
|
||||
},
|
||||
ErrAccessControlListNotSupported: {
|
||||
ErrCode: ErrAccessControlListNotSupported,
|
||||
Code: "AccessControlListNotSupported",
|
||||
Description: "The bucket does not allow ACLs.",
|
||||
HTTPStatusCode: http.StatusBadRequest,
|
||||
},
|
||||
ErrBadDigest: {
|
||||
ErrCode: ErrBadDigest,
|
||||
Code: "BadDigest",
|
||||
|
|
|
@ -257,6 +257,20 @@ func (h *handler) GetBucketACLHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "couldn't get bucket settings", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
if bktInfo.APEEnabled || len(settings.CannedACL) != 0 {
|
||||
if err = middleware.EncodeToResponse(w, h.encodeBucketCannedACL(ctx, bktInfo, settings)); err != nil {
|
||||
h.logAndSendError(w, "something went wrong", reqInfo, err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
bucketACL, err := h.obj.GetBucketACL(ctx, bktInfo)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "could not fetch bucket acl", reqInfo, err)
|
||||
|
@ -269,6 +283,54 @@ func (h *handler) GetBucketACLHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func (h *handler) encodeBucketCannedACL(ctx context.Context, bktInfo *data.BucketInfo, settings *data.BucketSettings) *AccessControlPolicy {
|
||||
ownerDisplayName := bktInfo.Owner.EncodeToString()
|
||||
ownerEncodedID := ownerDisplayName
|
||||
|
||||
if settings.OwnerKey == nil {
|
||||
h.reqLogger(ctx).Warn(logs.BucketOwnerKeyIsMissing, zap.String("owner", bktInfo.Owner.String()))
|
||||
} else {
|
||||
ownerDisplayName = settings.OwnerKey.Address()
|
||||
ownerEncodedID = hex.EncodeToString(settings.OwnerKey.Bytes())
|
||||
}
|
||||
|
||||
res := &AccessControlPolicy{Owner: Owner{
|
||||
ID: ownerEncodedID,
|
||||
DisplayName: ownerDisplayName,
|
||||
}}
|
||||
|
||||
res.AccessControlList = []*Grant{{
|
||||
Grantee: &Grantee{
|
||||
ID: ownerEncodedID,
|
||||
DisplayName: ownerDisplayName,
|
||||
Type: acpCanonicalUser,
|
||||
},
|
||||
Permission: aclFullControl,
|
||||
}}
|
||||
|
||||
switch settings.CannedACL {
|
||||
case basicACLPublic:
|
||||
res.AccessControlList = append(res.AccessControlList, &Grant{
|
||||
Grantee: &Grantee{
|
||||
URI: allUsersGroup,
|
||||
Type: acpGroup,
|
||||
},
|
||||
Permission: aclWrite,
|
||||
})
|
||||
fallthrough
|
||||
case basicACLReadOnly:
|
||||
res.AccessControlList = append(res.AccessControlList, &Grant{
|
||||
Grantee: &Grantee{
|
||||
URI: allUsersGroup,
|
||||
Type: acpGroup,
|
||||
},
|
||||
Permission: aclRead,
|
||||
})
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (h *handler) bearerTokenIssuerKey(ctx context.Context) (*keys.PublicKey, error) {
|
||||
box, err := middleware.GetBoxData(ctx)
|
||||
if err != nil {
|
||||
|
@ -288,6 +350,24 @@ func (h *handler) bearerTokenIssuerKey(ctx context.Context) (*keys.PublicKey, er
|
|||
|
||||
func (h *handler) PutBucketACLHandler(w http.ResponseWriter, r *http.Request) {
|
||||
reqInfo := middleware.GetReqInfo(r.Context())
|
||||
|
||||
bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "could not get bucket info", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "couldn't get bucket settings", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
if bktInfo.APEEnabled || len(settings.CannedACL) != 0 {
|
||||
h.putBucketACLAPEHandler(w, r, reqInfo, bktInfo, settings)
|
||||
return
|
||||
}
|
||||
|
||||
key, err := h.bearerTokenIssuerKey(r.Context())
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "couldn't get bearer token issuer key", reqInfo, err)
|
||||
|
@ -319,12 +399,6 @@ func (h *handler) PutBucketACLHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "could not get bucket info", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = h.updateBucketACL(r, astBucket, bktInfo, token); err != nil {
|
||||
h.logAndSendError(w, "could not update bucket acl", reqInfo, err)
|
||||
return
|
||||
|
@ -332,6 +406,64 @@ func (h *handler) PutBucketACLHandler(w http.ResponseWriter, r *http.Request) {
|
|||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func (h *handler) putBucketACLAPEHandler(w http.ResponseWriter, r *http.Request, reqInfo *middleware.ReqInfo, bktInfo *data.BucketInfo, settings *data.BucketSettings) {
|
||||
ctx := r.Context()
|
||||
|
||||
defer func() {
|
||||
if errBody := r.Body.Close(); errBody != nil {
|
||||
h.reqLogger(r.Context()).Warn(logs.CouldNotCloseRequestBody, zap.Error(errBody))
|
||||
}
|
||||
}()
|
||||
|
||||
written, err := io.Copy(io.Discard, r.Body)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "couldn't read request body", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
if written != 0 || len(r.Header.Get(api.AmzACL)) == 0 {
|
||||
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
||||
return
|
||||
}
|
||||
|
||||
cannedACL, err := parseCannedACL(r.Header)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "could not parse canned ACL", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
key, err := h.bearerTokenIssuerKey(ctx)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "couldn't get bearer token issuer key", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
chainRules := bucketCannedACLToAPERules(cannedACL, reqInfo, key, bktInfo.CID)
|
||||
|
||||
target := engine.NamespaceTarget(reqInfo.Namespace)
|
||||
for _, chainPolicy := range chainRules {
|
||||
if err = h.ape.AddChain(target, chainPolicy); err != nil {
|
||||
h.logAndSendError(w, "failed to add morph rule chain", reqInfo, err, zap.String("chain_id", string(chainPolicy.ID)))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
settings.CannedACL = cannedACL
|
||||
|
||||
sp := &layer.PutSettingsParams{
|
||||
BktInfo: bktInfo,
|
||||
Settings: settings,
|
||||
}
|
||||
|
||||
if err = h.obj.PutBucketSettings(ctx, sp); err != nil {
|
||||
h.logAndSendError(w, "couldn't save bucket settings", reqInfo, err,
|
||||
zap.String("container_id", bktInfo.CID.EncodeToString()))
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func (h *handler) updateBucketACL(r *http.Request, astChild *ast, bktInfo *data.BucketInfo, sessionToken *session.Container) (bool, error) {
|
||||
bucketACL, err := h.obj.GetBucketACL(r.Context(), bktInfo)
|
||||
if err != nil {
|
||||
|
@ -380,6 +512,22 @@ func (h *handler) GetObjectACLHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
apeEnabled := bktInfo.APEEnabled
|
||||
|
||||
if !apeEnabled {
|
||||
settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "couldn't get bucket settings", reqInfo, err)
|
||||
return
|
||||
}
|
||||
apeEnabled = len(settings.CannedACL) != 0
|
||||
}
|
||||
|
||||
if apeEnabled {
|
||||
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
||||
return
|
||||
}
|
||||
|
||||
bucketACL, err := h.obj.GetBucketACL(ctx, bktInfo)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "could not fetch bucket acl", reqInfo, err)
|
||||
|
@ -406,6 +554,29 @@ func (h *handler) GetObjectACLHandler(w http.ResponseWriter, r *http.Request) {
|
|||
func (h *handler) PutObjectACLHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
reqInfo := middleware.GetReqInfo(ctx)
|
||||
|
||||
bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "could not get bucket info", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
apeEnabled := bktInfo.APEEnabled
|
||||
|
||||
if !apeEnabled {
|
||||
settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "couldn't get bucket settings", reqInfo, err)
|
||||
return
|
||||
}
|
||||
apeEnabled = len(settings.CannedACL) != 0
|
||||
}
|
||||
|
||||
if apeEnabled {
|
||||
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
||||
return
|
||||
}
|
||||
|
||||
versionID := reqInfo.URL.Query().Get(api.QueryVersionID)
|
||||
key, err := h.bearerTokenIssuerKey(ctx)
|
||||
if err != nil {
|
||||
|
@ -419,12 +590,6 @@ func (h *handler) PutObjectACLHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "could not get bucket info", reqInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
p := &layer.HeadObjectParams{
|
||||
BktInfo: bktInfo,
|
||||
Object: reqInfo.ObjectName,
|
||||
|
|
|
@ -16,9 +16,11 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||
s3errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
|
@ -1303,7 +1305,7 @@ func TestPutBucketACL(t *testing.T) {
|
|||
bktName := "bucket-for-acl"
|
||||
|
||||
box, _ := createAccessBox(t)
|
||||
bktInfo := createBucket(t, tc, bktName, box)
|
||||
bktInfo := createBucketOldACL(tc, bktName, box)
|
||||
|
||||
header := map[string]string{api.AmzACL: "public-read"}
|
||||
putBucketACL(t, tc, bktName, box, header)
|
||||
|
@ -1488,12 +1490,56 @@ func createAccessBox(t *testing.T) (*accessbox.Box, *keys.PrivateKey) {
|
|||
return box, key
|
||||
}
|
||||
|
||||
func createBucket(t *testing.T, hc *handlerContext, bktName string, box *accessbox.Box) *data.BucketInfo {
|
||||
func createBucket(hc *handlerContext, bktName string) (*data.BucketInfo, *accessbox.Box) {
|
||||
box, _ := createAccessBox(hc.t)
|
||||
|
||||
w := createBucketBase(hc, bktName, box)
|
||||
assertStatus(t, w, http.StatusOK)
|
||||
assertStatus(hc.t, w, http.StatusOK)
|
||||
|
||||
bktInfo, err := hc.Layer().GetBucketInfo(hc.Context(), bktName)
|
||||
require.NoError(t, err)
|
||||
require.NoError(hc.t, err)
|
||||
return bktInfo, box
|
||||
}
|
||||
|
||||
func createBucketOldACL(hc *handlerContext, bktName string, box *accessbox.Box) *data.BucketInfo {
|
||||
w := createBucketBase(hc, bktName, box)
|
||||
assertStatus(hc.t, w, http.StatusOK)
|
||||
|
||||
cnrID, err := hc.tp.ContainerID(bktName)
|
||||
require.NoError(hc.t, err)
|
||||
|
||||
cnr, err := hc.tp.Container(hc.Context(), cnrID)
|
||||
require.NoError(hc.t, err)
|
||||
cnr.SetBasicACL(acl.PublicRWExtended)
|
||||
cnr.SetAttribute(layer.AttributeAPEEnabled, "false")
|
||||
hc.tp.SetContainer(cnrID, cnr)
|
||||
table := eacl.NewTable()
|
||||
table.SetCID(cnrID)
|
||||
|
||||
key, err := hc.h.bearerTokenIssuerKey(hc.Context())
|
||||
require.NoError(hc.t, err)
|
||||
for _, op := range fullOps {
|
||||
table.AddRecord(getAllowRecord(op, key))
|
||||
}
|
||||
|
||||
for _, op := range fullOps {
|
||||
table.AddRecord(getOthersRecord(op, eacl.ActionDeny))
|
||||
}
|
||||
err = hc.tp.SetContainerEACL(hc.Context(), *table, nil)
|
||||
require.NoError(hc.t, err)
|
||||
|
||||
bktInfo, err := hc.Layer().GetBucketInfo(hc.Context(), bktName)
|
||||
require.NoError(hc.t, err)
|
||||
|
||||
settings, err := hc.tree.GetSettingsNode(hc.Context(), bktInfo)
|
||||
require.NoError(hc.t, err)
|
||||
settings.CannedACL = ""
|
||||
err = hc.Layer().PutBucketSettings(hc.Context(), &layer.PutSettingsParams{BktInfo: bktInfo, Settings: settings})
|
||||
require.NoError(hc.t, err)
|
||||
|
||||
bktInfo, err = hc.Layer().GetBucketInfo(hc.Context(), bktName)
|
||||
require.NoError(hc.t, err)
|
||||
|
||||
return bktInfo
|
||||
}
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ func TestDeleteDeletedObject(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("versioned bucket not found obj", func(t *testing.T) {
|
||||
bktName, objName := "bucket-versioned-for-removal", "object-to-delete"
|
||||
bktName, objName := "bucket-versioned-for-removal-not-found", "object-to-delete"
|
||||
_, objInfo := createVersionedBucketAndObject(t, tc, bktName, objName)
|
||||
|
||||
versionID, isDeleteMarker := deleteObject(t, tc, bktName, objName, objInfo.VersionID())
|
||||
|
|
|
@ -21,7 +21,6 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/resolver"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/tree"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
|
@ -267,15 +266,7 @@ func (a *apeMock) DeletePolicy(namespace string, cnrID cid.ID) error {
|
|||
}
|
||||
|
||||
func createTestBucket(hc *handlerContext, bktName string) *data.BucketInfo {
|
||||
_, err := hc.MockedPool().CreateContainer(hc.Context(), layer.PrmContainerCreate{
|
||||
Creator: hc.owner,
|
||||
Name: bktName,
|
||||
BasicACL: acl.PublicRWExtended,
|
||||
})
|
||||
require.NoError(hc.t, err)
|
||||
|
||||
bktInfo, err := hc.Layer().GetBucketInfo(hc.Context(), bktName)
|
||||
require.NoError(hc.t, err)
|
||||
bktInfo, _ := createBucket(hc, bktName)
|
||||
return bktInfo
|
||||
}
|
||||
|
||||
|
@ -297,11 +288,15 @@ func createTestBucketWithLock(hc *handlerContext, bktName string, conf *data.Obj
|
|||
HomomorphicHashDisabled: res.HomomorphicHashDisabled,
|
||||
}
|
||||
|
||||
key, err := keys.NewPrivateKey()
|
||||
require.NoError(hc.t, err)
|
||||
|
||||
sp := &layer.PutSettingsParams{
|
||||
BktInfo: bktInfo,
|
||||
Settings: &data.BucketSettings{
|
||||
Versioning: data.VersioningEnabled,
|
||||
LockConfiguration: conf,
|
||||
OwnerKey: key.PublicKey(),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -834,7 +834,11 @@ func (h *handler) CreateBucketHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
sp := &layer.PutSettingsParams{
|
||||
BktInfo: bktInfo,
|
||||
Settings: &data.BucketSettings{APE: true},
|
||||
Settings: &data.BucketSettings{
|
||||
CannedACL: cannedACL,
|
||||
OwnerKey: key,
|
||||
Versioning: data.VersioningUnversioned,
|
||||
},
|
||||
}
|
||||
|
||||
if p.ObjectLockEnabled {
|
||||
|
|
|
@ -372,8 +372,7 @@ func TestCreateBucket(t *testing.T) {
|
|||
hc := prepareHandlerContext(t)
|
||||
bktName := "bkt-name"
|
||||
|
||||
box, _ := createAccessBox(t)
|
||||
createBucket(t, hc, bktName, box)
|
||||
_, box := createBucket(hc, bktName)
|
||||
createBucketAssertS3Error(hc, bktName, box, s3errors.ErrBucketAlreadyOwnedByYou)
|
||||
|
||||
box2, _ := createAccessBox(t)
|
||||
|
|
|
@ -28,7 +28,7 @@ type (
|
|||
|
||||
const (
|
||||
attributeLocationConstraint = ".s3-location-constraint"
|
||||
attributeAPEEnabled = ".s3-APE-enabled"
|
||||
AttributeAPEEnabled = ".s3-APE-enabled"
|
||||
AttributeLockEnabled = "LockEnabled"
|
||||
)
|
||||
|
||||
|
@ -75,7 +75,7 @@ func (n *layer) containerInfo(ctx context.Context, idCnr cid.ID) (*data.BucketIn
|
|||
}
|
||||
}
|
||||
|
||||
APEEnabled := cnr.Attribute(attributeAPEEnabled)
|
||||
APEEnabled := cnr.Attribute(AttributeAPEEnabled)
|
||||
if len(APEEnabled) > 0 {
|
||||
info.APEEnabled, err = strconv.ParseBool(APEEnabled)
|
||||
if err != nil {
|
||||
|
@ -136,7 +136,7 @@ func (n *layer) createContainer(ctx context.Context, p *CreateBucketParams) (*da
|
|||
|
||||
attributes := [][2]string{
|
||||
{attributeLocationConstraint, p.LocationConstraint},
|
||||
{attributeAPEEnabled, "true"},
|
||||
{AttributeAPEEnabled, "true"},
|
||||
}
|
||||
|
||||
if p.ObjectLockEnabled {
|
||||
|
|
|
@ -136,6 +136,10 @@ func (t *TestFrostFS) ContainerID(name string) (cid.ID, error) {
|
|||
return cid.ID{}, fmt.Errorf("not found")
|
||||
}
|
||||
|
||||
func (t *TestFrostFS) SetContainer(cnrID cid.ID, cnr *container.Container) {
|
||||
t.containers[cnrID.EncodeToString()] = cnr
|
||||
}
|
||||
|
||||
func (t *TestFrostFS) CreateContainer(_ context.Context, prm PrmContainerCreate) (*ContainerCreateResult, error) {
|
||||
var cnr container.Container
|
||||
cnr.Init()
|
||||
|
|
|
@ -142,4 +142,7 @@ const (
|
|||
CouldntPutAccessBoxIntoCache = "couldn't put accessbox into cache"
|
||||
InvalidAccessBoxCacheRemovingCheckInterval = "invalid accessbox check removing interval, using default value"
|
||||
CouldNotParseContainerAPEEnabledAttribute = "could not parse container APE enabled attribute"
|
||||
CouldNotCloseRequestBody = "could not close request body"
|
||||
BucketOwnerKeyIsMissing = "bucket owner key is missing"
|
||||
SettingsNodeInvalidOwnerKey = "settings node: invalid owner key"
|
||||
)
|
||||
|
|
|
@ -2,6 +2,7 @@ package tree
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -16,6 +17,7 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
@ -78,7 +80,8 @@ var (
|
|||
|
||||
const (
|
||||
versioningKV = "Versioning"
|
||||
apeKV = "APE"
|
||||
cannedACLKV = "cannedACL"
|
||||
ownerKeyKV = "ownerKey"
|
||||
lockConfigurationKV = "LockConfiguration"
|
||||
oidKV = "OID"
|
||||
|
||||
|
@ -333,7 +336,7 @@ func newPartInfo(node NodeResponse) (*data.PartInfo, error) {
|
|||
}
|
||||
|
||||
func (c *Tree) GetSettingsNode(ctx context.Context, bktInfo *data.BucketInfo) (*data.BucketSettings, error) {
|
||||
keysToReturn := []string{versioningKV, lockConfigurationKV, apeKV}
|
||||
keysToReturn := []string{versioningKV, lockConfigurationKV, cannedACLKV, ownerKeyKV}
|
||||
node, err := c.getSystemNode(ctx, bktInfo, []string{settingsFileName}, keysToReturn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't get node: %w", err)
|
||||
|
@ -350,8 +353,12 @@ func (c *Tree) GetSettingsNode(ctx context.Context, bktInfo *data.BucketInfo) (*
|
|||
}
|
||||
}
|
||||
|
||||
if ape, ok := node.Get(apeKV); ok {
|
||||
settings.APE, _ = strconv.ParseBool(ape)
|
||||
settings.CannedACL, _ = node.Get(cannedACLKV)
|
||||
|
||||
if ownerKeyHex, ok := node.Get(ownerKeyKV); ok {
|
||||
if settings.OwnerKey, err = keys.NewPublicKeyFromString(ownerKeyHex); err != nil {
|
||||
c.reqLogger(ctx).Error(logs.SettingsNodeInvalidOwnerKey, zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
return settings, nil
|
||||
|
@ -1389,7 +1396,8 @@ func metaFromSettings(settings *data.BucketSettings) map[string]string {
|
|||
results[FileNameKey] = settingsFileName
|
||||
results[versioningKV] = settings.Versioning
|
||||
results[lockConfigurationKV] = encodeLockConfiguration(settings.LockConfiguration)
|
||||
results[apeKV] = strconv.FormatBool(settings.APE)
|
||||
results[cannedACLKV] = settings.CannedACL
|
||||
results[ownerKeyKV] = hex.EncodeToString(settings.OwnerKey.Bytes())
|
||||
|
||||
return results
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
||||
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
|
||||
usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/zap/zaptest"
|
||||
)
|
||||
|
@ -111,6 +112,9 @@ func TestTreeServiceSettings(t *testing.T) {
|
|||
CID: cidtest.ID(),
|
||||
}
|
||||
|
||||
key, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
settings := &data.BucketSettings{
|
||||
Versioning: "Versioning",
|
||||
LockConfiguration: &data.ObjectLockConfiguration{
|
||||
|
@ -122,6 +126,7 @@ func TestTreeServiceSettings(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
OwnerKey: key.PublicKey(),
|
||||
}
|
||||
|
||||
err = treeService.PutSettingsNode(ctx, bktInfo, settings)
|
||||
|
|
Loading…
Reference in a new issue