mirror of https://github.com/coder/coder.git
fix(support): correctly rename existing agent connection info, add real netcheck (#12946)
This commit is contained in:
parent
c5367c201b
commit
b163bc7f01
|
@ -232,20 +232,21 @@ func findAgent(agentName string, haystack []codersdk.WorkspaceResource) (*coders
|
||||||
func writeBundle(src *support.Bundle, dest *zip.Writer) error {
|
func writeBundle(src *support.Bundle, dest *zip.Writer) error {
|
||||||
// We JSON-encode the following:
|
// We JSON-encode the following:
|
||||||
for k, v := range map[string]any{
|
for k, v := range map[string]any{
|
||||||
"deployment/buildinfo.json": src.Deployment.BuildInfo,
|
|
||||||
"deployment/config.json": src.Deployment.Config,
|
|
||||||
"deployment/experiments.json": src.Deployment.Experiments,
|
|
||||||
"deployment/health.json": src.Deployment.HealthReport,
|
|
||||||
"network/netcheck.json": src.Network.Netcheck,
|
|
||||||
"workspace/workspace.json": src.Workspace.Workspace,
|
|
||||||
"agent/agent.json": src.Agent.Agent,
|
"agent/agent.json": src.Agent.Agent,
|
||||||
"agent/listening_ports.json": src.Agent.ListeningPorts,
|
"agent/listening_ports.json": src.Agent.ListeningPorts,
|
||||||
"agent/manifest.json": src.Agent.Manifest,
|
"agent/manifest.json": src.Agent.Manifest,
|
||||||
"agent/peer_diagnostics.json": src.Agent.PeerDiagnostics,
|
"agent/peer_diagnostics.json": src.Agent.PeerDiagnostics,
|
||||||
"agent/ping_result.json": src.Agent.PingResult,
|
"agent/ping_result.json": src.Agent.PingResult,
|
||||||
|
"deployment/buildinfo.json": src.Deployment.BuildInfo,
|
||||||
|
"deployment/config.json": src.Deployment.Config,
|
||||||
|
"deployment/experiments.json": src.Deployment.Experiments,
|
||||||
|
"deployment/health.json": src.Deployment.HealthReport,
|
||||||
|
"network/connection_info.json": src.Network.ConnectionInfo,
|
||||||
|
"network/netcheck.json": src.Network.Netcheck,
|
||||||
"workspace/template.json": src.Workspace.Template,
|
"workspace/template.json": src.Workspace.Template,
|
||||||
"workspace/template_version.json": src.Workspace.TemplateVersion,
|
"workspace/template_version.json": src.Workspace.TemplateVersion,
|
||||||
"workspace/parameters.json": src.Workspace.Parameters,
|
"workspace/parameters.json": src.Workspace.Parameters,
|
||||||
|
"workspace/workspace.json": src.Workspace.Workspace,
|
||||||
} {
|
} {
|
||||||
f, err := dest.Create(k)
|
f, err := dest.Create(k)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -265,17 +266,17 @@ func writeBundle(src *support.Bundle, dest *zip.Writer) error {
|
||||||
|
|
||||||
// The below we just write as we have them:
|
// The below we just write as we have them:
|
||||||
for k, v := range map[string]string{
|
for k, v := range map[string]string{
|
||||||
"network/coordinator_debug.html": src.Network.CoordinatorDebug,
|
|
||||||
"network/tailnet_debug.html": src.Network.TailnetDebug,
|
|
||||||
"workspace/build_logs.txt": humanizeBuildLogs(src.Workspace.BuildLogs),
|
|
||||||
"agent/logs.txt": string(src.Agent.Logs),
|
"agent/logs.txt": string(src.Agent.Logs),
|
||||||
"agent/agent_magicsock.html": string(src.Agent.AgentMagicsockHTML),
|
"agent/agent_magicsock.html": string(src.Agent.AgentMagicsockHTML),
|
||||||
"agent/client_magicsock.html": string(src.Agent.ClientMagicsockHTML),
|
"agent/client_magicsock.html": string(src.Agent.ClientMagicsockHTML),
|
||||||
"agent/startup_logs.txt": humanizeAgentLogs(src.Agent.StartupLogs),
|
"agent/startup_logs.txt": humanizeAgentLogs(src.Agent.StartupLogs),
|
||||||
"agent/prometheus.txt": string(src.Agent.Prometheus),
|
"agent/prometheus.txt": string(src.Agent.Prometheus),
|
||||||
"workspace/template_file.zip": string(templateVersionBytes),
|
|
||||||
"logs.txt": strings.Join(src.Logs, "\n"),
|
|
||||||
"cli_logs.txt": string(src.CLILogs),
|
"cli_logs.txt": string(src.CLILogs),
|
||||||
|
"logs.txt": strings.Join(src.Logs, "\n"),
|
||||||
|
"network/coordinator_debug.html": src.Network.CoordinatorDebug,
|
||||||
|
"network/tailnet_debug.html": src.Network.TailnetDebug,
|
||||||
|
"workspace/build_logs.txt": humanizeBuildLogs(src.Workspace.BuildLogs),
|
||||||
|
"workspace/template_file.zip": string(templateVersionBytes),
|
||||||
} {
|
} {
|
||||||
f, err := dest.Create(k)
|
f, err := dest.Create(k)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"github.com/coder/coder/v2/coderd/database"
|
"github.com/coder/coder/v2/coderd/database"
|
||||||
"github.com/coder/coder/v2/coderd/database/dbfake"
|
"github.com/coder/coder/v2/coderd/database/dbfake"
|
||||||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||||
|
"github.com/coder/coder/v2/coderd/healthcheck/derphealth"
|
||||||
"github.com/coder/coder/v2/codersdk"
|
"github.com/coder/coder/v2/codersdk"
|
||||||
"github.com/coder/coder/v2/codersdk/agentsdk"
|
"github.com/coder/coder/v2/codersdk/agentsdk"
|
||||||
"github.com/coder/coder/v2/codersdk/healthsdk"
|
"github.com/coder/coder/v2/codersdk/healthsdk"
|
||||||
|
@ -182,6 +183,10 @@ func assertBundleContents(t *testing.T, path string, wantWorkspace bool, wantAge
|
||||||
var v healthsdk.HealthcheckReport
|
var v healthsdk.HealthcheckReport
|
||||||
decodeJSONFromZip(t, f, &v)
|
decodeJSONFromZip(t, f, &v)
|
||||||
require.NotEmpty(t, v, "health report should not be empty")
|
require.NotEmpty(t, v, "health report should not be empty")
|
||||||
|
case "network/connection_info.json":
|
||||||
|
var v workspacesdk.AgentConnectionInfo
|
||||||
|
decodeJSONFromZip(t, f, &v)
|
||||||
|
require.NotEmpty(t, v, "agent connection info should not be empty")
|
||||||
case "network/coordinator_debug.html":
|
case "network/coordinator_debug.html":
|
||||||
bs := readBytesFromZip(t, f)
|
bs := readBytesFromZip(t, f)
|
||||||
require.NotEmpty(t, bs, "coordinator debug should not be empty")
|
require.NotEmpty(t, bs, "coordinator debug should not be empty")
|
||||||
|
@ -189,13 +194,9 @@ func assertBundleContents(t *testing.T, path string, wantWorkspace bool, wantAge
|
||||||
bs := readBytesFromZip(t, f)
|
bs := readBytesFromZip(t, f)
|
||||||
require.NotEmpty(t, bs, "tailnet debug should not be empty")
|
require.NotEmpty(t, bs, "tailnet debug should not be empty")
|
||||||
case "network/netcheck.json":
|
case "network/netcheck.json":
|
||||||
var v workspacesdk.AgentConnectionInfo
|
var v derphealth.Report
|
||||||
decodeJSONFromZip(t, f, &v)
|
decodeJSONFromZip(t, f, &v)
|
||||||
if !wantAgent || !wantWorkspace {
|
require.NotEmpty(t, v, "netcheck should not be empty")
|
||||||
require.Empty(t, v, "expected connection info to be empty")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
require.NotEmpty(t, v, "connection info should not be empty")
|
|
||||||
case "workspace/workspace.json":
|
case "workspace/workspace.json":
|
||||||
var v codersdk.Workspace
|
var v codersdk.Workspace
|
||||||
decodeJSONFromZip(t, f, &v)
|
decodeJSONFromZip(t, f, &v)
|
||||||
|
|
|
@ -13,6 +13,9 @@ import (
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"tailscale.com/ipn/ipnstate"
|
"tailscale.com/ipn/ipnstate"
|
||||||
|
"tailscale.com/net/netcheck"
|
||||||
|
|
||||||
|
"github.com/coder/coder/v2/coderd/healthcheck/derphealth"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
@ -46,9 +49,16 @@ type Deployment struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Network struct {
|
type Network struct {
|
||||||
CoordinatorDebug string `json:"coordinator_debug"`
|
ConnectionInfo workspacesdk.AgentConnectionInfo
|
||||||
TailnetDebug string `json:"tailnet_debug"`
|
CoordinatorDebug string `json:"coordinator_debug"`
|
||||||
Netcheck *workspacesdk.AgentConnectionInfo `json:"netcheck"`
|
Netcheck *derphealth.Report `json:"netcheck"`
|
||||||
|
TailnetDebug string `json:"tailnet_debug"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Netcheck struct {
|
||||||
|
Report *netcheck.Report `json:"report"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
Logs []string `json:"logs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Workspace struct {
|
type Workspace struct {
|
||||||
|
@ -62,6 +72,7 @@ type Workspace struct {
|
||||||
|
|
||||||
type Agent struct {
|
type Agent struct {
|
||||||
Agent *codersdk.WorkspaceAgent `json:"agent"`
|
Agent *codersdk.WorkspaceAgent `json:"agent"`
|
||||||
|
ConnectionInfo *workspacesdk.AgentConnectionInfo `json:"connection_info"`
|
||||||
ListeningPorts *codersdk.WorkspaceAgentListeningPortsResponse `json:"listening_ports"`
|
ListeningPorts *codersdk.WorkspaceAgentListeningPortsResponse `json:"listening_ports"`
|
||||||
Logs []byte `json:"logs"`
|
Logs []byte `json:"logs"`
|
||||||
ClientMagicsockHTML []byte `json:"client_magicsock_html"`
|
ClientMagicsockHTML []byte `json:"client_magicsock_html"`
|
||||||
|
@ -136,7 +147,7 @@ func DeploymentInfo(ctx context.Context, client *codersdk.Client, log slog.Logge
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
func NetworkInfo(ctx context.Context, client *codersdk.Client, log slog.Logger, agentID uuid.UUID) Network {
|
func NetworkInfo(ctx context.Context, client *codersdk.Client, log slog.Logger) Network {
|
||||||
var (
|
var (
|
||||||
n Network
|
n Network
|
||||||
eg errgroup.Group
|
eg errgroup.Group
|
||||||
|
@ -171,15 +182,18 @@ func NetworkInfo(ctx context.Context, client *codersdk.Client, log slog.Logger,
|
||||||
})
|
})
|
||||||
|
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
if agentID == uuid.Nil {
|
// Need connection info to get DERP map for netcheck
|
||||||
log.Warn(ctx, "agent id required for agent connection info")
|
connInfo, err := workspacesdk.New(client).AgentConnectionInfoGeneric(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn(ctx, "unable to fetch generic agent connection info")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
connInfo, err := workspacesdk.New(client).AgentConnectionInfo(ctx, agentID)
|
n.ConnectionInfo = connInfo
|
||||||
if err != nil {
|
var rpt derphealth.Report
|
||||||
return xerrors.Errorf("fetch agent conn info: %w", err)
|
rpt.Run(ctx, &derphealth.ReportOptions{
|
||||||
}
|
DERPMap: connInfo.DERPMap,
|
||||||
n.Netcheck = &connInfo
|
})
|
||||||
|
n.Netcheck = &rpt
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -482,7 +496,7 @@ func Run(ctx context.Context, d *Deps) (*Bundle, error) {
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
ni := NetworkInfo(ctx, d.Client, d.Log, d.AgentID)
|
ni := NetworkInfo(ctx, d.Client, d.Log)
|
||||||
b.Network = ni
|
b.Network = ni
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
|
@ -62,9 +62,10 @@ func TestRun(t *testing.T) {
|
||||||
assertSanitizedDeploymentConfig(t, bun.Deployment.Config)
|
assertSanitizedDeploymentConfig(t, bun.Deployment.Config)
|
||||||
assertNotNilNotEmpty(t, bun.Deployment.HealthReport, "deployment health report should be present")
|
assertNotNilNotEmpty(t, bun.Deployment.HealthReport, "deployment health report should be present")
|
||||||
assertNotNilNotEmpty(t, bun.Deployment.Experiments, "deployment experiments should be present")
|
assertNotNilNotEmpty(t, bun.Deployment.Experiments, "deployment experiments should be present")
|
||||||
|
assertNotNilNotEmpty(t, bun.Network.ConnectionInfo, "agent connection info should be present")
|
||||||
assertNotNilNotEmpty(t, bun.Network.CoordinatorDebug, "network coordinator debug should be present")
|
assertNotNilNotEmpty(t, bun.Network.CoordinatorDebug, "network coordinator debug should be present")
|
||||||
assertNotNilNotEmpty(t, bun.Network.TailnetDebug, "network tailnet debug should be present")
|
|
||||||
assertNotNilNotEmpty(t, bun.Network.Netcheck, "network netcheck should be present")
|
assertNotNilNotEmpty(t, bun.Network.Netcheck, "network netcheck should be present")
|
||||||
|
assertNotNilNotEmpty(t, bun.Network.TailnetDebug, "network tailnet debug should be present")
|
||||||
assertNotNilNotEmpty(t, bun.Workspace.Workspace, "workspace should be present")
|
assertNotNilNotEmpty(t, bun.Workspace.Workspace, "workspace should be present")
|
||||||
assertSanitizedWorkspace(t, bun.Workspace.Workspace)
|
assertSanitizedWorkspace(t, bun.Workspace.Workspace)
|
||||||
assertNotNilNotEmpty(t, bun.Workspace.BuildLogs, "workspace build logs should be present")
|
assertNotNilNotEmpty(t, bun.Workspace.BuildLogs, "workspace build logs should be present")
|
||||||
|
@ -109,9 +110,10 @@ func TestRun(t *testing.T) {
|
||||||
assertSanitizedDeploymentConfig(t, bun.Deployment.Config)
|
assertSanitizedDeploymentConfig(t, bun.Deployment.Config)
|
||||||
assertNotNilNotEmpty(t, bun.Deployment.HealthReport, "deployment health report should be present")
|
assertNotNilNotEmpty(t, bun.Deployment.HealthReport, "deployment health report should be present")
|
||||||
assertNotNilNotEmpty(t, bun.Deployment.Experiments, "deployment experiments should be present")
|
assertNotNilNotEmpty(t, bun.Deployment.Experiments, "deployment experiments should be present")
|
||||||
|
assertNotNilNotEmpty(t, bun.Network.ConnectionInfo, "agent connection info should be present")
|
||||||
assertNotNilNotEmpty(t, bun.Network.CoordinatorDebug, "network coordinator debug should be present")
|
assertNotNilNotEmpty(t, bun.Network.CoordinatorDebug, "network coordinator debug should be present")
|
||||||
|
assertNotNilNotEmpty(t, bun.Network.Netcheck, "network netcheck should be present")
|
||||||
assertNotNilNotEmpty(t, bun.Network.TailnetDebug, "network tailnet debug should be present")
|
assertNotNilNotEmpty(t, bun.Network.TailnetDebug, "network tailnet debug should be present")
|
||||||
assert.Empty(t, bun.Network.Netcheck, "did not expect netcheck to be present")
|
|
||||||
assert.Empty(t, bun.Workspace.Workspace, "did not expect workspace to be present")
|
assert.Empty(t, bun.Workspace.Workspace, "did not expect workspace to be present")
|
||||||
assert.Empty(t, bun.Agent, "did not expect agent to be present")
|
assert.Empty(t, bun.Agent, "did not expect agent to be present")
|
||||||
assertNotNilNotEmpty(t, bun.Logs, "bundle logs should be present")
|
assertNotNilNotEmpty(t, bun.Logs, "bundle logs should be present")
|
||||||
|
|
Loading…
Reference in New Issue