Skip to content

Commit 411c140

Browse files
committed
Allow to pick up the AWS_REGION from the AWS Go SDK instead of having to set it up always.
1 parent a38d050 commit 411c140

File tree

1 file changed

+55
-27
lines changed

1 file changed

+55
-27
lines changed

pkg/s3/client.go

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,7 @@ func NewClientFromURL(s3URL string) (*Client, error) {
135135
secretKey := os.Getenv("AWS_SECRET_ACCESS_KEY")
136136
endpoint := os.Getenv("AWS_ENDPOINT")
137137
region := os.Getenv("AWS_REGION")
138-
if region == "" {
139-
region = "us-east-1" // Default region
140-
}
138+
// Don't default to us-east-1, let AWS SDK detect the region
141139

142140
// Path style defaults to false unless env var is set
143141
pathStyle := false
@@ -254,9 +252,8 @@ func NewClient(endpoint, bucket, accessKey, secretKey, region string, sslMode, p
254252
if envRegion := os.Getenv("AWS_REGION"); envRegion != "" {
255253
region = envRegion
256254
// fmt.Printf("S3 Client Debug - Using region from environment: %s\n", region)
257-
} else {
258-
region = "us-east-1" // Default region
259255
}
256+
// Don't default to us-east-1, let AWS SDK detect the region from config/metadata
260257
}
261258

262259
// Only use environment endpoint if no explicit endpoint was provided
@@ -323,9 +320,7 @@ func NewClientFromEnv(bucket string) (*Client, error) {
323320
secretKey := os.Getenv("AWS_SECRET_ACCESS_KEY")
324321
endpoint := os.Getenv("AWS_ENDPOINT")
325322
region := os.Getenv("AWS_REGION")
326-
if region == "" {
327-
region = "us-east-1"
328-
}
323+
// Don't default to us-east-1, let AWS SDK detect the region
329324

330325
// Path style is determined from environment
331326
pathStyle := false
@@ -376,49 +371,71 @@ func (c *Client) initialize(ctx context.Context) error {
376371
}
377372
}
378373

379-
// Create custom resolver for endpoint
380-
// This is critical for making localstack work with AWS SDK v2
381-
customResolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
382-
// Always return the custom endpoint for any service in any region
383-
// This is necessary for localstack compatibility
384-
endpoint := aws.Endpoint{
385-
URL: c.Endpoint,
386-
SigningRegion: c.Region,
387-
HostnameImmutable: true,
388-
}
389-
// fmt.Printf("S3 Client Debug - Resolving endpoint to URL: '%s', SigningRegion: '%s'\n",
390-
// endpoint.URL, endpoint.SigningRegion)
391-
return endpoint, nil
392-
})
393-
394374
// Load config using options
395375
var configOpts []func(*config.LoadOptions) error
396376

397-
// Always use custom endpoint resolver if an endpoint is provided
377+
// Only use custom endpoint resolver if an endpoint is provided (for localstack, etc.)
398378
if c.Endpoint != "" {
379+
// Create custom resolver for endpoint
380+
// This is critical for making localstack work with AWS SDK v2
381+
customResolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
382+
// Always return the custom endpoint for any service in any region
383+
// This is necessary for localstack compatibility
384+
signingRegion := c.Region
385+
if signingRegion == "" {
386+
// Use the region passed by the SDK if we don't have one
387+
signingRegion = region
388+
}
389+
endpoint := aws.Endpoint{
390+
URL: c.Endpoint,
391+
SigningRegion: signingRegion,
392+
HostnameImmutable: true,
393+
}
394+
// fmt.Printf("S3 Client Debug - Resolving endpoint to URL: '%s', SigningRegion: '%s'\n",
395+
// endpoint.URL, endpoint.SigningRegion)
396+
return endpoint, nil
397+
})
398+
399399
// fmt.Printf("S3 Client Debug - Using custom endpoint: %s\n", c.Endpoint)
400400
configOpts = append(configOpts, config.WithEndpointResolverWithOptions(customResolver))
401401

402402
// Disable AWS SDK v2's automatic endpoint resolution
403403
configOpts = append(configOpts, config.WithRetryMaxAttempts(1))
404404
}
405405

406-
// Add region
407-
configOpts = append(configOpts, config.WithRegion(c.Region))
406+
// Add region if explicitly provided
407+
if c.Region != "" {
408+
configOpts = append(configOpts, config.WithRegion(c.Region))
409+
}
410+
// If no region provided, LoadDefaultConfig will use the default region chain:
411+
// 1. AWS_REGION environment variable
412+
// 2. AWS_DEFAULT_REGION environment variable
413+
// 3. Region from shared config file (~/.aws/config)
414+
// 4. EC2 instance metadata service (if on EC2)
408415

409-
// Add credentials if provided
416+
// Add credentials if provided, otherwise use default AWS credential chain
410417
if c.AccessKey != "" && c.SecretKey != "" {
411418
configOpts = append(configOpts, config.WithCredentialsProvider(
412419
credentials.NewStaticCredentialsProvider(c.AccessKey, c.SecretKey, ""),
413420
))
414421
}
422+
// If no credentials provided, LoadDefaultConfig will use the default credential chain:
423+
// 1. Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN)
424+
// 2. Shared credentials file (~/.aws/credentials)
425+
// 3. IAM role (if running on EC2/ECS/Lambda)
415426

416427
// Load the AWS configuration
417428
cfg, err := config.LoadDefaultConfig(ctx, configOpts...)
418429
if err != nil {
419430
return errors.Wrap(err, "failed to load AWS config")
420431
}
421432

433+
// If region was not explicitly set, store the detected region
434+
if c.Region == "" {
435+
c.Region = cfg.Region
436+
// fmt.Printf("S3 Client Debug - Using detected region: %s\n", c.Region)
437+
}
438+
422439
// Create S3 client with path style config if needed
423440
s3Client := s3.NewFromConfig(cfg, func(o *s3.Options) {
424441
// Always use path style for LocalStack
@@ -598,6 +615,17 @@ func (c *Client) BucketExists(ctx context.Context) (bool, error) {
598615
if strings.Contains(err.Error(), "NotFound") || strings.Contains(err.Error(), "404") {
599616
return false, nil
600617
}
618+
// Check for 301 redirect which means wrong region
619+
if strings.Contains(err.Error(), "301") || strings.Contains(err.Error(), "MovedPermanently") {
620+
// For AWS S3, a 301 error means the bucket exists but is in a different region
621+
// We'll print a helpful warning but not fail the check
622+
fmt.Printf("WARNING: Failed to check if bucket exists: %v\n", err)
623+
fmt.Printf("This usually means the bucket '%s' exists but is in a different region than '%s'.\n", c.Bucket, c.Region)
624+
fmt.Printf("Please set the correct region using AWS_REGION environment variable.\n")
625+
// Since we can't properly verify the bucket, we'll return an error
626+
// This prevents potential issues with trying to use a bucket in the wrong region
627+
return false, fmt.Errorf("bucket appears to be in a different region (got 301 redirect)")
628+
}
601629
return false, errors.Wrap(err, "failed to check bucket existence")
602630
}
603631

0 commit comments

Comments
 (0)