Skip to content

Commit

Permalink
feat(fetch): supports using flag '-s/--run.sudo' (#20)
Browse files Browse the repository at this point in the history
For copying files and directories on target hosts to which the user does not have access permission.

Fixes #20.
  • Loading branch information
windvalley committed Jan 11, 2022
1 parent 8d3d6f6 commit a0371bc
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 66 deletions.
2 changes: 1 addition & 1 deletion internal/cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ hosts:
port: %d
run:
# Use sudo to execute the command.
# Use sudo to execute command/script or fetch files/dirs.
# Default: false
sudo: %v
Expand Down
8 changes: 7 additions & 1 deletion internal/cmd/fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,13 @@ Copy files/dirs from target hosts to local.`,
# Specify tmp dir on target host instead of default /tmp by flag '-t'.
# NOTE: If the tmp dir not exist, it will auto create it.
$ gossh fetch host1 -f /path/foo.txt -d ./backup/ -t /home/user/tmp/`,
$ gossh fetch host1 -f /path/foo.txt -d ./backup/ -t /home/user/tmp/
# Use sudo as root to copy no permission files.
$ gossh fetch host1 -f /root/foo.txt -d ./backup/ -s
# Use sudo as 'zhangsan' to copy no permission files.
$ gossh fetch host1 -f /home/zhangsan/foo.txt -d ./backup -s -U zhangsan`,
PreRun: func(cmd *cobra.Command, args []string) {
if errs := config.Validate(); len(errs) != 0 {
util.CheckErr(errs)
Expand Down
2 changes: 1 addition & 1 deletion internal/pkg/configflags/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func NewRun() *Run {

// AddFlagsTo ...
func (r *Run) AddFlagsTo(flags *pflag.FlagSet) {
flags.BoolVarP(&r.Sudo, flagRunSudo, "s", r.Sudo, "use sudo to execute commands/script")
flags.BoolVarP(&r.Sudo, flagRunSudo, "s", r.Sudo, "use sudo to execute commands/script or fetch files/dirs")
flags.StringVarP(&r.AsUser, flagRunAsUser, "U", r.AsUser, "run via sudo as this user")
flags.StringVarP(
&r.Lang,
Expand Down
2 changes: 1 addition & 1 deletion internal/pkg/sshtask/sshtask.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func (t *Task) RunSSH(addr string) (string, error) {
case PushTask:
return t.sshClient.PushFiles(addr, t.pushFiles.files, t.pushFiles.zipFiles, t.dstDir, t.allowOverwrite)
case FetchTask:
return t.sshClient.FetchFiles(addr, t.fetchFiles, t.dstDir, t.tmpDir)
return t.sshClient.FetchFiles(addr, t.fetchFiles, t.dstDir, t.tmpDir, sudo, runAs)
default:
return "", fmt.Errorf("unknown task type: %v", t.taskType)
}
Expand Down
135 changes: 73 additions & 62 deletions pkg/batchssh/batchssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,62 @@ func (c *Client) ExecuteCmd(addr, command, lang, runAs string, sudo bool) (strin
return c.executeCmd(session, command)
}

// ExecuteScript on remote host.
func (c *Client) ExecuteScript(
addr, srcFile, dstDir, lang, runAs string,
sudo, remove, allowOverwrite bool,
) (string, error) {
client, err := c.getClient(addr)
if err != nil {
return "", err
}
defer client.Close()

ftpC, err := sftp.NewClient(client)
if err != nil {
return "", err
}
defer ftpC.Close()

file, err := c.pushFile(ftpC, srcFile, dstDir, allowOverwrite)
if err != nil {
return "", err
}

//nolint:gomnd,govet
if err := file.Chmod(0755); err != nil {
return "", err
}

script := file.Name()
file.Close()

session, err := client.NewSession()
if err != nil {
return "", err
}
defer session.Close()

exportLang := ""
if lang != "" {
exportLang = fmt.Sprintf(exportLangPattern, lang, lang, lang)
}

command := ""
switch {
case sudo && remove:
command = fmt.Sprintf("%ssudo -u %s -H bash -c '%s;rm -f %s'", exportLang, runAs, script, script)
case sudo && !remove:
command = fmt.Sprintf("%ssudo -u %s -H bash -c '%s'", exportLang, runAs, script)
case !sudo && remove:
command = fmt.Sprintf("%s%s;rm -f %s", exportLang, script, script)
case !sudo && !remove:
command = exportLang + script
}

return c.executeCmd(session, command)
}

// PushFiles to remote host.
func (c *Client) PushFiles(
addr string,
Expand Down Expand Up @@ -281,6 +337,8 @@ func (c *Client) FetchFiles(
addr string,
srcFiles []string,
dstDir, tmpDir string,
sudo bool,
runAs string,
) (string, error) {
client, err := c.getClient(addr)
if err != nil {
Expand All @@ -306,9 +364,11 @@ func (c *Client) FetchFiles(
continue
}

if err, ok := err1.(*sftp.StatusError); ok && err.Code == uint32(sftp.ErrSshFxPermissionDenied) {
noPermSrcFiles = append(noPermSrcFiles, f)
continue
if !sudo {
if err, ok := err1.(*sftp.StatusError); ok && err.Code == uint32(sftp.ErrSshFxPermissionDenied) {
noPermSrcFiles = append(noPermSrcFiles, f)
continue
}
}
}

Expand Down Expand Up @@ -343,8 +403,15 @@ func (c *Client) FetchFiles(
_, err = c.executeCmd(
session,
fmt.Sprintf(
`which zip &>/dev/null && { mkdir -p %s;zip -r %s %s;} ||
{ echo "need install 'zip' command";exit 1;}`,
`if which zip &>/dev/null;then
sudo -u %s -H bash -c '[[ ! -d %s ]] && { mkdir -p %s;chmod 777 %s;};zip -r %s %s'
else
echo "need install 'zip' command"
exit 1
fi`,
runAs,
zippedFileTmpDir,
zippedFileTmpDir,
zippedFileTmpDir,
zippedFileFullpath,
strings.Join(validSrcFiles, " "),
Expand Down Expand Up @@ -372,7 +439,7 @@ func (c *Client) FetchFiles(

_, err = c.executeCmd(
session2,
fmt.Sprintf("rm -f %s", zippedFileFullpath),
fmt.Sprintf("sudo -u %s -H bash -c 'rm -f %s'", runAs, zippedFileFullpath),
)
if err != nil {
log.Debugf("remove '%s:%s' failed: %s", addr, zippedFileFullpath, err)
Expand Down Expand Up @@ -431,62 +498,6 @@ func (c *Client) FetchFiles(
return ret, nil
}

// ExecuteScript on remote host.
func (c *Client) ExecuteScript(
addr, srcFile, dstDir, lang, runAs string,
sudo, remove, allowOverwrite bool,
) (string, error) {
client, err := c.getClient(addr)
if err != nil {
return "", err
}
defer client.Close()

ftpC, err := sftp.NewClient(client)
if err != nil {
return "", err
}
defer ftpC.Close()

file, err := c.pushFile(ftpC, srcFile, dstDir, allowOverwrite)
if err != nil {
return "", err
}

//nolint:gomnd,govet
if err := file.Chmod(0755); err != nil {
return "", err
}

script := file.Name()
file.Close()

session, err := client.NewSession()
if err != nil {
return "", err
}
defer session.Close()

exportLang := ""
if lang != "" {
exportLang = fmt.Sprintf(exportLangPattern, lang, lang, lang)
}

command := ""
switch {
case sudo && remove:
command = fmt.Sprintf("%ssudo -u %s -H bash -c '%s;rm -f %s'", exportLang, runAs, script, script)
case sudo && !remove:
command = fmt.Sprintf("%ssudo -u %s -H bash -c '%s'", exportLang, runAs, script)
case !sudo && remove:
command = fmt.Sprintf("%s%s;rm -f %s", exportLang, script, script)
case !sudo && !remove:
command = exportLang + script
}

return c.executeCmd(session, command)
}

func (c *Client) executeCmd(session *ssh.Session, command string) (string, error) {
modes := ssh.TerminalModes{
ssh.ECHO: 0,
Expand Down

0 comments on commit a0371bc

Please sign in to comment.