Edit Apparently, the problem was that I should have donesu - 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.)
echo '===== Creating PostgreSQL databases and users'
su postgres << EOF
psql -c "
create user SomeUserName password '...';
alter user ...;
"
EOF
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.
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.
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 "..."
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With