capistrano-ops 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +21 -0
- data/README.md +61 -13
- data/capistrano-ops.gemspec +5 -5
- data/lib/capistrano/ops/backup/api.rb +40 -0
- data/lib/capistrano/ops/backup/s3.rb +52 -0
- data/lib/capistrano/ops/backup.rb +8 -0
- data/lib/capistrano/ops/capistrano/v3/tasks/backup/backup_helper.rb +50 -0
- data/lib/capistrano/ops/capistrano/v3/tasks/backup/database/create.rake +18 -0
- data/lib/capistrano/ops/capistrano/v3/tasks/backup/database/pull.rake +28 -0
- data/lib/capistrano/ops/capistrano/v3/tasks/backup/storage/create.rake +18 -0
- data/lib/capistrano/ops/capistrano/v3/tasks/backup/storage/pull.rake +30 -0
- data/lib/capistrano/ops/capistrano/v3/tasks/backup.rake +10 -14
- data/lib/capistrano/ops/capistrano/v3/tasks/figaro_yml.rake +59 -60
- data/lib/capistrano/ops/capistrano/v3/tasks/invoke.rake +16 -17
- data/lib/capistrano/ops/capistrano.rb +2 -0
- data/lib/capistrano/ops/notification/api.rb +29 -25
- data/lib/capistrano/ops/notification/slack.rb +65 -60
- data/lib/capistrano/ops/notification/webhook.rb +43 -36
- data/lib/capistrano/ops/notification.rb +4 -2
- data/lib/capistrano/ops/railtie.rb +1 -1
- data/lib/capistrano/ops/tasks/pg/dump.rake +60 -27
- data/lib/capistrano/ops/tasks/pg/remove_old_dumps.rake +50 -11
- data/lib/capistrano/ops/tasks/storage/backup.rake +66 -0
- data/lib/capistrano/ops/tasks/storage/remove_old_backups.rake +58 -0
- data/lib/capistrano/ops/version.rb +2 -1
- data/lib/capistrano/ops.rb +19 -18
- metadata +45 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6897d38c35cb8b0dfb713d16d0eb0c390c431636ea5c6565e1dc457b96a29c6b
|
4
|
+
data.tar.gz: 9789f0e37f0767403324c1ca68c97759a8ebdbdb5a3e4ac6d362b76dfc5064ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4607175b27284ed6d19ca2fe3032dccde17f54cb62dfbfc43c614af031abf9990b873b89b1d905c74d2acb48dc4e94a3eec6b50bbff18dee0079b2a5264d04dd
|
7
|
+
data.tar.gz: 1ce1060464559ce566320e9ef7a1700d5d94ee688e6f8aea85f7dbd2548e78bfc5e6cb1f5e751b38e9b566e7411e89587d4207eb6c0349592d0cacab854e6ffc
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
AllCops:
|
2
|
+
NewCops: disable
|
3
|
+
TargetRubyVersion: 2.7
|
4
|
+
Layout/LineLength:
|
5
|
+
Max: 160
|
6
|
+
Metrics/MethodLength:
|
7
|
+
Max: 50
|
8
|
+
Metrics/ClassLength:
|
9
|
+
Max: 750
|
10
|
+
Metrics/BlockLength:
|
11
|
+
Max: 50
|
12
|
+
Metrics/ParameterLists:
|
13
|
+
Max: 6
|
14
|
+
Metrics/AbcSize:
|
15
|
+
Max: 60
|
16
|
+
Metrics/CyclomaticComplexity:
|
17
|
+
Max: 25
|
18
|
+
Metrics/PerceivedComplexity:
|
19
|
+
Max: 25
|
20
|
+
Style/Documentation:
|
21
|
+
Enabled: false
|
data/README.md
CHANGED
@@ -9,6 +9,9 @@ Library of useful scripts for DevOps using capistrano with rails.
|
|
9
9
|
```ruby
|
10
10
|
'capistrano', '~> 3.0'
|
11
11
|
'whenever'
|
12
|
+
'capistrano-figaro-yml'
|
13
|
+
|
14
|
+
# hint: if you use other aws-sdk gems, its possible that you have to update them too
|
12
15
|
```
|
13
16
|
|
14
17
|
## Installation
|
@@ -43,8 +46,12 @@ require 'capistrano/ops'
|
|
43
46
|
|
44
47
|
| Script | Description |
|
45
48
|
| ------------------------------------------------ | ----------------------------------------------------------------- |
|
46
|
-
| `cap <environment> backup:create` | creates backup of postgres database on the server
|
47
|
-
| `cap <environment> backup:pull` | download latest postgres backup from server
|
49
|
+
| `cap <environment> backup:create` | creates backup of postgres database on the server (deprecated) |
|
50
|
+
| `cap <environment> backup:pull` | download latest postgres backup from server (deprecated) |
|
51
|
+
| `cap <environment> backup:database:create` | creates backup of postgres database on the server |
|
52
|
+
| `cap <environment> backup:database:pull` | download latest postgres backup from server |
|
53
|
+
| `cap <environment> backup:storage:create` | creates backup of storage on the server |
|
54
|
+
| `cap <environment> backup:storage:pull` | download latest storage backup from server |
|
48
55
|
| `cap <environment> figaro_yml:compare` | compare local application.yml with server application.yml |
|
49
56
|
| `cap <environment> figaro_yml:get` | shows env vars from server application.yml configured thru figaro |
|
50
57
|
| `cap <environment> logs:rails` | display server log live |
|
@@ -52,6 +59,8 @@ require 'capistrano/ops'
|
|
52
59
|
| `cap <environment> invoke:rake TASK=<your:task>` | invoke rake task on server |
|
53
60
|
| `rake pg:dump` | creates postgres database backup |
|
54
61
|
| `rake pg:remove_old_dumps` | remove old postgres backups |
|
62
|
+
| `rake storage:backup` | creates backup of storage |
|
63
|
+
| `rake storage:remove_old_backups` | remove old storage backups |
|
55
64
|
|
56
65
|
## Usage
|
57
66
|
|
@@ -69,17 +78,26 @@ production:
|
|
69
78
|
|
70
79
|
### Optional Settings for backup task
|
71
80
|
|
72
|
-
| env
|
73
|
-
|
|
74
|
-
| NUMBER_OF_BACKUPS
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
| env | description | type/options |
|
82
|
+
| -------------------------- | --------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------: |
|
83
|
+
| NUMBER_OF_BACKUPS | number of backups to keep (default: 7) | `number` |
|
84
|
+
| NUMBER_OF_LOCAL_BACKUPS | number of backups to keep locally (default: nil) | `number` |
|
85
|
+
| NUMBER_OF_EXTERNAL_BACKUPS | number of backups to keep externally (default: nil) | `number` |
|
86
|
+
| BACKUPS_ENABLED | enable/disable backup task (default: Rails.env == 'production') | `boolean` |
|
87
|
+
| EXTERNAL_BACKUP_ENABLED | enable/disable external backup (default: false) (only if 'BACKUPS_ENABLED', needs additional setup) | `boolean` |
|
88
|
+
| DEFAULT_URL | notification message title (default: "#{database} Backup") | `string` |
|
89
|
+
| NOTIFICATION_TYPE | for notification (default: nil) | `string` (`webhook`/`slack`) |
|
90
|
+
| NOTIFICATION_LEVEL | for notification (default: nil) | `string` (`info`/`error`) |
|
91
|
+
| SLACK_SECRET | for slack integration | `string` (e.g. `xoxb-1234567890-1234567890-1234567890-1234567890`) |
|
92
|
+
| SLACK_CHANNEL | for slack integration | `string` (e.g. `C234567890`) |
|
93
|
+
| WEBHOOK_URL | Webhook server to send message | e.g `http://example.com` |
|
94
|
+
| WEBHOOK_SECRET | Secret to send with uses md5-hmac hexdigest in header`x-hub-signature` | --- |
|
95
|
+
| BACKUP_PROVIDER | Backup provider (default: nil) | `string` (`s3`) |
|
96
|
+
| S3_BACKUP_BUCKET | S3 bucket name for backups | `string` |
|
97
|
+
| S3_BACKUP_REGION | S3 region for backups | `string` |
|
98
|
+
| S3_BACKUP_KEY | S3 access key for backups | `string` |
|
99
|
+
| S3_BACKUP_SECRET | S3 secret key for backups | `string` |
|
100
|
+
| S3_BACKUP_ENDPOINT | S3 endpoint for backups (optional, used for other S3 compatible services) | `string` |
|
83
101
|
|
84
102
|
### use with whenever/capistrano
|
85
103
|
|
@@ -93,10 +111,12 @@ set :output, -> { '2>&1 | logger -t whenever_cron' }
|
|
93
111
|
|
94
112
|
every :day, at: '2:00 am' do
|
95
113
|
rake 'pg:dump'
|
114
|
+
rake 'storage:backup'
|
96
115
|
end
|
97
116
|
|
98
117
|
every :day, at: '3:00 am' do
|
99
118
|
rake 'pg:remove_old_dumps'
|
119
|
+
rake 'storage:remove_old_backups'
|
100
120
|
end
|
101
121
|
```
|
102
122
|
|
@@ -144,6 +164,34 @@ if you want to use notification level you have to add this to your `application.
|
|
144
164
|
NOTIFICATION_LEVEL: 'info' # default is 'error'
|
145
165
|
```
|
146
166
|
|
167
|
+
## Backups
|
168
|
+
|
169
|
+
if you want to configure the number of backups you have to add this to your `application.yml`
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
NUMBER_OF_BACKUPS: 7 # default is 7 (local + external)
|
173
|
+
```
|
174
|
+
|
175
|
+
to fine tune the number of local and external backups you can use this:
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
NUMBER_OF_LOCAL_BACKUPS: 7 # default is nil (local)
|
179
|
+
NUMBER_OF_EXTERNAL_BACKUPS: 7 # default is nil (local)
|
180
|
+
```
|
181
|
+
|
182
|
+
### Backup provider
|
183
|
+
|
184
|
+
if you want to use an external backup provider you have to add this to your `application.yml`
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
BACKUP_PROVIDER: 's3'
|
188
|
+
S3_BACKUP_BUCKET: '<your-s3-bucket>'
|
189
|
+
S3_BACKUP_REGION: '<your-s3-region>'
|
190
|
+
S3_BACKUP_KEY: '<your-s3-key>'
|
191
|
+
S3_BACKUP_SECRET: '<your-s3-secret>'
|
192
|
+
S3_BACKUP_ENDPOINT: '<your-s3-endpoint>' # optional, used for other S3 compatible services
|
193
|
+
```
|
194
|
+
|
147
195
|
## Contributing
|
148
196
|
|
149
197
|
1. Fork it ( https://github.com/zauberware/capistrano-ops/fork )
|
data/capistrano-ops.gemspec
CHANGED
@@ -18,12 +18,12 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.test_files = `git ls-files -- test/{functional,unit}/*`.split("\n")
|
19
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
20
20
|
s.require_paths = ['lib']
|
21
|
-
|
22
|
-
s.required_ruby_version = '
|
23
|
-
|
24
|
-
s.add_dependency '
|
21
|
+
|
22
|
+
s.required_ruby_version = '~> 2.7.0'
|
23
|
+
s.add_dependency 'aws-sdk-s3', '~> 1.128'
|
24
|
+
s.add_dependency 'faraday'
|
25
25
|
s.add_dependency 'nokogiri'
|
26
|
-
|
26
|
+
s.add_dependency 'rails'
|
27
27
|
s.add_development_dependency 'bundler', '~> 2.4.12'
|
28
28
|
s.add_development_dependency 'rake', '~> 10.0'
|
29
29
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Backup
|
4
|
+
class Api
|
5
|
+
attr_accessor :backup_provider, :provider_config
|
6
|
+
|
7
|
+
def initialize(provider: ENV['BACKUP_PROVIDER'], provider_config: {})
|
8
|
+
self.backup_provider = provider
|
9
|
+
self.provider_config = provider_config
|
10
|
+
end
|
11
|
+
|
12
|
+
def upload(backup_file, filename)
|
13
|
+
case backup_provider
|
14
|
+
when 's3'
|
15
|
+
s3 = Backup::S3.new(**provider_config)
|
16
|
+
s3.upload(backup_file, filename)
|
17
|
+
when 'scp'
|
18
|
+
p 'SCP backup not implemented yet'
|
19
|
+
when 'rsync'
|
20
|
+
p 'Rsync backup not implemented yet'
|
21
|
+
else
|
22
|
+
raise Backup::Error, 'Backup provider not configured'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def remove_old_backups(basename, keep)
|
27
|
+
case backup_provider
|
28
|
+
when 's3'
|
29
|
+
s3 = Backup::S3.new(**provider_config)
|
30
|
+
s3.remove_old_backups(basename, keep: keep)
|
31
|
+
when 'scp'
|
32
|
+
p 'SCP backup not implemented yet'
|
33
|
+
when 'rsync'
|
34
|
+
p 'Rsync backup not implemented yet'
|
35
|
+
else
|
36
|
+
raise Backup::Error, 'Backup provider not configured'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Backup
|
4
|
+
require 'aws-sdk-s3'
|
5
|
+
class S3
|
6
|
+
attr_accessor :endpoint, :region, :access_key_id, :secret_access_key, :s3_client
|
7
|
+
|
8
|
+
def initialize(endpoint: ENV['S3_BACKUP_ENDPOINT'], region: ENV['S3_BACKUP_REGION'], access_key_id: ENV['S3_BACKUP_KEY'],
|
9
|
+
secret_access_key: ENV['S3_BACKUP_SECRET'])
|
10
|
+
self.endpoint = endpoint
|
11
|
+
self.region = region
|
12
|
+
self.access_key_id = access_key_id
|
13
|
+
self.secret_access_key = secret_access_key
|
14
|
+
config = {
|
15
|
+
region: region,
|
16
|
+
access_key_id: access_key_id,
|
17
|
+
secret_access_key: secret_access_key
|
18
|
+
}
|
19
|
+
config[:endpoint] = endpoint unless endpoint.nil?
|
20
|
+
self.s3_client = Aws::S3::Client.new(config)
|
21
|
+
end
|
22
|
+
|
23
|
+
def upload(backup_file, key)
|
24
|
+
begin
|
25
|
+
s3_client.put_object(
|
26
|
+
bucket: ENV['S3_BACKUP_BUCKET'],
|
27
|
+
key: key,
|
28
|
+
body: File.open(backup_file)
|
29
|
+
)
|
30
|
+
rescue StandardError => e
|
31
|
+
puts "Error uploading backup to S3: #{e.message}"
|
32
|
+
raise e
|
33
|
+
end
|
34
|
+
'File uploaded to S3'
|
35
|
+
end
|
36
|
+
|
37
|
+
def remove_old_backups(basename, keep: 5)
|
38
|
+
bucket = ENV['S3_BACKUP_BUCKET']
|
39
|
+
all_items = s3_client.list_objects_v2(bucket: bucket, prefix: basename).contents
|
40
|
+
count = all_items.count
|
41
|
+
if count <= keep
|
42
|
+
p 'Nothing to remove'
|
43
|
+
return
|
44
|
+
end
|
45
|
+
items = all_items.sort_by(&:last_modified).reverse.slice(keep..-1).map(&:key)
|
46
|
+
items.each do |item|
|
47
|
+
p "Removing #{item} from S3"
|
48
|
+
s3_client.delete_object(bucket: bucket, key: item)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BackupHelper
|
4
|
+
def backup_file_name(type)
|
5
|
+
regex = type == 'storage' ? "'.{0,}\.tar.gz'" : "'.{0,}\.dump'"
|
6
|
+
@backup_file_name ||= capture "cd #{shared_path}/backups && ls -lt | grep -E -i #{regex} | head -n 1 | awk '{print $9}'"
|
7
|
+
end
|
8
|
+
|
9
|
+
def backup_file_size
|
10
|
+
@backup_file_size ||= capture "cd #{shared_path}/backups && wc -c #{@backup_file_name} | awk '{print $1}'"
|
11
|
+
end
|
12
|
+
|
13
|
+
def download_backup(backup_file, type)
|
14
|
+
puts "Downloading #{type} backup"
|
15
|
+
download! "#{shared_path}/backups/#{backup_file}"
|
16
|
+
puts "Download finished\nDeleting temporary backup..."
|
17
|
+
cleanup_backup(backup_file, "Download finished\nDeleting temporary backup...")
|
18
|
+
end
|
19
|
+
|
20
|
+
def cleanup_backup(backup_file, message)
|
21
|
+
puts message
|
22
|
+
execute "cd #{shared_path}/backups && rm #{backup_file}"
|
23
|
+
puts 'Temporary backup deleted'
|
24
|
+
end
|
25
|
+
|
26
|
+
def question(question, default = 'n', &block)
|
27
|
+
print "#{question} #{default.downcase == 'n' ? '(y/N)' : '(Y/n)'}: "
|
28
|
+
input = $stdin.gets.strip.downcase
|
29
|
+
answer = (input.empty? ? default : input).downcase.to_s
|
30
|
+
|
31
|
+
if %w[y n].include?(answer)
|
32
|
+
block.call(answer == 'y')
|
33
|
+
else
|
34
|
+
question(question, default, &block)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def prepare_env
|
39
|
+
@env = "RAILS_ENV=#{fetch(:stage)}"
|
40
|
+
@path_cmd = "PATH=$HOME/.rbenv/versions/#{RUBY_VERSION}/bin:$PATH"
|
41
|
+
@test_command = "cd #{release_path} && #{@path_cmd} && #{@env}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def size_str(size)
|
45
|
+
units = %w[B KB MB GB TB]
|
46
|
+
e = (Math.log(size) / Math.log(1024)).floor
|
47
|
+
s = format('%.2f', size.to_f / 1024**e)
|
48
|
+
s.sub(/\.?0*$/, units[e])
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../backup_helper'
|
4
|
+
namespace :backup do
|
5
|
+
namespace :database do
|
6
|
+
include BackupHelper
|
7
|
+
# Default to :app role
|
8
|
+
rake_roles = fetch(:rake_roles, :app)
|
9
|
+
|
10
|
+
desc 'create a backup of the server database'
|
11
|
+
task :create do
|
12
|
+
on roles(rake_roles) do
|
13
|
+
puts 'Creating backup...'
|
14
|
+
execute "#{prepare_env} BACKUPS_ENABLED=true bundle exec rake pg:dump"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../backup_helper'
|
4
|
+
namespace :backup do
|
5
|
+
namespace :database do
|
6
|
+
include BackupHelper
|
7
|
+
# Default to :app role
|
8
|
+
rake_roles = fetch(:rake_roles, :app)
|
9
|
+
|
10
|
+
desc 'pull latest database dump from server to local'
|
11
|
+
task :pull do
|
12
|
+
on roles(rake_roles) do
|
13
|
+
puts 'Creating temporary backup...'
|
14
|
+
execute "#{prepare_env} BACKUPS_ENABLED=true EXTERNAL_BACKUP_ENABLED=false bundle exec rake pg:dump"
|
15
|
+
puts "Backup created\nPrepare download..."
|
16
|
+
backup_file = backup_file_name('database')
|
17
|
+
backup_size = backup_file_size
|
18
|
+
question("Backup size: #{size_str(backup_size.to_i)}. Continue?", 'n') do |answer|
|
19
|
+
if answer
|
20
|
+
download_backup(backup_file, 'database')
|
21
|
+
else
|
22
|
+
cleanup_backup(backup_file, "Aborting...\nDeleting temporary backup...")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../backup_helper'
|
4
|
+
namespace :backup do
|
5
|
+
namespace :storage do
|
6
|
+
include BackupHelper
|
7
|
+
# Default to :app role
|
8
|
+
rake_roles = fetch(:rake_roles, :app)
|
9
|
+
|
10
|
+
desc 'create storage dump on server'
|
11
|
+
task :create do
|
12
|
+
on roles(rake_roles) do
|
13
|
+
puts 'Creating backup...'
|
14
|
+
execute "#{prepare_env} BACKUPS_ENABLED=true EXTERNAL_BACKUP_ENABLED=false bundle exec rake storage:backup"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../backup_helper'
|
4
|
+
namespace :backup do
|
5
|
+
namespace :storage do
|
6
|
+
include BackupHelper
|
7
|
+
# Default to :app role
|
8
|
+
rake_roles = fetch(:rake_roles, :app)
|
9
|
+
desc 'pull latest storage dump from server to local'
|
10
|
+
task :pull do
|
11
|
+
on roles(rake_roles) do
|
12
|
+
puts 'Creating temporary backup...'
|
13
|
+
execute "#{prepare_env} BACKUPS_ENABLED=true EXTERNAL_BACKUP_ENABLED=false bundle exec rake storage:backup"
|
14
|
+
puts 'Backup created'
|
15
|
+
backup_file = backup_file_name('storage')
|
16
|
+
backup_size = backup_file_size
|
17
|
+
|
18
|
+
puts 'Prepare download...'
|
19
|
+
|
20
|
+
question("Backup size: #{size_str(backup_size.to_i)}. Continue?", 'n') do |answer|
|
21
|
+
if answer
|
22
|
+
download_backup(backup_file, 'storage')
|
23
|
+
else
|
24
|
+
cleanup_backup(backup_file, "Aborting...\nDeleting temporary backup...")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,29 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'backup/backup_helper'
|
4
|
+
|
3
5
|
namespace :backup do
|
6
|
+
include BackupHelper
|
4
7
|
# Default to :app role
|
5
8
|
rake_roles = fetch(:rake_roles, :app)
|
6
9
|
|
7
|
-
desc 'create a backup of the server database'
|
10
|
+
desc 'create a backup of the server database (deprecated, use backup:database:create instead)'
|
8
11
|
task :create do
|
9
12
|
on roles(rake_roles) do
|
10
|
-
|
11
|
-
#
|
12
|
-
path_cmd = "PATH=$HOME/.rbenv/versions/#{RUBY_VERSION}/bin:$PATH"
|
13
|
-
# rubocop:enable Layout/LineLength
|
14
|
-
execute "cd #{release_path} && #{path_cmd} && #{env} BACKUPS_ENABLED=true bundle exec rake pg:dump"
|
13
|
+
warn "deprecated: use 'backup:database:create' instead, in future versions this task will be removed"
|
14
|
+
execute "#{prepare_env} BACKUPS_ENABLED=true EXTERNAL_BACKUP_ENABLED=false bundle exec rake pg:dump"
|
15
15
|
end
|
16
16
|
end
|
17
|
-
desc 'pull latest database backups from server to local'
|
17
|
+
desc 'pull latest database backups from server to local (deprecated, use backup:database:pull instead)'
|
18
18
|
task :pull do
|
19
19
|
on roles(rake_roles) do
|
20
|
-
|
21
|
-
|
22
|
-
#
|
23
|
-
download! "#{shared_path}/backups.tar.gz", 'backups.tar.gz'
|
24
|
-
execute "rm #{shared_path}/backups.tar.gz"
|
25
|
-
system 'tar -xzf backups.tar.gz'
|
26
|
-
system 'rm backups.tar.gz'
|
20
|
+
warn "deprecated: use 'backup:database:pull' instead, in future versions this task will be removed"
|
21
|
+
backup_file = backup_file_name('database')
|
22
|
+
download! "#{shared_path}/backups/#{backup_file}"
|
27
23
|
end
|
28
24
|
end
|
29
25
|
end
|
@@ -7,63 +7,63 @@ namespace :figaro_yml do
|
|
7
7
|
|
8
8
|
desc 'get the `application.yml` file from server and create local if it does not exist'
|
9
9
|
task :get do
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
10
|
+
env = fetch(:stage)
|
11
|
+
if !File.exist?('config/application.yml')
|
12
|
+
puts 'config/application.yml does not exist, creating it from all stages'
|
13
|
+
run_locally do
|
14
|
+
yamls = {}
|
15
|
+
stages = Dir.glob('config/deploy/*.rb')
|
16
|
+
puts "found #{stages.count} stages"
|
17
|
+
stages.map do |f|
|
18
|
+
stage = File.basename(f, '.rb')
|
19
|
+
puts "download #{stage} application.yml"
|
20
|
+
begin
|
21
21
|
res = capture "cap #{stage} figaro_yml:get_stage"
|
22
|
-
yamls= yamls.merge(YAML.safe_load(res))
|
23
|
-
|
24
|
-
|
25
|
-
end
|
26
|
-
yamls
|
22
|
+
yamls = yamls.merge(YAML.safe_load(res))
|
23
|
+
rescue StandardError
|
24
|
+
puts "could not get #{stage} application.yml"
|
27
25
|
end
|
28
|
-
|
29
|
-
puts "writing to config/application.yml"
|
30
|
-
write_to_file('config/application.yml', yamls.to_yaml)
|
26
|
+
yamls
|
31
27
|
end
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
28
|
+
# write to new file
|
29
|
+
puts 'writing to config/application.yml'
|
30
|
+
write_to_file('config/application.yml', yamls.to_yaml)
|
31
|
+
end
|
32
|
+
else
|
33
|
+
local_yml = YAML.safe_load(File.read('config/application.yml'))
|
34
|
+
on roles(rake_roles) do
|
35
|
+
remote = capture("cat #{shared_path}/config/application.yml")
|
36
|
+
remote_yml = YAML.safe_load(remote)
|
37
|
+
remote_stage = remote_yml[env.to_s]
|
38
|
+
puts "remote application.yml stage '#{env}':\n\n"
|
39
|
+
puts "#{remote}\r\n"
|
40
|
+
puts "\r\n"
|
41
|
+
loop do
|
42
|
+
print "Overwrite local application.yml stage '#{env}'? (y/N): "
|
43
|
+
input = $stdin.gets.strip.downcase
|
44
|
+
answer = (input.empty? ? 'N' : input).downcase.to_s
|
45
|
+
|
46
|
+
next unless %w[y n].include?(answer)
|
47
|
+
|
48
|
+
if answer == 'y'
|
49
|
+
puts 'Updating local application.yml'
|
50
|
+
local_yml[env.to_s] = remote_stage
|
51
|
+
write_to_file('config/application.yml', local_yml.to_yaml)
|
52
|
+
exit
|
55
53
|
end
|
56
|
-
|
57
|
-
exit
|
54
|
+
break
|
58
55
|
end
|
56
|
+
puts 'Nothing written to local application.yml'
|
57
|
+
exit
|
59
58
|
end
|
60
59
|
end
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
60
|
+
end
|
61
|
+
|
62
|
+
task :get_stage do
|
63
|
+
on roles(rake_roles) do
|
64
|
+
puts capture "cat #{shared_path}/config/application.yml"
|
66
65
|
end
|
66
|
+
end
|
67
67
|
|
68
68
|
desc 'compare and set the figaro_yml file on the server'
|
69
69
|
task :compare do
|
@@ -93,12 +93,12 @@ namespace :figaro_yml do
|
|
93
93
|
result2 = compare_hashes(local_stage_env, remote_stage_env)
|
94
94
|
if !result1.empty? || !result2.empty?
|
95
95
|
loop do
|
96
|
-
print 'Update remote application.yml? (y/N): '
|
96
|
+
print 'Update remote application.yml? (y/N): '
|
97
97
|
input = $stdin.gets.strip.downcase
|
98
98
|
answer = (input.empty? ? 'N' : input).downcase.to_s
|
99
99
|
|
100
|
-
next unless %w
|
101
|
-
|
100
|
+
next unless %w[y n].include?(answer)
|
101
|
+
|
102
102
|
if answer == 'y'
|
103
103
|
puts 'Updating remote application.yml'
|
104
104
|
invoke 'figaro_yml:setup'
|
@@ -116,25 +116,24 @@ namespace :figaro_yml do
|
|
116
116
|
changes = false
|
117
117
|
local_server = hash1.to_a - hash2.to_a
|
118
118
|
server_local = hash2.to_a - hash1.to_a
|
119
|
-
|
120
|
-
[local_server + server_local].flatten(1).to_h.
|
119
|
+
|
120
|
+
[local_server + server_local].flatten(1).to_h.each_key do |k|
|
121
121
|
new_value = hash1[k].to_s
|
122
|
-
new_value = new_value.empty? ?
|
122
|
+
new_value = new_value.empty? ? 'nil' : new_value
|
123
123
|
old_value = hash2[k].to_s
|
124
|
-
old_value = old_value.empty? ?
|
124
|
+
old_value = old_value.empty? ? 'nil' : old_value
|
125
125
|
|
126
126
|
if old_value != new_value
|
127
|
-
|
128
|
-
|
127
|
+
puts "#{k}: #{old_value} => #{new_value} \r\n"
|
128
|
+
changes = true
|
129
129
|
end
|
130
130
|
end
|
131
|
-
end
|
131
|
+
end
|
132
132
|
|
133
133
|
def write_to_file(file, content)
|
134
134
|
File.open(file, 'w') do |f|
|
135
135
|
f.write(content)
|
136
136
|
end
|
137
137
|
end
|
138
|
-
|
139
138
|
end
|
140
139
|
# rubocop:enable Metrics/BlockLength
|