aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/gcs
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-06-01 17:09:55 +0200
committerDmitry Vyukov <dvyukov@google.com>2017-06-03 10:41:09 +0200
commit5d2b332ab5b3b5c8a170f1854d31015dbe376458 (patch)
treec906fc2ffef1818c752ff04bca32a2a2ed22cc53 /pkg/gcs
parent66fd442d487da7e9853eb467ff908ff0c1971756 (diff)
pkg/gcs: add new package
Move GCS-related functionality from syz-gce to a separate package.
Diffstat (limited to 'pkg/gcs')
-rw-r--r--pkg/gcs/gcs.go107
1 files changed, 107 insertions, 0 deletions
diff --git a/pkg/gcs/gcs.go b/pkg/gcs/gcs.go
new file mode 100644
index 000000000..ac95ec420
--- /dev/null
+++ b/pkg/gcs/gcs.go
@@ -0,0 +1,107 @@
+// Copyright 2017 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+// Package gcs provides wrappers around Google Cloud Storage (GCS) APIs.
+// Package uses Application Default Credentials assuming that the program runs on GCE.
+//
+// See the following links for details and API reference:
+// https://cloud.google.com/go/getting-started/using-cloud-storage
+// https://godoc.org/cloud.google.com/go/storage
+package gcs
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "os"
+ "strings"
+ "time"
+
+ "cloud.google.com/go/storage"
+)
+
+type Client struct {
+ client *storage.Client
+ ctx context.Context
+}
+
+type File struct {
+ Updated time.Time
+
+ ctx context.Context
+ handle *storage.ObjectHandle
+}
+
+func (file *File) Reader() (io.ReadCloser, error) {
+ return file.handle.NewReader(file.ctx)
+}
+
+func NewClient() (*Client, error) {
+ ctx := context.Background()
+ storageClient, err := storage.NewClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+ client := &Client{
+ client: storageClient,
+ ctx: ctx,
+ }
+ return client, nil
+}
+
+func (client *Client) Read(gcsFile string) (*File, error) {
+ bucket, filename, err := split(gcsFile)
+ if err != nil {
+ return nil, err
+ }
+ bkt := client.client.Bucket(bucket)
+ f := bkt.Object(filename)
+ attrs, err := f.Attrs(client.ctx)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read %v attributes: %v", gcsFile, err)
+ }
+ if !attrs.Deleted.IsZero() {
+ return nil, fmt.Errorf("file %v is deleted", gcsFile)
+ }
+ handle := f.If(storage.Conditions{
+ GenerationMatch: attrs.Generation,
+ MetagenerationMatch: attrs.Metageneration,
+ })
+ file := &File{
+ Updated: attrs.Updated,
+ ctx: client.ctx,
+ handle: handle,
+ }
+ return file, nil
+}
+
+func (client *Client) UploadFile(localFile, gcsFile string) error {
+ bucket, filename, err := split(gcsFile)
+ if err != nil {
+ return err
+ }
+ local, err := os.Open(localFile)
+ if err != nil {
+ return err
+ }
+ defer local.Close()
+ bkt := client.client.Bucket(bucket)
+ f := bkt.Object(filename)
+ w := f.NewWriter(client.ctx)
+ defer w.Close()
+ if _, err := io.Copy(w, local); err != nil {
+ return err
+ }
+ return nil
+}
+
+func split(file string) (bucket, filename string, err error) {
+ if strings.HasPrefix(file, "gs://") {
+ file = file[5:]
+ }
+ pos := strings.IndexByte(file, '/')
+ if pos == -1 {
+ return "", "", fmt.Errorf("invalid GCS file name: %v", file)
+ }
+ return file[:pos], file[pos+1:], nil
+}