launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/environs/storage/storage.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package storage 5 6 import ( 7 "fmt" 8 "io" 9 "path" 10 11 "launchpad.net/juju-core/environs/simplestreams" 12 "launchpad.net/juju-core/utils" 13 ) 14 15 // RemoveAll is a default implementation for StorageWriter.RemoveAll. 16 // Providers may have more efficient implementations, or better error handling, 17 // or safeguards against races with other users of the same storage medium. 18 // But a simple way to implement RemoveAll would be to delegate to here. 19 func RemoveAll(stor Storage) error { 20 files, err := List(stor, "") 21 if err != nil { 22 return fmt.Errorf("unable to list files for deletion: %v", err) 23 } 24 25 // Some limited parallellism might be useful in this loop. 26 for _, file := range files { 27 err = stor.Remove(file) 28 if err != nil { 29 break 30 } 31 } 32 return err 33 } 34 35 // Get gets the named file from stor using the stor's default consistency strategy. 36 func Get(stor StorageReader, name string) (io.ReadCloser, error) { 37 return GetWithRetry(stor, name, stor.DefaultConsistencyStrategy()) 38 } 39 40 // GetWithRetry gets the named file from stor using the specified attempt strategy. 41 func GetWithRetry(stor StorageReader, name string, attempt utils.AttemptStrategy) (r io.ReadCloser, err error) { 42 for a := attempt.Start(); a.Next(); { 43 r, err = stor.Get(name) 44 if err == nil || !stor.ShouldRetry(err) { 45 break 46 } 47 } 48 return r, err 49 } 50 51 // List lists the files matching prefix from stor using the stor's default consistency strategy. 52 func List(stor StorageReader, prefix string) ([]string, error) { 53 return ListWithRetry(stor, prefix, stor.DefaultConsistencyStrategy()) 54 } 55 56 // ListWithRetry lists the files matching prefix from stor using the specified attempt strategy. 57 func ListWithRetry(stor StorageReader, prefix string, attempt utils.AttemptStrategy) (list []string, err error) { 58 for a := attempt.Start(); a.Next(); { 59 list, err = stor.List(prefix) 60 if err == nil || !stor.ShouldRetry(err) { 61 break 62 } 63 } 64 return list, err 65 } 66 67 // BaseToolsPath is the container where tools tarballs and metadata are found. 68 var BaseToolsPath = "tools" 69 70 // BaseImagesPath is the container where images metadata is found. 71 var BaseImagesPath = "images" 72 73 // A storageSimpleStreamsDataSource retrieves data from a StorageReader. 74 type storageSimpleStreamsDataSource struct { 75 basePath string 76 storage StorageReader 77 allowRetry bool 78 } 79 80 // TestingGetAllowRetry is used in tests which need to see if allowRetry has been 81 // set on a storageSimpleStreamsDataSource. 82 func TestingGetAllowRetry(s simplestreams.DataSource) (bool, ok bool) { 83 if storageDataSource, ok := s.(*storageSimpleStreamsDataSource); ok { 84 return storageDataSource.allowRetry, ok 85 } 86 return false, false 87 } 88 89 // NewStorageSimpleStreamsDataSource returns a new datasource reading from the specified storage. 90 func NewStorageSimpleStreamsDataSource(storage StorageReader, basePath string) simplestreams.DataSource { 91 return &storageSimpleStreamsDataSource{basePath, storage, false} 92 } 93 94 func (s *storageSimpleStreamsDataSource) relpath(storagePath string) string { 95 relpath := storagePath 96 if s.basePath != "" { 97 relpath = path.Join(s.basePath, relpath) 98 } 99 return relpath 100 } 101 102 // Fetch is defined in simplestreams.DataSource. 103 func (s *storageSimpleStreamsDataSource) Fetch(path string) (io.ReadCloser, string, error) { 104 relpath := s.relpath(path) 105 dataURL := relpath 106 fullURL, err := s.storage.URL(relpath) 107 if err == nil { 108 dataURL = fullURL 109 } 110 var attempt utils.AttemptStrategy 111 if s.allowRetry { 112 attempt = s.storage.DefaultConsistencyStrategy() 113 } 114 rc, err := GetWithRetry(s.storage, relpath, attempt) 115 if err != nil { 116 return nil, dataURL, err 117 } 118 return rc, dataURL, nil 119 } 120 121 // URL is defined in simplestreams.DataSource. 122 func (s *storageSimpleStreamsDataSource) URL(path string) (string, error) { 123 return s.storage.URL(s.relpath(path)) 124 } 125 126 // SetAllowRetry is defined in simplestreams.DataSource. 127 func (s *storageSimpleStreamsDataSource) SetAllowRetry(allow bool) { 128 s.allowRetry = allow 129 }