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.
@@ -1,24 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  namespace :invoke do
4
+ # Defalut to :app roles
5
+ rake_roles = fetch(:rake_roles, :app)
2
6
 
3
- # Defalut to :app roles
4
- rake_roles = fetch(:rake_roles, :app)
5
-
6
- desc "Execute a rake task on a remote server (cap invoke:rake TASK=db:migrate)"
7
- task :rake do
8
- if ENV['TASK']
9
- on roles(rake_roles) do
10
- within current_path do
11
- with rails_env: fetch(:rails_env) do
12
- execute :rake, ENV['TASK']
13
- end
7
+ desc 'Execute a rake task on a remote server (cap invoke:rake TASK=db:migrate)'
8
+ task :rake do
9
+ if ENV['TASK']
10
+ on roles(rake_roles) do
11
+ within current_path do
12
+ with rails_env: fetch(:rails_env) do
13
+ execute :rake, ENV['TASK']
14
14
  end
15
15
  end
16
-
17
- else
18
- puts "\n\nFailed! You need to specify the 'TASK' parameter!",
19
- "Usage: cap <stage> invoke:rake TASK=your:task"
20
16
  end
17
+
18
+ else
19
+ puts "\n\nFailed! You need to specify the 'TASK' parameter!",
20
+ 'Usage: cap <stage> invoke:rake TASK=your:task'
21
21
  end
22
-
23
22
  end
24
-
23
+ end
@@ -8,6 +8,8 @@ if defined?(Capistrano::VERSION) && Gem::Version.new(Capistrano::VERSION).releas
8
8
  load File.expand_path('capistrano/v3/tasks/figaro_yml.rake', __dir__)
9
9
  load File.expand_path('capistrano/v3/tasks/logs.rake', __dir__)
10
10
  load File.expand_path('capistrano/v3/tasks/invoke.rake', __dir__)
11
+ path = File.expand_path(__dir__)
12
+ Dir.glob("#{path}/capistrano/v3/tasks/backup/**/*.rake").each { |f| load f }
11
13
  else
12
14
  puts 'Capistrano 3 is required to use this gem'
13
15
  end
@@ -1,30 +1,34 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Notification
2
- class Api
3
- attr_accessor :notification_type, :notification_level
4
+ class Api
5
+ attr_accessor :notification_type, :notification_level
6
+
7
+ def initialize(notification_type: ENV['NOTIFICATION_TYPE'], notification_level: ENV['NOTIFICATION_LEVEL'])
8
+ self.notification_type = notification_type
9
+ self.notification_level = notification_level || 'error'
10
+ end
4
11
 
5
- def initialize(notification_type: ENV['NOTIFICATION_TYPE'], notification_level: ENV['NOTIFICATION_LEVEL'])
6
- self.notification_type = notification_type
7
- self.notification_level = notification_level || 'error'
8
- end
12
+ def send_backup_notification(result, title, content, webhook_data = nil)
13
+ return if notification_type.nil?
14
+
15
+ case notification_type
16
+ when 'slack'
17
+ Slack.new.backup_notification(result, title, content, notification_level)
18
+ when 'webhook'
19
+ Webhook.new.backup_notification(result, webhook_data, notification_level)
20
+ end
21
+ end
9
22
 
10
- def send_backup_notification(result, date, database, backup_path)
11
- return if notification_type.nil?
12
- case notification_type
13
- when 'slack'
14
- Slack.new.backup_notification(result, date, database, backup_path, notification_level)
15
- when 'webhook'
16
- Webhook.new.backup_notification(result, date, database, backup_path, notification_level)
17
- end
18
- end
23
+ def send_notification(message)
24
+ return if notification_type.nil?
19
25
 
20
- def send_notification(message)
21
- return if notification_type.nil?
22
- case notification_type
23
- when 'slack'
24
- Slack.new.notify(message)
25
- when 'webhook'
26
- p 'webhook'
27
- end
28
- end
26
+ case notification_type
27
+ when 'slack'
28
+ Slack.new.notify(message)
29
+ when 'webhook'
30
+ p 'webhook'
31
+ end
29
32
  end
30
- end
33
+ end
34
+ end
@@ -1,67 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'json'
5
+
1
6
  module Notification
2
- class Slack
3
- require 'uri'
4
- require 'net/http'
5
- require 'net/https'
6
- def initialize
7
- @slack_secret = ENV['SLACK_SECRET']
8
- @slack_channel = ENV['SLACK_CHANNEL']
9
- @slack_base_url ='https://slack.com/api/'
10
- end
7
+ class Slack
8
+ def initialize
9
+ @slack_secret = ENV['SLACK_SECRET']
10
+ @slack_channel = ENV['SLACK_CHANNEL']
11
+ @conn = Faraday.new(url: 'https://slack.com/api/') do |faraday|
12
+ faraday.headers['Content-Type'] = 'application/json'
13
+ faraday.headers['Authorization'] = "Bearer #{@slack_secret}"
14
+ end
15
+ end
16
+
17
+ def notify(message)
18
+ return if @slack_secret.nil? || @slack_channel.nil?
11
19
 
12
- def notify(message)
13
- return if @slack_secret.nil? || @slack_channel.nil?
14
- uri = URI.parse("#{@slack_base_url}chat.postMessage")
15
- http = Net::HTTP.new(uri.host, uri.port)
16
- http.use_ssl = true
17
- request = Net::HTTP::Post.new(uri.request_uri, initHeader = {'Content-Type' =>'application/json', 'Authorization' => 'Bearer ' + @slack_secret})
18
- request.body = {
19
- channel: @slack_channel,
20
- text: message
21
- }.to_json
22
- response = http.request(request)
23
- puts response.body
20
+ begin
21
+ res = @conn.post('chat.postMessage') do |req|
22
+ req.body = {
23
+ "channel": @slack_channel,
24
+ "text": message
25
+ }.to_json
24
26
  end
27
+ response = JSON.parse(res.body)
28
+ raise Notification::Error, response['error'] if response['ok'] == false
25
29
 
26
- def backup_notification(result, date, database, backup_path, notification_level)
27
- return if @slack_secret.nil? || @slack_channel.nil?
28
- return if notification_level == 'error' && result
29
- uri = URI.parse("#{@slack_base_url}chat.postMessage")
30
- http = Net::HTTP.new(uri.host, uri.port)
31
- http.use_ssl = true
32
- request = Net::HTTP::Post.new(uri.request_uri, initHeader = {'Content-Type' =>'application/json', 'Authorization' => 'Bearer ' + @slack_secret})
33
- message_one = "Backup of #{database} successfully finished at #{Time.now}"
34
- message_two = "Backup path:\`#{backup_path}/#{database}_#{date}.dump\`"
35
- data = {
36
- channel: @slack_channel,
37
- blocks: [
38
- {
39
- type: 'header',
40
- text: {
41
- type: 'plain_text',
42
- text: ENV['DEFAULT_URL'] || "#{database} Backup",
43
- emoji: true
44
- }
45
- },
46
- {
47
- type: 'section',
48
- text: {
49
- type: 'mrkdwn',
50
- text: result ? "#{message_one}\n#{message_two}" : "Backup of #{database} failed at #{Time.now}"
51
- }
52
- }
53
- ]
54
- }
55
- request.body = data.to_json
56
- begin
57
- response = JSON.parse(http.request(request).body)
58
- if response['ok'] == false
59
- raise Notification::Error, response['error']
60
- end
61
- response
62
- rescue => e
63
- puts "Slack error: \n\t#{e.message}"
64
- end
30
+ response
31
+ rescue Notification::Error => e
32
+ puts "Slack error: \n\t#{e.message}"
33
+ end
34
+ end
35
+
36
+ def backup_notification(result, title, content, notification_level)
37
+ return if @slack_secret.nil? || @slack_channel.nil?
38
+ return if notification_level == 'error' && result
39
+
40
+ begin
41
+ res = @conn.post('chat.postMessage') do |req|
42
+ req.body = {
43
+ channel: @slack_channel,
44
+ blocks: [
45
+ {
46
+ type: 'header',
47
+ text: {
48
+ type: 'plain_text',
49
+ text: title || "#{Rails.env} Message",
50
+ emoji: true
51
+ }
52
+ },
53
+ {
54
+ type: 'section',
55
+ text: {
56
+ type: 'mrkdwn',
57
+ text: content || 'No content'
58
+ }
59
+ }
60
+ ]
61
+ }.to_json
65
62
  end
63
+ response = JSON.parse(res.body)
64
+ raise Notification::Error, response['error'] if response['ok'] == false
65
+
66
+ response
67
+ rescue Notification::Error => e
68
+ puts "Slack error: \n\t#{e.message}"
69
+ end
66
70
  end
71
+ end
67
72
  end
@@ -1,40 +1,47 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Notification
2
- class Webhook
3
- require 'uri'
4
- require 'net/http'
5
- require 'net/https'
6
- require 'openssl'
7
- require 'json'
8
-
9
- def initialize
10
- @webhook_url = ENV['WEBHOOK_URL']
11
- @secret = ENV['WEBHOOK_SECRET']
12
- end
13
-
14
- def generate_signature(payload_body)
15
- "md5=#{OpenSSL::HMAC.hexdigest('md5', ENV['WEBHOOK_SECRET'], payload_body)}"
16
- end
4
+ class Webhook
5
+ require 'faraday'
6
+ require 'openssl'
7
+ require 'json'
17
8
 
18
- def backup_notification(result, date, database, backup_path, notification_level)
19
- return if @webhook_url.nil? || @secret.nil?
20
- return if result && ENV['NOTIFICATION_LEVEL'] == 'error'
21
- data = {
22
- domain: ENV['DEFAULT_URL'] || "#{database} Backup",
23
- backupPath: result ? backup_path : nil,
24
- backupDate: date,
25
- }.to_json
26
-
27
- uri = URI.parse(@webhook_url)
28
- https = Net::HTTP.new(uri.host, uri.port)
29
- https.use_ssl = uri.scheme == "https"
30
- request = Net::HTTP::Post.new(uri.path.empty? ? "/" : uri.path, initHeader = {'Content-Type' =>'application/json', 'x-hub-signature' => generate_signature("#{data}")})
31
- request.body = "#{data}"
32
- begin
33
- response = https.request(request)
34
- response.to_hash
35
- rescue => e
36
- puts "Webhook error: \n\t#{e.message}"
37
- end
9
+ def initialize
10
+ @webhook_url = ENV['WEBHOOK_URL']
11
+ @secret = ENV['WEBHOOK_SECRET']
12
+ @conn = Faraday.new(url: @webhook_url) do |faraday|
13
+ faraday.headers['Content-Type'] = 'application/json'
14
+ end
15
+ end
16
+
17
+ def generate_signature(payload_body)
18
+ "md5=#{OpenSSL::HMAC.hexdigest('md5', ENV['WEBHOOK_SECRET'], payload_body)}"
19
+ end
20
+
21
+ def backup_notification(result, webhook_data, _notification_level)
22
+ return if @webhook_url.nil? || @secret.nil?
23
+ return if result && notification_level == 'error'
24
+
25
+ @date = webhook_data[:date]
26
+ @database = webhook_data[:database]
27
+ @backup_path = webhook_data[:backup_path]
28
+
29
+ @data = {
30
+ domain: ENV['DEFAULT_URL'] || "#{@database} Backup",
31
+ backupPath: result ? @backup_path : nil,
32
+ backupDate: @date
33
+ }.to_json
34
+
35
+ begin
36
+ @response = @conn.post do |req|
37
+ req.headers['x-hub-signature'] = generate_signature(@data.to_s)
38
+ req.body = @data
38
39
  end
40
+
41
+ @response.to_hash
42
+ rescue StandardError => e
43
+ puts "Webhook error: \n\t#{e.message}"
44
+ end
39
45
  end
40
- end
46
+ end
47
+ end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'capistrano/ops/notification/api'
2
4
  require 'capistrano/ops/notification/slack'
3
5
  require 'capistrano/ops/notification/webhook'
4
6
 
5
7
  module Notification
6
- class Error < StandardError; end
7
- end
8
+ class Error < StandardError; end
9
+ end
@@ -12,4 +12,4 @@ module Capistrano
12
12
  end
13
13
  end
14
14
  end
15
- end
15
+ end
@@ -2,38 +2,71 @@
2
2
 
3
3
  # rubocop:disable Metrics/BlockLength
4
4
  namespace :pg do
5
- default_backup_path = Rails.env.development? ? 'tmp/backups' : '../../shared/backups'
6
- database = Rails.configuration.database_configuration[Rails.env]['database']
7
- username = Rails.configuration.database_configuration[Rails.env]['username']
8
- password = Rails.configuration.database_configuration[Rails.env]['password']
9
- hostname = Rails.configuration.database_configuration[Rails.env]['host']
10
- portnumber = Rails.configuration.database_configuration[Rails.env]['port']
11
- backup_path = Rails.root.join(default_backup_path).to_s
5
+ @database = Rails.configuration.database_configuration[Rails.env]['database']
6
+ @username = Rails.configuration.database_configuration[Rails.env]['username']
7
+ @password = Rails.configuration.database_configuration[Rails.env]['password']
8
+ @hostname = Rails.configuration.database_configuration[Rails.env]['host']
9
+ @portnumber = Rails.configuration.database_configuration[Rails.env]['port']
10
+ @backup_path = Rails.root.join(Rails.env.development? ? 'tmp/backups' : '../../shared/backups').to_s
12
11
  backups_enabled = Rails.env.production? || ENV['BACKUPS_ENABLED'] == 'true'
13
-
12
+ external_backup = Rails.env.production? || ENV['EXTERNAL_BACKUP_ENABLED'] == 'true'
14
13
  task :dump do
15
- api = Notification::Api.new
16
- date = Time.now.to_i
17
- user = username.present? ? " -U #{username}" : ''
18
- host = hostname.present? ? " -h #{hostname}" : ''
19
- port = portnumber.present? ? " -p #{portnumber}" : ''
20
- # rubocop:disable Layout/LineLength
21
- dump_cmd = "export PGPASSWORD='#{password}' && cd #{backup_path} && pg_dump -Fc -d #{database}#{user}#{host}#{port} > #{database}_#{date}.dump"
22
- # rubocop:enable Layout/LineLength
23
- if backups_enabled
24
- system "mkdir -p #{backup_path}" unless Dir.exist?(backup_path)
25
- result = system(dump_cmd)
26
- api.send_backup_notification(result, date, database, backup_path)
27
- # Notification::Slack.new.backup_notification(result, date, database, backup_path)
14
+ unless backups_enabled
15
+ puts 'dump: Backups are disabled'
16
+ exit(0)
28
17
  end
29
- if backups_enabled
30
- # rubocop:disable Layout/LineLength
31
- p result ? "Backup created: #{backup_path}/#{database}_#{date}.dump" : "Backup failed, created empty file at #{backup_path}/#{database}_#{date}.dump"
32
- system "rm #{backup_path}/#{database}_#{date}.dump" unless result
33
- # rubocop:enable Layout/LineLength
18
+
19
+ notification = Notification::Api.new
20
+ commandlist = dump_cmd
21
+
22
+ system "mkdir -p #{@backup_path}" unless Dir.exist?(@backup_path)
23
+
24
+ result = system(commandlist.join(' && '))
25
+
26
+ if ENV['BACKUP_PROVIDER'].present? && external_backup && result
27
+ puts "Uploading #{@filename} to #{ENV['BACKUP_PROVIDER']}..."
28
+ provider = Backup::Api.new
29
+ begin
30
+ provider.upload("#{@backup_path}/#{@filename}", @filename.to_s)
31
+ puts "#{@filename} uploaded to #{ENV['BACKUP_PROVIDER']}"
32
+ rescue StandardError => e
33
+ puts "#{@filename} upload failed: #{e.message}"
34
+ end
35
+ end
36
+ notification.send_backup_notification(result, title, content(result), { date: @date, database: @database, backup_path: @backup_path })
37
+ puts result ? "Backup created: #{@backup_path}/#{@filename}" : 'Backup failed removing dump file'
38
+ system "rm #{@backup_path}/#{@filename}" unless result
39
+ end
40
+
41
+ def title
42
+ ENV['DEFAULT_URL'] || "#{Rails.env} Backup"
43
+ end
44
+
45
+ def content(result)
46
+ messages = []
47
+ if result
48
+ messages << "Backup of #{@database} successfully finished at #{Time.now}"
49
+ messages << "Backup path:\`#{@backup_path}/#{@filename}\`"
34
50
  else
35
- p 'dump: Backups are disabled'
51
+ messages << "Backup of #{@database} failed at #{Time.now}"
36
52
  end
53
+ messages.join("\n")
54
+ end
55
+
56
+ def dump_cmd
57
+ @date = Time.now.to_i
58
+ options = []
59
+ options << " -d #{@database}" if @database.present?
60
+ options << " -U #{@username}" if @username.present?
61
+ options << " -h #{@hostname}" if @hostname.present?
62
+ options << " -p #{@portnumber}" if @portnumber.present?
63
+
64
+ @filename = "#{@database}_#{@date}.dump"
65
+
66
+ commandlist = []
67
+ commandlist << "export PGPASSWORD='#{@password}'"
68
+ commandlist << "cd #{@backup_path}"
69
+ commandlist << "pg_dump -Fc #{options.join('')} > #{@filename}"
37
70
  end
38
71
  end
39
72
  # rubocop:enable Metrics/BlockLength
@@ -1,19 +1,58 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'rake'
3
4
  namespace :pg do
4
- default_backup_path = Rails.env.development? ? 'tmp/backups' : '../../shared/backups'
5
- database = Rails.configuration.database_configuration[Rails.env]['database']
6
-
7
- backup_path = Rails.root.join(default_backup_path).to_s
5
+ @backup_path = Rails.root.join(Rails.env.development? ? 'tmp/backups' : '../../shared/backups').to_s
6
+ @database = Rails.configuration.database_configuration[Rails.env]['database']
7
+ @env_local_no = ENV['NUMBER_OF_LOCAL_BACKUPS']
8
+ @env_external_no = ENV['NUMBER_OF_EXTERNAL_BACKUPS']
9
+ @total_local_backups_no = (@env_local_no || ENV['NUMBER_OF_BACKUPS'] || 7).to_i
10
+ @total_external_backups_no = (@env_external_no || ENV['NUMBER_OF_BACKUPS'] || 7).to_i
8
11
  backups_enabled = Rails.env.production? || ENV['BACKUPS_ENABLED'] == 'true'
12
+ external_backup = Rails.env.production? || ENV['EXTERNAL_BACKUP_ENABLED'] == 'true'
9
13
 
10
14
  task :remove_old_dumps do
11
- bash_regex = "'#{database}.{0,}\.dump'"
12
- total_backups_no = ENV['NUMBER_OF_BACKUPS'] || 1
13
- # rubocop:disable Layout/LineLength
14
- cmd = "cd #{backup_path} && ls -lt | grep -E -i #{bash_regex} | tail -n +#{total_backups_no.to_i + 1} | awk '{print $9}'|xargs rm -rf"
15
- # rubocop:enable Layout/LineLength
16
- system(cmd) if backups_enabled
17
- p backups_enabled ? 'Old backups removed' : 'remove_old_dumps: Backups are disabled'
15
+ bash_regex = "'#{@database}.{0,}\.dump'"
16
+
17
+ unless backups_enabled
18
+ puts 'remove_old_dumps: Backups are disabled'
19
+ exit(0)
20
+ end
21
+ unless @total_local_backups_no.positive?
22
+ puts "remove_old_dumps: No local cleanup because option '#{if @env_local_no
23
+ 'NUMBER_OF_LOCAL_BACKUPS='
24
+ else
25
+ 'NUMBER_OF_BACKUPS='
26
+ end}#{@total_local_backups_no}' sets unlimited backups"
27
+
28
+ end
29
+
30
+ commandlist = [
31
+ "cd #{@backup_path} && ls -lt ",
32
+ "grep -E -i #{bash_regex} ",
33
+ "tail -n +#{@total_local_backups_no + 1} ",
34
+ "awk '{print $9}' ",
35
+ 'xargs rm -rf'
36
+ ]
37
+
38
+ system(commandlist.join(' | '))
39
+
40
+ if ENV['BACKUP_PROVIDER'].present? && external_backup
41
+ unless @total_external_backups_no.positive?
42
+ puts "remove_old_dumps: No external cleanup because option '#{if @env_external_no
43
+ 'NUMBER_OF_EXTERNAL_BACKUPS='
44
+ else
45
+ 'NUMBER_OF_BACKUPS='
46
+ end}#{@total_external_backups_no}' sets unlimited backups"
47
+ exit(0)
48
+ end
49
+ provider = Backup::Api.new
50
+ begin
51
+ result = provider.remove_old_backups(@database, @total_external_backups_no)
52
+ rescue StandardError => e
53
+ puts "remove_old_dumps failed: #{e.message}"
54
+ end
55
+ puts 'remove_old_dumps finished' if result
56
+ end
18
57
  end
19
58
  end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Metrics/BlockLength
4
+ namespace :storage do
5
+ @backup_path = Rails.root.join(Rails.env.development? ? 'tmp/backups' : '../../shared/backups').to_s
6
+ @storage_path = Rails.root.join(Rails.env.development? ? 'storage' : '../../shared/storage').to_s
7
+ backups_enabled = Rails.env.production? || ENV['BACKUPS_ENABLED'] == 'true'
8
+ external_backup = Rails.env.production? || ENV['EXTERNAL_BACKUP_ENABLED'] == 'true'
9
+
10
+ desc 'backup storage'
11
+ task :backup do
12
+ unless backups_enabled
13
+ puts 'storage: Backups are disabled'
14
+ exit(0)
15
+ end
16
+ notification = Notification::Api.new
17
+
18
+ date = Time.now.to_i
19
+ @filename = "storage_#{date}.tar.gz"
20
+ FileUtils.mkdir_p(@backup_path) unless Dir.exist?(@backup_path)
21
+ result = system "tar -zcf #{@backup_path}/#{@filename} -C #{@storage_path} ."
22
+ FileUtils.rm_rf("#{@backup_path}/#{filename}") unless result
23
+ puts result ? "Backup created: #{@backup_path}/#{@filename} (#{size_str(File.size("#{@backup_path}/#{@filename}"))})" : 'Backup failed removing dump file'
24
+
25
+ if ENV['BACKUP_PROVIDER'].present? && external_backup && result
26
+ puts "Uploading #{@filename} to #{ENV['BACKUP_PROVIDER']}..."
27
+ provider = Backup::Api.new
28
+ begin
29
+ provider.upload("#{@backup_path}/#{@filename}", @filename.to_s)
30
+ puts "#{@filename} uploaded to #{ENV['BACKUP_PROVIDER']}"
31
+ rescue StandardError => e
32
+ puts "#{@filename} upload failed: #{e.message}"
33
+ end
34
+ end
35
+ notification.send_backup_notification(result, title, message(result), { date: date, backup_path: @backup_path, database: 'storage' })
36
+ end
37
+
38
+ def title
39
+ ENV['DEFAULT_URL'] || "#{Rails.env} Backup"
40
+ end
41
+
42
+ def message(result)
43
+ messages = []
44
+ if result
45
+ messages << "Backup of storage folder successfully finished at #{Time.now}"
46
+ messages << "Backup path:\`#{@backup_path}/#{@filename}\`"
47
+ else
48
+ messages << "Backup of storage folder failed at #{Time.now}"
49
+ end
50
+ messages.join("\n")
51
+ end
52
+
53
+ def size_str(size)
54
+ case size
55
+ when 0..1024
56
+ "#{size} B"
57
+ when 1024..1024 * 1024
58
+ "#{size / 1024} KB"
59
+ when 1024 * 1024..1024 * 1024 * 1024
60
+ "#{size / 1024 / 1024} MB"
61
+ when 1024 * 1024 * 1024..1024 * 1024 * 1024 * 1024
62
+ "#{size / 1024 / 1024 / 1024} GB"
63
+ end
64
+ end
65
+ end
66
+ # rubocop:enable Metrics/BlockLength
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rake'
4
+ namespace :storage do
5
+ backup_path = Rails.root.join(Rails.env.development? ? 'tmp/backups' : '../../shared/backups').to_s
6
+ backups_enabled = Rails.env.production? || ENV['BACKUPS_ENABLED'] == 'true'
7
+ external_backup = Rails.env.production? || ENV['EXTERNAL_BACKUP_ENABLED'] == 'true'
8
+
9
+ @env_local_no = ENV['NUMBER_OF_LOCAL_BACKUPS']
10
+ @env_external_no = ENV['NUMBER_OF_EXTERNAL_BACKUPS']
11
+ @total_local_backups_no = (@env_local_no || ENV['NUMBER_OF_BACKUPS'] || 7).to_i
12
+ @total_external_backups_no = (@env_external_no || ENV['NUMBER_OF_BACKUPS'] || 7).to_i
13
+ desc 'remove old storage backups'
14
+ task :remove_old_backups do
15
+ bash_regex = "'storage_.{0,}\.tar.gz'"
16
+
17
+ unless backups_enabled
18
+ puts 'remove_old_backups: Backups are disabled'
19
+ exit(0)
20
+ end
21
+
22
+ unless @total_local_backups_no.positive?
23
+ puts "remove_old_backups: No local cleanup because option '#{if @env_local_no
24
+ 'NUMBER_OF_LOCAL_BACKUPS='
25
+ else
26
+ 'NUMBER_OF_BACKUPS='
27
+ end}#{@total_local_backups_no}' sets unlimited backups"
28
+ end
29
+
30
+ commandlist = [
31
+ "cd #{backup_path} && ls -lt ",
32
+ "grep -E -i #{bash_regex} ",
33
+ "tail -n +#{@total_local_backups_no + 1} ",
34
+ "awk '{print $9}' ",
35
+ 'xargs rm -rf'
36
+ ]
37
+
38
+ system(commandlist.join(' | '))
39
+
40
+ if ENV['BACKUP_PROVIDER'].present? && external_backup
41
+ unless @total_external_backups_no.positive?
42
+ puts "remove_old_backups: No external cleanup because option '#{if @env_external_no
43
+ 'NUMBER_OF_EXTERNAL_BACKUPS='
44
+ else
45
+ 'NUMBER_OF_BACKUPS='
46
+ end}#{@total_external_backups_no}' sets unlimited backups"
47
+ exit(0)
48
+ end
49
+ provider = Backup::Api.new
50
+ begin
51
+ result = provider.remove_old_backups('storage_', @total_external_backups_no)
52
+ rescue StandardError => e
53
+ puts "remove_old_backups failed: #{e.message}"
54
+ end
55
+ puts 'remove_old_backups finished' if result
56
+ end
57
+ end
58
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Capistrano
3
4
  module Ops
4
- VERSION = '0.2.2'
5
+ VERSION = '0.2.4'
5
6
  end
6
7
  end