Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(823)

Side by Side Diff: state/apiserver/charms.go

Issue 93410043: Extract errors package to github.com/juju/errors
Patch Set: Created 9 years, 10 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 Canonical Ltd. 1 // Copyright 2013 Canonical Ltd.
2 // Licensed under the AGPLv3, see LICENCE file for details. 2 // Licensed under the AGPLv3, see LICENCE file for details.
3 3
4 package apiserver 4 package apiserver
5 5
6 import ( 6 import (
7 "archive/zip" 7 "archive/zip"
8 "crypto/sha256" 8 "crypto/sha256"
9 "encoding/hex" 9 "encoding/hex"
10 "encoding/json" 10 "encoding/json"
11 "fmt" 11 "fmt"
12 "io" 12 "io"
13 "io/ioutil" 13 "io/ioutil"
14 "mime" 14 "mime"
15 "net/http" 15 "net/http"
16 "net/url" 16 "net/url"
17 "os" 17 "os"
18 "path" 18 "path"
19 "path/filepath" 19 "path/filepath"
20 "sort" 20 "sort"
21 "strconv" 21 "strconv"
22 "strings" 22 "strings"
23 23
24 » "github.com/errgo/errgo" 24 » "github.com/juju/errors"
25 25
26 "launchpad.net/juju-core/charm" 26 "launchpad.net/juju-core/charm"
27 "launchpad.net/juju-core/environs" 27 "launchpad.net/juju-core/environs"
28 "launchpad.net/juju-core/state/api/params" 28 "launchpad.net/juju-core/state/api/params"
29 ziputil "launchpad.net/juju-core/utils/zip" 29 ziputil "launchpad.net/juju-core/utils/zip"
30 ) 30 )
31 31
32 // charmsHandler handles charm upload through HTTPS in the API server. 32 // charmsHandler handles charm upload through HTTPS in the API server.
33 type charmsHandler struct { 33 type charmsHandler struct {
34 httpHandler 34 httpHandler
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 if err != nil { 229 if err != nil {
230 return err 230 return err
231 } 231 }
232 defer f.Close() 232 defer f.Close()
233 fi, err := f.Stat() 233 fi, err := f.Stat()
234 if err != nil { 234 if err != nil {
235 return err 235 return err
236 } 236 }
237 zipr, err := zip.NewReader(f, fi.Size()) 237 zipr, err := zip.NewReader(f, fi.Size())
238 if err != nil { 238 if err != nil {
239 » » return errgo.Annotate(err, "cannot open charm archive") 239 » » return errors.Annotate(err, "cannot open charm archive")
240 } 240 }
241 241
242 // Find out the root dir prefix from the archive. 242 // Find out the root dir prefix from the archive.
243 rootDir, err := h.findArchiveRootDir(zipr) 243 rootDir, err := h.findArchiveRootDir(zipr)
244 if err != nil { 244 if err != nil {
245 » » return errgo.Annotate(err, "cannot read charm archive") 245 » » return errors.Annotate(err, "cannot read charm archive")
246 } 246 }
247 if rootDir == "." { 247 if rootDir == "." {
248 // Normal charm, just use charm.ReadBundle(). 248 // Normal charm, just use charm.ReadBundle().
249 return nil 249 return nil
250 } 250 }
251 251
252 // There is one or more subdirs, so we need extract it to a temp 252 // There is one or more subdirs, so we need extract it to a temp
253 // dir and then read it as a charm dir. 253 // dir and then read it as a charm dir.
254 tempDir, err := ioutil.TempDir("", "charm-extract") 254 tempDir, err := ioutil.TempDir("", "charm-extract")
255 if err != nil { 255 if err != nil {
256 » » return errgo.Annotate(err, "cannot create temp directory") 256 » » return errors.Annotate(err, "cannot create temp directory")
257 } 257 }
258 defer os.RemoveAll(tempDir) 258 defer os.RemoveAll(tempDir)
259 if err := ziputil.Extract(zipr, tempDir, rootDir); err != nil { 259 if err := ziputil.Extract(zipr, tempDir, rootDir); err != nil {
260 » » return errgo.Annotate(err, "cannot extract charm archive") 260 » » return errors.Annotate(err, "cannot extract charm archive")
261 } 261 }
262 dir, err := charm.ReadDir(tempDir) 262 dir, err := charm.ReadDir(tempDir)
263 if err != nil { 263 if err != nil {
264 » » return errgo.Annotate(err, "cannot read extracted archive") 264 » » return errors.Annotate(err, "cannot read extracted archive")
265 } 265 }
266 266
267 // Now repackage the dir as a bundle at the original path. 267 // Now repackage the dir as a bundle at the original path.
268 if err := f.Truncate(0); err != nil { 268 if err := f.Truncate(0); err != nil {
269 return err 269 return err
270 } 270 }
271 if err := dir.BundleTo(f); err != nil { 271 if err := dir.BundleTo(f); err != nil {
272 return err 272 return err
273 } 273 }
274 return nil 274 return nil
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
306 func (d byDepth) Less(i, j int) bool { return depth(d[i]) < depth(d[j]) } 306 func (d byDepth) Less(i, j int) bool { return depth(d[i]) < depth(d[j]) }
307 307
308 // repackageAndUploadCharm expands the given charm archive to a 308 // repackageAndUploadCharm expands the given charm archive to a
309 // temporary directoy, repackages it with the given curl's revision, 309 // temporary directoy, repackages it with the given curl's revision,
310 // then uploads it to providr storage, and finally updates the state. 310 // then uploads it to providr storage, and finally updates the state.
311 func (h *charmsHandler) repackageAndUploadCharm(archive *charm.Bundle, curl *cha rm.URL) error { 311 func (h *charmsHandler) repackageAndUploadCharm(archive *charm.Bundle, curl *cha rm.URL) error {
312 // Create a temp dir to contain the extracted charm 312 // Create a temp dir to contain the extracted charm
313 // dir and the repackaged archive. 313 // dir and the repackaged archive.
314 tempDir, err := ioutil.TempDir("", "charm-download") 314 tempDir, err := ioutil.TempDir("", "charm-download")
315 if err != nil { 315 if err != nil {
316 » » return errgo.Annotate(err, "cannot create temp directory") 316 » » return errors.Annotate(err, "cannot create temp directory")
317 } 317 }
318 defer os.RemoveAll(tempDir) 318 defer os.RemoveAll(tempDir)
319 extractPath := filepath.Join(tempDir, "extracted") 319 extractPath := filepath.Join(tempDir, "extracted")
320 repackagedPath := filepath.Join(tempDir, "repackaged.zip") 320 repackagedPath := filepath.Join(tempDir, "repackaged.zip")
321 repackagedArchive, err := os.Create(repackagedPath) 321 repackagedArchive, err := os.Create(repackagedPath)
322 if err != nil { 322 if err != nil {
323 » » return errgo.Annotate(err, "cannot repackage uploaded charm") 323 » » return errors.Annotate(err, "cannot repackage uploaded charm")
324 } 324 }
325 defer repackagedArchive.Close() 325 defer repackagedArchive.Close()
326 326
327 // Expand and repack it with the revision specified by curl. 327 // Expand and repack it with the revision specified by curl.
328 archive.SetRevision(curl.Revision) 328 archive.SetRevision(curl.Revision)
329 if err := archive.ExpandTo(extractPath); err != nil { 329 if err := archive.ExpandTo(extractPath); err != nil {
330 » » return errgo.Annotate(err, "cannot extract uploaded charm") 330 » » return errors.Annotate(err, "cannot extract uploaded charm")
331 } 331 }
332 charmDir, err := charm.ReadDir(extractPath) 332 charmDir, err := charm.ReadDir(extractPath)
333 if err != nil { 333 if err != nil {
334 » » return errgo.Annotate(err, "cannot read extracted charm") 334 » » return errors.Annotate(err, "cannot read extracted charm")
335 } 335 }
336 336
337 // Bundle the charm and calculate its sha256 hash at the 337 // Bundle the charm and calculate its sha256 hash at the
338 // same time. 338 // same time.
339 hash := sha256.New() 339 hash := sha256.New()
340 err = charmDir.BundleTo(io.MultiWriter(hash, repackagedArchive)) 340 err = charmDir.BundleTo(io.MultiWriter(hash, repackagedArchive))
341 if err != nil { 341 if err != nil {
342 » » return errgo.Annotate(err, "cannot repackage uploaded charm") 342 » » return errors.Annotate(err, "cannot repackage uploaded charm")
343 } 343 }
344 bundleSHA256 := hex.EncodeToString(hash.Sum(nil)) 344 bundleSHA256 := hex.EncodeToString(hash.Sum(nil))
345 size, err := repackagedArchive.Seek(0, 2) 345 size, err := repackagedArchive.Seek(0, 2)
346 if err != nil { 346 if err != nil {
347 » » return errgo.Annotate(err, "cannot get charm file size") 347 » » return errors.Annotate(err, "cannot get charm file size")
348 } 348 }
349 349
350 // Now upload to provider storage. 350 // Now upload to provider storage.
351 if _, err := repackagedArchive.Seek(0, 0); err != nil { 351 if _, err := repackagedArchive.Seek(0, 0); err != nil {
352 » » return errgo.Annotate(err, "cannot rewind the charm file reader" ) 352 » » return errors.Annotate(err, "cannot rewind the charm file reader ")
353 } 353 }
354 storage, err := environs.GetStorage(h.state) 354 storage, err := environs.GetStorage(h.state)
355 if err != nil { 355 if err != nil {
356 » » return errgo.Annotate(err, "cannot access provider storage") 356 » » return errors.Annotate(err, "cannot access provider storage")
357 } 357 }
358 name := charm.Quote(curl.String()) 358 name := charm.Quote(curl.String())
359 if err := storage.Put(name, repackagedArchive, size); err != nil { 359 if err := storage.Put(name, repackagedArchive, size); err != nil {
360 » » return errgo.Annotate(err, "cannot upload charm to provider stor age") 360 » » return errors.Annotate(err, "cannot upload charm to provider sto rage")
361 } 361 }
362 storageURL, err := storage.URL(name) 362 storageURL, err := storage.URL(name)
363 if err != nil { 363 if err != nil {
364 » » return errgo.Annotate(err, "cannot get storage URL for charm") 364 » » return errors.Annotate(err, "cannot get storage URL for charm")
365 } 365 }
366 bundleURL, err := url.Parse(storageURL) 366 bundleURL, err := url.Parse(storageURL)
367 if err != nil { 367 if err != nil {
368 » » return errgo.Annotate(err, "cannot parse storage URL") 368 » » return errors.Annotate(err, "cannot parse storage URL")
369 } 369 }
370 370
371 // And finally, update state. 371 // And finally, update state.
372 _, err = h.state.UpdateUploadedCharm(archive, curl, bundleURL, bundleSHA 256) 372 _, err = h.state.UpdateUploadedCharm(archive, curl, bundleURL, bundleSHA 256)
373 if err != nil { 373 if err != nil {
374 » » return errgo.Annotate(err, "cannot update uploaded charm in stat e") 374 » » return errors.Annotate(err, "cannot update uploaded charm in sta te")
375 } 375 }
376 return nil 376 return nil
377 } 377 }
378 378
379 // processGet handles a charm file GET request after authentication. 379 // processGet handles a charm file GET request after authentication.
380 // It returns the bundle path, the requested file path (if any) and an error. 380 // It returns the bundle path, the requested file path (if any) and an error.
381 func (h *charmsHandler) processGet(r *http.Request) (string, string, error) { 381 func (h *charmsHandler) processGet(r *http.Request) (string, string, error) {
382 query := r.URL.Query() 382 query := r.URL.Query()
383 383
384 // Retrieve and validate query parameters. 384 // Retrieve and validate query parameters.
(...skipping 24 matching lines...) Expand all
409 } 409 }
410 return charmArchivePath, filePath, nil 410 return charmArchivePath, filePath, nil
411 } 411 }
412 412
413 // downloadCharm downloads the given charm name from the provider storage and 413 // downloadCharm downloads the given charm name from the provider storage and
414 // saves the corresponding zip archive to the given charmArchivePath. 414 // saves the corresponding zip archive to the given charmArchivePath.
415 func (h *charmsHandler) downloadCharm(name, charmArchivePath string) error { 415 func (h *charmsHandler) downloadCharm(name, charmArchivePath string) error {
416 // Get the provider storage. 416 // Get the provider storage.
417 storage, err := environs.GetStorage(h.state) 417 storage, err := environs.GetStorage(h.state)
418 if err != nil { 418 if err != nil {
419 » » return errgo.Annotate(err, "cannot access provider storage") 419 » » return errors.Annotate(err, "cannot access provider storage")
420 } 420 }
421 421
422 // Use the storage to retrieve and save the charm archive. 422 // Use the storage to retrieve and save the charm archive.
423 reader, err := storage.Get(name) 423 reader, err := storage.Get(name)
424 if err != nil { 424 if err != nil {
425 » » return errgo.Annotate(err, "charm not found in the provider stor age") 425 » » return errors.Annotate(err, "charm not found in the provider sto rage")
426 } 426 }
427 defer reader.Close() 427 defer reader.Close()
428 data, err := ioutil.ReadAll(reader) 428 data, err := ioutil.ReadAll(reader)
429 if err != nil { 429 if err != nil {
430 » » return errgo.Annotate(err, "cannot read charm data") 430 » » return errors.Annotate(err, "cannot read charm data")
431 } 431 }
432 // In order to avoid races, the archive is saved in a temporary file whi ch 432 // In order to avoid races, the archive is saved in a temporary file whi ch
433 // is then atomically renamed. The temporary file is created in the 433 // is then atomically renamed. The temporary file is created in the
434 // charm cache directory so that we can safely assume the rename source and 434 // charm cache directory so that we can safely assume the rename source and
435 // target live in the same file system. 435 // target live in the same file system.
436 cacheDir := filepath.Dir(charmArchivePath) 436 cacheDir := filepath.Dir(charmArchivePath)
437 if err = os.MkdirAll(cacheDir, 0755); err != nil { 437 if err = os.MkdirAll(cacheDir, 0755); err != nil {
438 » » return errgo.Annotate(err, "cannot create the charms cache") 438 » » return errors.Annotate(err, "cannot create the charms cache")
439 } 439 }
440 tempCharmArchive, err := ioutil.TempFile(cacheDir, "charm") 440 tempCharmArchive, err := ioutil.TempFile(cacheDir, "charm")
441 if err != nil { 441 if err != nil {
442 » » return errgo.Annotate(err, "cannot create charm archive temp fil e") 442 » » return errors.Annotate(err, "cannot create charm archive temp fi le")
443 } 443 }
444 defer tempCharmArchive.Close() 444 defer tempCharmArchive.Close()
445 if err = ioutil.WriteFile(tempCharmArchive.Name(), data, 0644); err != n il { 445 if err = ioutil.WriteFile(tempCharmArchive.Name(), data, 0644); err != n il {
446 » » return errgo.Annotate(err, "error processing charm archive downl oad") 446 » » return errors.Annotate(err, "error processing charm archive down load")
447 } 447 }
448 if err = os.Rename(tempCharmArchive.Name(), charmArchivePath); err != ni l { 448 if err = os.Rename(tempCharmArchive.Name(), charmArchivePath); err != ni l {
449 defer os.Remove(tempCharmArchive.Name()) 449 defer os.Remove(tempCharmArchive.Name())
450 » » return errgo.Annotate(err, "error renaming the charm archive") 450 » » return errors.Annotate(err, "error renaming the charm archive")
451 } 451 }
452 return nil 452 return nil
453 } 453 }
OLDNEW

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b