mirror of
https://github.com/coder/coder.git
synced 2025-07-15 22:20:27 +00:00
feat: show devcontainer dirty status and allow recreate (#17880)
Updates #16424
This commit is contained in:
committed by
GitHub
parent
c775ea8411
commit
98e2ec4417
@ -15,6 +15,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sqlc-dev/pqtype"
|
||||
"golang.org/x/exp/maps"
|
||||
@ -893,6 +894,91 @@ func (api *API) workspaceAgentListContainers(rw http.ResponseWriter, r *http.Req
|
||||
httpapi.Write(ctx, rw, http.StatusOK, cts)
|
||||
}
|
||||
|
||||
// @Summary Recreate devcontainer for workspace agent
|
||||
// @ID recreate-devcontainer-for-workspace-agent
|
||||
// @Security CoderSessionToken
|
||||
// @Tags Agents
|
||||
// @Param workspaceagent path string true "Workspace agent ID" format(uuid)
|
||||
// @Param container path string true "Container ID or name"
|
||||
// @Success 204
|
||||
// @Router /workspaceagents/{workspaceagent}/containers/devcontainers/container/{container}/recreate [post]
|
||||
func (api *API) workspaceAgentRecreateDevcontainer(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
workspaceAgent := httpmw.WorkspaceAgentParam(r)
|
||||
|
||||
container := chi.URLParam(r, "container")
|
||||
if container == "" {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Container ID or name is required.",
|
||||
Validations: []codersdk.ValidationError{
|
||||
{Field: "container", Detail: "Container ID or name is required."},
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
apiAgent, err := db2sdk.WorkspaceAgent(
|
||||
api.DERPMap(),
|
||||
*api.TailnetCoordinator.Load(),
|
||||
workspaceAgent,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
api.AgentInactiveDisconnectTimeout,
|
||||
api.DeploymentValues.AgentFallbackTroubleshootingURL.String(),
|
||||
)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error reading workspace agent.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
if apiAgent.Status != codersdk.WorkspaceAgentConnected {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: fmt.Sprintf("Agent state is %q, it must be in the %q state.", apiAgent.Status, codersdk.WorkspaceAgentConnected),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// If the agent is unreachable, the request will hang. Assume that if we
|
||||
// don't get a response after 30s that the agent is unreachable.
|
||||
dialCtx, dialCancel := context.WithTimeout(ctx, 30*time.Second)
|
||||
defer dialCancel()
|
||||
agentConn, release, err := api.agentProvider.AgentConn(dialCtx, workspaceAgent.ID)
|
||||
if err != nil {
|
||||
httpapi.Write(dialCtx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error dialing workspace agent.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
defer release()
|
||||
|
||||
err = agentConn.RecreateDevcontainer(ctx, container)
|
||||
if err != nil {
|
||||
if errors.Is(err, context.Canceled) {
|
||||
httpapi.Write(ctx, rw, http.StatusRequestTimeout, codersdk.Response{
|
||||
Message: "Failed to recreate devcontainer from agent.",
|
||||
Detail: "Request timed out.",
|
||||
})
|
||||
return
|
||||
}
|
||||
// If the agent returns a codersdk.Error, we can return that directly.
|
||||
if cerr, ok := codersdk.AsError(err); ok {
|
||||
httpapi.Write(ctx, rw, cerr.StatusCode(), cerr.Response)
|
||||
return
|
||||
}
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error recreating devcontainer.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
// @Summary Get connection info for workspace agent
|
||||
// @ID get-connection-info-for-workspace-agent
|
||||
// @Security CoderSessionToken
|
||||
|
Reference in New Issue
Block a user