github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/apiserver/watcher.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package apiserver 5 6 import ( 7 "reflect" 8 9 "github.com/juju/errors" 10 11 "github.com/juju/juju/apiserver/common" 12 "github.com/juju/juju/apiserver/common/storagecommon" 13 "github.com/juju/juju/apiserver/params" 14 "github.com/juju/juju/core/migration" 15 "github.com/juju/juju/network" 16 "github.com/juju/juju/state" 17 ) 18 19 func init() { 20 common.RegisterFacade( 21 "AllWatcher", 1, NewAllWatcher, 22 reflect.TypeOf((*SrvAllWatcher)(nil)), 23 ) 24 // Note: AllModelWatcher uses the same infrastructure as AllWatcher 25 // but they are get under separate names as it possible the may 26 // diverge in the future (especially in terms of authorisation 27 // checks). 28 common.RegisterFacade( 29 "AllModelWatcher", 2, NewAllWatcher, 30 reflect.TypeOf((*SrvAllWatcher)(nil)), 31 ) 32 common.RegisterFacade( 33 "NotifyWatcher", 1, newNotifyWatcher, 34 reflect.TypeOf((*srvNotifyWatcher)(nil)), 35 ) 36 common.RegisterFacade( 37 "StringsWatcher", 1, newStringsWatcher, 38 reflect.TypeOf((*srvStringsWatcher)(nil)), 39 ) 40 common.RegisterFacade( 41 "RelationUnitsWatcher", 1, newRelationUnitsWatcher, 42 reflect.TypeOf((*srvRelationUnitsWatcher)(nil)), 43 ) 44 common.RegisterFacade( 45 "VolumeAttachmentsWatcher", 2, newVolumeAttachmentsWatcher, 46 reflect.TypeOf((*srvMachineStorageIdsWatcher)(nil)), 47 ) 48 common.RegisterFacade( 49 "FilesystemAttachmentsWatcher", 2, newFilesystemAttachmentsWatcher, 50 reflect.TypeOf((*srvMachineStorageIdsWatcher)(nil)), 51 ) 52 common.RegisterFacade( 53 "EntityWatcher", 2, newEntitiesWatcher, 54 reflect.TypeOf((*srvEntitiesWatcher)(nil)), 55 ) 56 common.RegisterFacade( 57 "MigrationStatusWatcher", 1, newMigrationStatusWatcher, 58 reflect.TypeOf((*srvMigrationStatusWatcher)(nil)), 59 ) 60 } 61 62 // NewAllWatcher returns a new API server endpoint for interacting 63 // with a watcher created by the WatchAll and WatchAllModels API calls. 64 func NewAllWatcher(st *state.State, resources *common.Resources, auth common.Authorizer, id string) (interface{}, error) { 65 if !auth.AuthClient() { 66 return nil, common.ErrPerm 67 } 68 69 watcher, ok := resources.Get(id).(*state.Multiwatcher) 70 if !ok { 71 return nil, common.ErrUnknownWatcher 72 } 73 return &SrvAllWatcher{ 74 watcher: watcher, 75 id: id, 76 resources: resources, 77 }, nil 78 } 79 80 // SrvAllWatcher defines the API methods on a state.Multiwatcher. 81 // which watches any changes to the state. Each client has its own 82 // current set of watchers, stored in resources. It is used by both 83 // the AllWatcher and AllModelWatcher facades. 84 type SrvAllWatcher struct { 85 watcher *state.Multiwatcher 86 id string 87 resources *common.Resources 88 } 89 90 func (aw *SrvAllWatcher) Next() (params.AllWatcherNextResults, error) { 91 deltas, err := aw.watcher.Next() 92 return params.AllWatcherNextResults{ 93 Deltas: deltas, 94 }, err 95 } 96 97 func (w *SrvAllWatcher) Stop() error { 98 return w.resources.Stop(w.id) 99 } 100 101 // srvNotifyWatcher defines the API access to methods on a state.NotifyWatcher. 102 // Each client has its own current set of watchers, stored in resources. 103 type srvNotifyWatcher struct { 104 watcher state.NotifyWatcher 105 id string 106 resources *common.Resources 107 } 108 109 func isAgent(auth common.Authorizer) bool { 110 return auth.AuthMachineAgent() || auth.AuthUnitAgent() 111 } 112 113 func newNotifyWatcher(st *state.State, resources *common.Resources, auth common.Authorizer, id string) (interface{}, error) { 114 if !isAgent(auth) { 115 return nil, common.ErrPerm 116 } 117 watcher, ok := resources.Get(id).(state.NotifyWatcher) 118 if !ok { 119 return nil, common.ErrUnknownWatcher 120 } 121 return &srvNotifyWatcher{ 122 watcher: watcher, 123 id: id, 124 resources: resources, 125 }, nil 126 } 127 128 // Next returns when a change has occurred to the 129 // entity being watched since the most recent call to Next 130 // or the Watch call that created the NotifyWatcher. 131 func (w *srvNotifyWatcher) Next() error { 132 if _, ok := <-w.watcher.Changes(); ok { 133 return nil 134 } 135 err := w.watcher.Err() 136 if err == nil { 137 err = common.ErrStoppedWatcher 138 } 139 return err 140 } 141 142 // Stop stops the watcher. 143 func (w *srvNotifyWatcher) Stop() error { 144 return w.resources.Stop(w.id) 145 } 146 147 // srvStringsWatcher defines the API for methods on a state.StringsWatcher. 148 // Each client has its own current set of watchers, stored in resources. 149 // srvStringsWatcher notifies about changes for all entities of a given kind, 150 // sending the changes as a list of strings. 151 type srvStringsWatcher struct { 152 watcher state.StringsWatcher 153 id string 154 resources *common.Resources 155 } 156 157 func newStringsWatcher(st *state.State, resources *common.Resources, auth common.Authorizer, id string) (interface{}, error) { 158 if !isAgent(auth) { 159 return nil, common.ErrPerm 160 } 161 watcher, ok := resources.Get(id).(state.StringsWatcher) 162 if !ok { 163 return nil, common.ErrUnknownWatcher 164 } 165 return &srvStringsWatcher{ 166 watcher: watcher, 167 id: id, 168 resources: resources, 169 }, nil 170 } 171 172 // Next returns when a change has occured to an entity of the 173 // collection being watched since the most recent call to Next 174 // or the Watch call that created the srvStringsWatcher. 175 func (w *srvStringsWatcher) Next() (params.StringsWatchResult, error) { 176 if changes, ok := <-w.watcher.Changes(); ok { 177 return params.StringsWatchResult{ 178 Changes: changes, 179 }, nil 180 } 181 err := w.watcher.Err() 182 if err == nil { 183 err = common.ErrStoppedWatcher 184 } 185 return params.StringsWatchResult{}, err 186 } 187 188 // Stop stops the watcher. 189 func (w *srvStringsWatcher) Stop() error { 190 return w.resources.Stop(w.id) 191 } 192 193 // srvRelationUnitsWatcher defines the API wrapping a state.RelationUnitsWatcher. 194 // It notifies about units entering and leaving the scope of a RelationUnit, 195 // and changes to the settings of those units known to have entered. 196 type srvRelationUnitsWatcher struct { 197 watcher state.RelationUnitsWatcher 198 id string 199 resources *common.Resources 200 } 201 202 func newRelationUnitsWatcher(st *state.State, resources *common.Resources, auth common.Authorizer, id string) (interface{}, error) { 203 if !isAgent(auth) { 204 return nil, common.ErrPerm 205 } 206 watcher, ok := resources.Get(id).(state.RelationUnitsWatcher) 207 if !ok { 208 return nil, common.ErrUnknownWatcher 209 } 210 return &srvRelationUnitsWatcher{ 211 watcher: watcher, 212 id: id, 213 resources: resources, 214 }, nil 215 } 216 217 // Next returns when a change has occured to an entity of the 218 // collection being watched since the most recent call to Next 219 // or the Watch call that created the srvRelationUnitsWatcher. 220 func (w *srvRelationUnitsWatcher) Next() (params.RelationUnitsWatchResult, error) { 221 if changes, ok := <-w.watcher.Changes(); ok { 222 return params.RelationUnitsWatchResult{ 223 Changes: changes, 224 }, nil 225 } 226 err := w.watcher.Err() 227 if err == nil { 228 err = common.ErrStoppedWatcher 229 } 230 return params.RelationUnitsWatchResult{}, err 231 } 232 233 // Stop stops the watcher. 234 func (w *srvRelationUnitsWatcher) Stop() error { 235 return w.resources.Stop(w.id) 236 } 237 238 // srvMachineStorageIdsWatcher defines the API wrapping a state.StringsWatcher 239 // watching machine/storage attachments. This watcher notifies about storage 240 // entities (volumes/filesystems) being attached to and detached from machines. 241 // 242 // TODO(axw) state needs a new watcher, this is a bt of a hack. State watchers 243 // could do with some deduplication of logic, and I don't want to add to that 244 // spaghetti right now. 245 type srvMachineStorageIdsWatcher struct { 246 watcher state.StringsWatcher 247 id string 248 resources *common.Resources 249 parser func([]string) ([]params.MachineStorageId, error) 250 } 251 252 func newVolumeAttachmentsWatcher( 253 st *state.State, 254 resources *common.Resources, 255 auth common.Authorizer, 256 id string, 257 ) (interface{}, error) { 258 return newMachineStorageIdsWatcher( 259 st, resources, auth, id, storagecommon.ParseVolumeAttachmentIds, 260 ) 261 } 262 263 func newFilesystemAttachmentsWatcher( 264 st *state.State, 265 resources *common.Resources, 266 auth common.Authorizer, 267 id string, 268 ) (interface{}, error) { 269 return newMachineStorageIdsWatcher( 270 st, resources, auth, id, storagecommon.ParseFilesystemAttachmentIds, 271 ) 272 } 273 274 func newMachineStorageIdsWatcher( 275 st *state.State, 276 resources *common.Resources, 277 auth common.Authorizer, 278 id string, 279 parser func([]string) ([]params.MachineStorageId, error), 280 ) (interface{}, error) { 281 if !isAgent(auth) { 282 return nil, common.ErrPerm 283 } 284 watcher, ok := resources.Get(id).(state.StringsWatcher) 285 if !ok { 286 return nil, common.ErrUnknownWatcher 287 } 288 return &srvMachineStorageIdsWatcher{watcher, id, resources, parser}, nil 289 } 290 291 // Next returns when a change has occured to an entity of the 292 // collection being watched since the most recent call to Next 293 // or the Watch call that created the srvMachineStorageIdsWatcher. 294 func (w *srvMachineStorageIdsWatcher) Next() (params.MachineStorageIdsWatchResult, error) { 295 if stringChanges, ok := <-w.watcher.Changes(); ok { 296 changes, err := w.parser(stringChanges) 297 if err != nil { 298 return params.MachineStorageIdsWatchResult{}, err 299 } 300 return params.MachineStorageIdsWatchResult{ 301 Changes: changes, 302 }, nil 303 } 304 err := w.watcher.Err() 305 if err == nil { 306 err = common.ErrStoppedWatcher 307 } 308 return params.MachineStorageIdsWatchResult{}, err 309 } 310 311 // Stop stops the watcher. 312 func (w *srvMachineStorageIdsWatcher) Stop() error { 313 return w.resources.Stop(w.id) 314 } 315 316 // EntitiesWatcher defines an interface based on the StringsWatcher 317 // but also providing a method for the mapping of the received 318 // strings to the tags of the according entities. 319 type EntitiesWatcher interface { 320 state.StringsWatcher 321 322 // MapChanges maps the received strings to their according tag strings. 323 // The EntityFinder interface representing state or a mock has to be 324 // upcasted into the needed sub-interface of state for the real mapping. 325 MapChanges(in []string) ([]string, error) 326 } 327 328 // srvEntitiesWatcher defines the API for methods on a state.StringsWatcher. 329 // Each client has its own current set of watchers, stored in resources. 330 // srvEntitiesWatcher notifies about changes for all entities of a given kind, 331 // sending the changes as a list of strings, which could be transformed 332 // from state entity ids to their corresponding entity tags. 333 type srvEntitiesWatcher struct { 334 st *state.State 335 resources *common.Resources 336 id string 337 watcher EntitiesWatcher 338 } 339 340 func newEntitiesWatcher(st *state.State, resources *common.Resources, auth common.Authorizer, id string) (interface{}, error) { 341 if !isAgent(auth) { 342 return nil, common.ErrPerm 343 } 344 watcher, ok := resources.Get(id).(EntitiesWatcher) 345 if !ok { 346 return nil, common.ErrUnknownWatcher 347 } 348 return &srvEntitiesWatcher{ 349 st: st, 350 resources: resources, 351 id: id, 352 watcher: watcher, 353 }, nil 354 } 355 356 // Next returns when a change has occured to an entity of the 357 // collection being watched since the most recent call to Next 358 // or the Watch call that created the srvEntitiesWatcher. 359 func (w *srvEntitiesWatcher) Next() (params.EntitiesWatchResult, error) { 360 if changes, ok := <-w.watcher.Changes(); ok { 361 mapped, err := w.watcher.MapChanges(changes) 362 if err != nil { 363 return params.EntitiesWatchResult{}, errors.Annotate(err, "cannot map changes") 364 } 365 return params.EntitiesWatchResult{ 366 Changes: mapped, 367 }, nil 368 } 369 err := w.watcher.Err() 370 if err == nil { 371 err = common.ErrStoppedWatcher 372 } 373 return params.EntitiesWatchResult{}, err 374 } 375 376 // Stop stops the watcher. 377 func (w *srvEntitiesWatcher) Stop() error { 378 return w.resources.Stop(w.id) 379 } 380 381 var getMigrationBackend = func(st *state.State) migrationBackend { 382 return st 383 } 384 385 // migrationBackend defines State functionality required by the 386 // migration watchers. 387 type migrationBackend interface { 388 GetModelMigration() (state.ModelMigration, error) 389 APIHostPorts() ([][]network.HostPort, error) 390 ControllerModel() (*state.Model, error) 391 } 392 393 func newMigrationStatusWatcher( 394 st *state.State, 395 resources *common.Resources, 396 auth common.Authorizer, 397 id string, 398 ) (interface{}, error) { 399 if !(auth.AuthMachineAgent() || auth.AuthUnitAgent()) { 400 return nil, common.ErrPerm 401 } 402 w, ok := resources.Get(id).(state.NotifyWatcher) 403 if !ok { 404 return nil, common.ErrUnknownWatcher 405 } 406 return &srvMigrationStatusWatcher{ 407 watcher: w, 408 id: id, 409 resources: resources, 410 st: getMigrationBackend(st), 411 }, nil 412 } 413 414 type srvMigrationStatusWatcher struct { 415 watcher state.NotifyWatcher 416 id string 417 resources *common.Resources 418 st migrationBackend 419 } 420 421 // Next returns when the status for a model migration for the 422 // associated model changes. The current details for the active 423 // migration are returned. 424 func (w *srvMigrationStatusWatcher) Next() (params.MigrationStatus, error) { 425 empty := params.MigrationStatus{} 426 427 if _, ok := <-w.watcher.Changes(); !ok { 428 err := w.watcher.Err() 429 if err == nil { 430 err = common.ErrStoppedWatcher 431 } 432 return empty, err 433 } 434 435 mig, err := w.st.GetModelMigration() 436 if errors.IsNotFound(err) { 437 return params.MigrationStatus{ 438 Phase: migration.NONE.String(), 439 }, nil 440 } else if err != nil { 441 return empty, errors.Annotate(err, "migration lookup") 442 } 443 444 attempt, err := mig.Attempt() 445 if err != nil { 446 return empty, errors.Annotate(err, "retrieving migration attempt") 447 } 448 449 phase, err := mig.Phase() 450 if err != nil { 451 return empty, errors.Annotate(err, "retrieving migration phase") 452 } 453 454 sourceAddrs, err := w.getLocalHostPorts() 455 if err != nil { 456 return empty, errors.Annotate(err, "retrieving source addresses") 457 } 458 459 sourceCACert, err := getControllerCACert(w.st) 460 if err != nil { 461 return empty, errors.Annotate(err, "retrieving source CA cert") 462 } 463 464 target, err := mig.TargetInfo() 465 if err != nil { 466 return empty, errors.Annotate(err, "retrieving target info") 467 } 468 469 return params.MigrationStatus{ 470 Attempt: attempt, 471 Phase: phase.String(), 472 SourceAPIAddrs: sourceAddrs, 473 SourceCACert: sourceCACert, 474 TargetAPIAddrs: target.Addrs, 475 TargetCACert: target.CACert, 476 }, nil 477 } 478 479 func (w *srvMigrationStatusWatcher) getLocalHostPorts() ([]string, error) { 480 hostports, err := w.st.APIHostPorts() 481 if err != nil { 482 return nil, errors.Trace(err) 483 } 484 var out []string 485 for _, section := range hostports { 486 for _, hostport := range section { 487 out = append(out, hostport.String()) 488 } 489 } 490 return out, nil 491 } 492 493 // Stop stops the watcher. 494 func (w *srvMigrationStatusWatcher) Stop() error { 495 return w.resources.Stop(w.id) 496 } 497 498 // This is a shim to avoid the need to use a working State into the 499 // unit tests. It is tested as part of the client side API tests. 500 var getControllerCACert = func(st migrationBackend) (string, error) { 501 model, err := st.ControllerModel() 502 if err != nil { 503 return "", errors.Trace(err) 504 } 505 506 config, err := model.Config() 507 if err != nil { 508 return "", errors.Trace(err) 509 } 510 511 cacert, ok := config.CACert() 512 if !ok { 513 return "", errors.New("missing CA cert for controller model") 514 } 515 return cacert, nil 516 }