Merge pull request #5426 from hashicorp/fix_4915

Fix 4915
This commit is contained in:
Matthew Hooker 2018-02-05 14:54:27 -08:00 committed by GitHub
commit ff64ccda55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 115 additions and 9 deletions

View File

@ -105,6 +105,21 @@ func (c *Communicator) uploadReader(dst string, src io.Reader) error {
// uploadFile uses docker cp to copy the file from the host to the container
func (c *Communicator) uploadFile(dst string, src io.Reader, fi *os.FileInfo) error {
// find out if it's a directory
testDirectoryCommand := fmt.Sprintf(`test -d "%s"`, dst)
cmd := &packer.RemoteCmd{Command: testDirectoryCommand}
err := c.Start(cmd)
if err != nil {
log.Printf("Unable to check whether remote path is a dir: %s", err)
return err
}
cmd.Wait()
if cmd.ExitStatus == 0 {
log.Printf("path is a directory; copying file into directory.")
dst = filepath.Join(dst, filepath.Base((*fi).Name()))
}
// command format: docker cp /path/to/infile containerid:/path/to/outfile
log.Printf("Copying to %s on container %s.", dst, c.ContainerID)

View File

@ -73,6 +73,24 @@ func (c *LxcAttachCommunicator) Upload(dst string, r io.Reader, fi *os.FileInfo)
return err
}
if fi != nil {
tfDir := filepath.Dir(tf.Name())
// rename tempfile to match original file name. This makes sure that if file is being
// moved into a directory, the filename is preserved instead of a temp name.
adjustedTempName := filepath.Join(tfDir, (*fi).Name())
mvCmd, err := c.CmdWrapper(fmt.Sprintf("sudo mv %s %s", tf.Name(), adjustedTempName))
if err != nil {
return err
}
defer os.Remove(adjustedTempName)
ShellCommand(mvCmd).Run()
// change cpCmd to use new file name as source
cpCmd, err = c.CmdWrapper(fmt.Sprintf("sudo cp %s %s", adjustedTempName, dst))
if err != nil {
return err
}
}
log.Printf("Running copy command: %s", dst)
return ShellCommand(cpCmd).Run()

View File

@ -55,7 +55,24 @@ func (c *Communicator) Start(cmd *packer.RemoteCmd) error {
}
func (c *Communicator) Upload(dst string, r io.Reader, fi *os.FileInfo) error {
cpCmd, err := c.CmdWrapper(fmt.Sprintf("lxc file push - %s", filepath.Join(c.ContainerName, dst)))
fileDestination := filepath.Join(c.ContainerName, dst)
// find out if the place we are pushing to is a directory
testDirectoryCommand := fmt.Sprintf(`test -d "%s"`, dst)
cmd := &packer.RemoteCmd{Command: testDirectoryCommand}
err := c.Start(cmd)
if err != nil {
log.Printf("Unable to check whether remote path is a dir: %s", err)
return err
}
cmd.Wait()
if cmd.ExitStatus == 0 {
log.Printf("path is a directory; copying file into directory.")
fileDestination = filepath.Join(c.ContainerName, dst, (*fi).Name())
}
cpCmd, err := c.CmdWrapper(fmt.Sprintf("lxc file push - %s", fileDestination))
if err != nil {
return err
}

View File

@ -402,15 +402,31 @@ func (c *comm) connectToAgent() {
func (c *comm) sftpUploadSession(path string, input io.Reader, fi *os.FileInfo) error {
sftpFunc := func(client *sftp.Client) error {
return sftpUploadFile(path, input, client, fi)
return c.sftpUploadFile(path, input, client, fi)
}
return c.sftpSession(sftpFunc)
}
func sftpUploadFile(path string, input io.Reader, client *sftp.Client, fi *os.FileInfo) error {
func (c *comm) sftpUploadFile(path string, input io.Reader, client *sftp.Client, fi *os.FileInfo) error {
log.Printf("[DEBUG] sftp: uploading %s", path)
// find out if destination is a directory (this is to replicate rsync behavior)
testDirectoryCommand := fmt.Sprintf(`test -d "%s"`, path)
cmd := &packer.RemoteCmd{Command: testDirectoryCommand}
err := c.Start(cmd)
if err != nil {
log.Printf("Unable to check whether remote path is a dir: %s", err)
return err
}
cmd.Wait()
if cmd.ExitStatus == 0 {
log.Printf("path is a directory; copying file into directory.")
path = filepath.Join(path, filepath.Base((*fi).Name()))
}
f, err := client.Create(path)
if err != nil {
return err
@ -461,7 +477,7 @@ func (c *comm) sftpUploadDirSession(dst string, src string, excl []string) error
return nil
}
return sftpVisitFile(finalDst, path, info, client)
return c.sftpVisitFile(finalDst, path, info, client)
}
return filepath.Walk(src, walkFunc)
@ -470,7 +486,7 @@ func (c *comm) sftpUploadDirSession(dst string, src string, excl []string) error
return c.sftpSession(sftpFunc)
}
func sftpMkdir(path string, client *sftp.Client, fi os.FileInfo) error {
func (c *comm) sftpMkdir(path string, client *sftp.Client, fi os.FileInfo) error {
log.Printf("[DEBUG] sftp: creating dir %s", path)
if err := client.Mkdir(path); err != nil {
@ -488,16 +504,16 @@ func sftpMkdir(path string, client *sftp.Client, fi os.FileInfo) error {
return nil
}
func sftpVisitFile(dst string, src string, fi os.FileInfo, client *sftp.Client) error {
func (c *comm) sftpVisitFile(dst string, src string, fi os.FileInfo, client *sftp.Client) error {
if !fi.IsDir() {
f, err := os.Open(src)
if err != nil {
return err
}
defer f.Close()
return sftpUploadFile(dst, f, client, &fi)
return c.sftpUploadFile(dst, f, client, &fi)
} else {
err := sftpMkdir(dst, client, fi)
err := c.sftpMkdir(dst, client, fi)
return err
}
}
@ -558,6 +574,23 @@ func (c *comm) scpUploadSession(path string, input io.Reader, fi *os.FileInfo) e
target_dir := filepath.Dir(path)
target_file := filepath.Base(path)
// find out if destination is a directory (this is to replicate rsync behavior)
testDirectoryCommand := fmt.Sprintf(`test -d "%s"`, path)
cmd := &packer.RemoteCmd{Command: testDirectoryCommand}
err := c.Start(cmd)
if err != nil {
log.Printf("Unable to check whether remote path is a dir: %s", err)
return err
}
cmd.Wait()
if cmd.ExitStatus == 0 {
log.Printf("path is a directory; copying file into directory.")
target_dir = path
target_file = filepath.Base((*fi).Name())
}
// On windows, filepath.Dir uses backslash seperators (ie. "\tmp").
// This does not work when the target host is unix. Switch to forward slash
// which works for unix and windows

View File

@ -122,11 +122,28 @@ func runCommand(shell *winrm.Shell, cmd *winrm.Command, rc *packer.RemoteCmd) {
}
// Upload implementation of communicator.Communicator interface
func (c *Communicator) Upload(path string, input io.Reader, _ *os.FileInfo) error {
func (c *Communicator) Upload(path string, input io.Reader, fi *os.FileInfo) error {
wcp, err := c.newCopyClient()
if err != nil {
return err
}
// Get information about destination path
endpoint := winrm.NewEndpoint(c.endpoint.Host, c.endpoint.Port, c.config.Https, c.config.Insecure, nil, nil, nil, c.config.Timeout)
client, err := winrm.NewClient(endpoint, c.config.Username, c.config.Password)
if err != nil {
return fmt.Errorf("Was unable to create winrm client: %s", err)
}
stdout, _, _, err := client.RunWithString(fmt.Sprintf("powershell -Command \"(Get-Item %s) -is [System.IO.DirectoryInfo]\"", path), "")
if err != nil {
return fmt.Errorf("Couldn't determine whether destination was a folder or file: %s", err)
}
if strings.Contains(stdout, "True") {
// The path exists and is a directory.
// Upload file into the directory instead of overwriting.
path = filepath.Join(path, filepath.Base((*fi).Name()))
}
log.Printf("Uploading file to '%s'", path)
return wcp.Write(path, input)
}

View File

@ -48,6 +48,12 @@ func newMockWinRMServer(t *testing.T) *winrmtest.Remote {
func(out, err io.Writer) int {
return 0
})
wrm.CommandFunc(
winrmtest.MatchText(`powershell -Command "(Get-Item C:/Temp/packer.cmd) -is [System.IO.DirectoryInfo]"`),
func(out, err io.Writer) int {
out.Write([]byte("False"))
return 0
})
return wrm
}