rds_backup 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 72effc5ca22b06b2b27abaab144db3418a747193
4
+ data.tar.gz: 8e44fc0fe5edea2e7ba6dcc03c607e093287507b
5
+ SHA512:
6
+ metadata.gz: 3807fb41057c41f7b8c8490258f29035c868c2965c06b8f1efb9d3c820464b2fbcb893960e3a7886b720d6070b8567e0a668d0bd6977baed97168d7c6646d364
7
+ data.tar.gz: be97982df38a7589e76ffe9aeb26dd1bd2ed889074cd910c5105d2de5093801d5732fe77d2beefb525adbf010040d6662d6e04f192a75c86dfd47c78c1af6a13
@@ -0,0 +1,38 @@
1
+ # Project specific
2
+ config.yml
3
+
4
+ # Ruby
5
+ *.gem
6
+ *.rbc
7
+ /.config
8
+ /coverage/
9
+ /InstalledFiles
10
+ /pkg/
11
+ /spec/reports/
12
+ /test/tmp/
13
+ /test/version_tmp/
14
+ /tmp/
15
+
16
+ ## Specific to RubyMotion:
17
+ .dat*
18
+ .repl_history
19
+ build/
20
+
21
+ ## Documentation cache and generated files:
22
+ /.yardoc/
23
+ /_yardoc/
24
+ /doc/
25
+ /rdoc/
26
+
27
+ ## Environment normalisation:
28
+ /.bundle/
29
+ /lib/bundler/man/
30
+
31
+ # for a library or gem, you might want to ignore these files since the code is
32
+ # intended to run in multiple environments; otherwise, check them in:
33
+ # Gemfile.lock
34
+ # .ruby-version
35
+ # .ruby-gemset
36
+
37
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
38
+ .rvmrc
@@ -0,0 +1,2 @@
1
+ Documentation:
2
+ Enabled: false
@@ -0,0 +1 @@
1
+ 2.1.2
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,75 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ aws-sdk (1.51.0)
5
+ json (~> 1.4)
6
+ nokogiri (>= 1.4.4)
7
+ builder (3.2.2)
8
+ byebug (2.7.0)
9
+ columnize (~> 0.3)
10
+ debugger-linecache (~> 1.2)
11
+ coderay (1.1.0)
12
+ columnize (0.8.9)
13
+ debugger-linecache (1.2.0)
14
+ excon (0.39.5)
15
+ fog (1.23.0)
16
+ fog-brightbox
17
+ fog-core (~> 1.23)
18
+ fog-json
19
+ fog-softlayer
20
+ ipaddress (~> 0.5)
21
+ nokogiri (~> 1.5, >= 1.5.11)
22
+ fog-brightbox (0.3.0)
23
+ fog-core (~> 1.22)
24
+ fog-json
25
+ inflecto
26
+ fog-core (1.23.0)
27
+ builder
28
+ excon (~> 0.38)
29
+ formatador (~> 0.2)
30
+ mime-types
31
+ net-scp (~> 1.1)
32
+ net-ssh (>= 2.1.3)
33
+ fog-json (1.0.0)
34
+ multi_json (~> 1.0)
35
+ fog-softlayer (0.3.14)
36
+ fog-core
37
+ fog-json
38
+ formatador (0.2.5)
39
+ hipchat (1.3.0)
40
+ httparty
41
+ httparty (0.13.1)
42
+ json (~> 1.8)
43
+ multi_xml (>= 0.5.2)
44
+ inflecto (0.0.2)
45
+ ipaddress (0.8.0)
46
+ json (1.8.1)
47
+ method_source (0.8.2)
48
+ mime-types (2.3)
49
+ mini_portile (0.6.0)
50
+ multi_json (1.10.1)
51
+ multi_xml (0.5.5)
52
+ net-scp (1.2.1)
53
+ net-ssh (>= 2.6.5)
54
+ net-ssh (2.9.1)
55
+ nokogiri (1.6.3.1)
56
+ mini_portile (= 0.6.0)
57
+ pry (0.10.1)
58
+ coderay (~> 1.1.0)
59
+ method_source (~> 0.8.1)
60
+ slop (~> 3.4)
61
+ pry-byebug (1.3.3)
62
+ byebug (~> 2.7)
63
+ pry (~> 0.10)
64
+ slop (3.6.0)
65
+ yell (2.0.4)
66
+
67
+ PLATFORMS
68
+ ruby
69
+
70
+ DEPENDENCIES
71
+ aws-sdk
72
+ fog
73
+ hipchat
74
+ pry-byebug
75
+ yell
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 IDXP Analytics Inc.
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.
@@ -0,0 +1,48 @@
1
+ # RDS Backup
2
+
3
+ This gem backs up RDS databases to different cloud providers, granting an extra level of mind peacefulness.
4
+
5
+ ## Installation
6
+
7
+ `rds_backup` should be run as a command line tool, so it makes sense to install it globally
8
+
9
+ ```bash
10
+ $ gem install rds_backup
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ `rds_backup` expects a `config.yml` file on the folder it is run, [here is a sample](config.yml.sample).
16
+
17
+ Currently, you need a Google Cloud account with access to Cloud Storage. Sign up [here](https://developers.google.com/storage/docs/signup?csw=1) and get your credentials [here](https://storage.cloud.google.com/m) under the section "Interoperable Access".
18
+
19
+ AWS credentials with access to SES and a Hipchat Room token from API v2 are also required at this time.
20
+
21
+ Then, simply run the gem's binary:
22
+
23
+ ```bash
24
+ $ rds_backup
25
+ ```
26
+
27
+ ### Cron Usage
28
+
29
+ This tool is usually scheduled in cron, below is an example
30
+
31
+ ```
32
+ 0 3 * * * . $HOME/.profile; cd $HOME/rds_backup && rds_backup >> /var/log/rds_backup/rds_backup.log 2>&1
33
+ ```
34
+
35
+ ## Roadmap
36
+
37
+ * Tests
38
+ * Multiple cloud providers (we're already using fog)
39
+ * More yell adapters (Slack, Campfire, IRC, etc)
40
+ * More flexibe rules on backups to keep (à la [ec2-expire-snapshots](https://github.com/alestic/ec2-expire-snapshots))
41
+
42
+ ## Contributing
43
+
44
+ 1. Fork it
45
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
46
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
47
+ 4. Push to the branch (`git push origin my-new-feature`)
48
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'rds_backup'
5
+ rescue LoadError
6
+ require 'rubygems'
7
+ require 'rds_backup'
8
+ end
9
+
10
+ rb = RdsBackup::Backup.new
11
+ rb.backup
@@ -0,0 +1,25 @@
1
+ cloud_storage:
2
+ access_key_id:
3
+ secret_access_key:
4
+ mysql:
5
+ user:
6
+ password:
7
+ host:
8
+ database:
9
+ ssl: false
10
+ rds_cert_path: /home/user/rds_backup/mysql-ssl-ca-cert.pem
11
+ aws:
12
+ access_key_id:
13
+ secret_access_key:
14
+ email:
15
+ from_address: no-reply@example.com
16
+ to_addresses:
17
+ - git@example.com
18
+ subject: 'RDS Backup'
19
+ hipchat:
20
+ token:
21
+ rooms:
22
+ - Test
23
+ loggers:
24
+ - ses
25
+ - hipchat
@@ -0,0 +1,4 @@
1
+ require 'rds_backup/backup'
2
+
3
+ module RdsBackup
4
+ end
@@ -0,0 +1,123 @@
1
+ require 'fog'
2
+ require 'open3'
3
+ require 'yaml'
4
+ require_relative '../yell_adapters/ses_adapter'
5
+ require_relative '../yell_adapters/hipchat_adapter'
6
+
7
+ module RdsBackup
8
+ class Backup
9
+ def initialize(config_file = 'config.yml')
10
+ config = YAML.load(File.open(config_file))
11
+ config_google(config)
12
+ config_mysql(config)
13
+ config_logger(config)
14
+
15
+ @backups_to_keep = config['backups_to_keep'] || 3
16
+ current_utc_time = Time.now.getutc.strftime('%Y%m%d%H%M%S')
17
+ @file_name = "#{mysql_database}-#{current_utc_time}.sql.gz"
18
+ end
19
+
20
+ def backup
21
+ logger.info 'Starting...'
22
+ dump_database
23
+ upload_backup
24
+ prune_old_backups
25
+ remove_local_dump
26
+ ensure
27
+ logger.info 'Exiting...'
28
+ logger.close
29
+ end
30
+
31
+ private
32
+
33
+ attr_accessor :mysql_database, :mysql_host, :mysql_user, :mysql_password,
34
+ :mysql_ssl, :rds_cert_path, :fog_directory, :file_name,
35
+ :backups_to_keep, :logger
36
+
37
+ def config_mysql(config)
38
+ @mysql_database = config['mysql']['database']
39
+ @mysql_host = config['mysql']['host']
40
+ @mysql_user = config['mysql']['user']
41
+ @mysql_password = config['mysql']['password']
42
+ @mysql_ssl = config['mysql']['ssl']
43
+ @rds_cert_path = config['mysql']['rds_cert_path'] if @mysql_ssl
44
+ end
45
+
46
+ def config_google(config)
47
+ google_access = config['cloud_storage']['access_key_id']
48
+ google_secret = config['cloud_storage']['secret_access_key']
49
+ connection = Fog::Storage.new(
50
+ provider: 'Google',
51
+ google_storage_access_key_id: google_access,
52
+ google_storage_secret_access_key: google_secret
53
+ )
54
+ @fog_directory = connection.directories.get('idxp-rds-backup')
55
+ end
56
+
57
+ def config_logger(config)
58
+ @logger = Yell.new do |yell_logger|
59
+ config['loggers'].each do |logger|
60
+ send("config_#{logger}_adapter", yell_logger, config)
61
+ end
62
+ end
63
+ end
64
+
65
+ def config_ses_adapter(logger, config)
66
+ logger.adapter :ses_adapter,
67
+ format: Yell::BasicFormat,
68
+ aws_access_key_id: config['aws']['access_key_id'],
69
+ aws_secret_access_key: config['aws']['secret_access_key'],
70
+ email_config: config['email']
71
+ end
72
+
73
+ def config_hipchat_adapter(logger, config)
74
+ logger.adapter :hipchat_adapter,
75
+ format: Yell::BasicFormat,
76
+ hipchat_token: config['hipchat']['token'],
77
+ hipchat_rooms: config['hipchat']['rooms']
78
+ end
79
+
80
+ def dump_database
81
+ _out, err, _status = Open3.capture3 mysqldump_cmd
82
+
83
+ if err.empty?
84
+ logger.info 'Database dump successfully created'
85
+ else
86
+ logger.error "Error when dumping the database: #{err.strip}"
87
+ remove_local_dump
88
+ fail RuntimeError
89
+ end
90
+ end
91
+
92
+ def mysqldump_cmd
93
+ cmd = "mysqldump -u#{mysql_user} "
94
+ cmd += "-p#{mysql_password} " if mysql_password
95
+ cmd += "--ssl_ca=#{rds_cert_path} " if mysql_ssl
96
+ cmd += '--single-transaction --routines --triggers '\
97
+ "-h #{mysql_host} #{mysql_database} "\
98
+ "| gzip -c > #{file_name}"
99
+ cmd
100
+ end
101
+
102
+ def upload_backup
103
+ fog_directory.files.create(key: file_name, body: File.open(file_name))
104
+ logger.info 'Backup uploaded to Google'
105
+ rescue
106
+ logger.error 'Error while uploading dump to Google'
107
+ end
108
+
109
+ def prune_old_backups
110
+ sorted_files = fog_directory.files.reload.sort do |x, y|
111
+ x.last_modified <=> y.last_modified
112
+ end
113
+ sorted_files[0 .. -backups_to_keep - 1].each { |f| f.destroy }
114
+ logger.info 'Old backups pruned'
115
+ rescue
116
+ logger.error 'Error while pruning old backups'
117
+ end
118
+
119
+ def remove_local_dump
120
+ Open3.capture3 "rm -rf #{file_name}"
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,3 @@
1
+ module RdsBackup
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,47 @@
1
+ require 'yell'
2
+ require 'hipchat'
3
+
4
+ class HipchatAdapter < Yell::Adapters::Base
5
+ include Yell::Helpers::Base
6
+ include Yell::Helpers::Formatter
7
+
8
+ attr_accessor :hipchat, :body_text, :hipchat_rooms, :errors
9
+
10
+ setup do |options|
11
+ self.formatter = options[:format]
12
+ self.hipchat = HipChat::Client.new(
13
+ options[:hipchat_token], api_version: 'v2'
14
+ )
15
+ self.hipchat_rooms = options[:hipchat_rooms]
16
+ self.body_text = ''
17
+ self.errors = false
18
+ end
19
+
20
+ write do |event|
21
+ self.body_text += formatter.call(event)
22
+ self.errors = true if event.level >= 3
23
+ end
24
+
25
+ close do
26
+ format_body_text_to_html
27
+ color = errors? ? 'red' : 'green'
28
+ hipchat_rooms.each do |room|
29
+ hipchat[room].send('RDS Backup', body_text, message_format: 'html',
30
+ color: color)
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def errors?
37
+ errors
38
+ end
39
+
40
+ def format_body_text_to_html
41
+ body_text.gsub!("\n", '<br>')
42
+ prepend = errors? ? '<strong>Error!</strong>' : '<strong>Success!</strong>'
43
+ self.body_text = [prepend, body_text].join '<br>'
44
+ end
45
+ end
46
+
47
+ Yell::Adapters.register :hipchat_adapter, HipchatAdapter
@@ -0,0 +1,48 @@
1
+ require 'yell'
2
+ require 'aws-sdk'
3
+
4
+ class SesAdapter < Yell::Adapters::Base
5
+ include Yell::Helpers::Base
6
+ include Yell::Helpers::Formatter
7
+
8
+ attr_accessor :ses, :body_text, :email_config, :errors
9
+
10
+ setup do |options|
11
+ self.formatter = options[:format]
12
+ self.ses = AWS::SimpleEmailService.new(
13
+ access_key_id: options[:aws_access_key_id],
14
+ secret_access_key: options[:aws_secret_access_key]
15
+ )
16
+ self.email_config = options[:email_config]
17
+ self.body_text = ''
18
+ self.errors = false
19
+ end
20
+
21
+ write do |event|
22
+ self.body_text += formatter.call(event)
23
+ self.errors = true if event.level >= 3
24
+ end
25
+
26
+ close do
27
+ base_subject = email_config['subject'] + Time.now.utc.strftime(' %Y/%m/%d')
28
+ subject = format_subject(base_subject)
29
+ ses.send_email(
30
+ subject: subject,
31
+ from: email_config['from_address'],
32
+ to: email_config['to_addresses'],
33
+ body_text: body_text
34
+ )
35
+ end
36
+
37
+ private
38
+
39
+ def errors?
40
+ errors
41
+ end
42
+
43
+ def format_subject(base_subject)
44
+ errors? ? "Error: #{base_subject}" : "Sucess: #{base_subject}"
45
+ end
46
+ end
47
+
48
+ Yell::Adapters.register :ses_adapter, SesAdapter
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rds_backup/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'rds_backup'
8
+ spec.version = RdsBackup::VERSION
9
+ spec.authors = ['Artur Rodrigues']
10
+ spec.email = ['arturhoo@gmail.com']
11
+ spec.description = 'Backs up RDS Databases and sync them to multiple '\
12
+ 'cloud providers'
13
+ spec.summary = 'Offsite and offprovider backups for RDS Databases'
14
+ spec.homepage = 'https://github.com/idxp/rds_backup'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
18
+ spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(/^(test|spec|features)\//)
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_development_dependency 'bundler', '~> 1.3'
23
+ spec.add_development_dependency 'pry'
24
+ spec.add_development_dependency 'pry_byebug'
25
+
26
+ spec.add_dependency 'aws-sdk'
27
+ spec.add_dependency 'fog'
28
+ spec.add_dependency 'yell'
29
+ spec.add_dependency 'hipchat'
30
+ end
metadata ADDED
@@ -0,0 +1,159 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rds_backup
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Artur Rodrigues
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry_byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: aws-sdk
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: fog
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: yell
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: hipchat
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Backs up RDS Databases and sync them to multiple cloud providers
112
+ email:
113
+ - arturhoo@gmail.com
114
+ executables:
115
+ - rds_backup
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - ".gitignore"
120
+ - ".rubocop.yml"
121
+ - ".ruby-version"
122
+ - Gemfile
123
+ - Gemfile.lock
124
+ - LICENSE.md
125
+ - README.md
126
+ - Rakefile
127
+ - bin/rds_backup
128
+ - config.yml.sample
129
+ - lib/rds_backup.rb
130
+ - lib/rds_backup/backup.rb
131
+ - lib/rds_backup/version.rb
132
+ - lib/yell_adapters/hipchat_adapter.rb
133
+ - lib/yell_adapters/ses_adapter.rb
134
+ - rds_backup.gemspec
135
+ homepage: https://github.com/idxp/rds_backup
136
+ licenses:
137
+ - MIT
138
+ metadata: {}
139
+ post_install_message:
140
+ rdoc_options: []
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ requirements: []
154
+ rubyforge_project:
155
+ rubygems_version: 2.2.2
156
+ signing_key:
157
+ specification_version: 4
158
+ summary: Offsite and offprovider backups for RDS Databases
159
+ test_files: []