Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add context to Sentry Hook #336

Merged
merged 3 commits into from
Apr 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions internal/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func NewRouter(runnerManager runner.Manager, environmentManager environment.Mana
func configureV1Router(router *mux.Router,
runnerManager runner.Manager, environmentManager environment.ManagerHandler) {
router.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.WithField("request", r).Debug("Not Found Handler")
log.WithContext(r.Context()).WithField("request", r).Debug("Not Found Handler")
w.WriteHeader(http.StatusNotFound)
})
v1 := router.PathPrefix(BasePath).Subrouter()
Expand Down Expand Up @@ -75,10 +75,10 @@ func configureV1Router(router *mux.Router,

// Version handles the version route.
// It responds the release information stored in the configuration.
func Version(writer http.ResponseWriter, _ *http.Request) {
func Version(writer http.ResponseWriter, request *http.Request) {
release := config.Config.Sentry.Release
if len(release) > 0 {
sendJSON(writer, release, http.StatusOK)
sendJSON(writer, release, http.StatusOK, request.Context())
} else {
writer.WriteHeader(http.StatusNotFound)
}
Expand All @@ -87,12 +87,12 @@ func Version(writer http.ResponseWriter, _ *http.Request) {
// StatisticsExecutionEnvironments handles the route for statistics about execution environments.
// It responds the prewarming pool size and the number of idle runners and used runners.
func StatisticsExecutionEnvironments(manager environment.Manager) http.HandlerFunc {
return func(writer http.ResponseWriter, _ *http.Request) {
return func(writer http.ResponseWriter, request *http.Request) {
result := make(map[string]*dto.StatisticalExecutionEnvironmentData)
environmentsData := manager.Statistics()
for id, data := range environmentsData {
result[id.ToString()] = data
}
sendJSON(writer, result, http.StatusOK)
sendJSON(writer, result, http.StatusOK, request.Context())
}
}
3 changes: 2 additions & 1 deletion internal/api/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ func HTTPAuthenticationMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get(TokenHeader)
if subtle.ConstantTimeCompare([]byte(token), correctAuthenticationToken) == 0 {
log.WithField("token", logging.RemoveNewlineSymbol(token)).
log.WithContext(r.Context()).
WithField("token", logging.RemoveNewlineSymbol(token)).
Warn("Incorrect token")
w.WriteHeader(http.StatusUnauthorized)
return
Expand Down
24 changes: 12 additions & 12 deletions internal/api/environments.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,30 +47,30 @@ func (e *EnvironmentController) ConfigureRoutes(router *mux.Router) {
func (e *EnvironmentController) list(writer http.ResponseWriter, request *http.Request) {
fetch, err := parseFetchParameter(request)
if err != nil {
writeClientError(writer, err, http.StatusBadRequest)
writeClientError(writer, err, http.StatusBadRequest, request.Context())
return
}

environments, err := e.manager.List(fetch)
if err != nil {
writeInternalServerError(writer, err, dto.ErrorUnknown)
writeInternalServerError(writer, err, dto.ErrorUnknown, request.Context())
return
}

sendJSON(writer, ExecutionEnvironmentsResponse{environments}, http.StatusOK)
sendJSON(writer, ExecutionEnvironmentsResponse{environments}, http.StatusOK, request.Context())
}

// get returns all information about the requested execution environment.
func (e *EnvironmentController) get(writer http.ResponseWriter, request *http.Request) {
environmentID, err := parseEnvironmentID(request)
if err != nil {
// This case is never used as the router validates the id format
writeClientError(writer, err, http.StatusBadRequest)
writeClientError(writer, err, http.StatusBadRequest, request.Context())
return
}
fetch, err := parseFetchParameter(request)
if err != nil {
writeClientError(writer, err, http.StatusBadRequest)
writeClientError(writer, err, http.StatusBadRequest, request.Context())
return
}

Expand All @@ -79,25 +79,25 @@ func (e *EnvironmentController) get(writer http.ResponseWriter, request *http.Re
writer.WriteHeader(http.StatusNotFound)
return
} else if err != nil {
writeInternalServerError(writer, err, dto.ErrorUnknown)
writeInternalServerError(writer, err, dto.ErrorUnknown, request.Context())
return
}

sendJSON(writer, executionEnvironment, http.StatusOK)
sendJSON(writer, executionEnvironment, http.StatusOK, request.Context())
}

// delete removes the specified execution environment.
func (e *EnvironmentController) delete(writer http.ResponseWriter, request *http.Request) {
environmentID, err := parseEnvironmentID(request)
if err != nil {
// This case is never used as the router validates the id format
writeClientError(writer, err, http.StatusBadRequest)
writeClientError(writer, err, http.StatusBadRequest, request.Context())
return
}

found, err := e.manager.Delete(environmentID)
if err != nil {
writeInternalServerError(writer, err, dto.ErrorUnknown)
writeInternalServerError(writer, err, dto.ErrorUnknown, request.Context())
return
} else if !found {
writer.WriteHeader(http.StatusNotFound)
Expand All @@ -111,12 +111,12 @@ func (e *EnvironmentController) delete(writer http.ResponseWriter, request *http
func (e *EnvironmentController) createOrUpdate(writer http.ResponseWriter, request *http.Request) {
req := new(dto.ExecutionEnvironmentRequest)
if err := json.NewDecoder(request.Body).Decode(req); err != nil {
writeClientError(writer, err, http.StatusBadRequest)
writeClientError(writer, err, http.StatusBadRequest, request.Context())
return
}
environmentID, err := parseEnvironmentID(request)
if err != nil {
writeClientError(writer, err, http.StatusBadRequest)
writeClientError(writer, err, http.StatusBadRequest, request.Context())
return
}

Expand All @@ -125,7 +125,7 @@ func (e *EnvironmentController) createOrUpdate(writer http.ResponseWriter, reque
created, err = e.manager.CreateOrUpdate(environmentID, *req, ctx)
})
if err != nil {
writeInternalServerError(writer, err, dto.ErrorUnknown)
writeInternalServerError(writer, err, dto.ErrorUnknown, request.Context())
}

if created {
Expand Down
18 changes: 10 additions & 8 deletions internal/api/helpers.go
Original file line number Diff line number Diff line change
@@ -1,38 +1,40 @@
package api

import (
"context"
"encoding/json"
"fmt"
"github.com/openHPI/poseidon/pkg/dto"
"net/http"
)

func writeInternalServerError(writer http.ResponseWriter, err error, errorCode dto.ErrorCode) {
sendJSON(writer, &dto.InternalServerError{Message: err.Error(), ErrorCode: errorCode}, http.StatusInternalServerError)
func writeInternalServerError(writer http.ResponseWriter, err error, errorCode dto.ErrorCode, ctx context.Context) {
sendJSON(writer, &dto.InternalServerError{Message: err.Error(), ErrorCode: errorCode},
http.StatusInternalServerError, ctx)
}

func writeClientError(writer http.ResponseWriter, err error, status uint16) {
sendJSON(writer, &dto.ClientError{Message: err.Error()}, int(status))
func writeClientError(writer http.ResponseWriter, err error, status uint16, ctx context.Context) {
sendJSON(writer, &dto.ClientError{Message: err.Error()}, int(status), ctx)
}

func sendJSON(writer http.ResponseWriter, content interface{}, httpStatusCode int) {
func sendJSON(writer http.ResponseWriter, content interface{}, httpStatusCode int, ctx context.Context) {
writer.Header().Set("Content-Type", "application/json")
writer.WriteHeader(httpStatusCode)
response, err := json.Marshal(content)
if err != nil {
// cannot produce infinite recursive loop, since json.Marshal of dto.InternalServerError won't return an error
writeInternalServerError(writer, err, dto.ErrorUnknown)
writeInternalServerError(writer, err, dto.ErrorUnknown, ctx)
return
}
if _, err = writer.Write(response); err != nil {
log.WithError(err).Error("Could not write JSON response")
log.WithError(err).WithContext(ctx).Error("Could not write JSON response")
http.Error(writer, err.Error(), http.StatusInternalServerError)
}
}

func parseJSONRequestBody(writer http.ResponseWriter, request *http.Request, structure interface{}) error {
if err := json.NewDecoder(request.Body).Decode(structure); err != nil {
writeClientError(writer, err, http.StatusBadRequest)
writeClientError(writer, err, http.StatusBadRequest, request.Context())
return fmt.Errorf("error parsing JSON request body: %w", err)
}
return nil
Expand Down
46 changes: 24 additions & 22 deletions internal/api/runners.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,20 @@ func (r *RunnerController) provide(writer http.ResponseWriter, request *http.Req
if err != nil {
switch {
case errors.Is(err, runner.ErrUnknownExecutionEnvironment):
writeClientError(writer, err, http.StatusNotFound)
writeClientError(writer, err, http.StatusNotFound, request.Context())
case errors.Is(err, runner.ErrNoRunnersAvailable):
log.WithField("environment", logging.RemoveNewlineSymbol(strconv.Itoa(int(environmentID)))).
log.WithContext(request.Context()).
WithField("environment", logging.RemoveNewlineSymbol(strconv.Itoa(int(environmentID)))).
Warn("No runners available")
writeInternalServerError(writer, err, dto.ErrorNomadOverload)
writeInternalServerError(writer, err, dto.ErrorNomadOverload, request.Context())
default:
writeInternalServerError(writer, err, dto.ErrorUnknown)
writeInternalServerError(writer, err, dto.ErrorUnknown, request.Context())
}
return
}
monitoring.AddRunnerMonitoringData(request, nextRunner.ID(), nextRunner.Environment())
sendJSON(writer, &dto.RunnerResponse{ID: nextRunner.ID(), MappedPorts: nextRunner.MappedPorts()}, http.StatusOK)
sendJSON(writer, &dto.RunnerResponse{ID: nextRunner.ID(), MappedPorts: nextRunner.MappedPorts()},
http.StatusOK, request.Context())
}

// listFileSystem handles the files API route with the method GET.
Expand All @@ -112,11 +114,11 @@ func (r *RunnerController) listFileSystem(writer http.ResponseWriter, request *h
err = targetRunner.ListFileSystem(path, recursive, writer, privilegedExecution, ctx)
})
if errors.Is(err, runner.ErrFileNotFound) {
writeClientError(writer, err, http.StatusFailedDependency)
writeClientError(writer, err, http.StatusFailedDependency, request.Context())
return
} else if err != nil {
log.WithError(err).Error("Could not perform the requested listFileSystem.")
writeInternalServerError(writer, err, dto.ErrorUnknown)
log.WithContext(request.Context()).WithError(err).Error("Could not perform the requested listFileSystem.")
writeInternalServerError(writer, err, dto.ErrorUnknown, request.Context())
return
}
}
Expand All @@ -138,8 +140,8 @@ func (r *RunnerController) updateFileSystem(writer http.ResponseWriter, request
err = targetRunner.UpdateFileSystem(fileCopyRequest, ctx)
})
if err != nil {
log.WithError(err).Error("Could not perform the requested updateFileSystem.")
writeInternalServerError(writer, err, dto.ErrorUnknown)
log.WithContext(request.Context()).WithError(err).Error("Could not perform the requested updateFileSystem.")
writeInternalServerError(writer, err, dto.ErrorUnknown, request.Context())
return
}

Expand All @@ -160,11 +162,11 @@ func (r *RunnerController) fileContent(writer http.ResponseWriter, request *http
err = targetRunner.GetFileContent(path, writer, privilegedExecution, ctx)
})
if errors.Is(err, runner.ErrFileNotFound) {
writeClientError(writer, err, http.StatusFailedDependency)
writeClientError(writer, err, http.StatusFailedDependency, request.Context())
return
} else if err != nil {
log.WithError(err).Error("Could not retrieve the requested file.")
writeInternalServerError(writer, err, dto.ErrorUnknown)
log.WithContext(request.Context()).WithError(err).Error("Could not retrieve the requested file.")
writeInternalServerError(writer, err, dto.ErrorUnknown, request.Context())
return
}
}
Expand All @@ -179,7 +181,7 @@ func (r *RunnerController) execute(writer http.ResponseWriter, request *http.Req
}
forbiddenCharacters := "'"
if strings.ContainsAny(executionRequest.Command, forbiddenCharacters) {
writeClientError(writer, ErrForbiddenCharacter, http.StatusBadRequest)
writeClientError(writer, ErrForbiddenCharacter, http.StatusBadRequest, request.Context())
return
}

Expand All @@ -194,14 +196,14 @@ func (r *RunnerController) execute(writer http.ResponseWriter, request *http.Req

path, err := r.runnerRouter.Get(WebsocketPath).URL(RunnerIDKey, targetRunner.ID())
if err != nil {
log.WithError(err).Error("Could not create runner websocket URL.")
writeInternalServerError(writer, err, dto.ErrorUnknown)
log.WithContext(request.Context()).WithError(err).Error("Could not create runner websocket URL.")
writeInternalServerError(writer, err, dto.ErrorUnknown, request.Context())
return
}
newUUID, err := uuid.NewRandom()
if err != nil {
log.WithError(err).Error("Could not create execution id")
writeInternalServerError(writer, err, dto.ErrorUnknown)
log.WithContext(request.Context()).WithError(err).Error("Could not create execution id")
writeInternalServerError(writer, err, dto.ErrorUnknown, request.Context())
return
}
id := newUUID.String()
Expand All @@ -216,7 +218,7 @@ func (r *RunnerController) execute(writer http.ResponseWriter, request *http.Req
RawQuery: fmt.Sprintf("%s=%s", ExecutionIDKey, id),
}

sendJSON(writer, &dto.ExecutionResponse{WebSocketURL: webSocketURL.String()}, http.StatusOK)
sendJSON(writer, &dto.ExecutionResponse{WebSocketURL: webSocketURL.String()}, http.StatusOK, request.Context())
}

// The findRunnerMiddleware looks up the runnerId for routes containing it
Expand All @@ -230,9 +232,9 @@ func (r *RunnerController) findRunnerMiddleware(next http.Handler) http.Handler
// See https://github.com/openHPI/poseidon/issues/54
_, readErr := io.ReadAll(request.Body)
if readErr != nil {
log.WithError(readErr).Warn("Failed to discard the request body")
log.WithContext(request.Context()).WithError(readErr).Warn("Failed to discard the request body")
}
writeClientError(writer, err, http.StatusGone)
writeClientError(writer, err, http.StatusGone, request.Context())
return
}
ctx := runner.NewContext(request.Context(), targetRunner)
Expand All @@ -252,7 +254,7 @@ func (r *RunnerController) delete(writer http.ResponseWriter, request *http.Requ
err = r.manager.Return(targetRunner)
})
if err != nil {
writeInternalServerError(writer, err, dto.ErrorNomadInternalServerError)
writeInternalServerError(writer, err, dto.ErrorNomadInternalServerError, request.Context())
return
}

Expand Down
Loading