gitlab.com/beacon-software/gadget@v0.0.0-20181217202115-54565ea1ed5e/storage/s3.go (about)

     1  package storage
     2  
     3  import (
     4  	"bytes"
     5  
     6  	"github.com/aws/aws-sdk-go/aws"
     7  	"github.com/aws/aws-sdk-go/aws/session"
     8  	"github.com/aws/aws-sdk-go/service/s3"
     9  	"github.com/aws/aws-sdk-go/service/s3/s3manager"
    10  
    11  	"gitlab.com/beacon-software/gadget/errors"
    12  	"gitlab.com/beacon-software/gadget/log"
    13  )
    14  
    15  var publicACL = "public-read"
    16  
    17  // Bucket wraps the S3 downloader with an in memory cache
    18  type Bucket struct {
    19  	bucket string
    20  	key    string
    21  	// ACL Amazon S3 access control lists value
    22  	ACL string
    23  }
    24  
    25  // NewS3 returns a Bucket with an S3 downloader
    26  func NewS3(bucket, key string) *Bucket {
    27  	return &Bucket{
    28  		bucket: bucket,
    29  		key:    key,
    30  		ACL:    publicACL,
    31  	}
    32  }
    33  
    34  func newSession() (*session.Session, errors.TracerError) {
    35  	session, err := session.NewSessionWithOptions(session.Options{
    36  		SharedConfigState: session.SharedConfigEnable,
    37  	})
    38  	return session, errors.Wrap(err)
    39  }
    40  
    41  // ReadObject downloads a file from s3 into a byte array
    42  func (b *Bucket) ReadObject() ([]byte, errors.TracerError) {
    43  	data := aws.NewWriteAtBuffer([]byte{})
    44  
    45  	session, tracerError := newSession()
    46  	if tracerError != nil {
    47  		return nil, tracerError
    48  	}
    49  
    50  	downloader := s3manager.NewDownloader(session)
    51  
    52  	_, err := downloader.Download(data,
    53  		&s3.GetObjectInput{
    54  			Bucket: aws.String(b.bucket),
    55  			Key:    aws.String(b.key),
    56  		})
    57  
    58  	if err != nil {
    59  		log.Errorf("Issue loading from S3, %s/%s (%s)", b.bucket, b.key, err)
    60  		return nil, errors.Wrap(err)
    61  	}
    62  	return data.Bytes(), nil
    63  }
    64  
    65  // WriteObject writes an object to a file in s3
    66  func (b *Bucket) WriteObject(p []byte) errors.TracerError {
    67  	session, tracerError := newSession()
    68  	if tracerError != nil {
    69  		return tracerError
    70  	}
    71  
    72  	uploader := s3manager.NewUploader(session)
    73  	upParams := &s3manager.UploadInput{
    74  		Bucket: &b.bucket,
    75  		Key:    &b.key,
    76  		Body:   bytes.NewReader(p),
    77  		ACL:    &b.ACL,
    78  	}
    79  	_, err := uploader.Upload(upParams)
    80  	if nil != err {
    81  		log.Errorf("Issue writing to S3, %s/%s (%s)", b.bucket, b.key, err)
    82  		return errors.Wrap(err)
    83  	}
    84  	return nil
    85  }
    86  
    87  // List the contents of a bucket with the given prefix
    88  func (b *Bucket) List(prefix string, startAfter string) (*s3.ListObjectsV2Output, errors.TracerError) {
    89  	session, tracerError := newSession()
    90  	if tracerError != nil {
    91  		return nil, tracerError
    92  	}
    93  
    94  	svc := s3.New(session)
    95  	input := &s3.ListObjectsV2Input{
    96  		Bucket:     aws.String(b.bucket),
    97  		Prefix:     aws.String(prefix),
    98  		StartAfter: aws.String(startAfter),
    99  	}
   100  
   101  	result, err := svc.ListObjectsV2(input)
   102  	if err != nil {
   103  		return nil, errors.Wrap(err)
   104  	}
   105  	return result, nil
   106  }
   107  
   108  // PruneByPrefix will remove objects over maxObjects from an S3 bucket with the given prefix
   109  func PruneByPrefix(bucket string, prefix string, maxObjects int) {
   110  	svc := s3.New(session.New())
   111  	input := &s3.ListObjectsV2Input{
   112  		Bucket: aws.String(bucket),
   113  		Prefix: aws.String(prefix),
   114  	}
   115  
   116  	objects, err := svc.ListObjectsV2(input)
   117  	if nil != err {
   118  		return
   119  	}
   120  
   121  	if len(objects.Contents) > maxObjects {
   122  		maxIdx := len(objects.Contents) - maxObjects
   123  		for _, obj := range objects.Contents[:maxIdx] {
   124  			delInp := &s3.DeleteObjectInput{
   125  				Bucket: aws.String(bucket),
   126  				Key:    obj.Key,
   127  			}
   128  			_, err = svc.DeleteObject(delInp)
   129  			if nil != err {
   130  				log.Errorf("prune failed for %s/%s\n%#v", bucket, *obj.Key, err)
   131  			}
   132  		}
   133  	}
   134  }