1
// Copyright 2014 Google Inc. All Rights Reserved.
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
7
// http://www.apache.org/licenses/LICENSE-2.0
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
15
// Package gcsdemo is an example App Engine or Mananged VM app using the Google Cloud Storage API.
26
"golang.org/x/net/context"
28
"golang.org/x/oauth2/google"
29
"google.golang.org/appengine"
30
"google.golang.org/appengine/file"
31
"google.golang.org/appengine/log"
32
"google.golang.org/appengine/urlfetch"
33
"google.golang.org/cloud"
34
"google.golang.org/cloud/storage"
37
// bucket is a local cache of the app's default bucket name.
38
var bucket string // or: var bucket = "<your-app-id>.appspot.com"
41
http.HandleFunc("/", handler)
44
// demo struct holds information needed to run the various demo functions.
49
// cleanUp is a list of filenames that need cleaning up at the end of the demo.
51
// failed indicates that one or more of the demo steps failed.
55
func (d *demo) errorf(format string, args ...interface{}) {
57
log.Errorf(d.c, format, args...)
60
// handler is the main demo entry point that calls the GCS operations.
61
func handler(w http.ResponseWriter, r *http.Request) {
62
if r.URL.Path != "/" {
66
c := appengine.NewContext(r)
69
if bucket, err = file.DefaultBucketName(c); err != nil {
70
log.Errorf(c, "failed to get default GCS bucket name: %v", err)
75
Transport: &oauth2.Transport{
76
Source: google.AppEngineTokenSource(c, storage.ScopeFullControl),
77
Base: &urlfetch.Transport{Context: c},
80
ctx := cloud.NewContext(appengine.AppID(c), hc)
81
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
82
fmt.Fprintf(w, "Demo GCS Application running from Version: %v\n", appengine.VersionID(c))
83
fmt.Fprintf(w, "Using bucket name: %v\n\n", bucket)
91
n := "demo-testfile-go"
100
d.putDefaultACLRule()
101
d.deleteDefaultACLRule()
104
d.deleteBucketACLRule()
111
io.WriteString(w, "\nDemo failed.\n")
113
io.WriteString(w, "\nDemo succeeded.\n")
117
// createFile creates a file in Google Cloud Storage.
118
func (d *demo) createFile(fileName string) {
119
fmt.Fprintf(d.w, "Creating file /%v/%v\n", bucket, fileName)
121
wc := storage.NewWriter(d.ctx, bucket, fileName)
122
wc.ContentType = "text/plain"
123
wc.Metadata = map[string]string{
124
"x-goog-meta-foo": "foo",
125
"x-goog-meta-bar": "bar",
127
d.cleanUp = append(d.cleanUp, fileName)
129
if _, err := wc.Write([]byte("abcde\n")); err != nil {
130
d.errorf("createFile: unable to write data to bucket %q, file %q: %v", bucket, fileName, err)
133
if _, err := wc.Write([]byte(strings.Repeat("f", 1024*4) + "\n")); err != nil {
134
d.errorf("createFile: unable to write data to bucket %q, file %q: %v", bucket, fileName, err)
137
if err := wc.Close(); err != nil {
138
d.errorf("createFile: unable to close bucket %q, file %q: %v", bucket, fileName, err)
143
// readFile reads the named file in Google Cloud Storage.
144
func (d *demo) readFile(fileName string) {
145
io.WriteString(d.w, "\nAbbreviated file content (first line and last 1K):\n")
147
rc, err := storage.NewReader(d.ctx, bucket, fileName)
149
d.errorf("readFile: unable to open file from bucket %q, file %q: %v", bucket, fileName, err)
153
slurp, err := ioutil.ReadAll(rc)
155
d.errorf("readFile: unable to read data from bucket %q, file %q: %v", bucket, fileName, err)
159
fmt.Fprintf(d.w, "%s\n", bytes.SplitN(slurp, []byte("\n"), 2)[0])
160
if len(slurp) > 1024 {
161
fmt.Fprintf(d.w, "...%s\n", slurp[len(slurp)-1024:])
163
fmt.Fprintf(d.w, "%s\n", slurp)
167
// copyFile copies a file in Google Cloud Storage.
168
func (d *demo) copyFile(fileName string) {
169
copyName := fileName + "-copy"
170
fmt.Fprintf(d.w, "Copying file /%v/%v to /%v/%v:\n", bucket, fileName, bucket, copyName)
172
attrs := storage.ObjectAttrs{
174
ContentType: "text/plain",
175
Metadata: map[string]string{
176
"x-goog-meta-foo-copy": "foo-copy",
177
"x-goog-meta-bar-copy": "bar-copy",
180
obj, err := storage.CopyObject(d.ctx, bucket, fileName, bucket, attrs)
182
d.errorf("copyFile: unable to copy /%v/%v to bucket %q, file %q: %v", bucket, fileName, bucket, copyName, err)
185
d.cleanUp = append(d.cleanUp, copyName)
190
func (d *demo) dumpStats(obj *storage.Object) {
191
fmt.Fprintf(d.w, "(filename: /%v/%v, ", obj.Bucket, obj.Name)
192
fmt.Fprintf(d.w, "ContentType: %q, ", obj.ContentType)
193
fmt.Fprintf(d.w, "ACL: %#v, ", obj.ACL)
194
fmt.Fprintf(d.w, "Owner: %v, ", obj.Owner)
195
fmt.Fprintf(d.w, "ContentEncoding: %q, ", obj.ContentEncoding)
196
fmt.Fprintf(d.w, "Size: %v, ", obj.Size)
197
fmt.Fprintf(d.w, "MD5: %q, ", obj.MD5)
198
fmt.Fprintf(d.w, "CRC32C: %q, ", obj.CRC32C)
199
fmt.Fprintf(d.w, "Metadata: %#v, ", obj.Metadata)
200
fmt.Fprintf(d.w, "MediaLink: %q, ", obj.MediaLink)
201
fmt.Fprintf(d.w, "StorageClass: %q, ", obj.StorageClass)
202
if !obj.Deleted.IsZero() {
203
fmt.Fprintf(d.w, "Deleted: %v, ", obj.Deleted)
205
fmt.Fprintf(d.w, "Updated: %v)\n", obj.Updated)
208
// statFile reads the stats of the named file in Google Cloud Storage.
209
func (d *demo) statFile(fileName string) {
210
io.WriteString(d.w, "\nFile stat:\n")
212
obj, err := storage.StatObject(d.ctx, bucket, fileName)
214
d.errorf("statFile: unable to stat file from bucket %q, file %q: %v", bucket, fileName, err)
221
// createListFiles creates files that will be used by listBucket.
222
func (d *demo) createListFiles() {
223
io.WriteString(d.w, "\nCreating more files for listbucket...\n")
224
for _, n := range []string{"foo1", "foo2", "bar", "bar/1", "bar/2", "boo/"} {
229
// listBucket lists the contents of a bucket in Google Cloud Storage.
230
func (d *demo) listBucket() {
231
io.WriteString(d.w, "\nListbucket result:\n")
233
query := &storage.Query{Prefix: "foo"}
235
objs, err := storage.ListObjects(d.ctx, bucket, query)
237
d.errorf("listBucket: unable to list bucket %q: %v", bucket, err)
242
for _, obj := range objs.Results {
248
func (d *demo) listDir(name, indent string) {
249
query := &storage.Query{Prefix: name, Delimiter: "/"}
251
objs, err := storage.ListObjects(d.ctx, bucket, query)
253
d.errorf("listBucketDirMode: unable to list bucket %q: %v", bucket, err)
258
for _, obj := range objs.Results {
259
fmt.Fprint(d.w, indent)
262
for _, dir := range objs.Prefixes {
263
fmt.Fprintf(d.w, "%v(directory: /%v/%v)\n", indent, bucket, dir)
264
d.listDir(dir, indent+" ")
269
// listBucketDirMode lists the contents of a bucket in dir mode in Google Cloud Storage.
270
func (d *demo) listBucketDirMode() {
271
io.WriteString(d.w, "\nListbucket directory mode result:\n")
275
// dumpDefaultACL prints out the default object ACL for this bucket.
276
func (d *demo) dumpDefaultACL() {
277
acl, err := storage.DefaultACL(d.ctx, bucket)
279
d.errorf("defaultACL: unable to list default object ACL for bucket %q: %v", bucket, err)
282
for _, v := range acl {
283
fmt.Fprintf(d.w, "Entity: %q, Role: %q\n", v.Entity, v.Role)
287
// defaultACL displays the default object ACL for this bucket.
288
func (d *demo) defaultACL() {
289
io.WriteString(d.w, "\nDefault object ACL:\n")
293
// putDefaultACLRule adds the "allUsers" default object ACL rule for this bucket.
294
func (d *demo) putDefaultACLRule() {
295
io.WriteString(d.w, "\nPut Default object ACL Rule:\n")
296
err := storage.PutDefaultACLRule(d.ctx, bucket, "allUsers", storage.RoleReader)
298
d.errorf("putDefaultACLRule: unable to save default object ACL rule for bucket %q: %v", bucket, err)
304
// deleteDefaultACLRule deleted the "allUsers" default object ACL rule for this bucket.
305
func (d *demo) deleteDefaultACLRule() {
306
io.WriteString(d.w, "\nDelete Default object ACL Rule:\n")
307
err := storage.DeleteDefaultACLRule(d.ctx, bucket, "allUsers")
309
d.errorf("deleteDefaultACLRule: unable to delete default object ACL rule for bucket %q: %v", bucket, err)
315
// dumpBucketACL prints out the bucket ACL.
316
func (d *demo) dumpBucketACL() {
317
acl, err := storage.BucketACL(d.ctx, bucket)
319
d.errorf("dumpBucketACL: unable to list bucket ACL for bucket %q: %v", bucket, err)
322
for _, v := range acl {
323
fmt.Fprintf(d.w, "Entity: %q, Role: %q\n", v.Entity, v.Role)
327
// bucketACL displays the bucket ACL for this bucket.
328
func (d *demo) bucketACL() {
329
io.WriteString(d.w, "\nBucket ACL:\n")
333
// putBucketACLRule adds the "allUsers" bucket ACL rule for this bucket.
334
func (d *demo) putBucketACLRule() {
335
io.WriteString(d.w, "\nPut Bucket ACL Rule:\n")
336
err := storage.PutBucketACLRule(d.ctx, bucket, "allUsers", storage.RoleReader)
338
d.errorf("putBucketACLRule: unable to save bucket ACL rule for bucket %q: %v", bucket, err)
344
// deleteBucketACLRule deleted the "allUsers" bucket ACL rule for this bucket.
345
func (d *demo) deleteBucketACLRule() {
346
io.WriteString(d.w, "\nDelete Bucket ACL Rule:\n")
347
err := storage.DeleteBucketACLRule(d.ctx, bucket, "allUsers")
349
d.errorf("deleteBucketACLRule: unable to delete bucket ACL rule for bucket %q: %v", bucket, err)
355
// dumpACL prints out the ACL of the named file.
356
func (d *demo) dumpACL(fileName string) {
357
acl, err := storage.ACL(d.ctx, bucket, fileName)
359
d.errorf("dumpACL: unable to list file ACL for bucket %q, file %q: %v", bucket, fileName, err)
362
for _, v := range acl {
363
fmt.Fprintf(d.w, "Entity: %q, Role: %q\n", v.Entity, v.Role)
367
// acl displays the ACL for the named file.
368
func (d *demo) acl(fileName string) {
369
fmt.Fprintf(d.w, "\nACL for file %v:\n", fileName)
373
// putACLRule adds the "allUsers" ACL rule for the named file.
374
func (d *demo) putACLRule(fileName string) {
375
fmt.Fprintf(d.w, "\nPut ACL rule for file %v:\n", fileName)
376
err := storage.PutACLRule(d.ctx, bucket, fileName, "allUsers", storage.RoleReader)
378
d.errorf("putACLRule: unable to save ACL rule for bucket %q, file %q: %v", bucket, fileName, err)
384
// deleteACLRule deleted the "allUsers" ACL rule for the named file.
385
func (d *demo) deleteACLRule(fileName string) {
386
fmt.Fprintf(d.w, "\nDelete ACL rule for file %v:\n", fileName)
387
err := storage.DeleteACLRule(d.ctx, bucket, fileName, "allUsers")
389
d.errorf("deleteACLRule: unable to delete ACL rule for bucket %q, file %q: %v", bucket, fileName, err)
395
// deleteFiles deletes all the temporary files from a bucket created by this demo.
396
func (d *demo) deleteFiles() {
397
io.WriteString(d.w, "\nDeleting files...\n")
398
for _, v := range d.cleanUp {
399
fmt.Fprintf(d.w, "Deleting file %v\n", v)
400
if err := storage.DeleteObject(d.ctx, bucket, v); err != nil {
401
d.errorf("deleteFiles: unable to delete bucket %q, file %q: %v", bucket, v, err)