@Summary Watch workspace agent for container updates. @ID watch-workspace-agent-for-container-updates @Security CoderSessionToken @Produce json @Tags Agents @Param workspaceagent path string true "Workspace agent ID" format(uuid) @Success 200 {object} codersdk.WorkspaceAgentListContainersResponse @R
(rw http.ResponseWriter, r *http.Request)
| 799 | // @Success 200 {object} codersdk.WorkspaceAgentListContainersResponse |
| 800 | // @Router /api/v2/workspaceagents/{workspaceagent}/containers/watch [get] |
| 801 | func (api *API) watchWorkspaceAgentContainers(rw http.ResponseWriter, r *http.Request) { |
| 802 | var ( |
| 803 | ctx = r.Context() |
| 804 | waws = httpmw.WorkspaceAgentAndWorkspaceParam(r) |
| 805 | logger = api.Logger.Named("agent_container_watcher").With(slog.F("agent_id", waws.WorkspaceAgent.ID)) |
| 806 | ) |
| 807 | |
| 808 | // If the agent is unreachable, the request will hang. Assume that if we |
| 809 | // don't get a response after 30s that the agent is unreachable. |
| 810 | dialCtx, dialCancel := context.WithTimeout(ctx, 30*time.Second) |
| 811 | defer dialCancel() |
| 812 | apiAgent, err := db2sdk.WorkspaceAgent( |
| 813 | api.DERPMap(), |
| 814 | *api.TailnetCoordinator.Load(), |
| 815 | waws.WorkspaceAgent, |
| 816 | nil, |
| 817 | nil, |
| 818 | nil, |
| 819 | api.AgentInactiveDisconnectTimeout, |
| 820 | api.DeploymentValues.AgentFallbackTroubleshootingURL.String(), |
| 821 | ) |
| 822 | if err != nil { |
| 823 | httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ |
| 824 | Message: "Internal error reading workspace agent.", |
| 825 | Detail: err.Error(), |
| 826 | }) |
| 827 | return |
| 828 | } |
| 829 | if apiAgent.Status != codersdk.WorkspaceAgentConnected { |
| 830 | httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ |
| 831 | Message: fmt.Sprintf("Agent state is %q, it must be in the %q state.", apiAgent.Status, codersdk.WorkspaceAgentConnected), |
| 832 | }) |
| 833 | return |
| 834 | } |
| 835 | |
| 836 | agentConn, release, err := api.agentProvider.AgentConn(dialCtx, waws.WorkspaceAgent.ID) |
| 837 | if err != nil { |
| 838 | httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ |
| 839 | Message: "Internal error dialing workspace agent.", |
| 840 | Detail: err.Error(), |
| 841 | }) |
| 842 | return |
| 843 | } |
| 844 | defer release() |
| 845 | |
| 846 | containersCh, closer, err := agentConn.WatchContainers(ctx, logger) |
| 847 | if err != nil { |
| 848 | httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ |
| 849 | Message: "Internal error watching agent's containers.", |
| 850 | Detail: err.Error(), |
| 851 | }) |
| 852 | return |
| 853 | } |
| 854 | defer closer.Close() |
| 855 | |
| 856 | conn, err := websocket.Accept(rw, r, nil) |
| 857 | if err != nil { |
| 858 | httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ |
nothing calls this directly
no test coverage detected