-
Notifications
You must be signed in to change notification settings - Fork 66
src debug command #731
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
src debug command #731
Changes from 103 commits
dfa7592
e729fa0
eb9f057
b48f332
dabaacb
74a28c3
88abc6f
77f06d2
746fce8
0dff03b
b7c4625
d4821a0
3de8d87
53932e4
fd4ad22
9415d56
c216923
e392fbb
9ef8036
ae4c240
9d09cb2
247d0a3
8115b72
3631b8a
5db3a39
dd52bf3
5c6987c
dc32e6f
26ebd78
53e8ecc
928d61f
1a655d9
572218e
62d915c
6943f52
0336668
f26f592
533c545
88b2a4e
2d91a35
a3c9977
709817c
edbe953
419d194
8a6aa2a
e2cdff3
877fedc
662c142
b96532a
7981e89
b54a1af
2d46ea8
d3d557e
e393535
7dff3b9
2e3b525
77f62e0
d1264a9
47ba3c5
367de18
13a2620
a8505f8
6a64a3c
487ab74
9c81467
d080d66
a33444c
688ccee
e1fe03d
df05363
9c656bd
38f5ce1
d6d71e5
023cbe0
3fafa35
7ecd7de
daa38e8
e5c3f8c
4bdba62
6b35078
94a6538
f759711
06640e5
8ecdff3
4396daa
c42c855
9e12b5f
ed870e5
dc7aef6
bd1366c
91c28d6
109f49e
877a333
edf6100
14f3441
1b09789
7eee487
3ab8775
066fd39
10fa745
0f2f878
c54fd23
feb5cf4
da74d2b
f0c57a4
9a2c7b0
4aa5180
1a6076b
91fef39
4805a7c
8eb1d8f
6b11205
48ffc5f
cc29b45
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
./src | ||
./cmd/src/src | ||
*.zip | ||
release | ||
./vendor | ||
.idea | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
) | ||
|
||
var debugCommands commander | ||
|
||
func init() { | ||
usage := `'src debug' gathers and bundles debug data from a Sourcegraph deployment for troubleshooting. | ||
|
||
Usage: | ||
|
||
src debug command [command options] | ||
|
||
The commands are: | ||
|
||
kube dumps context from k8s deployments | ||
compose dumps context from docker-compose deployments | ||
server dumps context from single-container deployments | ||
|
||
|
||
Use "src debug [command] -h" for more information about a subcommands. | ||
DaedalusG marked this conversation as resolved.
Show resolved
Hide resolved
|
||
src debug has access to flags on src -- Ex: src -v kube -o foo.zip | ||
|
||
` | ||
|
||
flagSet := flag.NewFlagSet("debug", flag.ExitOnError) | ||
handler := func(args []string) error { | ||
debugCommands.run(flagSet, "src debug", usage, args) | ||
return nil | ||
} | ||
|
||
// Register the command. | ||
commands = append(commands, &command{ | ||
flagSet: flagSet, | ||
aliases: []string{}, | ||
handler: handler, | ||
usageFunc: func() { fmt.Println(usage) }, | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package main | ||
|
||
import ( | ||
"archive/zip" | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"log" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
"github.com/sourcegraph/src-cli/internal/exec" | ||
|
||
"github.com/sourcegraph/sourcegraph/lib/errors" | ||
) | ||
|
||
type archiveFile struct { | ||
name string | ||
data []byte | ||
err error | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's unusual in Go to bundle an error field into a structure, as Go tends to strongly prefer returning type myType struct {
derivedFoo any
derivedBar any
}
func NewMyType(foo any, bar any) (*MyType, error) {
derivedFoo, err := doSomethingWithFoo(foo)
if err != nil {
return nil, errors.Wrap(err, "could not derive foo")
}
derivedBar, err := doSomethingWithBar(bar)
if err != nil {
return nil, errors.Wrap(err, "could not derive bar")
}
return &MyType{
derivedFoo: derivedFoo,
derivedBar: derivedBar,
}, nil
} Where we do tend to break this in Sourcegraph is where the error actually needs to persist across invocations — the most common case is where a GraphQL resolver does some sort of one time internal call to retrieve things from the database, but then might need to return the same error for each field that was requested in the GraphQL query. You don't need to change this, but it's worth being aware of for future Go projects. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will investigate after merge, ty ty There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @LawnGnome FYI these values go through a channel which is why it's packaged as a struct in the first place. Does that change this advice? |
||
} | ||
|
||
func archiveFileFromCommand(ctx context.Context, path, cmd string, args ...string) *archiveFile { | ||
f := &archiveFile{name: path} | ||
f.data, f.err = exec.CommandContext(ctx, cmd, args...).CombinedOutput() | ||
if f.err != nil { | ||
f.err = errors.Wrapf(f.err, "executing command: %s %s: received error: %s", cmd, strings.Join(args, " "), f.data) | ||
} | ||
return f | ||
} | ||
|
||
// This function prompts the user to confirm they want to run the command | ||
DaedalusG marked this conversation as resolved.
Show resolved
Hide resolved
|
||
func verify(confirmationText string) (bool, error) { | ||
input := "" | ||
for strings.ToLower(input) != "y" && strings.ToLower(input) != "n" { | ||
fmt.Printf("%s [y/N]: ", confirmationText) | ||
if _, err := fmt.Scanln(&input); err != nil { | ||
return false, err | ||
} | ||
} | ||
|
||
return strings.ToLower(input) == "y", nil | ||
} | ||
|
||
func processBaseDir(base string) (string, string) { | ||
if !strings.HasSuffix(base, ".zip") { | ||
return base + ".zip", base | ||
} | ||
|
||
return base, strings.TrimSuffix(base, ".zip") | ||
} | ||
|
||
// write all the outputs from an archive command passed on the channel to to the zip writer | ||
func writeChannelContentsToZip(zw *zip.Writer, ch <-chan *archiveFile, verbose bool) error { | ||
for f := range ch { | ||
if verbose { | ||
log.Printf("archiving file %q with %d bytes", f.name, len(f.data)) | ||
} | ||
|
||
if f.err != nil { | ||
return f.err | ||
} | ||
|
||
zf, err := zw.Create(f.name) | ||
if err != nil { | ||
return errors.Wrapf(err, "failed to create %q", f.name) | ||
} | ||
|
||
if _, err := zf.Write(f.data); err != nil { | ||
return errors.Wrapf(err, "failed to write to %q", f.name) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// TODO: Currently external services and site configs are pulled using the SRC_ENDPOINT env var, | ||
DaedalusG marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// if theres a way to validate that the env var is pointing at the same instance as the docker and kubectl commands, | ||
// it should be implemented. | ||
|
||
// TODO: file issue on the existence of OAuth signKey which needs to be redacted | ||
|
||
// getExternalServicesConfig calls src extsvc list with the format flag -f, | ||
// and then returns an archiveFile to be consumed | ||
func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile { | ||
const fmtStr = `{{range .Nodes}}{{.id}} | {{.kind}} | {{.displayName}}{{"\n"}}{{.config}}{{"\n---\n"}}{{end}}` | ||
return archiveFileFromCommand( | ||
ctx, | ||
filepath.Join(baseDir, "config", "external_services.txt"), | ||
os.Args[0], "extsvc", "list", "-f", fmtStr, | ||
) | ||
} | ||
|
||
// getSiteConfig calls src api -query=... to query the api for site config json | ||
func getSiteConfig(ctx context.Context, baseDir string) *archiveFile { | ||
const siteConfigStr = `query { site { configuration { effectiveContents } } }` | ||
f := archiveFileFromCommand(ctx, | ||
filepath.Join(baseDir, "config", "siteConfig.json"), | ||
os.Args[0], "api", "-query", siteConfigStr, | ||
) | ||
|
||
if f.err != nil { | ||
return f | ||
} | ||
|
||
var siteConfig struct { | ||
Data struct { | ||
Site struct { | ||
Configuration struct { | ||
EffectiveContents string | ||
} | ||
} | ||
} | ||
} | ||
|
||
if err := json.Unmarshal(f.data, &siteConfig); err != nil { | ||
f.err = err | ||
return f | ||
} | ||
|
||
f.data = []byte(siteConfig.Data.Site.Configuration.EffectiveContents) | ||
return f | ||
} |
Uh oh!
There was an error while loading. Please reload this page.