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

Commit99ad0db

Browse files
committed
feat: add support package and accompanying tests
1 parentb9e2d0a commit99ad0db

File tree

3 files changed

+396
-0
lines changed

3 files changed

+396
-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)GetDebugHealth(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+
bi,err:=client.BuildInfo(ctx)
66+
iferr!=nil {
67+
log.Error(ctx,"fetch build info",slog.Error(err))
68+
}else {
69+
d.BuildInfo=&bi
70+
}
71+
72+
dc,err:=client.DeploymentConfig(ctx)
73+
iferr!=nil {
74+
log.Error(ctx,"fetch deployment config",slog.Error(err))
75+
}else {
76+
d.Config=dc
77+
}
78+
79+
hr,err:=client.GetDebugHealth(ctx)
80+
iferr!=nil {
81+
log.Error(ctx,"fetch health report",slog.Error(err))
82+
}else {
83+
d.HealthReport=&hr
84+
}
85+
86+
exp,err:=client.Experiments(ctx)
87+
iferr!=nil {
88+
log.Error(ctx,"fetch experiments",slog.Error(err))
89+
}else {
90+
d.Experiments=exp
91+
}
92+
93+
returnd
94+
}
95+
96+
funcNetworkInfo(ctx context.Context,client*codersdk.Client,log slog.Logger,agentID uuid.UUID)Network {
97+
varnNetwork
98+
99+
// Get /api/v2/debug/coordinator
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+
// Get /api/v2/debug/tailnet
114+
tailResp,err:=client.Request(ctx,http.MethodGet,"/api/v2/debug/tailnet",nil)
115+
iferr!=nil {
116+
log.Error(ctx,"fetch tailnet debug page",slog.Error(err))
117+
}else {
118+
defertailResp.Body.Close()
119+
bs,err:=io.ReadAll(tailResp.Body)
120+
iferr!=nil {
121+
log.Error(ctx,"read tailnet debug page",slog.Error(err))
122+
}else {
123+
n.TailnetDebug=string(bs)
124+
}
125+
}
126+
127+
ifagentID!=uuid.Nil {
128+
connInfo,err:=client.WorkspaceAgentConnectionInfo(ctx,agentID)
129+
iferr!=nil {
130+
log.Error(ctx,"fetch agent conn info",slog.Error(err),slog.F("agent_id",agentID.String()))
131+
}else {
132+
n.NetcheckLocal=&connInfo
133+
}
134+
}else {
135+
log.Warn(ctx,"agent id required for agent connection info")
136+
}
137+
138+
returnn
139+
}
140+
141+
funcWorkspaceInfo(ctx context.Context,client*codersdk.Client,log slog.Logger,workspaceID,agentID uuid.UUID)Workspace {
142+
varwWorkspace
143+
144+
ifworkspaceID==uuid.Nil {
145+
log.Error(ctx,"no workspace id specified")
146+
returnw
147+
}
148+
149+
ifagentID==uuid.Nil {
150+
log.Error(ctx,"no agent id specified")
151+
}
152+
153+
ws,err:=client.Workspace(ctx,workspaceID)
154+
iferr!=nil {
155+
log.Error(ctx,"fetch workspace",slog.Error(err),slog.F("workspace_id",workspaceID))
156+
returnw
157+
}
158+
159+
w.Workspace=ws
160+
161+
buildLogCh,closer,err:=client.WorkspaceBuildLogsAfter(ctx,ws.LatestBuild.ID,0)
162+
iferr!=nil {
163+
log.Error(ctx,"fetch provisioner job logs",slog.Error(err),slog.F("job_id",ws.LatestBuild.Job.ID.String()))
164+
}else {
165+
defercloser.Close()
166+
forlog:=rangebuildLogCh {
167+
w.BuildLogs=append(w.BuildLogs,log)
168+
}
169+
}
170+
171+
iflen(w.Workspace.LatestBuild.Resources)==0 {
172+
log.Warn(ctx,"workspace build has no resources")
173+
returnw
174+
}
175+
176+
agentLogCh,closer,err:=client.WorkspaceAgentLogsAfter(ctx,agentID,0,false)
177+
iferr!=nil {
178+
log.Error(ctx,"fetch agent startup logs",slog.Error(err),slog.F("agent_id",agentID.String()))
179+
}else {
180+
defercloser.Close()
181+
forlogChunk:=rangeagentLogCh {
182+
w.AgentStartupLogs=append(w.AgentStartupLogs,logChunk...)
183+
}
184+
}
185+
186+
returnw
187+
}
188+
189+
// Run generates a support bundle with the given dependencies.
190+
funcRun(ctx context.Context,d*Deps) (*Bundle,error) {
191+
varbBundle
192+
ifd.Client==nil {
193+
returnnil,xerrors.Errorf("developer error: missing client!")
194+
}
195+
196+
authChecks:=map[string]codersdk.AuthorizationCheck{
197+
"Read DeploymentValues": {
198+
Object: codersdk.AuthorizationObject{
199+
ResourceType:codersdk.ResourceDeploymentValues,
200+
},
201+
Action:string(rbac.ActionRead),
202+
},
203+
}
204+
205+
authResp,err:=d.Client.AuthCheck(ctx, codersdk.AuthorizationRequest{Checks:authChecks})
206+
iferr!=nil {
207+
return&b,xerrors.Errorf("check authorization: %w",err)
208+
}
209+
fork,v:=rangeauthResp {
210+
if!v {
211+
return&b,xerrors.Errorf("failed authorization check: cannot %s",k)
212+
}
213+
}
214+
215+
// Ensure we capture logs from the client.
216+
varlogw strings.Builder
217+
d.Log.AppendSinks(sloghuman.Sink(&logw))
218+
deferfunc() {
219+
b.Logs=strings.Split(logw.String(),"\n")
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