sliday_backup 0.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/README.md +29 -0
  3. data/bin/sliday_backup +5 -0
  4. data/lib/sliday_backup.rb +147 -0
  5. data/lib/sliday_backup/archive.rb +170 -0
  6. data/lib/sliday_backup/binder.rb +22 -0
  7. data/lib/sliday_backup/cleaner.rb +116 -0
  8. data/lib/sliday_backup/cli.rb +374 -0
  9. data/lib/sliday_backup/cloud_io/base.rb +41 -0
  10. data/lib/sliday_backup/cloud_io/cloud_files.rb +298 -0
  11. data/lib/sliday_backup/cloud_io/s3.rb +260 -0
  12. data/lib/sliday_backup/compressor/base.rb +35 -0
  13. data/lib/sliday_backup/compressor/bzip2.rb +39 -0
  14. data/lib/sliday_backup/compressor/custom.rb +53 -0
  15. data/lib/sliday_backup/compressor/gzip.rb +74 -0
  16. data/lib/sliday_backup/config.rb +119 -0
  17. data/lib/sliday_backup/config/dsl.rb +103 -0
  18. data/lib/sliday_backup/config/helpers.rb +143 -0
  19. data/lib/sliday_backup/database/base.rb +86 -0
  20. data/lib/sliday_backup/database/mongodb.rb +187 -0
  21. data/lib/sliday_backup/database/mysql.rb +192 -0
  22. data/lib/sliday_backup/database/openldap.rb +95 -0
  23. data/lib/sliday_backup/database/postgresql.rb +133 -0
  24. data/lib/sliday_backup/database/redis.rb +179 -0
  25. data/lib/sliday_backup/database/riak.rb +82 -0
  26. data/lib/sliday_backup/database/sqlite.rb +57 -0
  27. data/lib/sliday_backup/encryptor/base.rb +29 -0
  28. data/lib/sliday_backup/encryptor/gpg.rb +747 -0
  29. data/lib/sliday_backup/encryptor/open_ssl.rb +77 -0
  30. data/lib/sliday_backup/errors.rb +58 -0
  31. data/lib/sliday_backup/logger.rb +199 -0
  32. data/lib/sliday_backup/logger/console.rb +51 -0
  33. data/lib/sliday_backup/logger/fog_adapter.rb +29 -0
  34. data/lib/sliday_backup/logger/logfile.rb +133 -0
  35. data/lib/sliday_backup/logger/syslog.rb +116 -0
  36. data/lib/sliday_backup/model.rb +479 -0
  37. data/lib/sliday_backup/notifier/base.rb +128 -0
  38. data/lib/sliday_backup/notifier/campfire.rb +63 -0
  39. data/lib/sliday_backup/notifier/command.rb +99 -0
  40. data/lib/sliday_backup/notifier/datadog.rb +107 -0
  41. data/lib/sliday_backup/notifier/flowdock.rb +103 -0
  42. data/lib/sliday_backup/notifier/hipchat.rb +112 -0
  43. data/lib/sliday_backup/notifier/http_post.rb +117 -0
  44. data/lib/sliday_backup/notifier/mail.rb +244 -0
  45. data/lib/sliday_backup/notifier/nagios.rb +69 -0
  46. data/lib/sliday_backup/notifier/pagerduty.rb +81 -0
  47. data/lib/sliday_backup/notifier/prowl.rb +68 -0
  48. data/lib/sliday_backup/notifier/pushover.rb +74 -0
  49. data/lib/sliday_backup/notifier/ses.rb +88 -0
  50. data/lib/sliday_backup/notifier/slack.rb +148 -0
  51. data/lib/sliday_backup/notifier/twitter.rb +58 -0
  52. data/lib/sliday_backup/notifier/zabbix.rb +63 -0
  53. data/lib/sliday_backup/package.rb +55 -0
  54. data/lib/sliday_backup/packager.rb +107 -0
  55. data/lib/sliday_backup/pipeline.rb +124 -0
  56. data/lib/sliday_backup/splitter.rb +76 -0
  57. data/lib/sliday_backup/storage/base.rb +69 -0
  58. data/lib/sliday_backup/storage/cloud_files.rb +158 -0
  59. data/lib/sliday_backup/storage/cycler.rb +75 -0
  60. data/lib/sliday_backup/storage/dropbox.rb +212 -0
  61. data/lib/sliday_backup/storage/ftp.rb +112 -0
  62. data/lib/sliday_backup/storage/local.rb +64 -0
  63. data/lib/sliday_backup/storage/qiniu.rb +65 -0
  64. data/lib/sliday_backup/storage/rsync.rb +248 -0
  65. data/lib/sliday_backup/storage/s3.rb +156 -0
  66. data/lib/sliday_backup/storage/scp.rb +67 -0
  67. data/lib/sliday_backup/storage/sftp.rb +82 -0
  68. data/lib/sliday_backup/storage/sliday_storage.rb +79 -0
  69. data/lib/sliday_backup/syncer/base.rb +70 -0
  70. data/lib/sliday_backup/syncer/cloud/base.rb +179 -0
  71. data/lib/sliday_backup/syncer/cloud/cloud_files.rb +83 -0
  72. data/lib/sliday_backup/syncer/cloud/local_file.rb +100 -0
  73. data/lib/sliday_backup/syncer/cloud/s3.rb +110 -0
  74. data/lib/sliday_backup/syncer/rsync/base.rb +54 -0
  75. data/lib/sliday_backup/syncer/rsync/local.rb +31 -0
  76. data/lib/sliday_backup/syncer/rsync/pull.rb +51 -0
  77. data/lib/sliday_backup/syncer/rsync/push.rb +205 -0
  78. data/lib/sliday_backup/template.rb +46 -0
  79. data/lib/sliday_backup/utilities.rb +224 -0
  80. data/lib/sliday_backup/version.rb +5 -0
  81. data/templates/cli/archive +28 -0
  82. data/templates/cli/compressor/bzip2 +4 -0
  83. data/templates/cli/compressor/custom +7 -0
  84. data/templates/cli/compressor/gzip +4 -0
  85. data/templates/cli/config +123 -0
  86. data/templates/cli/databases/mongodb +15 -0
  87. data/templates/cli/databases/mysql +18 -0
  88. data/templates/cli/databases/openldap +24 -0
  89. data/templates/cli/databases/postgresql +16 -0
  90. data/templates/cli/databases/redis +16 -0
  91. data/templates/cli/databases/riak +17 -0
  92. data/templates/cli/databases/sqlite +11 -0
  93. data/templates/cli/encryptor/gpg +27 -0
  94. data/templates/cli/encryptor/openssl +9 -0
  95. data/templates/cli/model +26 -0
  96. data/templates/cli/notifier/zabbix +15 -0
  97. data/templates/cli/notifiers/campfire +12 -0
  98. data/templates/cli/notifiers/command +32 -0
  99. data/templates/cli/notifiers/datadog +57 -0
  100. data/templates/cli/notifiers/flowdock +16 -0
  101. data/templates/cli/notifiers/hipchat +16 -0
  102. data/templates/cli/notifiers/http_post +32 -0
  103. data/templates/cli/notifiers/mail +24 -0
  104. data/templates/cli/notifiers/nagios +13 -0
  105. data/templates/cli/notifiers/pagerduty +12 -0
  106. data/templates/cli/notifiers/prowl +11 -0
  107. data/templates/cli/notifiers/pushover +11 -0
  108. data/templates/cli/notifiers/ses +15 -0
  109. data/templates/cli/notifiers/slack +22 -0
  110. data/templates/cli/notifiers/twitter +13 -0
  111. data/templates/cli/splitter +7 -0
  112. data/templates/cli/storages/cloud_files +11 -0
  113. data/templates/cli/storages/dropbox +20 -0
  114. data/templates/cli/storages/ftp +13 -0
  115. data/templates/cli/storages/local +8 -0
  116. data/templates/cli/storages/qiniu +12 -0
  117. data/templates/cli/storages/rsync +17 -0
  118. data/templates/cli/storages/s3 +16 -0
  119. data/templates/cli/storages/scp +15 -0
  120. data/templates/cli/storages/sftp +15 -0
  121. data/templates/cli/storages/sliday_storage +6 -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 +1079 -0
@@ -0,0 +1,54 @@
1
+ # encoding: utf-8
2
+
3
+ module SlidayBackup
4
+ module Syncer
5
+ module RSync
6
+ class Base < Syncer::Base
7
+
8
+ ##
9
+ # Additional String or Array of options for the rsync cli
10
+ attr_accessor :additional_rsync_options
11
+ attr_accessor :archive
12
+
13
+ def initialize(syncer_id = nil, &block)
14
+ super
15
+ instance_eval(&block) if block_given?
16
+
17
+ @path ||= '~/backups'
18
+ @archive = @archive.nil? ? true : @archive
19
+ end
20
+
21
+ private
22
+
23
+ ##
24
+ # Common base command for Local/Push/Pull
25
+ def rsync_command
26
+ utility(:rsync) << archive_option << mirror_option << exclude_option <<
27
+ " #{ Array(additional_rsync_options).join(' ') }".rstrip
28
+ end
29
+
30
+ def mirror_option
31
+ mirror ? ' --delete' : ''
32
+ end
33
+
34
+ def archive_option
35
+ archive ? ' --archive' : ''
36
+ end
37
+
38
+ def exclude_option
39
+ excludes.map {|pattern| " --exclude='#{ pattern }'" }.join
40
+ end
41
+
42
+ ##
43
+ # Each path is expanded, since these refer to local paths and are
44
+ # being shell-quoted. This will also remove any trailing `/` from
45
+ # each path, as we don't want rsync's "trailing / on source directories"
46
+ # behavior. This method is used by RSync::Local and RSync::Push.
47
+ def paths_to_push
48
+ directories.map {|dir| "'#{ File.expand_path(dir) }'" }.join(' ')
49
+ end
50
+
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ module SlidayBackup
4
+ module Syncer
5
+ module RSync
6
+ class Local < Base
7
+
8
+ def perform!
9
+ log!(:started)
10
+
11
+ create_dest_path!
12
+ run("#{ rsync_command } #{ paths_to_push } '#{ dest_path }'")
13
+
14
+ log!(:finished)
15
+ end
16
+
17
+ private
18
+
19
+ # Expand path, since this is local and shell-quoted.
20
+ def dest_path
21
+ @dest_path ||= File.expand_path(path)
22
+ end
23
+
24
+ def create_dest_path!
25
+ FileUtils.mkdir_p dest_path
26
+ end
27
+
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ module SlidayBackup
4
+ module Syncer
5
+ module RSync
6
+ class Pull < Push
7
+
8
+ def perform!
9
+ log!(:started)
10
+ write_password_file!
11
+
12
+ create_dest_path!
13
+ run("#{ rsync_command } #{ host_options }#{ paths_to_pull } " +
14
+ "'#{ dest_path }'")
15
+
16
+ log!(:finished)
17
+ ensure
18
+ remove_password_file!
19
+ end
20
+
21
+ private
22
+
23
+ ##
24
+ # Returns the syntax for pulling multiple paths from the remote host.
25
+ # e.g.
26
+ # rsync -a -e "ssh -p 22" host:'path1' :'path2' '/dest'
27
+ # rsync -a rsync_user@host::'modname/path1' ::'modname/path2' '/dest'
28
+ #
29
+ # Remove any preceeding '~/', since these paths are on the remote.
30
+ # Also remove any trailing `/`, since we don't want rsync's
31
+ # "trailing / on source directories" behavior.
32
+ def paths_to_pull
33
+ sep = mode == :ssh ? ':' : '::'
34
+ directories.map {|dir|
35
+ "#{ sep }'#{ dir.sub(/^~\//, '').sub(/\/$/, '') }'"
36
+ }.join(' ').sub(/^#{ sep }/, '')
37
+ end
38
+
39
+ # Expand path, since this is local and shell-quoted.
40
+ def dest_path
41
+ @dest_path ||= File.expand_path(path)
42
+ end
43
+
44
+ def create_dest_path!
45
+ FileUtils.mkdir_p dest_path
46
+ end
47
+
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,205 @@
1
+ # encoding: utf-8
2
+
3
+ module SlidayBackup
4
+ module Syncer
5
+ module RSync
6
+ class Push < Base
7
+
8
+ ##
9
+ # Mode of operation
10
+ #
11
+ # [:ssh (default)]
12
+ # Connects to the remote via SSH.
13
+ # Does not use an rsync daemon on the remote.
14
+ #
15
+ # [:ssh_daemon]
16
+ # Connects to the remote via SSH.
17
+ # Spawns a single-use daemon on the remote, which allows certain
18
+ # daemon features (like modules) to be used.
19
+ #
20
+ # [:rsync_daemon]
21
+ # Connects directly to an rsync daemon via TCP.
22
+ # Data transferred is not encrypted.
23
+ #
24
+ attr_accessor :mode
25
+
26
+ ##
27
+ # Server Address
28
+ attr_accessor :host
29
+
30
+ ##
31
+ # SSH or RSync port
32
+ #
33
+ # For `:ssh` or `:ssh_daemon` mode, this specifies the SSH port to use
34
+ # and defaults to 22.
35
+ #
36
+ # For `:rsync_daemon` mode, this specifies the TCP port to use
37
+ # and defaults to 873.
38
+ attr_accessor :port
39
+
40
+ ##
41
+ # SSH User
42
+ #
43
+ # If the user running the backup is not the same user that needs to
44
+ # authenticate with the remote server, specify the user here.
45
+ #
46
+ # The user must have SSH keys setup for passphrase-less access to the
47
+ # remote. If the SSH User does not have passphrase-less keys, or no
48
+ # default keys in their `~/.ssh` directory, you will need to use the
49
+ # `-i` option in `:additional_ssh_options` to specify the
50
+ # passphrase-less key to use.
51
+ #
52
+ # Used only for `:ssh` and `:ssh_daemon` modes.
53
+ attr_accessor :ssh_user
54
+
55
+ ##
56
+ # Additional SSH Options
57
+ #
58
+ # Used to supply a String or Array of options to be passed to the SSH
59
+ # command in `:ssh` and `:ssh_daemon` modes.
60
+ #
61
+ # For example, if you need to supply a specific SSH key for the `ssh_user`,
62
+ # you would set this to: "-i '/path/to/id_rsa'". Which would produce:
63
+ #
64
+ # rsync -e "ssh -p 22 -i '/path/to/id_rsa'"
65
+ #
66
+ # Arguments may be single-quoted, but should not contain any double-quotes.
67
+ #
68
+ # Used only for `:ssh` and `:ssh_daemon` modes.
69
+ attr_accessor :additional_ssh_options
70
+
71
+ ##
72
+ # RSync User
73
+ #
74
+ # If the user running the backup is not the same user that needs to
75
+ # authenticate with the rsync daemon, specify the user here.
76
+ #
77
+ # Used only for `:ssh_daemon` and `:rsync_daemon` modes.
78
+ attr_accessor :rsync_user
79
+
80
+ ##
81
+ # RSync Password
82
+ #
83
+ # If specified, SlidayBackup will write the password to a temporary file and
84
+ # use it with rsync's `--password-file` option for daemon authentication.
85
+ #
86
+ # Note that setting this will override `rsync_password_file`.
87
+ #
88
+ # Used only for `:ssh_daemon` and `:rsync_daemon` modes.
89
+ attr_accessor :rsync_password
90
+
91
+ ##
92
+ # RSync Password File
93
+ #
94
+ # If specified, this path will be passed to rsync's `--password-file`
95
+ # option for daemon authentication.
96
+ #
97
+ # Used only for `:ssh_daemon` and `:rsync_daemon` modes.
98
+ attr_accessor :rsync_password_file
99
+
100
+ ##
101
+ # Flag for compressing (only compresses for the transfer)
102
+ attr_accessor :compress
103
+
104
+ def initialize(syncer_id = nil)
105
+ super
106
+
107
+ @mode ||= :ssh
108
+ @port ||= mode == :rsync_daemon ? 873 : 22
109
+ @compress ||= false
110
+ end
111
+
112
+ def perform!
113
+ log!(:started)
114
+ write_password_file!
115
+
116
+ create_dest_path!
117
+ run("#{ rsync_command } #{ paths_to_push } " +
118
+ "#{ host_options }'#{ dest_path }'")
119
+
120
+ log!(:finished)
121
+ ensure
122
+ remove_password_file!
123
+ end
124
+
125
+ private
126
+
127
+ ##
128
+ # Remove any preceeding '~/', since this is on the remote,
129
+ # and remove any trailing `/`.
130
+ def dest_path
131
+ @dest_path ||= path.sub(/^~\//, '').sub(/\/$/, '')
132
+ end
133
+
134
+ ##
135
+ # Runs a 'mkdir -p' command on the remote to ensure the dest_path exists.
136
+ # This used because rsync will attempt to create the path, but will only
137
+ # call 'mkdir' without the '-p' option. This is only applicable in :ssh
138
+ # mode, and only used if the path would require this.
139
+ def create_dest_path!
140
+ return unless mode == :ssh && dest_path.index('/').to_i > 0
141
+
142
+ run "#{ utility(:ssh) } #{ ssh_transport_args } #{ host } " +
143
+ %Q["mkdir -p '#{ dest_path }'"]
144
+ end
145
+
146
+ ##
147
+ # For Push, this will prepend the #dest_path.
148
+ # For Pull, this will prepend the first path in #paths_to_pull.
149
+ def host_options
150
+ if mode == :ssh
151
+ "#{ host }:"
152
+ else
153
+ user = "#{ rsync_user }@" if rsync_user
154
+ "#{ user }#{ host }::"
155
+ end
156
+ end
157
+
158
+ ##
159
+ # Common base command, plus options for Push/Pull
160
+ def rsync_command
161
+ super << compress_option << password_option << transport_options
162
+ end
163
+
164
+ def compress_option
165
+ compress ? ' --compress' : ''
166
+ end
167
+
168
+ def password_option
169
+ return '' if mode == :ssh
170
+
171
+ path = @password_file ? @password_file.path : rsync_password_file
172
+ path ? " --password-file='#{ File.expand_path(path) }'" : ''
173
+ end
174
+
175
+ def transport_options
176
+ if mode == :rsync_daemon
177
+ " --port #{ port }"
178
+ else
179
+ %Q[ -e "#{ utility(:ssh) } #{ ssh_transport_args }"]
180
+ end
181
+ end
182
+
183
+ def ssh_transport_args
184
+ args = "-p #{ port } "
185
+ args << "-l #{ ssh_user } " if ssh_user
186
+ args << Array(additional_ssh_options).join(' ')
187
+ args.rstrip
188
+ end
189
+
190
+ def write_password_file!
191
+ return unless rsync_password && mode != :ssh
192
+
193
+ @password_file = Tempfile.new('backup-rsync-password')
194
+ @password_file.write(rsync_password)
195
+ @password_file.close
196
+ end
197
+
198
+ def remove_password_file!
199
+ @password_file.delete if @password_file
200
+ end
201
+
202
+ end
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ require 'erb'
4
+
5
+ module SlidayBackup
6
+ class Template
7
+
8
+ # Holds a binding object. Nil if not provided.
9
+ attr_accessor :binding
10
+
11
+ ##
12
+ # Creates a new instance of the SlidayBackup::Template class
13
+ # and optionally takes an argument that can be either a binding object, a Hash or nil
14
+ def initialize(object = nil)
15
+ if object.is_a?(Binding)
16
+ @binding = object
17
+ elsif object.is_a?(Hash)
18
+ @binding = SlidayBackup::Binder.new(object).get_binding
19
+ else
20
+ @binding = nil
21
+ end
22
+ end
23
+
24
+ ##
25
+ # Renders the provided file (in the context of the binding if any) to the console
26
+ def render(file)
27
+ puts result(file)
28
+ end
29
+
30
+ ##
31
+ # Returns a String object containing the contents of the file (in the context of the binding if any)
32
+ def result(file)
33
+ ERB.new(file_contents(file), nil, '<>').result(binding)
34
+ end
35
+
36
+ private
37
+
38
+ ##
39
+ # Reads and returns the contents of the provided file path,
40
+ # relative from the SlidayBackup::TEMPLATE_PATH
41
+ def file_contents(file)
42
+ File.read(File.join(SlidayBackup::TEMPLATE_PATH, file))
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,224 @@
1
+ # encoding: utf-8
2
+
3
+ module SlidayBackup
4
+ module Utilities
5
+ class Error < SlidayBackup::Error; end
6
+
7
+ UTILITY = {}
8
+ NAMES = %w{
9
+ tar cat split sudo chown hostname
10
+ gzip bzip2
11
+ mongo mongodump mysqldump innobackupex
12
+ pg_dump pg_dumpall redis-cli riak-admin
13
+ gpg openssl
14
+ rsync ssh
15
+ sendmail exim
16
+ send_nsca
17
+ zabbix_sender
18
+ }
19
+
20
+ module DSL
21
+ class << self
22
+ ##
23
+ # Allow users to set the path for all utilities in the .configure block.
24
+ #
25
+ # Utility names with dashes ('redis-cli') will be set using method calls
26
+ # with an underscore ('redis_cli').
27
+ NAMES.each do |name|
28
+ define_method name.gsub('-', '_'), lambda {|val|
29
+ path = File.expand_path(val)
30
+ unless File.executable?(path)
31
+ raise Utilities::Error, <<-EOS
32
+ The path given for '#{ name }' was not found or not executable.
33
+ Path was: #{ path }
34
+ EOS
35
+ end
36
+ UTILITY[name] = path
37
+ }
38
+ end
39
+
40
+ ##
41
+ # Allow users to set the +tar+ distribution if needed. (:gnu or :bsd)
42
+ def tar_dist(val)
43
+ Utilities.tar_dist(val)
44
+ end
45
+ end
46
+ end
47
+
48
+ class << self
49
+ ##
50
+ # Configure the path to system utilities used by SlidayBackup.
51
+ #
52
+ # SlidayBackup will attempt to locate any required system utilities using a
53
+ # +which+ command call. If a utility can not be found, or you need to
54
+ # specify an alternate path for a utility, you may do so in your
55
+ # +config.rb+ file using this method.
56
+ #
57
+ # SlidayBackup supports both GNU and BSD utilities.
58
+ # While SlidayBackup uses these utilities in a manner compatible with either
59
+ # version, the +tar+ utility requires some special handling with respect
60
+ # to +Archive+s. SlidayBackup will attempt to detect if the +tar+ command
61
+ # found (or set here) is GNU or BSD. If for some reason this fails,
62
+ # this may be set using the +tar_dist+ command shown below.
63
+ #
64
+ # SlidayBackup::Utilities.configure do
65
+ # # General Utilites
66
+ # tar '/path/to/tar'
67
+ # tar_dist :gnu # or :bsd
68
+ # cat '/path/to/cat'
69
+ # split '/path/to/split'
70
+ # sudo '/path/to/sudo'
71
+ # chown '/path/to/chown'
72
+ # hostname '/path/to/hostname'
73
+ #
74
+ # # Compressors
75
+ # gzip '/path/to/gzip'
76
+ # bzip2 '/path/to/bzip2'
77
+ #
78
+ # # Database Utilities
79
+ # mongo '/path/to/mongo'
80
+ # mongodump '/path/to/mongodump'
81
+ # mysqldump '/path/to/mysqldump'
82
+ # pg_dump '/path/to/pg_dump'
83
+ # pg_dumpall '/path/to/pg_dumpall'
84
+ # redis_cli '/path/to/redis-cli'
85
+ # riak_admin '/path/to/riak-admin'
86
+ #
87
+ # # Encryptors
88
+ # gpg '/path/to/gpg'
89
+ # openssl '/path/to/openssl'
90
+ #
91
+ # # Syncer and Storage
92
+ # rsync '/path/to/rsync'
93
+ # ssh '/path/to/ssh'
94
+ #
95
+ # # Notifiers
96
+ # sendmail '/path/to/sendmail'
97
+ # exim '/path/to/exim'
98
+ # send_nsca '/path/to/send_nsca'
99
+ # zabbix_sender '/path/to/zabbix_sender'
100
+ # end
101
+ #
102
+ # These paths may be set using absolute paths, or relative to the
103
+ # working directory when SlidayBackup is run.
104
+ def configure(&block)
105
+ DSL.instance_eval(&block)
106
+ end
107
+
108
+ def tar_dist(val)
109
+ # the acceptance tests need to be able to reset this to nil
110
+ @gnu_tar = val.nil? ? nil : val == :gnu
111
+ end
112
+
113
+ def gnu_tar?
114
+ return @gnu_tar unless @gnu_tar.nil?
115
+ @gnu_tar = !!run("#{ utility(:tar) } --version").match(/GNU/)
116
+ end
117
+
118
+ private
119
+
120
+ ##
121
+ # Returns the full path to the specified utility.
122
+ # Raises an error if utility can not be found in the system's $PATH
123
+ def utility(name)
124
+ name = name.to_s.strip
125
+ raise Error, 'Utility Name Empty' if name.empty?
126
+
127
+ UTILITY[name] ||= %x[which '#{ name }' 2>/dev/null].chomp
128
+ raise Error, <<-EOS if UTILITY[name].empty?
129
+ Could not locate '#{ name }'.
130
+ Make sure the specified utility is installed
131
+ and available in your system's $PATH, or specify it's location
132
+ in your 'config.rb' file using SlidayBackup::Utilities.configure
133
+ EOS
134
+
135
+ UTILITY[name].dup
136
+ end
137
+
138
+ ##
139
+ # Returns the name of the command name from the given command line.
140
+ # This is only used to simplify log messages.
141
+ def command_name(command)
142
+ parts = []
143
+ command = command.split(' ')
144
+ command.shift while command[0].to_s.include?('=')
145
+ parts << command.shift.split('/')[-1]
146
+ if parts[0] == 'sudo'
147
+ until command.empty?
148
+ part = command.shift
149
+ if part.include?('/')
150
+ parts << part.split('/')[-1]
151
+ break
152
+ else
153
+ parts << part
154
+ end
155
+ end
156
+ end
157
+ parts.join(' ')
158
+ end
159
+
160
+ ##
161
+ # Runs a system command
162
+ #
163
+ # All messages generated by the command will be logged.
164
+ # Messages on STDERR will be logged as warnings.
165
+ #
166
+ # If the command fails to execute, or returns a non-zero exit status
167
+ # an Error will be raised.
168
+ #
169
+ # Returns STDOUT
170
+ def run(command)
171
+ name = command_name(command)
172
+ Logger.info "Running system utility '#{ name }'..."
173
+
174
+ begin
175
+ out, err = '', ''
176
+ ps = Open4.popen4(command) do |pid, stdin, stdout, stderr|
177
+ stdin.close
178
+ out, err = stdout.read.strip, stderr.read.strip
179
+ end
180
+ rescue Exception => e
181
+ raise Error.wrap(e, "Failed to execute '#{ name }'")
182
+ end
183
+
184
+ if ps.success?
185
+ unless out.empty?
186
+ Logger.info(
187
+ out.lines.map {|line| "#{ name }:STDOUT: #{ line }" }.join
188
+ )
189
+ end
190
+
191
+ unless err.empty?
192
+ Logger.warn(
193
+ err.lines.map {|line| "#{ name }:STDERR: #{ line }" }.join
194
+ )
195
+ end
196
+
197
+ return out
198
+ else
199
+ raise Error, <<-EOS
200
+ '#{ name }' failed with exit status: #{ ps.exitstatus }
201
+ STDOUT Messages: #{ out.empty? ? 'None' : "\n#{ out }" }
202
+ STDERR Messages: #{ err.empty? ? 'None' : "\n#{ err }" }
203
+ EOS
204
+ end
205
+ end
206
+
207
+ def reset!
208
+ UTILITY.clear
209
+ @gnu_tar = nil
210
+ end
211
+ end
212
+
213
+ # Allows these utility methods to be included in other classes,
214
+ # while allowing them to be stubbed in spec_helper for all specs.
215
+ module Helpers
216
+ [:utility, :command_name, :run].each do |name|
217
+ define_method name, lambda {|arg| Utilities.send(name, arg) }
218
+ private name
219
+ end
220
+ private
221
+ def gnu_tar?; Utilities.gnu_tar?; end
222
+ end
223
+ end
224
+ end