Class: Backup

Inherits:
Object
  • Object
show all
Defined in:
lib/backup/backup.rb

Direct Known Subclasses

DbBackup, FilesBackup

Constant Summary collapse

DATE_FORMAT =
'%Y-%m-%d-%H-%M'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(compress: true, encrypt: nil, dry_run: true, quiet: false) ⇒ Backup

Returns a new instance of Backup.



10
11
12
13
14
15
16
17
# File 'lib/backup/backup.rb', line 10

def initialize(compress: true, encrypt: nil, dry_run: true, quiet: false)
  @compress = compress
  @encrypt = encrypt.nil? ? !ENV['GPGKEY'].nil? : encrypt
  @dry_run = dry_run
  @quiet = quiet
  raise "GPGKEY environment variable should be specified for encryption" if encrypt? && ENV['GPGKEY'].nil?
  ensure_path
end

Instance Attribute Details

#dry_runObject (readonly)

Returns the value of attribute dry_run.



7
8
9
# File 'lib/backup/backup.rb', line 7

def dry_run
  @dry_run
end

#quietObject (readonly)

Returns the value of attribute quiet.



7
8
9
# File 'lib/backup/backup.rb', line 7

def quiet
  @quiet
end

Instance Method Details

#backup_commandObject

Main pipe, which generates data for backup



56
57
58
# File 'lib/backup/backup.rb', line 56

def backup_command
  "echo Just text to backup"
end

#backup_typeObject



31
32
33
# File 'lib/backup/backup.rb', line 31

def backup_type
  self.class.to_s.gsub('Backup', '').downcase
end

#backup_type_filenameObject



35
36
37
# File 'lib/backup/backup.rb', line 35

def backup_type_filename
  backup_type
end

#clean_files(prefix = 'local') ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/backup/backup.rb', line 111

def clean_files(prefix = 'local')
  puts(dry_run ? 'Performing dry run' : '!!!! Cleaning backups !!!!')
  if prefix =~ /^\//
    process_clean_files(prefix)
  else
    # Process each backup type
    Dir["#{Techinform::BACKUPS_PREFIX}/#{prefix}/*"].each do |type|
      puts "Type: #{type}"
      # Get all backup name
      Dir["#{type}/*"].each do |path|
        process_clean_files(path)
      end
    end
  end
end

#compress?Boolean

Returns:

  • (Boolean)


19
20
21
# File 'lib/backup/backup.rb', line 19

def compress?
  @compress
end

#debug?Boolean

Returns:

  • (Boolean)


27
28
29
# File 'lib/backup/backup.rb', line 27

def debug?
  ENV['DEBUG'] == 'true'
end

#encrypt?Boolean

Returns:

  • (Boolean)


23
24
25
# File 'lib/backup/backup.rb', line 23

def encrypt?
  @encrypt
end

#encrypt_compress_pipe_commandObject



60
61
62
63
64
65
66
# File 'lib/backup/backup.rb', line 60

def encrypt_compress_pipe_command
  if encrypt?
    "| gpg2 --encrypt #{"--compress-algo=bzip2" if compress?} --recipient=#{ENV['GPGKEY']}"
  else
    "| #{bzip2}" if compress?
  end
end

#ensure_pathObject



80
81
82
# File 'lib/backup/backup.rb', line 80

def ensure_path
  `mkdir -p #{path}`
end

#filenameObject



39
40
41
# File 'lib/backup/backup.rb', line 39

def filename
  "#{backup_type_filename}-#{DateTime.now.strftime(DATE_FORMAT)}.#{filename_extension}"
end

#filename_extension(base = 'tar') ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
# File 'lib/backup/backup.rb', line 43

def filename_extension(base = 'tar')
  if encrypt?
    "#{base}.gpg"
  else
    if compress?
      "#{base}.bz2"
    else
      base
    end
  end
end

#filepathObject



76
77
78
# File 'lib/backup/backup.rb', line 76

def filepath
  "#{path}/#{filename}"
end

#get_datetime_from_filename(filename) ⇒ Object



84
85
86
# File 'lib/backup/backup.rb', line 84

def get_datetime_from_filename filename
  DateTime.strptime(filename.split('.').first.split('-')[-5..-1].join('-'), DATE_FORMAT)
end

#human_filesize(size) ⇒ Object



192
193
194
195
196
197
198
199
200
# File 'lib/backup/backup.rb', line 192

def human_filesize(size)
  {
      ' B'  => 1024,
      ' KB' => 1024 * 1024,
      ' MB' => 1024 * 1024 * 1024,
      ' GB' => 1024 * 1024 * 1024 * 1024,
      ' TB' => 1024 * 1024 * 1024 * 1024 * 1024
  }.each_pair { |e, s| return "#{(size.to_f / (s / 1024)).round(2)}#{e}" if size < s }
end

#mark_file_to_delete(path) ⇒ Object

Mark files to delete { ‘filenpath’ => true, ‘filepath2’ => false } true - delete file, false - do not delete



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/backup/backup.rb', line 163

def mark_file_to_delete(path)
  result = {}
  months_taken = []
  days_taken = []
  Dir["#{path}/*"].sort.each do |file|
    datetime = get_datetime_from_filename(file)
    day_id = datetime.strftime('%Y-%m-%d')
    month_id = datetime.strftime('%Y-%m')
    if datetime < (DateTime.now << 2)     # 2 month ago
      if datetime.day == 1 && !(months_taken.include? month_id)
        result[file] = false
        months_taken << month_id
      else
        result[file] = true
      end
    elsif datetime < DateTime.now - 14 # 2 weeks ago
      if [1, 7, 14, 21].include?(datetime.day) && !(days_taken.include?(day_id))
        result[file] = false
        days_taken << day_id
      else
        result[file] = true
      end
    else
      result[file] = false
    end
  end
  return result
end

#minimum_backup_sizeObject

Change it in child class



101
102
103
# File 'lib/backup/backup.rb', line 101

def minimum_backup_size
  50
end

#output_commandObject



68
69
70
# File 'lib/backup/backup.rb', line 68

def output_command
  "> #{filepath}"
end

#pathObject



72
73
74
# File 'lib/backup/backup.rb', line 72

def path
  "#{Techinform::BACKUPS_LOCAL_PREFIX}/#{backup_type}"
end


88
89
90
# File 'lib/backup/backup.rb', line 88

def print_info
  puts "Run backup to #{filepath}..."
end

#process_clean_files(path) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/backup/backup.rb', line 127

def process_clean_files(path)
  puts "Process files in path #{path}"
  # Get all files
  mark_files = mark_file_to_delete(path)
  mark_files.each do |file, delete|
    puts "#{file} #{"*" if delete}"
  end
  show_statistics(mark_files)
  unless dry_run
    return if !quiet && !HighLine.new.agree("Delete #{mark_files.select{|file, delete| delete}.keys.size} files - Are you sure? (yes/no)")
    # Actually delete files
    mark_files.select{|file, delete| delete}.keys.each do |file|
      result = `rm #{file}`
      puts result unless result.empty?
    end
  end
end

#runObject



92
93
94
95
96
97
98
# File 'lib/backup/backup.rb', line 92

def run
  print_info
  command = "#{backup_command} #{encrypt_compress_pipe_command} #{output_command}"
  puts "Command: #{command}" if debug?
  output = `#{command}`
  puts output unless output.empty?
end

#show_statistics(mark_files) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/backup/backup.rb', line 145

def show_statistics(mark_files)
  files_to_delete, files_to_store, size_to_delete, size_to_store  = 0, 0, 0, 0
  mark_files.each do |file, is_delete|
    if is_delete
      files_to_delete += 1
      size_to_delete += File.size(file)
    else
      files_to_store += 1
      size_to_store += File.size(file)
    end
  end
  puts "\u{1f480} Files to delete - #{files_to_delete}, files size - #{human_filesize(size_to_delete)} \u{1f480}"
  puts "Files to store - #{files_to_store}, files size - #{human_filesize(size_to_store)}"
end

#verify_backupObject

It worth to redefine that method to better check backup integrity Return true if everything ok



107
108
109
# File 'lib/backup/backup.rb', line 107

def verify_backup
  File.size(filepath) > minimum_backup_size
end