-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathgsapi.go
133 lines (118 loc) · 3.52 KB
/
gsapi.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright (c) 2021 Zededa, Inc.
// SPDX-License-Identifier: Apache-2.0
package gsutil
import (
"context"
"encoding/base64"
"encoding/hex"
"fmt"
"log"
"net/http"
"cloud.google.com/go/storage"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/api/iterator"
"google.golang.org/api/option"
)
//GSctx context for google cloud storage communication
type GSctx struct {
gsClient *storage.Client
projectID string
ctx context.Context
}
//NewGsCtx creates GSctx for provided options
//it uses data from apiKeyJSONContent to decode service account credentials
//setting of requestWriteAccess adds write scope to token in case of provided hctx
func NewGsCtx(ctx context.Context, projectID, apiKeyJSONContent string, hctx *http.Client, requestWriteAccess bool) (*GSctx, error) {
if ctx == nil {
ctx = context.Background()
}
var options []option.ClientOption
data, err := base64.StdEncoding.DecodeString(apiKeyJSONContent)
if err != nil {
data = []byte(apiKeyJSONContent)
}
if hctx != nil {
// we use different flow for provided http client
// because of WithHTTPClient overrides other options
// and removes authentication, so we use oauth2 transport
scope := "https://www.googleapis.com/auth/devstorage.read_only"
if requestWriteAccess {
scope = "https://www.googleapis.com/auth/devstorage.read_write"
}
JWTCfg, err := google.JWTConfigFromJSON(data, scope)
if err != nil {
return nil, fmt.Errorf("JWTConfigFromJSON error: %v", err)
}
transport := &oauth2.Transport{
Source: JWTCfg.TokenSource(ctx),
Base: hctx.Transport,
}
options = []option.ClientOption{option.WithHTTPClient(&http.Client{Transport: transport})}
} else {
options = append(options, option.WithCredentialsJSON(data))
}
client, err := storage.NewClient(ctx, options...)
if err != nil {
return nil, fmt.Errorf("NewClient error: %v", err)
}
gsCtx := GSctx{
gsClient: client,
projectID: projectID,
ctx: ctx,
}
return &gsCtx, nil
}
//CreateBucket creates bucket with the given name
func (s *GSctx) CreateBucket(bname string) error {
err := s.gsClient.Bucket(bname).Create(s.ctx, s.projectID, nil)
if err != nil {
log.Printf("Failed to create bucket %s in project %s/%v", bname, s.projectID, err)
return err
}
return nil
}
//IsBucketAvailable checks if the bucket with the given name available
func (s *GSctx) IsBucketAvailable(bname string) (bool, error) {
for {
bi, err := s.gsClient.Buckets(s.ctx, s.projectID).Next()
if err == iterator.Done {
break
}
if err != nil {
log.Printf("Failed to list buckets %s in project %s/%s", bname, s.projectID, err.Error())
return false, err
}
if bi == nil {
break
}
if bi.Name == bname {
return true, nil
}
}
return false, nil
}
//DeleteBucket removes the bucket
func (s *GSctx) DeleteBucket(bname string) error {
return s.gsClient.Bucket(bname).Delete(s.ctx)
}
//DeleteObject removes the object from bucket
func (s *GSctx) DeleteObject(bname, bkey string) error {
return s.gsClient.Bucket(bname).Object(bkey).Delete(s.ctx)
}
//GetObjectSize returns the size of object in bytes
func (s *GSctx) GetObjectSize(bname, bkey string) (int64, error) {
attrs, err := s.gsClient.Bucket(bname).Object(bkey).Attrs(s.ctx)
if err != nil {
return 0, err
}
return attrs.Size, nil
}
//GetObjectMD5 returns hex string of MD5 hash of object
func (s *GSctx) GetObjectMD5(bname, bkey string) (string, error) {
attrs, err := s.gsClient.Bucket(bname).Object(bkey).Attrs(s.ctx)
if err != nil {
return "", err
}
return hex.EncodeToString(attrs.MD5), nil
}