16
"launchpad.net/juju-core/environs"
16
"launchpad.net/juju-core/environs/storage"
17
17
"launchpad.net/juju-core/errors"
18
18
"launchpad.net/juju-core/utils"
21
func (e *environ) Storage() environs.Storage {
22
return e.state().storage
25
func (e *environ) PublicStorage() environs.StorageReader {
26
return e.state().publicStorage
29
func newStorage(state *environState, path string) *storage {
21
// IsSameStorage returns whether the storage instances are the same.
22
// Both storages must have been created through the dummy provider.
23
func IsSameStorage(s1, s2 storage.Storage) bool {
24
localS1, localS2 := s1.(*dummyStorage), s2.(*dummyStorage)
25
return localS1.env.name == localS2.env.name && localS1.public == localS2.public
28
func (e *environ) Storage() storage.Storage {
35
func (e *environ) PublicStorage() storage.StorageReader {
42
// storageServer holds the storage for an environState.
43
// There are two instances for each environState
44
// instance, one for public files and one for private.
45
type storageServer struct {
46
path string // path prefix in http space.
48
files map[string][]byte
49
poisoned map[string]error
52
func newStorageServer(state *environState, path string) *storageServer {
53
return &storageServer{
32
55
files: make(map[string][]byte),
38
61
// Poison causes all fetches of the given path to
39
62
// return the given error.
40
func Poison(ss environs.Storage, path string, err error) {
43
s.poisoned[path] = err
63
func Poison(ss storage.Storage, path string, poisonErr error) {
64
s := ss.(*dummyStorage)
65
srv, err := s.server()
67
panic("cannot poison destroyed storage")
70
srv.poisoned[path] = poisonErr
47
func (s *storage) ServeHTTP(w http.ResponseWriter, req *http.Request) {
74
func (s *storageServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
48
75
if req.Method != "GET" {
49
76
http.Error(w, "only GET is supported", http.StatusMethodNotAllowed)
64
func (s *storage) Get(name string) (io.ReadCloser, error) {
65
data, err := s.dataWithDelay(name)
69
return ioutil.NopCloser(bytes.NewBuffer(data)), nil
72
91
// dataWithDelay returns the data for the given path,
73
92
// waiting for the configured amount of time before
75
func (s *storage) dataWithDelay(path string) (data []byte, err error) {
94
func (s *storageServer) dataWithDelay(path string) (data []byte, err error) {
77
96
delay := s.state.storageDelay
78
97
s.state.mu.Unlock()
92
func (s *storage) URL(name string) (string, error) {
93
return fmt.Sprintf("http://%v%s/%s", s.state.httpListener.Addr(), s.path, name), nil
96
// ConsistencyStrategy is specified in the StorageReader interface.
97
func (s *storage) ConsistencyStrategy() utils.AttemptStrategy {
98
return utils.AttemptStrategy{}
101
func (s *storage) Put(name string, r io.Reader, length int64) error {
111
func (s *storageServer) Put(name string, r io.Reader, length int64) error {
102
112
// Allow Put to be poisoned as well.
103
113
if err := s.poisoned[name]; err != nil {
122
func (s *storage) Remove(name string) error {
132
func (s *storageServer) Get(name string) (io.ReadCloser, error) {
133
data, err := s.dataWithDelay(name)
137
return ioutil.NopCloser(bytes.NewBuffer(data)), nil
140
func (s *storageServer) URL(name string) (string, error) {
141
return fmt.Sprintf("http://%v%s/%s", s.state.httpListener.Addr(), s.path, name), nil
144
func (s *storageServer) Remove(name string) error {
123
145
s.state.mu.Lock()
124
146
delete(s.files, name)
125
147
s.state.mu.Unlock()
129
func (s *storage) RemoveAll() error {
151
func (s *storageServer) DefaultConsistencyStrategy() utils.AttemptStrategy {
152
return utils.AttemptStrategy{}
155
// ShouldRetry is specified in the StorageReader interface.
156
func (s *storageServer) ShouldRetry(err error) bool {
160
func (s *storageServer) RemoveAll() error {
130
161
s.state.mu.Lock()
131
162
s.files = make(map[string][]byte)
132
163
s.state.mu.Unlock()
136
func (s *storage) List(prefix string) ([]string, error) {
167
func (s *storageServer) List(prefix string) ([]string, error) {
137
168
s.state.mu.Lock()
138
169
defer s.state.mu.Unlock()
139
170
var names []string
145
176
sort.Strings(names)
146
177
return names, nil
180
// dummyStorage implements the client side of the Storage interface.
181
type dummyStorage struct {
186
// server returns the server side of the given storage.
187
func (s *dummyStorage) server() (*storageServer, error) {
188
st, err := s.env.state()
193
return st.publicStorage, nil
195
return st.storage, nil
198
func (s *dummyStorage) Get(name string) (io.ReadCloser, error) {
199
srv, err := s.server()
206
func (s *dummyStorage) URL(name string) (string, error) {
207
srv, err := s.server()
214
func (s *dummyStorage) DefaultConsistencyStrategy() utils.AttemptStrategy {
215
return utils.AttemptStrategy{}
218
// ShouldRetry is specified in the StorageReader interface.
219
func (s *dummyStorage) ShouldRetry(err error) bool {
223
func (s *dummyStorage) Put(name string, r io.Reader, length int64) error {
224
srv, err := s.server()
228
return srv.Put(name, r, length)
231
func (s *dummyStorage) Remove(name string) error {
232
srv, err := s.server()
236
return srv.Remove(name)
239
func (s *dummyStorage) RemoveAll() error {
240
srv, err := s.server()
244
return srv.RemoveAll()
247
func (s *dummyStorage) List(prefix string) ([]string, error) {
248
srv, err := s.server()
252
return srv.List(prefix)