| 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) |
| } |
| } |