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