sprinkle-tool / sprinkle

Sprinkle is a software provisioning tool you can use to build remote servers with. eg. to install a Rails, or Sinatra stack on a brand new slice directly after its been created
https://github.com/sprinkle-tool/sprinkle
MIT License
1.15k stars 138 forks source link

Is it possible for post :install not use sudo? #61

Closed krisleech closed 11 years ago

krisleech commented 12 years ago

Is it possible to run a post :install command without sudo?

I have the same problem with runner, but I can get around this using chown.

package :zsh do
  description 'Zsh with OhMyZsh'

  apt 'zsh' do
    # FIXME: This needs to be run as user, not sudo
    post :install, 'chsh -s /usr/bin/zsh'
  end

  verify do
    has_executable 'zsh'
  end

  requires :oh_my_zsh
end

package :oh_my_zsh do
  runner '/usr/bin/env git clone https://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh'
  runner 'chown -R deploy:deploy ~/.oh-my-zsh'
  runner 'cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc'
  runner 'echo "export PATH=$PATH" >> ~/.zshrc'

  verify do
    # has_file '~/.zshrc'
  end

  requires :git
end
tnitsche commented 12 years ago

It's lame, but as a work-around I'm frequently using something like

post :install, "true; mkdir bla/blub" # use true; to fool sudo

but you are right, something like

post :install, "mkdir bla/blub", :sudo => false 

would be definitely nicer.

joshgoebel commented 11 years ago

Why is it running as sudo in the first place, because you're using Capistrano actor? If so the quick fix is the workaround already mentioned. If you tell Capistano to do everything sudo then it's Capistrano making that decision, not sprinkle... please confirm this is your issue.

micnigh commented 11 years ago

Sprinkle defaults capistranos run_method to use sudo, if run_method hasn't been set.

The side effect is that every command is prepended with sudo which breaks some commands, eg cd.

See offending line here https://github.com/sprinkle-tool/sprinkle/blob/4746cb7734aed5f580f8d95a08f8b7099f12fbd2/lib/sprinkle/actors/capistrano.rb#L90

For a workaround, I had to add below to my deploy.rb file to turn the extra sudo off

set :run_method,  :run

It seems like the default should be not to prepend sudo unless overwritten - there may be some use cases I'm not considering though.

joshgoebel commented 11 years ago

Sprinkle defaults capistranos run_method to use sudo, if run_method hasn't been set. It seems like the default should be not to prepend sudo unless overwritten - there may be some use cases I'm not considering though.

See issue #102. We're changing sprinkle's behavior but if someone is using a default Capistrano setup then run_method will be :sudo by default, not :run. The Capistrano way is to turn sudo off rather than turn it on.

joshgoebel commented 11 years ago

You do know you can just pass user as the last argument to chsh (when running as root), right? Or was that just an example of the type of issue?

joshgoebel commented 11 years ago

I would suggest this:

# in your capistrano setup
set :use_sudo, false

# in your package
apt 'zsh', :sudo => true
runner 'chsh -s /usr/bin/zsh'

If you want sudo on most of the time (which makes sensE) and really want an exclusion ability you could build out some helpers to support that:

def without_sudo(cmd)
   "true; #{cmd}"
end

post :install, without_sudo("mkdir bla/blub")

Does that solve your issue?

joshgoebel commented 11 years ago

Someone may also want to look at the work I've done here: https://github.com/sprinkle-tool/sprinkle/tree/smart_sudo

Sprinkle could re-open the String class and add a sudo attribute... but if we're going to do that I'd want true/false/nil to be handled in a logical fashion all the way up the chain.

At this point you need to handle single commands that have sudo true in a global sudo false world...

And stuff like this looks pretty ugly to me:

package "mysql", :sudo => false do
  # do a few non sudo things here
  apt "mysql", :sudo => true do
    post :install, "echo done", :sudo => false
  end
end

I admit that's a contrived example.

micnigh commented 11 years ago

:+1:

Took a look at the smart_sudo branch, and looked at how it might be used in my own scripts, and this seems like a good approach. In most cases, using sudo is preferable, but often I'll want to split up certain packages as 'user' packages where sudo would be disabled on the package level. There are a few edge cases where a single command shouldn't be sudoed, which this handles, so I think all the cases are covered.

Very nice approach, I can clean up my scripts quite a bit with this change; I think there's going to be a sudo massacre very soon :smiling_imp:

joshgoebel commented 11 years ago

Really? All it does is fix the conflict between capistrano and sprinkle's own sudo support. It doesn't really do anything to help with this issue that I'm aware of. What's got you so excited?

micnigh commented 11 years ago

Previously there was no way to enable/disable sudo, especially at the package level. So I would default sudo to off and just filled my scripts with sudo to get to command level granularity, so I could handle those edge cases. Something like 500+ sudo's...

joshgoebel commented 11 years ago

There is still no way to disable sudo at a package level if it's turned on globally. Sudo is still a positive thing, not a negation that can be done.

micnigh commented 11 years ago

So, it looks like I should read change logs more - I completely missed the commit adding package level support to sudo over a year ago, hence the excitement over the new feature https://github.com/sprinkle-tool/sprinkle/commit/9cd86986a4e7332629e377364aebe887132e713b

joshgoebel commented 11 years ago

Indeed.

joshgoebel commented 11 years ago

Did that resolve your issue?

joshgoebel commented 11 years ago

Closing this and leaving my last post as the core recommendation (until we ever support sudo on a per-command basis):

def without_sudo(cmd)
   "true; #{cmd}"
end

post :install, without_sudo("mkdir bla/blub")

It's a hack, but a simple and functional hack.