mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-24 15:00:43 +02:00
* shell: discover the filer on first use instead of at startup The startup retry loop made every weed shell invocation wait out the connect timeout on clusters that have no filer, even for commands that only talk to the master. Discovery now runs once, on the first command that actually needs a filer, keeping the retry-until-registered fix for the fresh-cluster race without stalling master-only commands. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * shell: stop filer discovery retries on non-transient errors A master that keeps answering ListClusterNodes with a permanent error (permission denied, unimplemented) cannot gain a filer by retrying, so discovery returns instead of polling until the deadline. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * shell: explain an empty filer list when discovery times out * shell: retry filer discovery while the address is still empty Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
92 lines
2.6 KiB
Go
92 lines
2.6 KiB
Go
package shell
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/pb"
|
|
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
|
"github.com/seaweedfs/seaweedfs/weed/s3api/s3tables"
|
|
"google.golang.org/grpc"
|
|
)
|
|
|
|
const s3TablesDefaultRegion = ""
|
|
const timeFormat = "2006-01-02T15:04:05Z07:00"
|
|
|
|
func withFilerClient(commandEnv *CommandEnv, fn func(client filer_pb.SeaweedFilerClient) error) error {
|
|
return pb.WithGrpcClient(context.Background(), false, 0, func(conn *grpc.ClientConn) error {
|
|
client := filer_pb.NewSeaweedFilerClient(conn)
|
|
return fn(client)
|
|
}, commandEnv.FilerAddress().ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
|
|
}
|
|
|
|
func executeS3Tables(commandEnv *CommandEnv, operation string, req interface{}, resp interface{}, accountID string) error {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
return withFilerClient(commandEnv, func(client filer_pb.SeaweedFilerClient) error {
|
|
manager := s3tables.NewManager()
|
|
// The shell talks to the filer directly with no S3 auth, so it is trusted.
|
|
manager.SetTrusted(true)
|
|
mgrClient := s3tables.NewManagerClient(client)
|
|
return manager.Execute(ctx, mgrClient, operation, req, resp, accountID)
|
|
})
|
|
}
|
|
|
|
func parseS3TablesError(err error) error {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
var s3Err *s3tables.S3TablesError
|
|
if errors.As(err, &s3Err) {
|
|
if s3Err.Message != "" {
|
|
return fmt.Errorf("%s: %s", s3Err.Type, s3Err.Message)
|
|
}
|
|
return fmt.Errorf("%s", s3Err.Type)
|
|
}
|
|
return err
|
|
}
|
|
|
|
func parseS3TablesTags(value string) (map[string]string, error) {
|
|
parsed := make(map[string]string)
|
|
for _, kv := range strings.Split(value, ",") {
|
|
if kv == "" {
|
|
continue
|
|
}
|
|
parts := strings.SplitN(kv, "=", 2)
|
|
if len(parts) != 2 {
|
|
return nil, fmt.Errorf("invalid tag: %s", kv)
|
|
}
|
|
parsed[parts[0]] = parts[1]
|
|
}
|
|
if err := s3tables.ValidateTags(parsed); err != nil {
|
|
return nil, err
|
|
}
|
|
return parsed, nil
|
|
}
|
|
|
|
func parseS3TablesTagKeys(value string) ([]string, error) {
|
|
var keys []string
|
|
for _, key := range strings.Split(value, ",") {
|
|
key = strings.TrimSpace(key)
|
|
if key == "" {
|
|
continue
|
|
}
|
|
keys = append(keys, key)
|
|
}
|
|
if len(keys) == 0 {
|
|
return nil, fmt.Errorf("tagKeys are required")
|
|
}
|
|
return keys, nil
|
|
}
|
|
|
|
func buildS3TablesBucketARN(bucketName, accountID string) (string, error) {
|
|
return s3tables.BuildBucketARN(s3TablesDefaultRegion, accountID, bucketName)
|
|
}
|
|
|
|
func buildS3TablesTableARN(bucketName, namespace, tableName, accountID string) (string, error) {
|
|
return s3tables.BuildTableARN(s3TablesDefaultRegion, accountID, bucketName, namespace, tableName)
|
|
}
|