minicron 0.2 → 0.3

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 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