-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
VAULT-25848 replace mholt/archiver with native go calls #27228
Changes from 6 commits
d13549f
1a4382f
9348fce
46b67c1
c235897
2a5749f
bc8fe69
6349c31
508560d
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 | ||||
---|---|---|---|---|---|---|
|
@@ -4,10 +4,12 @@ | |||||
package command | ||||||
|
||||||
import ( | ||||||
"archive/tar" | ||||||
"compress/gzip" | ||||||
"context" | ||||||
"encoding/json" | ||||||
"fmt" | ||||||
"io/ioutil" | ||||||
"io" | ||||||
"net/url" | ||||||
"os" | ||||||
"path/filepath" | ||||||
|
@@ -26,7 +28,6 @@ import ( | |||||
"github.com/hashicorp/vault/sdk/helper/jsonutil" | ||||||
"github.com/hashicorp/vault/sdk/helper/logging" | ||||||
"github.com/hashicorp/vault/version" | ||||||
"github.com/mholt/archiver/v3" | ||||||
"github.com/oklog/run" | ||||||
"github.com/posener/complete" | ||||||
) | ||||||
|
@@ -374,7 +375,7 @@ func (c *DebugCommand) generateIndex() error { | |||||
} | ||||||
|
||||||
// Write out file | ||||||
if err := ioutil.WriteFile(filepath.Join(c.flagOutput, "index.json"), bytes, 0o600); err != nil { | ||||||
if err := os.WriteFile(filepath.Join(c.flagOutput, "index.json"), bytes, 0o600); err != nil { | ||||||
return fmt.Errorf("error generating index file; %s", err) | ||||||
} | ||||||
|
||||||
|
@@ -778,7 +779,7 @@ func (c *DebugCommand) collectPprof(ctx context.Context) { | |||||
return | ||||||
} | ||||||
|
||||||
err = ioutil.WriteFile(filepath.Join(dirName, target+".prof"), data, 0o600) | ||||||
err = os.WriteFile(filepath.Join(dirName, target+".prof"), data, 0o600) | ||||||
if err != nil { | ||||||
c.captureError("pprof."+target, err) | ||||||
} | ||||||
|
@@ -796,13 +797,13 @@ func (c *DebugCommand) collectPprof(ctx context.Context) { | |||||
return | ||||||
} | ||||||
|
||||||
err = ioutil.WriteFile(filepath.Join(dirName, "goroutines.txt"), data, 0o600) | ||||||
err = os.WriteFile(filepath.Join(dirName, "goroutines.txt"), data, 0o600) | ||||||
if err != nil { | ||||||
c.captureError("pprof.goroutines-text", err) | ||||||
} | ||||||
}() | ||||||
|
||||||
// If the our remaining duration is less than the interval value | ||||||
// If our remaining duration is less than the interval value | ||||||
// skip profile and trace. | ||||||
runDuration := currentTimestamp.Sub(startTime) | ||||||
if (c.flagDuration+debugDurationGrace)-runDuration < c.flagInterval { | ||||||
|
@@ -820,7 +821,7 @@ func (c *DebugCommand) collectPprof(ctx context.Context) { | |||||
return | ||||||
} | ||||||
|
||||||
err = ioutil.WriteFile(filepath.Join(dirName, "profile.prof"), data, 0o600) | ||||||
err = os.WriteFile(filepath.Join(dirName, "profile.prof"), data, 0o600) | ||||||
if err != nil { | ||||||
c.captureError("pprof.profile", err) | ||||||
} | ||||||
|
@@ -836,7 +837,7 @@ func (c *DebugCommand) collectPprof(ctx context.Context) { | |||||
return | ||||||
} | ||||||
|
||||||
err = ioutil.WriteFile(filepath.Join(dirName, "trace.out"), data, 0o600) | ||||||
err = os.WriteFile(filepath.Join(dirName, "trace.out"), data, 0o600) | ||||||
if err != nil { | ||||||
c.captureError("pprof.trace", err) | ||||||
} | ||||||
|
@@ -972,7 +973,7 @@ func (c *DebugCommand) persistCollection(collection []map[string]interface{}, ou | |||||
if err != nil { | ||||||
return err | ||||||
} | ||||||
if err := ioutil.WriteFile(filepath.Join(c.flagOutput, outFile), bytes, 0o600); err != nil { | ||||||
if err := os.WriteFile(filepath.Join(c.flagOutput, outFile), bytes, 0o600); err != nil { | ||||||
return err | ||||||
} | ||||||
|
||||||
|
@@ -984,8 +985,7 @@ func (c *DebugCommand) compress(dst string) error { | |||||
defer osutil.Umask(osutil.Umask(0o077)) | ||||||
} | ||||||
|
||||||
tgz := archiver.NewTarGz() | ||||||
if err := tgz.Archive([]string{c.flagOutput}, dst); err != nil { | ||||||
if err := archiveToTgz(c.flagOutput, dst); err != nil { | ||||||
return fmt.Errorf("failed to compress data: %s", err) | ||||||
} | ||||||
|
||||||
|
@@ -997,6 +997,93 @@ func (c *DebugCommand) compress(dst string) error { | |||||
return nil | ||||||
} | ||||||
|
||||||
// archiveToTgz compresses all the files in sourceDir to a | ||||||
// a tarball at destination. | ||||||
func archiveToTgz(sourceDir, destination string) error { | ||||||
file, err := os.Create(destination) | ||||||
if err != nil { | ||||||
return fmt.Errorf("failed to create file: %s", err) | ||||||
} | ||||||
defer file.Close() | ||||||
|
||||||
gzipWriter := gzip.NewWriter(file) | ||||||
defer gzipWriter.Close() | ||||||
|
||||||
tarWriter := tar.NewWriter(gzipWriter) | ||||||
defer tarWriter.Close() | ||||||
|
||||||
err = filepath.Walk(sourceDir, | ||||||
func(filePath string, info os.FileInfo, err error) error { | ||||||
if err != nil { | ||||||
return err | ||||||
} | ||||||
return addFileToTar(sourceDir, filePath, tarWriter) | ||||||
}) | ||||||
|
||||||
return err | ||||||
} | ||||||
|
||||||
// addFileToTar takes a file at filePath and adds it to the tar | ||||||
// being written to by tarWriter, alongside its header. T | ||||||
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.
Suggested change
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. BTW lovely comments 😎 |
||||||
// The tar header name will be relative. Example: If we're tarring | ||||||
// a file in ~/a/b/c/foo/bar.json, the header name will be foo/bar.json | ||||||
func addFileToTar(sourceDir, filePath string, tarWriter *tar.Writer) error { | ||||||
file, err := os.Open(filePath) | ||||||
if err != nil { | ||||||
return fmt.Errorf("failed to open file %q: %s", filePath, err) | ||||||
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. Is it worth using 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. From what I can tell, %v and %s should be equivalent for errs -- is there a reason you think %v might be preferred? 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. Sorry, I mean't 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. Oh, good shout. I always forget about that one since it only sometimes works (only for |
||||||
} | ||||||
defer file.Close() | ||||||
|
||||||
stat, err := file.Stat() | ||||||
if err != nil { | ||||||
return fmt.Errorf("failed to stat file %q: %s", filePath, err) | ||||||
} | ||||||
|
||||||
var link string | ||||||
mode := stat.Mode() | ||||||
if mode&os.ModeSymlink != 0 { | ||||||
if link, err = os.Readlink(filePath); err != nil { | ||||||
return fmt.Errorf("failed to read symlink for file %q: %s", filePath, err) | ||||||
} | ||||||
} | ||||||
tarHeader, err := tar.FileInfoHeader(stat, link) | ||||||
if err != nil { | ||||||
return fmt.Errorf("failed to create tar header for file %q: %s", filePath, err) | ||||||
} | ||||||
|
||||||
// The tar header name should be relative, so remove the sourceDir from it, | ||||||
// but preserve the last directory name. | ||||||
// Example: If we're tarring a file in ~/a/b/c/foo/bar.json | ||||||
// The name should be foo/bar.json | ||||||
sourceDirExceptLastDir := filepath.Dir(sourceDir) | ||||||
headerName := strings.TrimPrefix(filepath.Clean(filePath), filepath.Clean(sourceDirExceptLastDir)+"/") | ||||||
|
||||||
// Directories should end with a slash. | ||||||
if stat.IsDir() && !strings.HasSuffix(headerName, "/") { | ||||||
headerName += "/" | ||||||
} | ||||||
tarHeader.Name = headerName | ||||||
|
||||||
err = tarWriter.WriteHeader(tarHeader) | ||||||
if err != nil { | ||||||
return fmt.Errorf("failed to write tar header for file %q: %s", filePath, err) | ||||||
} | ||||||
|
||||||
// If it's not a regular file (e.g. link or directory) we shouldn't | ||||||
// copy the file. The body of a tar entry (i.e. what's done by the | ||||||
// below io.Copy call) is only required for tar files of TypeReg. | ||||||
if tarHeader.Typeflag != tar.TypeReg { | ||||||
return nil | ||||||
} | ||||||
|
||||||
_, err = io.Copy(tarWriter, file) | ||||||
if err != nil { | ||||||
return fmt.Errorf("failed to copy file %q into tarball: %s", filePath, err) | ||||||
} | ||||||
|
||||||
return nil | ||||||
} | ||||||
|
||||||
func pprofTarget(ctx context.Context, client *api.Client, target string, params url.Values) ([]byte, error) { | ||||||
req := client.NewRequest("GET", "/v1/sys/pprof/"+target) | ||||||
if params != nil { | ||||||
|
@@ -1008,7 +1095,7 @@ func pprofTarget(ctx context.Context, client *api.Client, target string, params | |||||
} | ||||||
defer resp.Body.Close() | ||||||
|
||||||
data, err := ioutil.ReadAll(resp.Body) | ||||||
data, err := io.ReadAll(resp.Body) | ||||||
if err != nil { | ||||||
return nil, err | ||||||
} | ||||||
|
@@ -1028,7 +1115,7 @@ func pprofProfile(ctx context.Context, client *api.Client, duration time.Duratio | |||||
} | ||||||
defer resp.Body.Close() | ||||||
|
||||||
data, err := ioutil.ReadAll(resp.Body) | ||||||
data, err := io.ReadAll(resp.Body) | ||||||
if err != nil { | ||||||
return nil, err | ||||||
} | ||||||
|
@@ -1048,7 +1135,7 @@ func pprofTrace(ctx context.Context, client *api.Client, duration time.Duration) | |||||
} | ||||||
defer resp.Body.Close() | ||||||
|
||||||
data, err := ioutil.ReadAll(resp.Body) | ||||||
data, err := io.ReadAll(resp.Body) | ||||||
if err != nil { | ||||||
return nil, err | ||||||
} | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😸