server

package
Version: v0.0.0-...-51f9457 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 9, 2021 License: Apache-2.0 Imports: 61 Imported by: 0

Documentation

Overview

Package server implements an environment for running LUCI servers.

It interprets command line flags and initializes the serving environment with the following core services:

• go.chromium.org/luci/common/logging: logging via Google Cloud Logging and error reporting via Google Cloud Error Reporting.

• go.chromium.org/luci/common/trace: Tracing via Google Cloud Trace and profiling Google Cloud Profiler.

• go.chromium.org/luci/server/tsmon: monitoring metrics via ProdX.

• go.chromium.org/luci/server/auth: sending and receiving RPCs authenticated with Google OAuth2 or OpenID tokens. Support for authorization via LUCI groups and LUCI realms.

• go.chromium.org/luci/server/caching: in-process caching.

• go.chromium.org/luci/server/warmup: allows other server components to register warmup callbacks that run before the server starts handling requests.

• go.chromium.org/luci/server/experiments: simple feature flags support.

• go.chromium.org/luci/grpc/prpc: pRPC server and RPC Explorer UI.

Other functionality is optional and provided by modules (objects implementing module.Module interface). They should be passed to the server when it starts (see the example below). Modules usually expose their configuration via command line flags, and provide functionality by injecting state into the server's global context.Context or by exposing pRPC endpoints.

Usage example:

import (
  ...

  "go.chromium.org/luci/server"
  "go.chromium.org/luci/server/gaeemulation"
  "go.chromium.org/luci/server/module"
  "go.chromium.org/luci/server/redisconn"
)

func main() {
  modules := []module.Module{
    gaeemulation.NewModuleFromFlags(),
    redisconn.NewModuleFromFlags(),
  }
  server.Main(nil, modules, func(srv *server.Server) error {
    // Initialize global state, change root context (if necessary).
    if err := initializeGlobalStuff(srv.Context); err != nil {
      return err
    }
    srv.Context = injectGlobalStuff(srv.Context)

    // Install regular HTTP routes.
    srv.Routes.GET("/", nil, func(c *router.Context) {
      // ...
    })

    // Install pRPC services.
    servicepb.RegisterSomeServer(srv.PRPC, &SomeServer{})
    return nil
  })
}

More examples can be found in the code search: https://source.chromium.org/search?q=%22server.Main(nil,%20modules,%22

Known modules

The following modules (in alphabetical order) are a part of the LUCI repository and can be used in any server binary:

• go.chromium.org/luci/config/server/cfgmodule: provides LUCI Config client, exposes config validation endpoints used by LUCI Config service.

• go.chromium.org/luci/server/bqlog: implements best effort low-overhead structured logging to BigQuery suitable for debug data like access logs.

• go.chromium.org/luci/server/cron: allows registering Cloud Scheduler (aka Appengine cron.yaml) handlers, with proper authentication and monitoring metrics.

• go.chromium.org/luci/server/encryptedcookies: implements an authentication scheme for HTTP routes based on encrypted cookies and user sessions in some session store.

• go.chromium.org/luci/server/dsmapper: provides a way to apply some function to all datastore entities of some particular kind, in parallel, distributing work via Cloud Tasks.

• go.chromium.org/luci/server/gaeemulation: implements go.chromium.org/luci/gae Datastore interface via Google Cloud Datastore API. Named so because because it enables migration of GAEv1 apps to GAEv2 without touching datastore-related code.

• go.chromium.org/luci/server/limiter: a simple load shedding mechanism that puts a limit on a number of concurrent gRPC/pRPC requests the server is handling.

• go.chromium.org/luci/server/redisconn: a Redis client. Also enables Redis as a caching backend for go.chromium.org/luci/server/caching and for go.chromium.org/luci/gae/filter/dscache.

• go.chromium.org/luci/server/secrets: enables generation and validation of HMAC-tagged tokens via go.chromium.org/luci/server/tokens.

• go.chromium.org/luci/server/span: a Cloud Spanner client. Wraps Spanner API a bit to improve interoperability with other modules (in particular the TQ module).

• go.chromium.org/luci/server/tq: implements a task queue mechanism on top of Cloud Tasks and Cloud PubSub. Also implements transactional task enqueuing when submitting tasks in a Cloud Datastore or a Cloud Spanner transaction.

Most of them need to be configured via corresponding CLI flags to be useful. See implementation of individual modules for details.

An up-to-date list of all known module implementations can be found here: https://source.chromium.org/search?q=%22NewModuleFromFlags()%20module.Module%22

pRPC services

The server.PRPC field is the primary grpc.ServiceRegistrar that should be used to expose server's public gRPC/pRPC APIs. It is pre-configured with a set of gRPC interceptors that collect performance metrics, catch panics and authenticate requests using OAuth2 access tokens. Modules can add more interceptors to the default interceptor chain.

Security considerations

The expected deployment environments are Kubernetes, Google App Engine and Google Cloud Run. In all cases the server is expected to be behind a load balancer (or a series of load balancers) that terminates TLS and sets X-Forwarded-For header as:

[<untrusted part>,]<IP that connected to the LB>,<unimportant>[,<more>].

Where <untrusted part> may be present if the original request from the Internet comes with X-Forwarded-For header. The IP specified there is not trusted, but the server assumes the load balancer at least sanitizes the format of this field.

<IP that connected to the LB> is the end-client IP that can be used by the server for logs and for IP-allowlist checks.

<unimportant> is "global forwarding rule external IP" for GKE or the constant "169.254.1.1" for GAE. It is unused. See https://cloud.google.com/load-balancing/docs/https for more info.

<more> may be present if the request was proxied through more layers of load balancers while already inside the cluster. The server currently assumes this is not happening (i.e. <more> is absent, or, in other words, the client IP is second to last in the X-Forwarded-For list). If you need to recognize more layers of load balancing, please file a feature request to add a CLI flag specifying how many layers of load balancers to skip to get to the original IP.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Main

func Main(opts *Options, mods []module.Module, init func(srv *Server) error)

Main initializes the server and runs its serving loop until SIGTERM.

Registers all options in the default flag set and uses `flag.Parse` to parse them. If 'opts' is nil, the default options will be used. Only flags are allowed in the command line (no positional arguments).

Additionally recognizes GAE_* env vars as an indicator that the server is running on GAE. This slightly tweaks its behavior to match what GAE expects from servers.

On errors, logs them and aborts the process with non-zero exit code.

Types

type Options

type Options struct {
	Prod     bool   // set when running in production (not on a dev workstation)
	GAE      bool   // set when running on GAE, implies Prod
	Hostname string // used for logging and metric fields, default is os.Hostname

	HTTPAddr  string // address to bind the main listening socket to
	AdminAddr string // address to bind the admin socket to, ignored on GAE

	DefaultRequestTimeout  time.Duration // how long non-internal HTTP handlers are allowed to run, 1 min by default
	InternalRequestTimeout time.Duration // how long "/internal/*" HTTP handlers are allowed to run, 10 min by default
	ShutdownDelay          time.Duration // how long to wait after SIGTERM before shutting down

	ClientAuth       clientauth.Options // base settings for client auth options
	TokenCacheDir    string             // where to cache auth tokens (optional)
	AuthDBPath       string             // if set, load AuthDB from a file
	AuthServiceHost  string             // hostname of an Auth Service to use
	AuthDBDump       string             // Google Storage path to fetch AuthDB dumps from
	AuthDBSigner     string             // service account that signs AuthDB dumps
	FrontendClientID string             // OAuth2 ClientID for frontend (e.g. user sign in)

	CloudProject string // name of the hosting Google Cloud Project
	CloudRegion  string // name of the hosting Google Cloud region

	TraceSampling string // what portion of traces to upload to Stackdriver (ignored on GAE)

	TsMonAccount     string // service account to flush metrics as
	TsMonServiceName string // service name of tsmon target
	TsMonJobName     string // job name of tsmon target

	ProfilingDisable   bool   // set to true to explicitly disable Stackdriver Profiler
	ProfilingServiceID string // service name to associated with profiles in Stackdriver Profiler

	ContainerImageID string // ID of the container image with this binary, for logs (optional)

	EnableExperiments []string // names of go.chromium.org/luci/server/experiments to enable

	CloudErrorReporting bool // set to true to enable Cloud Error Reporting
	// contains filtered or unexported fields
}

Options are used to configure the server.

Most of them are exposed as command line flags (see Register implementation). Some (mostly GAE-specific) are only settable through code or are derived from the environment.

func (*Options) FromGAEEnv

func (o *Options) FromGAEEnv()

FromGAEEnv uses the GAE_* env vars to configure the server for the GAE environment.

Does nothing if GAE_VERSION is not set.

Equivalent to passing the following flags:

-prod
-http-addr 0.0.0.0:${PORT}
-admin-addr -
-shutdown-delay 0s
-cloud-project ${GOOGLE_CLOUD_PROJECT}
-cloud-region <derived from the region code in GAE_APPLICATION>
-service-account-json :gce
-ts-mon-service-name ${GOOGLE_CLOUD_PROJECT}
-ts-mon-job-name ${GAE_SERVICE}

Additionally the hostname and -container-image-id (used in metric and trace fields) are derived from available GAE_* env vars to be semantically similar to what they represent in the GKE environment.

Note that a mapping between a region code in GAE_APPLICATION and the corresponding cloud region is not documented anywhere, so if you see warnings when your app starts up either update the code to recognize your region code or pass '-cloud-region' argument explicitly in app.yaml.

See https://cloud.google.com/appengine/docs/standard/go/runtime.

func (*Options) Register

func (o *Options) Register(f *flag.FlagSet)

Register registers the command line flags.

type Port

type Port struct {
	// Routes is a router for requests hitting this port.
	//
	// This router is used for all requests whose Host header does not match any
	// specially registered per-host routers (see VirtualHost). Normally, there
	// are no such per-host routers, so usually Routes is used for all requests.
	//
	// Should be populated before Server's ListenAndServe call.
	Routes *router.Router
	// contains filtered or unexported fields
}

Port is returned by Server's AddPort and used to setup the request routing.

func (*Port) VirtualHost

func (p *Port) VirtualHost(host string) *router.Router

VirtualHost returns a router (registering it if necessary) used for requests that have the given Host header.

Note that requests that match some registered virtual host router won't reach the default router (port.Routes), even if the virtual host router doesn't have a route for them. Such requests finish with HTTP 404.

Should be called before Server's ListenAndServe (panics otherwise).

type PortOptions

type PortOptions struct {
	Name           string // optional logical name of the port for logs
	ListenAddr     string // local address to bind to or "-" for a dummy port
	DisableMetrics bool   // do not collect HTTP metrics for requests on this port
}

PortOptions is a configuration of a single serving HTTP port.

See Server's AddPort.

type Server

type Server struct {
	// Context is the root context used by all requests and background activities.
	//
	// Can be replaced (by a derived context) before ListenAndServe call, for
	// example to inject values accessible to all request handlers.
	Context context.Context

	// Routes is a router for requests hitting HTTPAddr port.
	//
	// This router is used for all requests whose Host header does not match any
	// specially registered per-host routers (see VirtualHost). Normally, there
	// are no such per-host routers, so usually Routes is used for all requests.
	//
	// This router is also accessible to the server modules and they can install
	// routes into it.
	//
	// Should be populated before ListenAndServe call.
	Routes *router.Router

	// PRPC is pRPC server with APIs exposed on HTTPAddr port via Routes router.
	//
	// Should be populated before ListenAndServe call.
	PRPC *prpc.Server

	// CookieAuth is an authentication method implemented via cookies.
	//
	// It is initialized only if the server has a module implementing such scheme
	// (e.g. "go.chromium.org/luci/server/encryptedcookies").
	CookieAuth auth.Method

	// Options is a copy of options passed to New.
	Options Options
	// contains filtered or unexported fields
}

Server is responsible for initializing and launching the serving environment.

Generally assumed to be a singleton: do not launch multiple Server instances within the same process, use AddPort instead if you want to expose multiple ports.

Doesn't do TLS. Should be sitting behind a load balancer that terminates TLS.

func New

func New(ctx context.Context, opts Options, mods []module.Module) (srv *Server, err error)

New constructs a new server instance.

It hosts one or more HTTP servers and starts and stops them in unison. It is also responsible for preparing contexts for incoming requests.

The given context will become the root context of the server and will be inherited by all handlers.

On errors returns partially initialized server (always non-nil). At least its logging will be configured and can be used to report the error. Trying to use such partially initialized server for anything else is undefined behavior.

func (*Server) AddPort

func (s *Server) AddPort(opts PortOptions) *Port

AddPort prepares an additional serving HTTP port.

Can be used to open more listening HTTP ports (in addition to opts.HTTPAddr and opts.AdminAddr). The returned Port object can be used to populate the router that serves requests hitting the added port.

If opts.ListenAddr is '-', a dummy port will be added: it is a valid *Port object, but it is not actually exposed as a listening TCP socket. This is useful to disable listening ports without changing any code.

Should be called before ListenAndServe (panics otherwise).

func (*Server) Fatal

func (s *Server) Fatal(err error)

Fatal logs the error and immediately shuts down the process with exit code 3.

No cleanup is performed. Deferred statements are not run. Not recoverable.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe() error

ListenAndServe launches the serving loop.

Blocks forever or until the server is stopped via Shutdown (from another goroutine or from a SIGTERM handler). Returns nil if the server was shutdown correctly or an error if it failed to start or unexpectedly died. The error is logged inside.

Should be called only once. Panics otherwise.

func (*Server) RegisterCleanup

func (s *Server) RegisterCleanup(cb func(context.Context))

RegisterCleanup registers a callback that is run in ListenAndServe after the server has exited the serving loop.

Registering a new cleanup callback from within a cleanup causes a deadlock, don't do that.

func (*Server) RegisterUnaryServerInterceptor

func (s *Server) RegisterUnaryServerInterceptor(intr grpc.UnaryServerInterceptor)

RegisterUnaryServerInterceptor registers an grpc.UnaryServerInterceptor applied to all unary RPCs that hit the server.

Interceptors are chained in order they are registered, i.e. the first registered interceptor becomes the outermost. The initial chain already contains some base interceptors (e.g. for monitoring) and all interceptors registered by server modules. RegisterUnaryServerInterceptor extends this chain.

An interceptor set in server.PRPC.UnaryServerInterceptor (if any) is automatically registered as the last (innermost) one right before the server starts listening for requests in ListenAndServe.

Should be called before ListenAndServe (panics otherwise).

func (*Server) RegisterWarmup

func (s *Server) RegisterWarmup(cb func(context.Context))

RegisterWarmup registers a callback that is run in server's ListenAndServe right before the serving loop.

It receives the global server context (including all customizations made by the user code in server.Main). Intended for best-effort warmups: there's no way to gracefully abort the server startup from a warmup callback.

Registering a new warmup callback from within a warmup causes a deadlock, don't do that.

func (*Server) RunInBackground

func (s *Server) RunInBackground(activity string, f func(context.Context))

RunInBackground launches the given callback in a separate goroutine right before starting the serving loop.

If the server is already running, launches it right away. If the server fails to start, the goroutines will never be launched.

Should be used for background asynchronous activities like reloading configs.

All logs lines emitted by the callback are annotated with "activity" field which can be arbitrary, but by convention has format "<namespace>.<name>", where "luci" namespace is reserved for internal activities.

The context passed to the callback is canceled when the server is shutting down. It is expected the goroutine will exit soon after the context is canceled.

func (*Server) Shutdown

func (s *Server) Shutdown()

Shutdown gracefully stops the server if it was running.

Blocks until the server is stopped. Can be called multiple times.

func (*Server) VirtualHost

func (s *Server) VirtualHost(host string) *router.Router

VirtualHost returns a router (registering it if necessary) used for requests that hit the main port (opts.HTTPAddr) and have the given Host header.

Should be used in rare cases when the server is exposed through multiple domain names and requests should be routed differently based on what domain was used. If your server is serving only one domain name, or you don't care what domain name is used to access it, do not use VirtualHost.

Note that requests that match some registered virtual host router won't reach the default router (server.Routes), even if the virtual host router doesn't have a route for them. Such requests finish with HTTP 404.

Also the router created by VirtualHost is initially completely empty: the server and its modules don't install anything into it (there's intentionally no mechanism to do this). For that reason VirtualHost should never by used to register a router for the "main" domain name: it will make the default server.Routes (and all handlers installed there by server modules) useless, probably breaking the server. Put routes for the main server functionality directly into server.Routes instead, using VirtualHost only for routes that critically depend on Host header.

Should be called before ListenAndServe (panics otherwise).

Source Files

Directories

Path Synopsis
Package analytics provides a standard way to store the Google Analytics tracking ID.
Package analytics provides a standard way to store the Google Analytics tracking ID.
Package auth implements authentication and authorization framework for HTTP servers.
Package auth implements authentication and authorization framework for HTTP servers.
authdb
Package authdb contains definition of Authentication Database (aka AuthDB).
Package authdb contains definition of Authentication Database (aka AuthDB).
authdb/dump
Package dump implements loading AuthDB from dumps in Google Storage.
Package dump implements loading AuthDB from dumps in Google Storage.
authtest
Package authtest implements some interfaces used by auth package to simplify unit testing.
Package authtest implements some interfaces used by auth package to simplify unit testing.
delegation
Package delegation contains low-level API for working with delegation tokens.
Package delegation contains low-level API for working with delegation tokens.
deprecated
Package deprecated contains code that should not be used in new applications.
Package deprecated contains code that should not be used in new applications.
iap
Package iap implements auth.Method for GCP's Identity Aware Proxy.
Package iap implements auth.Method for GCP's Identity Aware Proxy.
openid
Package openid contains functionality related to OpenID Connect protocol.
Package openid contains functionality related to OpenID Connect protocol.
realms
Package realms contains functionality related to LUCI Realms.
Package realms contains functionality related to LUCI Realms.
service
Package service implements a wrapper around API exposed by auth_service: https://github.com/luci/luci-py/tree/master/appengine/auth_service The main focus is AuthDB replication protocol used to propagate changes to database of groups.
Package service implements a wrapper around API exposed by auth_service: https://github.com/luci/luci-py/tree/master/appengine/auth_service The main focus is AuthDB replication protocol used to propagate changes to database of groups.
signing
Package signing provides interfaces to sign arbitrary small blobs with RSA-SHA256 signature (PKCS1v15) and verify such signatures.
Package signing provides interfaces to sign arbitrary small blobs with RSA-SHA256 signature (PKCS1v15) and verify such signatures.
signing/signingtest
Package signingtest implements signing.Signer interface using small random keys.
Package signingtest implements signing.Signer interface using small random keys.
xsrf
Package xsrf provides Cross Site Request Forgery prevention middleware.
Package xsrf provides Cross Site Request Forgery prevention middleware.
Package bqlog implements best effort low-overhead structured logging to BigQuery.
Package bqlog implements best effort low-overhead structured logging to BigQuery.
Package caching implements common server object caches.
Package caching implements common server object caches.
cachingtest
Package cachingtest contains helpers for testing code that uses caching package.
Package cachingtest contains helpers for testing code that uses caching package.
layered
Package layered provides a two-layer cache for serializable objects.
Package layered provides a two-layer cache for serializable objects.
cmd
statsd-to-tsmon
Executable statsd-to-tsmon implements a statsd sink that sends aggregated metrics to tsmon.
Executable statsd-to-tsmon implements a statsd sink that sends aggregated metrics to tsmon.
tink-aead-key
Executable tink-aead-key allows to generate and rotate Tink AES 256 GCM key sets stored in a clear text JSON form in Google Secret Manager.
Executable tink-aead-key allows to generate and rotate Tink AES 256 GCM key sets stored in a clear text JSON form in Google Secret Manager.
tq-sweeper-spanner
Executable tq-sweeper-spanner runs an inproc sweeping driver that scans Spanner database for TQ transactional tasks reminders.
Executable tq-sweeper-spanner runs an inproc sweeping driver that scans Spanner database for TQ transactional tasks reminders.
Package cron allows to register handlers called by Cloud Scheduler.
Package cron allows to register handlers called by Cloud Scheduler.
Package dsmapper implements a simple Datastore mapper.
Package dsmapper implements a simple Datastore mapper.
Package encryptedcookies implements authentication using encrypted cookies.
Package encryptedcookies implements authentication using encrypted cookies.
session
Package session defines API for the session storage.
Package session defines API for the session storage.
session/datastore
Package datastore implements session storage over Cloud Datastore.
Package datastore implements session storage over Cloud Datastore.
Package experiments allow servers to use experimental code paths.
Package experiments allow servers to use experimental code paths.
Package gaeemulation provides a server module that adds implementation of some https://godoc.org/go.chromium.org/luci/gae APIs to the global server context.
Package gaeemulation provides a server module that adds implementation of some https://godoc.org/go.chromium.org/luci/gae APIs to the global server context.
Package limiter implements load shedding for servers.
Package limiter implements load shedding for servers.
Package middleware contains some basic middlewares.
Package middleware contains some basic middlewares.
Package module defines a framework for extending server.Server with optional reusable bundles of functionality (called "modules", naturally).
Package module defines a framework for extending server.Server with optional reusable bundles of functionality (called "modules", naturally).
Package portal implements HTTP routes for portal pages.
Package portal implements HTTP routes for portal pages.
Package pprof is similar to net/http/pprof, except it supports auth.
Package pprof is similar to net/http/pprof, except it supports auth.
Package redisconn implements integration with a Redis connection pool.
Package redisconn implements integration with a Redis connection pool.
adminpb
Package adminpb contains API with Redis-related administrative endpoints.
Package adminpb contains API with Redis-related administrative endpoints.
Package router provides an HTTP router.
Package router provides an HTTP router.
Package secrets provides a secrets store based on Google Secret Manager.
Package secrets provides a secrets store based on Google Secret Manager.
testsecrets
Package testsecrets provides a dumb in-memory secret store to use in unit tests.
Package testsecrets provides a dumb in-memory secret store to use in unit tests.
Package settings implements storage for infrequently changing global settings.
Package settings implements storage for infrequently changing global settings.
Package span implements a server module for communicating with Cloud Spanner.
Package span implements a server module for communicating with Cloud Spanner.
static
Package templates implements wrapper around html/template to provide lazy loading of templates and better integration with HTTP middleware framework.
Package templates implements wrapper around html/template to provide lazy loading of templates and better integration with HTTP middleware framework.
Package tokens provides means to generate and validate base64 encoded tokens compatible with luci-py's components.auth implementation.
Package tokens provides means to generate and validate base64 encoded tokens compatible with luci-py's components.auth implementation.
tq
Package tq provides a task queue implementation on top of Cloud Tasks.
Package tq provides a task queue implementation on top of Cloud Tasks.
tqtesting
Package tqtesting contains helpers for running server/tq in tests and on localhost.
Package tqtesting contains helpers for running server/tq in tests and on localhost.
txn/datastore
Datastore contains Transactional Enqueue support for Cloud Datastore.
Datastore contains Transactional Enqueue support for Cloud Datastore.
txn/spanner
Spanner contains Transactional Enqueue support for Cloud Spanner.
Spanner contains Transactional Enqueue support for Cloud Spanner.
Package tsmon adapts common/tsmon library to a server-side environment.
Package tsmon adapts common/tsmon library to a server-side environment.
Package warmup allows to register hooks executed during the server warmup.
Package warmup allows to register hooks executed during the server warmup.
Package internal is supporting code used by server.go.
Package internal is supporting code used by server.go.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
t or T : Toggle theme light dark auto
y or Y : Canonical URL