github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/instancepoller/instancepoller.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package instancepoller 5 6 import ( 7 "fmt" 8 9 "github.com/juju/utils/clock" 10 "gopkg.in/juju/names.v2" 11 12 "github.com/juju/juju/apiserver/common" 13 "github.com/juju/juju/apiserver/facade" 14 "github.com/juju/juju/apiserver/params" 15 "github.com/juju/juju/state" 16 "github.com/juju/juju/status" 17 ) 18 19 func init() { 20 common.RegisterStandardFacade("InstancePoller", 3, newInstancePollerAPI) 21 } 22 23 // InstancePollerAPI provides access to the InstancePoller API facade. 24 type InstancePollerAPI struct { 25 *common.LifeGetter 26 *common.ModelWatcher 27 *common.ModelMachinesWatcher 28 *common.InstanceIdGetter 29 *common.StatusGetter 30 31 st StateInterface 32 resources facade.Resources 33 authorizer facade.Authorizer 34 accessMachine common.GetAuthFunc 35 clock clock.Clock 36 } 37 38 // newInstancePollerAPI wraps NewInstancePollerAPI for RegisterStandardFacade. 39 func newInstancePollerAPI( 40 st *state.State, 41 resources facade.Resources, 42 authorizer facade.Authorizer, 43 ) (*InstancePollerAPI, error) { 44 return NewInstancePollerAPI(st, resources, authorizer, clock.WallClock) 45 } 46 47 // NewInstancePollerAPI creates a new server-side InstancePoller API 48 // facade. 49 func NewInstancePollerAPI( 50 st *state.State, 51 resources facade.Resources, 52 authorizer facade.Authorizer, 53 clock clock.Clock, 54 ) (*InstancePollerAPI, error) { 55 56 if !authorizer.AuthModelManager() { 57 // InstancePoller must run as environment manager. 58 return nil, common.ErrPerm 59 } 60 accessMachine := common.AuthFuncForTagKind(names.MachineTagKind) 61 sti := getState(st) 62 63 // Life() is supported for machines. 64 lifeGetter := common.NewLifeGetter( 65 sti, 66 accessMachine, 67 ) 68 // ModelConfig() and WatchForModelConfigChanges() are allowed 69 // with unrestriced access. 70 modelWatcher := common.NewModelWatcher( 71 sti, 72 resources, 73 authorizer, 74 ) 75 // WatchModelMachines() is allowed with unrestricted access. 76 machinesWatcher := common.NewModelMachinesWatcher( 77 sti, 78 resources, 79 authorizer, 80 ) 81 // InstanceId() is supported for machines. 82 instanceIdGetter := common.NewInstanceIdGetter( 83 sti, 84 accessMachine, 85 ) 86 // Status() is supported for machines. 87 statusGetter := common.NewStatusGetter( 88 sti, 89 accessMachine, 90 ) 91 92 return &InstancePollerAPI{ 93 LifeGetter: lifeGetter, 94 ModelWatcher: modelWatcher, 95 ModelMachinesWatcher: machinesWatcher, 96 InstanceIdGetter: instanceIdGetter, 97 StatusGetter: statusGetter, 98 st: sti, 99 resources: resources, 100 authorizer: authorizer, 101 accessMachine: accessMachine, 102 clock: clock, 103 }, nil 104 } 105 106 func (a *InstancePollerAPI) getOneMachine(tag string, canAccess common.AuthFunc) (StateMachine, error) { 107 machineTag, err := names.ParseMachineTag(tag) 108 if err != nil { 109 return nil, err 110 } 111 if !canAccess(machineTag) { 112 return nil, common.ErrPerm 113 } 114 entity, err := a.st.FindEntity(machineTag) 115 if err != nil { 116 return nil, err 117 } 118 machine, ok := entity.(StateMachine) 119 if !ok { 120 return nil, common.NotSupportedError( 121 machineTag, fmt.Sprintf("expected machine, got %T", entity), 122 ) 123 } 124 return machine, nil 125 } 126 127 // ProviderAddresses returns the list of all known provider addresses 128 // for each given entity. Only machine tags are accepted. 129 func (a *InstancePollerAPI) ProviderAddresses(args params.Entities) (params.MachineAddressesResults, error) { 130 result := params.MachineAddressesResults{ 131 Results: make([]params.MachineAddressesResult, len(args.Entities)), 132 } 133 canAccess, err := a.accessMachine() 134 if err != nil { 135 return result, err 136 } 137 for i, arg := range args.Entities { 138 machine, err := a.getOneMachine(arg.Tag, canAccess) 139 if err == nil { 140 addrs := machine.ProviderAddresses() 141 result.Results[i].Addresses = params.FromNetworkAddresses(addrs...) 142 } 143 result.Results[i].Error = common.ServerError(err) 144 } 145 return result, nil 146 } 147 148 // SetProviderAddresses updates the list of known provider addresses 149 // for each given entity. Only machine tags are accepted. 150 func (a *InstancePollerAPI) SetProviderAddresses(args params.SetMachinesAddresses) (params.ErrorResults, error) { 151 result := params.ErrorResults{ 152 Results: make([]params.ErrorResult, len(args.MachineAddresses)), 153 } 154 canAccess, err := a.accessMachine() 155 if err != nil { 156 return result, err 157 } 158 for i, arg := range args.MachineAddresses { 159 machine, err := a.getOneMachine(arg.Tag, canAccess) 160 if err == nil { 161 addrsToSet := params.NetworkAddresses(arg.Addresses...) 162 err = machine.SetProviderAddresses(addrsToSet...) 163 } 164 result.Results[i].Error = common.ServerError(err) 165 } 166 return result, nil 167 } 168 169 // InstanceStatus returns the instance status for each given entity. 170 // Only machine tags are accepted. 171 func (a *InstancePollerAPI) InstanceStatus(args params.Entities) (params.StatusResults, error) { 172 result := params.StatusResults{ 173 Results: make([]params.StatusResult, len(args.Entities)), 174 } 175 canAccess, err := a.accessMachine() 176 if err != nil { 177 return result, err 178 } 179 for i, arg := range args.Entities { 180 machine, err := a.getOneMachine(arg.Tag, canAccess) 181 if err == nil { 182 var statusInfo status.StatusInfo 183 statusInfo, err = machine.InstanceStatus() 184 result.Results[i].Status = statusInfo.Status.String() 185 result.Results[i].Info = statusInfo.Message 186 result.Results[i].Data = statusInfo.Data 187 result.Results[i].Since = statusInfo.Since 188 } 189 result.Results[i].Error = common.ServerError(err) 190 } 191 return result, nil 192 } 193 194 // SetInstanceStatus updates the instance status for each given 195 // entity. Only machine tags are accepted. 196 func (a *InstancePollerAPI) SetInstanceStatus(args params.SetStatus) (params.ErrorResults, error) { 197 result := params.ErrorResults{ 198 Results: make([]params.ErrorResult, len(args.Entities)), 199 } 200 canAccess, err := a.accessMachine() 201 if err != nil { 202 return result, err 203 } 204 for i, arg := range args.Entities { 205 machine, err := a.getOneMachine(arg.Tag, canAccess) 206 if err == nil { 207 now := a.clock.Now() 208 s := status.StatusInfo{ 209 Status: status.Status(arg.Status), 210 Message: arg.Info, 211 Data: arg.Data, 212 Since: &now, 213 } 214 err = machine.SetInstanceStatus(s) 215 } 216 result.Results[i].Error = common.ServerError(err) 217 } 218 return result, nil 219 } 220 221 // AreManuallyProvisioned returns whether each given entity is 222 // manually provisioned or not. Only machine tags are accepted. 223 func (a *InstancePollerAPI) AreManuallyProvisioned(args params.Entities) (params.BoolResults, error) { 224 result := params.BoolResults{ 225 Results: make([]params.BoolResult, len(args.Entities)), 226 } 227 canAccess, err := a.accessMachine() 228 if err != nil { 229 return result, err 230 } 231 for i, arg := range args.Entities { 232 machine, err := a.getOneMachine(arg.Tag, canAccess) 233 if err == nil { 234 result.Results[i].Result, err = machine.IsManual() 235 } 236 result.Results[i].Error = common.ServerError(err) 237 } 238 return result, nil 239 }