Skip to content

Commit

Permalink
Move copyfiles function to client-go
Browse files Browse the repository at this point in the history
Resolves #443

This PR will remove dependency of oc binary for `copyfiles` function which copies file to component while `odo push`
  • Loading branch information
surajnarwade committed Jun 7, 2018
1 parent 3b5940e commit add8f0f
Show file tree
Hide file tree
Showing 3 changed files with 254 additions and 172 deletions.
8 changes: 1 addition & 7 deletions pkg/component/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,17 +175,11 @@ func PushLocal(client *occlient.Client, componentName string, applicationName st
if err != nil {
return errors.Wrapf(err, "error while waiting for pod %s", podSelector)
}
var syncOutput string
if !asFile {
syncOutput, err = client.RsyncPath(path, pod.Name, targetPath)
} else {
syncOutput, err = client.CopyFile(path, pod.Name, targetPath)

}
err = client.CopyFile(asFile, path, pod.Name, targetPath)
if err != nil {
return errors.Wrap(err, "unable push files to pod")
}
fmt.Fprintf(out, syncOutput)
fmt.Fprintf(out, "Please wait, building component....\n")

// use pipes to write output from ExecCMDInContainer in yellow to 'out' io.Writer
Expand Down
242 changes: 166 additions & 76 deletions pkg/occlient/occlient.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package occlient

import (
taro "archive/tar"
"bytes"
"compress/gzip"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net"
"net/url"
"os"
"os/exec"
"path"
"path/filepath"
"strconv"
"strings"
Expand Down Expand Up @@ -134,8 +137,8 @@ func New() (*Client, error) {
}
client.namespace = namespace

// The following should go away once we're done with complete migration to
// client-go
//The following should go away once we're done with complete migration to
//client-go
ocpath, err := getOcBinary()
if err != nil {
return nil, errors.Wrap(err, "unable to get oc binary")
Expand Down Expand Up @@ -241,55 +244,56 @@ func getOcBinary() (string, error) {
return ocPath, nil
}

type OcCommand struct {
args []string
data *string
format string
}
//
//type OcCommand struct {
// args []string
// data *string
// format string
//}

// runOcCommands executes oc
// args - command line arguments to be passed to oc ('-o json' is added by default if data is not nil)
// data - is a pointer to a string, if set than data is given to command to stdin ('-f -' is added to args as default)
func (c *Client) runOcComamnd(command *OcCommand) ([]byte, error) {
cmd := exec.Command(c.ocpath, command.args...)

// if data is not set assume that it is get command
if len(command.format) > 0 {
cmd.Args = append(cmd.Args, "-o", command.format)
}
if command.data != nil {
// data is given, assume this is create or apply command
// that takes data from stdin
cmd.Args = append(cmd.Args, "-f", "-")

// Read from stdin
stdin, err := cmd.StdinPipe()
if err != nil {
return nil, err
}

// Write to stdin
go func() {
defer stdin.Close()
_, err := io.WriteString(stdin, *command.data)
if err != nil {
fmt.Printf("can't write to stdin %v\n", err)
}
}()
}

log.Debugf("running oc command with arguments: %s\n", strings.Join(cmd.Args, " "))

output, err := cmd.CombinedOutput()
if err != nil {
if _, ok := err.(*exec.ExitError); ok {
return nil, errors.Wrapf(err, "command: %v failed to run:\n%v", cmd.Args, string(output))
}
return nil, errors.Wrap(err, "unable to get combined output")
}

return output, nil
}
//func (c *Client) runOcComamnd(command *OcCommand) ([]byte, error) {
// cmd := exec.Command(c.ocpath, command.args...)
//
// // if data is not set assume that it is get command
// if len(command.format) > 0 {
// cmd.Args = append(cmd.Args, "-o", command.format)
// }
// if command.data != nil {
// // data is given, assume this is create or apply command
// // that takes data from stdin
// cmd.Args = append(cmd.Args, "-f", "-")
//
// // Read from stdin
// stdin, err := cmd.StdinPipe()
// if err != nil {
// return nil, err
// }
//
// // Write to stdin
// go func() {
// defer stdin.Close()
// _, err := io.WriteString(stdin, *command.data)
// if err != nil {
// fmt.Printf("can't write to stdin %v\n", err)
// }
// }()
// }
//
// log.Debugf("running oc command with arguments: %s\n", strings.Join(cmd.Args, " "))
//
// output, err := cmd.CombinedOutput()
// if err != nil {
// if _, ok := err.(*exec.ExitError); ok {
// return nil, errors.Wrapf(err, "command: %v failed to run:\n%v", cmd.Args, string(output))
// }
// return nil, errors.Wrap(err, "unable to get combined output")
// }
//
// return output, nil
//}

func isLoggedIn(ocpath string) bool {
cmd := exec.Command(ocpath, "whoami")
Expand Down Expand Up @@ -1546,46 +1550,132 @@ func (c *Client) GetOnePodFromSelector(selector string) (*corev1.Pod, error) {
return &pods.Items[0], nil
}

// RsyncPath copies local directory to directory in running Pod.
func (c *Client) RsyncPath(localPath string, targetPodName string, targetPath string) (string, error) {
log.Debugf("Syncing %s to pod %s:%s", localPath, targetPodName, targetPath)
//// RsyncPath copies local directory to directory in running Pod.
//func (c *Client) RsyncPath(localPath string, targetPodName string, targetPath string) (string, error) {
// log.Debugf("Syncing %s to pod %s:%s", localPath, targetPodName, targetPath)
//
// // TODO: do this without using 'oc' binary
// args := []string{
// "rsync",
// localPath,
// fmt.Sprintf("%s:%s", targetPodName, targetPath),
// "--exclude", ".git",
// "--no-perms",
// }
//
// output, err := c.runOcComamnd(&OcCommand{args: args})
// if err != nil {
// return "", err
// }
//
// log.Debugf("command output:\n %s \n", string(output[:]))
// return string(output[:]), nil
//}

// TODO: do this without using 'oc' binary
args := []string{
"rsync",
localPath,
fmt.Sprintf("%s:%s", targetPodName, targetPath),
"--exclude", ".git",
"--no-perms",
}
// CopyFile copies single local file to the directory in running Pod.
func (c *Client) CopyFile(asFile bool, localFile string, targetPodName string, targetPath string) error {
log.Debugf("Copying file %s to pod %s:%s", localFile, targetPodName, targetPath)

dest := targetPath + "/" + path.Base(localFile)

reader, writer := io.Pipe()

go func() {
defer writer.Close()
err := makeTar(localFile, dest, writer)
if err != nil {
os.Exit(-1)
}

output, err := c.runOcComamnd(&OcCommand{args: args})
}()

var cmdArr []string

if !asFile {
cmdArr = []string{"tar", "xf", "-", "-C", targetPath, "--strip", "1"}
} else {
cmdArr = []string{"tar", "xf", "-", "-C", targetPath}
}
//cmdArr := []string{"tar", "-C", targetPath, "-ox", "-v"}
err := c.ExecCMDInContainer(targetPodName, cmdArr, writer, writer, reader, false)
if err != nil {
return "", err
return err
}

log.Debugf("command output:\n %s \n", string(output[:]))
return string(output[:]), nil
return nil
}

// CopyFile copies single local file to the directory in running Pod.
func (c *Client) CopyFile(localFile string, targetPodName string, targetPath string) (string, error) {
log.Debugf("Copying file %s to pod %s:%s", localFile, targetPodName, targetPath)
func makeTar(srcPath, destPath string, writer io.Writer) error {
// TODO: use compression here?
tarWriter := taro.NewWriter(writer)
defer tarWriter.Close()

// TODO: do this without using 'oc' binary
args := []string{
"cp",
localFile,
fmt.Sprintf("%s:%s", targetPodName, targetPath),
}
srcPath = path.Clean(srcPath)
destPath = path.Clean(destPath)
return recursiveTar(path.Dir(srcPath), path.Base(srcPath), path.Dir(destPath), path.Base(destPath), tarWriter)
}

output, err := c.runOcComamnd(&OcCommand{args: args})
func recursiveTar(srcBase, srcFile, destBase, destFile string, tw *taro.Writer) error {
filepath := path.Join(srcBase, srcFile)
stat, err := os.Lstat(filepath)
if err != nil {
return "", err
return err
}
if stat.IsDir() {
files, err := ioutil.ReadDir(filepath)
if err != nil {
return err
}
if len(files) == 0 {
//case empty directory
hdr, _ := taro.FileInfoHeader(stat, filepath)
hdr.Name = destFile
if err := tw.WriteHeader(hdr); err != nil {
return err
}
}
for _, f := range files {
if err := recursiveTar(srcBase, path.Join(srcFile, f.Name()), destBase, path.Join(destFile, f.Name()), tw); err != nil {
return err
}
}
return nil
} else if stat.Mode()&os.ModeSymlink != 0 {
//case soft link
hdr, _ := taro.FileInfoHeader(stat, filepath)
target, err := os.Readlink(filepath)
if err != nil {
return err
}

log.Debugf("command output:\n %s \n", string(output[:]))
return string(output[:]), nil
hdr.Linkname = target
hdr.Name = destFile
if err := tw.WriteHeader(hdr); err != nil {
return err
}
} else {
//case regular file or other file type like pipe
hdr, err := taro.FileInfoHeader(stat, filepath)
if err != nil {
return err
}
hdr.Name = destFile

if err := tw.WriteHeader(hdr); err != nil {
return err
}

f, err := os.Open(filepath)
if err != nil {
return err
}
defer f.Close()

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

// GetOneServiceFromSelector returns the Service object associated with the
Expand Down

0 comments on commit add8f0f

Please sign in to comment.