blob: 2e5a638393b971841a0785d424a441f1c31251d1 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package main
import (
"context"
"net/http"
authServer "go.chromium.org/luci/appengine/gaeauth/server"
"go.chromium.org/luci/appengine/gaemiddleware"
"go.chromium.org/luci/appengine/gaemiddleware/standard"
"go.chromium.org/luci/common/logging"
"go.chromium.org/luci/common/sync/parallel"
"go.chromium.org/luci/config/appengine/gaeconfig"
"go.chromium.org/luci/config/impl/filesystem"
"go.chromium.org/luci/config/impl/remote"
"go.chromium.org/luci/grpc/discovery"
"go.chromium.org/luci/server/auth"
"go.chromium.org/luci/server/router"
"google.golang.org/appengine"
admin "infra/tricium/api/admin/v1"
"infra/tricium/appengine/common"
"infra/tricium/appengine/common/config"
)
func init() {
r := router.New()
base := common.MiddlewareForInternal()
// Tracker: handlers that perform actions while updating datastore.
r.POST("/tracker/internal/worker-done", base, workerDoneHandler)
r.POST("/tracker/internal/worker-launched", base, workerLaunchedHandler)
r.POST("/tracker/internal/workflow-launched", base, workflowLaunchedHandler)
r.GET("/tracker/internal/cron/bqlog/flush", base.Extend(gaemiddleware.RequireCron), bqFlushHandler)
// Driver: handlers that trigger and collect tasks.
r.POST("/driver/internal/trigger", base, triggerHandler)
r.POST("/driver/internal/collect", base, collectHandler)
// Devserver can't accept PubSub pushes, use manual PubSub pulls instead in development.
if appengine.IsDevAppServer() {
r.GET("/driver/internal/pull", base, pubsubPullHandler)
} else {
r.POST("/_ah/push-handlers/notify", base, pubsubPushHandler)
}
// Gerrit: handlers that interact with Gerrit.
r.GET("/gerrit/internal/poll", base, pollHandler)
r.POST("/gerrit/internal/poll-project", base, pollProjectHandler)
r.POST("/gerrit/internal/report-results", base, reportResultsHandler)
// Launcher: Handlers that initiate Tricium workflows.
r.POST("/launcher/internal/launch", base, launchHandler)
// Configure pRPC services.
s := common.NewRPCServer()
admin.RegisterTrackerServer(s, &trackerServer{})
admin.RegisterDriverServer(s, &driverServer{})
admin.RegisterReporterServer(s, &gerritReporterServer{})
admin.RegisterLauncherServer(s, &launcherServer{})
discovery.Enable(s)
s.InstallHandlers(r, common.MiddlewareForRPC())
// Configure config update cron job handler.
configMiddleware := withRemoteConfigService
if appengine.IsDevAppServer() {
// For the dev appserver, always we use configs from the local filesystem.
configMiddleware = withFilesystemConfigService
}
configUpdateMiddleware := standard.Base().Extend(
auth.Authenticate(authServer.CookieAuth),
configMiddleware,
gaemiddleware.RequireCron)
r.GET("/config/update", configUpdateMiddleware, UpdateHandler)
http.DefaultServeMux.Handle("/", r)
}
// withRemoteConfigService changes the context c to use configs from luci-config.
func withRemoteConfigService(c *router.Context, next router.Handler) {
s, err := gaeconfig.FetchCachedSettings(c.Context)
if err != nil {
c.Writer.WriteHeader(http.StatusInternalServerError)
logging.WithError(err).Errorf(c.Context, "Failed to retrieve cached settings")
return
}
iface := remote.New(s.ConfigServiceHost, false, func(c context.Context) (*http.Client, error) {
t, err := auth.GetRPCTransport(c, auth.AsSelf)
if err != nil {
return nil, err
}
return &http.Client{Transport: t}, nil
})
c.Context = config.WithConfigService(c.Context, iface)
next(c)
}
// withFilesystemConfigService changes the context c to use local configs.
func withFilesystemConfigService(c *router.Context, next router.Handler) {
iface, err := filesystem.New("../devcfg")
if err != nil {
c.Writer.WriteHeader(http.StatusInternalServerError)
logging.WithError(err).Errorf(c.Context, "Failed to load local config files.")
return
}
c.Context = config.WithConfigService(c.Context, iface)
next(c)
}
func bqFlushHandler(c *router.Context) {
// Flush all BigQuery rows; rows for separate tables can be flushed
// in parallel.
err := parallel.FanOutIn(func(ch chan<- func() error) {
ch <- func() error {
_, err := common.ResultsLog.Flush(c.Context)
return err
}
ch <- func() error {
_, err := common.EventsLog.Flush(c.Context)
return err
}
})
if err != nil {
http.Error(c.Writer, err.Error(), http.StatusInternalServerError)
return
}
c.Writer.WriteHeader(http.StatusOK)
}