fix(support): correctly rename existing agent connection info, add real netcheck (#12946)

This commit is contained in:
Cian Johnston 2024-04-12 09:40:04 +01:00 committed by GitHub
parent c5367c201b
commit b163bc7f01
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 49 additions and 31 deletions

View File

@ -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 {

View File

@ -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)

View File

@ -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
}) })

View File

@ -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")