go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/cipd/appengine/backend/main.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  // Binary backend implements HTTP server that handles task queues and crons.
    16  package main
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  
    22  	"go.chromium.org/luci/auth/identity"
    23  	"go.chromium.org/luci/common/errors"
    24  	"go.chromium.org/luci/common/logging"
    25  	"go.chromium.org/luci/server"
    26  	"go.chromium.org/luci/server/auth"
    27  	"go.chromium.org/luci/server/auth/openid"
    28  	"go.chromium.org/luci/server/cron"
    29  	"go.chromium.org/luci/server/router"
    30  
    31  	"go.chromium.org/luci/cipd/appengine/impl"
    32  	"go.chromium.org/luci/cipd/appengine/impl/bootstrap"
    33  	"go.chromium.org/luci/cipd/appengine/impl/monitoring"
    34  
    35  	// Using transactional datastore TQ tasks.
    36  	_ "go.chromium.org/luci/server/tq/txn/datastore"
    37  )
    38  
    39  func main() {
    40  	impl.Main(nil, func(srv *server.Server, svc *impl.Services) error {
    41  		// Needed when using manual scaling.
    42  		srv.Routes.GET("/_ah/start", nil, func(ctx *router.Context) {
    43  			_, _ = ctx.Writer.Write([]byte("OK"))
    44  		})
    45  		srv.Routes.GET("/_ah/stop", nil, func(ctx *router.Context) {
    46  			_, _ = ctx.Writer.Write([]byte("OK"))
    47  		})
    48  
    49  		// Periodically refresh the global service config in the datastore.
    50  		cron.RegisterHandler("import-config", func(ctx context.Context) error {
    51  			merr := errors.NewLazyMultiError(2)
    52  			merr.Assign(0, bootstrap.ImportConfig(ctx))
    53  			merr.Assign(1, monitoring.ImportConfig(ctx))
    54  			return merr.Get()
    55  		})
    56  
    57  		// PubSub push handler processing messages produced by events.go.
    58  		oidcMW := router.NewMiddlewareChain(
    59  			auth.Authenticate(&openid.GoogleIDTokenAuthMethod{
    60  				AudienceCheck: openid.AudienceMatchesHost,
    61  			}),
    62  		)
    63  		// bigquery-log-pubsub@ is a part of the PubSub Push subscription config.
    64  		pusherID := identity.Identity(fmt.Sprintf("user:bigquery-log-pubsub@%s.iam.gserviceaccount.com", srv.Options.CloudProject))
    65  		srv.Routes.POST("/internal/pubsub/bigquery-log", oidcMW, func(ctx *router.Context) {
    66  			if got := auth.CurrentIdentity(ctx.Request.Context()); got != pusherID {
    67  				logging.Errorf(ctx.Request.Context(), "Expecting ID token of %q, got %q", pusherID, got)
    68  				ctx.Writer.WriteHeader(403)
    69  			} else {
    70  				err := svc.EventLogger.HandlePubSubPush(ctx.Request.Context(), ctx.Request.Body)
    71  				if err != nil {
    72  					logging.Errorf(ctx.Request.Context(), "Failed to process the message: %s", err)
    73  					ctx.Writer.WriteHeader(500)
    74  				}
    75  			}
    76  		})
    77  
    78  		return nil
    79  	})
    80  }