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 }