backupii 0.1.0.pre.alpha.1

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.
Files changed (135) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +19 -0
  3. data/README.md +37 -0
  4. data/bin/backupii +5 -0
  5. data/bin/docker_test +24 -0
  6. data/lib/backup/archive.rb +171 -0
  7. data/lib/backup/binder.rb +23 -0
  8. data/lib/backup/cleaner.rb +114 -0
  9. data/lib/backup/cli.rb +376 -0
  10. data/lib/backup/cloud_io/base.rb +40 -0
  11. data/lib/backup/cloud_io/cloud_files.rb +301 -0
  12. data/lib/backup/cloud_io/s3.rb +256 -0
  13. data/lib/backup/compressor/base.rb +34 -0
  14. data/lib/backup/compressor/bzip2.rb +37 -0
  15. data/lib/backup/compressor/custom.rb +51 -0
  16. data/lib/backup/compressor/gzip.rb +76 -0
  17. data/lib/backup/config/dsl.rb +103 -0
  18. data/lib/backup/config/helpers.rb +139 -0
  19. data/lib/backup/config.rb +122 -0
  20. data/lib/backup/database/base.rb +89 -0
  21. data/lib/backup/database/mongodb.rb +189 -0
  22. data/lib/backup/database/mysql.rb +194 -0
  23. data/lib/backup/database/openldap.rb +97 -0
  24. data/lib/backup/database/postgresql.rb +134 -0
  25. data/lib/backup/database/redis.rb +179 -0
  26. data/lib/backup/database/riak.rb +82 -0
  27. data/lib/backup/database/sqlite.rb +57 -0
  28. data/lib/backup/encryptor/base.rb +29 -0
  29. data/lib/backup/encryptor/gpg.rb +745 -0
  30. data/lib/backup/encryptor/open_ssl.rb +76 -0
  31. data/lib/backup/errors.rb +55 -0
  32. data/lib/backup/logger/console.rb +50 -0
  33. data/lib/backup/logger/fog_adapter.rb +27 -0
  34. data/lib/backup/logger/logfile.rb +134 -0
  35. data/lib/backup/logger/syslog.rb +116 -0
  36. data/lib/backup/logger.rb +199 -0
  37. data/lib/backup/model.rb +478 -0
  38. data/lib/backup/notifier/base.rb +128 -0
  39. data/lib/backup/notifier/campfire.rb +63 -0
  40. data/lib/backup/notifier/command.rb +101 -0
  41. data/lib/backup/notifier/datadog.rb +107 -0
  42. data/lib/backup/notifier/flowdock.rb +101 -0
  43. data/lib/backup/notifier/hipchat.rb +118 -0
  44. data/lib/backup/notifier/http_post.rb +116 -0
  45. data/lib/backup/notifier/mail.rb +235 -0
  46. data/lib/backup/notifier/nagios.rb +67 -0
  47. data/lib/backup/notifier/pagerduty.rb +82 -0
  48. data/lib/backup/notifier/prowl.rb +70 -0
  49. data/lib/backup/notifier/pushover.rb +73 -0
  50. data/lib/backup/notifier/ses.rb +126 -0
  51. data/lib/backup/notifier/slack.rb +149 -0
  52. data/lib/backup/notifier/twitter.rb +57 -0
  53. data/lib/backup/notifier/zabbix.rb +62 -0
  54. data/lib/backup/package.rb +53 -0
  55. data/lib/backup/packager.rb +108 -0
  56. data/lib/backup/pipeline.rb +122 -0
  57. data/lib/backup/splitter.rb +75 -0
  58. data/lib/backup/storage/base.rb +72 -0
  59. data/lib/backup/storage/cloud_files.rb +158 -0
  60. data/lib/backup/storage/cycler.rb +73 -0
  61. data/lib/backup/storage/dropbox.rb +208 -0
  62. data/lib/backup/storage/ftp.rb +118 -0
  63. data/lib/backup/storage/local.rb +63 -0
  64. data/lib/backup/storage/qiniu.rb +68 -0
  65. data/lib/backup/storage/rsync.rb +251 -0
  66. data/lib/backup/storage/s3.rb +157 -0
  67. data/lib/backup/storage/scp.rb +67 -0
  68. data/lib/backup/storage/sftp.rb +82 -0
  69. data/lib/backup/syncer/base.rb +70 -0
  70. data/lib/backup/syncer/cloud/base.rb +180 -0
  71. data/lib/backup/syncer/cloud/cloud_files.rb +83 -0
  72. data/lib/backup/syncer/cloud/local_file.rb +99 -0
  73. data/lib/backup/syncer/cloud/s3.rb +118 -0
  74. data/lib/backup/syncer/rsync/base.rb +55 -0
  75. data/lib/backup/syncer/rsync/local.rb +29 -0
  76. data/lib/backup/syncer/rsync/pull.rb +49 -0
  77. data/lib/backup/syncer/rsync/push.rb +206 -0
  78. data/lib/backup/template.rb +45 -0
  79. data/lib/backup/utilities.rb +235 -0
  80. data/lib/backup/version.rb +5 -0
  81. data/lib/backup.rb +141 -0
  82. data/templates/cli/archive +28 -0
  83. data/templates/cli/compressor/bzip2 +4 -0
  84. data/templates/cli/compressor/custom +7 -0
  85. data/templates/cli/compressor/gzip +4 -0
  86. data/templates/cli/config +123 -0
  87. data/templates/cli/databases/mongodb +15 -0
  88. data/templates/cli/databases/mysql +18 -0
  89. data/templates/cli/databases/openldap +24 -0
  90. data/templates/cli/databases/postgresql +16 -0
  91. data/templates/cli/databases/redis +16 -0
  92. data/templates/cli/databases/riak +17 -0
  93. data/templates/cli/databases/sqlite +11 -0
  94. data/templates/cli/encryptor/gpg +27 -0
  95. data/templates/cli/encryptor/openssl +9 -0
  96. data/templates/cli/model +26 -0
  97. data/templates/cli/notifier/zabbix +15 -0
  98. data/templates/cli/notifiers/campfire +12 -0
  99. data/templates/cli/notifiers/command +32 -0
  100. data/templates/cli/notifiers/datadog +57 -0
  101. data/templates/cli/notifiers/flowdock +16 -0
  102. data/templates/cli/notifiers/hipchat +16 -0
  103. data/templates/cli/notifiers/http_post +32 -0
  104. data/templates/cli/notifiers/mail +24 -0
  105. data/templates/cli/notifiers/nagios +13 -0
  106. data/templates/cli/notifiers/pagerduty +12 -0
  107. data/templates/cli/notifiers/prowl +11 -0
  108. data/templates/cli/notifiers/pushover +11 -0
  109. data/templates/cli/notifiers/ses +15 -0
  110. data/templates/cli/notifiers/slack +22 -0
  111. data/templates/cli/notifiers/twitter +13 -0
  112. data/templates/cli/splitter +7 -0
  113. data/templates/cli/storages/cloud_files +11 -0
  114. data/templates/cli/storages/dropbox +20 -0
  115. data/templates/cli/storages/ftp +13 -0
  116. data/templates/cli/storages/local +8 -0
  117. data/templates/cli/storages/qiniu +12 -0
  118. data/templates/cli/storages/rsync +17 -0
  119. data/templates/cli/storages/s3 +16 -0
  120. data/templates/cli/storages/scp +15 -0
  121. data/templates/cli/storages/sftp +15 -0
  122. data/templates/cli/syncers/cloud_files +22 -0
  123. data/templates/cli/syncers/rsync_local +20 -0
  124. data/templates/cli/syncers/rsync_pull +28 -0
  125. data/templates/cli/syncers/rsync_push +28 -0
  126. data/templates/cli/syncers/s3 +27 -0
  127. data/templates/general/links +3 -0
  128. data/templates/general/version.erb +2 -0
  129. data/templates/notifier/mail/failure.erb +16 -0
  130. data/templates/notifier/mail/success.erb +16 -0
  131. data/templates/notifier/mail/warning.erb +16 -0
  132. data/templates/storage/dropbox/authorization_url.erb +6 -0
  133. data/templates/storage/dropbox/authorized.erb +4 -0
  134. data/templates/storage/dropbox/cache_file_written.erb +10 -0
  135. metadata +507 -0
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Backup
4
+ module Database
5
+ class Redis < Base
6
+ class Error < Backup::Error; end
7
+
8
+ MODES = %i[copy sync].freeze
9
+
10
+ ##
11
+ # Mode of operation.
12
+ #
13
+ # [:copy]
14
+ # Copies the redis dump file specified by {#rdb_path}.
15
+ # This data will be current as of the last RDB Snapshot
16
+ # performed by the server (per your redis.conf settings).
17
+ # You may set {#invoke_save} to +true+ to have Backup issue
18
+ # a +SAVE+ command to update the dump file with the current
19
+ # data before performing the copy.
20
+ #
21
+ # [:sync]
22
+ # Performs a dump of your redis data using +redis-cli --rdb -+.
23
+ # Redis implements this internally using a +SYNC+ command.
24
+ # The operation is analogous to requesting a +BGSAVE+, then having the
25
+ # dump returned. This mode is capable of dumping data from a local or
26
+ # remote server. Requires Redis v2.6 or better.
27
+ #
28
+ # Defaults to +:copy+.
29
+ attr_accessor :mode
30
+
31
+ ##
32
+ # Full path to the redis dump file.
33
+ #
34
+ # Required when {#mode} is +:copy+.
35
+ attr_accessor :rdb_path
36
+
37
+ ##
38
+ # Perform a +SAVE+ command using the +redis-cli+ utility
39
+ # before copying the dump file specified by {#rdb_path}.
40
+ #
41
+ # Only valid when {#mode} is +:copy+.
42
+ attr_accessor :invoke_save
43
+
44
+ ##
45
+ # Connectivity options for the +redis-cli+ utility.
46
+ attr_accessor :host, :port, :socket
47
+
48
+ ##
49
+ # Password for the +redis-cli+ utility.
50
+ attr_accessor :password
51
+
52
+ ##
53
+ # Additional options for the +redis-cli+ utility.
54
+ attr_accessor :additional_options
55
+
56
+ def initialize(model, database_id = nil, &block)
57
+ super
58
+ instance_eval(&block) if block_given?
59
+
60
+ @mode ||= :copy
61
+
62
+ raise Error, "'#{mode}' is not a valid mode" unless MODES.include?(mode)
63
+
64
+ if mode == :copy && rdb_path.nil?
65
+ raise Error, "`rdb_path` must be set when `mode` is :copy"
66
+ end
67
+ end
68
+
69
+ ##
70
+ # Performs the dump based on {#mode} and stores the Redis dump file
71
+ # to the +dump_path+ using the +dump_filename+.
72
+ #
73
+ # <trigger>/databases/Redis[-<database_id>].rdb[.gz]
74
+ def perform!
75
+ super
76
+
77
+ case mode
78
+ when :sync
79
+ # messages output by `redis-cli --rdb` on $stderr
80
+ Logger.configure do
81
+ ignore_warning(%r{Transfer finished with success})
82
+ ignore_warning(%r{SYNC sent to master})
83
+ end
84
+ sync!
85
+ when :copy
86
+ save! if invoke_save
87
+ copy!
88
+ end
89
+
90
+ log!(:finished)
91
+ end
92
+
93
+ private
94
+
95
+ def sync!
96
+ pipeline = Pipeline.new
97
+ dump_ext = "rdb".dup
98
+
99
+ pipeline << "#{redis_cli_cmd} --rdb -"
100
+
101
+ if model.compressor
102
+ model.compressor.compress_with do |command, ext|
103
+ pipeline << command
104
+ dump_ext << ext
105
+ end
106
+ end
107
+
108
+ pipeline << "#{utility(:cat)} > " \
109
+ "'#{File.join(dump_path, dump_filename)}.#{dump_ext}'"
110
+
111
+ pipeline.run
112
+
113
+ unless pipeline.success?
114
+ raise Error, "Dump Failed!\n" + pipeline.error_messages
115
+ end
116
+ end
117
+
118
+ def save!
119
+ resp = run("#{redis_cli_cmd} SAVE")
120
+ unless resp =~ %r{OK$}
121
+ raise Error, <<-EOS
122
+ Failed to invoke the `SAVE` command
123
+ Response was: #{resp}
124
+ EOS
125
+ end
126
+ rescue Error
127
+ if resp =~ %r{save already in progress}
128
+ unless (attempts ||= "0".dup).next! == "5"
129
+ sleep 5
130
+ retry
131
+ end
132
+ end
133
+ raise
134
+ end
135
+
136
+ def copy!
137
+ unless File.exist?(rdb_path)
138
+ raise Error, <<-EOS
139
+ Redis database dump not found
140
+ `rdb_path` was '#{rdb_path}'
141
+ EOS
142
+ end
143
+
144
+ dst_path = File.join(dump_path, dump_filename + ".rdb")
145
+ if model.compressor
146
+ model.compressor.compress_with do |command, ext|
147
+ run("#{command} -c '#{rdb_path}' > '#{dst_path + ext}'")
148
+ end
149
+ else
150
+ FileUtils.cp(rdb_path, dst_path)
151
+ end
152
+ end
153
+
154
+ def redis_cli_cmd
155
+ "#{utility("redis-cli")} #{password_option} " \
156
+ "#{connectivity_options} #{user_options}"
157
+ end
158
+
159
+ def password_option
160
+ return unless password
161
+
162
+ "-a '#{password}'"
163
+ end
164
+
165
+ def connectivity_options
166
+ return "-s '#{socket}'" if socket
167
+
168
+ opts = []
169
+ opts << "-h '#{host}'" if host
170
+ opts << "-p '#{port}'" if port
171
+ opts.join(" ")
172
+ end
173
+
174
+ def user_options
175
+ Array(additional_options).join(" ")
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Backup
4
+ module Database
5
+ class Riak < Base
6
+ ##
7
+ # Node is the node from which to perform the backup.
8
+ # Default: riak@127.0.0.1
9
+ attr_accessor :node
10
+
11
+ ##
12
+ # Cookie is the Erlang cookie/shared secret used to connect to the node.
13
+ # Default: riak
14
+ attr_accessor :cookie
15
+
16
+ ##
17
+ # Username for the riak instance
18
+ # Default: riak
19
+ attr_accessor :user
20
+
21
+ def initialize(model, database_id = nil, &block)
22
+ super
23
+ instance_eval(&block) if block_given?
24
+
25
+ @node ||= "riak@127.0.0.1"
26
+ @cookie ||= "riak"
27
+ @user ||= "riak"
28
+ end
29
+
30
+ ##
31
+ # Performs the dump using `riak-admin backup`.
32
+ #
33
+ # This will be stored in the final backup package as
34
+ # <trigger>/databases/<dump_filename>-<node>[.gz]
35
+ def perform!
36
+ super
37
+
38
+ dump_file = File.join(dump_path, dump_filename)
39
+ with_riak_owned_dump_path do
40
+ run("#{riakadmin} backup #{node} #{cookie} '#{dump_file}' node")
41
+ end
42
+
43
+ if model.compressor
44
+ model.compressor.compress_with do |command, ext|
45
+ # `riak-admin` appends `node` to the filename.
46
+ dump_file << "-#{node}"
47
+ run("#{command} -c '#{dump_file}' > '#{dump_file + ext}'")
48
+ FileUtils.rm_f(dump_file)
49
+ end
50
+ end
51
+
52
+ log!(:finished)
53
+ end
54
+
55
+ private
56
+
57
+ ##
58
+ # The `riak-admin backup` command is run as the riak +user+,
59
+ # so +user+ must have write priviledges to the +dump_path+.
60
+ #
61
+ # Note that the riak +user+ must also have access to +dump_path+.
62
+ # This means Backup's +tmp_path+ can not be under the home directory of
63
+ # the user running Backup, since the absence of the execute bit on their
64
+ # home directory would deny +user+ access.
65
+ def with_riak_owned_dump_path
66
+ run "#{utility(:sudo)} -n #{utility(:chown)} #{user} '#{dump_path}'"
67
+ yield
68
+ ensure
69
+ # reclaim ownership
70
+ run "#{utility(:sudo)} -n #{utility(:chown)} -R " \
71
+ "#{Config.user} '#{dump_path}'"
72
+ end
73
+
74
+ ##
75
+ # `riak-admin` must be run as the riak +user+.
76
+ # It will do this itself, but without `-n` and emits a message on STDERR.
77
+ def riakadmin
78
+ "#{utility(:sudo)} -n -u #{user} #{utility("riak-admin")}"
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Backup
4
+ module Database
5
+ class SQLite < Base
6
+ class Error < Backup::Error; end
7
+
8
+ ##
9
+ # Path to the sqlite3 file
10
+ attr_accessor :path
11
+
12
+ ##
13
+ # Path to sqlite utility (optional)
14
+ attr_accessor :sqlitedump_utility
15
+
16
+ ##
17
+ # Creates a new instance of the SQLite adapter object
18
+ def initialize(model, database_id = nil, &block)
19
+ super
20
+ instance_eval(&block) if block_given?
21
+
22
+ @sqlitedump_utility ||= utility(:sqlitedump)
23
+ end
24
+
25
+ ##
26
+ # Performs the sqlitedump command and outputs the
27
+ # data to the specified path based on the 'trigger'
28
+ def perform!
29
+ super
30
+
31
+ dump = "echo '.dump' | #{sqlitedump_utility} #{path}"
32
+
33
+ pipeline = Pipeline.new
34
+ dump_ext = "sql".dup
35
+
36
+ pipeline << dump
37
+ if model.compressor
38
+ model.compressor.compress_with do |command, ext|
39
+ pipeline << command
40
+ dump_ext << ext
41
+ end
42
+ end
43
+
44
+ pipeline << "cat > '#{File.join(dump_path, dump_filename)}.#{dump_ext}'"
45
+
46
+ pipeline.run
47
+
48
+ if pipeline.success?
49
+ log!(:finished)
50
+ else
51
+ raise Error,
52
+ "#{database_name} Dump Failed!\n" + pipeline.error_messages
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Backup
4
+ module Encryptor
5
+ class Base
6
+ include Utilities::Helpers
7
+ include Config::Helpers
8
+
9
+ def initialize
10
+ load_defaults!
11
+ end
12
+
13
+ private
14
+
15
+ ##
16
+ # Return the encryptor name, with Backup namespace removed
17
+ def encryptor_name
18
+ self.class.to_s.sub("Backup::", "")
19
+ end
20
+
21
+ ##
22
+ # Logs a message to the console and log file to inform
23
+ # the client that Backup is encrypting the archive
24
+ def log!
25
+ Logger.info "Using #{encryptor_name} to encrypt the archive."
26
+ end
27
+ end
28
+ end
29
+ end