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

64 lines
1.4 KiB
Go

package backend
import (
"fmt"
"io"
"strings"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/s3/s3iface"
)
const backendS3 = "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, fmt.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,
}
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))
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, fmt.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 fmt.Errorf("Unable to close reader as nothing was opened")
}