github.com/filecoin-project/bacalhau@v0.3.23-0.20230228154132-45c989550ace/pkg/requester/publicapi/endpoints_submit.go (about) 1 package publicapi 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 8 "github.com/filecoin-project/bacalhau/pkg/bacerrors" 9 "github.com/filecoin-project/bacalhau/pkg/job" 10 "github.com/filecoin-project/bacalhau/pkg/model" 11 "github.com/filecoin-project/bacalhau/pkg/publicapi/handlerwrapper" 12 "github.com/filecoin-project/bacalhau/pkg/system" 13 "github.com/rs/zerolog/log" 14 oteltrace "go.opentelemetry.io/otel/trace" 15 ) 16 17 type submitRequest struct { 18 // The data needed to submit and run a job on the network: 19 JobCreatePayload *json.RawMessage `json:"job_create_payload" validate:"required"` 20 21 // A base64-encoded signature of the data, signed by the client: 22 ClientSignature string `json:"signature" validate:"required"` 23 24 // The base64-encoded public key of the client: 25 ClientPublicKey string `json:"client_public_key" validate:"required"` 26 } 27 28 type submitResponse struct { 29 Job *model.Job `json:"job"` 30 } 31 32 // submit godoc 33 // 34 // @ID pkg/requester/publicapi/submit 35 // @Summary Submits a new job to the network. 36 // @Description.markdown endpoints_submit 37 // @Tags Job 38 // @Accept json 39 // @Produce json 40 // @Param submitRequest body submitRequest true " " 41 // @Success 200 {object} submitResponse 42 // @Failure 400 {object} string 43 // @Failure 500 {object} string 44 // @Router /requester/submit [post] 45 func (s *RequesterAPIServer) submit(res http.ResponseWriter, req *http.Request) { 46 ctx := req.Context() 47 if otherJobID := req.Header.Get("X-Bacalhau-Job-ID"); otherJobID != "" { 48 err := fmt.Errorf("rejecting job because HTTP header X-Bacalhau-Job-ID was set") 49 log.Ctx(ctx).Info().Str("X-Bacalhau-Job-ID", otherJobID).Err(err).Send() 50 http.Error(res, bacerrors.ErrorToErrorResponse(err), http.StatusBadRequest) 51 return 52 } 53 54 var submitReq submitRequest 55 if err := json.NewDecoder(req.Body).Decode(&submitReq); err != nil { 56 log.Ctx(ctx).Debug().Msgf("====> Decode submitReq error: %s", err) 57 http.Error(res, bacerrors.ErrorToErrorResponse(err), http.StatusBadRequest) 58 return 59 } 60 61 // first verify the signature on the raw bytes 62 if err := verifyRequestSignature(*submitReq.JobCreatePayload, submitReq.ClientSignature, submitReq.ClientPublicKey); err != nil { 63 log.Ctx(ctx).Debug().Msgf("====> VerifyRequestSignature error: %s", err) 64 errorResponse := bacerrors.ErrorToErrorResponse(err) 65 http.Error(res, errorResponse, http.StatusBadRequest) 66 return 67 } 68 69 // then decode the job create payload 70 var jobCreatePayload model.JobCreatePayload 71 if err := json.Unmarshal(*submitReq.JobCreatePayload, &jobCreatePayload); err != nil { 72 log.Ctx(ctx).Debug().Msgf("====> Decode JobCreatePayload error: %s", err) 73 http.Error(res, bacerrors.ErrorToErrorResponse(err), http.StatusBadRequest) 74 return 75 } 76 res.Header().Set(handlerwrapper.HTTPHeaderClientID, jobCreatePayload.ClientID) 77 78 if err := verifySignedJobRequest(jobCreatePayload.ClientID, submitReq.ClientSignature, submitReq.ClientPublicKey); err != nil { 79 log.Ctx(ctx).Debug().Msgf("====> verifySignedJobRequest error: %s", err) 80 errorResponse := bacerrors.ErrorToErrorResponse(err) 81 http.Error(res, errorResponse, http.StatusBadRequest) 82 return 83 } 84 85 if err := job.VerifyJobCreatePayload(ctx, &jobCreatePayload); err != nil { 86 log.Ctx(ctx).Debug().Msgf("====> VerifyJobCreate error: %s", err) 87 errorResponse := bacerrors.ErrorToErrorResponse(err) 88 http.Error(res, errorResponse, http.StatusBadRequest) 89 return 90 } 91 92 j, err := s.requester.SubmitJob( 93 ctx, 94 jobCreatePayload, 95 ) 96 res.Header().Set(handlerwrapper.HTTPHeaderJobID, j.Metadata.ID) 97 ctx = system.AddJobIDToBaggage(ctx, j.Metadata.ID) 98 system.AddJobIDFromBaggageToSpan(ctx, oteltrace.SpanFromContext(ctx)) 99 100 if err != nil { 101 http.Error(res, err.Error(), http.StatusInternalServerError) 102 return 103 } 104 105 res.WriteHeader(http.StatusOK) 106 err = json.NewEncoder(res).Encode(submitResponse{ 107 Job: j, 108 }) 109 if err != nil { 110 http.Error(res, bacerrors.ErrorToErrorResponse(err), http.StatusInternalServerError) 111 return 112 } 113 }