github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/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 priority int 81 requireSigned bool 82 } 83 84 // TestingGetAllowRetry is used in tests which need to see if allowRetry has been 85 // set on a storageSimpleStreamsDataSource. 86 func TestingGetAllowRetry(s simplestreams.DataSource) (bool, ok bool) { 87 if storageDataSource, ok := s.(*storageSimpleStreamsDataSource); ok { 88 return storageDataSource.allowRetry, ok 89 } 90 return false, false 91 } 92 93 // NewStorageSimpleStreamsDataSource returns a new datasource reading from the specified storage. 94 func NewStorageSimpleStreamsDataSource(description string, storage StorageReader, basePath string, priority int, requireSigned bool) simplestreams.DataSource { 95 return &storageSimpleStreamsDataSource{description, basePath, storage, false, priority, requireSigned} 96 } 97 98 func (s *storageSimpleStreamsDataSource) relpath(storagePath string) string { 99 relpath := storagePath 100 if s.basePath != "" { 101 relpath = path.Join(s.basePath, relpath) 102 } 103 return relpath 104 } 105 106 // Description is defined in simplestreams.DataSource. 107 func (s *storageSimpleStreamsDataSource) Description() string { 108 return s.description 109 } 110 111 // Fetch is defined in simplestreams.DataSource. 112 func (s *storageSimpleStreamsDataSource) Fetch(path string) (io.ReadCloser, string, error) { 113 relpath := s.relpath(path) 114 dataURL := relpath 115 fullURL, err := s.storage.URL(relpath) 116 if err == nil { 117 dataURL = fullURL 118 } 119 var attempt utils.AttemptStrategy 120 if s.allowRetry { 121 attempt = s.storage.DefaultConsistencyStrategy() 122 } 123 rc, err := GetWithRetry(s.storage, relpath, attempt) 124 if err != nil { 125 return nil, dataURL, err 126 } 127 return rc, dataURL, nil 128 } 129 130 // URL is defined in simplestreams.DataSource. 131 func (s *storageSimpleStreamsDataSource) URL(path string) (string, error) { 132 return s.storage.URL(s.relpath(path)) 133 } 134 135 // PublicSigningKey is defined in simplestreams.DataSource. 136 func (u *storageSimpleStreamsDataSource) PublicSigningKey() string { 137 return "" 138 } 139 140 // SetAllowRetry is defined in simplestreams.DataSource. 141 func (s *storageSimpleStreamsDataSource) SetAllowRetry(allow bool) { 142 s.allowRetry = allow 143 } 144 145 // Priority is defined in simplestreams.DataSource. 146 func (s *storageSimpleStreamsDataSource) Priority() int { 147 return s.priority 148 } 149 150 // RequireSigned is defined in simplestreams.DataSource. 151 func (s *storageSimpleStreamsDataSource) RequireSigned() bool { 152 return s.requireSigned 153 }