mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add API support for workspace automatic updates (#10099)
* Added automatic_updates to workspaces table Signed-off-by: Spike Curtis <spike@coder.com> * Queries and API updates Signed-off-by: Spike Curtis <spike@coder.com> * Golden files Signed-off-by: Spike Curtis <spike@coder.com> * Enable automatic updates on autostart Signed-off-by: Spike Curtis <spike@coder.com> * db migration number Signed-off-by: Spike Curtis <spike@coder.com> * fix imports and ts mock Signed-off-by: Spike Curtis <spike@coder.com> * code review updates Signed-off-by: Spike Curtis <spike@coder.com> --------- Signed-off-by: Spike Curtis <spike@coder.com>
This commit is contained in:
+87
-1
@@ -425,6 +425,19 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
|
||||
return
|
||||
}
|
||||
|
||||
// back-compatibility: default to "never" if not included.
|
||||
dbAU := database.AutomaticUpdatesNever
|
||||
if createWorkspace.AutomaticUpdates != "" {
|
||||
dbAU, err = validWorkspaceAutomaticUpdates(createWorkspace.AutomaticUpdates)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Invalid Workspace Automatic Updates setting.",
|
||||
Validations: []codersdk.ValidationError{{Field: "automatic_updates", Detail: err.Error()}},
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This should be a system call as the actor might not be able to
|
||||
// read other workspaces. Ideally we check the error on create and look for
|
||||
// a postgres conflict error.
|
||||
@@ -470,7 +483,8 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
|
||||
Ttl: dbTTL,
|
||||
// The workspaces page will sort by last used at, and it's useful to
|
||||
// have the newly created workspace at the top of the list!
|
||||
LastUsedAt: dbtime.Now(),
|
||||
LastUsedAt: dbtime.Now(),
|
||||
AutomaticUpdates: dbAU,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("insert workspace: %w", err)
|
||||
@@ -977,6 +991,66 @@ func (api *API) putExtendWorkspace(rw http.ResponseWriter, r *http.Request) {
|
||||
httpapi.Write(ctx, rw, code, resp)
|
||||
}
|
||||
|
||||
// @Summary Update workspace automatic updates by ID
|
||||
// @ID update-workspace-automatic-updates-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Tags Workspaces
|
||||
// @Param workspace path string true "Workspace ID" format(uuid)
|
||||
// @Param request body codersdk.UpdateWorkspaceAutomaticUpdatesRequest true "Automatic updates request"
|
||||
// @Success 204
|
||||
// @Router /workspaces/{workspace}/autoupdates [put]
|
||||
func (api *API) putWorkspaceAutoupdates(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
workspace = httpmw.WorkspaceParam(r)
|
||||
auditor = api.Auditor.Load()
|
||||
aReq, commitAudit = audit.InitRequest[database.Workspace](rw, &audit.RequestParams{
|
||||
Audit: *auditor,
|
||||
Log: api.Logger,
|
||||
Request: r,
|
||||
Action: database.AuditActionWrite,
|
||||
})
|
||||
)
|
||||
defer commitAudit()
|
||||
aReq.Old = workspace
|
||||
|
||||
var req codersdk.UpdateWorkspaceAutomaticUpdatesRequest
|
||||
if !httpapi.Read(ctx, rw, r, &req) {
|
||||
return
|
||||
}
|
||||
|
||||
if !database.AutomaticUpdates(req.AutomaticUpdates).Valid() {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Invalid request",
|
||||
Validations: []codersdk.ValidationError{{Field: "automatic_updates", Detail: "must be always or never"}},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err := api.Database.UpdateWorkspaceAutomaticUpdates(ctx, database.UpdateWorkspaceAutomaticUpdatesParams{
|
||||
ID: workspace.ID,
|
||||
AutomaticUpdates: database.AutomaticUpdates(req.AutomaticUpdates),
|
||||
})
|
||||
if httpapi.Is404Error(err) {
|
||||
httpapi.ResourceNotFound(rw)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error updating workspace automatic updates setting",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
newWorkspace := workspace
|
||||
newWorkspace.AutomaticUpdates = database.AutomaticUpdates(req.AutomaticUpdates)
|
||||
aReq.New = newWorkspace
|
||||
|
||||
rw.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// @Summary Watch workspace by ID
|
||||
// @ID watch-workspace-by-id
|
||||
// @Security CoderSessionToken
|
||||
@@ -1256,6 +1330,7 @@ func convertWorkspace(
|
||||
Healthy: len(failingAgents) == 0,
|
||||
FailingAgents: failingAgents,
|
||||
},
|
||||
AutomaticUpdates: codersdk.AutomaticUpdates(workspace.AutomaticUpdates),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1311,6 +1386,17 @@ func validWorkspaceTTLMillis(millis *int64, templateDefault, templateMax time.Du
|
||||
}, nil
|
||||
}
|
||||
|
||||
func validWorkspaceAutomaticUpdates(updates codersdk.AutomaticUpdates) (database.AutomaticUpdates, error) {
|
||||
if updates == "" {
|
||||
return database.AutomaticUpdatesNever, nil
|
||||
}
|
||||
dbAU := database.AutomaticUpdates(updates)
|
||||
if !dbAU.Valid() {
|
||||
return "", xerrors.New("Automatic updates must be always or never")
|
||||
}
|
||||
return dbAU, nil
|
||||
}
|
||||
|
||||
func validWorkspaceDeadline(startedAt, newDeadline time.Time) error {
|
||||
soon := time.Now().Add(29 * time.Minute)
|
||||
if newDeadline.Before(soon) {
|
||||
|
||||
Reference in New Issue
Block a user