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 )