go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/appengine/gaemiddleware/standard/env.go (about)

     1  // Copyright 2017 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package standard exposes a gaemiddleware Environment for Classic AppEngine.
    16  package standard
    17  
    18  import (
    19  	"context"
    20  	"net/http"
    21  	"strings"
    22  
    23  	"google.golang.org/appengine"
    24  
    25  	"go.chromium.org/luci/common/tsmon/monitor"
    26  	"go.chromium.org/luci/common/tsmon/target"
    27  	"go.chromium.org/luci/config/appengine/gaeconfig"
    28  	"go.chromium.org/luci/config/validation"
    29  	"go.chromium.org/luci/server/auth"
    30  	"go.chromium.org/luci/server/auth/authdb"
    31  	"go.chromium.org/luci/server/middleware"
    32  	"go.chromium.org/luci/server/portal"
    33  	"go.chromium.org/luci/server/pprof"
    34  	"go.chromium.org/luci/server/router"
    35  	"go.chromium.org/luci/server/tsmon"
    36  
    37  	"go.chromium.org/luci/appengine/gaeauth/client"
    38  	gaeauth "go.chromium.org/luci/appengine/gaeauth/server"
    39  	"go.chromium.org/luci/appengine/gaeauth/server/gaesigner"
    40  	"go.chromium.org/luci/appengine/gaemiddleware"
    41  	gaetsmon "go.chromium.org/luci/appengine/tsmon"
    42  
    43  	"go.chromium.org/luci/gae/impl/prod"
    44  	"go.chromium.org/luci/gae/service/info"
    45  )
    46  
    47  var (
    48  	// globalAuthConfig is configuration of the server/auth library.
    49  	//
    50  	// It specifies concrete GAE-based implementations for various interfaces
    51  	// used by the library.
    52  	//
    53  	// It is indirectly stateful (since NewDBCache returns a stateful object that
    54  	// keeps AuthDB cache in local memory), and thus it's defined as a long living
    55  	// global variable.
    56  	//
    57  	// Used in prod contexts only.
    58  	globalAuthConfig = auth.Config{
    59  		DBProvider:          authdb.NewDBCache(gaeauth.GetAuthDB),
    60  		Signer:              gaesigner.Signer{},
    61  		AccessTokenProvider: client.GetAccessToken,
    62  		AnonymousTransport: func(ctx context.Context) http.RoundTripper {
    63  			return &contextAwareURLFetch{ctx}
    64  		},
    65  		FrontendClientID: gaeauth.FetchFrontendClientID,
    66  		IsDevMode:        appengine.IsDevAppServer(),
    67  	}
    68  
    69  	// globalTsMonState holds configuration and state related to time series
    70  	// monitoring.
    71  	globalTsMonState = &tsmon.State{
    72  		CustomMonitor: tsmonDebugMonitor(),
    73  		Target: func(ctx context.Context) target.Task {
    74  			return target.Task{
    75  				DataCenter:  "appengine",
    76  				ServiceName: info.AppID(ctx),
    77  				JobName:     info.ModuleName(ctx),
    78  				HostName:    strings.SplitN(info.VersionID(ctx), ".", 2)[0],
    79  			}
    80  		},
    81  		InstanceID:        info.InstanceID,
    82  		TaskNumAllocator:  gaetsmon.DatastoreTaskNumAllocator{},
    83  		FlushInMiddleware: true,
    84  	}
    85  )
    86  
    87  // tsmonDebugMonitor returns debug monitor when running on dev server.
    88  func tsmonDebugMonitor() monitor.Monitor {
    89  	if appengine.IsDevAppServer() {
    90  		return monitor.NewDebugMonitor("")
    91  	}
    92  	return nil
    93  }
    94  
    95  // classicEnv is an AppEngine Classic GAE environment configuration. This is the
    96  // default AppEngine environment for simple (all-classic) layouts.
    97  var classicEnv = gaemiddleware.Environment{
    98  	MemcacheAvailable:  true,
    99  	WithInitialRequest: prod.Use,
   100  	WithConfig:         gaeconfig.Use,
   101  	WithAuth: func(ctx context.Context) context.Context {
   102  		return auth.Initialize(ctx, &globalAuthConfig)
   103  	},
   104  
   105  	ExtraMiddleware: func() router.MiddlewareChain {
   106  		mw := make([]router.Middleware, 0, 2)
   107  		if !appengine.IsDevAppServer() {
   108  			mw = append(mw, middleware.WithPanicCatcher)
   109  		}
   110  		mw = append(mw, globalTsMonState.Middleware)
   111  		return router.NewMiddlewareChain(mw...)
   112  	}(),
   113  
   114  	ExtraHandlers: func(r *router.Router, base router.MiddlewareChain) {
   115  		gaeauth.InstallHandlers(r, base)
   116  		gaetsmon.InstallHandlers(r, base)
   117  		portal.InstallHandlers(r, base, &gaeauth.UsersAPIAuthMethod{})
   118  		gaeconfig.InstallValidationHandlers(r, base, &validation.Rules)
   119  		pprof.InstallHandlers(r, base)
   120  	},
   121  }
   122  
   123  // With adds various production GAE LUCI services to the context.
   124  //
   125  // Basically, it installs GAE-specific backends and caches for various
   126  // subsystems to make them work in GAE environment.
   127  //
   128  // One example is a backend for Logging: go.chromium.org/luci/common/logging.
   129  // Logs emitted through a With() context go to GAE logs.
   130  //
   131  // 'Production' here means the services will use real GAE APIs (not mocks or
   132  // stubs), so With should never be used from unit tests.
   133  func With(ctx context.Context, req *http.Request) context.Context {
   134  	return classicEnv.With(ctx, req)
   135  }
   136  
   137  // Base returns a middleware chain to use for all GAE requests.
   138  //
   139  // This middleware chain installs prod GAE services into the request context
   140  // (via With), and wraps the request with a panic catcher and monitoring
   141  // hooks.
   142  func Base() router.MiddlewareChain { return classicEnv.Base() }
   143  
   144  // InstallHandlers installs handlers for framework routes using classic
   145  // production services' default middleware.
   146  //
   147  // See InstallHandlersWithMiddleware for more information.
   148  func InstallHandlers(r *router.Router) { classicEnv.InstallHandlers(r) }
   149  
   150  // InstallHandlersWithMiddleware installs handlers for framework routes using
   151  // classic production services.
   152  //
   153  // These routes are needed for various services provided in Base context to
   154  // work:
   155  //   - Authentication related routes (gaeauth)
   156  //   - Settings pages (gaesettings)
   157  //   - Various housekeeping crons (tsmon, gaeconfig)
   158  //   - Warmup (warmup)
   159  //
   160  // They must be installed into a default module, but it is also safe to
   161  // install them into a non-default module. This may be handy if you want to
   162  // move cron handlers into a non-default module.
   163  //
   164  // 'base' is expected to be an Environment's Base() or its derivative. It must
   165  // NOT do any interception of requests (e.g. checking and rejecting
   166  // unauthenticated requests).
   167  func InstallHandlersWithMiddleware(r *router.Router, base router.MiddlewareChain) {
   168  	classicEnv.InstallHandlersWithMiddleware(r, base)
   169  }