~jameinel/juju-core/scale-testing

« back to all changes in this revision

Viewing changes to charm/repo.go

[r=dimitern],[bug=1067979] state;apiserver: Fix a race - lp bug #1067979

This introduces some changes to how charm store
charms are added through the API (in state and
to provider storage). Now PrepareStoreCharmUpload
is called before trying to download the charm,
repackage it and upload it to storage, in order
to reserve a charm URL in state with pending
state. Added a test that demonstrates multiple
concurrent deployments of the same charm does
not cause the race issues, like mentioned in
the bug.

A few drive-by fixes brought up during review:
* Added ReadSHA256 and ReadFileSHA256 helpers in
  utils, and changed most places where hashes
  are calculated to use them.
* Charms are now uploaded to storage with a
  randomly generated archive names with the
  format "<charm-name>-<revision>-<uuid>".
  This allows multiple concurrent uploads
  to happen safely, and at the end AddCharm
  in the API checks to see if the charm info
  is already updated in state and if so, deletes
  the duplicated upload.
* Added GetEnvironStorage helper to environs/testing.
* Fixed potential compatibility issues with older
  versions and the recently added PendingUpload
  and Placeholder fields of the charm document.

Also tested multiple concurrent deployments with
the local provider manually and updated the bug
accordingly.

https://codereview.appspot.com/53210044/

R=fwereade

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
package charm
5
5
 
6
6
import (
7
 
        "crypto/sha256"
8
 
        "encoding/hex"
9
7
        "encoding/json"
10
8
        "fmt"
11
9
        "io"
299
297
// verify returns an error unless a file exists at path with a hex-encoded
300
298
// SHA256 matching digest.
301
299
func verify(path, digest string) error {
302
 
        f, err := os.Open(path)
 
300
        hash, _, err := utils.ReadFileSHA256(path)
303
301
        if err != nil {
304
302
                return err
305
303
        }
306
 
        defer f.Close()
307
 
        h := sha256.New()
308
 
        if _, err := io.Copy(h, f); err != nil {
309
 
                return err
310
 
        }
311
 
        if hex.EncodeToString(h.Sum(nil)) != digest {
 
304
        if hash != digest {
312
305
                return fmt.Errorf("bad SHA256 of %q", path)
313
306
        }
314
307
        return nil