doable 0.0.3 → 0.0.4
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 +4 -4
- data/lib/doable/exceptions/framework.rb +9 -7
- data/lib/doable/exceptions/linux.rb +11 -0
- data/lib/doable/exceptions/os.rb +45 -1
- data/lib/doable/helpers/linux.rb +296 -0
- data/lib/doable/helpers/password.rb +13 -0
- data/lib/doable/job.rb +14 -3
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12cd4bee334b582b69a835051c8cfeb0314aa3e3
|
4
|
+
data.tar.gz: 84db114358f2ea2f7511900421206ed8ddcbe9d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 380841e88c0f7dcf73a6d9a85bf6d3bdb0941a519f8072e0957515c42a38b224fc3e8be81ed6be0b4c338a7ae071f3c55228f0877fb634bfb8322cf7c69f4745
|
7
|
+
data.tar.gz: 56aea29e8c7bfd238d806d8953ab456ef13239b9ec019d2316b22be8e2a747bf9620106a3f686d7d429c4446d79ef41e2b7adfec0e98ba8de829596deabdfccd
|
@@ -1,21 +1,21 @@
|
|
1
1
|
module Doable
|
2
2
|
module Exceptions
|
3
3
|
module Framework
|
4
|
+
# Exception to be thrown when nothing else applies. Inherited by other exceptions.
|
4
5
|
class GenericFrameworkError < StandardError
|
5
6
|
end
|
6
7
|
|
8
|
+
# When the provided parameters or other input is not valid.
|
7
9
|
class InvalidInput < GenericFrameworkError
|
8
10
|
end
|
9
11
|
|
12
|
+
# Correct number of parameters is passed but it is not of the correct type.
|
13
|
+
# i.e., type error in strongly typed languages
|
10
14
|
class NotApplicable < InvalidInput
|
11
15
|
end
|
12
16
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
class MissingDefinitionsDirectory < GenericFrameworkError
|
17
|
-
end
|
18
|
-
|
17
|
+
# This can be called when a helper method is expecting a parameter that wasn't passed.
|
18
|
+
# i.e., an options hash doesn't contain the requisite elements.
|
19
19
|
class MissingParameter < InvalidInput
|
20
20
|
end
|
21
21
|
|
@@ -24,11 +24,13 @@ module Doable
|
|
24
24
|
end
|
25
25
|
|
26
26
|
# !These exceptions should never be caught by anything!
|
27
|
+
# This is an internal exception used primarily for logging purposes. Provides a clean way to log
|
27
28
|
class SkipStep < StandardError
|
28
29
|
end
|
29
30
|
|
31
|
+
# Allows the the application to notify the completion of a Rollback and that the job object was not successfully executed.
|
30
32
|
class RolledBack < StandardError
|
31
33
|
end
|
32
34
|
end
|
33
35
|
end
|
34
|
-
end
|
36
|
+
end
|
data/lib/doable/exceptions/os.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module Doable
|
2
2
|
module Exceptions
|
3
|
+
# Exceptions which are agnostic to the underlying OS.
|
3
4
|
module OS
|
5
|
+
# Generic exception to be inherited by all other OS-level exceptions.
|
4
6
|
class OSException < GenericFrameworkError
|
5
7
|
end
|
6
8
|
|
@@ -16,8 +18,50 @@ module Doable
|
|
16
18
|
class InvalidHostname < OSException
|
17
19
|
end
|
18
20
|
|
21
|
+
class FailedPasswordChange < OSException
|
22
|
+
end
|
23
|
+
|
19
24
|
class MissingFile < OSException
|
20
25
|
end
|
26
|
+
|
27
|
+
class MissingExecutable < OSException
|
28
|
+
end
|
29
|
+
|
30
|
+
class FailedCopy < OSException
|
31
|
+
end
|
32
|
+
|
33
|
+
class NotApplicable < OSException
|
34
|
+
end
|
35
|
+
|
36
|
+
class DuplicateUsers < OSException
|
37
|
+
end
|
38
|
+
|
39
|
+
class DuplicateGroups < OSException
|
40
|
+
end
|
41
|
+
|
42
|
+
class WrongHomedir < OSException
|
43
|
+
end
|
44
|
+
|
45
|
+
class InvalidArchitecture < OSException
|
46
|
+
end
|
47
|
+
|
48
|
+
class MissingUser < OSException
|
49
|
+
end
|
50
|
+
|
51
|
+
class WrongUser < OSException
|
52
|
+
end
|
53
|
+
|
54
|
+
class FailedGroupAdd < OSException
|
55
|
+
end
|
56
|
+
|
57
|
+
class FailedUserModification < OSException
|
58
|
+
end
|
59
|
+
|
60
|
+
class FailedUncompress < OSException
|
61
|
+
end
|
62
|
+
|
63
|
+
class AmbiguousProcess < OSException
|
64
|
+
end
|
21
65
|
end
|
22
66
|
end
|
23
|
-
end
|
67
|
+
end
|
@@ -0,0 +1,296 @@
|
|
1
|
+
require 'doable/helpers/os'
|
2
|
+
require 'doable/exceptions/linux'
|
3
|
+
|
4
|
+
module Doable
|
5
|
+
module Helpers
|
6
|
+
module Linux
|
7
|
+
include OS
|
8
|
+
include Exceptions::Linux
|
9
|
+
# Used like Unix chown
|
10
|
+
# @param user [String] User to set as the owner
|
11
|
+
# @param group [String] Group to set as the owner
|
12
|
+
# @param file_list [Array<String>,String] List of files to change the owner of
|
13
|
+
def chown(user, group, file_list, options = {recursive: false})
|
14
|
+
if options[:recursive]
|
15
|
+
options.delete :recursive
|
16
|
+
FileUtils.chown_R(user, group, file_list, options)
|
17
|
+
else
|
18
|
+
options.delete(:recursive) if options.has_key?(:recursive)
|
19
|
+
FileUtils.chown(user, group, file_list, options)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Used like Unix chmod
|
24
|
+
# @param permission [String, Fixnum] Permissions to set
|
25
|
+
# @param file_list [Array<String>,String] List of files to change the permissions of
|
26
|
+
def chmod(permission, file_list, options = {recursive: false})
|
27
|
+
if options[:recursive]
|
28
|
+
options.delete :recursive
|
29
|
+
FileUtils.chmod_R(permission, file_list, options)
|
30
|
+
else
|
31
|
+
options.delete(:recursive) if options.has_key?(:recursive)
|
32
|
+
FileUtils.chmod(permission, file_list, options)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Apply a patch file
|
37
|
+
# @param options [String] Options to be added to the `patch` system command
|
38
|
+
# @param patch_file [String] Path to the patch file to apply
|
39
|
+
# @param path [String] Optionally cd to this directory before patching
|
40
|
+
# @param user [String] Optionally apply patch as this user
|
41
|
+
def apply_patch(options, patch_file, path = nil, user = nil)
|
42
|
+
cmd = "patch #{options} < #{patch_file}"
|
43
|
+
|
44
|
+
olddir = `pwd`.chomp
|
45
|
+
Dir.chdir(path) if path
|
46
|
+
tee 'pwd'
|
47
|
+
if user
|
48
|
+
run_as_user user, cmd
|
49
|
+
else
|
50
|
+
tee cmd
|
51
|
+
end
|
52
|
+
Dir.chdir(olddir) if path
|
53
|
+
end
|
54
|
+
|
55
|
+
# Add an entry to a user's ~/.bashrc
|
56
|
+
# @param user [String] User to add bashrc entries to
|
57
|
+
# @param entry [String] Entry to add to user's .bashrc
|
58
|
+
def add_bashrc_entry(user, entry)
|
59
|
+
File.open(File.expand_path("~#{user}/.bashrc"), "a") {|f| f.puts entry }
|
60
|
+
end
|
61
|
+
|
62
|
+
# Get a list of process matching a Regexp
|
63
|
+
# @param regex [Regexp] Regular expression to use for finding processes
|
64
|
+
# @return [Array<String>] Array of PIDs that match the regex
|
65
|
+
def find_processes(regex)
|
66
|
+
`ps aux`.chomp.split("\n").map {|l| l.split(nil, 11) }.collect {|p| p if p[10].match(regex)}.compact
|
67
|
+
end
|
68
|
+
|
69
|
+
# Kill a process
|
70
|
+
# @param pid [Fixnum,String] PID to kill
|
71
|
+
# @param signal [String] Signal to kill PID with
|
72
|
+
def kill(pid, signal = "TERM")
|
73
|
+
Process.kill(signal, pid)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Does the system have an executable in $PATH? If not, return false.
|
77
|
+
# @param name [String] Executable to verify
|
78
|
+
# @return [String, false]
|
79
|
+
def have_executable?(name)
|
80
|
+
app_path = `which #{name}`.chomp
|
81
|
+
if app_path.match(name)
|
82
|
+
return app_path
|
83
|
+
else
|
84
|
+
return false
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Require an executable to be in $PATH
|
89
|
+
# @raise [MissingExecutable]
|
90
|
+
# @param name [String] Required executable
|
91
|
+
def find_executable(name)
|
92
|
+
have_executable?(name) ? true : raise(MissingExecutable, name)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Check for RPMs (kind of RHEL / SuSE specific)
|
96
|
+
# @raise [InvalidRPMList]
|
97
|
+
# @raise [NotApplicable]
|
98
|
+
# @raise [MissingRPMs]
|
99
|
+
# @param rpms [Array<String>] RPMs to verify
|
100
|
+
# #return [Boolean]
|
101
|
+
def check_for_rpms(rpms)
|
102
|
+
raise InvalidRPMList unless rpms.kind_of?(Array)
|
103
|
+
# Split the list of all installed RPMs into an Array containing only the RPM's base name
|
104
|
+
system_rpms = `rpm -qa`.chomp.split("\n").collect {|rpm| rpm.split(/-[0-9]/)[0]}
|
105
|
+
i686_rpms = `rpm -qa`.chomp.split("\n").collect {|rpm| rpm.split(/-[0-9]/)[0] if rpm.match(/\.i686$/)}.compact
|
106
|
+
raise NotApplicable unless $?.success?
|
107
|
+
missing_rpms = rpms.collect {|rpm| rpm unless rpm.match(/\.i686$/) }.compact - system_rpms # calculate what RPMs are not installed
|
108
|
+
missing_rpms = (missing_rpms + (rpms.collect {|rpm| rpm.split('.')[0] if rpm.match(/\.i686$/) }.compact - i686_rpms).compact.map {|r| "#{r}.i686" } ).compact
|
109
|
+
if missing_rpms.size > 0
|
110
|
+
log "Missing RPMs: #{missing_rpms.join(', ')}", :error
|
111
|
+
raise MissingRPMs
|
112
|
+
else
|
113
|
+
return true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Ensure a user exists on the system
|
118
|
+
# @raise [DuplicateUsers]
|
119
|
+
# @raise [WrongHomedir]
|
120
|
+
# @param user [String] User to add or verify
|
121
|
+
# @param homedir [String] User home directory
|
122
|
+
# @return [Boolean]
|
123
|
+
def find_or_create_user(user, homedir, options = {})
|
124
|
+
# Create an Array of Arrays storing all known system users and their attributes
|
125
|
+
all_users = `getent passwd`.chomp.split("\n").map {|line| line.split(':')}
|
126
|
+
# Determine if the user we want exists
|
127
|
+
this_user = all_users.collect {|u| u if u[0] == user}.compact
|
128
|
+
if this_user.size > 1
|
129
|
+
log "Multiple instances of user #{user} found. This is known to cause problems.", :error
|
130
|
+
raise DuplicateUsers
|
131
|
+
elsif this_user.size == 1
|
132
|
+
log "User '#{user}' already exists with uid: #{this_user.flatten[2]}. Skipping creation of user...", :warn
|
133
|
+
full_home = File.expand_path(homedir)
|
134
|
+
current_home = File.expand_path(this_user.flatten[5])
|
135
|
+
if (full_home != current_home) and (homedir != current_home)
|
136
|
+
log "User's home directory is set to #{current_home}, not #{homedir}!", :error
|
137
|
+
raise WrongHomedir
|
138
|
+
end
|
139
|
+
else
|
140
|
+
log "Creating #{user} user..."
|
141
|
+
shell = options[:shell] ? options[:shell] : '/bin/bash'
|
142
|
+
`useradd -d "#{homedir}" -s "#{shell}" -mr "#{user}"`
|
143
|
+
end
|
144
|
+
|
145
|
+
return true
|
146
|
+
end
|
147
|
+
|
148
|
+
# Sets a user's password
|
149
|
+
# @note This _may_ only work on RHEL (and the like), as chpasswd may not be available on other OS's
|
150
|
+
# @raise [FailedPasswordChange]
|
151
|
+
# @param user [String] User to set password for
|
152
|
+
# @param new_pass [String] New password for user
|
153
|
+
# @return [Boolean]
|
154
|
+
def set_user_password(user, new_pass)
|
155
|
+
log "Setting password for #{user}..."
|
156
|
+
`echo "#{user}:#{new_pass}" | chpasswd`
|
157
|
+
raise FailedPasswordChange unless $?.success?
|
158
|
+
return $?.success?
|
159
|
+
end
|
160
|
+
|
161
|
+
# Die if a user doesn't exist
|
162
|
+
# @raise [DuplicateUsers]
|
163
|
+
# @raise [MissingUser]
|
164
|
+
# @param user [String] User to verify
|
165
|
+
# @param noisy [Boolean] Should extra info be logged?
|
166
|
+
# @return [Array]
|
167
|
+
def find_user(user, noisy = false)
|
168
|
+
# Create an Array of Arrays storing all known system users and their attributes
|
169
|
+
all_users = `getent passwd`.chomp.split("\n").map {|line| line.split(':')}
|
170
|
+
# Determine if the user we want exists
|
171
|
+
this_user = all_users.collect {|u| u if u[0] == user}.compact
|
172
|
+
if this_user.size > 1
|
173
|
+
log "Multiple instances of user #{user} found. This is known to cause problems.", :error
|
174
|
+
raise DuplicateUsers
|
175
|
+
elsif this_user.size < 1
|
176
|
+
log "Missing Critical User '#{user}'!", :error
|
177
|
+
raise MissingUser
|
178
|
+
else
|
179
|
+
log "Found required user '#{user}' with uid #{this_user.flatten[2]}..." if noisy
|
180
|
+
end
|
181
|
+
return this_user.flatten
|
182
|
+
end
|
183
|
+
|
184
|
+
# Ensure a group exists
|
185
|
+
# @raise [DuplicateGroups]
|
186
|
+
# @raise [FailedGroupAdd]
|
187
|
+
# @param group [String] Group to create or verify
|
188
|
+
# @return [Boolean]
|
189
|
+
def find_or_create_group(group)
|
190
|
+
all_groups = `getent group`.chomp.split("\n").map {|line| line.split(':')}
|
191
|
+
this_group = all_groups.collect {|g| g if g[0] == group}.compact
|
192
|
+
if this_group.size > 1
|
193
|
+
log "Multiple instances of group #{group} found. This is known to cause problems.", :error
|
194
|
+
raise DuplicateGroups
|
195
|
+
elsif this_group.size == 1
|
196
|
+
log "Group '#{group}' already exists with gid: #{this_group.flatten[2]}. Skipping creation of group...", :warn
|
197
|
+
else
|
198
|
+
log "Creating group '#{group}'..."
|
199
|
+
`groupadd -r "#{group}"`
|
200
|
+
raise FailedGroupAdd unless $?.success?
|
201
|
+
return $?.success?
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Set a user's gid (default group)
|
206
|
+
# @raise [FailedUserModification]
|
207
|
+
# @param user [String] User to update
|
208
|
+
# @param gid [String,Fixnum] Group to set as default for user
|
209
|
+
def update_user_gid(user, gid)
|
210
|
+
user_details = find_user(user)
|
211
|
+
if user_details[3] != gid
|
212
|
+
log "Setting default group for #{user} to #{gid}..."
|
213
|
+
`usermod -g #{gid} "#{user}"`
|
214
|
+
raise FailedUserModification unless $?.success?
|
215
|
+
log "Fixing permissions..."
|
216
|
+
`chown -R #{user}:#{gid} "#{user_details[5]}"`
|
217
|
+
end
|
218
|
+
return gid
|
219
|
+
end
|
220
|
+
|
221
|
+
# Finds the mount point for a directory, then checks it for a minimum number of kilobytes
|
222
|
+
# @param install_dir [String] Directory from which check starts
|
223
|
+
# @param min_space [Fixnum] Minumum amount of space required on mount-point discovered from install_dir
|
224
|
+
def check_disk_space(install_dir, min_space)
|
225
|
+
all_filesystems = `df -PB 1024`.chomp.split("\n").collect {|fs| fs.split if fs.match(/^\/dev/) }.compact
|
226
|
+
best_fit = nil
|
227
|
+
current_test = install_dir
|
228
|
+
until best_fit
|
229
|
+
matching_fs = all_filesystems.collect {|fs| fs if File.expand_path(fs[5]) == File.expand_path(current_test) }.compact
|
230
|
+
if matching_fs.size == 1
|
231
|
+
best_fit = matching_fs.flatten
|
232
|
+
else
|
233
|
+
current_test = File.dirname(current_test)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
log "Closest matching filesystem is '#{best_fit[5]}'. Testing for free space..."
|
238
|
+
if Integer(best_fit[3]) >= min_space
|
239
|
+
log "Found sufficient space #{best_fit[3]} for install on #{best_fit[5]} with an install directory of #{install_dir}."
|
240
|
+
else
|
241
|
+
log "Insufficient space #{best_fit[3]} for install on #{best_fit[5]} with an install directory of #{install_dir}!", :error
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# Linux specific way to run something as another user. Command must be passed as a String.
|
246
|
+
# @param user [String] User that will run command
|
247
|
+
# @param command [String] Command to be run by user
|
248
|
+
def run_as_user(user, command)
|
249
|
+
log "Running '#{command}' as '#{user}'..."
|
250
|
+
tee("su -l #{user} -c \"#{command}\"")
|
251
|
+
end
|
252
|
+
|
253
|
+
# Set the max number of open files for a user (nofiles)
|
254
|
+
# (sets both hard and soft, errors out if user is already listed in limits.conf)
|
255
|
+
# Currently does NOT verify the existence of the specified user on the system
|
256
|
+
# @param user [String] User to set 'nofile' ulimit security setting for
|
257
|
+
# @param limit [Fixnum] Limit to set for user
|
258
|
+
# @return [Boolean]
|
259
|
+
def set_nofile(user, limit)
|
260
|
+
# See if the user is already in the limits.conf file
|
261
|
+
user_entries = `grep -E '^#{user}(\s|\t)+' /etc/security/limits.conf`.chomp.split("\n")
|
262
|
+
if user_entries.empty?
|
263
|
+
# Doing this the lazy way for now... this is probably dangerous for very large files
|
264
|
+
|
265
|
+
# Open and copy the current content of the limits file plus a few extra lines towards the end
|
266
|
+
current_file = File.readlines("/etc/security/limits.conf")
|
267
|
+
temporary = Tempfile.new("new_limits")
|
268
|
+
current_file[0..(current_file.size - 2)].each {|l| temporary.write l }
|
269
|
+
|
270
|
+
temporary.write "#{user}\t\tsoft\tnofile\t\t#{limit}\n"
|
271
|
+
temporary.write "#{user}\t\thard\tnofile\t\t#{limit}\n"
|
272
|
+
temporary.write "\n"
|
273
|
+
temporary.write current_file[current_file.size - 1]
|
274
|
+
temporary.rewind
|
275
|
+
|
276
|
+
# Create a backup of the current file
|
277
|
+
FileUtils.cp "/etc/security/limits.conf", "/etc/security/limits.conf.#{Time.now.to_i}"
|
278
|
+
# Clear out the current file
|
279
|
+
File.truncate("/etc/security/limits.conf", 0)
|
280
|
+
# Copy the temporary (new) file to the existing
|
281
|
+
current_file = File.new("/etc/security/limits.conf", "w")
|
282
|
+
temporary.each {|l| current_file.puts l }
|
283
|
+
# Close everything up
|
284
|
+
temporary.close
|
285
|
+
temporary.unlink
|
286
|
+
current_file.close
|
287
|
+
return true
|
288
|
+
else
|
289
|
+
log "User '#{user}' already has a specific entry in /etc/security/limits.conf. Ensure 'nofile' is at least #{limit}.", :warn
|
290
|
+
return false
|
291
|
+
end
|
292
|
+
end # set_nofile()
|
293
|
+
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
@@ -10,6 +10,19 @@ module Doable
|
|
10
10
|
|
11
11
|
(1..length).collect{|a| options[:characters][rand(options[:characters].size)] }.join
|
12
12
|
end # generate_password()
|
13
|
+
|
14
|
+
def sha1_hash(password, add_salt = true)
|
15
|
+
salt = if add_salt?
|
16
|
+
if add_salt.kind_of?(String) and add_salt.downcase.match(/^[0-9a-f]+$/)
|
17
|
+
add_salt.downcase
|
18
|
+
else
|
19
|
+
generate_password(16, characters: [*(0..9), *('a'..'f')])
|
20
|
+
end
|
21
|
+
else
|
22
|
+
''
|
23
|
+
end
|
24
|
+
Base64.encode64(Digest::SHA1.digest(password + salt) + salt).chomp
|
25
|
+
end
|
13
26
|
end
|
14
27
|
end
|
15
28
|
end
|
data/lib/doable/job.rb
CHANGED
@@ -8,10 +8,19 @@ module Doable
|
|
8
8
|
include Helpers::Logging
|
9
9
|
attr_reader :steps, :hooks, :handlers, :threads
|
10
10
|
|
11
|
+
# Allows sequential definition of job steps.
|
12
|
+
# @example usage
|
13
|
+
# job = Doable::Job.plan do |j|
|
14
|
+
# j.before { log "Starting my awesome job" }
|
15
|
+
# j.step { # do some stuff here }
|
16
|
+
# j.attempt { # try to do some other stuff here }
|
17
|
+
# j.after { log "Looks like we're all set" }
|
18
|
+
# end
|
11
19
|
def self.plan(&block)
|
12
20
|
self.new(&block)
|
13
21
|
end
|
14
|
-
|
22
|
+
|
23
|
+
# Yields itself to allow the syntax seen in the plan class method.
|
15
24
|
def initialize
|
16
25
|
@hooks = {}
|
17
26
|
@steps = []
|
@@ -58,7 +67,7 @@ module Doable
|
|
58
67
|
# WARNING! Exception handlers are __not__ used with these steps, as they never actually raise exceptions
|
59
68
|
# @param options [Hash]
|
60
69
|
# @param block [Proc]
|
61
|
-
# @return [Boolean]
|
70
|
+
# @return [Boolean] this will __always__ be true by the nature of "attempt"
|
62
71
|
def attempt(options = {}, &block)
|
63
72
|
@steps << Step.new(self, options) do
|
64
73
|
begin
|
@@ -113,6 +122,7 @@ module Doable
|
|
113
122
|
|
114
123
|
# This triggers a block associated with a hook
|
115
124
|
# @param hook [Symbol] Hook to trigger
|
125
|
+
# @return [Boolean] returns true no exceptions are encounter during enumeration of hook steps.
|
116
126
|
def trigger(hook)
|
117
127
|
@hooks[hook].each_with_index do |step, index|
|
118
128
|
begin
|
@@ -151,6 +161,7 @@ module Doable
|
|
151
161
|
end
|
152
162
|
end # begin()
|
153
163
|
end if @hooks[hook] # each_with_index()
|
164
|
+
return true
|
154
165
|
end # trigger()
|
155
166
|
|
156
167
|
# Here we actually trigger the execution of a Job
|
@@ -221,4 +232,4 @@ module Doable
|
|
221
232
|
log "All Job steps completed successfully!", :success # This should only happen if everything goes well
|
222
233
|
end # run()
|
223
234
|
end
|
224
|
-
end
|
235
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: doable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Gnagy
|
8
|
+
- Tim Earle
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2015-
|
12
|
+
date: 2015-02-02 00:00:00.000000000 Z
|
12
13
|
dependencies: []
|
13
14
|
description: A framework for automating tasks with ease
|
14
15
|
email: jonathan.gnagy@gmail.com
|
@@ -20,8 +21,10 @@ files:
|
|
20
21
|
- README.md
|
21
22
|
- lib/doable.rb
|
22
23
|
- lib/doable/exceptions/framework.rb
|
24
|
+
- lib/doable/exceptions/linux.rb
|
23
25
|
- lib/doable/exceptions/os.rb
|
24
26
|
- lib/doable/helpers/framework.rb
|
27
|
+
- lib/doable/helpers/linux.rb
|
25
28
|
- lib/doable/helpers/logging.rb
|
26
29
|
- lib/doable/helpers/os.rb
|
27
30
|
- lib/doable/helpers/password.rb
|