[#568] Add configuration for region to policy map

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2022-11-03 09:34:18 +03:00 committed by Alex Vanin
parent 3212805955
commit d47840f137
5 changed files with 101 additions and 44 deletions

View file

@ -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 (

View file

@ -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)
}

View file

@ -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)

View file

@ -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, &regionMap); 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
}

View file

@ -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"