backup-agent 1.0.0

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