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  }