capistrano-postgresql 4.9.2 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +41 -20
- data/lib/capistrano/postgresql/helper_methods.rb +18 -2
- data/lib/capistrano/postgresql/password_helpers.rb +4 -4
- data/lib/capistrano/postgresql/psql_helpers.rb +15 -26
- data/lib/capistrano/postgresql/version.rb +1 -1
- data/lib/capistrano/tasks/postgresql.rake +35 -58
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 62d90db3919f2557e6a3934726d251dac71b5abf48a2c7b1984dd32b3ee96852
|
4
|
+
data.tar.gz: 44cb5c724e536949afe34291907838a747fd8342e7c84bbbfad2cb61a2746a53
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: afd78f06f37d41d32da87073c979ede236aadcf9409ce7b4086ce5ecb232447efb0071007401cce4d556e6468e7af7743b4d4adaadf9f408e1882ce5767a8400
|
7
|
+
data.tar.gz: 41c442f96c4fb72594f9595d649a184e0447b1c168e114ea663d44cdc68d82e8393fd7c84f7ed5ae71d0816966fa7fb83b094b826cf8d16d5b5163e947e4ce6b
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,15 @@
|
|
2
2
|
|
3
3
|
### master
|
4
4
|
|
5
|
+
## v5.0.0, 2018-06-05
|
6
|
+
- Code cleanup
|
7
|
+
- Removal of legacy add hstore method
|
8
|
+
- Using execute and test properly so we can see what the gem is doing in the STDOUT
|
9
|
+
- Expanded remove_all task to actually cover everything
|
10
|
+
- Added deploy config option pg_generate_random_password, instead of using it by default when pg_password is excluded
|
11
|
+
- issues/53: Bug fixed for updates to the archetype when using random password
|
12
|
+
- projects/1: Prep for RSPEC testing project
|
13
|
+
|
5
14
|
## v4.9.1, 2018-06-04
|
6
15
|
- Added back set :pg_ask_for_password, false and ask_for_or_generate_password
|
7
16
|
|
data/README.md
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
# Capistrano::PostgreSQL
|
2
2
|
|
3
|
-
**Note: this plugin works only with Capistrano 3.**
|
3
|
+
**Note: this plugin works only with Capistrano 3.** Please check the capistrano
|
4
4
|
gem version you're using before installing this gem:
|
5
5
|
`$ bundle show | grep capistrano`
|
6
|
-
|
7
|
-
Plugin for Capistrano 2 [is here](https://github.com/bruno-/capistrano2-postgresql).
|
6
|
+
The plugin for Capistrano 2 [is here](https://github.com/bruno-/capistrano2-postgresql).
|
8
7
|
|
9
8
|
### About
|
10
9
|
|
@@ -14,11 +13,9 @@ tasks for PostgreSQL when deploying rails apps.
|
|
14
13
|
Here are the specific things this plugin does for your capistrano deployment
|
15
14
|
process:
|
16
15
|
|
17
|
-
*
|
18
|
-
*
|
19
|
-
|
20
|
-
* zero-config
|
21
|
-
* support for multi-server setup: separate `db` and `app` nodes (from version 4.0)
|
16
|
+
* Creates a new PostgreSQL database and database user on the server
|
17
|
+
* Generates and populates `database.yml` file on all release nodes (using ssh)
|
18
|
+
* Support for multi-server setup: separate `db` and `app` nodes ( versions > 4.0 )
|
22
19
|
|
23
20
|
**Note**: gem version 4 introduces some breaking changes. If you installed gem
|
24
21
|
version 3 or below you might want to follow the
|
@@ -30,7 +27,7 @@ Put the following in your application's `Gemfile`:
|
|
30
27
|
|
31
28
|
group :development do
|
32
29
|
gem 'capistrano', '~> 3.2.0'
|
33
|
-
gem 'capistrano-postgresql', '~>
|
30
|
+
gem 'capistrano-postgresql', '~> 5.0.0'
|
34
31
|
end
|
35
32
|
|
36
33
|
Then:
|
@@ -39,31 +36,55 @@ Then:
|
|
39
36
|
|
40
37
|
### Usage
|
41
38
|
|
42
|
-
|
43
|
-
the following in `Capfile` file:
|
39
|
+
In a standard RAILS app, you need to do is put the following in `Capfile` file:
|
44
40
|
|
45
41
|
```
|
46
42
|
require 'capistrano/postgresql'
|
47
43
|
```
|
48
44
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
45
|
+
You need to include ONLY ONE of the following in your config/deploy/*.rb files:
|
46
|
+
|
47
|
+
```
|
48
|
+
set :pg_password, ENV['DATABASE_USER_PASSWORD']
|
49
|
+
set :pg_ask_for_password, true
|
50
|
+
set :pg_generate_random_password, true
|
51
|
+
```
|
52
|
+
|
53
|
+
Example config:
|
54
|
+
|
55
|
+
```
|
56
|
+
server 'growtrader.dev', user: 'growtrader', roles: %w{app db}
|
57
|
+
set :stage, :development
|
58
|
+
set :branch, 'development'
|
59
|
+
# ==================
|
60
|
+
# Postgresql setup
|
61
|
+
set :pg_without_sudo, false
|
62
|
+
set :pg_host, 'growtrader.dev'
|
63
|
+
set :pg_database, 'growtrader'
|
64
|
+
set :pg_username, 'growtrader'
|
65
|
+
#set :pg_generate_random_password, true
|
66
|
+
#set :pg_ask_for_password, true
|
67
|
+
set :pg_password, ENV['GROWTRADER_PGPASS']
|
68
|
+
set :pg_extensions, ['citext','hstore']
|
69
|
+
set :pg_encoding, 'UTF-8'
|
70
|
+
set :pg_pool, '100'
|
71
|
+
```
|
54
72
|
|
55
73
|
Finally, to setup the server(s), run:
|
56
74
|
|
57
75
|
$ bundle exec cap production setup
|
58
76
|
|
59
|
-
###
|
77
|
+
### Requirements
|
60
78
|
|
61
|
-
Be sure to remove `config/database.yml` from your application's version control.
|
79
|
+
* Be sure to remove `config/database.yml` from your application's version control.
|
80
|
+
* Your pg_hba.conf must include `local all all trust`
|
81
|
+
* Make sure the `deploy_to` path exists and has the right privileges on your servers. The ~ symbol (i.e. `~/myapp`) is not supported.
|
82
|
+
* Within your app/config/deploy/{env}.rb files, you need to specify at least one :app and one :db server.
|
83
|
+
* If you have multiple :db role hosts, it's necessary to specify `:primary => true` on the end of your primary :db server.
|
62
84
|
|
63
85
|
### How it works
|
64
86
|
|
65
87
|
[How the plugin works](https://github.com/capistrano-plugins/capistrano-postgresql/wiki/How-it-works)
|
66
|
-
wiki page contains a list of actions the plugin executes.
|
67
88
|
|
68
89
|
Read it only if you want to learn more about the plugin internals.
|
69
90
|
|
@@ -87,7 +108,7 @@ Check out [capistrano-plugins](https://github.com/capistrano-plugins) github org
|
|
87
108
|
|
88
109
|
Contributions and improvements are very welcome.
|
89
110
|
|
90
|
-
If something is not working for you, or you find a bug please report it.
|
111
|
+
If something is not working for you, or you find a bug, please report it.
|
91
112
|
|
92
113
|
### Thanks
|
93
114
|
|
@@ -4,6 +4,22 @@ module Capistrano
|
|
4
4
|
module Postgresql
|
5
5
|
module HelperMethods
|
6
6
|
|
7
|
+
def extension_exists?(extension)
|
8
|
+
psql 'test', fetch(:pg_system_db), '-tAc', %Q{"SELECT 1 FROM pg_extension WHERE extname='#{extension}';" | grep -q 1}
|
9
|
+
end
|
10
|
+
|
11
|
+
def remove_extensions
|
12
|
+
if Array( fetch(:pg_extensions) ).any?
|
13
|
+
on roles :db do
|
14
|
+
# remove in reverse order if extension is present
|
15
|
+
Array( fetch(:pg_extensions) ).reverse.each do |ext|
|
16
|
+
next if [nil, false, ""].include?(ext)
|
17
|
+
psql 'execute', fetch(:pg_system_db), '-c', %Q{"DROP EXTENSION IF EXISTS #{ext};"} if extension_exists?(ext)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
7
23
|
def generate_database_yml_io(password=fetch(:pg_password))
|
8
24
|
StringIO.open do |s|
|
9
25
|
s.puts "#{fetch(:pg_env)}:"
|
@@ -26,10 +42,10 @@ module Capistrano
|
|
26
42
|
def pg_template(update=false,archetype_file=nil)
|
27
43
|
config_file = "#{fetch(:pg_templates_path)}/postgresql.yml.erb"
|
28
44
|
if update
|
29
|
-
raise('
|
45
|
+
raise('Regeneration of archetype database.yml need the original file to update from.') if archetype_file.nil?
|
30
46
|
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
|
31
47
|
# Update yml file from settings
|
32
|
-
if fetch(:
|
48
|
+
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
|
33
49
|
current_password = archetype_file.split("\n").grep(/password/)[0].split('password:')[1].strip
|
34
50
|
generate_database_yml_io(current_password)
|
35
51
|
else
|
@@ -8,15 +8,15 @@ module Capistrano
|
|
8
8
|
SecureRandom.hex(10)
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
def ask_for_or_generate_password
|
11
|
+
def pg_password_generate
|
13
12
|
if fetch(:pg_ask_for_password)
|
14
13
|
ask :pg_password, "Postgresql database password for the app: "
|
15
|
-
|
14
|
+
elsif fetch(:pg_generate_random_password)
|
16
15
|
set :pg_password, generate_random_password
|
16
|
+
else
|
17
|
+
set :pg_password, nil # Necessary for pg_template
|
17
18
|
end
|
18
19
|
end
|
19
|
-
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -2,39 +2,28 @@ module Capistrano
|
|
2
2
|
module Postgresql
|
3
3
|
module PsqlHelpers
|
4
4
|
|
5
|
-
def psql(*args)
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
5
|
+
def psql(type, database, *args)
|
6
|
+
cmd = [ :psql, "-d #{database}", *args ]
|
7
|
+
if fetch(:pg_without_sudo)
|
8
|
+
args.unshift("-U #{fetch(:pg_system_user)}") # Add the :pg_system_user to psql command since we aren't using sudo anymore
|
9
|
+
else
|
10
|
+
cmd = [:sudo, "-i -u #{fetch(:pg_system_user)}", *cmd]
|
11
|
+
end
|
12
|
+
if type == 'test'
|
13
|
+
test *cmd.flatten
|
14
|
+
else
|
15
|
+
execute *cmd.flatten
|
16
|
+
end
|
17
17
|
end
|
18
18
|
|
19
|
-
def
|
20
|
-
|
19
|
+
def database_user_exists?
|
20
|
+
psql 'test', fetch(:pg_system_db),'-tAc', %Q{"SELECT 1 FROM pg_roles WHERE rolname='#{fetch(:pg_username)}';" | grep -q 1}
|
21
21
|
end
|
22
22
|
|
23
23
|
def database_exists?
|
24
|
-
|
24
|
+
psql 'test', fetch(:pg_system_db), '-tAc', %Q{"SELECT 1 FROM pg_database WHERE datname='#{fetch(:pg_database)}';" | grep -q 1}
|
25
25
|
end
|
26
26
|
|
27
|
-
private
|
28
|
-
|
29
|
-
def psql_on_db(db_name, *args)
|
30
|
-
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
|
31
|
-
cmd = [ :psql, "-d #{db_name}", *args ]
|
32
|
-
cmd = [ :sudo, "-u #{fetch(:pg_system_user)}", *cmd ] unless fetch(:pg_without_sudo)
|
33
|
-
puts "Executing #{cmd.flatten}"
|
34
|
-
test *cmd.flatten
|
35
|
-
#test :sudo, "-u #{fetch(:pg_system_user)} psql -d #{db_name}", *args
|
36
|
-
end
|
37
|
-
|
38
27
|
end
|
39
28
|
end
|
40
29
|
end
|
@@ -13,8 +13,9 @@ namespace :load do
|
|
13
13
|
set :pg_database, -> { "#{fetch(:application)}_#{fetch(:stage)}" }
|
14
14
|
set :pg_pool, 5
|
15
15
|
set :pg_username, -> { fetch(:pg_database) }
|
16
|
-
set :
|
17
|
-
set :
|
16
|
+
set :pg_generate_random_password, nil
|
17
|
+
set :pg_ask_for_password, nil
|
18
|
+
set :pg_password, -> { pg_password_generate }
|
18
19
|
set :pg_socket, ''
|
19
20
|
set :pg_host, -> do # for multiple release nodes automatically use server hostname (IP?) in the database.yml
|
20
21
|
release_roles(:all).count == 1 && release_roles(:all).first == primary(:db) ? 'localhost' : primary(:db).hostname
|
@@ -44,86 +45,58 @@ namespace :postgresql do
|
|
44
45
|
# undocumented, for a reason: drops database. Use with care!
|
45
46
|
task :remove_all do
|
46
47
|
on release_roles :all do
|
47
|
-
if test "[ -e #{database_yml_file} ]"
|
48
|
-
execute :rm, database_yml_file
|
49
|
-
end
|
48
|
+
execute :rm, database_yml_file if test "[ -e #{database_yml_file} ]"
|
50
49
|
end
|
51
|
-
|
52
50
|
on primary :db do
|
53
|
-
if test "[ -e #{archetype_database_yml_file} ]"
|
54
|
-
execute :rm, archetype_database_yml_file
|
55
|
-
end
|
51
|
+
execute :rm, archetype_database_yml_file if test "[ -e #{archetype_database_yml_file} ]"
|
56
52
|
end
|
57
|
-
|
58
53
|
on roles :db do
|
59
|
-
psql '-c', %Q{"DROP database \\"#{fetch(:pg_database)}\\";"}
|
60
|
-
psql '-c', %Q{"DROP user \\"#{fetch(:pg_username)}\\";"}
|
54
|
+
psql'execute', fetch(:pg_system_db), '-c', %Q{"DROP database \\"#{fetch(:pg_database)}\\";"} if database_exists?
|
55
|
+
psql 'execute', fetch(:pg_system_db),'-c', %Q{"DROP user \\"#{fetch(:pg_username)}\\";"}if database_user_exists?
|
56
|
+
remove_extensions
|
61
57
|
end
|
58
|
+
puts 'Removed database.yml from all hosts, Database, Database User, and Removed Extensions'
|
62
59
|
end
|
63
60
|
|
64
61
|
task :remove_app_database_yml_files do
|
65
62
|
# We should never delete archetype files. The generate_database_yml_archetype task will handle updates
|
66
63
|
on release_roles :app do
|
67
|
-
|
68
|
-
execute :rm, database_yml_file
|
69
|
-
end
|
64
|
+
execute :rm, database_yml_file if test "[ -e #{database_yml_file} ]"
|
70
65
|
end
|
71
66
|
end
|
72
67
|
|
73
68
|
desc 'Remove pg_extension from postgresql db'
|
74
69
|
task :remove_extensions do
|
75
|
-
|
76
|
-
on roles :db do
|
77
|
-
# remove in reverse order if extension is present
|
78
|
-
Array( fetch(:pg_extensions) ).reverse.each do |ext|
|
79
|
-
psql_on_app_db '-c', %Q{"DROP EXTENSION IF EXISTS #{ext};"} unless [nil, false, ""].include?(ext)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
desc 'Add the hstore extension to postgresql'
|
85
|
-
task :add_hstore do
|
86
|
-
next unless fetch(:pg_use_hstore)
|
87
|
-
on roles :db do
|
88
|
-
psql_on_app_db '-c', %Q{"CREATE EXTENSION IF NOT EXISTS hstore;"}
|
89
|
-
end
|
70
|
+
remove_extensions
|
90
71
|
end
|
91
72
|
|
92
73
|
desc 'Add pg_extension to postgresql db'
|
93
74
|
task :add_extensions do
|
94
|
-
next unless Array( fetch(:pg_extensions) ).any?
|
95
75
|
on roles :db do
|
96
|
-
Array( fetch(:pg_extensions) ).
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
else
|
101
|
-
error "postgresql: adding extension #{ext} failed!"
|
102
|
-
exit 1
|
76
|
+
if Array( fetch(:pg_extensions) ).any?
|
77
|
+
Array( fetch(:pg_extensions) ).each do |ext|
|
78
|
+
next if [nil, false, ''].include?(ext)
|
79
|
+
psql 'execute', fetch(:pg_system_db), '-c', %Q{"CREATE EXTENSION IF NOT EXISTS #{ext};"}unless extension_exists?(ext)
|
103
80
|
end
|
104
81
|
end
|
105
82
|
end
|
106
83
|
end
|
107
84
|
|
108
|
-
desc 'Create database'
|
109
|
-
task :
|
85
|
+
desc 'Create pg_username in database'
|
86
|
+
task :create_database_user do
|
110
87
|
on roles :db do
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
exit 1
|
88
|
+
unless database_user_exists?
|
89
|
+
# If you use CREATE USER instead of CREATE ROLE the LOGIN right is granted automatically; otherwise you must specify it in the WITH clause of the CREATE statement.
|
90
|
+
psql 'execute', fetch(:pg_system_db), '-c', %Q{"CREATE USER \\"#{fetch(:pg_username)}\\" PASSWORD '#{fetch(:pg_password)}';"}
|
115
91
|
end
|
116
92
|
end
|
117
93
|
end
|
118
94
|
|
119
|
-
desc 'Create
|
120
|
-
task :
|
95
|
+
desc 'Create database'
|
96
|
+
task :create_database do
|
121
97
|
on roles :db do
|
122
|
-
|
123
|
-
|
124
|
-
unless psql_on_db fetch(:pg_system_db), '-c', %Q{"CREATE USER \\"#{fetch(:pg_username)}\\" PASSWORD '#{fetch(:pg_password)}';"}
|
125
|
-
error "postgresql: creating database user \"#{fetch(:pg_username)}\" failed!"
|
126
|
-
exit 1
|
98
|
+
unless database_exists?
|
99
|
+
psql 'execute', fetch(:pg_system_db), '-c', %Q{"CREATE DATABASE \\"#{fetch(:pg_database)}\\" OWNER \\"#{fetch(:pg_username)}\\";"}
|
127
100
|
end
|
128
101
|
end
|
129
102
|
end
|
@@ -148,7 +121,6 @@ namespace :postgresql do
|
|
148
121
|
on primary :db do
|
149
122
|
database_yml_contents = download! archetype_database_yml_file
|
150
123
|
end
|
151
|
-
|
152
124
|
on release_roles :all do
|
153
125
|
execute :mkdir, '-pv', File.dirname(database_yml_file)
|
154
126
|
Net::SCP.upload!(self.host.hostname, self.host.user, StringIO.new(database_yml_contents), database_yml_file)
|
@@ -163,26 +135,31 @@ namespace :postgresql do
|
|
163
135
|
|
164
136
|
desc 'Postgresql setup tasks'
|
165
137
|
task :setup do
|
166
|
-
puts "*
|
138
|
+
puts "* ===== Postgresql Setup ===== *\n"
|
139
|
+
puts " All psql commands will be run #{fetch(:pg_without_sudo) ? 'without sudo' : 'with sudo'}\n You can modify this in your app/config/deploy/#{fetch(:rails_env)}.rb by setting the pg_without_sudo boolean.\n"
|
167
140
|
if release_roles(:app).empty?
|
168
|
-
|
141
|
+
warn " WARNING: There are no servers in your app/config/deploy/#{fetch(:rails_env)}.rb with a :app role... Skipping Postgresql setup."
|
169
142
|
else
|
170
143
|
invoke 'postgresql:remove_app_database_yml_files' # Deletes old yml files from all servers. Allows you to avoid having to manually delete the files on your app servers to get a new pool size for example. Don't touch the archetype file to avoid deleting generated passwords.
|
171
144
|
if release_roles(:db).empty? # Test to be sure we have a :db role host
|
172
|
-
|
145
|
+
warn " WARNING: There is no server in your app/config/deploy/#{fetch(:rails_env)}.rb with a :db role... Skipping Postgresql setup."
|
146
|
+
elsif !fetch(:pg_password) && !fetch(:pg_generate_random_password) && !fetch(:pg_ask_for_password)
|
147
|
+
warn " WARNING: There is no :pg_password set in your app/config/deploy/#{fetch(:rails_env)}.rb.\n If you don't wish to set it, 'set :pg_generate_random_password, true' or 'set :pg_ask_for_password, true' are available!"
|
148
|
+
elsif fetch(:pg_generate_random_password) && fetch(:pg_ask_for_password)
|
149
|
+
warn " WARNING: You cannot have both :pg_generate_random_password and :pg_ask_for_password enabled in app/config/deploy/#{fetch(:rails_env)}.rb."
|
173
150
|
else
|
174
|
-
invoke 'postgresql:
|
151
|
+
invoke 'postgresql:create_database_user'
|
175
152
|
invoke 'postgresql:create_database'
|
176
|
-
invoke 'postgresql:add_hstore'
|
177
153
|
invoke 'postgresql:add_extensions'
|
178
154
|
invoke 'postgresql:generate_database_yml_archetype'
|
179
155
|
invoke 'postgresql:generate_database_yml'
|
180
156
|
end
|
181
157
|
end
|
158
|
+
puts "* ============================= *"
|
182
159
|
end
|
183
160
|
end
|
184
161
|
|
185
162
|
desc 'Server setup tasks'
|
186
163
|
task :setup do
|
187
|
-
invoke
|
164
|
+
invoke 'postgresql:setup'
|
188
165
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: capistrano-postgresql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bruno Sutic
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-06-
|
12
|
+
date: 2018-06-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: capistrano
|