~rogpeppe/juju-core/438-local-instance-Addresses

« back to all changes in this revision

Viewing changes to provider/dummy/storage.go

  • Committer: Tarmac
  • Author(s): Roger Peppe, John Arbash Meinel
  • Date: 2013-10-02 12:38:13 UTC
  • mfrom: (1717.1.42 375-dummy-prepare-state-id)
  • Revision ID: tarmac-20131002123813-3tidl1lj00d3a29c
[r=rogpeppe] environs/dummy: add state-id

This makes the dummy provider more like the other
providers in that the Environ does not refer
directly to the bootstrapped state, but is looked
up when operations are performed on it.

This is also a test case for adding attributes at Prepare
time - many tests needed changing to correctly
deal with this.

https://codereview.appspot.com/14207046/

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
// IsSameStorage returns whether the storage instances are the same.
22
22
// Both storages must have been created through the dummy provider.
23
23
func IsSameStorage(s1, s2 storage.Storage) bool {
24
 
        return s1.(*dummystorage) == s2.(*dummystorage)
 
24
        localS1, localS2 := s1.(*dummyStorage), s2.(*dummyStorage)
 
25
        return localS1.env.name == localS2.env.name && localS1.public == localS2.public
25
26
}
26
27
 
27
28
func (e *environ) Storage() storage.Storage {
28
 
        return e.state().storage
 
29
        return &dummyStorage{
 
30
                env:    e,
 
31
                public: false,
 
32
        }
29
33
}
30
34
 
31
35
func (e *environ) PublicStorage() storage.StorageReader {
32
 
        return e.state().publicStorage
33
 
}
34
 
 
35
 
func newStorage(state *environState, path string) *dummystorage {
36
 
        return &dummystorage{
 
36
        return &dummyStorage{
 
37
                env:    e,
 
38
                public: true,
 
39
        }
 
40
}
 
41
 
 
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.
 
47
        state    *environState
 
48
        files    map[string][]byte
 
49
        poisoned map[string]error
 
50
}
 
51
 
 
52
func newStorageServer(state *environState, path string) *storageServer {
 
53
        return &storageServer{
37
54
                state:    state,
38
55
                files:    make(map[string][]byte),
39
56
                path:     path,
43
60
 
44
61
// Poison causes all fetches of the given path to
45
62
// return the given error.
46
 
func Poison(ss storage.Storage, path string, err error) {
47
 
        s := ss.(*dummystorage)
48
 
        s.state.mu.Lock()
49
 
        s.poisoned[path] = err
50
 
        s.state.mu.Unlock()
 
63
func Poison(ss storage.Storage, path string, poisonErr error) {
 
64
        s := ss.(*dummyStorage)
 
65
        srv, err := s.server()
 
66
        if err != nil {
 
67
                panic("cannot poison destroyed storage")
 
68
        }
 
69
        srv.state.mu.Lock()
 
70
        srv.poisoned[path] = poisonErr
 
71
        srv.state.mu.Unlock()
51
72
}
52
73
 
53
 
func (s *dummystorage) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 
74
func (s *storageServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
54
75
        if req.Method != "GET" {
55
76
                http.Error(w, "only GET is supported", http.StatusMethodNotAllowed)
56
77
                return
67
88
        w.Write(data)
68
89
}
69
90
 
70
 
func (s *dummystorage) Get(name string) (io.ReadCloser, error) {
71
 
        data, err := s.dataWithDelay(name)
72
 
        if err != nil {
73
 
                return nil, err
74
 
        }
75
 
        return ioutil.NopCloser(bytes.NewBuffer(data)), nil
76
 
}
77
 
 
78
91
// dataWithDelay returns the data for the given path,
79
92
// waiting for the configured amount of time before
80
93
// accessing it.
81
 
func (s *dummystorage) dataWithDelay(path string) (data []byte, err error) {
 
94
func (s *storageServer) dataWithDelay(path string) (data []byte, err error) {
82
95
        s.state.mu.Lock()
83
96
        delay := s.state.storageDelay
84
97
        s.state.mu.Unlock()
95
108
        return data, nil
96
109
}
97
110
 
98
 
func (s *dummystorage) URL(name string) (string, error) {
99
 
        return fmt.Sprintf("http://%v%s/%s", s.state.httpListener.Addr(), s.path, name), nil
100
 
}
101
 
 
102
 
// ConsistencyStrategy is specified in the StorageReader interface.
103
 
func (s *dummystorage) DefaultConsistencyStrategy() utils.AttemptStrategy {
104
 
        return utils.AttemptStrategy{}
105
 
}
106
 
 
107
 
// ShouldRetry is specified in the StorageReader interface.
108
 
func (s *dummystorage) ShouldRetry(err error) bool {
109
 
        return false
110
 
}
111
 
 
112
 
func (s *dummystorage) Put(name string, r io.Reader, length int64) error {
 
111
func (s *storageServer) Put(name string, r io.Reader, length int64) error {
113
112
        // Allow Put to be poisoned as well.
114
113
        if err := s.poisoned[name]; err != nil {
115
114
                return err
130
129
        return nil
131
130
}
132
131
 
133
 
func (s *dummystorage) Remove(name string) error {
 
132
func (s *storageServer) Get(name string) (io.ReadCloser, error) {
 
133
        data, err := s.dataWithDelay(name)
 
134
        if err != nil {
 
135
                return nil, err
 
136
        }
 
137
        return ioutil.NopCloser(bytes.NewBuffer(data)), nil
 
138
}
 
139
 
 
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
 
142
}
 
143
 
 
144
func (s *storageServer) Remove(name string) error {
134
145
        s.state.mu.Lock()
135
146
        delete(s.files, name)
136
147
        s.state.mu.Unlock()
137
148
        return nil
138
149
}
139
150
 
140
 
func (s *dummystorage) RemoveAll() error {
 
151
func (s *storageServer) DefaultConsistencyStrategy() utils.AttemptStrategy {
 
152
        return utils.AttemptStrategy{}
 
153
}
 
154
 
 
155
// ShouldRetry is specified in the StorageReader interface.
 
156
func (s *storageServer) ShouldRetry(err error) bool {
 
157
        return false
 
158
}
 
159
 
 
160
func (s *storageServer) RemoveAll() error {
141
161
        s.state.mu.Lock()
142
162
        s.files = make(map[string][]byte)
143
163
        s.state.mu.Unlock()
144
164
        return nil
145
165
}
146
166
 
147
 
func (s *dummystorage) List(prefix string) ([]string, error) {
 
167
func (s *storageServer) List(prefix string) ([]string, error) {
148
168
        s.state.mu.Lock()
149
169
        defer s.state.mu.Unlock()
150
170
        var names []string
156
176
        sort.Strings(names)
157
177
        return names, nil
158
178
}
 
179
 
 
180
// dummyStorage implements the client side of the Storage interface.
 
181
type dummyStorage struct {
 
182
        env    *environ
 
183
        public bool
 
184
}
 
185
 
 
186
// server returns the server side of the given storage.
 
187
func (s *dummyStorage) server() (*storageServer, error) {
 
188
        st, err := s.env.state()
 
189
        if err != nil {
 
190
                return nil, err
 
191
        }
 
192
        if s.public {
 
193
                return st.publicStorage, nil
 
194
        }
 
195
        return st.storage, nil
 
196
}
 
197
 
 
198
func (s *dummyStorage) Get(name string) (io.ReadCloser, error) {
 
199
        srv, err := s.server()
 
200
        if err != nil {
 
201
                return nil, err
 
202
        }
 
203
        return srv.Get(name)
 
204
}
 
205
 
 
206
func (s *dummyStorage) URL(name string) (string, error) {
 
207
        srv, err := s.server()
 
208
        if err != nil {
 
209
                return "", err
 
210
        }
 
211
        return srv.URL(name)
 
212
}
 
213
 
 
214
func (s *dummyStorage) DefaultConsistencyStrategy() utils.AttemptStrategy {
 
215
        return utils.AttemptStrategy{}
 
216
}
 
217
 
 
218
// ShouldRetry is specified in the StorageReader interface.
 
219
func (s *dummyStorage) ShouldRetry(err error) bool {
 
220
        return false
 
221
}
 
222
 
 
223
func (s *dummyStorage) Put(name string, r io.Reader, length int64) error {
 
224
        srv, err := s.server()
 
225
        if err != nil {
 
226
                return err
 
227
        }
 
228
        return srv.Put(name, r, length)
 
229
}
 
230
 
 
231
func (s *dummyStorage) Remove(name string) error {
 
232
        srv, err := s.server()
 
233
        if err != nil {
 
234
                return err
 
235
        }
 
236
        return srv.Remove(name)
 
237
}
 
238
 
 
239
func (s *dummyStorage) RemoveAll() error {
 
240
        srv, err := s.server()
 
241
        if err != nil {
 
242
                return err
 
243
        }
 
244
        return srv.RemoveAll()
 
245
}
 
246
 
 
247
func (s *dummyStorage) List(prefix string) ([]string, error) {
 
248
        srv, err := s.server()
 
249
        if err != nil {
 
250
                return nil, err
 
251
        }
 
252
        return srv.List(prefix)
 
253
}