[#568] Add configuration for region to policy map
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
3212805955
commit
d47840f137
5 changed files with 101 additions and 44 deletions
|
@ -24,12 +24,17 @@ type (
|
|||
|
||||
// Config contains data which handler needs to keep.
|
||||
Config struct {
|
||||
DefaultPolicy netmap.PlacementPolicy
|
||||
Policy PlacementPolicy
|
||||
DefaultMaxAge int
|
||||
NotificatorEnabled bool
|
||||
TLSEnabled bool
|
||||
CopiesNumber uint32
|
||||
}
|
||||
|
||||
PlacementPolicy struct {
|
||||
Default netmap.PlacementPolicy
|
||||
RegionMap map[string]netmap.PlacementPolicy
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -123,6 +123,7 @@ func (h *handler) HeadBucketHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
w.Header().Set(api.ContainerID, bktInfo.CID.EncodeToString())
|
||||
w.Header().Set(api.AmzBucketRegion, bktInfo.LocationConstraint)
|
||||
api.WriteResponse(w, http.StatusOK, nil, api.MimeNone)
|
||||
}
|
||||
|
||||
|
|
|
@ -667,12 +667,10 @@ func parseMetadata(r *http.Request) map[string]string {
|
|||
}
|
||||
|
||||
func (h *handler) CreateBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
reqInfo = api.GetReqInfo(r.Context())
|
||||
p = layer.CreateBucketParams{
|
||||
Name: reqInfo.BucketName,
|
||||
}
|
||||
)
|
||||
reqInfo := api.GetReqInfo(r.Context())
|
||||
p := &layer.CreateBucketParams{
|
||||
Name: reqInfo.BucketName,
|
||||
}
|
||||
|
||||
if err := checkBucketName(reqInfo.BucketName); err != nil {
|
||||
h.logAndSendError(w, "invalid bucket name", reqInfo, err)
|
||||
|
@ -722,24 +720,11 @@ func (h *handler) CreateBucketHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
useDefaultPolicy := true
|
||||
if createParams.LocationConstraint != "" {
|
||||
for _, placementPolicy := range policies {
|
||||
if placementPolicy.LocationConstraint == createParams.LocationConstraint {
|
||||
p.Policy = placementPolicy.Policy
|
||||
p.LocationConstraint = createParams.LocationConstraint
|
||||
useDefaultPolicy = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if useDefaultPolicy {
|
||||
p.Policy = h.cfg.DefaultPolicy
|
||||
}
|
||||
h.setPolicy(p, createParams.LocationConstraint, policies)
|
||||
|
||||
p.ObjectLockEnabled = isLockEnabled(r.Header)
|
||||
|
||||
bktInfo, err := h.obj.CreateBucket(r.Context(), &p)
|
||||
bktInfo, err := h.obj.CreateBucket(r.Context(), p)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "could not create bucket", reqInfo, err)
|
||||
return
|
||||
|
@ -762,6 +747,27 @@ func (h *handler) CreateBucketHandler(w http.ResponseWriter, r *http.Request) {
|
|||
api.WriteSuccessResponseHeadersOnly(w)
|
||||
}
|
||||
|
||||
func (h handler) setPolicy(prm *layer.CreateBucketParams, locationConstraint string, userPolicies []*accessbox.ContainerPolicy) {
|
||||
prm.Policy = h.cfg.Policy.Default
|
||||
|
||||
if locationConstraint == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if policy, ok := h.cfg.Policy.RegionMap[locationConstraint]; ok {
|
||||
prm.Policy = policy
|
||||
prm.LocationConstraint = locationConstraint
|
||||
}
|
||||
|
||||
for _, placementPolicy := range userPolicies {
|
||||
if placementPolicy.LocationConstraint == locationConstraint {
|
||||
prm.Policy = placementPolicy.Policy
|
||||
prm.LocationConstraint = locationConstraint
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isLockEnabled(header http.Header) bool {
|
||||
lockEnabledStr := header.Get(api.AmzBucketObjectLockEnabled)
|
||||
lockEnabled, _ := strconv.ParseBool(lockEnabledStr)
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
|
@ -27,6 +28,7 @@ import (
|
|||
"github.com/nspcc-dev/neofs-s3-gw/internal/neofs"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/internal/version"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/internal/wallet"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
||||
"github.com/spf13/viper"
|
||||
"go.uber.org/zap"
|
||||
|
@ -596,41 +598,83 @@ func getAccessBoxCacheConfig(v *viper.Viper, l *zap.Logger) *cache.Config {
|
|||
}
|
||||
|
||||
func getHandlerOptions(v *viper.Viper, l *zap.Logger) *handler.Config {
|
||||
var (
|
||||
cfg handler.Config
|
||||
err error
|
||||
policyStr = handler.DefaultPolicy
|
||||
defaultMaxAge = handler.DefaultMaxAge
|
||||
setCopiesNumber = handler.DefaultCopiesNumber
|
||||
)
|
||||
|
||||
if v.IsSet(cfgDefaultPolicy) {
|
||||
policyStr = v.GetString(cfgDefaultPolicy)
|
||||
cfg := &handler.Config{
|
||||
Policy: handler.PlacementPolicy{
|
||||
RegionMap: make(map[string]netmap.PlacementPolicy),
|
||||
},
|
||||
DefaultMaxAge: handler.DefaultMaxAge,
|
||||
NotificatorEnabled: v.GetBool(cfgEnableNATS),
|
||||
TLSEnabled: v.IsSet(cfgTLSKeyFile) && v.IsSet(cfgTLSCertFile),
|
||||
CopiesNumber: handler.DefaultCopiesNumber,
|
||||
}
|
||||
|
||||
if err = cfg.DefaultPolicy.DecodeString(policyStr); err != nil {
|
||||
l.Fatal("couldn't parse container default policy",
|
||||
zap.Error(err))
|
||||
defaultPolicyStr := handler.DefaultPolicy
|
||||
if v.IsSet(cfgPolicyDefault) {
|
||||
defaultPolicyStr = v.GetString(cfgPolicyDefault)
|
||||
}
|
||||
|
||||
if err := cfg.Policy.Default.DecodeString(defaultPolicyStr); err != nil {
|
||||
l.Fatal("couldn't parse container default policy", zap.Error(err))
|
||||
}
|
||||
|
||||
regionPolicyMap, err := parseRegionMap(v)
|
||||
if err != nil {
|
||||
l.Fatal("couldn't parse region mapping policy file", zap.Error(err))
|
||||
}
|
||||
|
||||
for region, policy := range regionPolicyMap {
|
||||
var pp netmap.PlacementPolicy
|
||||
if err = pp.DecodeString(policy); err == nil {
|
||||
cfg.Policy.RegionMap[region] = pp
|
||||
continue
|
||||
}
|
||||
|
||||
if err = pp.UnmarshalJSON([]byte(policy)); err == nil {
|
||||
cfg.Policy.RegionMap[region] = pp
|
||||
continue
|
||||
}
|
||||
|
||||
l.Fatal("couldn't parse region mapping policy", zap.String("name", region), zap.Error(err))
|
||||
}
|
||||
|
||||
if v.IsSet(cfgDefaultMaxAge) {
|
||||
defaultMaxAge = v.GetInt(cfgDefaultMaxAge)
|
||||
defaultMaxAge := v.GetInt(cfgDefaultMaxAge)
|
||||
|
||||
if defaultMaxAge <= 0 && defaultMaxAge != -1 {
|
||||
l.Fatal("invalid defaultMaxAge",
|
||||
zap.String("parameter", cfgDefaultMaxAge),
|
||||
zap.String("value in config", strconv.Itoa(defaultMaxAge)))
|
||||
}
|
||||
cfg.DefaultMaxAge = defaultMaxAge
|
||||
}
|
||||
|
||||
if val := v.GetUint32(cfgSetCopiesNumber); val > 0 {
|
||||
setCopiesNumber = val
|
||||
cfg.CopiesNumber = val
|
||||
}
|
||||
|
||||
cfg.DefaultMaxAge = defaultMaxAge
|
||||
cfg.NotificatorEnabled = v.GetBool(cfgEnableNATS)
|
||||
cfg.TLSEnabled = v.IsSet(cfgTLSKeyFile) && v.IsSet(cfgTLSCertFile)
|
||||
cfg.CopiesNumber = setCopiesNumber
|
||||
|
||||
return &cfg
|
||||
return cfg
|
||||
}
|
||||
|
||||
func parseRegionMap(v *viper.Viper) (map[string]string, error) {
|
||||
regionMap := make(map[string]string)
|
||||
|
||||
filePath := v.GetString(cfgPolicyRegionMapFile)
|
||||
if filePath == "" {
|
||||
return regionMap, nil
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("coudln't read file '%s'", filePath)
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(data, ®ionMap); err != nil {
|
||||
return nil, fmt.Errorf("unmarshal policies: %w", err)
|
||||
}
|
||||
|
||||
if _, ok := regionMap[api.DefaultLocationConstraint]; ok {
|
||||
return nil, fmt.Errorf("config overrides %s location constraint", api.DefaultLocationConstraint)
|
||||
}
|
||||
|
||||
return regionMap, nil
|
||||
}
|
||||
|
|
|
@ -76,7 +76,8 @@ const ( // Settings.
|
|||
cfgNATSRootCAFiles = "nats.root_ca"
|
||||
|
||||
// Policy.
|
||||
cfgDefaultPolicy = "default_policy"
|
||||
cfgPolicyDefault = "placement_policy.default"
|
||||
cfgPolicyRegionMapFile = "placement_policy.region_mapping"
|
||||
|
||||
// CORS.
|
||||
cfgDefaultMaxAge = "cors.default_max_age"
|
||||
|
|
Loading…
Reference in a new issue