capistrano-ops 0.2.2 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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