105 lines
3.0 KiB
Go
105 lines
3.0 KiB
Go
package storage
|
|
|
|
import (
|
|
stderr "errors"
|
|
"fmt"
|
|
|
|
"github.com/aws/aws-sdk-go-v2/service/s3/types"
|
|
"github.com/aws/smithy-go"
|
|
"github.com/hashicorp/boundary-plugin-aws/internal/errors"
|
|
pb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
)
|
|
|
|
const (
|
|
s3StatusErrMsg = "aws s3 error: %s"
|
|
|
|
// s3ErrorBadDigest is returned when there is a checksum
|
|
// mismatch between the request and the s3 service. This
|
|
// error code is returned for the PutObject request.
|
|
s3ErrorBadDigest = "BadDigest"
|
|
)
|
|
|
|
// parseS3Error will convert an S3 api error into a RPC status. If the
|
|
// error does not match against an s3 error type, it will fallback to
|
|
// evaluating against generic aws service errors. This includes throttling,
|
|
// credentials, and connectivity error types.
|
|
//
|
|
// https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
|
|
func parseS3Error(err error, msg string) (st *status.Status) {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
var plgErr *pb.PluginError
|
|
defer func() {
|
|
if plgErr != nil {
|
|
st, err = st.WithDetails(plgErr)
|
|
if err != nil {
|
|
st = status.New(codes.Internal, err.Error())
|
|
}
|
|
}
|
|
}()
|
|
|
|
// The NoSuchBucket error is returned when trying to access
|
|
// an s3 bucket that does not exist.
|
|
var missingStore *types.NoSuchBucket
|
|
if stderr.As(err, &missingStore) {
|
|
plgErr = &pb.PluginError{
|
|
Code: pb.ERROR_ERROR_STORAGE_NO_SUCH_BUCKET,
|
|
Message: missingStore.ErrorMessage(),
|
|
Nonretryable: true,
|
|
}
|
|
return status.New(codes.NotFound, fmt.Sprintf(s3StatusErrMsg, msg))
|
|
}
|
|
|
|
// The NoSuchKey error is returned when trying to download
|
|
// an object from s3 that does not exist.
|
|
var missingObject *types.NoSuchKey
|
|
if stderr.As(err, &missingObject) {
|
|
plgErr = &pb.PluginError{
|
|
Code: pb.ERROR_ERROR_STORAGE_NO_SUCH_OBJECT,
|
|
Message: missingObject.ErrorMessage(),
|
|
Nonretryable: true,
|
|
}
|
|
return status.New(codes.NotFound, fmt.Sprintf(s3StatusErrMsg, msg))
|
|
}
|
|
|
|
var notFound *types.NotFound
|
|
if stderr.As(err, ¬Found) {
|
|
plgErr = &pb.PluginError{
|
|
Code: pb.ERROR_ERROR_STORAGE_NO_SUCH_OBJECT,
|
|
Message: notFound.ErrorMessage(),
|
|
Nonretryable: true,
|
|
}
|
|
return status.New(codes.NotFound, fmt.Sprintf(s3StatusErrMsg, msg))
|
|
}
|
|
|
|
// The InvalidObjectState error is returned when trying to
|
|
// access an object that was moved into cold storage.
|
|
var invalidState *types.InvalidObjectState
|
|
if stderr.As(err, &invalidState) {
|
|
plgErr = &pb.PluginError{
|
|
Code: pb.ERROR_ERROR_STORAGE_NO_SUCH_OBJECT,
|
|
Message: invalidState.ErrorMessage(),
|
|
Nonretryable: true,
|
|
}
|
|
return status.New(codes.NotFound, fmt.Sprintf(s3StatusErrMsg, msg))
|
|
}
|
|
|
|
var apiErr smithy.APIError
|
|
if stderr.As(err, &apiErr) {
|
|
if apiErr.ErrorCode() == s3ErrorBadDigest {
|
|
plgErr = &pb.PluginError{
|
|
Code: pb.ERROR_ERROR_STORAGE_CHECKSUM_MISMATCH,
|
|
Message: apiErr.ErrorMessage(),
|
|
Nonretryable: false,
|
|
}
|
|
return status.New(codes.Aborted, fmt.Sprintf(s3StatusErrMsg, msg))
|
|
}
|
|
}
|
|
|
|
return errors.ParseAWSError(err, msg)
|
|
}
|