diff --git a/CHANGELOG.md b/CHANGELOG.md index 11e6e67..767cdb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ This document outlines major changes between releases. - Don't create unnecessary delete-markers (#83) ### Added +- Add `copies_numbers` section to `placement_policy` in config file and support vectors of copies numbers (#70) - Return `X-Owner-Id` in `head-bucket` response (#79) - Return container name in `head-bucket` response (TrueCloudLab#18) - Billing metrics (TrueCloudLab#5) diff --git a/api/data/tree.go b/api/data/tree.go index dbcb245..e24d7d8 100644 --- a/api/data/tree.go +++ b/api/data/tree.go @@ -68,13 +68,13 @@ type ObjectTaggingInfo struct { type MultipartInfo struct { // ID is node id in tree service. // It's ignored when creating a new multipart upload. - ID uint64 - Key string - UploadID string - Owner user.ID - Created time.Time - Meta map[string]string - CopiesNumber uint32 + ID uint64 + Key string + UploadID string + Owner user.ID + Created time.Time + Meta map[string]string + CopiesNumbers []uint32 } // PartInfo is upload information about part. diff --git a/api/handler/api.go b/api/handler/api.go index f16e1ca..59810ab 100644 --- a/api/handler/api.go +++ b/api/handler/api.go @@ -3,7 +3,10 @@ package handler import ( "encoding/xml" "errors" + "fmt" "io" + "strconv" + "strings" "time" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api" @@ -32,6 +35,7 @@ type ( DefaultMaxAge int NotificatorEnabled bool CopiesNumber uint32 + CopiesNumbers map[string][]uint32 ResolveZoneList []string IsResolveListAllow bool // True if ResolveZoneList contains allowed zones CompleteMultipartKeepalive time.Duration @@ -78,3 +82,44 @@ func New(log *zap.Logger, obj layer.Client, notificator Notificator, cfg *Config notificator: notificator, }, nil } + +// pickCopiesNumbers chooses the return values following this logic: +// 1) array of copies numbers sent in request's header has the highest priority +// 2) array of copies numbers with corresponding location constraint provided in the config file +// 3) default copies number from the config file wrapped into array +func (h *handler) pickCopiesNumbers(metadata map[string]string, locationConstraint string) ([]uint32, error) { + copiesNumbersStr, ok := metadata[layer.AttributeFrostfsCopiesNumber] + if ok { + result, err := parseCopiesNumbers(copiesNumbersStr) + if err != nil { + return nil, err + } + return result, nil + } + + copiesNumbers, ok := h.cfg.CopiesNumbers[locationConstraint] + if ok { + return copiesNumbers, nil + } + + return []uint32{h.cfg.CopiesNumber}, nil +} + +func parseCopiesNumbers(copiesNumbersStr string) ([]uint32, error) { + var result []uint32 + copiesNumbersSplit := strings.Split(copiesNumbersStr, ",") + + for i := range copiesNumbersSplit { + item := strings.ReplaceAll(copiesNumbersSplit[i], " ", "") + if len(item) == 0 { + continue + } + copiesNumber, err := strconv.ParseUint(item, 10, 32) + if err != nil { + return nil, fmt.Errorf("pasrse copies number: %w", err) + } + result = append(result, uint32(copiesNumber)) + } + + return result, nil +} diff --git a/api/handler/api_test.go b/api/handler/api_test.go new file mode 100644 index 0000000..46ed8c8 --- /dev/null +++ b/api/handler/api_test.go @@ -0,0 +1,69 @@ +package handler + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestCopiesNumberPicker(t *testing.T) { + var locConstraints = map[string][]uint32{} + locationConstraint1 := "one" + locationConstraint2 := "two" + locConstraints[locationConstraint1] = []uint32{2, 3, 4} + + config := &Config{ + CopiesNumber: 1, + CopiesNumbers: locConstraints, + } + h := handler{ + cfg: config, + } + + metadata := map[string]string{} + + t.Run("pick default copies number", func(t *testing.T) { + metadata["somekey1"] = "5, 6, 7" + expectedCopiesNumbers := []uint32{1} + + actualCopiesNumbers, err := h.pickCopiesNumbers(metadata, locationConstraint2) + require.NoError(t, err) + require.Equal(t, expectedCopiesNumbers, actualCopiesNumbers) + }) + + t.Run("pick copies number vector according to location constraint", func(t *testing.T) { + metadata["somekey2"] = "6, 7, 8" + expectedCopiesNumbers := []uint32{2, 3, 4} + + actualCopiesNumbers, err := h.pickCopiesNumbers(metadata, locationConstraint1) + require.NoError(t, err) + require.Equal(t, expectedCopiesNumbers, actualCopiesNumbers) + }) + + t.Run("pick copies number from metadata", func(t *testing.T) { + metadata["frostfs-copies-number"] = "7, 8, 9" + expectedCopiesNumbers := []uint32{7, 8, 9} + + actualCopiesNumbers, err := h.pickCopiesNumbers(metadata, locationConstraint2) + require.NoError(t, err) + require.Equal(t, expectedCopiesNumbers, actualCopiesNumbers) + }) + + t.Run("pick copies number from metadata with no space", func(t *testing.T) { + metadata["frostfs-copies-number"] = "7,8,9" + expectedCopiesNumbers := []uint32{7, 8, 9} + + actualCopiesNumbers, err := h.pickCopiesNumbers(metadata, locationConstraint2) + require.NoError(t, err) + require.Equal(t, expectedCopiesNumbers, actualCopiesNumbers) + }) + + t.Run("pick copies number from metadata with trailing comma", func(t *testing.T) { + metadata["frostfs-copies-number"] = "11, 12, 13, " + expectedCopiesNumbers := []uint32{11, 12, 13} + + actualCopiesNumbers, err := h.pickCopiesNumbers(metadata, locationConstraint2) + require.NoError(t, err) + require.Equal(t, expectedCopiesNumbers, actualCopiesNumbers) + }) +} diff --git a/api/handler/copy.go b/api/handler/copy.go index 1238843..67b7d45 100644 --- a/api/handler/copy.go +++ b/api/handler/copy.go @@ -167,23 +167,22 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) { metadata[api.ContentType] = contentType } - copiesNumber, err := getCopiesNumberOrDefault(metadata, h.cfg.CopiesNumber) + params := &layer.CopyObjectParams{ + SrcObject: srcObjInfo, + ScrBktInfo: srcObjPrm.BktInfo, + DstBktInfo: dstBktInfo, + DstObject: reqInfo.ObjectName, + SrcSize: srcObjInfo.Size, + Header: metadata, + Encryption: encryptionParams, + } + + params.CopiesNumbers, err = h.pickCopiesNumbers(metadata, dstBktInfo.LocationConstraint) if err != nil { h.logAndSendError(w, "invalid copies number", reqInfo, err) return } - params := &layer.CopyObjectParams{ - SrcObject: srcObjInfo, - ScrBktInfo: srcObjPrm.BktInfo, - DstBktInfo: dstBktInfo, - DstObject: reqInfo.ObjectName, - SrcSize: srcObjInfo.Size, - Header: metadata, - Encryption: encryptionParams, - CopiesNuber: copiesNumber, - } - params.Lock, err = formObjectLock(r.Context(), dstBktInfo, settings.LockConfiguration, r.Header) if err != nil { h.logAndSendError(w, "could not form object lock", reqInfo, err) diff --git a/api/handler/cors.go b/api/handler/cors.go index 841a2e3..962a78b 100644 --- a/api/handler/cors.go +++ b/api/handler/cors.go @@ -48,9 +48,14 @@ func (h *handler) PutBucketCorsHandler(w http.ResponseWriter, r *http.Request) { } p := &layer.PutCORSParams{ - BktInfo: bktInfo, - Reader: r.Body, - CopiesNumber: h.cfg.CopiesNumber, + BktInfo: bktInfo, + Reader: r.Body, + } + + p.CopiesNumbers, err = h.pickCopiesNumbers(parseMetadata(r), bktInfo.LocationConstraint) + if err != nil { + h.logAndSendError(w, "invalid copies number", reqInfo, err) + return } if err = h.obj.PutBucketCORS(r.Context(), p); err != nil { diff --git a/api/handler/locking.go b/api/handler/locking.go index e659712..881e97d 100644 --- a/api/handler/locking.go +++ b/api/handler/locking.go @@ -143,7 +143,12 @@ func (h *handler) PutObjectLegalHoldHandler(w http.ResponseWriter, r *http.Reque Enabled: legalHold.Status == legalHoldOn, }, }, - CopiesNumber: h.cfg.CopiesNumber, + } + + p.CopiesNumbers, err = h.pickCopiesNumbers(parseMetadata(r), bktInfo.LocationConstraint) + if err != nil { + h.logAndSendError(w, "invalid copies number", reqInfo, err) + return } if err = h.obj.PutLockInfo(r.Context(), p); err != nil { @@ -221,8 +226,13 @@ func (h *handler) PutObjectRetentionHandler(w http.ResponseWriter, r *http.Reque ObjectName: reqInfo.ObjectName, VersionID: reqInfo.URL.Query().Get(api.QueryVersionID), }, - NewLock: lock, - CopiesNumber: h.cfg.CopiesNumber, + NewLock: lock, + } + + p.CopiesNumbers, err = h.pickCopiesNumbers(parseMetadata(r), bktInfo.LocationConstraint) + if err != nil { + h.logAndSendError(w, "invalid copies number", reqInfo, err) + return } if err = h.obj.PutLockInfo(r.Context(), p); err != nil { diff --git a/api/handler/multipart_upload.go b/api/handler/multipart_upload.go index f0b36ab..1db3bd5 100644 --- a/api/handler/multipart_upload.go +++ b/api/handler/multipart_upload.go @@ -149,7 +149,7 @@ func (h *handler) CreateMultipartUploadHandler(w http.ResponseWriter, r *http.Re p.Header[api.ContentType] = contentType } - p.CopiesNumber, err = getCopiesNumberOrDefault(p.Header, h.cfg.CopiesNumber) + p.CopiesNumbers, err = h.pickCopiesNumbers(p.Header, bktInfo.LocationConstraint) if err != nil { h.logAndSendError(w, "invalid copies number", reqInfo, err) return diff --git a/api/handler/notifications.go b/api/handler/notifications.go index 1cdf0e9..adb6754 100644 --- a/api/handler/notifications.go +++ b/api/handler/notifications.go @@ -118,7 +118,12 @@ func (h *handler) PutBucketNotificationHandler(w http.ResponseWriter, r *http.Re RequestInfo: reqInfo, BktInfo: bktInfo, Configuration: conf, - CopiesNumber: h.cfg.CopiesNumber, + } + + p.CopiesNumbers, err = h.pickCopiesNumbers(parseMetadata(r), bktInfo.LocationConstraint) + if err != nil { + h.logAndSendError(w, "invalid copies number", reqInfo, err) + return } if err = h.obj.PutBucketNotificationConfiguration(r.Context(), p); err != nil { diff --git a/api/handler/put.go b/api/handler/put.go index 3acd183..643d7ef 100644 --- a/api/handler/put.go +++ b/api/handler/put.go @@ -212,12 +212,6 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) { metadata[api.Expires] = expires } - copiesNumber, err := getCopiesNumberOrDefault(metadata, h.cfg.CopiesNumber) - if err != nil { - h.logAndSendError(w, "invalid copies number", reqInfo, err) - return - } - encryptionParams, err := formEncryptionParams(r) if err != nil { h.logAndSendError(w, "invalid sse headers", reqInfo, err) @@ -225,13 +219,18 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) { } params := &layer.PutObjectParams{ - BktInfo: bktInfo, - Object: reqInfo.ObjectName, - Reader: r.Body, - Size: r.ContentLength, - Header: metadata, - Encryption: encryptionParams, - CopiesNumber: copiesNumber, + BktInfo: bktInfo, + Object: reqInfo.ObjectName, + Reader: r.Body, + Size: r.ContentLength, + Header: metadata, + Encryption: encryptionParams, + } + + params.CopiesNumbers, err = h.pickCopiesNumbers(metadata, bktInfo.LocationConstraint) + if err != nil { + h.logAndSendError(w, "invalid copies number", reqInfo, err) + return } settings, err := h.obj.GetBucketSettings(r.Context(), bktInfo) @@ -312,20 +311,6 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) { api.WriteSuccessResponseHeadersOnly(w) } -func getCopiesNumberOrDefault(metadata map[string]string, defaultCopiesNumber uint32) (uint32, error) { - copiesNumberStr, ok := metadata[layer.AttributeFrostfsCopiesNumber] - if !ok { - return defaultCopiesNumber, nil - } - - copiesNumber, err := strconv.ParseUint(copiesNumberStr, 10, 32) - if err != nil { - return 0, fmt.Errorf("pasrse copies number: %w", err) - } - - return uint32(copiesNumber), nil -} - func formEncryptionParams(r *http.Request) (enc encryption.Params, err error) { sseCustomerAlgorithm := r.Header.Get(api.AmzServerSideEncryptionCustomerAlgorithm) sseCustomerKey := r.Header.Get(api.AmzServerSideEncryptionCustomerKey) diff --git a/api/layer/cors.go b/api/layer/cors.go index 8a76833..cad882d 100644 --- a/api/layer/cors.go +++ b/api/layer/cors.go @@ -42,7 +42,7 @@ func (n *layer) PutBucketCORS(ctx context.Context, p *PutCORSParams) error { Payload: &buf, Filepath: p.BktInfo.CORSObjectName(), CreationTime: TimeNow(ctx), - CopiesNumber: p.CopiesNumber, + CopiesNumber: p.CopiesNumbers, } objID, _, err := n.objectPutAndHash(ctx, prm, p.BktInfo) diff --git a/api/layer/frostfs.go b/api/layer/frostfs.go index d24bc2c..d22279a 100644 --- a/api/layer/frostfs.go +++ b/api/layer/frostfs.go @@ -113,7 +113,7 @@ type PrmObjectCreate struct { Payload io.Reader // Number of object copies that is enough to consider put successful. - CopiesNumber uint32 + CopiesNumber []uint32 } // PrmObjectDelete groups parameters of FrostFS.DeleteObject operation. diff --git a/api/layer/layer.go b/api/layer/layer.go index 72505d5..508505a 100644 --- a/api/layer/layer.go +++ b/api/layer/layer.go @@ -99,14 +99,14 @@ type ( // PutObjectParams stores object put request parameters. PutObjectParams struct { - BktInfo *data.BucketInfo - Object string - Size int64 - Reader io.Reader - Header map[string]string - Lock *data.ObjectLock - Encryption encryption.Params - CopiesNumber uint32 + BktInfo *data.BucketInfo + Object string + Size int64 + Reader io.Reader + Header map[string]string + Lock *data.ObjectLock + Encryption encryption.Params + CopiesNumbers []uint32 } DeleteObjectParams struct { @@ -123,23 +123,23 @@ type ( // PutCORSParams stores PutCORS request parameters. PutCORSParams struct { - BktInfo *data.BucketInfo - Reader io.Reader - CopiesNumber uint32 + BktInfo *data.BucketInfo + Reader io.Reader + CopiesNumbers []uint32 } // CopyObjectParams stores object copy request parameters. CopyObjectParams struct { - SrcObject *data.ObjectInfo - ScrBktInfo *data.BucketInfo - DstBktInfo *data.BucketInfo - DstObject string - SrcSize int64 - Header map[string]string - Range *RangeParams - Lock *data.ObjectLock - Encryption encryption.Params - CopiesNuber uint32 + SrcObject *data.ObjectInfo + ScrBktInfo *data.BucketInfo + DstBktInfo *data.BucketInfo + DstObject string + SrcSize int64 + Header map[string]string + Range *RangeParams + Lock *data.ObjectLock + Encryption encryption.Params + CopiesNumbers []uint32 } // CreateBucketParams stores bucket create request parameters. CreateBucketParams struct { @@ -524,13 +524,13 @@ func (n *layer) CopyObject(ctx context.Context, p *CopyObjectParams) (*data.Exte }() return n.PutObject(ctx, &PutObjectParams{ - BktInfo: p.DstBktInfo, - Object: p.DstObject, - Size: p.SrcSize, - Reader: pr, - Header: p.Header, - Encryption: p.Encryption, - CopiesNumber: p.CopiesNuber, + BktInfo: p.DstBktInfo, + Object: p.DstObject, + Size: p.SrcSize, + Reader: pr, + Header: p.Header, + Encryption: p.Encryption, + CopiesNumbers: p.CopiesNumbers, }) } diff --git a/api/layer/locking_test.go b/api/layer/locking_test.go index d465c1a..94ff1f2 100644 --- a/api/layer/locking_test.go +++ b/api/layer/locking_test.go @@ -30,7 +30,7 @@ func TestObjectLockAttributes(t *testing.T) { Until: time.Now(), }, }, - CopiesNumber: 0, + CopiesNumbers: []uint32{0}, } err = tc.layer.PutLockInfo(tc.ctx, p) diff --git a/api/layer/multipart_upload.go b/api/layer/multipart_upload.go index 7fec347..322f55c 100644 --- a/api/layer/multipart_upload.go +++ b/api/layer/multipart_upload.go @@ -46,10 +46,10 @@ type ( } CreateMultipartParams struct { - Info *UploadInfoParams - Header map[string]string - Data *UploadData - CopiesNumber uint32 + Info *UploadInfoParams + Header map[string]string + Data *UploadData + CopiesNumbers []uint32 } UploadData struct { @@ -141,12 +141,12 @@ func (n *layer) CreateMultipartUpload(ctx context.Context, p *CreateMultipartPar } info := &data.MultipartInfo{ - Key: p.Info.Key, - UploadID: p.Info.UploadID, - Owner: n.Owner(ctx), - Created: TimeNow(ctx), - Meta: make(map[string]string, metaSize), - CopiesNumber: p.CopiesNumber, + Key: p.Info.Key, + UploadID: p.Info.UploadID, + Owner: n.Owner(ctx), + Created: TimeNow(ctx), + Meta: make(map[string]string, metaSize), + CopiesNumbers: p.CopiesNumbers, } for key, val := range p.Header { @@ -207,7 +207,7 @@ func (n *layer) uploadPart(ctx context.Context, multipartInfo *data.MultipartInf Attributes: make([][2]string, 2), Payload: p.Reader, CreationTime: TimeNow(ctx), - CopiesNumber: multipartInfo.CopiesNumber, + CopiesNumber: multipartInfo.CopiesNumbers, } decSize := p.Size @@ -443,13 +443,13 @@ func (n *layer) CompleteMultipartUpload(ctx context.Context, p *CompleteMultipar r.prm.bktInfo = p.Info.Bkt extObjInfo, err := n.PutObject(ctx, &PutObjectParams{ - BktInfo: p.Info.Bkt, - Object: p.Info.Key, - Reader: r, - Header: initMetadata, - Size: multipartObjetSize, - Encryption: p.Info.Encryption, - CopiesNumber: multipartInfo.CopiesNumber, + BktInfo: p.Info.Bkt, + Object: p.Info.Key, + Reader: r, + Header: initMetadata, + Size: multipartObjetSize, + Encryption: p.Info.Encryption, + CopiesNumbers: multipartInfo.CopiesNumbers, }) if err != nil { n.log.Error("could not put a completed object (multipart upload)", diff --git a/api/layer/notifications.go b/api/layer/notifications.go index b47cdb6..3b6a9cf 100644 --- a/api/layer/notifications.go +++ b/api/layer/notifications.go @@ -16,7 +16,7 @@ type PutBucketNotificationConfigurationParams struct { RequestInfo *api.ReqInfo BktInfo *data.BucketInfo Configuration *data.NotificationConfiguration - CopiesNumber uint32 + CopiesNumbers []uint32 } func (n *layer) PutBucketNotificationConfiguration(ctx context.Context, p *PutBucketNotificationConfigurationParams) error { @@ -31,7 +31,7 @@ func (n *layer) PutBucketNotificationConfiguration(ctx context.Context, p *PutBu Payload: bytes.NewReader(confXML), Filepath: p.BktInfo.NotificationConfigurationObjectName(), CreationTime: TimeNow(ctx), - CopiesNumber: p.CopiesNumber, + CopiesNumber: p.CopiesNumbers, } objID, _, err := n.objectPutAndHash(ctx, prm, p.BktInfo) diff --git a/api/layer/object.go b/api/layer/object.go index e2c6f35..7dda084 100644 --- a/api/layer/object.go +++ b/api/layer/object.go @@ -234,7 +234,7 @@ func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*data.Extend Filepath: p.Object, Payload: r, CreationTime: TimeNow(ctx), - CopiesNumber: p.CopiesNumber, + CopiesNumber: p.CopiesNumbers, } prm.Attributes = make([][2]string, 0, len(p.Header)) @@ -267,9 +267,9 @@ func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*data.Extend ObjectName: p.Object, VersionID: id.EncodeToString(), }, - NewLock: p.Lock, - CopiesNumber: p.CopiesNumber, - NodeVersion: newVersion, // provide new version to make one less tree service call in PutLockInfo + NewLock: p.Lock, + CopiesNumbers: p.CopiesNumbers, + NodeVersion: newVersion, // provide new version to make one less tree service call in PutLockInfo } if err = n.PutLockInfo(ctx, putLockInfoPrms); err != nil { diff --git a/api/layer/system_object.go b/api/layer/system_object.go index 29e7654..3e5d41d 100644 --- a/api/layer/system_object.go +++ b/api/layer/system_object.go @@ -20,10 +20,10 @@ const ( ) type PutLockInfoParams struct { - ObjVersion *ObjectVersion - NewLock *data.ObjectLock - CopiesNumber uint32 - NodeVersion *data.NodeVersion // optional + ObjVersion *ObjectVersion + NewLock *data.ObjectLock + CopiesNumbers []uint32 + NodeVersion *data.NodeVersion // optional } func (n *layer) PutLockInfo(ctx context.Context, p *PutLockInfoParams) (err error) { @@ -68,7 +68,7 @@ func (n *layer) PutLockInfo(ctx context.Context, p *PutLockInfoParams) (err erro } } lock := &data.ObjectLock{Retention: newLock.Retention} - retentionOID, err := n.putLockObject(ctx, p.ObjVersion.BktInfo, versionNode.OID, lock, p.CopiesNumber) + retentionOID, err := n.putLockObject(ctx, p.ObjVersion.BktInfo, versionNode.OID, lock, p.CopiesNumbers) if err != nil { return err } @@ -78,7 +78,7 @@ func (n *layer) PutLockInfo(ctx context.Context, p *PutLockInfoParams) (err erro if newLock.LegalHold != nil { if newLock.LegalHold.Enabled && !lockInfo.IsLegalHoldSet() { lock := &data.ObjectLock{LegalHold: newLock.LegalHold} - legalHoldOID, err := n.putLockObject(ctx, p.ObjVersion.BktInfo, versionNode.OID, lock, p.CopiesNumber) + legalHoldOID, err := n.putLockObject(ctx, p.ObjVersion.BktInfo, versionNode.OID, lock, p.CopiesNumbers) if err != nil { return err } @@ -111,7 +111,7 @@ func (n *layer) getNodeVersionFromCacheOrFrostfs(ctx context.Context, objVersion return nodeVersion, nil } -func (n *layer) putLockObject(ctx context.Context, bktInfo *data.BucketInfo, objID oid.ID, lock *data.ObjectLock, copiesNumber uint32) (oid.ID, error) { +func (n *layer) putLockObject(ctx context.Context, bktInfo *data.BucketInfo, objID oid.ID, lock *data.ObjectLock, copiesNumber []uint32) (oid.ID, error) { prm := PrmObjectCreate{ Container: bktInfo.CID, Creator: bktInfo.Owner, diff --git a/cmd/s3-gw/app.go b/cmd/s3-gw/app.go index 5d832e8..0c3a035 100644 --- a/cmd/s3-gw/app.go +++ b/cmd/s3-gw/app.go @@ -652,6 +652,8 @@ func (a *App) initHandler() { cfg.DefaultMaxAge = defaultMaxAge } + cfg.CopiesNumbers = fetchCopiesNumbers(a.log, a.cfg) + if val := a.cfg.GetUint32(cfgSetCopiesNumber); val > 0 { cfg.CopiesNumber = val } diff --git a/cmd/s3-gw/app_settings.go b/cmd/s3-gw/app_settings.go index f97e397..d750546 100644 --- a/cmd/s3-gw/app_settings.go +++ b/cmd/s3-gw/app_settings.go @@ -83,6 +83,7 @@ const ( // Settings. // Policy. cfgPolicyDefault = "placement_policy.default" cfgPolicyRegionMapFile = "placement_policy.region_mapping" + cfgCopiesNumbers = "placement_policy.copies_numbers" // CORS. cfgDefaultMaxAge = "cors.default_max_age" @@ -151,6 +152,34 @@ var ignore = map[string]struct{}{ cmdVersion: {}, } +func fetchCopiesNumbers(l *zap.Logger, v *viper.Viper) map[string][]uint32 { + var copiesNums = make(map[string][]uint32) +LOOP: + for i := 0; ; i++ { + key := cfgCopiesNumbers + "." + strconv.Itoa(i) + "." + constraint := v.GetString(key + "location_constraint") + vector := v.GetStringSlice(key + "vector") + + vector32 := make([]uint32, len(vector)) + for j := range vector { + parsedValue, err := strconv.ParseUint(vector[j], 10, 32) + if err != nil { + l.Error("cannot parse copies numbers", zap.Error(err)) + break LOOP + } + vector32[j] = uint32(parsedValue) + } + + if constraint == "" || len(vector) == 0 { + break + } + + copiesNums[constraint] = vector32 + l.Debug("added constraint", zap.String("location", constraint), zap.Strings("copies numbers", vector)) + } + return copiesNums +} + func fetchPeers(l *zap.Logger, v *viper.Viper) []pool.NodeParam { var nodes []pool.NodeParam for i := 0; ; i++ { diff --git a/config/config.env b/config/config.env index ba690f3..0a2282c 100644 --- a/config/config.env +++ b/config/config.env @@ -111,6 +111,14 @@ S3_GW_PLACEMENT_POLICY_DEFAULT_POLICY="REP 3" # Path to container policy mapping. The same as '--container-policy' flag for authmate S3_GW_PLACEMENT_POLICY_REGION_MAPPING=/path/to/container/policy.json +# Name of location constraint +S3_GW_PLACEMENT_POLICY_COPIES_NUMBERS_0_LOCATION_CONSTRAINT=sample-01 +# Array of copies numbers for corresponding location constraint +S3_GW_PLACEMENT_POLICY_COPIES_NUMBERS_0_VECTOR=1 2 3 +# Second set of location constraint and its copies numbers +S3_GW_PLACEMENT_POLICY_COPIES_NUMBERS_1_LOCATION_CONSTRAINT=sample-02 +S3_GW_PLACEMENT_POLICY_COPIES_NUMBERS_1_VECTOR=2 3 4 + # CORS # value of Access-Control-Max-Age header if this value is not set in a rule. Has an int type. S3_GW_CORS_DEFAULT_MAX_AGE=600 diff --git a/config/config.yaml b/config/config.yaml index a4e292f..e5f72d6 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -129,6 +129,17 @@ placement_policy: # Region to placement policy mapping json file. # Path to container policy mapping. The same as '--container-policy' flag for authmate region_mapping: /path/to/container/policy.json + # Array of locations constraints and their vectors of copies numbers + copies_numbers: + - location_constraint: sample-01 + vector: + - 1 + - 2 + - location_constraint: sample-02 + vector: + - 1 + - 2 + - 3 # CORS # value of Access-Control-Max-Age header if this value is not set in a rule. Has an int type. diff --git a/docs/configuration.md b/docs/configuration.md index 35d1852..454dd36 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -279,12 +279,19 @@ peers: placement_policy: default: REP 3 region_mapping: /path/to/mapping/rules.json + copies_numbers: + - location_constraint: one-dc + vector: + - 1 + - 2 + - 3 ``` -| Parameter | Type | SIGHUP reload | Default value | Description | -|------------------|----------|---------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `default` | `string` | yes | `REP 3` | Default policy of placing containers in FrostFS. If a user sends a request `CreateBucket` and doesn't define policy for placing of a container in FrostFS, the S3 Gateway will put the container with default policy. | -| `region_mapping` | `string` | yes | | Path to file that maps aws `LocationContraint` values to FrostFS placement policy. The similar to `--container-policy` flag in `frostfs-s3-authmate` util, see in [docs](./authmate.md#containers-policy) | +| Parameter | Type | SIGHUP reload | Default value | Description | +|------------------|------------------------------------------------|---------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `default` | `string` | yes | `REP 3` | Default policy of placing containers in FrostFS. If a user sends a request `CreateBucket` and doesn't define policy for placing of a container in FrostFS, the S3 Gateway will put the container with default policy. | +| `region_mapping` | `string` | yes | | Path to file that maps aws `LocationContraint` values to FrostFS placement policy. The similar to `--container-policy` flag in `frostfs-s3-authmate` util, see in [docs](./authmate.md#containers-policy) | +| `copies_numbers` | [[]Copies numbers](#copies_numbers-subsection) | no | | Array of configured location constraints and their copies numbers. | File for `region_mapping` must contain something like this: @@ -299,6 +306,22 @@ File for `region_mapping` must contain something like this: **Note:** on SIGHUP reload policies will be updated only if both parameters are valid. So if you change `default` to some valid value and set invalid path in `region_mapping` the `default` value won't be changed. +#### `copies_numbers` subsection + +```yaml +- location_constraint: sample-01 + vector: + - 1 + - 2 + - 3 +``` + +| Parameter | Type | SIGHUP reload | Default value | Description | +|-----------------------|----------|---------------|---------------|----------------------------------------------------------| +| `location_constraint` | `string` | no | | Location constraint text label. | +| `vector` | `[]int` | no | | Array of copies numbers corresponding to the constraint. | + + ### `server` section You can specify several listeners for server. For example, for `http` and `https`. diff --git a/go.mod b/go.mod index f2571f7..ce68be2 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module git.frostfs.info/TrueCloudLab/frostfs-s3-gw go 1.18 require ( - git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.11.2-0.20230315095236-9dc375346703 + git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.15.1-0.20230418080822-bd44a3f47b85 git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 - git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20230329125804-552219b8e130 + git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20230420104105-d0762d037d2c github.com/aws/aws-sdk-go v1.44.6 github.com/bluele/gcache v0.0.2 github.com/google/uuid v1.3.0 @@ -18,11 +18,11 @@ require ( github.com/prometheus/client_model v0.2.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.15.0 - github.com/stretchr/testify v1.8.1 + github.com/stretchr/testify v1.8.2 github.com/urfave/cli/v2 v2.3.0 go.uber.org/zap v1.24.0 golang.org/x/crypto v0.4.0 - google.golang.org/grpc v1.52.0 + google.golang.org/grpc v1.53.0 google.golang.org/protobuf v1.28.1 ) @@ -34,14 +34,18 @@ require ( github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 // indirect github.com/benbjohnson/clock v1.1.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/cenkalti/backoff/v4 v4.2.0 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.3 // indirect github.com/gorilla/websocket v1.4.2 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/hashicorp/golang-lru v0.6.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -67,15 +71,23 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/subosito/gotenv v1.4.2 // indirect github.com/urfave/cli v1.22.5 // indirect + go.opentelemetry.io/otel v1.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 // indirect + go.opentelemetry.io/otel/sdk v1.14.0 // indirect + go.opentelemetry.io/otel/trace v1.14.0 // indirect + go.opentelemetry.io/proto/otlp v0.19.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/exp v0.0.0-20221227203929-1b447090c38c // indirect - golang.org/x/net v0.4.0 // indirect + golang.org/x/net v0.7.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/term v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect - google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/term v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect + google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 47a2653..7404966 100644 --- a/go.sum +++ b/go.sum @@ -36,14 +36,14 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.11.2-0.20230315095236-9dc375346703 h1:lxe0DtZq/uFZVZu9apx6OcIXCJskQBMd/GVeYGKA3wA= -git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.11.2-0.20230315095236-9dc375346703/go.mod h1:gRd5iE5A84viily6AcNBsSlTx2XgoWrwRDz7z0MayDQ= +git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.15.1-0.20230418080822-bd44a3f47b85 h1:77lvdk0kMhnUgtnmqEcAPXPQaGlt24goMPu2+E5WRTk= +git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.15.1-0.20230418080822-bd44a3f47b85/go.mod h1:sPyITTmQT662ZI38ud2aoE1SUCAr1mO5xV8P4nzLkKI= git.frostfs.info/TrueCloudLab/frostfs-contract v0.0.0-20230307110621-19a8ef2d02fb h1:S/TrbOOu9qEXZRZ9/Ddw7crnxbBUQLo68PSzQWYrc9M= git.frostfs.info/TrueCloudLab/frostfs-contract v0.0.0-20230307110621-19a8ef2d02fb/go.mod h1:nkR5gaGeez3Zv2SE7aceP0YwxG2FzIB5cGKpQO2vV2o= git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk= git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0/go.mod h1:RUIKZATQLJ+TaYQa60X2fTDwfuhMfm8Ar60bQ5fr+vU= -git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20230329125804-552219b8e130 h1:V+3dGwEXwEvvSvseMKn8S6ZEMNhxBBYrcyx+F7VaptM= -git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20230329125804-552219b8e130/go.mod h1:23fUGlEv/ImaOi3vck6vZj0v0b4hteOhLLPnVWHSQeA= +git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20230420104105-d0762d037d2c h1:dSicW6Gbb7sZTb+eyHj6IXihCyoCp5lGz/Z4YqnW8Ak= +git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20230420104105-d0762d037d2c/go.mod h1:TaJJOF3Uhuq8aqv2CrfuY2yhxePUinW35Xd3wfXLV/I= git.frostfs.info/TrueCloudLab/hrw v1.2.0 h1:KvAES7xIqmQBGd2q8KanNosD9+4BhU/zqD5Kt5KSflk= git.frostfs.info/TrueCloudLab/hrw v1.2.0/go.mod h1:mq2sbvYfO+BB6iFZwYBkgC0yc6mJNx+qZi4jW918m+Y= git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 h1:M2KR3iBj7WpY3hP10IevfIB9MURr4O9mwVfJ+SjT3HA= @@ -56,6 +56,7 @@ github.com/CityOfZion/neo-go v0.62.1-pre.0.20191114145240-e740fbe708f8/go.mod h1 github.com/CityOfZion/neo-go v0.70.1-pre.0.20191209120015-fccb0085941e/go.mod h1:0enZl0az8xA6PVkwzEOwPWVJGqlt/GO4hA4kmQ5Xzig= github.com/CityOfZion/neo-go v0.70.1-pre.0.20191212173117-32ac01130d4c/go.mod h1:JtlHfeqLywZLswKIKFnAp+yzezY4Dji9qlfQKB2OD/I= github.com/CityOfZion/neo-go v0.71.1-pre.0.20200129171427-f773ec69fb84/go.mod h1:FLI526IrRWHmcsO+mHsCbj64pJZhwQFTLJZu+A4PGOA= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= github.com/abiosoft/ishell v2.0.0+incompatible/go.mod h1:HQR9AqF2R3P4XXpMpI0NAzgHf/aS6+zVXRj14cVk9qg= github.com/abiosoft/ishell/v2 v2.0.2/go.mod h1:E4oTCXfo6QjoCart0QYa5m9w4S+deXs/P/9jA77A9Bs= @@ -94,11 +95,15 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= +github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -106,7 +111,11 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= @@ -125,6 +134,7 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= @@ -149,11 +159,18 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-redis/redis v6.10.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -229,6 +246,8 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7 github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= @@ -400,6 +419,7 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= @@ -423,8 +443,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/syndtr/goleveldb v0.0.0-20180307113352-169b1b37be73/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= @@ -454,14 +475,30 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= +go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 h1:/fXHZHGvro6MVqV34fJzDhi7sHGpX3Ej/Qjmfn003ho= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0/go.mod h1:UFG7EBMRdXyFstOwH028U0sVf+AvukSGhF0g8+dmNG8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 h1:TKf2uAs2ueguzLaxOCBXNpHxfO/aC7PAdDsSH0IbeRQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0/go.mod h1:HrbCVv40OOLTABmOn1ZWty6CHXkU8DK/Urc43tHug70= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 h1:ap+y8RXX3Mu9apKVtOkM6WSFESLM8K3wNQyOU8sWHcc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0/go.mod h1:5w41DY6S9gZrbjuq6Y+753e96WfPha5IcsOSZTtullM= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 h1:sEL90JjOO/4yhquXl5zTAkLLsZ5+MycAgX99SDsxGc8= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0/go.mod h1:oCslUcizYdpKYyS9e8srZEqM6BB8fq41VJBjLAE6z1w= +go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY= +go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= +go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= +go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= @@ -560,12 +597,13 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -576,6 +614,7 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -643,8 +682,10 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -652,23 +693,24 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210429154555-c04ba851c2a4/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -791,8 +833,9 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef h1:uQ2vjV/sHTsWSqdKeLqmwitzgvjMl7o4IdtHwUDXSJY= -google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -811,9 +854,11 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.52.0 h1:kd48UiU7EHsV4rnLyOJRuP/Il/UHE7gdDAQ+SZI7nZk= -google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/internal/frostfs/frostfs.go b/internal/frostfs/frostfs.go index 86d60b7..2274b8b 100644 --- a/internal/frostfs/frostfs.go +++ b/internal/frostfs/frostfs.go @@ -269,7 +269,7 @@ func (x *FrostFS) CreateObject(ctx context.Context, prm layer.PrmObjectCreate) ( var prmPut pool.PrmObjectPut prmPut.SetHeader(*obj) prmPut.SetPayload(prm.Payload) - prmPut.SetCopiesNumber(prm.CopiesNumber) + prmPut.SetCopiesNumberVector(prm.CopiesNumber) if prm.BearerToken != nil { prmPut.UseBearer(*prm.BearerToken)