github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/apiserver/migrationflag/facade.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the LGPLv3, see LICENCE file for details. 3 4 package migrationflag 5 6 import ( 7 "github.com/juju/errors" 8 "gopkg.in/juju/names.v2" 9 10 "github.com/juju/juju/apiserver/common" 11 "github.com/juju/juju/apiserver/facade" 12 "github.com/juju/juju/apiserver/params" 13 "github.com/juju/juju/core/migration" 14 "github.com/juju/juju/state" 15 "github.com/juju/juju/state/watcher" 16 ) 17 18 // Backend exposes information about any current model migrations. 19 type Backend interface { 20 ModelUUID() string 21 MigrationPhase() (migration.Phase, error) 22 WatchMigrationPhase() state.NotifyWatcher 23 } 24 25 // Facade lets clients watch and get models' migration phases. 26 type Facade struct { 27 backend Backend 28 resources facade.Resources 29 } 30 31 // New creates a Facade backed by backend and resources. If auth 32 // doesn't identity the client as a machine agent or a unit agent, 33 // it will return common.ErrPerm. 34 func New(backend Backend, resources facade.Resources, auth facade.Authorizer) (*Facade, error) { 35 if !auth.AuthMachineAgent() && !auth.AuthUnitAgent() { 36 return nil, common.ErrPerm 37 } 38 return &Facade{ 39 backend: backend, 40 resources: resources, 41 }, nil 42 } 43 44 // auth is very simplistic: it only accepts the model tag reported by 45 // the backend. 46 func (facade *Facade) auth(tagString string) error { 47 tag, err := names.ParseModelTag(tagString) 48 if err != nil { 49 return errors.Trace(err) 50 } 51 if tag.Id() != facade.backend.ModelUUID() { 52 return common.ErrPerm 53 } 54 return nil 55 } 56 57 // Phase returns the current migration phase or an error for every 58 // supplied entity. 59 func (facade *Facade) Phase(entities params.Entities) params.PhaseResults { 60 count := len(entities.Entities) 61 results := params.PhaseResults{ 62 Results: make([]params.PhaseResult, count), 63 } 64 for i, entity := range entities.Entities { 65 phase, err := facade.onePhase(entity.Tag) 66 results.Results[i].Phase = phase 67 results.Results[i].Error = common.ServerError(err) 68 } 69 return results 70 } 71 72 // onePhase does auth and lookup for a single entity. 73 func (facade *Facade) onePhase(tagString string) (string, error) { 74 if err := facade.auth(tagString); err != nil { 75 return "", errors.Trace(err) 76 } 77 phase, err := facade.backend.MigrationPhase() 78 if err != nil { 79 return "", errors.Trace(err) 80 } 81 return phase.String(), nil 82 } 83 84 // Watch returns an id for use with the NotifyWatcher facade, or an 85 // error, for every supplied entity. 86 func (facade *Facade) Watch(entities params.Entities) params.NotifyWatchResults { 87 count := len(entities.Entities) 88 results := params.NotifyWatchResults{ 89 Results: make([]params.NotifyWatchResult, count), 90 } 91 for i, entity := range entities.Entities { 92 id, err := facade.oneWatch(entity.Tag) 93 results.Results[i].NotifyWatcherId = id 94 results.Results[i].Error = common.ServerError(err) 95 } 96 return results 97 } 98 99 // oneWatch does auth, and watcher creation/registration, for a single 100 // entity. 101 func (facade *Facade) oneWatch(tagString string) (string, error) { 102 if err := facade.auth(tagString); err != nil { 103 return "", errors.Trace(err) 104 } 105 watch := facade.backend.WatchMigrationPhase() 106 if _, ok := <-watch.Changes(); ok { 107 return facade.resources.Register(watch), nil 108 } 109 return "", watcher.EnsureErr(watch) 110 }