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