2023-06-23 13:10:43 +00:00
|
|
|
package modules
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
2024-01-19 07:00:04 +00:00
|
|
|
"strings"
|
2023-06-23 13:10:43 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs"
|
2024-03-12 08:31:44 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid/contract"
|
2023-08-23 11:07:52 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
2024-01-19 07:00:04 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
2023-06-23 13:10:43 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
|
2023-08-03 12:08:22 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
2023-06-23 13:10:43 +00:00
|
|
|
"github.com/spf13/viper"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
"go.uber.org/zap/zapcore"
|
|
|
|
)
|
|
|
|
|
|
|
|
type PoolConfig struct {
|
2023-08-03 12:08:22 +00:00
|
|
|
Key *keys.PrivateKey
|
2023-06-23 13:10:43 +00:00
|
|
|
Address string
|
|
|
|
DialTimeout time.Duration
|
|
|
|
HealthcheckTimeout time.Duration
|
|
|
|
StreamTimeout time.Duration
|
|
|
|
RebalanceInterval time.Duration
|
|
|
|
}
|
|
|
|
|
2024-04-26 14:32:58 +00:00
|
|
|
func createFrostFS(ctx context.Context, log *zap.Logger, cfg PoolConfig) (*frostfs.AuthmateFrostFS, error) {
|
2023-08-23 11:07:52 +00:00
|
|
|
log.Debug(logs.PrepareConnectionPool)
|
2023-06-23 13:10:43 +00:00
|
|
|
|
|
|
|
var prm pool.InitParameters
|
2023-08-03 12:08:22 +00:00
|
|
|
prm.SetKey(&cfg.Key.PrivateKey)
|
2023-06-23 13:10:43 +00:00
|
|
|
prm.SetNodeDialTimeout(cfg.DialTimeout)
|
|
|
|
prm.SetHealthcheckTimeout(cfg.HealthcheckTimeout)
|
|
|
|
prm.SetNodeStreamTimeout(cfg.StreamTimeout)
|
|
|
|
prm.SetClientRebalanceInterval(cfg.RebalanceInterval)
|
|
|
|
prm.SetLogger(log)
|
|
|
|
prm.AddNode(pool.NewNodeParam(1, cfg.Address, 1))
|
|
|
|
|
|
|
|
p, err := pool.NewPool(prm)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("create pool: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = p.Dial(ctx); err != nil {
|
|
|
|
return nil, fmt.Errorf("dial pool: %w", err)
|
|
|
|
}
|
|
|
|
|
2024-04-26 14:32:58 +00:00
|
|
|
return frostfs.NewAuthmateFrostFS(frostfs.NewFrostFS(p, cfg.Key)), nil
|
2023-06-23 13:10:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func parsePolicies(val string) (authmate.ContainerPolicies, error) {
|
|
|
|
if val == "" {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
data = []byte(val)
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
if !json.Valid(data) {
|
|
|
|
if data, err = os.ReadFile(val); err != nil {
|
|
|
|
return nil, fmt.Errorf("coudln't read json file or provided json is invalid")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var policies authmate.ContainerPolicies
|
|
|
|
if err = json.Unmarshal(data, &policies); err != nil {
|
|
|
|
return nil, fmt.Errorf("unmarshal policies: %w", err)
|
|
|
|
}
|
|
|
|
if _, ok := policies[api.DefaultLocationConstraint]; ok {
|
|
|
|
return nil, fmt.Errorf("config overrides %s location constraint", api.DefaultLocationConstraint)
|
|
|
|
}
|
|
|
|
|
|
|
|
return policies, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getJSONRules(val string) ([]byte, error) {
|
|
|
|
if val == "" {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
data := []byte(val)
|
|
|
|
if json.Valid(data) {
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if data, err := os.ReadFile(val); err == nil {
|
|
|
|
if json.Valid(data) {
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, fmt.Errorf("coudln't read json file or provided json is invalid")
|
|
|
|
}
|
|
|
|
|
|
|
|
// getSessionRules reads json session rules.
|
|
|
|
// It returns true if rules must be skipped.
|
|
|
|
func getSessionRules(r string) ([]byte, bool, error) {
|
|
|
|
if r == "none" {
|
|
|
|
return nil, true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
data, err := getJSONRules(r)
|
|
|
|
return data, false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// getLogger returns new logger depending on appropriate values in viper.Viper
|
|
|
|
// if logger cannot be built it panics.
|
|
|
|
func getLogger() *zap.Logger {
|
|
|
|
if !viper.GetBool(withLogFlag) {
|
|
|
|
return zap.NewNop()
|
|
|
|
}
|
|
|
|
|
|
|
|
var zapConfig = zap.Config{
|
|
|
|
Development: true,
|
|
|
|
Encoding: "console",
|
|
|
|
Level: zap.NewAtomicLevelAt(zapcore.FatalLevel),
|
|
|
|
OutputPaths: []string{"stdout"},
|
|
|
|
EncoderConfig: zapcore.EncoderConfig{
|
|
|
|
MessageKey: "message",
|
|
|
|
LevelKey: "level",
|
|
|
|
EncodeLevel: zapcore.CapitalLevelEncoder,
|
|
|
|
TimeKey: "time",
|
|
|
|
EncodeTime: zapcore.ISO8601TimeEncoder,
|
|
|
|
CallerKey: "caller",
|
|
|
|
EncodeCaller: zapcore.ShortCallerEncoder,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
if viper.GetBool(debugFlag) {
|
|
|
|
zapConfig.Level = zap.NewAtomicLevelAt(zapcore.DebugLevel)
|
|
|
|
}
|
|
|
|
|
|
|
|
log, err := zapConfig.Build()
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Errorf("create logger: %w", err))
|
|
|
|
}
|
|
|
|
|
|
|
|
return log
|
|
|
|
}
|
2023-11-16 11:39:58 +00:00
|
|
|
|
2024-03-12 08:31:44 +00:00
|
|
|
func createFrostFSID(ctx context.Context, log *zap.Logger, cfg contract.Config) (*contract.FrostFSID, error) {
|
2023-11-16 11:39:58 +00:00
|
|
|
log.Debug(logs.PrepareFrostfsIDClient)
|
|
|
|
|
2024-03-12 08:31:44 +00:00
|
|
|
cli, err := contract.New(ctx, cfg)
|
2023-11-16 11:39:58 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("create frostfsid client: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return cli, nil
|
|
|
|
}
|
2024-01-19 07:00:04 +00:00
|
|
|
|
2024-03-12 08:31:44 +00:00
|
|
|
func registerPublicKey(cli *contract.FrostFSID, namespace string, key *keys.PublicKey) error {
|
|
|
|
err := cli.Wait(cli.CreateSubject(namespace, key))
|
|
|
|
if err != nil && !strings.Contains(err.Error(), "subject already exists") {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-01-19 07:00:04 +00:00
|
|
|
func parseObjectAttrs(attributes string) ([]object.Attribute, error) {
|
|
|
|
if len(attributes) == 0 {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
rawAttrs := strings.Split(attributes, ",")
|
|
|
|
|
|
|
|
attrs := make([]object.Attribute, len(rawAttrs))
|
|
|
|
for i := range rawAttrs {
|
|
|
|
k, v, found := strings.Cut(rawAttrs[i], "=")
|
|
|
|
if !found {
|
|
|
|
return nil, fmt.Errorf("invalid attribute format: %s", rawAttrs[i])
|
|
|
|
}
|
|
|
|
attrs[i].SetKey(k)
|
|
|
|
attrs[i].SetValue(v)
|
|
|
|
}
|
|
|
|
|
|
|
|
return attrs, nil
|
|
|
|
}
|