Files
seaweedfs/weed/shell/command_s3_iam_client.go
T
Chris LuandDevin 6a34d82f05 shell: retry filer discovery until master knows a filer (#11989)
* 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>
2026-10-23 22:52:51 -07:00

46 lines
1.9 KiB
Go

package shell
import (
"context"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"github.com/seaweedfs/seaweedfs/weed/security"
"github.com/seaweedfs/seaweedfs/weed/util"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)
// iamRequestTimeout caps every shell-originated IAM gRPC call so the shell
// can't hang on an unresponsive filer.
const iamRequestTimeout = 30 * time.Second
// withIamClient invokes fn against the filer's IAM gRPC service. When
// jwt.filer_signing.key is configured in security.toml, a freshly minted admin
// Bearer token is attached to the outgoing context so the filer's
// IamGrpcServer.checkAdminAuth passes; with no key configured the filer
// accepts unauthenticated calls. The context already has the iamRequestTimeout
// applied — callers can derive child contexts but should not need their own
// timeout boilerplate.
func (ce *CommandEnv) withIamClient(fn func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error) error {
return pb.WithGrpcClient(context.Background(), false, 0, func(conn *grpc.ClientConn) error {
ctx, cancel := context.WithTimeout(iamAdminAuthContext(context.Background()), iamRequestTimeout)
defer cancel()
return fn(ctx, iam_pb.NewSeaweedIdentityAccessManagementClient(conn))
}, ce.FilerAddress().ToGrpcAddress(), false, ce.option.GrpcDialOption)
}
func iamAdminAuthContext(ctx context.Context) context.Context {
signingKey := util.GetViper().GetString("jwt.filer_signing.key")
if signingKey == "" {
return ctx
}
expiresAfterSec := util.GetViper().GetInt("jwt.filer_signing.expires_after_seconds")
token := security.GenJwtForFilerAdmin(security.SigningKey(signingKey), expiresAfterSec)
if token == "" {
return ctx
}
return metadata.AppendToOutgoingContext(ctx, "authorization", security.BearerPrefix+string(token))
}