github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/facade/interface.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package facade
     5  
     6  import (
     7  	"net/http"
     8  	"net/url"
     9  	"time"
    10  
    11  	"github.com/juju/names/v5"
    12  
    13  	"github.com/juju/juju/core/cache"
    14  	coredatabase "github.com/juju/juju/core/database"
    15  	"github.com/juju/juju/core/leadership"
    16  	"github.com/juju/juju/core/lease"
    17  	"github.com/juju/juju/core/multiwatcher"
    18  	"github.com/juju/juju/core/permission"
    19  	"github.com/juju/juju/core/presence"
    20  	"github.com/juju/juju/state"
    21  )
    22  
    23  // Facade could be anything; it will be interpreted by the apiserver
    24  // machinery such that certain exported methods will be made available
    25  // as facade methods to connected clients.
    26  type Facade interface{}
    27  
    28  // Factory is a callback used to create a Facade.
    29  type Factory func(Context) (Facade, error)
    30  
    31  // LeadershipContext describes factory methods for objects that deliver
    32  // specific lease-related capabilities
    33  type LeadershipContext interface {
    34  
    35  	// LeadershipClaimer returns a leadership.Claimer tied to a
    36  	// specific model.
    37  	LeadershipClaimer(modelUUID string) (leadership.Claimer, error)
    38  
    39  	// LeadershipRevoker returns a leadership.Revoker tied to a
    40  	// specific model.
    41  	LeadershipRevoker(modelUUID string) (leadership.Revoker, error)
    42  
    43  	// LeadershipChecker returns a leadership.Checker for this
    44  	// context's model.
    45  	LeadershipChecker() (leadership.Checker, error)
    46  
    47  	// LeadershipPinner returns a leadership.Pinner for this
    48  	// context's model.
    49  	LeadershipPinner(modelUUID string) (leadership.Pinner, error)
    50  
    51  	// LeadershipReader returns a leadership.Reader for this
    52  	// context's model.
    53  	LeadershipReader(modelUUID string) (leadership.Reader, error)
    54  
    55  	// SingularClaimer returns a lease.Claimer for singular leases for
    56  	// this context's model.
    57  	SingularClaimer() (lease.Claimer, error)
    58  }
    59  
    60  // Context exposes useful capabilities to a Facade.
    61  type Context interface {
    62  	// TODO (stickupkid): This shouldn't be embedded, instead this should be
    63  	// in the form of `context.Leadership() Leadership`, which returns the
    64  	// contents of the LeadershipContext.
    65  	// Context should have a single responsibility, and that's access to other
    66  	// types/objects.
    67  	LeadershipContext
    68  
    69  	// Cancel channel represents an indication from the API server that
    70  	// all interruptable calls should stop. The channel is only ever
    71  	// closed, and never sents values.
    72  	Cancel() <-chan struct{}
    73  
    74  	// Auth represents information about the connected client. You
    75  	// should always be checking individual requests against Auth:
    76  	// both state changes *and* data retrieval should be blocked
    77  	// with apiservererrors.ErrPerm for any targets for which the client is
    78  	// not *known* to have a responsibility or requirement.
    79  	Auth() Authorizer
    80  
    81  	// Dispose disposes the context and any resources related to
    82  	// the API server facade object. Normally the context will not
    83  	// be disposed until the API connection is closed. This is OK
    84  	// except when contexts are dynamically generated, such as in
    85  	// the case of watchers. When a facade context is no longer
    86  	// needed, e.g. when a watcher is closed, then the context may
    87  	// be disposed by calling this method.
    88  	Dispose()
    89  
    90  	// Resources exposes per-connection capabilities. By adding a
    91  	// resource, you make it accessible by (returned) id to all
    92  	// other facades used by this connection. It's mostly used to
    93  	// pass watcher ids over to watcher-specific facades, but that
    94  	// seems to be an antipattern: it breaks the separate-facades-
    95  	// by-role advice, and makes it inconvenient to track a given
    96  	// worker's watcher activity alongside its other communications.
    97  	//
    98  	// It's also used to hold some config strings used by various
    99  	// consumers, because it's convenient; and the Pinger that
   100  	// reports client presence in state, because every Resource gets
   101  	// Stop()ped on conn close. Not all of these uses are
   102  	// necessarily a great idea.
   103  	Resources() Resources
   104  
   105  	// State returns, /sigh, a *State. As yet, there is no way
   106  	// around this; in the not-too-distant future, we hope, its
   107  	// capabilities will migrate towards access via Resources.
   108  	State() *state.State
   109  
   110  	// StatePool returns the state pool used by the apiserver to minimise the
   111  	// creation of the expensive *State instances.
   112  	StatePool() *state.StatePool
   113  
   114  	// MultiwatcherFactory returns the factory to create multiwatchers.
   115  	MultiwatcherFactory() multiwatcher.Factory
   116  
   117  	// Controller returns the in-memory representation of the models
   118  	// in the database.
   119  	Controller() *cache.Controller
   120  
   121  	// CachedModel returns the in-memory representation of the specified
   122  	// model. This call will wait for the model to appear in the cache.
   123  	// The method optimistically expects the model to exist in the cache
   124  	// or appear very soon. If the model doesn't appear, the database is
   125  	// checked. A NotFound error is returned if the model no longer exists
   126  	// in the database, or a Timeout error is returned if the model didn't
   127  	// appear, but should have.
   128  	CachedModel(uuid string) (*cache.Model, error)
   129  
   130  	// Presence returns an instance that is able to be asked for
   131  	// the current model presence.
   132  	Presence() Presence
   133  
   134  	// Hub returns the central hub that the API server holds.
   135  	// At least at this stage, facades only need to publish events.
   136  	Hub() Hub
   137  
   138  	// ID returns a string that should almost always be "", unless
   139  	// this is a watcher facade, in which case it exists in lieu of
   140  	// actual arguments in the Next() call, and is used as a key
   141  	// into Resources to get the watcher in play. This is not really
   142  	// a good idea; see Resources.
   143  	ID() string
   144  
   145  	// RequestRecorder defines a metrics collector for outbound requests.
   146  	RequestRecorder() RequestRecorder
   147  
   148  	// HTTPClient returns an HTTP client to use for the given purpose.
   149  	HTTPClient(purpose HTTPClientPurpose) HTTPClient
   150  
   151  	// ControllerDB returns a TrackedDB reference for the controller database.
   152  	ControllerDB() (coredatabase.TrackedDB, error)
   153  }
   154  
   155  // RequestRecorder is implemented by types that can record information about
   156  // successful and unsuccessful http requests.
   157  type RequestRecorder interface {
   158  	// Record an outgoing request that produced a http.Response.
   159  	Record(method string, url *url.URL, res *http.Response, rtt time.Duration)
   160  
   161  	// RecordError records an outgoing request that returned back an error.
   162  	RecordError(method string, url *url.URL, err error)
   163  }
   164  
   165  // Authorizer represents the authenticated entity using the API server.
   166  type Authorizer interface {
   167  
   168  	// GetAuthTag returns the entity's tag.
   169  	GetAuthTag() names.Tag
   170  
   171  	// AuthController returns whether the authenticated entity is
   172  	// a machine acting as a controller. Can't be removed from this
   173  	// interface without introducing a dependency on something else
   174  	// to look up that property: it's not inherent in the result of
   175  	// GetAuthTag, as the other methods all are.
   176  	AuthController() bool
   177  
   178  	// TODO(wallyworld - bug 1733759) - the following auth methods should not be on this interface
   179  	// eg introduce a utility func or something.
   180  
   181  	// AuthMachineAgent returns true if the entity is a machine agent.
   182  	AuthMachineAgent() bool
   183  
   184  	// AuthApplicationAgent returns true if the entity is an application operator.
   185  	AuthApplicationAgent() bool
   186  
   187  	// AuthModelAgent returns true if the entity is a model operator.
   188  	AuthModelAgent() bool
   189  
   190  	// AuthUnitAgent returns true if the entity is a unit agent.
   191  	AuthUnitAgent() bool
   192  
   193  	// AuthOwner returns true if tag == .GetAuthTag().
   194  	AuthOwner(tag names.Tag) bool
   195  
   196  	// AuthClient returns true if the entity is an external user.
   197  	AuthClient() bool
   198  
   199  	// HasPermission reports whether the given access is allowed for the given
   200  	// target by the authenticated entity.
   201  	HasPermission(operation permission.Access, target names.Tag) error
   202  
   203  	// EntityHasPermission reports whether the given access is allowed for the given
   204  	// target by the given entity.
   205  	EntityHasPermission(entity names.Tag, operation permission.Access, target names.Tag) error
   206  
   207  	// ConnectedModel returns the UUID of the model to which the API
   208  	// connection was made.
   209  	ConnectedModel() string
   210  }
   211  
   212  // Resources allows you to store and retrieve Resource implementations.
   213  //
   214  // The lack of error returns are in deference to the existing
   215  // implementation, not because they're a good idea.
   216  type Resources interface {
   217  	Register(Resource) string
   218  	Get(string) Resource
   219  	Stop(string) error
   220  }
   221  
   222  // Resource should almost certainly be worker.Worker: the current
   223  // implementation renders the apiserver vulnerable to deadlock when
   224  // shutting down. (See common.Resources.StopAll -- *that* should be a
   225  // Kill() and a Wait(), so that connection cleanup can kill the
   226  // resources early, along with everything else, and then just wait for
   227  // all those things to finish.)
   228  type Resource interface {
   229  	Stop() error
   230  }
   231  
   232  // Presence represents the current known state of API connections from agents
   233  // to any of the API servers.
   234  type Presence interface {
   235  	ModelPresence(modelUUID string) ModelPresence
   236  }
   237  
   238  // ModelPresence represents the API server connections for a model.
   239  type ModelPresence interface {
   240  	// For a given non controller agent, return the Status for that agent.
   241  	AgentStatus(agent string) (presence.Status, error)
   242  }
   243  
   244  // Hub represents the central hub that the API server has.
   245  type Hub interface {
   246  	Publish(topic string, data interface{}) (func(), error)
   247  }
   248  
   249  // HTTPClient represents an HTTP client, for example, an *http.Client.
   250  type HTTPClient interface {
   251  	Do(*http.Request) (*http.Response, error)
   252  }
   253  
   254  // HTTPClientPurpose describes a specific purpose for an HTTP client.
   255  type HTTPClientPurpose string
   256  
   257  const (
   258  	CharmhubHTTPClient HTTPClientPurpose = "charmhub"
   259  )