luci: go.chromium.org/luci/appengine/gaemiddleware Index | Files | Directories

package gaemiddleware

import "go.chromium.org/luci/appengine/gaemiddleware"

Package gaemiddleware provides a standard middleware for Appengine apps. The gaemiddleware package itself provides a generic Environment class and common implementations of methods. An Environment matching your AppEngine environment configuration (e.g., standard, flex) should be chosen from a sub-package.

This middleware configures the request environment to use GAE-based services (like datastore via luci/gae package, logging and many more).

For full functionality, the "default" module of a GAE application must be running on an AppEngine Standard instance, and must have handlers installed (via "standard.InstallHandlers").

The minimal usage example (from GAE standard):

import (
  ...

  "go.chromium.org/luci/appengine/gaemiddleware/standard"
  "go.chromium.org/luci/common/logging"
  "go.chromium.org/luci/server/router"
)

func init() {
  r := router.New()
  standard.InstallHandlers(r)

  r.GET("/", standard.Base(), indexPage)

  http.DefaultServeMux.Handle("/", r)
}

func indexPage(c *router.Context) {
  logging.Infof(c.Context, "Handling the page")
  ...
}

It registers various routes required for LUCI framework functionality in the router, and sets up an application route (indexPage) configured to use GAE services.

Handlers setup

Some default registered routes are intended for use only by administrators or internally by GAE itself (crons, task queues). While LUCI framework does authorization checks itself, it is still recommended that you protect such routes on app.yaml level with "login: admin" check, to make GAE reject unauthorized access earlier.

In contrast, the rest of the routes (end-user facing HTML pages, API handlers) usually use LUCI's authentication framework (to support OAuth2 tokens, among other things), and for that reason they must not use "login: required" or "login: admin", since in that case GAE will enable its own cookie-based authentication mechanism (that doesn't work with OAuth2).

Thus the recommended handlers list is:

handlers:
- url: /(internal|admin)/.*
  script: _go_app
  secure: always
  login: admin

- url: /.*
  script: _go_app
  secure: always

See https://cloud.google.com/appengine/docs/standard/go/config/appref for more info about app.yaml.

Cron setup

Some of the default LUCI services installed in BaseProd require cron jobs for their operation.

InstallHandlers call registers the cron handlers in the HTTP router, but GAE still has to be instructed to actually call them.

This can done by adding following jobs to cron.yaml file of your project:

- description: "tsmon housekeeping task"
  url: /internal/cron/ts_mon/housekeeping
  schedule: every 1 minutes

- description: "LUCI Config datastore cache periodic refresh"
  url: /admin/config/cache/manager
  schedule: every 10 mins

See https://cloud.google.com/appengine/docs/standard/go/config/cronref for more information about cron.yaml.

Index

Package Files

appengine.go cache.go context.go doc.go settings.go version.go

Constants

const Version = "1.0.0"

Version is a semantic version of base luci-go GAE library.

It is bumped whenever we add new features or fix important bugs. It is reported to monitoring as 'luci/components/version' string metric with 'component' field set to 'go.chromium.org/luci/appengine/gaemiddleware'.

It allows to track what GAE apps use what version of the library, so it's easier to detect stale code running in production.

func RequireCron Uses

func RequireCron(c *router.Context, next router.Handler)

RequireCron ensures that the request is from the appengine 'cron' service.

It checks the presence of a magical header that can be set only by GAE. If the header is not there, it aborts the request with StatusForbidden.

This middleware has no effect when using 'BaseTest' or when running under dev_appserver.py

func RequireTaskQueue Uses

func RequireTaskQueue(queue string) router.Middleware

RequireTaskQueue ensures that the request is from the specified task queue.

It checks the presence of a magical header that can be set only by GAE. If the header is not there, it aborts the request with StatusForbidden.

if 'queue' is the empty string, than this simply checks that this handler was run from ANY appengine taskqueue.

This middleware has no effect when using 'BaseTest' or when running under dev_appserver.py

type Environment Uses

type Environment struct {
    // MemcacheAvailable is true if the environment has working memcache.
    //
    // If false, also implies disabled datastore caching layer.
    MemcacheAvailable bool

    // DSReadOnly, if true, causes a read-only datastore layer to be imposed,
    // preventing datastore writes.
    //
    // For any given datastore instance, at most one caching layer may be used.
    // All other instances must be ReadOnly to prevent errant writes from breaking
    // the assumptions of that caching layer. For example, if a Flex VM is being
    // used in conjunction with a non-read-only Classic AppEngine instance.
    DSReadOnly bool

    // DSReadOnlyPredicate returns true for keys that must not be mutated.
    //
    // Effective only when DSReadOnly is true. If nil, all keys are considered
    // read-only.
    DSReadOnlyPredicate readonly.Predicate

    // Prepare will be called once after init() time, but before serving requests.
    //
    // The given context is very bare, use it only for logging and deadlines and
    // stuff like that. It has no other services installed.
    Prepare func(context.Context)

    // WithInitialRequest is called at the very beginning of the handler. It
    // contains a reference to the handler's HTTP request.
    //
    // This should install basic services into the Context, including:
    // - Logging
    // - luci/GAE services.
    WithInitialRequest func(context.Context, *http.Request) context.Context

    // WithConfig is called during service setup to install the "gaeconfig" layer.
    //
    // If nil, no config layer will be installed.
    WithConfig func(context.Context) context.Context

    // WithAuth is called during service setup to install the "gaeauth" layer.
    //
    // If nil, no auth layer will be installed.
    WithAuth func(context.Context) context.Context

    // ExtraMiddleware, if not nil, is additional middleware chain to append to
    // the end of the Base middleware chain to perform per-request monitoring.
    ExtraMiddleware router.MiddlewareChain

    // ExtraHandlers, if not nil, is used to install additional handlers when
    // InstallHandlers is called.
    ExtraHandlers func(r *router.Router, base router.MiddlewareChain)
    // contains filtered or unexported fields
}

Environment is a middleware environment. Its parameters define how the middleware is applied, and which services are enlisted.

This is low-level API. Use either 'gaemiddeware/standard' or 'gaemiddeware/flex' packages to target a specific flavor of GAE environment.

func (*Environment) Base Uses

func (e *Environment) Base() router.MiddlewareChain

Base returns a middleware chain to use for all GAE environment requests.

Base DOES NOT install "luci/gae" services. To install appropriate services, use methods from a sub-package. This is done so that a given AppEngine environment doesn't need to include the superset of packages across all supported environments.

This middleware chain installs prod GAE services into the request context (via With), and wraps the request with a panic catcher and monitoring hooks.

func (*Environment) InstallHandlers Uses

func (e *Environment) InstallHandlers(r *router.Router)

InstallHandlers installs handlers for an Environment's framework routes.

See InstallHandlersWithMiddleware for more information.

func (*Environment) InstallHandlersWithMiddleware Uses

func (e *Environment) InstallHandlersWithMiddleware(r *router.Router, base router.MiddlewareChain)

InstallHandlersWithMiddleware installs handlers for an Environment's framework routes.

In addition to Environment-specific handlers, InstallHandlersWithMiddleware installs:

* Warmup Handler (warmup)

func (*Environment) With Uses

func (e *Environment) With(c context.Context, req *http.Request) context.Context

With adds various production GAE LUCI services to the context.

Basically, it installs GAE-specific backends and caches for various subsystems to make them work in GAE environment.

One example is a backend for Logging: go.chromium.org/luci/common/logging. Logs emitted through a WithProd() context go to GAE logs.

'Production' here means the services will use real GAE APIs (not mocks or stubs), so With should never be used from unit tests.

Directories

PathSynopsis
flexPackage flex exposes gaemiddleware Environments for AppEngine's Flex environment.
standardPackage standard exposes a gaemiddleware Environment for Classic AppEngine.

Package gaemiddleware imports 23 packages (graph) and is imported by 21 packages. Updated 2018-10-19. Refresh now. Tools for package owners.