Skip to content

Commit

Permalink
add flag to request and gather a flamegraph (#299)
Browse files Browse the repository at this point in the history
  • Loading branch information
jakecoffman authored Apr 3, 2024
1 parent af4c0f9 commit 818bc30
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 1 deletion.
1 change: 1 addition & 0 deletions cmd/dependabot/internal/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type SharedFlags struct {
file string
cache string
debugging bool
flamegraph bool
proxyCertPath string
collectorConfigPath string
extraHosts []string
Expand Down
2 changes: 2 additions & 0 deletions cmd/dependabot/internal/cmd/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ func NewUpdateCommand() *cobra.Command {
CollectorImage: collectorImage,
Creds: input.Credentials,
Debug: flags.debugging,
Flamegraph: flags.flamegraph,
Expected: nil, // update subcommand doesn't use expectations
ExtraHosts: flags.extraHosts,
InputName: flags.file,
Expand Down Expand Up @@ -126,6 +127,7 @@ func NewUpdateCommand() *cobra.Command {
cmd.Flags().StringVar(&flags.collectorConfigPath, "collector-config", "", "path to an OpenTelemetry collector config file")
cmd.Flags().BoolVar(&flags.pullImages, "pull", true, "pull the image if it isn't present")
cmd.Flags().BoolVar(&flags.debugging, "debug", false, "run an interactive shell inside the updater")
cmd.Flags().BoolVar(&flags.flamegraph, "flamegraph", false, "generate a flamegraph and other metrics")
cmd.Flags().StringArrayVarP(&flags.volumes, "volume", "v", nil, "mount volumes in Docker")
cmd.Flags().StringArrayVar(&flags.extraHosts, "extra-hosts", nil, "Docker extra hosts setting on the proxy")
cmd.Flags().DurationVarP(&flags.timeout, "timeout", "t", 0, "max time to run an update")
Expand Down
33 changes: 32 additions & 1 deletion internal/infra/run.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package infra

import (
"archive/tar"
"context"
"encoding/base64"
"encoding/json"
Expand Down Expand Up @@ -48,6 +49,8 @@ type RunParams struct {
PullImages bool
// run an interactive shell?
Debug bool
// generate performance metrics?
Flamegraph bool
// Volumes are used to mount directories in Docker
Volumes []string
// Timeout specifies an optional maximum duration the CLI will run an update.
Expand Down Expand Up @@ -408,10 +411,17 @@ func runContainers(ctx context.Context, params RunParams) (err error) {
return err
}
} else {
env := userEnv(prox.url, params.ApiUrl)
if params.Flamegraph {
env = append(env, "FLAMEGRAPH=1")
}
const cmd = "update-ca-certificates && bin/run fetch_files && bin/run update_files"
if err := updater.RunCmd(ctx, cmd, dependabot, userEnv(prox.url, params.ApiUrl)...); err != nil {
if err := updater.RunCmd(ctx, cmd, dependabot, env...); err != nil {
return err
}
if params.Flamegraph {
getFromContainer(ctx, cli, updater.containerID, "/tmp/dependabot-flamegraph.html")
}
// If the exit code is non-zero, error when using the `update` subcommand, but not the `test` subcommand.
if params.Expected == nil && *updater.ExitCode != 0 {
return fmt.Errorf("updater exited with code %d", *updater.ExitCode)
Expand All @@ -421,6 +431,27 @@ func runContainers(ctx context.Context, params RunParams) (err error) {
return nil
}

func getFromContainer(ctx context.Context, cli *client.Client, containerID, srcPath string) {
reader, _, err := cli.CopyFromContainer(ctx, containerID, srcPath)
if err != nil {
log.Println("Failed to get from container:", err)
return
}
defer reader.Close()
outFile, err := os.Create("flamegraph.html")
if err != nil {
log.Println("Failed to create file while getting from container:", err)
return
}
defer outFile.Close()
tarReader := tar.NewReader(reader)
tarReader.Next()
_, err = io.Copy(outFile, tarReader)
if err != nil {
log.Printf("Failed copy while getting from container %v: %v\n", srcPath, err)
}
}

func putCloneDir(ctx context.Context, cli *client.Client, updater *Updater, dir string) error {
// Docker won't create the directory, so we have to do it first.
const cmd = "mkdir -p " + guestRepoDir
Expand Down
32 changes: 32 additions & 0 deletions testdata/scripts/flamegraph.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Build the dummy Dockerfile
exec docker build -qt flamegraph-updater .

# Run the dependabot command
dependabot update go_modules dependabot/cli --updater-image flamegraph-updater --flamegraph

# There should be a flamegraph file in the current directory
exists flamegraph.html

exec docker rmi -f flamegraph-updater

-- Dockerfile --
FROM ubuntu:22.04

RUN useradd dependabot

COPY --chown=dependabot --chmod=755 update-ca-certificates /usr/bin/update-ca-certificates
COPY --chown=dependabot --chmod=755 run bin/run

-- update-ca-certificates --
#!/usr/bin/env bash

echo "Updated those certificates for ya"

-- run --
#!/usr/bin/env bash

# if there's an environment variable "FLAMEGRAPH" set, create a fake flamegraph in tmp
if [ -n "$FLAMEGRAPH" ]; then
echo "Creating flamegraph"
echo "fake flamegraph" > /tmp/dependabot-flamegraph.html
fi

0 comments on commit 818bc30

Please sign in to comment.