sshkit icon indicating copy to clipboard operation
sshkit copied to clipboard

Bug: upload! within an `as 'root'` block will fail.

Open troelskn opened this issue 9 years ago • 6 comments

The following will usually fail:

  task :foo do
    on roles(:web) do
      as "root" do
        upload! "/tmp/foo", "/var/bar/cuux"
      end
    end
  end

Since scp will not su to root. Would you accept a PR that allows upload! to upload to /tmp and then mv the file into place, if the current user has been switched?

troelskn avatar Feb 09 '16 08:02 troelskn

I'd consider a helper function that wrapped both, but not a change to the upload! api.

leehambley avatar Feb 09 '16 14:02 leehambley

I haven't tested this, but maybe it would work?

on roles(:web) do |host|
  host.user = "root"
  upload! "/tmp/foo", "/var/bar/cuux"
end

mattbrictson avatar Feb 09 '16 16:02 mattbrictson

@mattbrictson won't work if the root user can't login (Which is default for Ubuntu images an aws anyway).

troelskn avatar Feb 09 '16 19:02 troelskn

Ah, then the helper method you described is probably the best bet.

mattbrictson avatar Feb 09 '16 19:02 mattbrictson

What if the behaviour required an explicit option to be set. E.g.:

  task :foo do
    on roles(:web) do
      as "root", file_transfer: true do
        upload! "/tmp/foo", "/var/bar/cuux"
      end
    end
  end

Not sure if I disagree with your stance btw. - I'm just thinking out loud here.

troelskn avatar Feb 09 '16 19:02 troelskn

Here's a helper that I use in my own projects. Maybe we could adapt it to be useful for both of our cases and add it to core?

# Uploads the given string or file-like object to the current host
# context. Accepts :owner and :mode options that affect the permissions of the
# remote file.
#
def put(string_or_io, remote_path, opts={})
  sudo_exec = ->(*cmd) {
    cmd = [:sudo] + cmd if opts[:sudo]
    execute *cmd
  }

  tmp_path = "/tmp/#{SecureRandom.uuid}"

  owner = opts[:owner]
  mode = opts[:mode]

  source = if string_or_io.respond_to?(:read)
    string_or_io
  else
    StringIO.new(string_or_io.to_s)
  end

  sudo_exec.call :mkdir, "-p", File.dirname(remote_path)

  upload!(source, tmp_path)

  sudo_exec.call(:mv, "-f", tmp_path, remote_path)
  sudo_exec.call(:chown, owner, remote_path) if owner
  sudo_exec.call(:chmod, mode, remote_path) if mode
end

mattbrictson avatar Feb 09 '16 21:02 mattbrictson