Skip to content

Commit

Permalink
feat: support directory buckets in s3 cache
Browse files Browse the repository at this point in the history
  • Loading branch information
Michad committed Jun 6, 2024
1 parent ffe319c commit 796812b
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 3 deletions.
10 changes: 8 additions & 2 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ Cache tiles as objects in an AWS S3 bucket.

Ensure the user you're using has proper permissions for reading and writing objects in the bucket. The permissions required are the minimal set you'd expect: GetObject and PutObject. It's highly recommended to also grant ListBucket permissions, otherwise the log will contain misleading 403 error messages for every cache miss. Also ensure the user has access to the KMS key if using bucket encryption.

If you're using a Directory Bucket AKA Express One Zone there's a few things to configure:
* Ensure `storageclass` is set to "EXPRESS_ONEZONE"
* The bucket contains the full name including suffix. For example: `my-tilegroxy-cache--use1-az6--x-s3`
* An endpoint is configured in the format "https://s3express-{az_id}.{region}.amazonaws.com" For example: "https://s3express-use1-az6.us-east-1.amazonaws.com"

Name should be "s3"

Configuration options:
Expand All @@ -134,13 +139,14 @@ Configuration options:
| access | string | No | None | The AWS Access Key ID to authenticate with. This is not recommended; it is offered as a fallback authentication method only. Consult [AWS documentation](https://docs.aws.amazon.com/cli/v1/userguide/cli-chap-authentication.html) for better options |
| secret | string | No | None | The AWS Secret Key to authenticate with. This is not recommended; it is offered as a fallback authentication method only. Consult [AWS documentation](https://docs.aws.amazon.com/cli/v1/userguide/cli-chap-authentication.html) for better options |
| profile | string | No | None | The profile to use to authenticate against the AWS API. Consult [AWS documentation for specifics](https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html#file-format-profile) |
| storageclass | string | No | STANDARD | The storage class to use for the object. You probably can leave this blank and use the bucket default. Consult [AWS documentation](https://aws.amazon.com/s3/storage-classes/) for an overview of options, the specific values to use here can be found by running `aws s3 cp help` |
| storageclass | string | No | STANDARD | The storage class to use for the object. You probably can leave this blank and use the bucket default. Consult [AWS documentation](https://aws.amazon.com/s3/storage-classes/) for an overview of options. The following are currently valid: STANDARD REDUCED_REDUNDANCY STANDARD_IA ONEZONE_IA INTELLIGENT_TIERING GLACIER DEEP_ARCHIVE OUTPOSTS GLACIER_IR SNOW EXPRESS_ONEZONE |
| endpoint | string | No | AWS Auto | Override the S3 API Endpoint we talk to. Useful if you're using S3 outside AWS or using a directory bucket |

## Authentication

Implements incoming authentication schemes.

These authentication options are not comprehensive and do not support role-based authentication. For complex use cases it is recommended to implement authentication and authorization in compliance with your business logic as a proxy/gateway before tilegroxy.
These authentication options are not comprehensive and do not support authorization. That is, anyone who authenticates can access all layers. For complex use cases it is recommended to implement authentication and authorization in compliance with your business logic as a proxy/gateway before tilegroxy.

Requests that do not comply with authentication requirements will receive a 401 Unauthorized HTTP status code.

Expand Down
22 changes: 21 additions & 1 deletion internal/caches/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"errors"
"fmt"
"slices"
"strconv"
"strings"

Expand All @@ -25,6 +26,7 @@ type S3Config struct {
Path string
Profile string
StorageClass string //STANDARD | REDUCED_REDUNDANCY | STANDARD_IA | ONEZONE_IA | INTELLIGENT_TIERING | GLACIER | DEEP_ARCHIVE | GLACIER_IR
Endpoint string
}

type S3 struct {
Expand Down Expand Up @@ -61,6 +63,23 @@ func ConstructS3(config *S3Config, errorMessages *config.ErrorMessages) (*S3, er
awsConfig.WithCredentials(credentials.NewStaticCredentials(config.Access, config.Secret, ""))
}

if config.Endpoint != "" {
awsConfig.WithEndpoint(config.Endpoint)
}

if config.StorageClass != "" {
validValues := s3.StorageClass_Values()

if !slices.Contains(validValues, config.StorageClass) {
return nil, fmt.Errorf(errorMessages.EnumError, "cache.s3.storageclass", config.StorageClass, validValues)
}

if strings.Contains(config.StorageClass, "ONEZONE") {
//Directory AKA Express One Zone fails if an MD5 header set. The Go SDK requires you find this obscure flag to disable that
awsConfig.WithS3DisableContentMD5Validation(true)
}
}

sessionOptions.Config = awsConfig

if config.Profile != "" {
Expand All @@ -74,7 +93,7 @@ func ConstructS3(config *S3Config, errorMessages *config.ErrorMessages) (*S3, er
}

downloader := s3manager.NewDownloader(awsSession)
uploader := s3manager.NewUploader(awsSession)
uploader := s3manager.NewUploader(awsSession, s3manager.WithUploaderRequestOptions())

return &S3{config, downloader, uploader}, nil
}
Expand Down Expand Up @@ -109,6 +128,7 @@ func (c S3) Lookup(t pkg.TileRequest) (*pkg.Image, error) {
}

func (c S3) Save(t pkg.TileRequest, img *pkg.Image) error {

uploadConfig := &s3manager.UploadInput{
Bucket: &c.Bucket,
Key: aws.String(calcKey(&c, &t)),
Expand Down
2 changes: 2 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type ErrorMessages struct {
ServerError string
ProviderError string
ParamsBothOrNeither string
EnumError string
}

type ErrorConfig struct {
Expand Down Expand Up @@ -124,6 +125,7 @@ func DefaultConfig() Config {
ServerError: "Unexpected server error: %v",
ProviderError: "Provider failed to return image",
ParamsBothOrNeither: "Parameters %v and %v must be either both or neither supplied",
EnumError: "Invalid value supplied for %v: '%v'. It must be one of: %v",
},
},
Authentication: map[string]interface{}{
Expand Down

0 comments on commit 796812b

Please sign in to comment.