backup-agent 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 30d19db4d2b7b5ccd2d5b22ba4984b12cbf2d91b
4
+ data.tar.gz: eca7fd9183ba78f8b1bee805167ffcb30c967548
5
+ SHA512:
6
+ metadata.gz: 580cb22de5ecfdeb372e1b2fa163d979123f2099da0f4dd4b0d17105f8acd739627e5b6645db613fdae6d3a5ec8e624897a377edde1421924a1999506e09f293
7
+ data.tar.gz: 5656f4668372fff2b3d1be5dedeb644aa97a26d672a9d90c52d21e5897512125ac2ef36ac077883a212ea138b5590d5a09d54b0f381f0c9f7e960c660c81df56
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ .idea
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in confo.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Yaroslav Konoplov
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,16 @@
1
+ ```ruby
2
+ BackupAgent.configure_s3 do
3
+ set :access_key_id, 'xxx'
4
+ set :secret_access_key, 'yyy'
5
+ set :region, 'eu-central-1'
6
+ end
7
+
8
+ BackupAgent.perform_backup do
9
+ set :s3_bucket, 'my-backups'
10
+ end
11
+ ```
12
+
13
+ ## Gemfile
14
+ ```ruby
15
+ gem 'backup-agent', github: 'yivo/backup-agent'
16
+ ```
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'backup-agent'
5
+ s.version = '1.0.0'
6
+ s.authors = ['Yaroslav Konoplov']
7
+ s.email = ['yaroslav@inbox.com']
8
+ s.summary = 'Easy AWS S3 backup'
9
+ s.description = 'Easy AWS S3 backup'
10
+ s.homepage = 'http://github.com/yivo/backup-agent'
11
+ s.license = 'MIT'
12
+
13
+ s.executables = `git ls-files -z -- bin/*`.split("\x0").map{ |f| File.basename(f) }
14
+ s.files = `git ls-files -z`.split("\x0")
15
+ s.test_files = `git ls-files -z -- {test,spec,features}/*`.split("\x0")
16
+ s.require_paths = ['lib']
17
+
18
+ s.add_dependency 'aws-sdk'
19
+ s.add_dependency 'confo-config', '>= 1.0.0'
20
+ s.add_dependency 'activesupport', '>= 3.2.0'
21
+ end
@@ -0,0 +1,19 @@
1
+ puts "Ruby version #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
2
+
3
+ %w(rubygems aws-sdk fileutils confo-config shellwords).each { |lib| require lib }
4
+
5
+ require_relative 'backup-agent/s3_config'
6
+ require_relative 'backup-agent/task_config'
7
+ require_relative 'backup-agent/service'
8
+ require_relative 'backup-agent/features'
9
+ require_relative 'backup-agent/s3'
10
+
11
+ module BackupAgent
12
+ class << self
13
+ def perform_backup(&block)
14
+ task_config = TaskConfig.new
15
+ task_config.configure(&block) if block
16
+ Service.new(task_config).perform_backup
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,32 @@
1
+ module BackupAgent
2
+ class << self
3
+ def check_mysql
4
+ if @mysql_check.nil?
5
+ @mysql_check = system('/usr/bin/env mysql --version') ? true : (puts('MySQL is not installed'); false)
6
+ end
7
+ @mysql_check
8
+ end
9
+
10
+ def check_mongodb
11
+ if @mongodb_check.nil?
12
+ @mongodb_check = system('/usr/bin/env mongod --version') ? true : (puts('MongoDB is not installed'))
13
+ end
14
+ @mongodb_check
15
+ end
16
+
17
+ def check_features
18
+ check_mysql
19
+ check_mongodb
20
+ end
21
+
22
+ def mysql_installed?
23
+ check_features
24
+ !!@mysql_check
25
+ end
26
+
27
+ def mongodb_installed?
28
+ check_features
29
+ !!@mongodb_check
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,22 @@
1
+ module BackupAgent
2
+ class << self
3
+ def s3_config
4
+ @s3_config ||= S3Config.new
5
+ end
6
+
7
+ def configure_s3(&block)
8
+ @s3 = nil
9
+ s3_config.configure(&block)
10
+ end
11
+
12
+ def s3
13
+ @s3 ||= begin
14
+ Aws.config.update(
15
+ region: s3_config.region,
16
+ credentials: Aws::Credentials.new(s3_config.access_key_id, s3_config.secret_access_key)
17
+ )
18
+ Aws::S3::Resource.new
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,10 @@
1
+ module BackupAgent
2
+ class S3Config < Confo::Config
3
+ def initialize(*)
4
+ super
5
+ set :access_key_id, nil
6
+ set :secret_access_key, nil
7
+ set :region, nil
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,109 @@
1
+ module BackupAgent
2
+ class Service
3
+ attr_reader :config
4
+
5
+ def initialize(config)
6
+ @config = config
7
+ end
8
+
9
+ def perform_backup
10
+ @started_at = Time.now.utc
11
+ @timestamp = @started_at.strftime('%s - %A %d %B %Y %H:%M')
12
+ make_tmp_dir
13
+ backup_mysql if BackupAgent.mysql_installed?
14
+ backup_mongodb if BackupAgent.mongodb_installed?
15
+ backup_directories
16
+ backup_files
17
+ cleanup_old_backups
18
+ ensure
19
+ remove_tmp_dir
20
+ end
21
+
22
+ protected
23
+
24
+ def backup_directories
25
+ config.get(:directories).each do |name, dir|
26
+ dir_filename = "dir-#{name}.tar.gz"
27
+ cmd = "cd #{dir} && /usr/bin/env tar -czf #{tmp_path}/#{dir_filename} ."
28
+ puts "Exec #{cmd}"
29
+ system(cmd)
30
+
31
+ obj = BackupAgent.s3.bucket(config.s3_bucket).object("#{@timestamp}/#{dir_filename}")
32
+ obj.upload_file("#{tmp_path}/#{dir_filename}")
33
+ end
34
+ end
35
+
36
+ def backup_files
37
+ config.get(:files).each do |name, files|
38
+ begin
39
+ files_tmp_path = File.join(tmp_path, "#{name}-tmp")
40
+ file_bunch_name = "files-#{name}.tar.gz"
41
+
42
+ FileUtils.mkdir_p(files_tmp_path)
43
+ FileUtils.cp(files.select { |el| File.exists?(el) }, files_tmp_path)
44
+
45
+ cmd = "cd #{files_tmp_path} && /usr/bin/env tar -czf #{tmp_path}/#{file_bunch_name} ."
46
+ system(cmd)
47
+
48
+ obj = BackupAgent.s3.bucket(config.s3_bucket).object("#{@timestamp}/#{file_bunch_name}")
49
+ obj.upload_file("#{tmp_path}/#{file_bunch_name}")
50
+ ensure
51
+ FileUtils.remove_dir(files_tmp_path)
52
+ end
53
+ end
54
+ end
55
+
56
+ def backup_mysql
57
+ config.get(:mysql_databases).each do |db|
58
+ db_filename = "mysql-#{db}.gz"
59
+ dump = "/usr/bin/env mysqldump #{config.get(:mysql_connect)} #{config.get(:mysqldump_options).join(' ')} #{db}"
60
+ gzip = "/usr/bin/env gzip -5 -c > #{tmp_path}/#{db_filename}"
61
+
62
+ puts "Exec #{dump} | #{gzip}"
63
+ system "#{dump} | #{gzip}"
64
+
65
+ obj = BackupAgent.s3.bucket(config.s3_bucket).object("#{@timestamp}/#{db_filename}")
66
+ obj.upload_file("#{tmp_path}/#{db_filename}")
67
+ end
68
+ end
69
+
70
+ def backup_mongodb
71
+ mongo_dump_dir = File.join(tmp_path, 'mongo')
72
+ FileUtils.mkdir_p(mongo_dump_dir)
73
+
74
+ config.get(:mongo_databases).each do |db|
75
+ db_filename = "mongo-#{db}.tgz"
76
+ dump = "/usr/bin/env mongodump #{config.get(:mongo_connect)} -d #{db} -o #{mongo_dump_dir}"
77
+ cd = "cd #{mongo_dump_dir}/#{db}"
78
+ tar = "/usr/bin/env tar -czf #{tmp_path}/#{db_filename} ."
79
+
80
+ puts "Exec #{dump} && #{cd} && #{tar}"
81
+ system "#{dump} && #{cd} && #{tar}"
82
+
83
+ obj = BackupAgent.s3.bucket(config.s3_bucket).object("#{@timestamp}/#{db_filename}")
84
+ obj.upload_file("#{tmp_path}/#{db_filename}")
85
+ end
86
+ ensure
87
+ FileUtils.remove_dir(mongo_dump_dir)
88
+ end
89
+
90
+ def cleanup_old_backups
91
+ cutoff_date = Time.now.utc.to_i - (config.get(:days_to_keep_backups) * 86400)
92
+ BackupAgent.s3.bucket(config.s3_bucket).objects.each do |o|
93
+ o.delete if o.last_modified.to_i < cutoff_date
94
+ end
95
+ end
96
+
97
+ def make_tmp_dir
98
+ FileUtils.mkdir_p(tmp_path)
99
+ end
100
+
101
+ def remove_tmp_dir
102
+ FileUtils.remove_dir(tmp_path)
103
+ end
104
+
105
+ def tmp_path
106
+ "/tmp/backup-agent-#{@started_at.strftime('%d-%m-%Y-%H:%M')}"
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,55 @@
1
+ module BackupAgent
2
+ class TaskConfig < Confo::Config
3
+ def initialize(*)
4
+ super
5
+ set :mysql_user, 'root'
6
+ set :mysql_password, 'root'
7
+ set :mysql_host, 'localhost'
8
+ set :mysql_databases, -> do
9
+ `/usr/bin/env mysql #{get(:mysql_connect)} -e "SHOW DATABASES;"`
10
+ .split("\n")
11
+ .reject { |el| el =~ /Database|information_schema|mysql|performance_schema|test|phpmyadmin/ }
12
+ end
13
+
14
+ set :mysqldump_options, %w(
15
+ --single-transaction
16
+ --add-drop-table
17
+ --add-locks
18
+ --create-options
19
+ --disable-keys
20
+ --extended-insert
21
+ --quick)
22
+
23
+ set :mysql_connect, -> do
24
+ pass = get(:mysql_password)
25
+ pass_param = pass && !pass.empty? ? "-p#{pass}" : ''
26
+ "-u #{get(:mysql_user)} #{pass_param} -h #{get(:mysql_host)}"
27
+ end
28
+
29
+ set :mongo_databases, -> do
30
+ if `/usr/bin/env mongo --eval "db.getMongo().getDBNames()"` =~ /connecting to: (.*)/m
31
+ $1.split(/[\n,]/).reject(&:empty?)
32
+ else
33
+ []
34
+ end
35
+ end
36
+
37
+ set :mongo_host, 'localhost'
38
+ set :mongo_connect, -> { "-h #{get(:mongo_host)}" }
39
+
40
+ set :directories, -> {
41
+ Dir['/var/www/*'].each_with_object({}) do |el, memo|
42
+ if Dir.exists?(File.join(el, 'current/public/uploads'))
43
+ memo["#{File.basename(el)}-uploads"] = File.join(el, 'current/public/uploads')
44
+ end
45
+ end
46
+ }
47
+
48
+ set :files, {}
49
+
50
+ set :s3_bucket, nil
51
+
52
+ set :days_to_keep_backups, 30
53
+ end
54
+ end
55
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: backup-agent
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Yaroslav Konoplov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-12-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: confo-config
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 3.2.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 3.2.0
55
+ description: Easy AWS S3 backup
56
+ email:
57
+ - yaroslav@inbox.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - backup-agent.gemspec
68
+ - lib/backup-agent.rb
69
+ - lib/backup-agent/features.rb
70
+ - lib/backup-agent/s3.rb
71
+ - lib/backup-agent/s3_config.rb
72
+ - lib/backup-agent/service.rb
73
+ - lib/backup-agent/task_config.rb
74
+ homepage: http://github.com/yivo/backup-agent
75
+ licenses:
76
+ - MIT
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 2.4.8
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: Easy AWS S3 backup
98
+ test_files: []