blob: bd5c1583ec8a61c717dcfdd8a3c3ebe2009d9070 [file] [log] [blame]
package api
import (
"context"
"encoding/json"
"net/http"
"github.com/go-chi/chi/v5"
"go.opencensus.io/trace"
"go.skia.org/infra/go/alogin"
"go.skia.org/infra/go/httputils"
"go.skia.org/infra/go/roles"
"go.skia.org/infra/go/skerr"
"go.skia.org/infra/go/sklog"
backendClient "go.skia.org/infra/perf/go/backend/client"
"go.skia.org/infra/perf/go/pinpoint"
pinpoint_pb "go.skia.org/infra/pinpoint/proto/v1"
)
// pinpointApi provides a struct for handling Pinpoint requests.
type pinpointApi struct {
loginProvider alogin.Login
pinpointClient *pinpoint.Client
}
// NewPinpointApi returns a new instance of the pinpointApi struct.
func NewPinpointApi(loginProvider alogin.Login, pinpointClient *pinpoint.Client) pinpointApi {
return pinpointApi{
loginProvider: loginProvider,
pinpointClient: pinpointClient,
}
}
// RegisterHandlers registers the api handlers for their respective routes.
func (api pinpointApi) RegisterHandlers(router *chi.Mux) {
router.Post("/_/bisect/create", api.createBisectHandler)
router.Post("/_/try/", api.createTryJobHandler)
router.HandleFunc("/p/", api.pinpointBisectionHandler)
}
// createTryJobHandler takes the POST'd to create a Pinpoint try job request
// then it calls legacy Pinpoint Service to create the job and returns the job id and job url.
func (api pinpointApi) createTryJobHandler(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), defaultDatabaseTimeout)
defer cancel()
w.Header().Set("Content-Type", "application/json")
// TODO(b/404880786): Create a PinpointUser role and deprecate Bisecter.
if !api.loginProvider.HasRole(r, roles.Bisecter) {
http.Error(w, "User is not logged in or is not authorized to start try job.", http.StatusForbidden)
return
}
if api.pinpointClient == nil {
err := skerr.Fmt("Pinpoint client has not been initialized.")
httputils.ReportError(w, err, "Create try job is not enabled for this instance, please check configuration file.", http.StatusInternalServerError)
return
}
var cbr pinpoint.CreateLegacyTryRequest
if err := json.NewDecoder(r.Body).Decode(&cbr); err != nil {
httputils.ReportError(w, err, "Failed to decode JSON.", http.StatusInternalServerError)
return
}
sklog.Debugf("Got request of creating bisect job: %+v", cbr)
resp, err := api.pinpointClient.CreateTryJob(ctx, cbr)
if err != nil {
httputils.ReportError(w, err, "Failed to create try job.", http.StatusInternalServerError)
return
}
if err := json.NewEncoder(w).Encode(resp); err != nil {
sklog.Errorf("Failed to parse the response of creating A/B job: %s", err)
}
}
// createBisectHandler takes the POST'd create bisect request
// then it calls Pinpoint Service API to create bisect job and returns the job id and job url.
func (api pinpointApi) createBisectHandler(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), defaultDatabaseTimeout)
defer cancel()
w.Header().Set("Content-Type", "application/json")
if !api.loginProvider.HasRole(r, roles.Bisecter) {
http.Error(w, "User is not logged in or is not authorized to start bisect.", http.StatusForbidden)
return
}
if api.pinpointClient == nil {
err := skerr.Fmt("Pinpoint client has not been initialized.")
httputils.ReportError(w, err, "Create bisect is not enabled for this instance, please check configuration file.", http.StatusInternalServerError)
return
}
var cbr pinpoint.CreateBisectRequest
if err := json.NewDecoder(r.Body).Decode(&cbr); err != nil {
httputils.ReportError(w, err, "Failed to decode JSON.", http.StatusInternalServerError)
return
}
sklog.Debugf("Got request of creating bisect job: %+v", cbr)
resp, err := api.pinpointClient.CreateBisect(ctx, cbr)
if err != nil {
httputils.ReportError(w, err, "Failed to create bisect job.", http.StatusInternalServerError)
return
}
if err := json.NewEncoder(w).Encode(resp); err != nil {
sklog.Errorf("Failed to parse the response of creating bisect job: %s", err)
}
}
// pinpointBisectionHandler handles a pinpoint bisection request and passes it on to the backend service.
func (api pinpointApi) pinpointBisectionHandler(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), defaultDatabaseTimeout)
defer cancel()
ctx, span := trace.StartSpan(ctx, "schedulePinpointBisectionRequest")
defer span.End()
pinpointClient, err := backendClient.NewPinpointClient("")
if err != nil {
httputils.ReportError(w, err, "Error scheduling bisection.", 500)
}
// TODO(ashwinpv) Get the request data from incoming request.
resp, err := pinpointClient.QueryBisection(ctx, &pinpoint_pb.QueryBisectRequest{})
if err != nil {
httputils.ReportError(w, err, "Error scheduling bisection.", 500)
}
if err := json.NewEncoder(w).Encode(resp); err != nil {
sklog.Errorf("Failed to write or encode output: %s", err)
}
}