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  }