`execute` as vagrant user, not root, with chef-solo

vagrant

I'm trying to run the following chef command:

# install zombiejs, q (promises), should, coffee-script & mocha                 
execute "install q and zombiejs" do                                             
  cwd "/home/vagrant"                                                           
  user "vagrant"                                                                
  action :run                                                                   
  command "npm install -g q zombie should mocha coffee-script"                  
end

But it keeps failing because it can't find npm:

execute[install q and zombiejs] (chef-redtail::default line 205) had an error: Errno::ENOENT: No such file or directory – npm install -g q zombie should mocha coffee-script

Logging in to vagrant via vagrant ssh and running the command manually works perfectly fine. Logging in as root, via sudo -i and running the command fails for the same reason the chef recipe fails (npm is installed locally only for the vagrant user, not for root: this is what I want).

So… how can I specify this chef execute block to run as the vagrant user and not root?


UPDATE: I think this sums up my problem:

(ssh) /vagrant git:backbone ❯ whoami
vagrant

(ssh) /vagrant git:backbone ❯ which npm
/home/vagrant/.local/bin/npm

(ssh) /vagrant git:backbone ❯ echo $PATH
/home/vagrant/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

(ssh) /vagrant git:backbone ❯ sudo -H -u vagrant -i echo $PATH
/home/vagrant/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

(ssh) /vagrant git:backbone ❯ sudo -H -u vagrant -i which npm
npm not found

via http://tickets.opscode.com/browse/CHEF-2517


ANOTHER UPDATE: So I just noticed this discrepancy:

(ssh) /vagrant git:backbone ❯ sudo -H -u vagrant -i echo $PATH
/home/vagrant/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

(ssh) /vagrant git:backbone ❯ sudo -H -u vagrant -i export
HOME=/home/vagrant
LANG=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
LOGNAME=vagrant
MAIL=/var/mail/vagrant
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
SHELL=/bin/zsh
SSH_AUTH_SOCK=/tmp/ssh-uJUopA4146/agent.4146
SUDO_COMMAND='/bin/zsh -c export'
SUDO_GID=1001
SUDO_UID=1000
SUDO_USER=vagrant
TERM=xterm
USER=vagrant

Notice the difference in PATH? The export doesn't have the /home/vagrant/.local/bin directory listed in it… why would the first echo return PATH with it and the second export return PATH without it? Is this the issue?

Best Answer

To execute a script or a command as a user, you need to combine su -l and bash -i:

 execute "npm_install" do
    command "su vagrant -l -c 'cd /shared-with-host/helperScripts/ && bash -i npm install -g q zombie should mocha coffee-script'" 
    action :run
  end

Because of some bugs, chef does not set properly the environment for the specified user in execute. The narced133's solution will not work.