github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/undertaker/undertaker.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package undertaker 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/state" 14 "github.com/juju/juju/state/watcher" 15 ) 16 17 func init() { 18 common.RegisterStandardFacade("Undertaker", 1, NewUndertakerAPI) 19 } 20 21 // UndertakerAPI implements the API used by the model undertaker worker. 22 type UndertakerAPI struct { 23 st State 24 resources facade.Resources 25 *common.StatusSetter 26 } 27 28 // NewUndertakerAPI creates a new instance of the undertaker API. 29 func NewUndertakerAPI(st *state.State, resources facade.Resources, authorizer facade.Authorizer) (*UndertakerAPI, error) { 30 return newUndertakerAPI(&stateShim{st}, resources, authorizer) 31 } 32 33 func newUndertakerAPI(st State, resources facade.Resources, authorizer facade.Authorizer) (*UndertakerAPI, error) { 34 if !authorizer.AuthMachineAgent() || !authorizer.AuthModelManager() { 35 return nil, common.ErrPerm 36 } 37 model, err := st.Model() 38 if err != nil { 39 return nil, errors.Trace(err) 40 } 41 getCanModifyModel := func() (common.AuthFunc, error) { 42 return func(tag names.Tag) bool { 43 if st.IsController() { 44 return true 45 } 46 // Only the agent's model can be modified. 47 modelTag, ok := tag.(names.ModelTag) 48 if !ok { 49 return false 50 } 51 return modelTag.Id() == model.UUID() 52 }, nil 53 } 54 return &UndertakerAPI{ 55 st: st, 56 resources: resources, 57 StatusSetter: common.NewStatusSetter(st, getCanModifyModel), 58 }, nil 59 } 60 61 // ModelInfo returns information on the model needed by the undertaker worker. 62 func (u *UndertakerAPI) ModelInfo() (params.UndertakerModelInfoResult, error) { 63 result := params.UndertakerModelInfoResult{} 64 env, err := u.st.Model() 65 66 if err != nil { 67 return result, errors.Trace(err) 68 } 69 70 result.Result = params.UndertakerModelInfo{ 71 UUID: env.UUID(), 72 GlobalName: env.Owner().String() + "/" + env.Name(), 73 Name: env.Name(), 74 IsSystem: u.st.IsController(), 75 Life: params.Life(env.Life().String()), 76 } 77 78 return result, nil 79 } 80 81 // ProcessDyingModel checks if a dying environment has any machines or services. 82 // If there are none, the environment's life is changed from dying to dead. 83 func (u *UndertakerAPI) ProcessDyingModel() error { 84 return u.st.ProcessDyingModel() 85 } 86 87 // RemoveModel removes any records of this model from Juju. 88 func (u *UndertakerAPI) RemoveModel() error { 89 return u.st.RemoveAllModelDocs() 90 } 91 92 func (u *UndertakerAPI) environResourceWatcher() params.NotifyWatchResult { 93 var nothing params.NotifyWatchResult 94 machines, err := u.st.AllMachines() 95 if err != nil { 96 nothing.Error = common.ServerError(err) 97 return nothing 98 } 99 services, err := u.st.AllApplications() 100 if err != nil { 101 nothing.Error = common.ServerError(err) 102 return nothing 103 } 104 var watchers []state.NotifyWatcher 105 for _, machine := range machines { 106 watchers = append(watchers, machine.Watch()) 107 } 108 for _, service := range services { 109 watchers = append(watchers, service.Watch()) 110 } 111 112 watch := common.NewMultiNotifyWatcher(watchers...) 113 114 if _, ok := <-watch.Changes(); ok { 115 return params.NotifyWatchResult{ 116 NotifyWatcherId: u.resources.Register(watch), 117 } 118 } 119 nothing.Error = common.ServerError(watcher.EnsureErr(watch)) 120 return nothing 121 } 122 123 // WatchModelResources creates watchers for changes to the lifecycle of an 124 // model's machines and services. 125 func (u *UndertakerAPI) WatchModelResources() params.NotifyWatchResults { 126 return params.NotifyWatchResults{ 127 Results: []params.NotifyWatchResult{ 128 u.environResourceWatcher(), 129 }, 130 } 131 } 132 133 // ModelConfig returns the model's configuration. 134 func (u *UndertakerAPI) ModelConfig() (params.ModelConfigResult, error) { 135 result := params.ModelConfigResult{} 136 137 config, err := u.st.ModelConfig() 138 if err != nil { 139 return result, err 140 } 141 allAttrs := config.AllAttrs() 142 result.Config = allAttrs 143 return result, nil 144 }