()
| 65 | cliui.Bold("Continue? ") |
| 66 | |
| 67 | func (r *RootCmd) supportBundle() *serpent.Command { |
| 68 | var outputPath string |
| 69 | var coderURLOverride string |
| 70 | var workspacesTotalCap64 int64 = 10 |
| 71 | var templateName string |
| 72 | var pprof bool |
| 73 | cmd := &serpent.Command{ |
| 74 | Use: "bundle [<workspace>] [<agent>]", |
| 75 | Short: "Generate a support bundle to troubleshoot issues connecting to a workspace.", |
| 76 | Long: `This command generates a file containing detailed troubleshooting information about the Coder deployment and workspace connections. You may specify a single workspace (and optionally an agent name). When run inside a workspace, the workspace and agent are inferred from the environment if not provided.`, |
| 77 | Middleware: serpent.Chain( |
| 78 | serpent.RequireRangeArgs(0, 2), |
| 79 | ), |
| 80 | Handler: func(inv *serpent.Invocation) error { |
| 81 | client, err := r.InitClient(inv) |
| 82 | if err != nil { |
| 83 | return err |
| 84 | } |
| 85 | var cliLogBuf bytes.Buffer |
| 86 | cliLogW := sloghuman.Sink(&cliLogBuf) |
| 87 | cliLog := slog.Make(cliLogW).Leveled(slog.LevelDebug) |
| 88 | if r.verbose { |
| 89 | cliLog = cliLog.AppendSinks(sloghuman.Sink(inv.Stderr)) |
| 90 | } |
| 91 | ans, err := cliui.Prompt(inv, cliui.PromptOptions{ |
| 92 | Text: supportBundleBlurb, |
| 93 | Secret: false, |
| 94 | IsConfirm: true, |
| 95 | }) |
| 96 | if err != nil || ans != cliui.ConfirmYes { |
| 97 | return err |
| 98 | } |
| 99 | if skip, _ := inv.ParsedFlags().GetBool("yes"); skip { |
| 100 | cliLog.Debug(inv.Context(), "user auto-confirmed") |
| 101 | } else { |
| 102 | cliLog.Debug(inv.Context(), "user confirmed manually", slog.F("answer", ans)) |
| 103 | } |
| 104 | |
| 105 | vi := defaultVersionInfo() |
| 106 | cliLog.Debug(inv.Context(), "version info", |
| 107 | slog.F("version", vi.Version), |
| 108 | slog.F("build_time", vi.BuildTime), |
| 109 | slog.F("external_url", vi.ExternalURL), |
| 110 | slog.F("slim", vi.Slim), |
| 111 | slog.F("agpl", vi.AGPL), |
| 112 | slog.F("boring_crypto", vi.BoringCrypto), |
| 113 | ) |
| 114 | cliLog.Debug(inv.Context(), "invocation", slog.F("args", strings.Join(os.Args, " "))) |
| 115 | |
| 116 | // Bypass rate limiting for support bundle collection since it makes many API calls. |
| 117 | // Note: this can only be done by the owner user. |
| 118 | if ok, err := support.CanGenerateFull(inv.Context(), client); err == nil && ok { |
| 119 | cliLog.Debug(inv.Context(), "running as owner") |
| 120 | client.HTTPClient.Transport = &codersdk.HeaderTransport{ |
| 121 | Transport: client.HTTPClient.Transport, |
| 122 | Header: http.Header{codersdk.BypassRatelimitHeader: {"true"}}, |
| 123 | } |
| 124 | } else if !ok { |
no test coverage detected