minicron 0.3 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +42 -33
  3. data/bin/minicron +3 -0
  4. data/lib/minicron.rb +12 -3
  5. data/lib/minicron/alert.rb +9 -6
  6. data/lib/minicron/cli.rb +15 -6
  7. data/lib/minicron/cli/commands.rb +35 -12
  8. data/lib/minicron/constants.rb +1 -1
  9. data/lib/minicron/cron.rb +71 -30
  10. data/lib/minicron/hub/app.rb +6 -0
  11. data/lib/minicron/hub/assets/app/components/schedules.js +1 -1
  12. data/lib/minicron/hub/assets/app/controllers/hosts.js +6 -2
  13. data/lib/minicron/hub/assets/app/controllers/jobs.js +5 -2
  14. data/lib/minicron/hub/assets/app/controllers/schedules.js +15 -13
  15. data/lib/minicron/hub/assets/app/models/host.js +1 -0
  16. data/lib/minicron/hub/assets/app/models/job.js +1 -0
  17. data/lib/minicron/hub/controllers/api/executions.rb +0 -1
  18. data/lib/minicron/hub/controllers/api/hosts.rb +12 -13
  19. data/lib/minicron/hub/controllers/api/job_execution_outputs.rb +0 -1
  20. data/lib/minicron/hub/controllers/api/jobs.rb +5 -3
  21. data/lib/minicron/hub/controllers/api/schedule.rb +3 -1
  22. data/lib/minicron/hub/db/schema.rb +8 -6
  23. data/lib/minicron/hub/db/schema.sql +4 -2
  24. data/lib/minicron/hub/views/handlebars/hosts.erb +18 -0
  25. data/lib/minicron/hub/views/handlebars/jobs.erb +18 -0
  26. data/lib/minicron/monitor.rb +14 -12
  27. data/lib/minicron/transport.rb +0 -1
  28. data/lib/minicron/transport/client.rb +19 -11
  29. data/lib/minicron/transport/faye/client.rb +16 -2
  30. data/lib/minicron/transport/faye/extensions/job_handler.rb +10 -4
  31. data/lib/minicron/transport/faye/server.rb +5 -4
  32. data/lib/minicron/transport/server.rb +9 -4
  33. data/lib/minicron/transport/ssh.rb +5 -4
  34. data/spec/minicron/alert/pagerduty_spec.rb +1 -0
  35. data/spec/minicron/alert/sms_spec.rb +1 -0
  36. data/spec/minicron/cli_spec.rb +1 -0
  37. data/spec/minicron/transport/client_spec.rb +1 -0
  38. data/spec/minicron/transport/faye/client_spec.rb +1 -0
  39. data/spec/minicron/transport/server_spec.rb +1 -0
  40. data/spec/minicron/transport_spec.rb +1 -0
  41. data/spec/minicron_spec.rb +6 -0
  42. metadata +88 -88
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9dd39723811b197138d5655e871e4c07fb49d4d4
4
- data.tar.gz: 30b855c523a3ce04c9aaa83bc0a348b950e947c4
3
+ metadata.gz: 1b6939554f2e620783856cad085a5caebb87d70c
4
+ data.tar.gz: 3384f8536105f764031a7035c9a3fea95b985bcf
5
5
  SHA512:
6
- metadata.gz: 5cb855f69d4a2727a5f837df5a96f9c1ff68a85f74150ca2f1c9497729f733af92517e7eb72fbf65457b0483205055c0f2ec9d9b596751f468da79449e2ae13a
7
- data.tar.gz: 3181ea25877f42863c5317d39bb8a6998d563b5d55f75f6d06c0f478c140c3c76114e342edc30fd8d49c68e40c56abb7c1aa91318088eb330ede9b94ef116c79
6
+ metadata.gz: f9420b0503c77643198a875eda7a194630186dd9809f90574b1c234eff524ffc9a1f6b925dc5e766ad775f2d9f89e94e3450c3c810347157d55de6745f9b8287
7
+ data.tar.gz: d4ffe62daecf9ae0abab5b85baf68d40da45a6c1b89a68b20793c4256a7488c8b1e875e4827ab5bcf0856d455c2260d5ed5cf1359b5d41e60d4d9fdc70b487b7
data/README.md CHANGED
@@ -14,23 +14,31 @@ server(s) and executes your cron command and reports the status back to the Hub.
14
14
  where data from one or many instances of the CLI are is recieved and stored in a database. The Hub also provides
15
15
  a web interface to the data and makes it easy to manage your cron jobs.
16
16
 
17
- - [Background](https://github.com/jamesrwhite/minicron/blob/master/README.md#background)
18
- - [Features](https://github.com/jamesrwhite/minicron/blob/master/README.md#goals)
19
- - [Requirements](https://github.com/jamesrwhite/minicron/blob/master/README.md#requirements)
20
- - [Installation](https://github.com/jamesrwhite/minicron/blob/master/README.md#installation)
21
- - [Usage](https://github.com/jamesrwhite/minicron/blob/master/README.md#usage)
22
- - [Documentation](https://github.com/jamesrwhite/minicron/blob/master/README.md#documentation)
23
- - [Versioning](https://github.com/jamesrwhite/minicron/blob/master/README.md#versioning)
24
- - [Contributing](https://github.com/jamesrwhite/minicron/blob/master/README.md#contributing)
25
- - [Support](https://github.com/jamesrwhite/minicron/blob/master/README.md#support)
26
- - [License](https://github.com/jamesrwhite/minicron/blob/master/README.md#license)
17
+ - [Screenshots](#screenshots)
18
+ - [Background](#background)
19
+ - [Features](#goals)
20
+ - [Requirements](#requirements)
21
+ - [Installation](#installation)
22
+ - [Usage](#usage)
23
+ - [Documentation](#documentation)
24
+ - [Versioning](#versioning)
25
+ - [Contributing](#contributing)
26
+ - [Support](#support)
27
+ - [License](#license)
28
+
29
+ Screenshots
30
+ ------------
31
+
32
+ <img src="http://f.cl.ly/items/2o3q3x1N1X3n2t180H1u/Image%202014-04-12%20at%2010.54.39%20pm.png" height="100"/>
33
+
34
+ More coming..
27
35
 
28
36
  Background
29
37
  -----------
30
38
 
31
- I'm developing minicron as part of my dissertation at university which is due in May but I plan to continue
32
- development after that. My inspiration for developing minicron comes from time spent working at
33
- [Miniclip](http://www.miniclip.com) where the management and monitoring of cron jobs at times proved to be tricky!
39
+ I'm developing minicron as part of my dissertation at university which has to be completed by May but I plan to continue
40
+ development after that. The inspiration for developing minicron comes from my own experience, in particular my time spent
41
+ working at [Miniclip](http://www.miniclip.com) where the management and monitoring of cron jobs at times proved to be tricky!
34
42
 
35
43
  Features
36
44
  ---------
@@ -43,9 +51,9 @@ Features
43
51
  - Alerts when jobs executions are missed or fail via:
44
52
  - Email
45
53
  - SMS ([using Twilio](https://www.twilio.com))
46
- - [PagerDuty](www.pagerduty.com)
54
+ - [PagerDuty](http://www.pagerduty.com) (SMS, Phone, Mobile Push Notifications and Email)
47
55
 
48
- Lots more is planned for the future, see issues tagged [feature](https://github.com/jamesrwhite/minicron/issues?labels=feature&milestone=&page=1&state=open).
56
+ Lots more is planned for the future, see [open issues](issues?state=open) or if you don't see the feature you want there add it!
49
57
 
50
58
  Requirements
51
59
  -------------
@@ -53,7 +61,7 @@ Requirements
53
61
  #### Ruby
54
62
  - **MRI**: 1.9.3 and above (tested on 1.9.3, 2.0.0, 2.1.0)
55
63
  - <del>**Rubinius**: Travis builds are run on the latest release</del> [*awaiting bug fix*](https://github.com/rubinius/rubinius/issues/2944)
56
- - **JRuby:** currently untested but most likely needs some workn
64
+ - **JRuby:** currently untested but most likely needs some work
57
65
 
58
66
  #### Database
59
67
 
@@ -63,7 +71,7 @@ Requirements
63
71
  #### Web Server / Reverse Proxy
64
72
 
65
73
  If you want to run minicron behind a web server or proxy it needs to support the web socket protocol.
66
- nginx for example supports web sockets from version 1.3.13 and up. I've included an [example config](https://github.com/jamesrwhite/minicron/blob/master/sample.nginx.conf) for nginx.
74
+ nginx for example supports web sockets from version 1.3.13 and up. I've included an [example config](sample.nginx.conf) for nginx.
67
75
 
68
76
  #### Browser
69
77
 
@@ -72,22 +80,22 @@ I'm currently unsure of how it functions in the various of Internet Explorer but
72
80
 
73
81
  #### OS
74
82
 
75
- Should run on any linux/bsd based OS that the above ruby versions run on.
83
+ Should run on osx and any linux/bsd based OS that the above ruby versions run on.
76
84
 
77
85
  Installation
78
86
  -------------
79
87
 
80
88
  minicron is currently under heavy development and as such I would not recommend that you use this in production yet
81
- but I encourage you to give it a try in a non critical environment and help me to improve it.
89
+ but I encourage you to give it a try in a non critical environment and help me to improve it and work towards the first stable release (1.0).
82
90
 
83
- 1. First check you meet the [requirements](https://github.com/jamesrwhite/minicron/blob/master/README.md#requirements)
91
+ 1. First check you meet the [requirements](#requirements)
84
92
 
85
93
  2. On some distributions you may need to install the ````ruby-dev```` and ````build-essential```` packages
86
94
 
87
- 3. To install the latest release (currently 0.3) you can ````gem install minicron````, depending on your ruby setup
95
+ 3. To install the latest release (currently 0.4) you can ````gem install minicron````, depending on your ruby setup
88
96
  you may need to run this with ````sudo````
89
97
 
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
98
+ 4. Set your database configuration options in ````/etc/minicron.toml````, you can use the [default.config.toml](default.config.toml) as a guide on what options are configurable
91
99
 
92
100
  5. Make sure you have created an empty database with the name you set in ````/etc/minicron.toml````
93
101
 
@@ -99,7 +107,7 @@ but I encourage you to give it a try in a non critical environment and help me t
99
107
  > ````
100
108
 
101
109
  6. You can then ````minicron db setup```` to create the database schema, alternatively you can use
102
- the [schema dump provided](https://github.com/jamesrwhite/minicron/blob/master/lib/minicron/hub/db/schema.sql)
110
+ the [schema dump provided](lib/minicron/hub/db/schema.sql)
103
111
 
104
112
  7. Done! See the usage section below for more details on how to use minicron now you have it installed
105
113
 
@@ -149,7 +157,7 @@ you can also use the ````stop```` and ````status```` commands to control the ser
149
157
  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
158
  option.
151
159
 
152
- See [sample.nginx.conf](https://github.com/jamesrwhite/minicron/blob/master/sample.nginx.conf) for an example of
160
+ See [sample.nginx.conf](sample.nginx.conf) for an example of
153
161
  how to run minicron behind a reverse proxy.
154
162
 
155
163
  #### Connecting to a host via SSH
@@ -163,7 +171,7 @@ most linux distributions or ````/var/root/.ssh/authorized_keys```` on OSX.
163
171
 
164
172
  #### Version
165
173
 
166
- Like many command line programs minicron will show it's version number when the global options ````-v````
174
+ Like many command line programs minicron will show its version number when the global options ````-v````
167
175
  or ````--version```` are passed to the CLI.
168
176
 
169
177
  #### Configuration
@@ -171,14 +179,14 @@ or ````--version```` are passed to the CLI.
171
179
  Some configuration options can be passed in manually but the recommend way to configure minicron is through the use
172
180
  of a config file. You can specify the path to the file using the ````--config```` global option. The file is expected
173
181
  to be in the [toml](https://github.com/mojombo/toml "toml") format. The default options are specified in the
174
- [default.config.toml](https://github.com/jamesrwhite/minicron/blob/master/default.config.toml "default.config.toml")
182
+ [default.config.toml](default.config.toml "default.config.toml")
175
183
  file and minicron will parse a config located in ````/etc/minicron.toml```` if it exists. Options specified via
176
184
  the command line will take precedence over those taken from a config file.
177
185
 
178
186
  Documentation
179
187
  -------------
180
188
 
181
- minicron uses [Yard](http://yardoc.org/ "Yard") for it's code documentation, you can either generate it and view
189
+ minicron uses [Yard](http://yardoc.org/ "Yard") for its code documentation (currently the only *usage* documentation is what you're reading right now), you can either generate it and view
182
190
  it locally using the following commands:
183
191
 
184
192
  ````bash
@@ -191,7 +199,8 @@ or view the most up to date version online at [RubyDoc.info](http://rdoc.info/gi
191
199
  Versioning
192
200
  -----------
193
201
 
194
- Where possible all releases will follow the [semantic versioning](http://semver.org/) guidelines.
202
+ All stable releases will follow the [semantic versioning](http://semver.org/) guidelines. Until 1.0 hits I will try to document any
203
+ major breaking changes in the release descriptions.
195
204
 
196
205
  Releases will be numbered with the following format:
197
206
 
@@ -206,17 +215,17 @@ Based on the following guidelines:
206
215
  Contributing
207
216
  ------------
208
217
 
209
- Feedback and pull requests are welcome, please see [CONTRIBUTING.md](https://github.com/jamesrwhite/minicron/blob/master/CONTRIBUTING.md "CONTRIBUTING.md") for more info.
218
+ Feedback and pull requests are welcome, please see [CONTRIBUTING.md](CONTRIBUTING.md "CONTRIBUTING.md") for more info.
210
219
 
211
220
  Areas that I would love some help with:
212
221
 
213
- - Any of the unassigned [issues here](https://github.com/jamesrwhite/minicron/issues?state=open).
222
+ - Any of the unassigned [issues here](issues?state=open).
214
223
  - General testing of the system, let me know what you think and create issues for any bugs you find!
215
224
  - Tests!!
216
225
  - Validation and error handling improvements
217
- - Documentation improvements. Find something confusing or unexpected, let me know and I'll add or improve
226
+ - Documentation improvements. If you find something confusing or unexpected let me know and I'll add or improve
218
227
  documentation for it!
219
- - Look for '[TODO:](https://github.com/jamesrwhite/minicron/search?q=TODO%3A)' notices littered around the code,
228
+ - Look for '[TODO:](search?q=TODO%3A)' notices littered around the code,
220
229
  I'm trying to convert them all to issues but there are a lot..
221
230
  - Code refactoring, I had a reasonably tight deadline to have the main concept done by so some parts are a bit rushed
222
231
  - UI improvements
@@ -234,4 +243,4 @@ Or feel free to open an issue and I'll do my best to help.
234
243
  License
235
244
  --------
236
245
 
237
- minicron is licensed under the GPL v3, [see here for the full license](https://github.com/jamesrwhite/minicron/blob/master/LICENSE "see here")
246
+ minicron is licensed under the GPL v3, [see here for the full license](LICENSE "see here")
data/bin/minicron CHANGED
@@ -4,6 +4,9 @@ require 'minicron'
4
4
  require 'minicron/cli'
5
5
  require 'minicron/transport/server'
6
6
 
7
+ # Set the process name to something more useful
8
+ $PROGRAM_NAME = "minicron #{ARGV.join(' ')}"
9
+
7
10
  begin
8
11
  # Capture any output from STDERR so we can handle it how we want to
9
12
  Minicron.capture_output(:type => :stderr) do
data/lib/minicron.rb CHANGED
@@ -1,10 +1,12 @@
1
- require 'stringio'
2
- require 'toml'
3
- require 'sshkey'
4
1
  require 'minicron/constants'
5
2
 
6
3
  # @author James White <dev.jameswhite+minicron@gmail.com>
7
4
  module Minicron
5
+ # Define module autoloading
6
+ autoload :TOML, 'toml'
7
+ autoload :StringIO, 'stringio'
8
+ autoload :SSHKey, 'sshkey'
9
+
8
10
  # Default configuration, this can be overriden
9
11
  @config = {
10
12
  'verbose' => false,
@@ -179,4 +181,11 @@ module Minicron
179
181
  def self.get_hostname
180
182
  `hostname -s`.strip
181
183
  end
184
+
185
+ # Get the user minicron is being run as
186
+ #
187
+ # @return [String]
188
+ def self.get_user
189
+ `whoami`.strip
190
+ end
182
191
  end
@@ -1,10 +1,13 @@
1
- require 'minicron/alert/email'
2
- require 'minicron/alert/sms'
3
- require 'minicron/alert/pagerduty'
4
- require 'minicron/hub/models/alert'
5
- require 'minicron/hub/models/job'
6
-
7
1
  module Minicron
2
+ autoload :Email, 'minicron/alert/email'
3
+ autoload :SMS, 'minicron/alert/sms'
4
+ autoload :PagerDuty, 'minicron/alert/pagerduty'
5
+
6
+ module Hub
7
+ autoload :Alert, 'minicron/hub/models/alert'
8
+ autoload :Job, 'minicron/hub/models/job'
9
+ end
10
+
8
11
  # Allows the sending of alerts via multiple mediums
9
12
  class Alert
10
13
  # Send an alert using all enabled mediums
data/lib/minicron/cli.rb CHANGED
@@ -1,17 +1,23 @@
1
- require 'pty'
1
+ autoload :PTY, 'pty'
2
+ autoload :Minicron, 'minicron'
3
+
2
4
  require 'English'
3
5
  require 'rainbow/ext/string'
4
6
  require 'commander'
5
7
  require 'minicron/constants'
6
8
  require 'minicron/cli/commands'
7
- require 'minicron/transport'
8
- require 'minicron/transport/client'
9
- require 'minicron/transport/server'
10
- require 'minicron/monitor'
11
9
 
12
10
  include Commander::UI
13
11
 
14
12
  module Minicron
13
+ autoload :Transport, 'minicron/transport'
14
+ autoload :Monitor, 'minicron/monitor'
15
+
16
+ module Transport
17
+ autoload :Client, 'minicron/transport/client'
18
+ autoload :Server, 'minicron/transport/server'
19
+ end
20
+
15
21
  # Handles the main CLI interaction of minicron
16
22
  # TODO: this class is probably too complicated and should be refactored a bit
17
23
  module CLI
@@ -188,6 +194,9 @@ module Minicron
188
194
  @cli.program :version, Minicron::VERSION
189
195
  @cli.program :description, 'cli for minicron; a system a to manage and monitor cron jobs'
190
196
 
197
+ # Display the output in a compact format
198
+ @cli.program :help_formatter, Commander::HelpFormatter::TerminalCompact
199
+
191
200
  # Set the default command to run
192
201
  @cli.default_command :help
193
202
 
@@ -197,7 +206,7 @@ module Minicron
197
206
  end
198
207
 
199
208
  # Add a global option for verbose mode
200
- @cli.global_option '--verbose', "Turn on verbose mode. Default: #{Minicron.config['cli']['verbose']}" do
209
+ @cli.global_option '--verbose', "Turn on verbose mode. Default: #{Minicron.config['verbose'].to_s}" do
201
210
  Minicron.config['verbose'] = true
202
211
  end
203
212
 
@@ -1,8 +1,23 @@
1
- require 'insidious'
2
- require 'minicron'
3
- require 'minicron/transport/client'
1
+ autoload :Minicron, 'minicron'
2
+ autoload :Insidious, 'insidious'
3
+ autoload :Rake, 'rake'
4
+
5
+ module Sinatra
6
+ autoload :ActiveRecordTasks, 'sinatra/activerecord/rake'
7
+ end
4
8
 
5
9
  module Minicron
10
+ autoload :Transport, 'minicron/transport'
11
+
12
+ module Transport
13
+ autoload :Client, 'minicron/transport/client'
14
+ autoload :Server, 'minicron/transport/server'
15
+ end
16
+
17
+ module Hub
18
+ autoload :App, 'minicron/hub/app'
19
+ end
20
+
6
21
  module CLI
7
22
  class Commands
8
23
  # Add the `minicron db` command
@@ -20,11 +35,6 @@ module Minicron
20
35
  # Parse the file and cli config options
21
36
  Minicron::CLI.parse_config(opts)
22
37
 
23
- # These are inlined as we only need them in this use case
24
- require 'rake'
25
- require 'minicron/hub/app'
26
- require 'sinatra/activerecord/rake'
27
-
28
38
  # Setup the db
29
39
  Minicron::Hub::App.setup_db
30
40
 
@@ -125,7 +135,16 @@ module Minicron
125
135
  # Set up the job and get the jexecution and job ids back from the server
126
136
  ids = setup_job(args.first, faye)
127
137
  end
138
+ rescue Exception => e
139
+ raise Exception, "Unable to setup job, reason: #{e.message}"
128
140
 
141
+ # Ensure that all messages are delivered and that we
142
+ unless Minicron.config['cli']['dry_run']
143
+ faye.tidy_up
144
+ end
145
+ end
146
+
147
+ begin
129
148
  # Execute the command and yield the output
130
149
  Minicron::CLI.run_command(args.first, :mode => Minicron.config['cli']['mode'], :verbose => Minicron.config['verbose']) do |output|
131
150
  # We need to handle the yielded output differently based on it's type
@@ -143,6 +162,7 @@ module Minicron
143
162
  yield output[:output] unless output[:type] == :status
144
163
  end
145
164
  rescue Exception => e
165
+ p e
146
166
  # Send the exception message to the server and yield it
147
167
  unless Minicron.config['cli']['dry_run']
148
168
  faye.send(:job_id => ids[:job_id], :execution_id => ids[:execution_id], :type => :output, :message => e.message)
@@ -171,9 +191,6 @@ module Minicron
171
191
  # Get the fully qualified domain name of the currnet host
172
192
  fqdn = Minicron.get_fqdn
173
193
 
174
- # Get the short hostname of the current host
175
- hostname = Minicron.get_hostname
176
-
177
194
  # Get the md5 hash for the job
178
195
  job_hash = Minicron::Transport.get_job_hash(command, fqdn)
179
196
 
@@ -181,7 +198,13 @@ module Minicron
181
198
  faye.ensure_em_running
182
199
 
183
200
  # Setup the job on the server
184
- ids = faye.setup(job_hash, command, fqdn, hostname)
201
+ ids = faye.setup(
202
+ :job_hash => job_hash,
203
+ :user => Minicron.get_user,
204
+ :command => command,
205
+ :fqdn => fqdn,
206
+ :hostname => Minicron.get_hostname
207
+ )
185
208
 
186
209
  # Wait until we get the execution id
187
210
  faye.ensure_delivery
@@ -1,6 +1,6 @@
1
1
  # The minicron module
2
2
  module Minicron
3
- VERSION = '0.3'
3
+ VERSION = '0.4'
4
4
  DEFAULT_CONFIG_FILE = '/etc/minicron.toml'
5
5
  BASE_PATH = File.expand_path('../../../', __FILE__)
6
6
  LIB_PATH = File.expand_path('../../', __FILE__)
data/lib/minicron/cron.rb CHANGED
@@ -3,9 +3,6 @@ require 'escape'
3
3
 
4
4
  module Minicron
5
5
  # Used to interact with the crontab on hosts over an ssh connection
6
- # TODO: I've had a moment of clarity, I don't need to do all the CRUD
7
- # using unix commands. I can cat the crontab, manipulate it in ruby
8
- # and then echo it back!
9
6
  class Cron
10
7
  # Initialise the cron class
11
8
  #
@@ -16,15 +13,49 @@ module Minicron
16
13
 
17
14
  # Build the minicron command to be used in the crontab
18
15
  #
19
- # @param command [String]
20
16
  # @param schedule [String]
17
+ # @param user [String]
18
+ # @param command [String]
21
19
  # @return [String]
22
- def build_minicron_command(command, schedule)
20
+ def build_minicron_command(schedule, user, command)
23
21
  # Escape the command so it will work in bourne shells
24
22
  command = Escape.shell_command(['minicron', 'run', command])
25
- cron_command =Escape.shell_command(['/bin/bash', '-l', '-c', command])
23
+ cron_command = Escape.shell_command(['/bin/bash', '-l', '-c', command])
26
24
 
27
- "#{schedule} root #{cron_command}"
25
+ "#{schedule} #{user} #{cron_command}"
26
+ end
27
+
28
+ # Test an SSH connection and the permissions for the crontab
29
+ #
30
+ # @param conn an instance of an open ssh connection
31
+ # @return [Hash]
32
+ def test_host_permissions(conn = nil)
33
+ # Open an SSH connection
34
+ conn ||= @ssh.open
35
+
36
+ # Check if /etc is writeable
37
+ etc_write = conn.exec!("/bin/sh -c 'test -w /etc && echo \"y\" || echo \"n\"'").strip
38
+
39
+ # Check if /etc is executable
40
+ etc_execute = conn.exec!("/bin/sh -c 'test -x /etc && echo \"y\" || echo \"n\"'").strip
41
+
42
+ # Check if the crontab is readable
43
+ crontab_read = conn.exec!("/bin/sh -c 'test -r /etc/crontab && echo \"y\" || echo \"n\"'").strip
44
+
45
+ # Check if the crontab is writeable
46
+ crontab_write = conn.exec!("/bin/sh -c 'test -w /etc/crontab && echo \"y\" || echo \"n\"'").strip
47
+
48
+ {
49
+ :connect => true,
50
+ :etc => {
51
+ :write => etc_write == 'y',
52
+ :execute => etc_execute == 'y'
53
+ },
54
+ :crontab => {
55
+ :read => crontab_read == 'y',
56
+ :write => crontab_write == 'y'
57
+ }
58
+ }
28
59
  end
29
60
 
30
61
  # Used to find a string and replace it with another in the crontab by
@@ -34,7 +65,27 @@ module Minicron
34
65
  # @param find [String]
35
66
  # @param replace [String]
36
67
  def find_and_replace(conn, find, replace)
37
- # TODO: move ssh test here for crontab permissions
68
+ begin
69
+ # Test the SSH connection first
70
+ test = test_host_permissions(conn)
71
+ rescue Exception => e
72
+ raise Exception, "Error connecting to host, reason: #{e.message}"
73
+ end
74
+
75
+ # Check the connection worked
76
+ raise Exception, "Unable to connect to host, reason: unknown" if !test[:connect]
77
+
78
+ # Check the crontab is readable
79
+ raise Exception, "Insufficient permissions to read from /etc/crontab" if !test[:crontab][:read]
80
+
81
+ # Check the crontab is writeable
82
+ raise Exception, "Insufficient permissions to write to /etc/crontab" if !test[:crontab][:write]
83
+
84
+ # Check /etc is writeable
85
+ raise Exception, "/etc is not writeable by the current user" if !test[:etc][:write]
86
+
87
+ # Check /etc is executable
88
+ raise Exception, "/etc is not executable by the current user" if !test[:etc][:execute]
38
89
 
39
90
  # Get the full crontab
40
91
  crontab = conn.exec!('cat /etc/crontab').to_s.strip
@@ -47,17 +98,12 @@ module Minicron
47
98
  end
48
99
 
49
100
  # Echo the crontab back to the tmp crontab
50
- update = conn.exec!("echo #{crontab.shellescape} > /etc/crontab.tmp && echo 'y' || echo 'n'").to_s.strip
51
-
52
- # Throw an exception if it failed
53
- if update != 'y'
54
- fail Exception, "Unable to replace '#{find}' with '#{replace}' in the crontab"
55
- end
101
+ conn.exec!("echo #{crontab.shellescape} > /tmp/minicron_crontab").to_s.strip
56
102
 
57
103
  # If it's a delete
58
104
  if replace == ''
59
105
  # Check the original line is no longer there
60
- grep = conn.exec!("grep -F #{find.shellescape} /etc/crontab.tmp").to_s.strip
106
+ grep = conn.exec!("grep -F #{find.shellescape} /tmp/minicron_crontab").to_s.strip
61
107
 
62
108
  # Throw an exception if we can't see our new line at the end of the file
63
109
  if grep != replace
@@ -65,7 +111,7 @@ module Minicron
65
111
  end
66
112
  else
67
113
  # Check the updated line is there
68
- grep = conn.exec!("grep -F #{replace.shellescape} /etc/crontab.tmp").to_s.strip
114
+ grep = conn.exec!("grep -F #{replace.shellescape} /tmp/minicron_crontab").to_s.strip
69
115
 
70
116
  # Throw an exception if we can't see our new line at the end of the file
71
117
  if grep != replace
@@ -74,10 +120,10 @@ module Minicron
74
120
  end
75
121
 
76
122
  # And finally replace the crontab with the new one now we now the change worked
77
- move = conn.exec!("mv /etc/crontab.tmp /etc/crontab && echo 'y' || echo 'n'").to_s.strip
123
+ move = conn.exec!("/bin/sh -c 'mv /tmp/minicron_crontab /etc/crontab && echo \"y\" || echo \"n\"'").to_s.strip
78
124
 
79
125
  if move != 'y'
80
- fail Exception, 'Unable to move tmp crontab with updated crontab'
126
+ fail Exception, 'Unable to move /tmp/minicron_crontab to /etc/crontab, check the permissions?'
81
127
  end
82
128
  end
83
129
 
@@ -91,20 +137,15 @@ module Minicron
91
137
  conn ||= @ssh.open
92
138
 
93
139
  # Prepare the line we are going to write to the crontab
94
- line = build_minicron_command(job.command, schedule)
140
+ line = build_minicron_command(schedule, job.user, job.command)
95
141
  escaped_line = line.shellescape
96
- echo_line = "echo #{escaped_line} >> /etc/crontab && echo 'y' || echo 'n'"
142
+ echo_line = "echo #{escaped_line} >> /etc/crontab"
97
143
 
98
144
  # Append it to the end of the crontab
99
- write = conn.exec!(echo_line).strip
100
-
101
- # Throw an exception if it failed
102
- if write != 'y'
103
- fail Exception, "Unable to echo #{escaped_line} to the crontab"
104
- end
145
+ conn.exec!(echo_line).to_s.strip
105
146
 
106
147
  # Check the line is there
107
- tail = conn.exec!('tail -n 1 /etc/crontab').strip
148
+ tail = conn.exec!('tail -n 1 /etc/crontab').to_s.strip
108
149
 
109
150
  # Throw an exception if we can't see our new line at the end of the file
110
151
  if tail != line
@@ -123,10 +164,10 @@ module Minicron
123
164
  conn ||= @ssh.open
124
165
 
125
166
  # We are looking for the current value of the schedule
126
- find = build_minicron_command(job.command, old_schedule)
167
+ find = build_minicron_command(old_schedule, job.user, job.command)
127
168
 
128
169
  # And replacing it with the updated value
129
- replace = build_minicron_command(job.command, new_schedule)
170
+ replace = build_minicron_command(new_schedule, job.user, job.command)
130
171
 
131
172
  # Replace the old schedule with the new schedule
132
173
  find_and_replace(conn, find, replace)
@@ -142,7 +183,7 @@ module Minicron
142
183
  conn ||= @ssh.open
143
184
 
144
185
  # We are looking for the current value of the schedule
145
- find = build_minicron_command(job.command, schedule)
186
+ find = build_minicron_command(schedule, job.user, job.command)
146
187
 
147
188
  # Replace the old schedule with nothing i.e deleting it
148
189
  find_and_replace(conn, find, '')