Skip to content
25 changes: 16 additions & 9 deletions cli/support.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,19 @@ func findAgent(agentName string, haystack []codersdk.WorkspaceResource) (*coders
}

func writeBundle(src *support.Bundle, dest *zip.Writer) error {
// We JSON-encode the following:
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_local.json": src.Network.NetcheckLocal,
"network/netcheck_remote.json": src.Network.NetcheckRemote,
"network/netcheck.json": src.Network.Netcheck,
"workspace/workspace.json": src.Workspace.Workspace,
"workspace/agent.json": src.Workspace.Agent,
"agent/agent.json": src.Agent.Agent,
"agent/listening_ports.json": src.Agent.ListeningPorts,
"agent/manifest.json": src.Agent.Manifest,
"agent/peer_diagnostics.json": src.Agent.PeerDiagnostics,
"agent/ping_result.json": src.Agent.PingResult,
"workspace/template.json": src.Workspace.Template,
"workspace/template_version.json": src.Workspace.TemplateVersion,
"workspace/parameters.json": src.Workspace.Parameters,
Expand All @@ -166,13 +170,16 @@ func writeBundle(src *support.Bundle, dest *zip.Writer) error {
return xerrors.Errorf("decode template zip from base64")
}

// The below we just write as we have them:
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),
"workspace/agent_startup_logs.txt": humanizeAgentLogs(src.Workspace.AgentStartupLogs),
"workspace/template_file.zip": string(templateVersionBytes),
"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),
"agent/logs.txt": string(src.Agent.Logs),
"agent/magicsock.html": string(src.Agent.MagicsockHTML),
"agent/startup_logs.txt": humanizeAgentLogs(src.Agent.StartupLogs),
"workspace/template_file.zip": string(templateVersionBytes),
"logs.txt": strings.Join(src.Logs, "\n"),
} {
f, err := dest.Create(k)
if err != nil {
Expand Down
54 changes: 45 additions & 9 deletions cli/support_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,26 @@ import (
"archive/zip"
"encoding/json"
"io"
"os"
"path/filepath"
"runtime"
"testing"
"time"

"tailscale.com/ipn/ipnstate"

"github.com/stretchr/testify/require"

"github.com/coder/coder/v2/agent"
"github.com/coder/coder/v2/agent/agenttest"
"github.com/coder/coder/v2/cli/clitest"
"github.com/coder/coder/v2/coderd/coderdtest"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbfake"
"github.com/coder/coder/v2/coderd/database/dbtime"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/codersdk/agentsdk"
"github.com/coder/coder/v2/tailnet"
"github.com/coder/coder/v2/testutil"
)

Expand All @@ -37,7 +44,14 @@ func TestSupportBundle(t *testing.T) {
}).WithAgent().Do()
ws, err := client.Workspace(ctx, r.Workspace.ID)
require.NoError(t, err)
agt := ws.LatestBuild.Resources[0].Agents[0]
tempDir := t.TempDir()
logPath := filepath.Join(tempDir, "coder-agent.log")
require.NoError(t, os.WriteFile(logPath, []byte("hello from the agent"), 0o600))
agt := agenttest.New(t, client.URL, r.AgentToken, func(o *agent.Options) {
o.LogDir = tempDir
})
defer agt.Close()
coderdtest.NewWorkspaceAgentWaiter(t, client, r.Workspace.ID).Wait()

// Insert a provisioner job log
_, err = db.InsertProvisionerJobLogs(ctx, database.InsertProvisionerJobLogsParams{
Expand All @@ -51,7 +65,7 @@ func TestSupportBundle(t *testing.T) {
require.NoError(t, err)
// Insert an agent log
_, err = db.InsertWorkspaceAgentLogs(ctx, database.InsertWorkspaceAgentLogsParams{
AgentID: agt.ID,
AgentID: ws.LatestBuild.Resources[0].Agents[0].ID,
CreatedAt: dbtime.Now(),
Output: []string{"started up"},
Level: []database.LogLevel{database.LogLevelInfo},
Expand Down Expand Up @@ -141,22 +155,44 @@ func assertBundleContents(t *testing.T, path string) {
case "network/tailnet_debug.html":
bs := readBytesFromZip(t, f)
require.NotEmpty(t, bs, "tailnet debug should not be empty")
case "network/netcheck_local.json", "network/netcheck_remote.json":
// TODO: setup fake agent?
bs := readBytesFromZip(t, f)
require.NotEmpty(t, bs, "netcheck should not be empty")
case "network/netcheck.json":
var v codersdk.WorkspaceAgentConnectionInfo
decodeJSONFromZip(t, f, &v)
require.NotEmpty(t, v, "connection info should not be empty")
case "workspace/workspace.json":
var v codersdk.Workspace
decodeJSONFromZip(t, f, &v)
require.NotEmpty(t, v, "workspace should not be empty")
case "workspace/build_logs.txt":
bs := readBytesFromZip(t, f)
require.Contains(t, string(bs), "provision done")
case "workspace/agent.json":
case "agent/agent.json":
var v codersdk.WorkspaceAgent
decodeJSONFromZip(t, f, &v)
require.NotEmpty(t, v, "agent should not be empty")
case "workspace/agent_startup_logs.txt":
case "agent/listening_ports.json":
var v codersdk.WorkspaceAgentListeningPortsResponse
decodeJSONFromZip(t, f, &v)
require.NotEmpty(t, v, "agent listening ports should not be empty")
case "agent/logs.txt":
bs := readBytesFromZip(t, f)
require.NotEmpty(t, bs, "logs should not be empty")
case "agent/magicsock.html":
bs := readBytesFromZip(t, f)
require.NotEmpty(t, bs, "agent magicsock should not be empty")
case "agent/manifest.json":
var v agentsdk.Manifest
decodeJSONFromZip(t, f, &v)
require.NotEmpty(t, v, "agent manifest should not be empty")
case "agent/peer_diagnostics.json":
var v *tailnet.PeerDiagnostics
decodeJSONFromZip(t, f, &v)
require.NotEmpty(t, v, "peer diagnostics should not be empty")
case "agent/ping_result.json":
var v *ipnstate.PingResult
decodeJSONFromZip(t, f, &v)
require.NotEmpty(t, v, "ping result should not be empty")
case "agent/startup_logs.txt":
bs := readBytesFromZip(t, f)
require.Contains(t, string(bs), "started up")
case "workspace/template.json":
Expand All @@ -178,7 +214,7 @@ func assertBundleContents(t *testing.T, path string) {
bs := readBytesFromZip(t, f)
require.NotEmpty(t, bs, "logs should not be empty")
default:
require.Failf(t, "unexpected file in bundle: %q", f.Name)
require.Failf(t, "unexpected file in bundle", f.Name)
}
}
}
Expand Down
Loading