How to use not_if in a chef recipe - ruby

I am new to chef so I am a little confused in how the conditional not_if works inside a execute resource. I understand that it tells chef not to execute a command if the command returns 0 or true; however, in my code it is apparently still running the command.
The following code is supposed to create a user (and its password) and a database; however, if the user and database already exist, it should not do anything. The user, database and password are defined in the attributes. The following is the code I have:
execute "create-user" do
code = <<-EOH
psql -U postgres -c "select * from pg_user where usename='#{node[:user]}'" | grep -c #{node[:user]}
EOH
user "postgres"
command "createuser -s #{node[:user]}"
not_if code
end
execute "set-user-password" do
user "postgres"
command "psql -U postgres -d template1 -c \"ALTER USER #{node[:user]} WITH PASSWORD '#{node[:password]}';\""
end
execute "create-database" do
exists = <<-EOH
psql -U postgres -c "select * from pg_database WHERE datname='#{node[:database]}'" | grep -c #{node[:database]}}
EOH
user "postgres"
command "createdb #{node[:database]}"
not_if exists
end
Chef gives me the following error:
Error executing action run on resource 'execute[create-user]'
...
[2013-01-25T12:24:51-08:00] FATAL: Mixlib::ShellOut::ShellCommandFailed: execute[create-user] (postgresql::initialize line 16) had an error: Mixlib::ShellOut::ShellCommandFailed: Expected process to exit with [0], but received '1'
STDERR: createuser: creation of new role failed: ERROR: role "user" already exists
To me it seems that it should work;however, it still running the execute. Am I missing something?
Thank you

I had been having the same issue. But, in my case, "not_if" seems executed by different user (root), and failed to check the condition properly. Adding [:user => "postgres"] resolved the issue.
execute "create-database-user" do
user "postgres"
exists = <<-EOH
psql -U postgres -c "select * from pg_user where usename='#{settings[:username]}'" | grep -c #{settings[:username]}
EOH
command "createuser -U postgres -sw #{settings[:username]}"
not_if exists, :user => "postgres"
end
I've referred the following code example.
https://github.com/MarcinKoziuk/chef-postgres-dbsetup/blob/master/recipes/default.rb

You're checking for the existence of:
node[:user]
If it doesn't exist, you create:
node[:postgresql][:user]
Unless these happen to be equal, you'll keep trying to create node[:postgresql][:user] repeatedly.

First, there is a typo in the WHERE condition. It should probably be username instead of usename.
Anyawy, you should do:
execute "create-user" do
user "postgres"
command "createuser -s #{node[:user]}"
not_if "psql -U postgres -c \"select * from pg_user where username='#{node[:user]}'\" | grep -c #{node[:user]}"
end
This assumes that your psql -U postgres -c "select * from pg_user where username='#{node[:user]}'" is correct.
Same with a database:
execute "create-database" do
user "postgres"
command "createdb #{node[:database]}"
not_if "psql -U postgres -c \"select * from pg_database WHERE datname='#{node[:database]}'\" | grep -c #{node[:database]}}"
end
Regarding the username, even if it already exists, changing the password to the known one shouldn't cause a problem. After all you know the password.
FYI, you can define multiple conditionals within one resource.
Good luck with Chef! I love it very much!

Related

change user and execute one command under bash

Basically, I want to switch to user postgres and get a listing of databases. This is with a Fabric script that reads command lines from a text file one by one, executes them and then saves their output to file.
su - postgres && psql -c '\l'
When I do this under bash directly:
(ssha)root ~$su - postgres && psql -c '\l'
postgres#localvm:~$
I saw a related question, linux - Executing multiple commands under as another username within a file in BASH shell, but that wouldn't work with my 1-line-per-command scheme and I don't need a full script, just 1 command.
You can use su -c:
su - postgres -c "psql -c '\l'"
Though often you'll also have sudo, which is more robust and easier to use:
sudo -u postgres psql -c '\l'

PostgreSQL: execute query from script

I'm installing PostgreSQL + POSTGIS on a CentOS 7 virtual machine using Vagrant and Virtual Box.
My Vagtantfile is the follow ...
Vagrant.configure("2") do |config|
config.vm.box = "centos/7"
config.vm.network "private_network", ip: "192.168.56.2"
config.vm.provider "virtualbox" do |vb|
vb.memory = "4096"
vb.name = "Test"
end
config.vm.provision "shell", path: "./scripts/InstallPostgresqlPostgis.sh"
end
In ./scripts/InstallPostgresqlPostgis.sh there are all the commands to install PostgreSQL and, when run, PostgreSQL is installed and works.
To add POSTGIS at my PostgreSQL installation, in interactive way, I use this procedure
su postgres
----->>>>>>> HERE I'VE TO PUT THE USER PASSWORD <<<<<<<-------
psql
-- Enable PostGIS (includes raster)
CREATE EXTENSION postgis;
-- Enable Topology
CREATE EXTENSION postgis_topology;
-- Enable PostGIS Advanced 3D
-- and other geoprocessing algorithms
-- sfcgal not available with all distributions
CREATE EXTENSION postgis_sfcgal;
-- fuzzy matching needed for Tiger
CREATE EXTENSION fuzzystrmatch;
-- rule based standardizer
CREATE EXTENSION address_standardizer;
-- example rule data set
CREATE EXTENSION address_standardizer_data_us;
-- Enable US Tiger Geocoder
CREATE EXTENSION postgis_tiger_geocoder;
\q
and all works.
I've to "translate" this procedure in my InstallPostgresqlPostgis.sh that I refer in my Vagrantfile and I've tried this
sudo -u postgres -H -- psql -d postgres -c "CREATE EXTENSION postgis"
sudo -u postgres -H -- psql -d postgres -c "CREATE EXTENSION postgis_topology"
sudo -u postgres -H -- psql -d postgres -c "CREATE EXTENSION postgis_sfcgal"
sudo -u postgres -H -- psql -d postgres -c "CREATE EXTENSION fuzzystrmatch"
sudo -u postgres -H -- psql -d postgres -c "CREATE EXTENSION address_standardizer"
sudo -u postgres -H -- psql -d postgres -c "CREATE EXTENSION address_standardizer_data_us"
sudo -u postgres -H -- psql -d postgres -c "CREATE EXTENSION postgis_tiger_geocoder"
but the result is ...
default: could not change directory to "/home/vagrant": Permission denied
default: CREATE EXTENSION
default: could not change directory to "/home/vagrant": Permission denied
default: CREATE EXTENSION
default: could not change directory to "/home/vagrant": Permission denied
default: CREATE EXTENSION
default: could not change directory to "/home/vagrant": Permission denied
default: CREATE EXTENSION
default: could not change directory to "/home/vagrant": Permission denied
default: CREATE EXTENSION
default: could not change directory to "/home/vagrant": Permission denied
default: CREATE EXTENSION
default: could not change directory to "/home/vagrant": Permission denied
default: CREATE EXTENSION
Where am I doing wrong?
Your problem is that you are executing the commands with a working directory
that is not accessible to postgres user. In fact it is the home directory of the user executing the commands (vagrant).
There are three approaches for fixing this issue:
use --login (or -i for short) option to sudo
This will cause sudo to execute the commands with settings similar to a login shell.
Especially this will (try) changing to the target user's home directory as a working directory.
change the working directory within your script using cd ~postgres
This will result in all sudo commands will being executed there.
Allow user postgres access to the home directory of user vagrant
THIS IS DANGEROUS AND ABSOLUTELY NOT RECOMMENDED!!!
I just mention it for completeness. It might be an option iff
you need such access regularly
and you have some fine grain access control at hand (e.g. ACL)
that allows ensuring postgres really is the only user being granted access.
Even then you should think thrice!
In most cases alternatives 1. or 2. are to be preferred.
I've solved in this way ...
sudo su postgres
sudo -u postgres -H -- psql -d postgres -c "CREATE EXTENSION postgis"
sudo -u postgres -H -- psql -d postgres -c "CREATE EXTENSION postgis_topology"
sudo -u postgres -H -- psql -d postgres -c "CREATE EXTENSION postgis_sfcgal"
sudo -u postgres -H -- psql -d postgres -c "CREATE EXTENSION fuzzystrmatch"
sudo -u postgres -H -- psql -d postgres -c "CREATE EXTENSION address_standardizer"
sudo -u postgres -H -- psql -d postgres -c "CREATE EXTENSION address_standardizer_data_us"
sudo -u postgres -H -- psql -d postgres -c "CREATE EXTENSION postgis_tiger_geocoder"

"error retrieving current directory" running psql commands under sudo

from a bash script I´m trying to create a postgresql database + users.
It looks like this:
#!/usr/bin/env bash
echo ' Create DBs'
sudo -u postgres createdb -E 'utf-8' -l en_US.utf8 -T template0 testdb
echo ' Create User'
sudo -u postgres psql -c "create role bert with login password 'pass';"
echo ' alter permissions'
sudo -u postgres psql -c "alter database testdb owner to bert;"
unfortuantely I´m getting following errors:
==> default: Create DBs
==> default: could not identify current directory: No such file or directory
==> default: Create User
==> default: shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
==> default: CREATE ROLE
==> default: alter permissions
==> default: shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
I would be very thankful if one coule explain what´s going wrong and how to work around the getcwd error.
thanks!
Your script is being run from somewhere (such as /root -- or possibly a previously-deleted temporary directory) where the postgres user does not have access to the current working directory.
These messages are effectively harmless (unless you're invoking scripts that depend on $PWD or similar variables or commands), but if you want to avoid them, change directories to somewhere certain to exist and which the postgres user has access to. For instance, put the line:
cd /
...at the top of your script, just under the shebang.

Why command -- sh raise error?

Why the shell command raises error:
sudo -u postgres \
-- sh -c '/usr/bin/env psql -c "CREATE ROLE deploy PASSWORD secret SUPERUSER CREATEDB CREATEROLE INHERIT LOGIN;"'
Causes:
ERROR: syntax error at end of input
LINE 1: CREATE
^
What's right syntax ?
Many thanks.
Try:
sudo -u postgres '/usr/bin/env RBENV_ROOT=/usr/local/rbenv RBENV_VERSION=2.1.3 psql -c "CREATE ROLE deploy PASSWORD secret SUPERUSER CREATEDB CREATEROLE INHERIT LOGIN;"'
env takes variable assignments before the command to run. And I don't see why you need to use sh -c, sudo executes the command for you.

invalid multibyte char (US-ASCII) in a chef recipe

Im trying to do a postgresql base back up via bash chef resources. Below is my code and im getting the following error. When i deploy them. Any thoughts why.
$PGDATA = "node['fc_db']['postgres']['pg_data']"
bash "backup master db" do
user "postgres"
code <<-EOH
initdb –D –-no-locale –-encoding=UTF8
pg_ctl –D #{$PGDATA} start
psql –c "SELECT pg_start_backup('initial backup for SR')" template1
tar cvf pg_base_backup.tar #{$PGDATA}
psql –c "SELECT pg_stop_backup()" template1
EOH
end
Which version of Ruby are you using? If not 2.x.x, try adding # encoding: UTF-8 on top of your wal-e.rb?
The line in the code :
initdb –D –-no-locale –-encoding=UTF8
Should be:
initdb –D --no-locale --encoding=UTF8

Resources