github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/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 description string 76 basePath string 77 storage StorageReader 78 allowRetry bool 79 } 80 81 // TestingGetAllowRetry is used in tests which need to see if allowRetry has been 82 // set on a storageSimpleStreamsDataSource. 83 func TestingGetAllowRetry(s simplestreams.DataSource) (bool, ok bool) { 84 if storageDataSource, ok := s.(*storageSimpleStreamsDataSource); ok { 85 return storageDataSource.allowRetry, ok 86 } 87 return false, false 88 } 89 90 // NewStorageSimpleStreamsDataSource returns a new datasource reading from the specified storage. 91 func NewStorageSimpleStreamsDataSource(description string, storage StorageReader, basePath string) simplestreams.DataSource { 92 return &storageSimpleStreamsDataSource{description, basePath, storage, false} 93 } 94 95 func (s *storageSimpleStreamsDataSource) relpath(storagePath string) string { 96 relpath := storagePath 97 if s.basePath != "" { 98 relpath = path.Join(s.basePath, relpath) 99 } 100 return relpath 101 } 102 103 // Description is defined in simplestreams.DataSource. 104 func (s *storageSimpleStreamsDataSource) Description() string { 105 return s.description 106 } 107 108 // Fetch is defined in simplestreams.DataSource. 109 func (s *storageSimpleStreamsDataSource) Fetch(path string) (io.ReadCloser, string, error) { 110 relpath := s.relpath(path) 111 dataURL := relpath 112 fullURL, err := s.storage.URL(relpath) 113 if err == nil { 114 dataURL = fullURL 115 } 116 var attempt utils.AttemptStrategy 117 if s.allowRetry { 118 attempt = s.storage.DefaultConsistencyStrategy() 119 } 120 rc, err := GetWithRetry(s.storage, relpath, attempt) 121 if err != nil { 122 return nil, dataURL, err 123 } 124 return rc, dataURL, nil 125 } 126 127 // URL is defined in simplestreams.DataSource. 128 func (s *storageSimpleStreamsDataSource) URL(path string) (string, error) { 129 return s.storage.URL(s.relpath(path)) 130 } 131 132 // SetAllowRetry is defined in simplestreams.DataSource. 133 func (s *storageSimpleStreamsDataSource) SetAllowRetry(allow bool) { 134 s.allowRetry = allow 135 }