Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions pbm/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"io"
"maps"
"os"
"reflect"
"strconv"
"strings"
Expand Down Expand Up @@ -629,12 +628,6 @@ func SetConfig(ctx context.Context, m connect.Client, cfg *Config) error {
}
sanitizeStoragePaths(&cfg.Storage)

if cfg.Storage.Type == storage.S3 {
// call the function for notification purpose.
// warning about unsupported levels will be printed
s3.SDKLogLevel(cfg.Storage.S3.DebugLogLevels, os.Stderr)
}

if cfg.PITR != nil {
if c := string(cfg.PITR.Compression); c != "" && !compress.IsValidCompressionType(c) {
return errors.Errorf("unsupported compression type: %q", c)
Expand Down Expand Up @@ -725,7 +718,9 @@ func SetConfigVar(ctx context.Context, m connect.Client, key, val string) error
return errors.New("storage.filesystem.path can't be empty")
}
case "storage.s3.debugLogLevels":
s3.SDKLogLevel(v.(string), os.Stderr)
if err := s3.ValidateDebugLogLevels(v.(string)); err != nil {
return errors.Wrap(err, "set s3 debug log")
}
}

_, err = m.ConfigCollection().UpdateOne(ctx,
Expand Down
47 changes: 47 additions & 0 deletions pbm/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/mongodb"
"go.mongodb.org/mongo-driver/v2/bson"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options"
"go.mongodb.org/mongo-driver/v2/mongo/readpref"
Expand Down Expand Up @@ -620,6 +621,52 @@ func TestConfig(t *testing.T) {
})
}

func TestS3DebugLogLevelValidation(t *testing.T) {
ctx := context.Background()
newConfig := func(levels string) *Config {
return &Config{
Storage: StorageConf{
Type: storage.S3,
S3: &s3.Config{
Bucket: "bucket",
DebugLogLevels: levels,
},
},
}
}

const validLevels = "Signing,Retries"
require.NoError(t, SetConfig(ctx, connClient, newConfig(validLevels)))
require.NoError(t, SetConfigVar(ctx, connClient, "storage.s3.debugLogLevels", "Request,Response"))

err := SetConfigVar(ctx, connClient, "storage.s3.debugLogLevels", "RequestEventMessage")
require.ErrorContains(t, err, "set s3 debug log")

err = SetConfig(ctx, connClient, newConfig("LogDebug"))
require.Error(t, err)

profile := newConfig("Unknown")
profile.Name = "invalid-debug-log-level"
profile.IsProfile = true
err = AddProfile(ctx, connClient, profile)
require.Error(t, err)

_, err = connClient.ConfigCollection().UpdateOne(ctx,
bson.D{{"profile", nil}},
bson.M{"$set": bson.M{"storage.s3.debugLogLevels": "Unknown"}},
)
require.NoError(t, err)

persisted, err := GetConfig(ctx, connClient)
require.NoError(t, err)
require.ErrorContains(t, persisted.Storage.Cast(), "validate s3 debug log")

require.NoError(t, SetConfigVar(ctx, connClient, "storage.s3.debugLogLevels", "Signing"))
got, err := GetConfigVar(ctx, connClient, "storage.s3.debugLogLevels")
require.NoError(t, err)
assert.Equal(t, "Signing", got)
}

func TestRestoreConfGetIndexCommitQuorum(t *testing.T) {
tests := []struct {
name string
Expand Down
9 changes: 0 additions & 9 deletions pbm/config/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,13 @@ package config

import (
"context"
"os"

"go.mongodb.org/mongo-driver/v2/bson"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options"

"github.com/percona/percona-backup-mongodb/pbm/connect"
"github.com/percona/percona-backup-mongodb/pbm/errors"
"github.com/percona/percona-backup-mongodb/pbm/storage"
"github.com/percona/percona-backup-mongodb/pbm/storage/s3"
)

func ListProfiles(ctx context.Context, m connect.Client) ([]Config, error) {
Expand Down Expand Up @@ -66,12 +63,6 @@ func AddProfile(ctx context.Context, m connect.Client, profile *Config) error {
}
sanitizeStoragePaths(&profile.Storage)

if profile.Storage.Type == storage.S3 {
// call the function for notification purpose.
// warning about unsupported levels will be printed
s3.SDKLogLevel(profile.Storage.S3.DebugLogLevels, os.Stderr)
}

_, err := m.ConfigCollection().ReplaceOne(ctx,
bson.D{
{"profile", true},
Expand Down
111 changes: 27 additions & 84 deletions pbm/storage/s3/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"crypto/md5"
"crypto/tls"
"encoding/base64"
"fmt"
"io"
"maps"
"net/http"
Expand Down Expand Up @@ -61,11 +60,10 @@
// certificate chain and host name
InsecureSkipTLSVerify bool `bson:"insecureSkipTLSVerify" json:"insecureSkipTLSVerify" yaml:"insecureSkipTLSVerify"`

// DebugLogLevels enables AWS SDK debug logging (sub)levels. Available options:
// LogDebug, Signing, HTTPBody, RequestRetries, RequestErrors, EventStreamBody
//
// Any sub levels will enable LogDebug level accordingly to AWS SDK Go module behavior
// https://pkg.go.dev/github.com/aws/aws-sdk-go@v1.40.7/aws#LogLevelType
// DebugLogLevels enables AWS SDK v2 debug logging modes. Available options:
// Signing, Retries, Request, RequestWithBody, Response, ResponseWithBody,
// DeprecatedUsage.
// https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#ClientLogMode
DebugLogLevels string `bson:"debugLogLevels,omitempty" json:"debugLogLevels,omitempty" yaml:"debugLogLevels,omitempty"`

// Retryer is configuration for client.DefaultRetryer
Expand All @@ -90,21 +88,13 @@
type SDKDebugLogLevel string

const (
Signing SDKDebugLogLevel = "Signing"
Retries SDKDebugLogLevel = "Retries"
Request SDKDebugLogLevel = "Request"
RequestWithBody SDKDebugLogLevel = "RequestWithBody"
Response SDKDebugLogLevel = "Response"
ResponseWithBody SDKDebugLogLevel = "ResponseWithBody"
DeprecatedUsage SDKDebugLogLevel = "DeprecatedUsage"
RequestEventMessage SDKDebugLogLevel = "RequestEventMessage"
ResponseEventMessage SDKDebugLogLevel = "ResponseEventMessage"

LogDebug SDKDebugLogLevel = "LogDebug"
HTTPBody SDKDebugLogLevel = "HTTPBody"
RequestRetries SDKDebugLogLevel = "RequestRetries"
RequestErrors SDKDebugLogLevel = "RequestErrors"
EventStreamBody SDKDebugLogLevel = "EventStreamBody"
Signing SDKDebugLogLevel = "Signing"
Retries SDKDebugLogLevel = "Retries"
Request SDKDebugLogLevel = "Request"
RequestWithBody SDKDebugLogLevel = "RequestWithBody"
Response SDKDebugLogLevel = "Response"
ResponseWithBody SDKDebugLogLevel = "ResponseWithBody"
DeprecatedUsage SDKDebugLogLevel = "DeprecatedUsage"
)

type AWSsse struct {
Expand Down Expand Up @@ -209,6 +199,9 @@
if cfg == nil {
return errors.New("missing S3 configuration with S3 storage type")
}
if err := ValidateDebugLogLevels(cfg.DebugLogLevels); err != nil {
return errors.Wrap(err, "validate s3 debug log")
}
if cfg.Region == "" {
cfg.Region = defaultS3Region
}
Expand Down Expand Up @@ -252,38 +245,16 @@
return defaultMaxObjSizeGB
}

// SDKLogLevel returns AWS SDK log level value from comma-separated
// SDKDebugLogLevel values string. If the string does not contain a valid value,
// returns 0 (logging is disabled).
//
// If the string is incorrect formatted, prints warnings to the io.Writer.
// Passing nil as the io.Writer will discard any warnings.
//
// Deprecated log level values from v1 are supported for backwards
// compatibility and are automatically mapped to their current equivalents.
func SDKLogLevel(levels string, out io.Writer) aws.ClientLogMode {
if out == nil {
out = io.Discard
}

var logLevel aws.ClientLogMode

// ValidateDebugLogLevels checks that all configured levels are supported.
func ValidateDebugLogLevels(levels string) error {
for _, lvl := range strings.Split(levels, ",") {
lvl = strings.TrimSpace(lvl)
if lvl == "" {
continue
if lvl != "" && toClientLogMode(lvl) == 0 {
return errors.Errorf("unsupported S3 client debug log level %q", lvl)
}

l := toClientLogMode(lvl)
if l == 0 {
fmt.Fprintf(out, "Warning: S3 client debug log level: unsupported %q\n", lvl)
continue
}

logLevel |= l
}

return logLevel
return nil
}

//nolint:lll
Expand Down Expand Up @@ -440,7 +411,7 @@
storage.PrettySize(partSize))
}

_, err := manager.NewUploader(s.s3cli, func(u *manager.Uploader) {

Check failure on line 414 in pbm/storage/s3/s3.go

View workflow job for this annotation

GitHub Actions / runner / golangci-lint

SA1019: manager.NewUploader(s.s3cli, func(u *manager.Uploader) {
u.MaxUploadParts = s.opts.MaxUploadParts
u.PartSize = partSize // 10MB part size
u.LeavePartsOnError = true // Don't delete the parts if the upload fails.
Expand Down Expand Up @@ -718,55 +689,27 @@
for _, item := range items {
flag := strings.TrimSpace(item)

switch flag {
case "Signing":
// v1 had "LogDebugWithSigning"
switch SDKDebugLogLevel(flag) {
case Signing:
mode |= aws.LogSigning

case "Retries":
case Retries:
mode |= aws.LogRetries

case "Request":
case Request:
mode |= aws.LogRequest

case "RequestWithBody":
case RequestWithBody:
mode |= aws.LogRequestWithBody

case "Response":
case Response:
mode |= aws.LogResponse

case "ResponseWithBody":
case ResponseWithBody:
mode |= aws.LogResponseWithBody

case "DeprecatedUsage":
case DeprecatedUsage:
mode |= aws.LogDeprecatedUsage

case "RequestEventMessage":
mode |= aws.LogRequestEventMessage

case "ResponseEventMessage":
mode |= aws.LogResponseEventMessage

// Mapping deprecated flags from v1 for backwards compatibility
case "LogDebug":
// v1 had "LogDebug"
mode |= aws.LogRequest | aws.LogResponse

case "HTTPBody":
// v1 had "LogDebugWithHTTPBody"
mode |= aws.LogRequestWithBody | aws.LogResponseWithBody

case "RequestRetries":
// v1 had "LogDebugWithRequestRetries"
mode |= aws.LogRetries

case "RequestErrors":
// v1 had "LogDebugWithRequestErrors"
mode |= aws.LogResponse

case "EventStreamBody":
// v1 had "LogDebugWithEventStreamBody"
mode |= aws.LogRequestWithBody | aws.LogResponseWithBody
}
}

Expand Down
Loading
Loading