minicron 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.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/README.md +187 -0
  4. data/Rakefile +17 -0
  5. data/bin/minicron +26 -0
  6. data/lib/minicron.rb +179 -0
  7. data/lib/minicron/alert.rb +115 -0
  8. data/lib/minicron/alert/email.rb +50 -0
  9. data/lib/minicron/alert/pagerduty.rb +39 -0
  10. data/lib/minicron/alert/sms.rb +47 -0
  11. data/lib/minicron/cli.rb +367 -0
  12. data/lib/minicron/constants.rb +7 -0
  13. data/lib/minicron/cron.rb +192 -0
  14. data/lib/minicron/hub/app.rb +132 -0
  15. data/lib/minicron/hub/assets/app/application.js +151 -0
  16. data/lib/minicron/hub/assets/app/components/schedules.js +280 -0
  17. data/lib/minicron/hub/assets/app/controllers/executions.js +35 -0
  18. data/lib/minicron/hub/assets/app/controllers/hosts.js +129 -0
  19. data/lib/minicron/hub/assets/app/controllers/jobs.js +109 -0
  20. data/lib/minicron/hub/assets/app/controllers/schedules.js +80 -0
  21. data/lib/minicron/hub/assets/app/helpers.js +22 -0
  22. data/lib/minicron/hub/assets/app/models/execution.js +13 -0
  23. data/lib/minicron/hub/assets/app/models/host.js +15 -0
  24. data/lib/minicron/hub/assets/app/models/job.js +15 -0
  25. data/lib/minicron/hub/assets/app/models/job_execution_output.js +11 -0
  26. data/lib/minicron/hub/assets/app/models/schedule.js +32 -0
  27. data/lib/minicron/hub/assets/app/router.js +31 -0
  28. data/lib/minicron/hub/assets/app/routes/executions.js +36 -0
  29. data/lib/minicron/hub/assets/app/routes/hosts.js +42 -0
  30. data/lib/minicron/hub/assets/app/routes/index.js +9 -0
  31. data/lib/minicron/hub/assets/app/routes/jobs.js +52 -0
  32. data/lib/minicron/hub/assets/app/routes/schedules.js +37 -0
  33. data/lib/minicron/hub/assets/css/bootswatch.min.css +9 -0
  34. data/lib/minicron/hub/assets/css/main.scss +323 -0
  35. data/lib/minicron/hub/assets/fonts/glyphicons-halflings-regular.eot +0 -0
  36. data/lib/minicron/hub/assets/fonts/glyphicons-halflings-regular.svg +229 -0
  37. data/lib/minicron/hub/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
  38. data/lib/minicron/hub/assets/fonts/glyphicons-halflings-regular.woff +0 -0
  39. data/lib/minicron/hub/assets/fonts/lato-bold-700.woff +0 -0
  40. data/lib/minicron/hub/assets/fonts/lato-italic-400.woff +0 -0
  41. data/lib/minicron/hub/assets/fonts/lato-regular-400.woff +0 -0
  42. data/lib/minicron/hub/assets/js/ansi_up-1.1.1.min.js +6 -0
  43. data/lib/minicron/hub/assets/js/auth/ember-auth-9.0.7.min.js +2 -0
  44. data/lib/minicron/hub/assets/js/auth/ember-auth-request-jquery-1.0.3.min.js +1 -0
  45. data/lib/minicron/hub/assets/js/bootstrap-3.1.1.min.js +6 -0
  46. data/lib/minicron/hub/assets/js/ember-1.4.1.min.js +18 -0
  47. data/lib/minicron/hub/assets/js/ember-data-1.0.0-beta.7.f87cba88.min.js +10 -0
  48. data/lib/minicron/hub/assets/js/faye-browser-1.0.1.min.js +2 -0
  49. data/lib/minicron/hub/assets/js/handlebars-1.3.0.min.js +29 -0
  50. data/lib/minicron/hub/assets/js/jquery-2.1.0.min.js +4 -0
  51. data/lib/minicron/hub/assets/js/moment-2.5.1.min.js +7 -0
  52. data/lib/minicron/hub/controllers/api/executions.rb +34 -0
  53. data/lib/minicron/hub/controllers/api/hosts.rb +150 -0
  54. data/lib/minicron/hub/controllers/api/job_execution_outputs.rb +30 -0
  55. data/lib/minicron/hub/controllers/api/jobs.rb +118 -0
  56. data/lib/minicron/hub/controllers/api/schedule.rb +184 -0
  57. data/lib/minicron/hub/controllers/index.rb +5 -0
  58. data/lib/minicron/hub/db/schema.rb +98 -0
  59. data/lib/minicron/hub/db/schema.sql +158 -0
  60. data/lib/minicron/hub/models/alert.rb +7 -0
  61. data/lib/minicron/hub/models/execution.rb +8 -0
  62. data/lib/minicron/hub/models/host.rb +7 -0
  63. data/lib/minicron/hub/models/job.rb +18 -0
  64. data/lib/minicron/hub/models/job_execution_output.rb +7 -0
  65. data/lib/minicron/hub/models/schedule.rb +25 -0
  66. data/lib/minicron/hub/serializers/execution.rb +75 -0
  67. data/lib/minicron/hub/serializers/host.rb +57 -0
  68. data/lib/minicron/hub/serializers/job.rb +104 -0
  69. data/lib/minicron/hub/serializers/job_execution_output.rb +48 -0
  70. data/lib/minicron/hub/serializers/schedule.rb +68 -0
  71. data/lib/minicron/hub/views/handlebars/application.erb +51 -0
  72. data/lib/minicron/hub/views/handlebars/errors.erb +29 -0
  73. data/lib/minicron/hub/views/handlebars/executions.erb +79 -0
  74. data/lib/minicron/hub/views/handlebars/hosts.erb +205 -0
  75. data/lib/minicron/hub/views/handlebars/jobs.erb +203 -0
  76. data/lib/minicron/hub/views/handlebars/loading.erb +3 -0
  77. data/lib/minicron/hub/views/handlebars/schedules.erb +354 -0
  78. data/lib/minicron/hub/views/index.erb +7 -0
  79. data/lib/minicron/hub/views/layouts/app.erb +15 -0
  80. data/lib/minicron/monitor.rb +116 -0
  81. data/lib/minicron/transport.rb +15 -0
  82. data/lib/minicron/transport/client.rb +80 -0
  83. data/lib/minicron/transport/faye/client.rb +103 -0
  84. data/lib/minicron/transport/faye/extensions/job_handler.rb +184 -0
  85. data/lib/minicron/transport/faye/server.rb +58 -0
  86. data/lib/minicron/transport/server.rb +62 -0
  87. data/lib/minicron/transport/ssh.rb +51 -0
  88. data/spec/invalid_config.toml +2 -0
  89. data/spec/minicron/cli_spec.rb +154 -0
  90. data/spec/minicron/transport/client_spec.rb +8 -0
  91. data/spec/minicron/transport/faye/client_spec.rb +53 -0
  92. data/spec/minicron/transport/server_spec.rb +70 -0
  93. data/spec/minicron/transport_spec.rb +13 -0
  94. data/spec/minicron_spec.rb +133 -0
  95. data/spec/spec_helper.rb +33 -0
  96. data/spec/valid_config.toml +48 -0
  97. metadata +577 -0
@@ -0,0 +1,50 @@
1
+ require 'mail'
2
+
3
+ module Minicron
4
+ class Email
5
+ # Configure the mail client
6
+ def initialize
7
+ Mail.defaults do
8
+ delivery_method(
9
+ :smtp,
10
+ :address => Minicron.config['alerts']['email']['smtp']['address'],
11
+ :port => Minicron.config['alerts']['email']['smtp']['port']
12
+ )
13
+ end
14
+ end
15
+ # Return the message for an alert
16
+ #
17
+ # @option options [Minicron::Hub::Job] job a job instance
18
+ # @option options [String] kind 'fail' or 'miss'
19
+ # @option options [Integer, nil] schedule_id only applies to 'miss' alerts
20
+ # @option options [Integer, nil] execution_id only used by 'fail' alerts
21
+ # @option options [Integer] job_id used to look up the job name for the alert message
22
+ # @option options [Time] expected_at when the schedule was expected to execute
23
+ # @option options [String] medium the medium to send the alert via
24
+ def get_message(options = {})
25
+ case options[:kind]
26
+ when 'miss'
27
+ "Job ##{options[:job_id]} '#{options[:job].name}' failed to execute at its expected time: #{options[:expected_at]}."
28
+ when 'fail'
29
+ "Execution ##{options[:execution_id]} of Job ##{options[:job_id]} '#{options[:job].name}' failed."
30
+ else
31
+ raise Exception, "The kind '#{options[:kind]} is not supported!"
32
+ end
33
+ end
34
+
35
+ # Send an email alert
36
+ #
37
+ # @param from [String]
38
+ # @param to [String]
39
+ # @param subject [String]
40
+ # @param message [String]
41
+ def send(from, to, subject, message)
42
+ Mail.deliver do
43
+ to to
44
+ from from
45
+ subject subject
46
+ body message
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,39 @@
1
+ require 'pagerduty'
2
+
3
+ module Minicron
4
+ class PagerDuty
5
+ # Used to set up on the pagerduty client
6
+ def initialize
7
+ # Get an instance of the Pagerduty client
8
+ @client = ::Pagerduty.new(Minicron.config['alerts']['pagerduty']['service_key'])
9
+ end
10
+
11
+ # Return the message for an alert
12
+ #
13
+ # @option options [Minicron::Hub::Job] job a job instance
14
+ # @option options [String] kind 'fail' or 'miss'
15
+ # @option options [Integer, nil] schedule_id only applies to 'miss' alerts
16
+ # @option options [Integer, nil] execution_id only used by 'fail' alerts
17
+ # @option options [Integer] job_id used to look up the job name for the alert message
18
+ # @option options [Time] expected_at when the schedule was expected to execute
19
+ # @option options [String] medium the medium to send the alert via
20
+ def get_message(options = {})
21
+ case options[:kind]
22
+ when 'miss'
23
+ "Job ##{options[:job_id]} failed to execute at its expected time - #{options[:expected_at]}"
24
+ when 'fail'
25
+ "Execution ##{options[:execution_id]} of Job ##{options[:job_id]} failed"
26
+ else
27
+ raise Exception, "The kind '#{options[:kind]} is not supported!"
28
+ end
29
+ end
30
+
31
+ # Send a pager duty alert
32
+ #
33
+ # @param title [String]
34
+ # @param message [String]
35
+ def send(title, message)
36
+ @client.trigger(title, { :message => message })
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,47 @@
1
+ require 'twilio-ruby'
2
+
3
+ module Minicron
4
+ class SMS
5
+ # Used to set up on the twilio client
6
+ def initialize
7
+ # Get an instance of the twilio client
8
+ @client = Twilio::REST::Client.new(
9
+ Minicron.config['alerts']['sms']['twilio']['account_sid'],
10
+ Minicron.config['alerts']['sms']['twilio']['auth_token']
11
+ )
12
+ end
13
+
14
+ # Return the message for an alert
15
+ #
16
+ # @option options [Minicron::Hub::Job] job a job instance
17
+ # @option options [String] kind 'fail' or 'miss'
18
+ # @option options [Integer, nil] schedule_id only applies to 'miss' alerts
19
+ # @option options [Integer, nil] execution_id only used by 'fail' alerts
20
+ # @option options [Integer] job_id used to look up the job name for the alert message
21
+ # @option options [Time] expected_at when the schedule was expected to execute
22
+ # @option options [String] medium the medium to send the alert via
23
+ def get_message(options = {})
24
+ case options[:kind]
25
+ when 'miss'
26
+ "minicron alert - job missed!\nJob ##{options[:job_id]} failed to execute at its expected time: #{options[:expected_at]}"
27
+ when 'fail'
28
+ "minicron alert - job failed!\nExecution ##{options[:execution_id]} of Job ##{options[:job_id]} failed"
29
+ else
30
+ raise Exception, "The kind '#{options[:kind]} is not supported!"
31
+ end
32
+ end
33
+
34
+ # Send an sms alert
35
+ #
36
+ # @param from [String]
37
+ # @param to [String]
38
+ # @param message [String]
39
+ def send(from, to, message)
40
+ @client.account.messages.create(
41
+ :from => from,
42
+ :to => to,
43
+ :body => message
44
+ )
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,367 @@
1
+ require 'pty'
2
+ require 'English'
3
+ require 'rainbow/ext/string'
4
+ require 'commander'
5
+ require 'minicron/constants'
6
+ require 'minicron/transport'
7
+ require 'minicron/transport/client'
8
+ require 'minicron/transport/server'
9
+ require 'minicron/monitor'
10
+
11
+ include Commander::UI
12
+
13
+ module Minicron
14
+ class CLI
15
+ # Function to the parse the config of the options passed to commands
16
+ #
17
+ # @param opts [Hash] The Commander provided options hash
18
+ def parse_config(opts)
19
+ # Parse the --config file options if it was passed
20
+ Minicron.parse_file_config(opts.config)
21
+
22
+ # Parse the cli options
23
+ Minicron.parse_cli_config(
24
+ 'global' => {
25
+ 'verbose' => opts.verbose,
26
+ 'trace' => opts.trace
27
+ },
28
+ 'cli' => {
29
+ 'mode' => opts.mode,
30
+ 'dry_run' => opts.dry_run
31
+ },
32
+ 'server' => {
33
+ 'host' => opts.host,
34
+ 'port' => opts.port,
35
+ 'path' => opts.path
36
+ }
37
+ )
38
+ end
39
+
40
+ # Used as a helper for yielding command output, returns it in a structured hash
41
+ #
42
+ # @param type [Symbol] The type of command output, currently one of :status, :command and :verbose
43
+ # @param output [String]
44
+ # @return [Hash]
45
+ def structured(type, output)
46
+ { :type => type, :output => output }
47
+ end
48
+
49
+ # Sets up an instance of commander and runs it based on the argv param
50
+ #
51
+ # @param argv [Array] an array of arguments passed to the cli
52
+ # @yieldparam output [String] output from the cli
53
+ # @raise [ArgumentError] if no arguments are passed to the run cli command
54
+ # i.e when the argv param is ['run']. A second option (the command to execute)
55
+ # should be present in the array
56
+ def run(argv)
57
+ # replace ARGV with the contents of argv to aid testability
58
+ ARGV.replace(argv)
59
+
60
+ # Get an instance of commander
61
+ @cli = Commander::Runner.new
62
+
63
+ # Set some default otions on it
64
+ setup_cli
65
+
66
+ # Add the run command to the cli
67
+ add_run_cli_command { |output| yield output }
68
+
69
+ # Add the server command to the cli
70
+ add_server_cli_command
71
+
72
+ # Add the db command to the cli
73
+ add_db_cli_command
74
+
75
+ # And off we go!
76
+ @cli.run!
77
+ end
78
+
79
+ # Executes a command in a pseudo terminal and yields the output
80
+ #
81
+ # @param command [String] the command to execute e.g 'ls'
82
+ # @option options [String] mode ('line') the method to yield the
83
+ # command output. Either 'line' by line or 'char' by char.
84
+ # @option options [Boolean] verbose whether or not to output extra
85
+ # information for debugging purposes.
86
+ # @yieldparam output [String] output from the command execution
87
+ def run_command(command, options = {})
88
+ # Default the options
89
+ options[:mode] ||= 'line'
90
+ options[:verbose] ||= false
91
+
92
+ # Record the start time of the command
93
+ start = Time.now.utc
94
+ subtract_total = 0
95
+
96
+ # yield the start time
97
+ subtract = Time.now.utc
98
+ yield structured :status, "START #{start.strftime("%Y-%m-%d %H:%M:%S")}"
99
+ subtract_total += Time.now.utc - subtract
100
+
101
+ # Spawn a process to run the command
102
+ begin
103
+ PTY.spawn(command) do |stdout, stdin, pid|
104
+
105
+ # Output some debug info
106
+ if options[:verbose]
107
+ subtract = Time.now.utc
108
+ yield structured :verbose, '[minicron]'.colour(:magenta)
109
+ yield structured :verbose, ' started running '.colour(:blue) + "`#{command}`".colour(:yellow) + " at #{start}\n\n".colour(:blue)
110
+ subtract_total += Time.now.utc - subtract
111
+ end
112
+
113
+ begin
114
+ # Loop until data is no longer being sent to stdout
115
+ until stdout.eof?
116
+ # One character at a time or one line at a time?
117
+ output = options[:mode] == 'char' ? stdout.read(1) : stdout.readline
118
+
119
+ subtract = Time.now.utc
120
+ yield structured :command, output
121
+ subtract_total += Time.now.utc - subtract
122
+ end
123
+ # See https://github.com/ruby/ruby/blob/57fb2199059cb55b632d093c2e64c8a3c60acfbb/ext/pty/pty.c#L519
124
+ rescue Errno::EIO
125
+ ensure
126
+ # Force waiting for the process to finish so we can get the exit status
127
+ Process.wait pid
128
+ end
129
+ end
130
+ rescue Errno::ENOENT
131
+ exit_status = 1
132
+
133
+ fail Exception, "Running the command `#{command}` failed, are you sure it exists?"
134
+ ensure
135
+ # Record the time the command finished
136
+ finish = Time.now.utc - subtract_total
137
+ exit_status = $CHILD_STATUS.exitstatus ? $CHILD_STATUS.exitstatus : nil
138
+
139
+ # yield the finish time and exit status
140
+ yield structured :status, "FINISH #{finish.strftime("%Y-%m-%d %H:%M:%S")}"
141
+ yield structured :status, "EXIT #{exit_status}"
142
+
143
+ # Output some debug info
144
+ if options[:verbose]
145
+ yield structured :verbose, "\n" + "[minicron]".colour(:magenta)
146
+ yield structured :verbose, ' finished running '.colour(:blue) + "`#{command}`".colour(:yellow) + " at #{start}\n".colour(:blue)
147
+ yield structured :verbose, '[minicron]'.colour(:magenta)
148
+ yield structured :verbose, ' running '.colour(:blue) + "`#{command}`".colour(:yellow) + " took #{finish - start}s\n".colour(:blue)
149
+ yield structured :verbose, '[minicron]'.colour(:magenta)
150
+ yield structured :verbose, " `#{command}`".colour(:yellow) + ' finished with an exit status of '.colour(:blue)
151
+ yield structured :verbose, exit_status == 0 ? "#{exit_status}\n".colour(:green) : "#{exit_status}\n".colour(:red)
152
+ end
153
+ end
154
+ end
155
+
156
+ # Whether or not coloured output of the rainbox gem is enabled, this is
157
+ # enabled by default
158
+ #
159
+ # @return [Boolean] whether rainbow is enabled or not
160
+ def coloured_output?
161
+ Rainbow.enabled
162
+ end
163
+
164
+ # Enable coloured terminal output from the rainbow gem, this is enabled
165
+ # by default
166
+ #
167
+ # @return [Boolean] whether rainbow is enabled or not
168
+ def enable_coloured_output!
169
+ Rainbow.enabled = true
170
+ end
171
+
172
+ # Disable coloured terminal output from the rainbow gem, this is enabled
173
+ # by default
174
+ #
175
+ # @return [Boolean] whether rainbow is enabled or not
176
+ def disable_coloured_output!
177
+ Rainbow.enabled = false
178
+ end
179
+
180
+ private
181
+
182
+ # Sets the basic options for a commander cli instance
183
+ def setup_cli
184
+ # basic information for the help menu
185
+ @cli.program :name, 'minicron'
186
+ @cli.program :help, 'Author', 'James White <dev.jameswhite+minicron@gmail.com>'
187
+ @cli.program :help, 'License', 'GPL v3'
188
+ @cli.program :version, Minicron::VERSION
189
+ @cli.program :description, 'cli for minicron; a system a to manage and monitor cron jobs'
190
+
191
+ # Set the default command to run
192
+ @cli.default_command :help
193
+
194
+ # Check if --trace was pased or not
195
+ if @cli.instance_variable_get(:@args).include? '--trace'
196
+ Minicron.config['global']['trace'] = true
197
+ end
198
+
199
+ # Add a global option for verbose mode
200
+ @cli.global_option '--verbose', "Turn on verbose mode. Default: #{Minicron.config['cli']['verbose']}" do
201
+ Minicron.config['global']['verbose'] = true
202
+ end
203
+
204
+ # Add a global option for passing the path to a config file
205
+ @cli.global_option '--config FILE', 'Set the config file to use'
206
+ end
207
+
208
+ # Setup a job by sending the SETUP command to the server
209
+ #
210
+ # @param command [String] the job command
211
+ # @param faye a faye client instance
212
+ # @return [Hash] the job_id and execution_id
213
+ def setup_job(command, faye)
214
+ # Get the fully qualified domain name of the currnet host
215
+ fqdn = `hostname -f`.strip
216
+
217
+ # Get the short hostname of the current host
218
+ hostname = `hostname -s`.strip
219
+
220
+ # Get the md5 hash for the job
221
+ job_hash = Minicron::Transport.get_job_hash(command, fqdn)
222
+
223
+ # Fire up eventmachine
224
+ faye.ensure_em_running
225
+
226
+ # Setup the job on the server
227
+ ids = faye.setup(job_hash, command, fqdn, hostname)
228
+
229
+ # Wait until we get the execution id
230
+ faye.ensure_delivery
231
+
232
+ # Return the ids
233
+ ids
234
+ end
235
+
236
+ # Add the `minicron db` command
237
+ def add_db_cli_command
238
+ @cli.command :db do |c|
239
+ c.syntax = 'minicron db [setup|dump]'
240
+ c.description = 'Loads or dumps the minicron database schema.'
241
+
242
+ c.action do |args, opts|
243
+ # Check that exactly one argument has been passed
244
+ if args.length != 1
245
+ fail ArgumentError, 'A valid command to run is required! See `minicron help db`'
246
+ end
247
+
248
+ # Parse the file and cli config options
249
+ parse_config(opts)
250
+
251
+ # These are inlined as we only need them in this use case
252
+ require 'rake'
253
+ require 'minicron/hub/app'
254
+ require 'sinatra/activerecord/rake'
255
+
256
+ # Setup the db
257
+ Minicron::Hub::App.setup_db
258
+
259
+ # Tell activerecord where the db folder is, it assumes it is in db/
260
+ Sinatra::ActiveRecordTasks.db_dir = 'lib/minicron/hub/db'
261
+
262
+ # Adjust the task name
263
+ task = args.first == 'setup' ? 'load' : args.first
264
+
265
+ # Run the task
266
+ Rake.application['db:schema:' + task].invoke
267
+ end
268
+ end
269
+ end
270
+
271
+ # Add the `minicron server` command
272
+ def add_server_cli_command
273
+ @cli.command :server do |c|
274
+ c.syntax = 'minicron server'
275
+ c.description = 'Starts the minicron server.'
276
+ c.option '--host STRING', String, "The host for the server to listen on. Default: #{Minicron.config['server']['host']}"
277
+ c.option '--port STRING', Integer, "How port for the server to listed on. Default: #{Minicron.config['server']['port']}"
278
+ c.option '--path STRING', String, "The path on the host. Default: #{Minicron.config['server']['path']}"
279
+
280
+ c.action do |args, opts|
281
+ # Parse the file and @cli config options
282
+ parse_config(opts)
283
+
284
+ # Run the execution monitor (this runs in a separate thread)
285
+ monitor = Minicron::Monitor.new
286
+ monitor.start!
287
+
288
+ # Start the server!
289
+ server = Minicron::Transport::Server.new
290
+ server.start!(
291
+ Minicron.config['server']['host'],
292
+ Minicron.config['server']['port'],
293
+ Minicron.config['server']['path']
294
+ )
295
+ end
296
+ end
297
+ end
298
+
299
+ # Add the `minicron run [command]` command
300
+ # @yieldparam output [String] output from the cli
301
+ def add_run_cli_command
302
+ # Add the run command to the cli
303
+ @cli.command :run do |c|
304
+ c.syntax = "minicron run 'command -option value'"
305
+ c.description = 'Runs the command passed as an argument.'
306
+ c.option '--mode STRING', String, "How to capture the command output, each 'line' or each 'char'? Default: #{Minicron.config['cli']['mode']}"
307
+ c.option '--dry-run', "Run the command without sending the output to the server. Default: #{Minicron.config['cli']['dry_run']}"
308
+
309
+ c.action do |args, opts|
310
+ # Check that exactly one argument has been passed
311
+ if args.length != 1
312
+ fail ArgumentError, 'A valid command to run is required! See `minicron help run`'
313
+ end
314
+
315
+ # Parse the file and cli config options
316
+ parse_config(opts)
317
+
318
+ begin
319
+ # Set up the job and get the job and execution ids
320
+ unless Minicron.config['cli']['dry_run']
321
+ # Get a faye instance so we can send data about the job
322
+ faye = Minicron::Transport::Client.new(
323
+ Minicron.config['client']['scheme'],
324
+ Minicron.config['client']['host'],
325
+ Minicron.config['client']['port'],
326
+ Minicron.config['client']['path']
327
+ )
328
+
329
+ # Set up the job and get the jexecution and job ids back from the server
330
+ ids = setup_job(args.first, faye)
331
+ end
332
+
333
+ # Execute the command and yield the output
334
+ run_command(args.first, :mode => Minicron.config['cli']['mode'], :verbose => Minicron.config['global']['verbose']) do |output|
335
+ # We need to handle the yielded output differently based on it's type
336
+ case output[:type]
337
+ when :status
338
+ unless Minicron.config['cli']['dry_run']
339
+ faye.send(:job_id => ids[:job_id], :execution_id => ids[:execution_id], :type => :status, :message => output[:output])
340
+ end
341
+ when :command
342
+ unless Minicron.config['cli']['dry_run']
343
+ faye.send(:job_id => ids[:job_id], :execution_id => ids[:execution_id], :type => :output, :message => output[:output])
344
+ end
345
+ end
346
+
347
+ yield output[:output] unless output[:type] == :status
348
+ end
349
+ rescue Exception => e
350
+ # Send the exception message to the server and yield it
351
+ unless Minicron.config['cli']['dry_run']
352
+ faye.send(:job_id => ids[:job_id], :execution_id => ids[:execution_id], :type => :output, :message => e.message)
353
+ end
354
+
355
+ fail e
356
+ ensure
357
+ # Ensure that all messages are delivered and that we
358
+ unless Minicron.config['cli']['dry_run']
359
+ faye.ensure_delivery
360
+ faye.tidy_up
361
+ end
362
+ end
363
+ end
364
+ end
365
+ end
366
+ end
367
+ end