fix(agent/agentcontainers): reset error at start of rebuild (#18686)

Reset the error associated with a devcontainer when a rebuild is requested.
This commit is contained in:
Danielle Maywood
2025-07-01 10:57:43 +01:00
committed by GitHub
parent 258a839d27
commit 7e372f7a35
2 changed files with 24 additions and 8 deletions

View File

@ -946,6 +946,7 @@ func (api *API) handleDevcontainerRecreate(w http.ResponseWriter, r *http.Reques
// devcontainer multiple times in parallel. // devcontainer multiple times in parallel.
dc.Status = codersdk.WorkspaceAgentDevcontainerStatusStarting dc.Status = codersdk.WorkspaceAgentDevcontainerStatusStarting
dc.Container = nil dc.Container = nil
dc.Error = ""
api.knownDevcontainers[dc.WorkspaceFolder] = dc api.knownDevcontainers[dc.WorkspaceFolder] = dc
go func() { go func() {
_ = api.CreateDevcontainer(dc.WorkspaceFolder, dc.ConfigPath, WithRemoveExistingContainer()) _ = api.CreateDevcontainer(dc.WorkspaceFolder, dc.ConfigPath, WithRemoveExistingContainer())

View File

@ -69,7 +69,7 @@ func (f *fakeContainerCLI) ExecAs(ctx context.Context, name, user string, args .
type fakeDevcontainerCLI struct { type fakeDevcontainerCLI struct {
upID string upID string
upErr error upErr error
upErrC chan error // If set, send to return err, close to return upErr. upErrC chan func() error // If set, send to return err, close to return upErr.
execErr error execErr error
execErrC chan func(cmd string, args ...string) error // If set, send fn to return err, nil or close to return execErr. execErrC chan func(cmd string, args ...string) error // If set, send fn to return err, nil or close to return execErr.
readConfig agentcontainers.DevcontainerConfig readConfig agentcontainers.DevcontainerConfig
@ -82,9 +82,9 @@ func (f *fakeDevcontainerCLI) Up(ctx context.Context, _, _ string, _ ...agentcon
select { select {
case <-ctx.Done(): case <-ctx.Done():
return "", ctx.Err() return "", ctx.Err()
case err, ok := <-f.upErrC: case fn, ok := <-f.upErrC:
if ok { if ok {
return f.upID, err return f.upID, fn()
} }
} }
} }
@ -613,7 +613,7 @@ func TestAPI(t *testing.T) {
nowRecreateErrorTrap := mClock.Trap().Now("recreate", "errorTimes") nowRecreateErrorTrap := mClock.Trap().Now("recreate", "errorTimes")
nowRecreateSuccessTrap := mClock.Trap().Now("recreate", "successTimes") nowRecreateSuccessTrap := mClock.Trap().Now("recreate", "successTimes")
tt.devcontainerCLI.upErrC = make(chan error) tt.devcontainerCLI.upErrC = make(chan func() error)
// Setup router with the handler under test. // Setup router with the handler under test.
r := chi.NewRouter() r := chi.NewRouter()
@ -1665,7 +1665,7 @@ func TestAPI(t *testing.T) {
mClock = quartz.NewMock(t) mClock = quartz.NewMock(t)
fCCLI = &fakeContainerCLI{arch: "<none>"} fCCLI = &fakeContainerCLI{arch: "<none>"}
fDCCLI = &fakeDevcontainerCLI{ fDCCLI = &fakeDevcontainerCLI{
upErrC: make(chan error, 1), upErrC: make(chan func() error, 1),
} }
fSAC = &fakeSubAgentClient{ fSAC = &fakeSubAgentClient{
logger: logger.Named("fakeSubAgentClient"), logger: logger.Named("fakeSubAgentClient"),
@ -1717,7 +1717,7 @@ func TestAPI(t *testing.T) {
// Given: We simulate an error running `devcontainer up` // Given: We simulate an error running `devcontainer up`
simulatedError := xerrors.New("simulated error") simulatedError := xerrors.New("simulated error")
testutil.RequireSend(ctx, t, fDCCLI.upErrC, simulatedError) testutil.RequireSend(ctx, t, fDCCLI.upErrC, func() error { return simulatedError })
nowRecreateErrorTrap.MustWait(ctx).MustRelease(ctx) nowRecreateErrorTrap.MustWait(ctx).MustRelease(ctx)
nowRecreateErrorTrap.Close() nowRecreateErrorTrap.Close()
@ -1742,7 +1742,22 @@ func TestAPI(t *testing.T) {
require.Equal(t, http.StatusAccepted, rec.Code) require.Equal(t, http.StatusAccepted, rec.Code)
// Given: We allow `devcontainer up` to succeed. // Given: We allow `devcontainer up` to succeed.
testutil.RequireSend(ctx, t, fDCCLI.upErrC, nil) testutil.RequireSend(ctx, t, fDCCLI.upErrC, func() error {
req = httptest.NewRequest(http.MethodGet, "/", nil)
rec = httptest.NewRecorder()
r.ServeHTTP(rec, req)
require.Equal(t, http.StatusOK, rec.Code)
response = codersdk.WorkspaceAgentListContainersResponse{}
err = json.NewDecoder(rec.Body).Decode(&response)
require.NoError(t, err)
// Then: We make sure that the error has been cleared before running up.
require.Len(t, response.Devcontainers, 1)
require.Equal(t, "", response.Devcontainers[0].Error)
return nil
})
nowRecreateSuccessTrap.MustWait(ctx).MustRelease(ctx) nowRecreateSuccessTrap.MustWait(ctx).MustRelease(ctx)
nowRecreateSuccessTrap.Close() nowRecreateSuccessTrap.Close()
@ -1756,7 +1771,7 @@ func TestAPI(t *testing.T) {
err = json.NewDecoder(rec.Body).Decode(&response) err = json.NewDecoder(rec.Body).Decode(&response)
require.NoError(t, err) require.NoError(t, err)
// Then: We expect that there will be no error associated with the devcontainer. // Then: We also expect no error after running up..
require.Len(t, response.Devcontainers, 1) require.Len(t, response.Devcontainers, 1)
require.Equal(t, "", response.Devcontainers[0].Error) require.Equal(t, "", response.Devcontainers[0].Error)
}) })