Skip to content
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

feat: supports adding files inside the VM to support bundles #549

Merged
merged 1 commit into from
Sep 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/finch/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ var newApp = func(logger flog.Logger, fp path.Finch, fs afero.Fs, fc *config.Fin
support.NewBundleConfig(fp, system.NewStdLib().Env("HOME")),
fp,
ecc,
lcc,
wrapper.NewLimaWrapper(),
)

Expand Down
3 changes: 2 additions & 1 deletion cmd/finch/support_bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ func newSupportBundleGenerateCommand(logger flog.Logger, builder support.BundleB
}

supportBundleGenerateCommand.Flags().StringArray("include", []string{},
"additional files to include in the support bundle, specified by absolute or relative path")
//nolint:lll // usage string
`additional files to include in the support bundle, specified by absolute or relative path. to include a file from the VM, prefix the file path with "vm:"`)
supportBundleGenerateCommand.Flags().StringArray("exclude", []string{},
//nolint:lll // usage string
"files to exclude from the support bundle. if you specify a base name, all files matching that base name will be excluded. if you specify an absolute or relative path, only exact matches will be excluded")
Expand Down
2 changes: 2 additions & 0 deletions pkg/command/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ type Command interface {
SetStderr(io.Writer)

Run() error
Start() error
Wait() error
Output() ([]byte, error)
CombinedOutput() ([]byte, error)
}
28 changes: 28 additions & 0 deletions pkg/mocks/command_command.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

114 changes: 92 additions & 22 deletions pkg/support/support.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package support

import (
"archive/zip"
"bufio"
"bytes"
"errors"
"fmt"
Expand Down Expand Up @@ -51,6 +52,7 @@ type bundleBuilder struct {
config BundleConfig
finch fpath.Finch
ecc command.Creator
lcc command.LimaCmdCreator
lima wrapper.LimaWrapper
}

Expand All @@ -61,6 +63,7 @@ func NewBundleBuilder(
config BundleConfig,
finch fpath.Finch,
ecc command.Creator,
lcc command.LimaCmdCreator,
lima wrapper.LimaWrapper,
) BundleBuilder {
return &bundleBuilder{
Expand All @@ -69,6 +72,7 @@ func NewBundleBuilder(
config: config,
finch: finch,
ecc: ecc,
lcc: lcc,
lima: lima,
}
}
Expand Down Expand Up @@ -108,7 +112,8 @@ func (bb *bundleBuilder) GenerateSupportBundle(additionalFiles []string, exclude
bb.logger.Infof("Excluding %s...", file)
continue
}
err := bb.copyInFile(writer, file, path.Join(zipPrefix, logPrefix))
bb.logger.Debugf("Copying %s...", file)
err = bb.copyFileFromVMOrLocal(writer, file, path.Join(zipPrefix, logPrefix))
if err != nil {
bb.logger.Warnf("Could not copy in %q. Error: %s", file, err)
}
Expand All @@ -120,7 +125,8 @@ func (bb *bundleBuilder) GenerateSupportBundle(additionalFiles []string, exclude
bb.logger.Infof("Excluding %s...", file)
continue
}
err := bb.copyInFile(writer, file, path.Join(zipPrefix, configPrefix))
bb.logger.Debugf("Copying %s...", file)
err = bb.copyFileFromVMOrLocal(writer, file, path.Join(zipPrefix, configPrefix))
if err != nil {
bb.logger.Warnf("Could not copy in %q. Error: %s", file, err)
}
Expand All @@ -132,7 +138,8 @@ func (bb *bundleBuilder) GenerateSupportBundle(additionalFiles []string, exclude
bb.logger.Infof("Excluding %s...", file)
continue
}
err := bb.copyInFile(writer, file, path.Join(zipPrefix, additionalPrefix))
bb.logger.Debugf("Copying %s...", file)
err = bb.copyFileFromVMOrLocal(writer, file, path.Join(zipPrefix, additionalPrefix))
if err != nil {
bb.logger.Warnf("Could not add additional file %s. Error: %s", file, err)
}
Expand All @@ -146,30 +153,28 @@ func (bb *bundleBuilder) GenerateSupportBundle(additionalFiles []string, exclude
return zipFileName, nil
}

func (bb *bundleBuilder) copyInFile(writer *zip.Writer, fileName string, prefix string) error {
f, err := bb.fs.Open(fileName)
if err != nil {
return err
}

bb.logger.Debugf("Copying %s...", fileName)
type bufReader interface {
ReadBytes(delim byte) ([]byte, error)
}

var buf bytes.Buffer
_, err = buf.ReadFrom(f)
if err != nil {
return err
func (bb *bundleBuilder) copyFileFromVMOrLocal(writer *zip.Writer, filename, zipPath string) error {
if isFileFromVM(filename) {
return bb.streamFileFromVM(writer, filename, zipPath)
}
return bb.copyInFile(writer, filename, zipPath)
}

var redacted []byte
func (bb *bundleBuilder) copyAndRedactFile(writer io.Writer, reader bufReader) error {
var bufErr error
for bufErr == nil {
var line []byte
line, bufErr = buf.ReadBytes('\n')
line, bufErr = reader.ReadBytes('\n')
if bufErr != nil && !errors.Is(bufErr, io.EOF) {
bb.logger.Error(bufErr.Error())
continue
}

line, err = redactFinchInstall(line, bb.finch)
line, err := redactFinchInstall(line, bb.finch)
if err != nil {
return err
}
Expand All @@ -187,7 +192,20 @@ func (bb *bundleBuilder) copyInFile(writer *zip.Writer, fileName string, prefix
line = redactPorts(line)
line = redactSSHKeys(line)

redacted = append(redacted, line...)
_, err = writer.Write(line)
if err != nil {
return err
}
}

return nil
}

func (bb *bundleBuilder) copyInFile(writer *zip.Writer, fileName string, prefix string) error {
// check filename validity?
f, err := bb.fs.Open(fileName)
if err != nil {
return err
}

baseName := path.Base(fileName)
Expand All @@ -196,12 +214,56 @@ func (bb *bundleBuilder) copyInFile(writer *zip.Writer, fileName string, prefix
return err
}

_, err = zipCopy.Write(redacted)
buf := new(bytes.Buffer)
_, err = buf.ReadFrom(f)
if err != nil {
return err
}

return nil
return bb.copyAndRedactFile(zipCopy, buf)
}

func (bb *bundleBuilder) streamFileFromVM(writer *zip.Writer, filename, prefix string) error {
pipeReader, pipeWriter := io.Pipe()
errBuf := new(bytes.Buffer)

_, filePathInVM, _ := strings.Cut(filename, ":")
cmd := bb.lcc.CreateWithoutStdio("shell", "finch", "sudo", "cat", filePathInVM)
cmd.SetStdout(pipeWriter)
cmd.SetStderr(errBuf)

err := cmd.Start()
if err != nil {
return err
}

waitStatus := make(chan error)
go func() {
err := cmd.Wait()
if err != nil {
errorMsg, readErr := io.ReadAll(errBuf)
if readErr == nil && len(errorMsg) > 0 {
err = errors.New(string(errorMsg))
}
}
_ = pipeWriter.Close()
waitStatus <- err
mharwani marked this conversation as resolved.
Show resolved Hide resolved
}()

baseName := path.Base(filename)
zipCopy, err := writer.Create(path.Join(prefix, baseName))
if err != nil {
return err
}

bufReader := bufio.NewReader(pipeReader)

err = bb.copyAndRedactFile(zipCopy, bufReader)
if err != nil {
return err
}

return <-waitStatus
}

func (bb *bundleBuilder) getPlatformData() (*PlatformData, error) {
Expand Down Expand Up @@ -280,7 +342,11 @@ func bundleFileName() string {
}

func fileShouldBeExcluded(filename string, exclude []string) bool {
fileAbs, err := filepath.Abs(filename)
realFilename := filename
if isFileFromVM(filename) {
_, realFilename, _ = strings.Cut(filename, ":")
}
fileAbs, err := filepath.Abs(realFilename)
if err != nil {
return true
}
Expand All @@ -292,9 +358,13 @@ func fileShouldBeExcluded(filename string, exclude []string) bool {
if fileAbs == excludeAbs {
return true
}
if path.Base(filename) == excludeFile {
if path.Base(realFilename) == excludeFile {
return true
}
}
return false
}

func isFileFromVM(filename string) bool {
return strings.HasPrefix(filename, "vm:")
}
Loading
Loading