mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: trace httpapi.{Read,Write} (#4134)
This commit is contained in:
@@ -91,6 +91,7 @@ func UseLoginURL(loginURL *url.URL) func(http.Handler) http.Handler {
|
||||
func ExtractAPIKey(db database.Store, oauth *OAuth2Configs, redirectToLogin bool) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
// Write wraps writing a response to redirect if the handler
|
||||
// specified it should. This redirect is used for user-facing
|
||||
// pages like workspace applications.
|
||||
@@ -127,7 +128,7 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs, redirectToLogin bool
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(rw, code, response)
|
||||
httpapi.Write(ctx, rw, code, response)
|
||||
}
|
||||
|
||||
cookieValue := apiTokenFromRequest(r)
|
||||
@@ -329,7 +330,6 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs, redirectToLogin bool
|
||||
return
|
||||
}
|
||||
|
||||
ctx := r.Context()
|
||||
ctx = context.WithValue(ctx, apiKeyContextKey{}, key)
|
||||
ctx = context.WithValue(ctx, userAuthKey{}, Authorization{
|
||||
ID: key.UserID,
|
||||
|
||||
@@ -34,7 +34,7 @@ func TestAPIKey(t *testing.T) {
|
||||
|
||||
successHandler := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
// Only called if the API key passes through the handler.
|
||||
httpapi.Write(rw, http.StatusOK, codersdk.Response{
|
||||
httpapi.Write(context.Background(), rw, http.StatusOK, codersdk.Response{
|
||||
Message: "It worked!",
|
||||
})
|
||||
})
|
||||
@@ -205,7 +205,7 @@ func TestAPIKey(t *testing.T) {
|
||||
httpmw.ExtractAPIKey(db, nil, false)(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
// Checks that it exists on the context!
|
||||
_ = httpmw.APIKey(r)
|
||||
httpapi.Write(rw, http.StatusOK, codersdk.Response{
|
||||
httpapi.Write(r.Context(), rw, http.StatusOK, codersdk.Response{
|
||||
Message: "It worked!",
|
||||
})
|
||||
})).ServeHTTP(rw, r)
|
||||
@@ -249,7 +249,7 @@ func TestAPIKey(t *testing.T) {
|
||||
apiKey := httpmw.APIKey(r)
|
||||
assert.Equal(t, database.APIKeyScopeApplicationConnect, apiKey.Scope)
|
||||
|
||||
httpapi.Write(rw, http.StatusOK, codersdk.Response{
|
||||
httpapi.Write(r.Context(), rw, http.StatusOK, codersdk.Response{
|
||||
Message: "it worked!",
|
||||
})
|
||||
})).ServeHTTP(rw, r)
|
||||
@@ -285,7 +285,7 @@ func TestAPIKey(t *testing.T) {
|
||||
httpmw.ExtractAPIKey(db, nil, false)(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
// Checks that it exists on the context!
|
||||
_ = httpmw.APIKey(r)
|
||||
httpapi.Write(rw, http.StatusOK, codersdk.Response{
|
||||
httpapi.Write(r.Context(), rw, http.StatusOK, codersdk.Response{
|
||||
Message: "It worked!",
|
||||
})
|
||||
})).ServeHTTP(rw, r)
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
func parseUUID(rw http.ResponseWriter, r *http.Request, param string) (uuid.UUID, bool) {
|
||||
rawID := chi.URLParam(r, param)
|
||||
if rawID == "" {
|
||||
httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
|
||||
httpapi.Write(r.Context(), rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Missing UUID in URL.",
|
||||
// Url params mean nothing to a user
|
||||
Detail: fmt.Sprintf("%q URL param missing", param),
|
||||
@@ -25,7 +25,7 @@ func parseUUID(rw http.ResponseWriter, r *http.Request, param string) (uuid.UUID
|
||||
|
||||
parsed, err := uuid.Parse(rawID)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
|
||||
httpapi.Write(r.Context(), rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: fmt.Sprintf("Invalid UUID %q.", param),
|
||||
Detail: err.Error(),
|
||||
})
|
||||
|
||||
@@ -43,9 +43,10 @@ func OAuth2(r *http.Request) OAuth2State {
|
||||
func ExtractOAuth2(config OAuth2Config) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
// Interfaces can hold a nil value
|
||||
if config == nil || reflect.ValueOf(config).IsNil() {
|
||||
httpapi.Write(rw, http.StatusPreconditionRequired, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusPreconditionRequired, codersdk.Response{
|
||||
Message: "The oauth2 method requested is not configured!",
|
||||
})
|
||||
return
|
||||
@@ -58,7 +59,7 @@ func ExtractOAuth2(config OAuth2Config) func(http.Handler) http.Handler {
|
||||
// If the code isn't provided, we'll redirect!
|
||||
state, err := cryptorand.String(32)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error generating state string.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
@@ -87,7 +88,7 @@ func ExtractOAuth2(config OAuth2Config) func(http.Handler) http.Handler {
|
||||
}
|
||||
|
||||
if state == "" {
|
||||
httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "State must be provided.",
|
||||
})
|
||||
return
|
||||
@@ -95,13 +96,13 @@ func ExtractOAuth2(config OAuth2Config) func(http.Handler) http.Handler {
|
||||
|
||||
stateCookie, err := r.Cookie(codersdk.OAuth2StateKey)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusUnauthorized, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusUnauthorized, codersdk.Response{
|
||||
Message: fmt.Sprintf("Cookie %q must be provided.", codersdk.OAuth2StateKey),
|
||||
})
|
||||
return
|
||||
}
|
||||
if stateCookie.Value != state {
|
||||
httpapi.Write(rw, http.StatusUnauthorized, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusUnauthorized, codersdk.Response{
|
||||
Message: "State mismatched.",
|
||||
})
|
||||
return
|
||||
@@ -113,16 +114,16 @@ func ExtractOAuth2(config OAuth2Config) func(http.Handler) http.Handler {
|
||||
redirect = stateRedirect.Value
|
||||
}
|
||||
|
||||
oauthToken, err := config.Exchange(r.Context(), code)
|
||||
oauthToken, err := config.Exchange(ctx, code)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error exchanging Oauth code.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), oauth2StateKey{}, OAuth2State{
|
||||
ctx = context.WithValue(ctx, oauth2StateKey{}, OAuth2State{
|
||||
Token: oauthToken,
|
||||
Redirect: redirect,
|
||||
})
|
||||
|
||||
@@ -38,24 +38,25 @@ func OrganizationMemberParam(r *http.Request) database.OrganizationMember {
|
||||
func ExtractOrganizationParam(db database.Store) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
orgID, ok := parseUUID(rw, r, "organization")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
organization, err := db.GetOrganizationByID(r.Context(), orgID)
|
||||
organization, err := db.GetOrganizationByID(ctx, orgID)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
httpapi.ResourceNotFound(rw)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching organization.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
ctx := context.WithValue(r.Context(), organizationParamContextKey{}, organization)
|
||||
ctx = context.WithValue(ctx, organizationParamContextKey{}, organization)
|
||||
next.ServeHTTP(rw, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
@@ -66,10 +67,11 @@ func ExtractOrganizationParam(db database.Store) func(http.Handler) http.Handler
|
||||
func ExtractOrganizationMemberParam(db database.Store) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
organization := OrganizationParam(r)
|
||||
user := UserParam(r)
|
||||
|
||||
organizationMember, err := db.GetOrganizationMemberByUserID(r.Context(), database.GetOrganizationMemberByUserIDParams{
|
||||
organizationMember, err := db.GetOrganizationMemberByUserID(ctx, database.GetOrganizationMemberByUserIDParams{
|
||||
OrganizationID: organization.ID,
|
||||
UserID: user.ID,
|
||||
})
|
||||
@@ -78,14 +80,14 @@ func ExtractOrganizationMemberParam(db database.Store) func(http.Handler) http.H
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching organization member.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
ctx := context.WithValue(r.Context(), organizationMemberParamContextKey{}, organizationMember)
|
||||
|
||||
ctx = context.WithValue(ctx, organizationMemberParamContextKey{}, organizationMember)
|
||||
next.ServeHTTP(rw, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ func RateLimitPerMinute(count int) func(http.Handler) http.Handler {
|
||||
return httprate.KeyByIP(r)
|
||||
}, httprate.KeyByEndpoint),
|
||||
httprate.WithLimitHandler(func(w http.ResponseWriter, r *http.Request) {
|
||||
httpapi.Write(w, http.StatusTooManyRequests, codersdk.Response{
|
||||
httpapi.Write(r.Context(), w, http.StatusTooManyRequests, codersdk.Response{
|
||||
Message: "You've been rate limited for sending too many requests!",
|
||||
})
|
||||
}),
|
||||
|
||||
@@ -24,11 +24,12 @@ func RequestID(r *http.Request) uuid.UUID {
|
||||
func AttachRequestID(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
rid := uuid.New()
|
||||
ridString := rid.String()
|
||||
|
||||
ctx := context.WithValue(r.Context(), requestIDContextKey{}, rid)
|
||||
ctx = slog.With(ctx, slog.F("request_id", rid))
|
||||
|
||||
rw.Header().Set("X-Coder-Request-Id", rid.String())
|
||||
rw.Header().Set("X-Coder-Request-Id", ridString)
|
||||
next.ServeHTTP(rw, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ func TemplateParam(r *http.Request) database.Template {
|
||||
func ExtractTemplateParam(db database.Store) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
templateID, parsed := parseUUID(rw, r, "template")
|
||||
if !parsed {
|
||||
return
|
||||
@@ -38,14 +39,14 @@ func ExtractTemplateParam(db database.Store) func(http.Handler) http.Handler {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching template.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), templateParamContextKey{}, template)
|
||||
ctx = context.WithValue(ctx, templateParamContextKey{}, template)
|
||||
chi.RouteContext(ctx).URLParams.Add("organization", template.OrganizationID.String())
|
||||
next.ServeHTTP(rw, r.WithContext(ctx))
|
||||
})
|
||||
|
||||
@@ -28,24 +28,25 @@ func TemplateVersionParam(r *http.Request) database.TemplateVersion {
|
||||
func ExtractTemplateVersionParam(db database.Store) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
templateVersionID, parsed := parseUUID(rw, r, "templateversion")
|
||||
if !parsed {
|
||||
return
|
||||
}
|
||||
templateVersion, err := db.GetTemplateVersionByID(r.Context(), templateVersionID)
|
||||
templateVersion, err := db.GetTemplateVersionByID(ctx, templateVersionID)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
httpapi.ResourceNotFound(rw)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching template version.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), templateVersionParamContextKey{}, templateVersion)
|
||||
ctx = context.WithValue(ctx, templateVersionParamContextKey{}, templateVersion)
|
||||
chi.RouteContext(ctx).URLParams.Add("organization", templateVersion.OrganizationID.String())
|
||||
next.ServeHTTP(rw, r.WithContext(ctx))
|
||||
})
|
||||
|
||||
+13
-10
@@ -37,26 +37,29 @@ func UserParam(r *http.Request) database.User {
|
||||
func ExtractUserParam(db database.Store) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
var user database.User
|
||||
var err error
|
||||
var (
|
||||
ctx = r.Context()
|
||||
user database.User
|
||||
err error
|
||||
)
|
||||
|
||||
// userQuery is either a uuid, a username, or 'me'
|
||||
userQuery := chi.URLParam(r, "user")
|
||||
if userQuery == "" {
|
||||
httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "\"user\" must be provided.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if userQuery == "me" {
|
||||
user, err = db.GetUserByID(r.Context(), APIKey(r).UserID)
|
||||
user, err = db.GetUserByID(ctx, APIKey(r).UserID)
|
||||
if xerrors.Is(err, sql.ErrNoRows) {
|
||||
httpapi.ResourceNotFound(rw)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching user.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
@@ -64,27 +67,27 @@ func ExtractUserParam(db database.Store) func(http.Handler) http.Handler {
|
||||
}
|
||||
} else if userID, err := uuid.Parse(userQuery); err == nil {
|
||||
// If the userQuery is a valid uuid
|
||||
user, err = db.GetUserByID(r.Context(), userID)
|
||||
user, err = db.GetUserByID(ctx, userID)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: userErrorMessage,
|
||||
})
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// Try as a username last
|
||||
user, err = db.GetUserByEmailOrUsername(r.Context(), database.GetUserByEmailOrUsernameParams{
|
||||
user, err = db.GetUserByEmailOrUsername(ctx, database.GetUserByEmailOrUsernameParams{
|
||||
Username: userQuery,
|
||||
})
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: userErrorMessage,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), userParamContextKey{}, user)
|
||||
ctx = context.WithValue(ctx, userParamContextKey{}, user)
|
||||
next.ServeHTTP(rw, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -29,37 +29,38 @@ func WorkspaceAgent(r *http.Request) database.WorkspaceAgent {
|
||||
func ExtractWorkspaceAgent(db database.Store) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
cookieValue := apiTokenFromRequest(r)
|
||||
if cookieValue == "" {
|
||||
httpapi.Write(rw, http.StatusUnauthorized, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusUnauthorized, codersdk.Response{
|
||||
Message: fmt.Sprintf("Cookie %q must be provided.", codersdk.SessionTokenKey),
|
||||
})
|
||||
return
|
||||
}
|
||||
token, err := uuid.Parse(cookieValue)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusUnauthorized, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusUnauthorized, codersdk.Response{
|
||||
Message: "Agent token is invalid.",
|
||||
})
|
||||
return
|
||||
}
|
||||
agent, err := db.GetWorkspaceAgentByAuthToken(r.Context(), token)
|
||||
agent, err := db.GetWorkspaceAgentByAuthToken(ctx, token)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
httpapi.Write(rw, http.StatusUnauthorized, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusUnauthorized, codersdk.Response{
|
||||
Message: "Agent token is invalid.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching workspace agent.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), workspaceAgentContextKey{}, agent)
|
||||
ctx = context.WithValue(ctx, workspaceAgentContextKey{}, agent)
|
||||
next.ServeHTTP(rw, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -28,59 +28,60 @@ func WorkspaceAgentParam(r *http.Request) database.WorkspaceAgent {
|
||||
func ExtractWorkspaceAgentParam(db database.Store) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
agentUUID, parsed := parseUUID(rw, r, "workspaceagent")
|
||||
if !parsed {
|
||||
return
|
||||
}
|
||||
|
||||
agent, err := db.GetWorkspaceAgentByID(r.Context(), agentUUID)
|
||||
agent, err := db.GetWorkspaceAgentByID(ctx, agentUUID)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
httpapi.Write(rw, http.StatusNotFound, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{
|
||||
Message: "Agent doesn't exist with that id.",
|
||||
})
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching workspace agent.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
resource, err := db.GetWorkspaceResourceByID(r.Context(), agent.ResourceID)
|
||||
resource, err := db.GetWorkspaceResourceByID(ctx, agent.ResourceID)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching workspace resource.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
job, err := db.GetProvisionerJobByID(r.Context(), resource.JobID)
|
||||
job, err := db.GetProvisionerJobByID(ctx, resource.JobID)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching provisioner job.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
if job.Type != database.ProvisionerJobTypeWorkspaceBuild {
|
||||
httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Workspace agents can only be fetched for builds.",
|
||||
})
|
||||
return
|
||||
}
|
||||
build, err := db.GetWorkspaceBuildByJobID(r.Context(), job.ID)
|
||||
build, err := db.GetWorkspaceBuildByJobID(ctx, job.ID)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching workspace build.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), workspaceAgentParamContextKey{}, agent)
|
||||
ctx = context.WithValue(ctx, workspaceAgentParamContextKey{}, agent)
|
||||
chi.RouteContext(ctx).URLParams.Add("workspace", build.WorkspaceID.String())
|
||||
next.ServeHTTP(rw, r.WithContext(ctx))
|
||||
})
|
||||
|
||||
@@ -28,24 +28,25 @@ func WorkspaceBuildParam(r *http.Request) database.WorkspaceBuild {
|
||||
func ExtractWorkspaceBuildParam(db database.Store) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
workspaceBuildID, parsed := parseUUID(rw, r, "workspacebuild")
|
||||
if !parsed {
|
||||
return
|
||||
}
|
||||
workspaceBuild, err := db.GetWorkspaceBuildByID(r.Context(), workspaceBuildID)
|
||||
workspaceBuild, err := db.GetWorkspaceBuildByID(ctx, workspaceBuildID)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
httpapi.ResourceNotFound(rw)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching workspace build.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), workspaceBuildParamContextKey{}, workspaceBuild)
|
||||
ctx = context.WithValue(ctx, workspaceBuildParamContextKey{}, workspaceBuild)
|
||||
// This injects the "workspace" parameter, because it's expected the consumer
|
||||
// will want to use the Workspace middleware to ensure the caller owns the workspace.
|
||||
chi.RouteContext(ctx).URLParams.Add("workspace", workspaceBuild.WorkspaceID.String())
|
||||
|
||||
@@ -31,24 +31,25 @@ func WorkspaceParam(r *http.Request) database.Workspace {
|
||||
func ExtractWorkspaceParam(db database.Store) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
workspaceID, parsed := parseUUID(rw, r, "workspace")
|
||||
if !parsed {
|
||||
return
|
||||
}
|
||||
workspace, err := db.GetWorkspaceByID(r.Context(), workspaceID)
|
||||
workspace, err := db.GetWorkspaceByID(ctx, workspaceID)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
httpapi.ResourceNotFound(rw)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching workspace.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), workspaceParamContextKey{}, workspace)
|
||||
ctx = context.WithValue(ctx, workspaceParamContextKey{}, workspace)
|
||||
next.ServeHTTP(rw, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
@@ -63,11 +64,12 @@ func ExtractWorkspaceParam(db database.Store) func(http.Handler) http.Handler {
|
||||
func ExtractWorkspaceAndAgentParam(db database.Store) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
user := UserParam(r)
|
||||
workspaceWithAgent := chi.URLParam(r, "workspace_and_agent")
|
||||
workspaceParts := strings.Split(workspaceWithAgent, ".")
|
||||
|
||||
workspace, err := db.GetWorkspaceByOwnerIDAndName(r.Context(), database.GetWorkspaceByOwnerIDAndNameParams{
|
||||
workspace, err := db.GetWorkspaceByOwnerIDAndName(ctx, database.GetWorkspaceByOwnerIDAndNameParams{
|
||||
OwnerID: user.ID,
|
||||
Name: workspaceParts[0],
|
||||
})
|
||||
@@ -76,25 +78,25 @@ func ExtractWorkspaceAndAgentParam(db database.Store) func(http.Handler) http.Ha
|
||||
httpapi.ResourceNotFound(rw)
|
||||
return
|
||||
}
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching workspace.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
build, err := db.GetLatestWorkspaceBuildByWorkspaceID(r.Context(), workspace.ID)
|
||||
build, err := db.GetLatestWorkspaceBuildByWorkspaceID(ctx, workspace.ID)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching workspace build.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
resources, err := db.GetWorkspaceResourcesByJobID(r.Context(), build.JobID)
|
||||
resources, err := db.GetWorkspaceResourcesByJobID(ctx, build.JobID)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching workspace resources.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
@@ -105,9 +107,9 @@ func ExtractWorkspaceAndAgentParam(db database.Store) func(http.Handler) http.Ha
|
||||
resourceIDs = append(resourceIDs, resource.ID)
|
||||
}
|
||||
|
||||
agents, err := db.GetWorkspaceAgentsByResourceIDs(r.Context(), resourceIDs)
|
||||
agents, err := db.GetWorkspaceAgentsByResourceIDs(ctx, resourceIDs)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching workspace agents.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
@@ -115,7 +117,7 @@ func ExtractWorkspaceAndAgentParam(db database.Store) func(http.Handler) http.Ha
|
||||
}
|
||||
|
||||
if len(agents) == 0 {
|
||||
httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "No agents exist for this workspace",
|
||||
})
|
||||
return
|
||||
@@ -123,7 +125,7 @@ func ExtractWorkspaceAndAgentParam(db database.Store) func(http.Handler) http.Ha
|
||||
|
||||
// If we have more than 1 workspace agent, we need to specify which one to use.
|
||||
if len(agents) > 1 && len(workspaceParts) <= 1 {
|
||||
httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "More than one agent exists, but no agent specified.",
|
||||
})
|
||||
return
|
||||
@@ -143,7 +145,7 @@ func ExtractWorkspaceAndAgentParam(db database.Store) func(http.Handler) http.Ha
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: fmt.Sprintf("No agent exists with the name %q", workspaceParts[1]),
|
||||
})
|
||||
return
|
||||
@@ -152,7 +154,6 @@ func ExtractWorkspaceAndAgentParam(db database.Store) func(http.Handler) http.Ha
|
||||
agent = agents[0]
|
||||
}
|
||||
|
||||
ctx := r.Context()
|
||||
ctx = context.WithValue(ctx, workspaceParamContextKey{}, workspace)
|
||||
ctx = context.WithValue(ctx, workspaceAgentParamContextKey{}, agent)
|
||||
next.ServeHTTP(rw, r.WithContext(ctx))
|
||||
|
||||
@@ -28,49 +28,50 @@ func WorkspaceResourceParam(r *http.Request) database.WorkspaceResource {
|
||||
func ExtractWorkspaceResourceParam(db database.Store) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
resourceUUID, parsed := parseUUID(rw, r, "workspaceresource")
|
||||
if !parsed {
|
||||
return
|
||||
}
|
||||
resource, err := db.GetWorkspaceResourceByID(r.Context(), resourceUUID)
|
||||
resource, err := db.GetWorkspaceResourceByID(ctx, resourceUUID)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
httpapi.Write(rw, http.StatusNotFound, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{
|
||||
Message: "Resource doesn't exist with that id.",
|
||||
})
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching provisioner resource.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
job, err := db.GetProvisionerJobByID(r.Context(), resource.JobID)
|
||||
job, err := db.GetProvisionerJobByID(ctx, resource.JobID)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error provisioner job.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
if job.Type != database.ProvisionerJobTypeWorkspaceBuild {
|
||||
httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Workspace resources can only be fetched for builds.",
|
||||
})
|
||||
return
|
||||
}
|
||||
build, err := db.GetWorkspaceBuildByJobID(r.Context(), job.ID)
|
||||
build, err := db.GetWorkspaceBuildByJobID(ctx, job.ID)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error workspace build.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), workspaceResourceParamContextKey{}, resource)
|
||||
ctx = context.WithValue(ctx, workspaceResourceParamContextKey{}, resource)
|
||||
ctx = context.WithValue(ctx, workspaceBuildParamContextKey{}, build)
|
||||
chi.RouteContext(ctx).URLParams.Add("workspace", build.WorkspaceID.String())
|
||||
next.ServeHTTP(rw, r.WithContext(ctx))
|
||||
|
||||
Reference in New Issue
Block a user