doable 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|