Skip to content

Commit

Permalink
Fix bug with DockerExecutor's CopyFile
Browse files Browse the repository at this point in the history
The check to see if the source path was in the tgz archive was wrong
when source path was a folder, the arguments to strings.Contains were
inverted.
  • Loading branch information
duboisf committed Mar 21, 2019
1 parent 4bfbb20 commit ac0b320
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 27 deletions.
26 changes: 8 additions & 18 deletions util/file/fileutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,27 @@ import (
"encoding/base64"
"io"
"io/ioutil"
"os"
"strings"

log "github.com/sirupsen/logrus"
)

// IsFileOrDirExistInGZip return true if file or directory exists in GZip file
func IsFileOrDirExistInGZip(sourcePath string, gzipFilePath string) bool {

fi, err := os.Open(gzipFilePath)

if os.IsNotExist(err) {
return false
}
defer close(fi)
type TarReader interface {
Next() (*tar.Header, error)
}

fz, err := gzip.NewReader(fi)
if err != nil {
return false
}
tr := tar.NewReader(fz)
// ExistsInTar return true if file or directory exists in tar
func ExistsInTar(sourcePath string, tarReader TarReader) bool {
sourcePath = strings.Trim(sourcePath, "/")
for {
hdr, err := tr.Next()
hdr, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {

return false
}
if hdr.FileInfo().IsDir() && strings.Contains(strings.Trim(hdr.Name, "/"), strings.Trim(sourcePath, "/")) {
if hdr.FileInfo().IsDir() && strings.Contains(sourcePath, strings.Trim(hdr.Name, "/")) {
return true
}
if strings.Contains(sourcePath, hdr.Name) && hdr.Size > 0 {
Expand Down
110 changes: 105 additions & 5 deletions util/file/fileutil_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package file
package file_test

import (
"testing"

"archive/tar"
"bytes"
"github.com/argoproj/argo/util/file"
"github.com/stretchr/testify/assert"
"os"
"testing"
)

// TestResubmitWorkflowWithOnExit ensures we do not carry over the onExit node even if successful
Expand All @@ -13,9 +16,106 @@ func TestCompressContentString(t *testing.T) {
"\"Succeeded\",\"boundaryID\":\"pod-limits-rrdm8\",\"startedAt\":\"2019-03-07T19:14:50Z\",\"finishedAt\":" +
"\"2019-03-07T19:14:55Z\"}}"

compString := CompressEncodeString(content)
compString := file.CompressEncodeString(content)

resultString, _ := DecodeDecompressString(compString)
resultString, _ := file.DecodeDecompressString(compString)

assert.Equal(t, content, resultString)
}

func TestExistsInTar(t *testing.T) {
type fakeFile struct {
name, body string
isDir bool
}

newTarReader := func(t *testing.T, files []fakeFile) *tar.Reader {
var buf bytes.Buffer
writer := tar.NewWriter(&buf)
for _, f := range files {
mode := os.FileMode(0600)
if f.isDir {
mode |= os.ModeDir
}
hdr := tar.Header{Name: f.name, Mode: int64(mode), Size: int64(len(f.body))}
err := writer.WriteHeader(&hdr)
assert.Nil(t, err)
_, err = writer.Write([]byte(f.body))
assert.Nil(t, err)
}
err := writer.Close()
assert.Nil(t, err)
return tar.NewReader(&buf)
}

type TestCase struct {
sourcePath string
expected bool
files []fakeFile
}

tests := []TestCase{
{
sourcePath: "/root.txt", expected: true,
files: []fakeFile{{name: "root.txt", body: "file in the root"}},
},
{
sourcePath: "/tmp/file/in/subfolder.txt", expected: true,
files: []fakeFile{{name: "subfolder.txt", body: "a file in a subfolder"}},
},
{
sourcePath: "/root", expected: true,
files: []fakeFile{
{name: "root/", isDir: true},
{name: "root/a.txt", body: "a"},
{name: "root/b.txt", body: "b"},
},
},
{
sourcePath: "/tmp/subfolder", expected: true,
files: []fakeFile{
{name: "subfolder/", isDir: true},
{name: "subfolder/a.txt", body: "a"},
{name: "subfolder/b.txt", body: "b"},
},
},
{
// should an empty tar return true??
sourcePath: "/tmp/empty", expected: true,
files: []fakeFile{
{name: "empty/", isDir: true},
},
},
{
sourcePath: "/tmp/folder/that", expected: false,
files: []fakeFile{
{name: "this/", isDir: true},
{name: "this/a.txt", body: "a"},
{name: "this/b.txt", body: "b"},
},
},
{
sourcePath: "/empty.txt", expected: false,
files: []fakeFile{
// fails because empty.txt is empty
{name: "empty.txt", body: ""},
},
},
{
sourcePath: "/tmp/empty.txt", expected: false,
files: []fakeFile{
// fails because empty.txt is empty
{name: "empty.txt", body: ""},
},
},
}
for _, tc := range tests {
tc := tc
t.Run("source path "+tc.sourcePath, func(t *testing.T) {
t.Parallel()
tarReader := newTarReader(t, tc.files)
actual := file.ExistsInTar(tc.sourcePath, tarReader)
assert.Equalf(t, tc.expected, actual, "sourcePath %s not found", tc.sourcePath)
})
}
}
17 changes: 13 additions & 4 deletions workflow/executor/docker/docker.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package docker

import (
"archive/tar"
"compress/gzip"
"fmt"
"os"
"os/exec"
Expand Down Expand Up @@ -53,10 +55,17 @@ func (d *DockerExecutor) CopyFile(containerID string, sourcePath string, destPat
if err != nil {
return err
}
if !file.IsFileOrDirExistInGZip(sourcePath, destPath) {
errMsg := fmt.Sprintf("File or Artifact does not exist. %s", sourcePath)
log.Warn(errMsg)
return errors.InternalError(errMsg)
copiedFile, err := os.Open(destPath)
if err != nil {
return err
}
defer util.Close(copiedFile)
gzipReader, err := gzip.NewReader(copiedFile)
if err != nil {
return err
}
if !file.ExistsInTar(sourcePath, tar.NewReader(gzipReader)) {
return errors.InternalErrorf("path %s does not exist (or %s is empty) in archive %s", sourcePath, sourcePath, destPath)
}
log.Infof("Archiving completed")
return nil
Expand Down

0 comments on commit ac0b320

Please sign in to comment.