[#667] Use separate copies numbers for system containers

Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
Denis Kirillov 2025-03-26 16:32:06 +03:00
parent 42d6fc3fc6
commit 949fc0b484
15 changed files with 311 additions and 125 deletions

View file

@ -6,6 +6,7 @@ This document outlines major changes between releases.
### Fixed
- Number of bucket tags increased to 50 (#613)
- Use own copies number for CORS and Lifecycle containers (#667)
## [0.32.13] - 2025-03-10

View file

@ -43,6 +43,8 @@ type (
RetryStrategy() RetryStrategy
TLSTerminationHeader() string
ListingKeepaliveThrottle() time.Duration
CORSCopiesNumbers() []uint32
LifecycleCopiesNumbers() []uint32
}
FrostFSID interface {

View file

@ -17,7 +17,7 @@ func TestHandler_ListBucketsHandler(t *testing.T) {
const defaultConstraint = "default"
region := "us-west-1"
hc := prepareWithoutCORSHandlerContext(t)
hc := prepareWithoutContainersHandlerContext(t, true, true)
hc.config.putLocationConstraint(region)
props := []Bucket{

View file

@ -65,12 +65,7 @@ func (h *handler) PutBucketCorsHandler(w http.ResponseWriter, r *http.Request) {
Reader: r.Body,
NewDecoder: h.cfg.NewXMLDecoder,
UserAgent: r.UserAgent(),
}
p.CopiesNumbers, err = h.pickCopiesNumbers(parseMetadata(r), reqInfo.Namespace, bktInfo.LocationConstraint)
if err != nil {
h.logAndSendError(ctx, w, "invalid copies number", reqInfo, err)
return
CopiesNumbers: h.cfg.CORSCopiesNumbers(),
}
if err = h.obj.PutBucketCORS(ctx, p); err != nil {

View file

@ -1,6 +1,8 @@
package handler
import (
"crypto/md5"
"encoding/base64"
"encoding/xml"
"net/http"
"net/http/httptest"
@ -364,6 +366,30 @@ func addCORSToTree(hc *handlerContext, cors string, bkt *data.BucketInfo, corsCn
require.NoError(hc.t, err)
}
func TestPutBucketCORSCopiesNumbers(t *testing.T) {
hc := prepareHandlerContext(t)
bktName := "bucket-cors"
createBucket(hc, bktName)
cfg := &data.CORSConfiguration{
CORSRules: []data.CORSRule{{
AllowedHeaders: []string{"*"},
AllowedMethods: []string{"GET"},
AllowedOrigins: []string{"*"},
}},
}
hc.config.corsCopiesNumbers = []uint32{1}
hc.config.copiesNumbers = map[string][]uint32{"default": {2}}
putBucketCORSConfiguration(hc, bktName, cfg, map[string]string{"X-Amz-Meta-Frostfs-Copies-Number": "3"}, true)
objs := hc.tp.Objects()
require.Len(t, objs, 1)
require.EqualValues(t, hc.config.corsCopiesNumbers, hc.tp.CopiesNumbers(addrFromObject(objs[0]).EncodeToString()))
}
func requireEqualCORS(t *testing.T, expected string, actual string) {
expectedCORS := &data.CORSConfiguration{}
err := xml.NewDecoder(strings.NewReader(expected)).Decode(expectedCORS)
@ -398,3 +424,28 @@ func getBucketCORS(hc *handlerContext, bktName string) *httptest.ResponseRecorde
assertStatus(hc.t, w, http.StatusOK)
return w
}
func putBucketCORSConfiguration(hc *handlerContext, bktName string, cfg *data.CORSConfiguration, headers map[string]string, addMD5 bool) {
w := putBucketCORSConfigurationBase(hc, bktName, cfg, headers, addMD5)
assertStatus(hc.t, w, http.StatusOK)
}
func putBucketCORSConfigurationBase(hc *handlerContext, bktName string, cfg *data.CORSConfiguration, headers map[string]string, addMD5 bool) *httptest.ResponseRecorder {
w, r := prepareTestRequest(hc, bktName, "", cfg)
for k, v := range headers {
r.Header.Set(k, v)
}
if addMD5 {
rawBody, err := xml.Marshal(cfg)
require.NoError(hc.t, err)
hash := md5.New()
hash.Write(rawBody)
r.Header.Set(api.ContentMD5, base64.StdEncoding.EncodeToString(hash.Sum(nil)))
}
hc.Handler().PutBucketCorsHandler(w, r)
return w
}

View file

@ -81,6 +81,8 @@ type configMock struct {
placementPolicies map[string]netmap.PlacementPolicy
copiesNumbers map[string][]uint32
defaultCopiesNumbers []uint32
corsCopiesNumbers []uint32
lifecycleCopiesNumbers []uint32
bypassContentEncodingInChunks bool
md5Enabled bool
tlsTerminationHeader string
@ -161,6 +163,14 @@ func (c *configMock) ListingKeepaliveThrottle() time.Duration {
return 0
}
func (c *configMock) CORSCopiesNumbers() []uint32 {
return c.corsCopiesNumbers
}
func (c *configMock) LifecycleCopiesNumbers() []uint32 {
return c.lifecycleCopiesNumbers
}
func (c *configMock) putLocationConstraint(constraint string) {
c.placementPolicies[constraint] = c.defaultPolicy
}
@ -168,6 +178,7 @@ func (c *configMock) putLocationConstraint(constraint string) {
type handlerConfig struct {
cacheCfg *layer.CachesConfig
withoutCORS bool
withoutLifecycle bool
}
func prepareHandlerContext(t *testing.T) *handlerContext {
@ -180,11 +191,12 @@ func prepareHandlerContext(t *testing.T) *handlerContext {
}
}
func prepareWithoutCORSHandlerContext(t *testing.T) *handlerContext {
func prepareWithoutContainersHandlerContext(t *testing.T, cors, lifecycle bool) *handlerContext {
log := zaptest.NewLogger(t)
hc, err := prepareHandlerContextBase(&handlerConfig{
cacheCfg: layer.DefaultCachesConfigs(log),
withoutCORS: true,
withoutCORS: cors,
withoutLifecycle: lifecycle,
}, log)
require.NoError(t, err)
return &handlerContext{
@ -247,12 +259,18 @@ func prepareHandlerContextBase(config *handlerConfig, log *zap.Logger) (*handler
}
if !config.withoutCORS {
layerCfg.CORSCnrInfo, err = createCORSContainer(key, tp)
layerCfg.CORSCnrInfo, err = createContainer(key, tp, "cors")
if err != nil {
return nil, err
}
}
if !config.withoutLifecycle {
if layerCfg.LifecycleCnrInfo, err = createContainer(key, tp, "lifecycle"); err != nil {
return nil, err
}
}
var pp netmap.PlacementPolicy
err = pp.DecodeString("REP 1")
if err != nil {
@ -296,14 +314,13 @@ func prepareHandlerContextBase(config *handlerConfig, log *zap.Logger) (*handler
return hc, nil
}
func createCORSContainer(key *keys.PrivateKey, tp *layer.TestFrostFS) (*data.BucketInfo, error) {
func createContainer(key *keys.PrivateKey, tp *layer.TestFrostFS, bktName string) (*data.BucketInfo, error) {
bearerToken := bearertest.Token()
err := bearerToken.Sign(key.PrivateKey)
if err != nil {
return nil, err
}
bktName := "cors"
res, err := tp.CreateContainer(middleware.SetBox(context.Background(), &middleware.Box{AccessBox: &accessbox.Box{
Gate: &accessbox.GateData{
BearerToken: &bearerToken,

View file

@ -108,13 +108,16 @@ func (h *handler) PutBucketLifecycleHandler(w http.ResponseWriter, r *http.Reque
params := &layer.PutBucketLifecycleParams{
BktInfo: bktInfo,
LifecycleCfg: cfg,
CopiesNumbers: h.cfg.LifecycleCopiesNumbers(),
}
if h.obj.LifecycleContainerInfo() == nil {
params.CopiesNumbers, err = h.pickCopiesNumbers(parseMetadata(r), reqInfo.Namespace, bktInfo.LocationConstraint)
if err != nil {
h.logAndSendError(ctx, w, "invalid copies number", reqInfo, err)
return
}
}
if err = h.obj.PutBucketLifecycleConfiguration(ctx, params); err != nil {
h.logAndSendError(ctx, w, "could not put bucket lifecycle configuration", reqInfo, err)

View file

@ -521,6 +521,58 @@ func TestPutBucketLifecycleInvalidXML(t *testing.T) {
assertS3Error(hc.t, w, apierr.GetAPIError(apierr.ErrMalformedXML))
}
func TestPutBucketLifecycleCopiesNumbers(t *testing.T) {
t.Run("with lifecycle container", func(t *testing.T) {
hc := prepareHandlerContext(t)
bktName := "bucket-lifecycle"
createBucket(hc, bktName)
cfg := &data.LifecycleConfiguration{
Rules: []data.LifecycleRule{{
Status: data.LifecycleStatusEnabled,
Expiration: &data.LifecycleExpiration{Days: ptr(21)},
}},
}
hc.config.lifecycleCopiesNumbers = []uint32{1}
hc.config.copiesNumbers = map[string][]uint32{"default": {2}}
putBucketLifecycleConfiguration(hc, bktName, cfg, map[string]string{"X-Amz-Meta-Frostfs-Copies-Number": "3"}, true)
objs := hc.tp.Objects()
require.Len(t, objs, 1)
require.EqualValues(t, hc.config.lifecycleCopiesNumbers, hc.tp.CopiesNumbers(addrFromObject(objs[0]).EncodeToString()))
})
t.Run("without lifecycle container", func(t *testing.T) {
hc := prepareWithoutContainersHandlerContext(t, false, true)
bktName := "bucket-lifecycle"
createBucket(hc, bktName)
cfg := &data.LifecycleConfiguration{
Rules: []data.LifecycleRule{{
Status: data.LifecycleStatusEnabled,
Expiration: &data.LifecycleExpiration{Days: ptr(21)},
}},
}
hc.config.lifecycleCopiesNumbers = []uint32{1}
hc.config.copiesNumbers = map[string][]uint32{"default": {2}}
putBucketLifecycleConfiguration(hc, bktName, cfg, nil, true)
objs := hc.tp.Objects()
require.Len(t, objs, 1)
require.EqualValues(t, []uint32{2}, hc.tp.CopiesNumbers(addrFromObject(objs[0]).EncodeToString()))
putBucketLifecycleConfiguration(hc, bktName, cfg, map[string]string{"X-Amz-Meta-Frostfs-Copies-Number": "3"}, true)
objs = hc.tp.Objects()
require.Len(t, objs, 1)
require.EqualValues(t, []uint32{3}, hc.tp.CopiesNumbers(addrFromObject(objs[0]).EncodeToString()))
})
}
func putBucketLifecycleConfiguration(hc *handlerContext, bktName string, cfg *data.LifecycleConfiguration, headers map[string]string, addMD5 bool) {
w := putBucketLifecycleConfigurationBase(hc, bktName, cfg, headers, addMD5)
assertStatus(hc.t, w, http.StatusOK)

View file

@ -1054,3 +1054,7 @@ func (n *Layer) GetNetworkInfo(ctx context.Context) (netmap.NetworkInfo, error)
return networkInfo, nil
}
func (n *Layer) LifecycleContainerInfo() *data.BucketInfo {
return n.lifecycleCnrInfo
}

View file

@ -143,6 +143,8 @@ type (
listingKeepaliveThrottle time.Duration
removeOnReplace bool
removeOnReplaceTimeout time.Duration
corsCopiesNumbers []uint32
lifecycleCopiesNumbers []uint32
}
maxClientsConfig struct {
@ -379,6 +381,8 @@ func (s *appSettings) update(v *viper.Viper, log *zap.Logger) {
listingKeepaliveThrottle := v.GetDuration(cfgKludgeListingKeepAliveThrottle)
removeOnReplace := v.GetBool(cfgRemoveOnReplaceEnabled)
removeOnReplaceTimeout := fetchRemoveOnReplaceTimeout(v)
corsCopiesNumbers := fetchCopiesNumbers(log, v, cfgCORSCopiesNumbers)
lifecycleCopiesNumbers := fetchCopiesNumbers(log, v, cfgLifecycleCopiesNumbers)
s.mu.Lock()
defer s.mu.Unlock()
@ -415,6 +419,8 @@ func (s *appSettings) update(v *viper.Viper, log *zap.Logger) {
s.listingKeepaliveThrottle = listingKeepaliveThrottle
s.removeOnReplace = removeOnReplace
s.removeOnReplaceTimeout = removeOnReplaceTimeout
s.corsCopiesNumbers = corsCopiesNumbers
s.lifecycleCopiesNumbers = lifecycleCopiesNumbers
}
func (s *appSettings) prepareVHSNamespaces(v *viper.Viper, log *zap.Logger, defaultNamespaces []string) map[string]bool {
@ -676,6 +682,18 @@ func (s *appSettings) RemoveOnReplaceQueue() int {
return s.removeOnReplaceQueue
}
func (s *appSettings) CORSCopiesNumbers() []uint32 {
s.mu.RLock()
defer s.mu.RUnlock()
return s.corsCopiesNumbers
}
func (s *appSettings) LifecycleCopiesNumbers() []uint32 {
s.mu.RLock()
defer s.mu.RUnlock()
return s.lifecycleCopiesNumbers
}
func (a *App) initAPI(ctx context.Context) {
a.initLayer(ctx)
a.initHandler()

View file

@ -167,6 +167,10 @@ const (
// CORS.
cfgDefaultMaxAge = "cors.default_max_age"
cfgCORSCopiesNumbers = "cors.copies_numbers"
// Lifecycle.
cfgLifecycleCopiesNumbers = "lifecycle.copies_numbers"
// MaxClients.
cfgMaxClientsCount = "max_clients_count"
@ -631,15 +635,16 @@ func readRegionMap(filePath string) (map[string]string, error) {
return regionMap, nil
}
func fetchDefaultCopiesNumbers(l *zap.Logger, v *viper.Viper) []uint32 {
unparsed := v.GetStringSlice(cfgSetCopiesNumber)
func fetchCopiesNumbers(l *zap.Logger, v *viper.Viper, param string) []uint32 {
unparsed := v.GetStringSlice(param)
result := make([]uint32, len(unparsed))
for i := range unparsed {
parsedValue, err := strconv.ParseUint(unparsed[i], 10, 32)
if err != nil {
l.Warn(logs.FailedToParseDefaultCopiesNumbers,
l.Warn(logs.FailedToParseCopiesNumbers,
zap.Strings("copies numbers", unparsed),
zap.Uint32s("default", defaultCopiesNumbers),
zap.String("parameter", param),
zap.Error(err),
logs.TagField(logs.TagApp),
)
@ -683,7 +688,7 @@ func fetchKludgeProfiles(v *viper.Viper) map[string]*KludgeParams {
return kludgeProfiles
}
func fetchCopiesNumbers(l *zap.Logger, v *viper.Viper) map[string][]uint32 {
func fetchPlacementPolicyCopiesNumbers(l *zap.Logger, v *viper.Viper) map[string][]uint32 {
copiesNums := make(map[string][]uint32)
for i := 0; ; i++ {
key := cfgCopiesNumbers + "." + strconv.Itoa(i) + "."
@ -698,7 +703,7 @@ func fetchCopiesNumbers(l *zap.Logger, v *viper.Viper) map[string][]uint32 {
for j := range vector {
parsedValue, err := strconv.ParseUint(vector[j], 10, 32)
if err != nil {
l.Warn(logs.FailedToParseCopiesNumbers,
l.Warn(logs.FailedToParsePlacementPolicyCopiesNumbers,
zap.String("location", constraint),
zap.Strings("copies numbers", vector), zap.Error(err),
logs.TagField(logs.TagApp))
@ -733,8 +738,8 @@ func fetchNamespacesConfig(l *zap.Logger, v *viper.Viper) (NamespacesConfig, []s
defaultNSRegionMap := fetchRegionMappingPolicies(l, v)
defaultNSRegionMap[defaultConstraintName] = fetchDefaultPolicy(l, v)
defaultNSCopiesNumbers := fetchCopiesNumbers(l, v)
defaultNSCopiesNumbers[defaultConstraintName] = fetchDefaultCopiesNumbers(l, v)
defaultNSCopiesNumbers := fetchPlacementPolicyCopiesNumbers(l, v)
defaultNSCopiesNumbers[defaultConstraintName] = fetchCopiesNumbers(l, v, cfgSetCopiesNumber)
defaultNSValue := Namespace{
LocationConstraints: defaultNSRegionMap,

View file

@ -159,6 +159,14 @@ 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
# Numbers of the object copies (for each replica) to consider PUT to FrostFS successful.
# `[0]` or empty list means that object will be processed according to the container's placement policy.
S3_GW_CORS_COPIES_NUMBERS=0
# Lifecycle configuration
# Numbers of the object copies (for each replica) to consider PUT to FrostFS successful.
# `[0]` or empty list means that object will be processed according to the container's placement policy.
S3_GW_LIFECYCLE_COPIES_NUMBERS=0
# Parameters of requests to FrostFS
# Numbers of the object copies (for each replica, syntax the same as for `S3_GW_PLACEMENT_POLICY_COPIES_NUMBERS_0_VECTOR` above)

View file

@ -196,9 +196,18 @@ placement_policy:
- 3
# CORS
# value of Access-Control-Max-Age header if this value is not set in a rule. Has an int type.
cors:
# value of Access-Control-Max-Age header if this value is not set in a rule. Has an int type.
default_max_age: 600
# Numbers of the object copies (for each replica) to consider PUT to FrostFS successful.
# `[0]` or empty list means that object will be processed according to the container's placement policy.
copies_numbers: [ 0 ]
# Lifecycle configuration
lifecycle:
# Numbers of the object copies (for each replica) to consider PUT to FrostFS successful.
# `[0]` or empty list means that object will be processed according to the container's placement policy.
copies_numbers: [ 0 ]
# Parameters of requests to FrostFS
frostfs:

View file

@ -115,8 +115,10 @@ $ frostfs-s3-gw --config your-config.yaml
### Multiple configs
You can use several config files when running application. It allows you to split configuration into parts.
For example, you can use separate yaml file for pprof and prometheus section in config (see [config examples](../config)).
You can either provide several files with repeating `--config` flag or provide path to the dir that contains all configs using `--config-dir` flag.
For example, you can use separate yaml file for pprof and prometheus section in config (
see [config examples](../config)).
You can either provide several files with repeating `--config` flag or provide path to the dir that contains all configs
using `--config-dir` flag.
Also, you can combine these flags:
```shell
@ -181,6 +183,7 @@ There are some custom types used for brevity:
| `http_logging` | [HTTP Request logger configuration](#http_logging-section) |
| `cache` | [Cache configuration](#cache-section) |
| `cors` | [CORS configuration](#cors-section) |
| `lifecycle` | [Lifecycle configuration](#lifecycle-section) |
| `pprof` | [Pprof configuration](#pprof-section) |
| `prometheus` | [Prometheus configuration](#prometheus-section) |
| `tracing` | [Tracing configuration](#tracing-section) |
@ -263,7 +266,7 @@ wallet:
```
| Parameter | Type | Default value | Description |
|--------------|----------|---------------|---------------------------------------------------------------------------|
|--------------|----------|---------------|--------------------------------------------------------------------------|
| `path` | `string` | | Path to wallet |
| `passphrase` | `string` | | Passphrase to decrypt wallet. |
| `address` | `string` | | Account address to get from wallet. If omitted default one will be used. |
@ -299,7 +302,6 @@ peers:
| `priority` | `int` | `1` | It allows to group nodes and don't switch group until all nodes with the same priority will be unhealthy. The lower the value, the higher the priority. |
| `weight` | `float` | `1` | Weight of node in the group with the same priority. Distribute requests to nodes proportionally to these values. |
### `placement_policy` section
```yaml
@ -331,7 +333,8 @@ 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.
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
@ -348,7 +351,6 @@ So if you change `default` to some valid value and set invalid path in `region_m
| `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`.
@ -417,7 +419,7 @@ tags:
```
| Parameter | Type | SIGHUP reload | Default value | Description |
|-----------------------|------------|---------------|---------------------------|-------------------------------------------------------------------------------------------------------|
|-----------|----------|---------------|---------------------------|-------------------------------------------------------------------------------------------------------|
| `name` | `string` | yes | | Tag name. Possible values see below in `Tag values` section. |
| `level` | `string` | yes | Value from `logger.level` | Logging level for specific tag. Possible values: `debug`, `info`, `warn`, `dpanic`, `panic`, `fatal`. |
@ -429,10 +431,10 @@ tags:
* `external_storage` - external interaction with storage node (enabled by default).
* `external_storage_tree` - external interaction with tree service in storage node (enabled by default).
### `http_logging` section
Could be enabled only in builds with `loghttp` build tag. To build with `loghttp` tag, pass `GOFLAGS` var to `make`:
```bash
make GOFLAGS="-tags=loghttp" [target]
```
@ -454,7 +456,6 @@ http_logging:
| `gzip` | `bool` | yes | `false` | Whether to enable Gzip compression to backup log files. |
| `destination` | `string` | yes | `stdout` | Specify path for log output. Accepts log file path, or "stdout" and "stderr" reserved words to print in output streams. File and folders are created if necessary. |
### `cache` section
```yaml
@ -539,11 +540,24 @@ size: 100
```yaml
cors:
default_max_age: 600
copies_numbers: [ 0 ]
```
| Parameter | Type | Default value | Description |
|-------------------|-------|---------------|------------------------------------------------------|
| `default_max_age` | `int` | `600` | Value of `Access-Control-Max-Age` header in seconds. |
| Parameter | Type | SIGHUP reload | Default value | Description |
|-------------------|------------|---------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `default_max_age` | `int` | no | `600` | Value of `Access-Control-Max-Age` header in seconds. |
| `copies_numbers` | `[]uint32` | yes | `[0]` | Numbers of the object copies (for each replica) to consider PUT to FrostFS successful. <br/>Default value `[0]` or empty list means that object will be processed according to the container's placement policy. |
### `lifecycle` section
```yaml
lifecycle:
copies_numbers: [ 0 ]
```
| Parameter | Type | SIGHUP reload | Default value | Description |
|------------------|------------|---------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `copies_numbers` | `[]uint32` | yes | `[0]` | Numbers of the object copies (for each replica) to consider PUT to FrostFS successful. <br/>Default value `[0]` or empty list means that object will be processed according to the container's placement policy. |
# `pprof` section
@ -594,7 +608,7 @@ tracing:
```
| Parameter | Type | SIGHUP reload | Default value | Description |
| ------------ | -------------------------------------- | ------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|--------------|----------------------------------------|---------------|---------------|---------------------------------------------------------------------------------------------------------------------------------|
| `enabled` | `bool` | yes | `false` | Flag to enable the service. |
| `exporter` | `string` | yes | | Type of tracing exporter. |
| `endpoint` | `string` | yes | | Address that service listener binds to. |
@ -612,7 +626,7 @@ tracing:
```
| Parameter | Type | SIGHUP reload | Default value | Description |
|-----------------------|----------|---------------|---------------|----------------------------------------------------------|
|-----------|----------|---------------|---------------|------------------|
| `key` | `string` | yes | | Attribute key. |
| `value` | `string` | yes | | Attribute value. |
@ -620,7 +634,8 @@ tracing:
Contains parameters of requests to FrostFS.
The `set_copies_number` value can be overridden with `X-Amz-Meta-Frostfs-Copies-Number` (value is comma separated numbers: `1,2,3`)
The `set_copies_number` value can be overridden with `X-Amz-Meta-Frostfs-Copies-Number` (value is comma separated
numbers: `1,2,3`)
header for `PutObject`, `CopyObject`, `CreateMultipartUpload`.
```yaml
@ -667,7 +682,8 @@ resolve_bucket:
# `kludge` section
Workarounds for non-standard use cases. In `profiles` subsection has the ability to override behavior for specific user agent.
Workarounds for non-standard use cases. In `profiles` subsection has the ability to override behavior for specific user
agent.
```yaml
kludge:
@ -708,9 +724,8 @@ kludge:
| `use_default_xmlns` | `bool` | yes | | Enable using default xml namespace for profile. |
| `bypass_content_encoding_check_in_chunks` | `bool` | yes | | Use this flag to be able to use [chunked upload approach](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html) without having `aws-chunked` value in `Content-Encoding` header. |
# `runtime` section
Contains runtime parameters.
```yaml
@ -723,6 +738,7 @@ runtime:
| `soft_memory_limit` | `size` | yes | maxint64 | Soft memory limit for the runtime. Zero or no value stands for no limit. If `GOMEMLIMIT` environment variable is set, the value from the configuration file will be ignored. |
# `features` section
Contains parameters for enabling features.
```yaml
@ -748,6 +764,7 @@ features:
| `remove_on_replace.queue` | `int` | false | `10000` | Buffer size for objects to delete. If buffer is full creation new unversioned object won't remove old one. Lifecycler will do that. |
# `web` section
Contains web server configuration parameters.
```yaml
@ -836,8 +853,12 @@ To override config values for default namespaces use namespace names that are pr
"test": "{\"replicas\":[{\"count\":1,\"selector\":\"\"}],\"containerBackupFactor\":0,\"selectors\":[],\"filters\":[],\"unique\":false}"
},
"copies_numbers": {
"default": [ 0 ],
"test": [ 1 ]
"default": [
0
],
"test": [
1
]
}
}
}

View file

@ -71,8 +71,8 @@ const (
FailedToReadRegionMapFilePolicies = "failed to read region map file, policies will be empty"
DefaultLocationConstraintCantBeOverriden = "'default' location constraint can't be overriden by custom policy, use 'placement_policy.default'"
FailedToParseLocationConstraint = "failed to parse location constraint, it cannot be used"
FailedToParseDefaultCopiesNumbers = "failed to parse 'default' copies numbers, default one will be used"
FailedToParseCopiesNumbers = "failed to parse copies numbers, skip"
FailedToParseCopiesNumbers = "failed to parse copies numbers, default one will be used"
FailedToParsePlacementPolicyCopiesNumbers = "failed to parse placement policy copies numbers, skip"
FailedToInitializeTracing = "failed to initialize tracing"
DefaultNamespacesCannotBeEmpty = "default namespaces cannot be empty, defaults will be used"
FailedToParseNamespacesConfig = "failed to unmarshal namespaces config"