launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/apiserver/root.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  	"launchpad.net/errgo/errors"
     8  	"time"
     9  
    10  	"launchpad.net/tomb"
    11  
    12  	"launchpad.net/juju-core/rpc"
    13  	"launchpad.net/juju-core/state"
    14  	"launchpad.net/juju-core/state/apiserver/agent"
    15  	"launchpad.net/juju-core/state/apiserver/charmrevisionupdater"
    16  	"launchpad.net/juju-core/state/apiserver/client"
    17  	"launchpad.net/juju-core/state/apiserver/common"
    18  	"launchpad.net/juju-core/state/apiserver/deployer"
    19  	"launchpad.net/juju-core/state/apiserver/environment"
    20  	"launchpad.net/juju-core/state/apiserver/firewaller"
    21  	"launchpad.net/juju-core/state/apiserver/keymanager"
    22  	"launchpad.net/juju-core/state/apiserver/keyupdater"
    23  	loggerapi "launchpad.net/juju-core/state/apiserver/logger"
    24  	"launchpad.net/juju-core/state/apiserver/machine"
    25  	"launchpad.net/juju-core/state/apiserver/provisioner"
    26  	"launchpad.net/juju-core/state/apiserver/uniter"
    27  	"launchpad.net/juju-core/state/apiserver/upgrader"
    28  	"launchpad.net/juju-core/state/multiwatcher"
    29  )
    30  
    31  type clientAPI struct{ *client.API }
    32  
    33  type taggedAuthenticator interface {
    34  	state.Entity
    35  	state.Authenticator
    36  }
    37  
    38  // maxPingInterval defines the timeframe until the ping
    39  // timeout closes the monitored connection.
    40  // TODO(mue): Idea by Roger: Move to API (e.g. params) so
    41  // that the pinging there may depend on the interval.
    42  var maxPingInterval = 3 * time.Minute
    43  
    44  // srvRoot represents a single client's connection to the state
    45  // after it has logged in.
    46  type srvRoot struct {
    47  	clientAPI
    48  	srv         *Server
    49  	rpcConn     *rpc.Conn
    50  	resources   *common.Resources
    51  	pingTimeout *pingTimeout
    52  
    53  	entity taggedAuthenticator
    54  }
    55  
    56  // newSrvRoot creates the client's connection representation
    57  // and starts a ping timeout for the monitoring of this
    58  // connection.
    59  func newSrvRoot(root *initialRoot, entity taggedAuthenticator) *srvRoot {
    60  	r := &srvRoot{
    61  		srv:       root.srv,
    62  		rpcConn:   root.rpcConn,
    63  		resources: common.NewResources(),
    64  		entity:    entity,
    65  	}
    66  	r.clientAPI.API = client.NewAPI(r.srv.state, r.resources, r, r.srv.dataDir)
    67  	return r
    68  }
    69  
    70  // Kill implements rpc.Killer.  It cleans up any resources that need
    71  // cleaning up to ensure that all outstanding requests return.
    72  func (r *srvRoot) Kill() {
    73  	r.resources.StopAll()
    74  	if r.pingTimeout != nil {
    75  		r.pingTimeout.stop()
    76  	}
    77  }
    78  
    79  // requireAgent checks whether the current client is an agent and hence
    80  // may access the agent APIs.  We filter out non-agents when calling one
    81  // of the accessor functions (Machine, Unit, etc) which avoids us making
    82  // the check in every single request method.
    83  func (r *srvRoot) requireAgent() error {
    84  	if !isAgent(r.entity) {
    85  		return common.ErrPerm
    86  	}
    87  	return nil
    88  }
    89  
    90  // requireClient returns an error unless the current
    91  // client is a juju client user.
    92  func (r *srvRoot) requireClient() error {
    93  	if isAgent(r.entity) {
    94  		return common.ErrPerm
    95  	}
    96  	return nil
    97  }
    98  
    99  // KeyManager returns an object that provides access to the KeyManager API
   100  // facade. The id argument is reserved for future use and currently
   101  // needs to be empty.
   102  func (r *srvRoot) KeyManager(id string) (*keymanager.KeyManagerAPI, error) {
   103  	if id != "" {
   104  		return nil, common.ErrBadId
   105  	}
   106  	return keymanager.NewKeyManagerAPI(r.srv.state, r.resources, r)
   107  }
   108  
   109  // Machiner returns an object that provides access to the Machiner API
   110  // facade. The id argument is reserved for future use and currently
   111  // needs to be empty.
   112  func (r *srvRoot) Machiner(id string) (*machine.MachinerAPI, error) {
   113  	if id != "" {
   114  		// Safeguard id for possible future use.
   115  		return nil, common.ErrBadId
   116  	}
   117  	return machine.NewMachinerAPI(r.srv.state, r.resources, r)
   118  }
   119  
   120  // Provisioner returns an object that provides access to the
   121  // Provisioner API facade. The id argument is reserved for future use
   122  // and currently needs to be empty.
   123  func (r *srvRoot) Provisioner(id string) (*provisioner.ProvisionerAPI, error) {
   124  	if id != "" {
   125  		// Safeguard id for possible future use.
   126  		return nil, common.ErrBadId
   127  	}
   128  	return provisioner.NewProvisionerAPI(r.srv.state, r.resources, r)
   129  }
   130  
   131  // Uniter returns an object that provides access to the Uniter API
   132  // facade. The id argument is reserved for future use and currently
   133  // needs to be empty.
   134  func (r *srvRoot) Uniter(id string) (*uniter.UniterAPI, error) {
   135  	if id != "" {
   136  		// Safeguard id for possible future use.
   137  		return nil, common.ErrBadId
   138  	}
   139  	return uniter.NewUniterAPI(r.srv.state, r.resources, r)
   140  }
   141  
   142  // Firewaller returns an object that provides access to the Firewaller
   143  // API facade. The id argument is reserved for future use and
   144  // currently needs to be empty.
   145  func (r *srvRoot) Firewaller(id string) (*firewaller.FirewallerAPI, error) {
   146  	if id != "" {
   147  		// Safeguard id for possible future use.
   148  		return nil, common.ErrBadId
   149  	}
   150  	return firewaller.NewFirewallerAPI(r.srv.state, r.resources, r)
   151  }
   152  
   153  // Agent returns an object that provides access to the
   154  // agent API.  The id argument is reserved for future use and must currently
   155  // be empty.
   156  func (r *srvRoot) Agent(id string) (*agent.API, error) {
   157  	if id != "" {
   158  		return nil, common.ErrBadId
   159  	}
   160  	return agent.NewAPI(r.srv.state, r)
   161  }
   162  
   163  // Deployer returns an object that provides access to the Deployer API facade.
   164  // The id argument is reserved for future use and must be empty.
   165  func (r *srvRoot) Deployer(id string) (*deployer.DeployerAPI, error) {
   166  	if id != "" {
   167  		// TODO(dimitern): There is no direct test for this
   168  		return nil, common.ErrBadId
   169  	}
   170  	return deployer.NewDeployerAPI(r.srv.state, r.resources, r)
   171  }
   172  
   173  // Environment returns an object that provides access to the Environment API
   174  // facade. The id argument is reserved for future use and currently needs to
   175  // be empty.
   176  func (r *srvRoot) Environment(id string) (*environment.EnvironmentAPI, error) {
   177  	if id != "" {
   178  		// Safeguard id for possible future use.
   179  		return nil, common.ErrBadId
   180  	}
   181  	return environment.NewEnvironmentAPI(r.srv.state, r.resources, r)
   182  }
   183  
   184  // Logger returns an object that provides access to the Logger API facade.
   185  // The id argument is reserved for future use and must be empty.
   186  func (r *srvRoot) Logger(id string) (*loggerapi.LoggerAPI, error) {
   187  	if id != "" {
   188  		// TODO: There is no direct test for this
   189  		return nil, common.ErrBadId
   190  	}
   191  	return loggerapi.NewLoggerAPI(r.srv.state, r.resources, r)
   192  }
   193  
   194  // Upgrader returns an object that provides access to the Upgrader API facade.
   195  // The id argument is reserved for future use and must be empty.
   196  func (r *srvRoot) Upgrader(id string) (*upgrader.UpgraderAPI, error) {
   197  	if id != "" {
   198  		// TODO: There is no direct test for this
   199  		return nil, common.ErrBadId
   200  	}
   201  	return upgrader.NewUpgraderAPI(r.srv.state, r.resources, r)
   202  }
   203  
   204  // KeyUpdater returns an object that provides access to the KeyUpdater API facade.
   205  // The id argument is reserved for future use and must be empty.
   206  func (r *srvRoot) KeyUpdater(id string) (*keyupdater.KeyUpdaterAPI, error) {
   207  	if id != "" {
   208  		// TODO: There is no direct test for this
   209  		return nil, common.ErrBadId
   210  	}
   211  	return keyupdater.NewKeyUpdaterAPI(r.srv.state, r.resources, r)
   212  }
   213  
   214  // CharmRevisionUpdater returns an object that provides access to the CharmRevisionUpdater API facade.
   215  // The id argument is reserved for future use and must be empty.
   216  func (r *srvRoot) CharmRevisionUpdater(id string) (*charmrevisionupdater.CharmRevisionUpdaterAPI, error) {
   217  	if id != "" {
   218  		// TODO: There is no direct test for this
   219  		return nil, common.ErrBadId
   220  	}
   221  	return charmrevisionupdater.NewCharmRevisionUpdaterAPI(r.srv.state, r.resources, r)
   222  }
   223  
   224  // NotifyWatcher returns an object that provides
   225  // API access to methods on a state.NotifyWatcher.
   226  // Each client has its own current set of watchers, stored
   227  // in r.resources.
   228  func (r *srvRoot) NotifyWatcher(id string) (*srvNotifyWatcher, error) {
   229  	if err := r.requireAgent(); err != nil {
   230  		return nil, mask(err)
   231  	}
   232  	watcher, ok := r.resources.Get(id).(state.NotifyWatcher)
   233  	if !ok {
   234  		return nil, common.ErrUnknownWatcher
   235  	}
   236  	return &srvNotifyWatcher{
   237  		watcher:   watcher,
   238  		id:        id,
   239  		resources: r.resources,
   240  	}, nil
   241  }
   242  
   243  // StringsWatcher returns an object that provides API access to
   244  // methods on a state.StringsWatcher.  Each client has its own
   245  // current set of watchers, stored in r.resources.
   246  func (r *srvRoot) StringsWatcher(id string) (*srvStringsWatcher, error) {
   247  	if err := r.requireAgent(); err != nil {
   248  		return nil, mask(err)
   249  	}
   250  	watcher, ok := r.resources.Get(id).(state.StringsWatcher)
   251  	if !ok {
   252  		return nil, common.ErrUnknownWatcher
   253  	}
   254  	return &srvStringsWatcher{
   255  		watcher:   watcher,
   256  		id:        id,
   257  		resources: r.resources,
   258  	}, nil
   259  }
   260  
   261  // RelationUnitsWatcher returns an object that provides API access to
   262  // methods on a state.RelationUnitsWatcher. Each client has its own
   263  // current set of watchers, stored in r.resources.
   264  func (r *srvRoot) RelationUnitsWatcher(id string) (*srvRelationUnitsWatcher, error) {
   265  	if err := r.requireAgent(); err != nil {
   266  		return nil, mask(err)
   267  	}
   268  	watcher, ok := r.resources.Get(id).(state.RelationUnitsWatcher)
   269  	if !ok {
   270  		return nil, common.ErrUnknownWatcher
   271  	}
   272  	return &srvRelationUnitsWatcher{
   273  		watcher:   watcher,
   274  		id:        id,
   275  		resources: r.resources,
   276  	}, nil
   277  }
   278  
   279  // AllWatcher returns an object that provides API access to methods on
   280  // a state/multiwatcher.Watcher, which watches any changes to the
   281  // state. Each client has its own current set of watchers, stored in
   282  // r.resources.
   283  func (r *srvRoot) AllWatcher(id string) (*srvClientAllWatcher, error) {
   284  	if err := r.requireClient(); err != nil {
   285  		return nil, mask(err)
   286  	}
   287  	watcher, ok := r.resources.Get(id).(*multiwatcher.Watcher)
   288  	if !ok {
   289  		return nil, common.ErrUnknownWatcher
   290  	}
   291  	return &srvClientAllWatcher{
   292  		watcher:   watcher,
   293  		id:        id,
   294  		resources: r.resources,
   295  	}, nil
   296  }
   297  
   298  // Pinger returns an object that can be pinged
   299  // by calling its Ping method. If this method
   300  // is not called frequently enough, the connection
   301  // will be dropped.
   302  func (r *srvRoot) Pinger(id string) (pinger, error) {
   303  	if r.pingTimeout == nil {
   304  		return nullPinger{}, nil
   305  	}
   306  	return r.pingTimeout, nil
   307  }
   308  
   309  type nullPinger struct{}
   310  
   311  func (nullPinger) Ping() {}
   312  
   313  // AuthMachineAgent returns whether the current client is a machine agent.
   314  func (r *srvRoot) AuthMachineAgent() bool {
   315  	_, ok := r.entity.(*state.Machine)
   316  	return ok
   317  }
   318  
   319  // AuthUnitAgent returns whether the current client is a unit agent.
   320  func (r *srvRoot) AuthUnitAgent() bool {
   321  	_, ok := r.entity.(*state.Unit)
   322  	return ok
   323  }
   324  
   325  // AuthOwner returns whether the authenticated user's tag matches the
   326  // given entity tag.
   327  func (r *srvRoot) AuthOwner(tag string) bool {
   328  	return r.entity.Tag() == tag
   329  }
   330  
   331  // AuthEnvironManager returns whether the authenticated user is a
   332  // machine with running the ManageEnviron job.
   333  func (r *srvRoot) AuthEnvironManager() bool {
   334  	return isMachineWithJob(r.entity, state.JobManageEnviron)
   335  }
   336  
   337  // AuthClient returns whether the authenticated entity is a client
   338  // user.
   339  func (r *srvRoot) AuthClient() bool {
   340  	return !isAgent(r.entity)
   341  }
   342  
   343  // GetAuthTag returns the tag of the authenticated entity.
   344  func (r *srvRoot) GetAuthTag() string {
   345  	return r.entity.Tag()
   346  }
   347  
   348  // GetAuthEntity returns the authenticated entity.
   349  func (r *srvRoot) GetAuthEntity() state.Entity {
   350  	return r.entity
   351  }
   352  
   353  // pinger describes a type that can be pinged.
   354  type pinger interface {
   355  	Ping()
   356  }
   357  
   358  // pingTimeout listens for pings and will call the
   359  // passed action in case of a timeout. This way broken
   360  // or inactive connections can be closed.
   361  type pingTimeout struct {
   362  	tomb    tomb.Tomb
   363  	action  func()
   364  	timeout time.Duration
   365  	reset   chan struct{}
   366  }
   367  
   368  // newPingTimeout returns a new pingTimeout instance
   369  // that invokes the given action asynchronously if there
   370  // is more than the given timeout interval between calls
   371  // to its Ping method.
   372  func newPingTimeout(action func(), timeout time.Duration) *pingTimeout {
   373  	pt := &pingTimeout{
   374  		action:  action,
   375  		timeout: timeout,
   376  		reset:   make(chan struct{}),
   377  	}
   378  	go func() {
   379  		defer pt.tomb.Done()
   380  		pt.tomb.Kill(pt.loop())
   381  	}()
   382  	return pt
   383  }
   384  
   385  // Ping is used by the client heartbeat monitor and resets
   386  // the killer.
   387  func (pt *pingTimeout) Ping() {
   388  	select {
   389  	case <-pt.tomb.Dying():
   390  	case pt.reset <- struct{}{}:
   391  	}
   392  }
   393  
   394  // stop terminates the ping timeout.
   395  func (pt *pingTimeout) stop() error {
   396  	pt.tomb.Kill(nil)
   397  	return pt.tomb.Wait()
   398  }
   399  
   400  // loop waits for a reset signal, otherwise it performs
   401  // the initially passed action.
   402  func (pt *pingTimeout) loop() error {
   403  	timer := time.NewTimer(pt.timeout)
   404  	defer timer.Stop()
   405  	for {
   406  		select {
   407  		case <-pt.tomb.Dying():
   408  			return nil
   409  		case <-timer.C:
   410  			go pt.action()
   411  			return errors.New("ping timeout")
   412  		case <-pt.reset:
   413  			timer.Reset(pt.timeout)
   414  		}
   415  	}
   416  }