160 lines
5.1 KiB
Go
160 lines
5.1 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"github.com/gorilla/mux"
|
|
"github.com/openHPI/poseidon/internal/environment"
|
|
"github.com/openHPI/poseidon/internal/runner"
|
|
"github.com/openHPI/poseidon/pkg/dto"
|
|
"github.com/openHPI/poseidon/pkg/logging"
|
|
"net/http"
|
|
"strconv"
|
|
)
|
|
|
|
const (
|
|
executionEnvironmentIDKey = "executionEnvironmentId"
|
|
fetchEnvironmentKey = "fetch"
|
|
listRouteName = "list"
|
|
getRouteName = "get"
|
|
createOrUpdateRouteName = "createOrUpdate"
|
|
deleteRouteName = "delete"
|
|
)
|
|
|
|
var ErrMissingURLParameter = errors.New("url parameter missing")
|
|
|
|
type EnvironmentController struct {
|
|
manager environment.ManagerHandler
|
|
}
|
|
|
|
type ExecutionEnvironmentsResponse struct {
|
|
ExecutionEnvironments []runner.ExecutionEnvironment `json:"executionEnvironments"`
|
|
}
|
|
|
|
func (e *EnvironmentController) ConfigureRoutes(router *mux.Router) {
|
|
environmentRouter := router.PathPrefix(EnvironmentsPath).Subrouter()
|
|
environmentRouter.HandleFunc("", e.list).Methods(http.MethodGet).Name(listRouteName)
|
|
|
|
specificEnvironmentRouter := environmentRouter.Path(fmt.Sprintf("/{%s:[0-9]+}", executionEnvironmentIDKey)).Subrouter()
|
|
specificEnvironmentRouter.HandleFunc("", e.get).Methods(http.MethodGet).Name(getRouteName)
|
|
specificEnvironmentRouter.HandleFunc("", e.createOrUpdate).Methods(http.MethodPut).Name(createOrUpdateRouteName)
|
|
specificEnvironmentRouter.HandleFunc("", e.delete).Methods(http.MethodDelete).Name(deleteRouteName)
|
|
}
|
|
|
|
// list returns all information about available execution environments.
|
|
func (e *EnvironmentController) list(writer http.ResponseWriter, request *http.Request) {
|
|
fetch, err := parseFetchParameter(request)
|
|
if err != nil {
|
|
writeClientError(writer, err, http.StatusBadRequest, request.Context())
|
|
return
|
|
}
|
|
|
|
environments, err := e.manager.List(fetch)
|
|
if err != nil {
|
|
writeInternalServerError(writer, err, dto.ErrorUnknown, request.Context())
|
|
return
|
|
}
|
|
|
|
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, request.Context())
|
|
return
|
|
}
|
|
fetch, err := parseFetchParameter(request)
|
|
if err != nil {
|
|
writeClientError(writer, err, http.StatusBadRequest, request.Context())
|
|
return
|
|
}
|
|
|
|
executionEnvironment, err := e.manager.Get(environmentID, fetch)
|
|
if errors.Is(err, runner.ErrUnknownExecutionEnvironment) {
|
|
writer.WriteHeader(http.StatusNotFound)
|
|
return
|
|
} else if err != nil {
|
|
writeInternalServerError(writer, err, dto.ErrorUnknown, request.Context())
|
|
return
|
|
}
|
|
|
|
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, request.Context())
|
|
return
|
|
}
|
|
|
|
found, err := e.manager.Delete(environmentID)
|
|
if err != nil {
|
|
writeInternalServerError(writer, err, dto.ErrorUnknown, request.Context())
|
|
return
|
|
} else if !found {
|
|
writer.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
writer.WriteHeader(http.StatusNoContent)
|
|
}
|
|
|
|
// createOrUpdate creates/updates an execution environment on the executor.
|
|
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, request.Context())
|
|
return
|
|
}
|
|
environmentID, err := parseEnvironmentID(request)
|
|
if err != nil {
|
|
writeClientError(writer, err, http.StatusBadRequest, request.Context())
|
|
return
|
|
}
|
|
|
|
var created bool
|
|
logging.StartSpan("api.env.update", "Create Environment", request.Context(), func(ctx context.Context) {
|
|
created, err = e.manager.CreateOrUpdate(environmentID, *req, ctx)
|
|
})
|
|
if err != nil {
|
|
writeInternalServerError(writer, err, dto.ErrorUnknown, request.Context())
|
|
}
|
|
|
|
if created {
|
|
writer.WriteHeader(http.StatusCreated)
|
|
} else {
|
|
writer.WriteHeader(http.StatusNoContent)
|
|
}
|
|
}
|
|
|
|
func parseEnvironmentID(request *http.Request) (dto.EnvironmentID, error) {
|
|
id, ok := mux.Vars(request)[executionEnvironmentIDKey]
|
|
if !ok {
|
|
return 0, fmt.Errorf("could not find %s: %w", executionEnvironmentIDKey, ErrMissingURLParameter)
|
|
}
|
|
environmentID, err := dto.NewEnvironmentID(id)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("could not update environment: %w", err)
|
|
}
|
|
return environmentID, nil
|
|
}
|
|
|
|
func parseFetchParameter(request *http.Request) (fetch bool, err error) {
|
|
fetchString := request.FormValue(fetchEnvironmentKey)
|
|
if fetchString != "" {
|
|
fetch, err = strconv.ParseBool(fetchString)
|
|
if err != nil {
|
|
return false, fmt.Errorf("could not parse fetch parameter: %w", err)
|
|
}
|
|
}
|
|
return fetch, nil
|
|
}
|