1package storage 2 3import ( 4 "context" 5 "encoding/hex" 6 "encoding/json" 7 "fmt" 8 "io" 9 10 gcs "cloud.google.com/go/storage" 11 "github.com/mholt/archiver" 12 oauthgoogle "golang.org/x/oauth2/google" 13 "google.golang.org/api/iterator" 14 "google.golang.org/api/option" 15) 16 17// untested gcs api instantiation 18type objectHandleWrapper struct { 19 objectHandle *gcs.ObjectHandle 20} 21 22func (o objectHandleWrapper) Version() (Version, error) { 23 r, err := o.objectHandle.Attrs(context.Background()) 24 if err == gcs.ErrObjectNotExist { 25 return Version{}, ObjectNotFoundError 26 } 27 if err != nil { 28 return Version{}, err 29 } 30 31 return Version{Name: r.Name, Ref: hex.EncodeToString(r.MD5), Updated: r.Updated}, nil 32} 33 34func (o objectHandleWrapper) NewReader() (io.ReadCloser, error) { 35 r, err := o.objectHandle.NewReader(context.Background()) 36 if err == gcs.ErrObjectNotExist { 37 return nil, ObjectNotFoundError 38 } 39 return r, err 40} 41 42func (o objectHandleWrapper) NewWriter() io.WriteCloser { 43 return o.objectHandle.NewWriter(context.Background()) 44} 45 46type bucketHandleWrapper struct { 47 bucketHandle *gcs.BucketHandle 48} 49 50func (b bucketHandleWrapper) GetAllObjects() ([]Object, error) { 51 objectIter := b.bucketHandle.Objects(context.Background(), nil) 52 53 var objects []Object 54 for { 55 next, err := objectIter.Next() 56 if err == iterator.Done { 57 break 58 } 59 if err != nil { 60 return nil, err 61 } 62 handle := objectHandleWrapper{objectHandle: b.bucketHandle.Object(next.Name)} 63 objects = append(objects, handle) 64 } 65 return objects, nil 66} 67 68func (b bucketHandleWrapper) Delete() error { 69 objectIter := b.bucketHandle.Objects(context.Background(), nil) 70 71 for { 72 next, err := objectIter.Next() 73 if err == iterator.Done { 74 break 75 } 76 if err != nil { 77 return err 78 } 79 err = b.bucketHandle.Object(next.Name).Delete(context.Background()) 80 if err != nil { 81 return err 82 } 83 } 84 return b.bucketHandle.Delete(context.Background()) 85} 86 87func NewGCSStorage(serviceAccountKey, objectName, bucketName string) (Storage, error) { 88 storageJwtConf, err := oauthgoogle.JWTConfigFromJSON([]byte(serviceAccountKey), gcs.ScopeReadWrite) 89 if err != nil { 90 return Storage{}, fmt.Errorf("failed to form JWT config from GCP storage account key: %s", err) 91 } 92 ctx := context.Background() 93 tokenSource := storageJwtConf.TokenSource(ctx) 94 95 storageClient, err := gcs.NewClient(ctx, option.WithTokenSource(tokenSource)) 96 if err != nil { 97 return Storage{}, fmt.Errorf("failed to instantiate storageclient: %s", err) 98 } 99 100 p := struct { 101 ProjectId string `json:"project_id"` 102 }{} 103 if err := json.Unmarshal([]byte(serviceAccountKey), &p); err != nil { 104 return Storage{}, fmt.Errorf("Unmarshalling account key for project id: %s", err) 105 } 106 bucket := storageClient.Bucket(bucketName).UserProject(p.ProjectId) 107 108 _, err = bucket.Attrs(ctx) 109 if err != nil && err != gcs.ErrBucketNotExist { 110 return Storage{}, fmt.Errorf("Failed to get bucket: %s", err) 111 } else if err == gcs.ErrBucketNotExist { 112 err = bucket.Create(ctx, p.ProjectId, nil) 113 } 114 if err != nil { 115 return Storage{}, fmt.Errorf("Failed to create bucket: %s", err) 116 } 117 118 object := bucket.Object(objectName) 119 120 return Storage{ 121 Name: objectName, 122 Bucket: bucketHandleWrapper{ 123 bucketHandle: bucket, 124 }, 125 Object: objectHandleWrapper{ 126 objectHandle: object, 127 }, 128 Archiver: archiver.TarGz, 129 }, nil 130} 131