minicron 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aa2c40fa9887bb6c06b46153ba397a13806ed4f9
4
- data.tar.gz: e1fc6d9b267c3e0a21727328f25922ecffeae9e4
3
+ metadata.gz: 9dd39723811b197138d5655e871e4c07fb49d4d4
4
+ data.tar.gz: 30b855c523a3ce04c9aaa83bc0a348b950e947c4
5
5
  SHA512:
6
- metadata.gz: 3f8fa7cdcd2a80623bbf1a0c3f266e575f9c3da024325579e96b65a523158212ac879ced4cffa834a11f150c14c3bfce48d921b90004ec380a5629779af89e14
7
- data.tar.gz: 3e48387f403abbf3b34d1efd85bb4f3d33aec113a20abfce5336c6e801794d9a49a6f0e00e7844af12e4aa87a298de04632a6a2bffaf13b8686519ae790e34b7
6
+ metadata.gz: 5cb855f69d4a2727a5f837df5a96f9c1ff68a85f74150ca2f1c9497729f733af92517e7eb72fbf65457b0483205055c0f2ec9d9b596751f468da79449e2ae13a
7
+ data.tar.gz: 3181ea25877f42863c5317d39bb8a6998d563b5d55f75f6d06c0f478c140c3c76114e342edc30fd8d49c68e40c56abb7c1aa91318088eb330ede9b94ef116c79
data/README.md CHANGED
@@ -84,7 +84,7 @@ but I encourage you to give it a try in a non critical environment and help me t
84
84
 
85
85
  2. On some distributions you may need to install the ````ruby-dev```` and ````build-essential```` packages
86
86
 
87
- 3. To install the latest release (currently 0.2) you can ````gem install minicron````, depending on your ruby setup
87
+ 3. To install the latest release (currently 0.3) you can ````gem install minicron````, depending on your ruby setup
88
88
  you may need to run this with ````sudo````
89
89
 
90
90
  4. Set your database configuration options in ````/etc/minicron.toml````, you can use the [default.config.toml](https://github.com/jamesrwhite/minicron/blob/master/default.config.toml) as a guide on what options are configurable
@@ -144,7 +144,7 @@ by default it will bind to port 9292 on the host 127.0.0.1 but this can be confi
144
144
  arguments ````--host```` ````--port```` and ````--path```` or in the config file.
145
145
 
146
146
  By default the server will run as a daemon with its process id stored in ````/tmp/minicron.pid````
147
- you can also use the ````stop```` ````restart```` and ````status```` commands to control the server.
147
+ you can also use the ````stop```` and ````status```` commands to control the server.
148
148
 
149
149
  To run the server in debug mode, i.e not as a daemon so you can see its output you can pass the ````--debug````
150
150
  option.
@@ -1,11 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
+ require 'insidious'
2
3
  require 'minicron'
4
+ require 'minicron/cli'
5
+ require 'minicron/transport/server'
3
6
 
4
7
  begin
5
8
  # Capture any output from STDERR so we can handle it how we want to
6
9
  Minicron.capture_output(:type => :stderr) do
7
10
  # Run the CLI and pass it all arguments passed to us
8
- Minicron::CLI.new.run(ARGV) do |output|
11
+ Minicron::CLI.run(ARGV) do |output|
9
12
  print output
10
13
  STDOUT.flush
11
14
  end
@@ -13,14 +16,26 @@ begin
13
16
  # Handle ctrl-c and other nasty interruptions
14
17
  rescue Interrupt, SignalException
15
18
  puts "\nExiting.."
19
+
20
+ # Stop the daemon if it's running i.e tidy up the pid file
21
+ insidious = Insidious.new(:pid_file => '/tmp/minicron.pid')
22
+
23
+ if insidious.running?
24
+ insidious.stop!
25
+ end
16
26
  # Accept failure
17
27
  rescue Exception => e
18
28
  $stderr.write("#{e.message}\n")
19
29
 
20
- if Minicron.config['cli']['trace']
30
+ if Minicron.config['trace']
21
31
  puts
22
32
  fail e
23
33
  end
24
34
 
25
35
  exit(1)
36
+ ensure
37
+ # Shut down the server if it's running
38
+ if Minicron::Transport::Server.running?
39
+ Minicron::Transport::Server.stop!
40
+ end
26
41
  end
@@ -1,17 +1,14 @@
1
1
  require 'stringio'
2
2
  require 'toml'
3
3
  require 'sshkey'
4
- require 'minicron/cli'
5
4
  require 'minicron/constants'
6
5
 
7
6
  # @author James White <dev.jameswhite+minicron@gmail.com>
8
7
  module Minicron
9
8
  # Default configuration, this can be overriden
10
9
  @config = {
11
- 'global' => {
12
- 'verbose' => false,
13
- 'trace' => false
14
- },
10
+ 'verbose' => false,
11
+ 'trace' => false,
15
12
  'client' => {
16
13
  'scheme' => 'http',
17
14
  'host' => '127.0.0.1',
@@ -77,22 +74,24 @@ module Minicron
77
74
  raise Exception, "Unable to the load the file '#{file_path}', are you sure it exists?"
78
75
  end
79
76
  rescue Errno::EACCES
80
- fail Exception, "Unable to the readthe file '#{file_path}', check it has the right permissions."
77
+ fail Exception, "Unable to the read the file '#{file_path}', check it has the right permissions."
81
78
  rescue TOML::ParseError
82
79
  fail Exception, "An error occured parsing the config file '#{file_path}', please check it uses valid TOML syntax."
83
80
  end
84
81
  end
85
82
 
86
- # Parses the config options from the cli
87
- # @option options [Hash] global global options
88
- # @option options [Hash] server server options
89
- # @option options [Hash] cli cli options
90
- def self.parse_cli_config(options = {})
91
- options.each do |type, _|
92
- options[type].each do |key, value|
93
- if value
94
- @config[type][key] = value
83
+ # Parses the config options from the given hash that matches the expected
84
+ # config format in Minicron.config
85
+ def self.parse_config_hash(options = {})
86
+ options.each do |key, value|
87
+ if options[key].respond_to?(:each)
88
+ options[key].each do |k, v|
89
+ if !v.nil?
90
+ @config[key][k] = v
91
+ end
95
92
  end
93
+ else
94
+ @config[key] = value
96
95
  end
97
96
  end
98
97
  end
@@ -143,21 +142,6 @@ module Minicron
143
142
  end
144
143
  end
145
144
 
146
- # Sanitize a filename - taken from http://guides.rubyonrails.org/security.html
147
- #
148
- # @param filename [String]
149
- # @return [String]
150
- def self.sanitize_filename(filename)
151
- filename.strip.tap do |name|
152
- name.sub!(/\A.*(\\|\/)/, '')
153
- # Finally, replace all non alphanumeric, underscore
154
- # or periods with underscore
155
- name.gsub!(/[^\w\.\-]/, '_')
156
- end
157
-
158
- filename
159
- end
160
-
161
145
  # Used to generate SSH keys for hosts but is completely generic
162
146
  #
163
147
  # @param type [String] the thing that is using the key, this is just here
@@ -168,8 +152,8 @@ module Minicron
168
152
  key = SSHKey.generate(:comment => "minicron public key for #{name}")
169
153
 
170
154
  # Set the locations to save the public key private key pair
171
- private_key_path = sanitize_filename(File.expand_path("~/.ssh/minicron_#{type}_#{id}_rsa"))
172
- public_key_path = sanitize_filename(File.expand_path("~/.ssh/minicron_#{type}_#{id}_rsa.pub"))
155
+ private_key_path = File.expand_path("~/.ssh/minicron_#{type}_#{id}_rsa")
156
+ public_key_path = File.expand_path("~/.ssh/minicron_#{type}_#{id}_rsa.pub")
173
157
 
174
158
  # Save the public key private key pair
175
159
  File.write(private_key_path, key.private_key)
@@ -181,4 +165,18 @@ module Minicron
181
165
 
182
166
  key
183
167
  end
168
+
169
+ # Get the system fully qualified domain name
170
+ #
171
+ # @return [String]
172
+ def self.get_fqdn
173
+ `hostname -f`.strip
174
+ end
175
+
176
+ # Get the system short hostname
177
+ #
178
+ # @return [String]
179
+ def self.get_hostname
180
+ `hostname -s`.strip
181
+ end
184
182
  end
@@ -34,7 +34,7 @@ module Minicron
34
34
  # @param title [String]
35
35
  # @param message [String]
36
36
  def send(title, message)
37
- @client.trigger(title, :message => message)
37
+ @client.trigger(title, :message => message)
38
38
  end
39
39
  end
40
40
  end
@@ -2,8 +2,8 @@ require 'pty'
2
2
  require 'English'
3
3
  require 'rainbow/ext/string'
4
4
  require 'commander'
5
- require 'insidious'
6
5
  require 'minicron/constants'
6
+ require 'minicron/cli/commands'
7
7
  require 'minicron/transport'
8
8
  require 'minicron/transport/client'
9
9
  require 'minicron/transport/server'
@@ -14,20 +14,18 @@ include Commander::UI
14
14
  module Minicron
15
15
  # Handles the main CLI interaction of minicron
16
16
  # TODO: this class is probably too complicated and should be refactored a bit
17
- class CLI
17
+ module CLI
18
18
  # Function to the parse the config of the options passed to commands
19
19
  #
20
20
  # @param opts [Hash] The Commander provided options hash
21
- def parse_config(opts)
21
+ def self.parse_config(opts)
22
22
  # Parse the --config file options if it was passed
23
23
  Minicron.parse_file_config(opts.config)
24
24
 
25
25
  # Parse the cli options
26
- Minicron.parse_cli_config(
27
- 'global' => {
28
- 'verbose' => opts.verbose,
29
- 'trace' => opts.trace
30
- },
26
+ Minicron.parse_config_hash(
27
+ 'verbose' => opts.verbose,
28
+ 'trace' => opts.trace,
31
29
  'cli' => {
32
30
  'mode' => opts.mode,
33
31
  'dry_run' => opts.dry_run
@@ -46,7 +44,7 @@ module Minicron
46
44
  # @param type [Symbol] The type of command output, currently one of :status, :command and :verbose
47
45
  # @param output [String]
48
46
  # @return [Hash]
49
- def structured(type, output)
47
+ def self.structured(type, output)
50
48
  { :type => type, :output => output }
51
49
  end
52
50
 
@@ -57,7 +55,7 @@ module Minicron
57
55
  # @raise [ArgumentError] if no arguments are passed to the run cli command
58
56
  # i.e when the argv param is ['run']. A second option (the command to execute)
59
57
  # should be present in the array
60
- def run(argv)
58
+ def self.run(argv)
61
59
  # replace ARGV with the contents of argv to aid testability
62
60
  ARGV.replace(argv)
63
61
 
@@ -65,16 +63,16 @@ module Minicron
65
63
  @cli = Commander::Runner.new
66
64
 
67
65
  # Set some default otions on it
68
- setup_cli
66
+ setup
69
67
 
70
68
  # Add the run command to the cli
71
- add_run_cli_command { |output| yield output }
69
+ Minicron::CLI::Commands.add_run_cli_command(@cli) { |output| yield output }
72
70
 
73
71
  # Add the server command to the cli
74
- add_server_cli_command
72
+ Minicron::CLI::Commands.add_server_cli_command(@cli)
75
73
 
76
74
  # Add the db command to the cli
77
- add_db_cli_command
75
+ Minicron::CLI::Commands.add_db_cli_command(@cli)
78
76
 
79
77
  # And off we go!
80
78
  @cli.run!
@@ -88,7 +86,7 @@ module Minicron
88
86
  # @option options [Boolean] verbose whether or not to output extra
89
87
  # information for debugging purposes.
90
88
  # @yieldparam output [String] output from the command execution
91
- def run_command(command, options = {})
89
+ def self.run_command(command, options = {})
92
90
  # Default the options
93
91
  options[:mode] ||= 'line'
94
92
  options[:verbose] ||= false
@@ -159,7 +157,7 @@ module Minicron
159
157
  # enabled by default
160
158
  #
161
159
  # @return [Boolean] whether rainbow is enabled or not
162
- def coloured_output?
160
+ def self.coloured_output?
163
161
  Rainbow.enabled
164
162
  end
165
163
 
@@ -167,7 +165,7 @@ module Minicron
167
165
  # by default
168
166
  #
169
167
  # @return [Boolean] whether rainbow is enabled or not
170
- def enable_coloured_output!
168
+ def self.enable_coloured_output!
171
169
  Rainbow.enabled = true
172
170
  end
173
171
 
@@ -175,14 +173,14 @@ module Minicron
175
173
  # by default
176
174
  #
177
175
  # @return [Boolean] whether rainbow is enabled or not
178
- def disable_coloured_output!
176
+ def self.disable_coloured_output!
179
177
  Rainbow.enabled = false
180
178
  end
181
179
 
182
180
  private
183
181
 
184
182
  # Sets the basic options for a commander cli instance
185
- def setup_cli
183
+ def self.setup
186
184
  # basic information for the help menu
187
185
  @cli.program :name, 'minicron'
188
186
  @cli.program :help, 'Author', 'James White <dev.jameswhite+minicron@gmail.com>'
@@ -195,203 +193,16 @@ module Minicron
195
193
 
196
194
  # Check if --trace was pased or not
197
195
  if @cli.instance_variable_get(:@args).include? '--trace'
198
- Minicron.config['global']['trace'] = true
196
+ Minicron.config['trace'] = true
199
197
  end
200
198
 
201
199
  # Add a global option for verbose mode
202
200
  @cli.global_option '--verbose', "Turn on verbose mode. Default: #{Minicron.config['cli']['verbose']}" do
203
- Minicron.config['global']['verbose'] = true
201
+ Minicron.config['verbose'] = true
204
202
  end
205
203
 
206
204
  # Add a global option for passing the path to a config file
207
205
  @cli.global_option '--config FILE', 'Set the config file to use'
208
206
  end
209
-
210
- # Setup a job by sending the SETUP command to the server
211
- #
212
- # @param command [String] the job command
213
- # @param faye a faye client instance
214
- # @return [Hash] the job_id and execution_id
215
- def setup_job(command, faye)
216
- # Get the fully qualified domain name of the currnet host
217
- fqdn = `hostname -f`.strip
218
-
219
- # Get the short hostname of the current host
220
- hostname = `hostname -s`.strip
221
-
222
- # Get the md5 hash for the job
223
- job_hash = Minicron::Transport.get_job_hash(command, fqdn)
224
-
225
- # Fire up eventmachine
226
- faye.ensure_em_running
227
-
228
- # Setup the job on the server
229
- ids = faye.setup(job_hash, command, fqdn, hostname)
230
-
231
- # Wait until we get the execution id
232
- faye.ensure_delivery
233
-
234
- # Return the ids
235
- ids
236
- end
237
-
238
- # Start the server and monitor
239
- def start_server
240
- # Run the execution monitor (this runs in a separate thread)
241
- monitor = Minicron::Monitor.new
242
- monitor.start!
243
-
244
- # Start the server!
245
- server = Minicron::Transport::Server.new
246
- server.start!(
247
- Minicron.config['server']['host'],
248
- Minicron.config['server']['port'],
249
- Minicron.config['server']['path']
250
- )
251
- end
252
-
253
- # Add the `minicron db` command
254
- def add_db_cli_command
255
- @cli.command :db do |c|
256
- c.syntax = 'minicron db [setup]'
257
- c.description = 'Sets up the minicron database schema.'
258
-
259
- c.action do |args, opts|
260
- # Check that exactly one argument has been passed
261
- if args.length != 1
262
- fail ArgumentError, 'A valid command to run is required! See `minicron help db`'
263
- end
264
-
265
- # Parse the file and cli config options
266
- parse_config(opts)
267
-
268
- # These are inlined as we only need them in this use case
269
- require 'rake'
270
- require 'minicron/hub/app'
271
- require 'sinatra/activerecord/rake'
272
-
273
- # Setup the db
274
- Minicron::Hub::App.setup_db
275
-
276
- # Tell activerecord where the db folder is, it assumes it is in db/
277
- Sinatra::ActiveRecordTasks.db_dir = Minicron::HUB_PATH + '/db'
278
-
279
- # Adjust the task name
280
- task = args.first == 'setup' ? 'load' : args.first
281
-
282
- # Run the task
283
- Rake.application['db:schema:' + task].invoke
284
- end
285
- end
286
- end
287
-
288
- # Add the `minicron server` command
289
- def add_server_cli_command
290
- @cli.command :server do |c|
291
- c.syntax = 'minicron server [start|stop|restart|status]'
292
- c.description = 'Controls the minicron server.'
293
- c.option '--host STRING', String, "The host for the server to listen on. Default: #{Minicron.config['server']['host']}"
294
- c.option '--port STRING', Integer, "How port for the server to listed on. Default: #{Minicron.config['server']['port']}"
295
- c.option '--path STRING', String, "The path on the host. Default: #{Minicron.config['server']['path']}"
296
- c.option '--debug', "Enable debug mode. Default: #{Minicron.config['server']['debug']}"
297
-
298
- c.action do |args, opts|
299
- # Parse the file and @cli config options
300
- parse_config(opts)
301
-
302
- # If we get no arguments then default the action to start
303
- action = args.first.nil? ? 'start' : args.first
304
-
305
- # Get an instance of insidious and set the pid file
306
- insidious = Insidious.new(
307
- :pid_file => '/tmp/minicron.pid',
308
- :daemonize => Minicron.config['server']['debug'] == false
309
- )
310
-
311
- case action
312
- when 'start'
313
- insidious.start! { start_server }
314
- when 'stop'
315
- insidious.stop!
316
- when 'restart'
317
- insidious.restart! { start_server }
318
- when 'status'
319
- if insidious.running?
320
- puts 'minicron is running'
321
- else
322
- puts 'minicron is not running'
323
- end
324
- end
325
- end
326
- end
327
- end
328
-
329
- # Add the `minicron run [command]` command
330
- # @yieldparam output [String] output from the cli
331
- def add_run_cli_command
332
- # Add the run command to the cli
333
- @cli.command :run do |c|
334
- c.syntax = "minicron run 'command -option value'"
335
- c.description = 'Runs the command passed as an argument.'
336
- c.option '--mode STRING', String, "How to capture the command output, each 'line' or each 'char'? Default: #{Minicron.config['cli']['mode']}"
337
- c.option '--dry-run', "Run the command without sending the output to the server. Default: #{Minicron.config['cli']['dry_run']}"
338
-
339
- c.action do |args, opts|
340
- # Check that exactly one argument has been passed
341
- if args.length != 1
342
- fail ArgumentError, 'A valid command to run is required! See `minicron help run`'
343
- end
344
-
345
- # Parse the file and cli config options
346
- parse_config(opts)
347
-
348
- begin
349
- # Set up the job and get the job and execution ids
350
- unless Minicron.config['cli']['dry_run']
351
- # Get a faye instance so we can send data about the job
352
- faye = Minicron::Transport::Client.new(
353
- Minicron.config['client']['scheme'],
354
- Minicron.config['client']['host'],
355
- Minicron.config['client']['port'],
356
- Minicron.config['client']['path']
357
- )
358
-
359
- # Set up the job and get the jexecution and job ids back from the server
360
- ids = setup_job(args.first, faye)
361
- end
362
-
363
- # Execute the command and yield the output
364
- run_command(args.first, :mode => Minicron.config['cli']['mode'], :verbose => Minicron.config['global']['verbose']) do |output|
365
- # We need to handle the yielded output differently based on it's type
366
- case output[:type]
367
- when :status
368
- unless Minicron.config['cli']['dry_run']
369
- faye.send(:job_id => ids[:job_id], :execution_id => ids[:execution_id], :type => :status, :message => output[:output])
370
- end
371
- when :command
372
- unless Minicron.config['cli']['dry_run']
373
- faye.send(:job_id => ids[:job_id], :execution_id => ids[:execution_id], :type => :output, :message => output[:output])
374
- end
375
- end
376
-
377
- yield output[:output] unless output[:type] == :status
378
- end
379
- rescue Exception => e
380
- # Send the exception message to the server and yield it
381
- unless Minicron.config['cli']['dry_run']
382
- faye.send(:job_id => ids[:job_id], :execution_id => ids[:execution_id], :type => :output, :message => e.message)
383
- end
384
-
385
- raise e
386
- ensure
387
- # Ensure that all messages are delivered and that we
388
- unless Minicron.config['cli']['dry_run']
389
- faye.ensure_delivery
390
- faye.tidy_up
391
- end
392
- end
393
- end
394
- end
395
- end
396
207
  end
397
208
  end