~rogpeppe/juju-core/324-machineagent-api-client-2

« back to all changes in this revision

Viewing changes to cmd/juju/synctools.go

mergeĀ 323-machineagent-api-client

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
 
6
6
import (
7
7
        "bytes"
8
 
        "encoding/xml"
9
8
        "fmt"
10
9
        "io"
11
 
        "io/ioutil"
12
 
        "net/http"
13
 
        "sort"
14
 
        "strings"
15
 
        "time"
16
10
 
17
11
        "launchpad.net/gnuflag"
18
12
        "launchpad.net/juju-core/cmd"
19
13
        "launchpad.net/juju-core/environs"
 
14
        "launchpad.net/juju-core/environs/ec2"
20
15
        "launchpad.net/juju-core/environs/tools"
21
 
        "launchpad.net/juju-core/errors"
22
16
        "launchpad.net/juju-core/log"
23
17
        "launchpad.net/juju-core/state"
24
18
        "launchpad.net/juju-core/version"
25
19
)
26
20
 
 
21
// defaultToolsUrl leads to the juju distribution on S3.
 
22
var defaultToolsLocation string = "https://juju-dist.s3.amazonaws.com/"
 
23
 
27
24
// SyncToolsCommand copies all the tools from the us-east-1 bucket to the local
28
25
// bucket.
29
26
type SyncToolsCommand struct {
65
62
        return cmd.CheckEmpty(args)
66
63
}
67
64
 
68
 
var officialBucketAttrs = map[string]interface{}{
69
 
        "name":            "juju-public",
70
 
        "type":            "ec2",
71
 
        "control-bucket":  "juju-dist",
72
 
        "access-key":      "",
73
 
        "secret-key":      "",
74
 
        "authorized-keys": "not-really", // We shouldn't need ssh access
75
 
}
76
 
 
77
65
func copyOne(
78
66
        tool *state.Tools, source environs.StorageReader,
79
67
        target environs.Storage, ctx *cmd.Context,
118
106
}
119
107
 
120
108
func (c *SyncToolsCommand) Run(ctx *cmd.Context) error {
121
 
        sourceStorage := newHttpToolsReader()
 
109
        sourceStorage := ec2.NewHTTPStorageReader(defaultToolsLocation)
122
110
        targetEnv, err := environs.NewFromName(c.EnvName)
123
111
        if err != nil {
124
112
                log.Errorf("unable to read %q from environment", c.EnvName)
182
170
        fmt.Fprintf(ctx.Stderr, "copied %d tools\n", len(missing))
183
171
        return nil
184
172
}
185
 
 
186
 
// defaultToolsUrl leads to the juju distribution on S3.
187
 
var defaultToolsLocation string = "https://juju-dist.s3.amazonaws.com/"
188
 
 
189
 
// listBucketResult is the top level XML element of the storage index.
190
 
type listBucketResult struct {
191
 
        XMLName     xml.Name `xml: "ListBucketResult"`
192
 
        Name        string
193
 
        Prefix      string
194
 
        Marker      string
195
 
        MaxKeys     int
196
 
        IsTruncated bool
197
 
        Contents    []*contents
198
 
}
199
 
 
200
 
// content describes one entry of the storage index.
201
 
type contents struct {
202
 
        XMLName      xml.Name `xml: "Contents"`
203
 
        Key          string
204
 
        LastModified time.Time
205
 
        ETag         string
206
 
        Size         int
207
 
        StorageClass string
208
 
}
209
 
 
210
 
// httpToolsReader implements the environs.StorageReader interface by
211
 
// accessing the juju-core public store simply using http.
212
 
type httpToolsReader struct {
213
 
        location string
214
 
}
215
 
 
216
 
// newHttpToolsReader creates a storage reader for the http
217
 
// access to the juju-core public store.
218
 
func newHttpToolsReader() environs.StorageReader {
219
 
        return &httpToolsReader{defaultToolsLocation}
220
 
}
221
 
 
222
 
// Get opens the given storage file and returns a ReadCloser
223
 
// that can be used to read its contents.
224
 
func (h *httpToolsReader) Get(name string) (io.ReadCloser, error) {
225
 
        locationName, err := h.URL(name)
226
 
        if err != nil {
227
 
                return nil, err
228
 
        }
229
 
        resp, err := http.Get(locationName)
230
 
        if err != nil && resp.StatusCode == http.StatusNotFound {
231
 
                return nil, &errors.NotFoundError{err, ""}
232
 
        }
233
 
        return resp.Body, nil
234
 
}
235
 
 
236
 
// List lists all names in the storage with the given prefix.
237
 
func (h *httpToolsReader) List(prefix string) ([]string, error) {
238
 
        lbr, err := h.getListBucketResult()
239
 
        if err != nil {
240
 
                return nil, err
241
 
        }
242
 
        var names []string
243
 
        for _, c := range lbr.Contents {
244
 
                if strings.HasPrefix(c.Key, prefix) {
245
 
                        names = append(names, c.Key)
246
 
                }
247
 
        }
248
 
        sort.Strings(names)
249
 
        return names, nil
250
 
}
251
 
 
252
 
// URL returns a URL that can be used to access the given storage file.
253
 
func (h *httpToolsReader) URL(name string) (string, error) {
254
 
        if strings.HasSuffix(h.location, "/") {
255
 
                return h.location + name, nil
256
 
        }
257
 
        return h.location + "/" + name, nil
258
 
}
259
 
 
260
 
// getListBucketResult retrieves the index of the storage,
261
 
func (h *httpToolsReader) getListBucketResult() (*listBucketResult, error) {
262
 
        resp, err := http.Get(h.location)
263
 
        if err != nil {
264
 
                return nil, err
265
 
        }
266
 
        defer resp.Body.Close()
267
 
        buf, err := ioutil.ReadAll(resp.Body)
268
 
        if err != nil {
269
 
                return nil, err
270
 
        }
271
 
        var lbr listBucketResult
272
 
        err = xml.Unmarshal(buf, &lbr)
273
 
        if err != nil {
274
 
                return nil, err
275
 
        }
276
 
        return &lbr, nil
277
 
}