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