Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I switch user in Vagrant bootstrap shell script?

Tags:

shell

vagrant

Edit Apparently, the problem was that I should have done
su - postgres -c "commands, commands, commands",
that is, passed any commands to su, rather than attempting to list them below su, because those commands (below su) aren't affected by su. /Edit

Edit 2: See David Braun's answer for an even better solution: https://stackoverflow.com/a/22947716/694469


Can I not switch user (su - postgres) in a Vagrant bootstrap shell provisioning script? (Why not?)

I'm writing such a script. In that script, I do:

echo '===== Creating PostgreSQL databases and users'

su - postgres

psql -c "
  create user SomeUserName password '...';
  alter user ...;
  "

Here, psql should attempt to login as user postgres. What happens, however, is that su - postgres apparently fails, and the shell attempts to login as user root. (Apparently, root is the user that runs the Vagrant bootstrap shell script.)

So this error appears and the psql commands aren't invoked:

psql: FATAL: role "root" does not exist

Replacing su - postgres with sudo su - postgres has no effect (I think the script is already run as root.)

I added id (which prints the current user ID) before and after su - postgres, and id prints uid=0(root) gid=0(root) groups=0(root) both before and after su was called. So as far as I can tell, su - postgres is kind of ignored? And a certain exit, later on when I attempt to switch back to the root user, exits the bootstrap script completely :-(

However. After doing vagrant ssh, I'm able to sudo su - postgres just fine, and then start psql. But not from within the provisioning script.

(A workaround is to specify -h 127.0.0.1 --username postgres when I call psql (instead of switching user to postgres). And also enable PostgreSQL trust based authentication for VM local connections.)

like image 385
KajMagnus Avatar asked May 27 '13 08:05

KajMagnus


4 Answers

echo '===== Creating PostgreSQL databases and users'

su postgres << EOF
psql -c "
  create user SomeUserName password '...';
  alter user ...;
  "
EOF
like image 187
David Braun Avatar answered Nov 15 '22 20:11

David Braun


I just found this while looking for a way to run Vagrant provider scripts as non-root, and would like to add an explanation for the observed behaviour, which is quite fundamental Unix knowledge that would be useful for readers to know.

Running a program (such as /bin/sh, sudo or su) in a shell script cannot change anything in the context (working directory, running user etc) in which it runs, only set the context for the process it creates (and only change the running uid if running as root - uid 0). This is also why cd is a builtin command in shells. su is a setuid program (note the "s" when you try the command "ls -l which su") which means that it will run as the user owning the program (root) rather than as the user running it.

like image 21
LHP Avatar answered Nov 15 '22 22:11

LHP


LHP is right: it is not really a vagrant issue. I needed to do that some time ago and here is how I've solved it:

#!/bin/bash

case $(id -u) in
    0) 
         echo first: running as root
         echo doing the root tasks...
         sudo -u vagrant -i $0  # script calling itself as the vagrant user
         ;;
    *) 
         echo then: running as vagrant user
         echo doing the vagrant user's tasks
         ;;
esac

Maybe this could be useful for someone, but another obvious solution will be just run a second script using sudo.

FIXED: Thank you Macattack. I wrote directly in stackoverflow and it still not tested.

EDIT: The question has been edited and now its description, and most of the answers, are focusing on "How to create a postgres database with the right user" rather than how to switch user in a vagrant script.

like image 22
olivecoder Avatar answered Nov 15 '22 21:11

olivecoder


I'm not sure if you can switch users in Vagrant shell scripts as that might require user input which you cannot give it when the script is running in the provisioner... but why not just specify the user with the psql command?

psql --username=postgres -c "..."
like image 40
Matt Cooper Avatar answered Nov 15 '22 22:11

Matt Cooper