Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

### master

## v5.0.0, 2018-06-05
- Code cleanup
- Removal of legacy add hstore method
- Using execute and test properly so we can see what the gem is doing in the STDOUT
- Expanded remove_all task to actually cover everything
- Added deploy config option pg_generate_random_password, instead of using it by default when pg_password is excluded
- issues/53: Bug fixed for updates to the archetype when using random password
- projects/1: Prep for RSPEC testing project

## v4.9.1, 2018-06-04
- Added back set :pg_ask_for_password, false and ask_for_or_generate_password

Expand Down
61 changes: 41 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
# Capistrano::PostgreSQL

**Note: this plugin works only with Capistrano 3.** Plase check the capistrano
**Note: this plugin works only with Capistrano 3.** Please check the capistrano
gem version you're using before installing this gem:
`$ bundle show | grep capistrano`

Plugin for Capistrano 2 [is here](https://github.com/bruno-/capistrano2-postgresql).
The plugin for Capistrano 2 [is here](https://github.com/bruno-/capistrano2-postgresql).

### About

Expand All @@ -14,11 +13,9 @@ tasks for PostgreSQL when deploying rails apps.
Here are the specific things this plugin does for your capistrano deployment
process:

* creates a new PostgreSQL database and database user on the server
* generates and populates `database.yml` file on all release nodes
(no need to ssh to the server and do this manually!)
* zero-config
* support for multi-server setup: separate `db` and `app` nodes (from version 4.0)
* Creates a new PostgreSQL database and database user on the server
* Generates and populates `database.yml` file on all release nodes (using ssh)
* Support for multi-server setup: separate `db` and `app` nodes ( versions > 4.0 )

**Note**: gem version 4 introduces some breaking changes. If you installed gem
version 3 or below you might want to follow the
Expand All @@ -30,7 +27,7 @@ Put the following in your application's `Gemfile`:

group :development do
gem 'capistrano', '~> 3.2.0'
gem 'capistrano-postgresql', '~> 4.8.0'
gem 'capistrano-postgresql', '~> 5.0.0'
end

Then:
Expand All @@ -39,31 +36,55 @@ Then:

### Usage

If you're deploying a standard rails app, all you need to do is put
the following in `Capfile` file:
In a standard RAILS app, you need to do is put the following in `Capfile` file:

```
require 'capistrano/postgresql'
```

* Make sure the `deploy_to` path exists and has the right privileges on the
server (i.e. `/var/www/myapp`). Warning: The ~ symbol (i.e. `~/myapp`) is not supported.
* Within your app/config/deploy/{env}.rb files, you need to specify at least one :app and one :db server.
* It's also suggested to specify `:primary => true` on the end of your primary :db server line.
* Optionally, you can run psql commands WITHOUT sudo if needed. Set the following (which defaults to false): `set :pg_without_sudo, true`
You need to include ONLY ONE of the following in your config/deploy/*.rb files:

```
set :pg_password, ENV['DATABASE_USER_PASSWORD']
set :pg_ask_for_password, true
set :pg_generate_random_password, true
```

Example config:

```
server 'growtrader.dev', user: 'growtrader', roles: %w{app db}
set :stage, :development
set :branch, 'development'
# ==================
# Postgresql setup
set :pg_without_sudo, false
set :pg_host, 'growtrader.dev'
set :pg_database, 'growtrader'
set :pg_username, 'growtrader'
#set :pg_generate_random_password, true
#set :pg_ask_for_password, true
set :pg_password, ENV['GROWTRADER_PGPASS']
set :pg_extensions, ['citext','hstore']
set :pg_encoding, 'UTF-8'
set :pg_pool, '100'
```

Finally, to setup the server(s), run:

$ bundle exec cap production setup

### Gotchas
### Requirements

Be sure to remove `config/database.yml` from your application's version control.
* Be sure to remove `config/database.yml` from your application's version control.
* Your pg_hba.conf must include `local all all trust`
* Make sure the `deploy_to` path exists and has the right privileges on your servers. The ~ symbol (i.e. `~/myapp`) is not supported.
* Within your app/config/deploy/{env}.rb files, you need to specify at least one :app and one :db server.
* If you have multiple :db role hosts, it's necessary to specify `:primary => true` on the end of your primary :db server.

### How it works

[How the plugin works](https://github.com/capistrano-plugins/capistrano-postgresql/wiki/How-it-works)
wiki page contains a list of actions the plugin executes.

Read it only if you want to learn more about the plugin internals.

Expand All @@ -87,7 +108,7 @@ Check out [capistrano-plugins](https://github.com/capistrano-plugins) github org

Contributions and improvements are very welcome.

If something is not working for you, or you find a bug please report it.
If something is not working for you, or you find a bug, please report it.

### Thanks

Expand Down
20 changes: 18 additions & 2 deletions lib/capistrano/postgresql/helper_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ module Capistrano
module Postgresql
module HelperMethods

def extension_exists?(extension)
psql 'test', fetch(:pg_system_db), '-tAc', %Q{"SELECT 1 FROM pg_extension WHERE extname='#{extension}';" | grep -q 1}
end

def remove_extensions
if Array( fetch(:pg_extensions) ).any?
on roles :db do
# remove in reverse order if extension is present
Array( fetch(:pg_extensions) ).reverse.each do |ext|
next if [nil, false, ""].include?(ext)
psql 'execute', fetch(:pg_system_db), '-c', %Q{"DROP EXTENSION IF EXISTS #{ext};"} if extension_exists?(ext)
end
end
end
end

def generate_database_yml_io(password=fetch(:pg_password))
StringIO.open do |s|
s.puts "#{fetch(:pg_env)}:"
Expand All @@ -26,10 +42,10 @@ def generate_database_yml_io(password=fetch(:pg_password))
def pg_template(update=false,archetype_file=nil)
config_file = "#{fetch(:pg_templates_path)}/postgresql.yml.erb"
if update
raise('Updates need the original file to update from.') if archetype_file.nil?
raise('Regeneration of archetype database.yml need the original file to update from.') if archetype_file.nil?
raise('Cannot update a custom postgresql.yml.erb file.') if File.exists?(config_file) # Skip custom postgresql.yml.erb if we're updating. It's not supported
# Update yml file from settings
if fetch(:pg_password).nil? && fetch(:pg_ask_for_password) == false # User isn't generating a random password or wanting to set it manually from prompt
if fetch(:pg_generate_random_password) || !fetch(:pg_password) # We need to prevent updating the archetype file if we've done a random or "ask"ed password
current_password = archetype_file.split("\n").grep(/password/)[0].split('password:')[1].strip
generate_database_yml_io(current_password)
else
Expand Down
8 changes: 4 additions & 4 deletions lib/capistrano/postgresql/password_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ def generate_random_password
SecureRandom.hex(10)
end

# This method is invoked only if :pg_password is not already set in config/#{:stage}/deploy.rb. Directly setting :pg_password has precedence.
def ask_for_or_generate_password
def pg_password_generate
if fetch(:pg_ask_for_password)
ask :pg_password, "Postgresql database password for the app: "
else
elsif fetch(:pg_generate_random_password)
set :pg_password, generate_random_password
else
set :pg_password, nil # Necessary for pg_template
end
end

end
end
end
Expand Down
41 changes: 15 additions & 26 deletions lib/capistrano/postgresql/psql_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,28 @@ module Capistrano
module Postgresql
module PsqlHelpers

def psql(*args)
# Reminder: -u #{fetch(:pg_system_user)} seen below differs slightly from -U, an option on the psql command: https://www.postgresql.org/docs/9.6/static/app-psql.html
args.unshift("-U #{fetch(:pg_system_user)}") if fetch(:pg_without_sudo) # Add the :pg_system_user to psql command since we aren't using sudo anymore
# test :sudo, "-u #{fetch(:pg_system_user)} psql", *args
cmd = [ :psql, *args ]
cmd = [ :sudo, "-u #{fetch(:pg_system_user)}", *cmd ] unless fetch(:pg_without_sudo)
test *cmd.flatten
end

# Runs psql on the application database
def psql_on_app_db(*args)
psql_on_db(fetch(:pg_database), *args)
def psql(type, database, *args)
cmd = [ :psql, "-d #{database}", *args ]
if fetch(:pg_without_sudo)
args.unshift("-U #{fetch(:pg_system_user)}") # Add the :pg_system_user to psql command since we aren't using sudo anymore
else
cmd = [:sudo, "-i -u #{fetch(:pg_system_user)}", *cmd]
end
if type == 'test'
test *cmd.flatten
else
execute *cmd.flatten
end
end

def db_user_exists?
psql_on_db fetch(:pg_system_db),'-tAc', %Q{"SELECT 1 FROM pg_roles WHERE rolname='#{fetch(:pg_username)}';" | grep -q 1}
def database_user_exists?
psql 'test', fetch(:pg_system_db),'-tAc', %Q{"SELECT 1 FROM pg_roles WHERE rolname='#{fetch(:pg_username)}';" | grep -q 1}
end

def database_exists?
psql_on_db fetch(:pg_system_db), '-tAc', %Q{"SELECT 1 FROM pg_database WHERE datname='#{fetch(:pg_database)}';" | grep -q 1}
psql 'test', fetch(:pg_system_db), '-tAc', %Q{"SELECT 1 FROM pg_database WHERE datname='#{fetch(:pg_database)}';" | grep -q 1}
end

private

def psql_on_db(db_name, *args)
args.unshift("-U #{fetch(:pg_system_user)}") if fetch(:pg_without_sudo) # Add the :pg_system_user to psql command since we aren't using sudo anymore
cmd = [ :psql, "-d #{db_name}", *args ]
cmd = [ :sudo, "-u #{fetch(:pg_system_user)}", *cmd ] unless fetch(:pg_without_sudo)
puts "Executing #{cmd.flatten}"
test *cmd.flatten
#test :sudo, "-u #{fetch(:pg_system_user)} psql -d #{db_name}", *args
end

end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/capistrano/postgresql/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module Capistrano
module Postgresql
VERSION = '4.9.2'
VERSION = '5.0.0'
end
end
Loading