feat(support): fetch agent network info over tailnet (#12577)

Adds agent-related information to support bundle command.
This commit is contained in:
Cian Johnston
2024-03-15 11:01:39 +00:00
committed by GitHub
parent 653ddccd8e
commit 2abc1cd2b7
4 changed files with 265 additions and 90 deletions
+16 -9
View File
@@ -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,
@@ -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 {
+45 -9
View File
@@ -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"
)
@@ -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{
@@ -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},
@@ -141,10 +155,10 @@ 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)
@@ -152,11 +166,33 @@ func assertBundleContents(t *testing.T, path string) {
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":
@@ -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)
}
}
}