Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite57c101

Browse files
authored
feat: add support package and accompanying tests (#12289)
1 parent2bf3c72 commite57c101

File tree

3 files changed

+409
-0
lines changed

3 files changed

+409
-0
lines changed

‎codersdk/health.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@ type UpdateHealthSettings struct {
4444
DismissedHealthchecks []HealthSection`json:"dismissed_healthchecks"`
4545
}
4646

47+
func (c*Client)DebugHealth(ctx context.Context) (HealthcheckReport,error) {
48+
res,err:=c.Request(ctx,http.MethodGet,"/api/v2/debug/health",nil)
49+
iferr!=nil {
50+
returnHealthcheckReport{},err
51+
}
52+
deferres.Body.Close()
53+
ifres.StatusCode!=http.StatusOK {
54+
returnHealthcheckReport{},ReadBodyAsError(res)
55+
}
56+
varrptHealthcheckReport
57+
returnrpt,json.NewDecoder(res.Body).Decode(&rpt)
58+
}
59+
4760
func (c*Client)HealthSettings(ctx context.Context) (HealthSettings,error) {
4861
res,err:=c.Request(ctx,http.MethodGet,"/api/v2/debug/health/settings",nil)
4962
iferr!=nil {

‎support/support.go

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
package support
2+
3+
import (
4+
"context"
5+
"io"
6+
"net/http"
7+
"strings"
8+
9+
"golang.org/x/xerrors"
10+
11+
"github.com/google/uuid"
12+
13+
"cdr.dev/slog"
14+
"cdr.dev/slog/sloggers/sloghuman"
15+
"github.com/coder/coder/v2/coderd/rbac"
16+
"github.com/coder/coder/v2/codersdk"
17+
)
18+
19+
// Bundle is a set of information discovered about a deployment.
20+
// Even though we do attempt to sanitize data, it may still contain
21+
// sensitive information and should thus be treated as secret.
22+
typeBundlestruct {
23+
DeploymentDeployment`json:"deployment"`
24+
NetworkNetwork`json:"network"`
25+
WorkspaceWorkspace`json:"workspace"`
26+
Logs []string`json:"logs"`
27+
}
28+
29+
typeDeploymentstruct {
30+
BuildInfo*codersdk.BuildInfoResponse`json:"build"`
31+
Config*codersdk.DeploymentConfig`json:"config"`
32+
Experiments codersdk.Experiments`json:"experiments"`
33+
HealthReport*codersdk.HealthcheckReport`json:"health_report"`
34+
}
35+
36+
typeNetworkstruct {
37+
CoordinatorDebugstring`json:"coordinator_debug"`
38+
TailnetDebugstring`json:"tailnet_debug"`
39+
NetcheckLocal*codersdk.WorkspaceAgentConnectionInfo`json:"netcheck_local"`
40+
NetcheckRemote*codersdk.WorkspaceAgentConnectionInfo`json:"netcheck_remote"`
41+
}
42+
43+
typeWorkspacestruct {
44+
Workspace codersdk.Workspace`json:"workspace"`
45+
BuildLogs []codersdk.ProvisionerJobLog`json:"build_logs"`
46+
Agent codersdk.WorkspaceAgent`json:"agent"`
47+
AgentStartupLogs []codersdk.WorkspaceAgentLog`json:"startup_logs"`
48+
}
49+
50+
// Deps is a set of dependencies for discovering information
51+
typeDepsstruct {
52+
// Source from which to obtain information.
53+
Client*codersdk.Client
54+
// Log is where to log any informational or warning messages.
55+
Log slog.Logger
56+
// WorkspaceID is the optional workspace against which to run connection tests.
57+
WorkspaceID uuid.UUID
58+
// AgentID is the optional agent ID against which to run connection tests.
59+
// Defaults to the first agent of the workspace, if not specified.
60+
AgentID uuid.UUID
61+
}
62+
63+
funcDeploymentInfo(ctx context.Context,client*codersdk.Client,log slog.Logger)Deployment {
64+
vardDeployment
65+
66+
bi,err:=client.BuildInfo(ctx)
67+
iferr!=nil {
68+
log.Error(ctx,"fetch build info",slog.Error(err))
69+
}else {
70+
d.BuildInfo=&bi
71+
}
72+
73+
dc,err:=client.DeploymentConfig(ctx)
74+
iferr!=nil {
75+
log.Error(ctx,"fetch deployment config",slog.Error(err))
76+
}else {
77+
d.Config=dc
78+
}
79+
80+
hr,err:=client.DebugHealth(ctx)
81+
iferr!=nil {
82+
log.Error(ctx,"fetch health report",slog.Error(err))
83+
}else {
84+
d.HealthReport=&hr
85+
}
86+
87+
exp,err:=client.Experiments(ctx)
88+
iferr!=nil {
89+
log.Error(ctx,"fetch experiments",slog.Error(err))
90+
}else {
91+
d.Experiments=exp
92+
}
93+
94+
returnd
95+
}
96+
97+
funcNetworkInfo(ctx context.Context,client*codersdk.Client,log slog.Logger,agentID uuid.UUID)Network {
98+
varnNetwork
99+
100+
coordResp,err:=client.Request(ctx,http.MethodGet,"/api/v2/debug/coordinator",nil)
101+
iferr!=nil {
102+
log.Error(ctx,"fetch coordinator debug page",slog.Error(err))
103+
}else {
104+
defercoordResp.Body.Close()
105+
bs,err:=io.ReadAll(coordResp.Body)
106+
iferr!=nil {
107+
log.Error(ctx,"read coordinator debug page",slog.Error(err))
108+
}else {
109+
n.CoordinatorDebug=string(bs)
110+
}
111+
}
112+
113+
tailResp,err:=client.Request(ctx,http.MethodGet,"/api/v2/debug/tailnet",nil)
114+
iferr!=nil {
115+
log.Error(ctx,"fetch tailnet debug page",slog.Error(err))
116+
}else {
117+
defertailResp.Body.Close()
118+
bs,err:=io.ReadAll(tailResp.Body)
119+
iferr!=nil {
120+
log.Error(ctx,"read tailnet debug page",slog.Error(err))
121+
}else {
122+
n.TailnetDebug=string(bs)
123+
}
124+
}
125+
126+
ifagentID!=uuid.Nil {
127+
connInfo,err:=client.WorkspaceAgentConnectionInfo(ctx,agentID)
128+
iferr!=nil {
129+
log.Error(ctx,"fetch agent conn info",slog.Error(err),slog.F("agent_id",agentID.String()))
130+
}else {
131+
n.NetcheckLocal=&connInfo
132+
}
133+
}else {
134+
log.Warn(ctx,"agent id required for agent connection info")
135+
}
136+
137+
returnn
138+
}
139+
140+
funcWorkspaceInfo(ctx context.Context,client*codersdk.Client,log slog.Logger,workspaceID,agentID uuid.UUID)Workspace {
141+
varwWorkspace
142+
143+
ifworkspaceID==uuid.Nil {
144+
log.Error(ctx,"no workspace id specified")
145+
returnw
146+
}
147+
148+
ifagentID==uuid.Nil {
149+
log.Error(ctx,"no agent id specified")
150+
}
151+
152+
ws,err:=client.Workspace(ctx,workspaceID)
153+
iferr!=nil {
154+
log.Error(ctx,"fetch workspace",slog.Error(err),slog.F("workspace_id",workspaceID))
155+
returnw
156+
}
157+
158+
w.Workspace=ws
159+
160+
buildLogCh,closer,err:=client.WorkspaceBuildLogsAfter(ctx,ws.LatestBuild.ID,0)
161+
iferr!=nil {
162+
log.Error(ctx,"fetch provisioner job logs",slog.Error(err),slog.F("job_id",ws.LatestBuild.Job.ID.String()))
163+
}else {
164+
defercloser.Close()
165+
forlog:=rangebuildLogCh {
166+
w.BuildLogs=append(w.BuildLogs,log)
167+
}
168+
}
169+
170+
iflen(w.Workspace.LatestBuild.Resources)==0 {
171+
log.Warn(ctx,"workspace build has no resources")
172+
returnw
173+
}
174+
175+
agentLogCh,closer,err:=client.WorkspaceAgentLogsAfter(ctx,agentID,0,false)
176+
iferr!=nil {
177+
log.Error(ctx,"fetch agent startup logs",slog.Error(err),slog.F("agent_id",agentID.String()))
178+
}else {
179+
defercloser.Close()
180+
forlogChunk:=rangeagentLogCh {
181+
w.AgentStartupLogs=append(w.AgentStartupLogs,logChunk...)
182+
}
183+
}
184+
185+
returnw
186+
}
187+
188+
// Run generates a support bundle with the given dependencies.
189+
funcRun(ctx context.Context,d*Deps) (*Bundle,error) {
190+
varbBundle
191+
ifd.Client==nil {
192+
returnnil,xerrors.Errorf("developer error: missing client!")
193+
}
194+
195+
authChecks:=map[string]codersdk.AuthorizationCheck{
196+
"Read DeploymentValues": {
197+
Object: codersdk.AuthorizationObject{
198+
ResourceType:codersdk.ResourceDeploymentValues,
199+
},
200+
Action:string(rbac.ActionRead),
201+
},
202+
}
203+
204+
// Ensure we capture logs from the client.
205+
varlogw strings.Builder
206+
d.Log.AppendSinks(sloghuman.Sink(&logw))
207+
d.Client.SetLogger(d.Log)
208+
deferfunc() {
209+
b.Logs=strings.Split(logw.String(),"\n")
210+
}()
211+
212+
authResp,err:=d.Client.AuthCheck(ctx, codersdk.AuthorizationRequest{Checks:authChecks})
213+
iferr!=nil {
214+
return&b,xerrors.Errorf("check authorization: %w",err)
215+
}
216+
fork,v:=rangeauthResp {
217+
if!v {
218+
return&b,xerrors.Errorf("failed authorization check: cannot %s",k)
219+
}
220+
}
221+
222+
b.Deployment=DeploymentInfo(ctx,d.Client,d.Log)
223+
b.Workspace=WorkspaceInfo(ctx,d.Client,d.Log,d.WorkspaceID,d.AgentID)
224+
b.Network=NetworkInfo(ctx,d.Client,d.Log,d.AgentID)
225+
226+
return&b,nil
227+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp