Skip to content

Commit

Permalink
Merge pull request #2087 from shaloulcy/bugfix_for_populate_volume
Browse files Browse the repository at this point in the history
bugfix: populate volume error
  • Loading branch information
allencloud authored Aug 14, 2018
2 parents a4ecf83 + c2186ef commit 25a45e1
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 9 deletions.
12 changes: 3 additions & 9 deletions daemon/mgr/container_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"strconv"

"github.com/alibaba/pouch/apis/opts"
"github.com/alibaba/pouch/apis/types"
"github.com/alibaba/pouch/pkg/archive"
"github.com/alibaba/pouch/pkg/errtypes"
"github.com/alibaba/pouch/pkg/randomid"
"github.com/alibaba/pouch/pkg/system"
Expand Down Expand Up @@ -672,15 +672,9 @@ func copyImageContent(source, destination string) error {
return err
}
if len(dstList) == 0 {
// TODO: refactor

// If the source volume is empty, copies files from the root into the volume
commandLine := fmt.Sprintf("cp -r %s/* %s", source, destination)

cmd := exec.Command("sh", "-c", commandLine)
out, err := cmd.CombinedOutput()
err := archive.CopyWithTar(source, destination)
if err != nil {
logrus.Errorf("copyImageContent: %s, %v", string(out), err)
logrus.Errorf("copyImageContent: %v", err)
return err
}
}
Expand Down
116 changes: 116 additions & 0 deletions pkg/archive/archive.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package archive

import (
"archive/tar"
"bytes"
"fmt"
"io"
"os"
"path/filepath"
"strings"
)

func tarFromDir(src string, writer io.Writer) error {
// ensure the src actually exists before trying to tar it
if _, err := os.Stat(src); err != nil {
return fmt.Errorf("failed to stat source file %s: %v", src, err)
}

tw := tar.NewWriter(writer)
defer tw.Close()

// walk path
return filepath.Walk(src, func(file string, fi os.FileInfo, err error) error {
if err != nil {
return err
}

// create a new dir/file header
header, err := tar.FileInfoHeader(fi, fi.Name())
if err != nil {
return err
}

// update the name to correctly reflect the desired destination when untaring
header.Name = strings.TrimPrefix(strings.Replace(file, src, "", 1), string(filepath.Separator))
// write the header
if err := tw.WriteHeader(header); err != nil {
return err
}

if !fi.Mode().IsRegular() {
return nil
}

// open files for taring
f, err := os.Open(file)
if err != nil {
return err
}
defer f.Close()

// copy file data into tar writer
if _, err := io.Copy(tw, f); err != nil {
return err
}

return nil
})
}

func untarToDir(dst string, r io.Reader) error {
tr := tar.NewReader(r)

for {
header, err := tr.Next()

switch {
case err == io.EOF:
return nil
case err != nil:
return err
case header == nil:
continue
}

// the target location where the dir/file should be created
target := filepath.Join(dst, header.Name)

// check the file type
switch header.Typeflag {
case tar.TypeDir:
if _, err := os.Stat(target); err != nil {
if err := os.MkdirAll(target, 0755); err != nil {
return err
}
}
case tar.TypeReg:
f, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode))
if err != nil {
return err
}
defer f.Close()

if _, err := io.Copy(f, tr); err != nil {
return err
}
}
}
}

// CopyWithTar create a tar from src directory,
// and untar it in dst directory.
func CopyWithTar(src, dst string) error {
buf := new(bytes.Buffer)

if err := tarFromDir(src, buf); err != nil {
return err
}

if err := untarToDir(dst, buf); err != nil {
return err
}

return nil

}
79 changes: 79 additions & 0 deletions pkg/archive/archive_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package archive

import (
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"testing"

"github.com/alibaba/pouch/pkg/utils"
)

func TestCopyWithTar(t *testing.T) {
source, err := ioutil.TempDir("", "source")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(source)

destination, err := ioutil.TempDir("", "destination")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(destination)

files := []string{"file1", "file2", "dir1/file3", "dir2/file4"}

err = makeFiles(source, files)
if err != nil {
t.Fatal(err)
}

err = CopyWithTar(source, destination)
if err != nil {
t.Fatal(err)
}
actualFiles := targetFiles(destination)

if !utils.StringSliceEqual(files, actualFiles) {
t.Fatalf(" TestCopyWithTar expected get %v, but got %v", files, actualFiles)
}
}

func makeFiles(baseDir string, files []string) error {
for _, file := range files {
fullPath := path.Join(baseDir, file)

dir := path.Dir(fullPath)

// create dir.
err := os.MkdirAll(dir, 0755)
if err != nil {
return err
}

// create file.
fi, err := os.Create(fullPath)
if err != nil {
return err
}
fi.Close()
}

return nil
}

func targetFiles(baseDir string) []string {
files := []string{}

filepath.Walk(baseDir, func(name string, fi os.FileInfo, err error) error {
if fi.Mode().IsRegular() {
files = append(files, strings.TrimPrefix(name, baseDir+"/"))
}
return nil
})

return files
}
29 changes: 29 additions & 0 deletions pkg/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,32 @@ func IsFileExist(file string) bool {

return false
}

// StringSliceEqual compare two string slice, ignore the order.
func StringSliceEqual(s1, s2 []string) bool {
if s1 == nil && s2 == nil {
return true
}

if s1 == nil || s2 == nil {
return false
}

if len(s1) != len(s2) {
return false
}

for _, s := range s1 {
if !StringInSlice(s2, s) {
return false
}
}

for _, s := range s2 {
if !StringInSlice(s1, s) {
return false
}
}

return true
}
21 changes: 21 additions & 0 deletions pkg/utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -523,3 +523,24 @@ func TestIsFileExist(t *testing.T) {
assert.Equal(IsFileExist(t.path), t.exist)
}
}

func TestStringSliceEqual(t *testing.T) {
tests := []struct {
s1 []string
s2 []string
equal bool
}{
{nil, nil, true},
{nil, []string{"a"}, false},
{[]string{"a"}, []string{"a"}, true},
{[]string{"a"}, []string{"b", "a"}, false},
{[]string{"a", "b"}, []string{"b", "a"}, true},
}

for _, test := range tests {
result := StringSliceEqual(test.s1, test.s2)
if result != test.equal {
t.Fatalf("StringSliceEqual(%v, %v) expected: %v, but got %v", test.s1, test.s2, test.equal, result)
}
}
}

0 comments on commit 25a45e1

Please sign in to comment.