driftctl/pkg/iac/terraform/state/backend/s3_reader.go

73 lines
1.6 KiB
Go

package backend
import (
"io"
"strings"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/pkg/errors"
"github.com/snyk/driftctl/pkg/envproxy"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/s3/s3iface"
)
const BackendKeyS3 = "s3"
type S3Backend struct {
input s3.GetObjectInput
reader io.ReadCloser
S3Client s3iface.S3API
}
func NewS3Reader(path string) (*S3Backend, error) {
backend := S3Backend{}
bucketPath := strings.Split(path, "/")
if len(bucketPath) < 2 {
return nil, errors.Errorf("Unable to parse S3 path: %s. Must be BUCKET_NAME/PATH/TO/OBJECT", path)
}
bucket := bucketPath[0]
key := strings.Join(bucketPath[1:], "/")
backend.input = s3.GetObjectInput{
Key: &key,
Bucket: &bucket,
}
envProxy := envproxy.NewEnvProxy("DCTL_S3_", "AWS_")
envProxy.Apply()
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))
envProxy.Restore()
backend.S3Client = s3.New(sess)
return &backend, nil
}
func (s *S3Backend) Read(p []byte) (n int, err error) {
if s.reader == nil {
response, err := s.S3Client.GetObject(&s.input)
if err != nil {
requestFailure, ok := err.(s3.RequestFailure)
if ok {
return 0, errors.Errorf(
"Error reading state '%s' from s3 bucket '%s': %s",
*s.input.Key,
*s.input.Bucket,
requestFailure.Message(),
)
}
return 0, err
}
s.reader = response.Body
}
return s.reader.Read(p)
}
func (s *S3Backend) Close() error {
if s.reader != nil {
return s.reader.Close()
}
return errors.New("Unable to close reader as nothing was opened")
}